Jump to content

Help with Science


Recommended Posts

I am making my first plugin (read: I'm a complete newbie at this), and I'm not sure where to start when trying to modify Science experiments.

For now, my first goal is this: Making the transmit data of a science experiment (like Crew or Eva reports) be worth more than the non-transmitted data.

I am thinking that ModuleScienceExperiment would be the correct class to inherit in this case, and I think that ResearchAndDevelopment can be used somehow, but other than that I'm not sure how I can get started on accomplishing my first goal.

Link to comment
Share on other sites

After much trial and error, I have managed to figure out how to achieve my first goal.


[KSPAddon(KSPAddon.Startup.Flight,false)]
public class ScienceRedefined : MonoBehaviour
{
public void Start()
{
Vessel craft = FlightGlobals.ActiveVessel;
List<Part> parts = craft.parts;

foreach (Part p in parts)
{
float modDataScalar = 0.0f;
if (p.name.Contains("mk1pod")) modDataScalar = 2.0f;

List<ModuleScienceExperiment> mods = p.FindModulesImplementing<ModuleScienceExperiment>();
foreach (ModuleScienceExperiment m in mods)
{
m.xmitDataScalar += modDataScalar;
}
}

}
}

As long as the scienceCap is bigger than the baseValue, the above code will let the first command pod in Career boost the Science value by up to 200% (for a total value of 300%) through transmission.

So now for my next goal: How would I make it so that the Science Lab (module) boosts the baseValue of the Scientific data instead of the Transmission value? Right now I'm thinking of making a Part Module that inherits the ModuleScienceLab class, and somehow manipulating the ScienceData values that pass through it, but I'm not sure where I could get the ScienceData to manipulate.

Link to comment
Share on other sites

Fiddling around with the code a bit, I believe I need to modify the ProcessData function. However, it appears to be an Interface (IEnumerator) or returns an Interface, so I'm not sure how to modify it (specifically, the callback argument).

Edit: Or it's not the ProcessData that I need to modify. Nothing is printed out into the console when I Process the lab data.

public class ModuleLabBooster : ModuleScienceLab
{
new public System.Collections.IEnumerator ProcessData(ScienceData data, Callback<ScienceData> onComplete)
{
Debug.Log("Processing the Data");
Debug.Log("Moonstone Cannon, FIRE!!!!");

return base.ProcessData(data, onComplete);
}

//This Event is fired when the "Process Data" button on the actual module itself is pressed
new public void ProcessScienceDataEvent()
{
Debug.Log("Processing Event");
base.ProcessScienceDataEvent();
}

}

Edit #2: Now that I've thought about it, I think what I'm wanting to change is the ModuleScienceExperiment. From what I can tell, that is what actually stores the data and calls for the Lab to do its thing. However, making a PartModule that inherits the ModuleScienceExperiment and using that on a Science part leads to a NullReferenceError for some reason.

Edit #3: After testing a lot more code, I have narrowed down the cause of what processes the Lab Boost to being outside of the ModuleScienceLab class itself. ScienceUtil supplies a boost value to whatever is eventually submitting the Report to ResearchAndDevelopment.

My guess as to what actually uses the Lab boost?

Q6qqG6B.jpg

Or in other words, an RDReportListItemContainer object, which happens to have all of the variables at hand. The question is whether I can manipulate what goes on behind that box somehow. Any ideas?

Edited by Rhidian
Link to comment
Share on other sites

Edit #2: Now that I've thought about it, I think what I'm wanting to change is the ModuleScienceExperiment. From what I can tell, that is what actually stores the data and calls for the Lab to do its thing. However, making a PartModule that inherits the ModuleScienceExperiment and using that on a Science part leads to a NullReferenceError for some reason.

I had issues with this too.

The problem, I think, was calling OnStart (I was replacing the default animation functions too). I seem to have fixed it by adding the base.OnStart(state) line and forcing the part to activate:

 public override void OnStart(PartModule.StartState state)
{
base.OnStart(state);
if (state == StartState.Editor) { return; }
this.part.force_activate();
anim = part.FindModelAnimators(animationName)[0];


}

I wish I knew why that worked (well, I sort-of understand it), but it seems to. Though it sounds like you might not need to inherit the ModuleScienceExperiment anymore.

Link to comment
Share on other sites

I think that I am going to have to give up on changing the baseValue via the Science Lab. I don't know where the base values are stored midflight and I don't know how to determine/modify the Lab's data boosting function.

I'll just settle with the Science Lab's experiment resetting ability and the massive transmission boost that I'll give it later. Which means I'll move onto my next goal, which is to make it so that upon successful recovery of a vessel that performed an experiment, that experiment's data entropy is reduced (ie you can repeat the experiment again with less of a penalty). I've noticed that the 'data entropy' as I've termed it is located within the persistence save file under the specific experiment report. So the question I have is how could I access/overwrite the information in that file, and how can I determine if the craft that has performed an experiment has been successfully recovered?

Edit: I just had a Eureka moment (that still needs to be tested). Would it be possible to use ModuleScienceExperiment's GetData function and change the baseValues for the experiment directly? Like if during the experiment's DeployExperiment function I checked to see if there is a functioning Lab on the vessel, and if so, increase the baseValues by iterating through the GetData array?

Edit: Or there is no data stored in the experiment at the time that the experiment is deployed. Which means if I want to modify the data, it would have to be after it's been collected. To this end, I think it should be possible to add one of those actions to the Lab Module to iterate through the data and increase the data value. So how would I go about creating one of those actions like that which says "Process Lab Data" when there is data to be processed?

Edited by Rhidian
Link to comment
Share on other sites

It has been a long journey, but I have finally figured out how to change the Base Value of an experiment via the presence of a Science Lab successfully.


public class ModuleResearchExperiment : ModuleScienceExperiment
{
[KSPField(isPersistant = true)]
public bool beenBoosted = false;

protected ScienceExperiment boostExperiment = null;

public void initializeExperiment()
{
boostExperiment = new ScienceExperiment();
ConfigNode sNode = new ConfigNode();
ResearchAndDevelopment.GetExperiment(this.experimentID).Save(sNode);

//Copies values from original experiment to the internal experiment
boostExperiment.Load(sNode);

Debug.Log("Initialized Successfully");
Debug.Log("Testing: " + boostExperiment.experimentTitle);

this.experiment = boostExperiment;
Debug.Log("Transferred successfully");

beenBoosted = false;
}

new public void DeployExperiment()
{
//If it is the first time deploying the experiment, initialize it
if (boostExperiment == null)
{
initializeExperiment();
}
Debug.Log("Experiment has been deployed");
requestBoost();

base.DeployExperiment();
}

new public void ResetExperiment()
{
Debug.Log("Experiment has been resetted");
initializeExperiment();
base.ResetExperiment();
// this.resetBoost();
}

public void requestBoost()
{
//If this hasn't been boosted already
if (!this.beenBoosted)
{
Vessel v = FlightGlobals.ActiveVessel;
List<ModuleScienceLab> labs = v.FindPartModulesImplementing<ModuleScienceLab>();
float boost = 1.0f;
foreach (ModuleScienceLab lab in labs)
{
if (lab.dataTransmissionBoost > boost)
{
boost = lab.dataTransmissionBoost;
}
}

if (boost > 1.0f)
{
//The "this.experiment" that is being changes should be the boostExperiment
this.experiment.baseValue = this.experiment.baseValue * boost;
beenBoosted = true;
}

}
}

}

The key to the whole problem is the Science Experiment module itself, which houses the information that is used to generate the science reports. However, a big problem I encountered was that changing the "this.experiment.baseValue" directly changed it for *all* experiments of the same type, which got out of hand fast with multiple Experiment modules on-board. And so my solution is for each PartModule to house it's own individualized ScienceExperiment (which is a copy of the original), so that any changes to its baseValue is compartmentalized.

With this hurdle being overcome, I am much closer to getting a WIP version out on the main Add-On Development forum where the focus would be on balancing the changes I make. But before that, is there anything else I could/should do to change the Science data collection mechanics?

Link to comment
Share on other sites

I believe I have just found the Holy Grail of Science Reports, the ExperimentResultDialogPage class, whose constructor requires everything necessary to display that popup that shows after collecting any sort of data. So the question is, how would I go about constructing one correctly?

At the moment I'm stumped by what subjectID I am needing. The ones I have tried don't seem to be actual ScienceSubjects (like "crewReport", etc).

Link to comment
Share on other sites

The ExperimentResultsPage was a red herring; I wasn't able to find any way to make my own due to the fact that the ScienceSubject (or at least its ID) that the results page requires doesn't actually exist until after the results page shows up. That being said, I did manage to get one up on that results screen by manipulating what goes into it by removing Science Decay, which normally makes each successive experiment worth less and less.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...