Jump to content

Contract Modding Information for Mod Authors


MrHappyFace

Recommended Posts

...Looking at those structures, it appears it should be feasible to create a plugin that consumes Mission Controller campaigns and produces stock contracts.

Which, I think, would be a welcome addition, since unlike the procedurally generated contracts, Mission Controller campaigns usually make some sort of sense.

Link to comment
Share on other sites

It woudl be nice if it required specific orbit parameters, for example molniya orbit-like. Players are launching exuatorial all the time, except rare cases of when they want to encounter asterid or put satellite on polar orbit.

Also, is it possible to make use of asteroid/stranded kerbal spawning system to make game spawn its own ships?

Right now, it selects a random orbit from 3 types: low orbit, geostationary, and ececentric. Also please note that ( as far as I know) the "asteroid system" doesn't spawn anything itself, it simply asks the vessel spawning system to spawn asteroids, and the vessel spawning system is moddable, so yes, it is possible.

Edited by MrHappyFace
Link to comment
Share on other sites

It looks like they added some new GameEvents, which should be extremely helpful for detecting completion of new contracts.

OnScienceReceived fires after transmitting or recovering science and returns the science subject and the amount of science gained. This should be perfect for setting up very specific science contracts. Instead of just collect science from the Mun, I think I can give it a specific experiment (and even biome) with a required amount of science to be gained. I will post the ContractParameter code if I get it working.

Edit: Success! I've got created a new Contract Parameter that calls for specific experiments around a specific body, and can require a set amount of science to be gathered.

Javascript is disabled. View full album

This code is all sorts of rough, but everything seems to be working so far.


namespace DMagic
{
public class DMContract: Contract
{

private CelestialBody body = null;
private BodyLocation scienceLocation;
private ScienceExperiment exp = null;

#region overrides

protected override bool Generate()
{
if (body == null)
body = FlightGlobals.Bodies[1];
scienceLocation = BodyLocation.Space;
if (exp == null)
exp = ResearchAndDevelopment.GetExperiment("rpwsScan");
this.agent = Contracts.Agents.AgentList.Instance.GetAgent("DMagic");
this.AddParameter(new DMCollectScience(body, scienceLocation, exp), null);
base.SetExpiry();
base.SetScience(5f, body);
base.SetDeadlineYears(100f, body);
base.SetReputation(5f, 10f, body);
base.SetFunds(100f, 10f, 50f, body);
return true;
}

public override bool CanBeCancelled()
{
return true;
}

public override bool CanBeDeclined()
{
return true;
}

protected override string GetHashString()
{
return body.name + scienceLocation.ToString() + exp.id;
}

protected override string GetTitle()
{
return "Contract to do something";
}

protected override string GetDescription()
{
return "Do something!";
}

protected override string GetSynopsys()
{
return "You did something!";
}

protected override string MessageCompleted()
{
return "Success";
}

protected override void OnLoad(ConfigNode node)
{
Debug.Log("[DM] Loading Contract");
int targetBodyID = int.Parse(node.GetValue("ScienceTarget"));
foreach (CelestialBody cBody in FlightGlobals.Bodies)
{
if (cBody.flightGlobalsIndex == targetBodyID)
body = cBody;
}
Debug.Log("[DM] Body Set");
ScienceExperiment sciExp = ResearchAndDevelopment.GetExperiment(node.GetValue("ScienceExperiment"));
if (sciExp != null)
exp = sciExp;
Debug.Log("[DM] Experiment Set");
string location = node.GetValue("TargetLocation");
if (location != null)
if (location == "Space")
scienceLocation = BodyLocation.Space;
else
scienceLocation = BodyLocation.Surface;
Debug.Log("[DM] Location Set");
}

protected override void OnSave(ConfigNode node)
{
Debug.Log("[DM] Saving Contract");
node.AddValue("ScienceTarget", body.flightGlobalsIndex);
node.AddValue("ScienceExperiment", exp.id);
node.AddValue("TargetLocation", scienceLocation);
}

public override bool MeetRequirements()
{
return true;
}

#endregion

}

#region Contract Parameter

public class DMCollectScience: CollectScience
{
public CelestialBody scienceTargetBody;
public BodyLocation scienceLocation;
public ScienceExperiment targetScience;

public DMCollectScience()
{
}

public DMCollectScience(CelestialBody target, BodyLocation location, ScienceExperiment experiment)
{
scienceTargetBody = target;
scienceLocation = location;
targetScience = experiment;
}

protected override string GetHashString()
{
return scienceTargetBody.name + scienceLocation.ToString() + targetScience.id;
}

protected override string GetTitle()
{
if (scienceLocation == BodyLocation.Space)
return string.Format("Collect {0} data from in orbit around {1}.", targetScience.experimentTitle, scienceTargetBody.theName);
else
return string.Format("Collect {0} data from the surface of {1}.", targetScience.experimentTitle, scienceTargetBody.theName);
}

protected override void OnRegister()
{
GameEvents.OnScienceRecieved.Add(scienceRecieve);
}

protected override void OnUnregister()
{
GameEvents.OnScienceRecieved.Remove(scienceRecieve);
}

protected override void OnSave(ConfigNode node)
{
Debug.Log("[DM] Saving Contract Parameter");
node.AddValue("ScienceTarget", scienceTargetBody.flightGlobalsIndex);
node.AddValue("ScienceExperiment", targetScience.id);
node.AddValue("TargetLocation", scienceLocation);
}

protected override void OnLoad(ConfigNode node)
{
Debug.Log("[DM] Loading Contract Parameter");
int targetBodyID = int.Parse(node.GetValue("ScienceTarget"));
foreach (CelestialBody body in FlightGlobals.Bodies)
{
if (body.flightGlobalsIndex == targetBodyID)
scienceTargetBody = body;
}
Debug.Log("[DM] Param Body Set");
ScienceExperiment exp = ResearchAndDevelopment.GetExperiment(node.GetValue("ScienceExperiment"));
if (exp != null)
targetScience = exp;
Debug.Log("[DM] Param Experiment Set");
string location = node.GetValue("TargetLocation");
if (location != null)
if (location == "Space")
scienceLocation = BodyLocation.Space;
else
scienceLocation = BodyLocation.Surface;
Debug.Log("[DM] Param Location Set");
}

private void scienceRecieve(float sci, ScienceSubject sub)
{
if (sub.id == targetScience.id + "@" + scienceTargetBody.name + ExperimentSituations.InSpaceLow.ToString())
{
Debug.Log("[DM] Contract Complete");
base.SetComplete();
}
}


}

#endregion

The OnSave and OnLoad methods were giving me headaches, hence all of the debug spam, but in principle they are simple (also, MrHappyFace, I think you have the OnSave and OnLoad switched in your ContractParameter code), you can check the persistent file to see how things look once they've been saved.

The other problem that I kept running into, was that my DMCollectScience Contract Parameter needed to have an empty constructor, the public DMCollectScience() line, in addition to the one called by the Contract generator.

The only method really specific to this type of contract is the last one, scienceRecieve(), that's the one tied to the game event that checks to see if the correct experiment has been performed. It also returns the amount of science gained, so I could check that, too.

Edited by DMagic
Link to comment
Share on other sites

The OnSave and OnLoad methods were giving me headaches, hence all of the debug spam.

Hello OnSaveLoad Debug Spam buddy! I had the same issues, and also noticed that the example code was reversed. We might be able to pool our resources into one mod once we all finish our respective contract types and get that code out there.

Link to comment
Share on other sites

I'm all for combining resources, but most of my contracts will probably be specific to my own parts.

I'm thinking, though, that maybe I'll make a generic generator with a ScienceExperiment array populated with the available science parts to serve as a source of contracts. There is no reason why this wouldn't work with stock science parts too, or any other science experiments.

This could exist separately from my mod, or maybe I could also include it with my mod, but just disable it if the separate version is also installed. I'll have to see what's possible.

Link to comment
Share on other sites

I'm good with the combined mod idea. Also, the code in the op has long since been updated, the contract's target will never be the same twice, and it picks the next logical target based on where you've been, but the OnLoad OnSave thing did cause me some grief... I just hate how much of my time has been wasted on REALLY stupid typos like that.

Link to comment
Share on other sites

Hey awesome guide! Used this to mess around on my own, but i'm now stuck on a few problems:

I am not able to set up those Contract Parameters right, where there is a specific condition like "Reach Altitude from 2000 to 3000".

Once i am in the specified altitude the Parameter for my custom contract gets green (which is fine), but when leaving the altitude range the parameter stays green...

Tried using Contracts.Parameters.ReachAltitudeEnvelope and also a custom Paramter. It kind of looks like that the OnUpdate is not triggered anymore once the parameter is set to completed and i do not know how to reset this parameter once the condition is no more met... Also the ReachAltitudeEnvelope is a stock parameter and i do not get why this does not work here.

Second thing is about those sub parameters for parameters.

I created a new custom parameter and tried to add a sub parameter : Contracts.Parameters.ReachAltitudeEnvelope.

I instanciated that one in the constructor and in the OnRegister() Method i add it to my base parameter.

Also in OnUnregister i remove that parameter. Problem here is: When accepting a contract i see the sub parameter, but when going through a loading screen i get a new sub paramter added everytime additionally to the old one:

class ShipParam : ContractParameter {        const String PARAMID = "";
Contracts.Parameters.ReachAltitudeEnvelope alt;


public ShipParam() {
alt = new Contracts.Parameters.ReachAltitudeEnvelope(3000, 2000, "a");
}


protected override void OnRegister() {
this.AddParameter(alt, "test");
base.OnRegister();
}


protected override void OnUnregister() {
this.RemoveParameter(alt);
base.OnUnregister();
}


protected override void OnUpdate() {


base.OnUpdate();
}


}
}

Also the same problem regarding the setting to imcomplete applies here.

Link to comment
Share on other sites

I've had some success getting a more generalized and customizable system setup for adding science experiment contracts.

First of all, I'm not sure if it's been mentioned, but in the Alt+F12 debug console there is a "Contracts" tab that allows you to manually create any type of contract. There are three buttons there, and I'm not sure what the difference is, but this is great for forcing contract generation while testing.

So anyway, my first thought was that instead of just scanning through all of the existing science experiments (and potentially stepping on science modders' toes) I would setup a config file system. It's a fairly simple system where you just include a few items about the experiments you want to add and put them in a config file.


CONTRACT_EXPERIMENT
{
name = Magnetometer Scan
experimentID = magScan
sitMask = 51
bioMask = 1
part = dmmagBoom
techNode = scienceTech
agent = DMagic
}

This is my format. My experiments have a few added complications because I store the situation and biome masks internally rather than in the ScienceDefs.cfg file (the better to keep unwanted mods from interfering with my parts:wink:), but the basic requirements are simple. You add a name, I'm using the experiment name from the ScienceDefs file, but anything will do, the experimentID, the name of the part that the experiment is associated with, the tech node where that part can be researched, and an agent.

These can be generalized or made to work with different types of experiments. For example the EVA report would look like


CONTRACT_EXPERIMENT
{
name = EVA Report
experimentID = evaReport
part = None
techNode = notANode
agent = Any
}

As long as the part is named "None" then the system will assume that no part is associated with the experiment and skip all of the part and tech node steps (putting something in the tech node field is probably still required though). And setting the agent equal to "Any" means that none will be specified.

The code is getting too complicated to post here, but everything is on GitHub in the Contracts! branch and I update that frequently.

The system loads all of the experiments from the config file at the mainmenu and prints out which were added. It stores all of the information in a simple object that I created.

The contract generator just takes a random value from the list of all these objects then scans through to check if it is eligible. It checks to see if the tech node is valid and has been researched, then it checks to see if the specific part has been purchased from the R&D center.

Once it gets past there it assigns a target Celestial Body (which I haven't really implemented yet, but it looks like there are some standard methods for this). Then it checks which experimental situations can be done by the selected experiment, selects one at random, and generates the appropriate Science Subject. This would be the experiment ID, the target body, the target situation, and a biome if applicable (I haven't implemented the biome part yet). If the experiment doesn't have enough remaining science to be collected (maybe one or two samples from that area have already been collected) then it returns false.

If it gets past that point then it assigns the agent if applicable, and generates the Contract Paramater.

I have an idea to set the rewards values based on the celestial body science parameters. These are the multipliers for your science experiments, I think they serve as a decent analogue for the difficulty level involved with any given experiment.

It all seems to working so far. It's generating contracts based on my list of experiments, and none of them are invalid, I'm not getting requests to perform a laser surface scan from orbit.

I think I just need to figure out the celestial body generating code, come with a way to generate descriptions, and maybe tweak the reward settings.

But it should be very simple to add in the stock experiments and any standard mod experiments using a slightly altered form of this code. Then the contracts for my own experiments could live alongside these without any conflicts.

I'll post more when I get something more finalized.

Link to comment
Share on other sites

That's kind of an unorthodox method of creating parameters, why not try simply extending ReachAltitudeEnvelope

Hi,

that is of course just a code snippet. My own parameter gets it's own logic, but should use some sub parameters that have to be considered first. Just like the part testing contracts, where some conditions have to be met first before the actual part can be tested.

So why should i extend the ReachAltitudeEnvelop when i want to include this one as it is as a sub parameter of my own?

Anyway with my above mentioned method the sub parameter do not behave correctly...

Link to comment
Share on other sites

(also, MrHappyFace, I think you have the OnSave and OnLoad switched in your ContractParameter code)

THANK YOU for pointing this out! I'm new to modding, and I just couldn't spot where the problem was.

It's an interesting bug, though - it seems to make most of the game interface fail, and even the KSP.log can fail to be written. All of which, of course, made it a bit difficult to figure out. :)

And thanks to MrHappyFace for the original code! This is perfect for what I'm trying to do.

Link to comment
Share on other sites

Man getting my head around this and coverting Mission Controller missions to new contracts is going to be a huge task I think.

Getting a simple orbit mission with MaxApA and MinPeA to work, getting paid but for somereason the contract itself is not showing finished. Must be missing something.

I noticed the switch too in the OnLoad and OnSave. LOL. ;)

My question is. Does the OnRegister and OnUnRegister code wise have to happen at the same exact time the event is fired.

For instance having an OrbitalGoal max ApA and MinPeA set to numbers. If I use EventData<Vessel> onVesselCreate to fire my code. Then obviously this does not happen at the same time as Orbit Event I have. Only EventData I can find that comes close is the EventDate.Situtions.OnOrbit.. But again that will fire first, then it could still take player a few mins to get the exact ApA and PeA that is specified in code.

I will have to do more testing. Right now the biggest concern is why contract is not going away.

I used these events in MCE for a lot of code well before .24 and usually the code was waiting for event to fire then it completed. No idea how make my own events yet.

Edit: Think I fixed it. Hope so. The contract now finishes but still having issues finding an event that will fire at the same time that the player reaches the correct ApA and PeA. At this point you have to switch around ships to get it work.

Edited by malkuth
Link to comment
Share on other sites

Edit: Think I fixed it. Hope so. The contract now finishes but still having issues finding an event that will fire at the same time that the player reaches the correct ApA and PeA. At this point you have to switch around ships to get it work.

Can you run stuff in Update() in the contract parameter code? You might have to end up using some kind of custom event management to trigger the base.setComplete() method that completes the contract.

Link to comment
Share on other sites

Just checking in oh the Contracts front...

Oh God, /words...

Good thing my troubles with x64 crashes have kept me busy or I would probably be coding right now...

Anyways, this will all probably come handy once I do start work on my Contract Pack.

Damn, I love the KSP modding community... Give it a couple days and the right incentive and they'll probably solve 42...

Link to comment
Share on other sites

Can you run stuff in Update() in the contract parameter code? You might have to end up using some kind of custom event management to trigger the base.setComplete() method that completes the contract.

Im not sure. But I think it was a real bad decision to limit us to Events to trigger our codes if that is the case, be a huge step down from even PartModules. Must be more we can do. Be nice to just have our parameters running in something like OnFixedUpdate or something.

Link to comment
Share on other sites

Im not sure. But I think it was a real bad decision to limit us to Events to trigger our codes if that is the case, be a huge step down from even PartModules. Must be more we can do. Be nice to just have our parameters running in something like OnFixedUpdate or something.

In ContractParameter, there is a protected method you can override called OnUpdate()

Link to comment
Share on other sites

Anyway to limit the contract spam. Set up a contract that has some random values and it seems that the contract system lives to fill up its max amount of contracts with it. Noticed that if you have a contract with set values you only get one of them offered usually.

Link to comment
Share on other sites

So the OnUpdate works great. Wow, that means that contracts have become pretty dam easy to make, once I get some more framwork in for MissionGoals I should be able to write Contracts pretty quick. Nice. ;)

still like to find a way to make only 1 contract available at a time thats clean.

seems to be an Enum for state. Having issue getting it to work though.

Edited by malkuth
Link to comment
Share on other sites

MrHappyFace I ran into some serious issues with Extra Contracts last night, my waypoint code works, but yesterday I tried to implement a contract with it, and that involves setting up a waypoint object, keeping it serialized, and sending it to WaypointManager on the start of the flight scene, and deleting it from the WaypointManager at the end of the flight scene. I spent all night trying to get that seemingly simple order of operations into the game's head, but it kept throwing null reference errors (which cause the game to have a coronary).

My point is that I noticed a few things.

A: OnRegister only runs for contracts you accept, but OnUnregister seems to run for any contracts that are posted, even if you have not accepted them. This is an important distinction, because for me, OnRegister allocates memory for the object, and OnUnregister uses it. If I don't check for null in OnUnregister, the game freaks out checking all the missions on the mission board that I haven't accepted and therefore have not generated waypoints for yet.

B: I set up an event for OnFlightReady, and I checked how it's order would compare to Update, OnRegistered, and the ctor. The order seems completely random.

These things are making it hard to work, but not impossible. If it comes down to it I can write a really messy way of sending data to the WaypointManager using strings or something instead of objects.

Link to comment
Share on other sites

Anyway to limit the contract spam. Set up a contract that has some random values and it seems that the contract system lives to fill up its max amount of contracts with it. Noticed that if you have a contract with set values you only get one of them offered usually.

There is a static int: Contract.contractsInExistance that I think you can use to prevent spamming the list with your contracts. Just put a check for some max value at the top of your Generate() code.

Has anyone else been playing with the Contract.MeetRequirements() bool? I've noticed that it sometimes seems to get stuck on repeat, or is just running in Update(). When I put even a simple debug message it sometimes spams the log and sometimes doesn't. I'm not sure exactly what's going on, but maybe it's not a good idea to put much code in here if it's going to run all of the time.

Also, has anyone played around with targeting agencies based on their mentalities? Some of the mentalities in the stock agencies have "not implemented" flags in their descriptions, and they have some kind of multiplier associated with them that does something. There's probably a good way of selecting agencies based on their mentalities and reputation, I just haven't looked into it enough.

Link to comment
Share on other sites

There is a static int: Contract.contractsInExistance that I think you can use to prevent spamming the list with your contracts. Just put a check for some max value at the top of your Generate() code.

Has anyone else been playing with the Contract.MeetRequirements() bool? I've noticed that it sometimes seems to get stuck on repeat, or is just running in Update(). When I put even a simple debug message it sometimes spams the log and sometimes doesn't. I'm not sure exactly what's going on, but maybe it's not a good idea to put much code in here if it's going to run all of the time.

Also, has anyone played around with targeting agencies based on their mentalities? Some of the mentalities in the stock agencies have "not implemented" flags in their descriptions, and they have some kind of multiplier associated with them that does something. There's probably a good way of selecting agencies based on their mentalities and reputation, I just haven't looked into it enough.

All I have used it for is for a technology check for when the contract is available. Did not use any dubug code for it though.

Link to comment
Share on other sites

There is a static int: Contract.contractsInExistance that I think you can use to prevent spamming the list with your contracts. Just put a check for some max value at the top of your Generate() code.

It looks like contractsInExistance just gives you the total of all types of contracts.

Use ContractSystem.Instance.GetCurrentContracts<*YourContractType*>().Count() to find out the number of contracts of a given type. This presumably counts both active and offered contracts.

GetCurrentActiveContracts probably returns the number of accepted contracts of a given type.

Link to comment
Share on other sites

Modding Contracts

http://imgur.com/a/rOXdl

As you can see, there are now some contracts asking you to dock around Kerbin, of course, it needs some work (the insane rewards are insane), but it is basically the framework for a modded contract. It was also generated based on how far i had advanced (none at all, because it was a testing world, hence why it said Kerbin instead of Jool or something crazy like that)

Notes:

  • MOST Contract related stuff is found in the Contracts namespace
  • any class extending Contract (in the namespace Contracts) is automatically found and added

Creating a contract:

  1. Make a class that extends Contract, the game automatically finds all classes extending Contract and adds them in.
  2. override the following methods:
    • Generate()
    • CanBeCancelled()
    • CanBeDeclined()
    • GetHashString()
    • GetTitle()
    • GetDescription()
    • GetSynopsis()
    • MessageCompleted()
    • OnLoad()
    • OnSave()
    • MeetRequirements()

[*]In Generate(), you MUST call the following things:

  • base.SetExpiry()
  • base.SetScience(float reward, CelestialBody)
  • base.SetDeadlineYears(float numberOfYears, CelestialBody targetBody) OR base.SetDeadlineDays(float numberOfDays, CelestialBody targetBody)
  • base.SetReputation(float reward, float failiure, CelestialBody targetBody)
  • base.SetFunds(float advance, float reward, float failiure, targetBody)

[*]In Generate(), add some parameters using this.AddParameter(ContractParameter parameter, string id). I have no clue what id does, I just use null, which seems to work, Ill talk about ContractParameters later in this thread, but for now, just use new KerbalDeaths(), which will make you fail the contract if you kill any victims kerbals while the contract is active. The stock ContractParameters are in the namespace Contracts.Parameters, so try messing around with those.

[*]In MeetRequirements(), you can check if this contract should show up in mission control, and return false is it shouldn't and true if it should.

[*]the rest is customizable, but if you fill out the GetTitle(), GetDescription(), GetSynopsis(), and MessageCompleted(), it should show up in game. Mess around with the TextGen class (which, of course, is in the namespace Contracts)

ContractParameters:

  1. Make a class extending ContractParameter
  2. Override the following methods:
    • OnRegister()
    • OnUnregister()
    • OnLoad()
    • OnSave()
    • GetTitle()
    • GetHashString()

[*]In OnRegister(), put initialization code such as adding to a GameEvent, or instantiating a new MonoBehaviour

[*]In OnUnregister(), put code similar to what you would expect in OnDestroy(), such as removing a GameEvent added in OnRegister() or destroying a MonoBehaviour created in OnRegister()

[*]OnSave() and OnLoad() are where you handle persistence, keep in mind that in OnSave(), NEVER use node.SetValue(), ALWAYS usennode.AddValue()

[*]In GetTitle(), simply return the name of your parameter, like "Orbit " + targetBody.the name

[*]use base.SetComplete() to complete the contract.

Using ProgressTracking to select targets based on progress: such an imaginative title!

  • ​just mess around with the ProgressTracking class and the protected static methods in the Contract class, such as Contract.GetBodies_NextUnvisited(). Use these in Generate () in your contract class to select the targetBody parameter used in SetScience() and SetFunds() in your contract class. You should also pipe the targetBody parameter into the the ContractParameter you made.

Example Code:

Note: I dont care what you do with this code, its in the public domain

DockingContract.cs:


using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Contracts;
using Contracts.Parameters;
using KSP;
using KSPAchievements;
using ContractsPlus.Contracts.Parameters;

namespace ContractsPlus.Contracts
{
public class DockingContract : Contract
{
CelestialBody targetBody = null;

protected override bool Generate ()
{
targetBody = GetNextUnreachedTarget (1, true, false);
if (targetBody == null)
{
targetBody = Planetarium.fetch.Home;
Debug.LogWarning ("targetBody could not be computed, using Kerbin");
}

CelestialBodySubtree progress = null;
foreach (var node in ProgressTracking.Instance.celestialBodyNodes)
{
if (node.Body == targetBody)
progress = node;
}
if (progress == null)
{
Debug.LogError ("ProgressNode for targetBody " + targetBody.bodyName + " not found, terminating contract");
return false;
}

if (progress.docking.IsComplete)
{
Debug.Log ("Docking has already been completed for targetBody " + targetBody.bodyName + ", terminating contract");
return false;
}
bool manned = UnityEngine.Random.Range (0, 1) == 0;

this.AddParameter (new DockingParameter (targetBody, manned), null);
if (manned)
this.AddParameter (new KerbalDeaths(), null);

base.SetExpiry ();
base.SetScience (2.25f, targetBody);
base.SetDeadlineYears (1f, targetBody);
base.SetReputation (150f, 60f, targetBody);
base.SetFunds(15000f, 50000f, 35000f, targetBody);
return true;
}

public override bool CanBeCancelled ()
{
return true;
}
public override bool CanBeDeclined ()
{
return true;
}

protected override string GetHashString ()
{
return targetBody.bodyName;
}
protected override string GetTitle ()
{
return "Dock in orbit around " + targetBody.theName;
}
protected override string GetDescription ()
{
//those 3 strings appear to do nothing
return TextGen.GenerateBackStories (Agent.Name, Agent.GetMindsetString (), "docking", "dock", "kill all humans", new System.Random ().Next());
}
protected override string GetSynopsys ()
{
return "Dock two vessels in orbit around " + targetBody.theName;
}
protected override string MessageCompleted ()
{
return "You have succesfully docked around " + targetBody.theName;
}

protected override void OnLoad (ConfigNode node)
{
int bodyID = int.Parse(node.GetValue ("targetBody"));
foreach(var body in FlightGlobals.Bodies)
{
if (body.flightGlobalsIndex == bodyID)
targetBody = body;
}
}
protected override void OnSave (ConfigNode node)
{
int bodyID = targetBody.flightGlobalsIndex;
node.AddValue ("targetBody", bodyID);
}

//for testing purposes
public override bool MeetRequirements ()
{
return true;
}

protected static CelestialBody GetNextUnreachedTarget(int depth, bool removeSun, bool removeKerbin)
{
var bodies = Contract.GetBodies_NextUnreached (depth, null);
if (bodies != null)
{
if (removeSun)
bodies.Remove (Planetarium.fetch.Sun);
if (removeKerbin)
bodies.Remove (Planetarium.fetch.Home);

if (bodies.Count > 0)
return bodies [UnityEngine.Random.Range (0, bodies.Count - 1)];
}
return null;
}
}
}

DockingParameter.cs:


using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Contracts;
using KSP;
using KSPAchievements;

namespace ContractsPlus.Contracts.Parameters
{
public class DockingParameter : ContractParameter
{
public CelestialBody targetBody;
public bool manned = false;

public DockingParameter(CelestialBody target, bool manned)
{
this.targetBody = target;
this.manned = manned;
}

protected override string GetHashString ()
{
return targetBody.bodyName;
}
protected override string GetTitle ()
{
return "Dock two vessels in orbit around " + targetBody.theName;
}

protected override void OnRegister ()
{
GameEvents.onPartCouple.Add (OnDock);
}
protected override void OnUnregister ()
{
GameEvents.onPartCouple.Remove (OnDock);
}

protected override void OnSave (ConfigNode node)
{
int bodyID = int.Parse(node.GetValue ("targetBody"));
foreach(var body in FlightGlobals.Bodies)
{
if (body.flightGlobalsIndex == bodyID)
targetBody = body;
}
}
protected override void OnLoad (ConfigNode node)
{
int bodyID = targetBody.flightGlobalsIndex;
node.AddValue ("targetBody", bodyID);
}

private void OnDock(GameEvents.FromToAction<Part, Part> action)
{
if (manned)
{
if (action.from.vessel.GetVesselCrew ().Count > 0 && action.to.vessel.GetVesselCrew ().Count > 0)
{
if (action.from.vessel.mainBody == targetBody && action.to.vessel.mainBody)
{
base.SetComplete ();
}
}
}
else
{
if (action.from.vessel.mainBody == targetBody && action.to.vessel.mainBody)
{
base.SetComplete ();
}
}
}
}
}

:)

Feel free to contribute and/or correct me if im wrong.

Ok, if you do not mind, I have a stupid question. Is the function "OnDock()" a function that we are overriding or is a function we are completely defining from scratch?

Thank you.

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...