Jump to content

[1.10.1+] Contract Configurator [v1.30.5] [2020-10-05]


nightingale

Recommended Posts

Hey @nightingale,

I am still running into problems with ships and stations properly being identified when they are the target of a docking. Here is what is happening...

The player launches the core of Space Station Mir. It is set to be defined properly (as far as I know):

PARAMETER
	{
		name = Mir
		type = VesselParameterGroup
		title = Mir
		define = Mir

This contract completes fine (there are many parameters to it), but the issues arrive in the next set of contracts. The next set of contracts requires the player to bring up specific modules that made up Mir. Here is the example of the Kvant contract:

PARAMETER
	{
		name = Kvant-1
		type = VesselParameterGroup
		title = Kvant 1
		define = Kvant-1
		
		PARAMETER
		{
			name = NewVessel
			type = NewVessel
			hidden = true
		}
		PARAMETER 
		{
			name = Crewmembers
			type = HasCrew
			minCrew = 0
			maxCrew = 0
			title = Unmanned
			hideChildren = true
		}
		PARAMETER
		{
			name = DockingPort
			type = PartValidation
			partModuleType = Dock
			minCount = 1
			title = Have at least 1 Docking Port
			hideChildren = true
		}
		PARAMETER
        {
            name = ScienceLab
            type = PartValidation
            title = Have a Science Lab on board
            hideChildren = true
            partModule = ModuleScienceLab
        }
		PARAMETER
		{
			name = DockWithMir
			type = Docking
			vessel = Mir
			title = Dock with Mir
			hideChildren = true
		}
	}

The contract system recognizes success on all of the parameters, but it never completes the DockWithMir part.

 

I have other contracts that are written the same way that suffer the same issues. I am guessing that it is something on my end. Should I be defining them in a different way if I need them to persist from contract to contract?

Thanks for your help!

Link to comment
Share on other sites

I am also having an issue with the sortKey function on the Contract Groups. They are not actually working and I am getting a Warning Error on them:

TmTPaet.png

 

And here it is in the config file, seems like they should work as they are children of the main one:

CONTRACT_GROUP
{
	name = HistoricalProgression
	displayName = Historical Progression
	agent = Historical Progression
	minVersion = 1.16.0
	maxSimultaneous = 100
	maxCompletions = 0
	
	disabledContractType = ExploreBody
	disabledContractType = WorldFirstContract

	CONTRACT_GROUP
	{
		name = ApolloProgram
		displayName = Apollo Program
		agent = Apollo Program
		maxSimultaneous = 10
		maxCompletions = 0
		sortKey = 6
	}
	
	CONTRACT_GROUP
	{
		name = Apollo-Soyuz
		displayName = Apollo Soyuz Test Project
		agent = Apollo Soyuz Test Project
		maxSimultaneous = 10
		maxCompletions = 0
		sortKey = 8
	}

 

Link to comment
Share on other sites

A while ago I found acontract pack that made more use of space stations. You had to rotate crews and repair stuff by EVA'ing and stuff, in stead of the "build station, destroy and build a new one" in stock. Does anyone know where I can find this pack? I cannot find it :( . 

Link to comment
Share on other sites

16 minutes ago, hugix said:

A while ago I found acontract pack that made more use of space stations. You had to rotate crews and repair stuff by EVA'ing and stuff, in stead of the "build station, destroy and build a new one" in stock. Does anyone know where I can find this pack? I cannot find it :( . 

I could be wrong, but I think you are looking for this:

...which is an excellent contract pack that adds crew rotations contracts, station expansion contracts, the odd emergency evacuation... It also adds contracts to re-stock life support resources if you have certain LS mods installed, and if you have ScanSat it will also add contracts to find the perfect ground base location by scanning and sending rovers before you start to build surface bases.

Link to comment
Share on other sites

New release, download here!  The orbit/waypoint disabling is fairly basic (you can't select by contract), and doesn't affect the stock contracts (I may look at it for a future release).  Let me know what you guys think!

Contract Configurator 1.17.0

  • Mission Control remembers the last visited tab when you open it, and takes you there.
  • Added Tracking Station buttons for filtering orbits/waypoints from contracts.
  • Added support for adding loading tool tips.
  • Better support for Kolniya/Tundra orbits - will error if the orbit would exit the SOI.  Also added CelestialBody methods to determine if the body is allowed to have Kolniya/Tundra orbits.
  • Fix for contracts not being offered on a brand new save until at least one stock contract is offered (thanks to all the RP-0 users who reported this).
  • Fixed issue where parameter completion data wasn't correctly copied to newly created vessel on undock/decouple (thanks linuxgurugamer).
  • Fixed DraftTwitchViewers support.
  • Fixed issue with using Enter button to go to Mission Control (thanks Deimos Rast).
  • Fixed agent for stock satellite contracts.
  • Fixed issue with sortKey in child contract groups (thanks pap1723).
Link to comment
Share on other sites

On 08/08/2016 at 3:05 AM, nightingale said:

Send you  a PR with the fix (but just for the one contract, I assume you have the same issue in others).  I don't have a good way to make it more transparent, although the DEBUG log message gives a *slight* hint as to the problem:


[DEBUG] ContractConfigurator.ExpressionRequirement: Contract CleverSatCore: requirement Expression was not met.
[DEBUG] ContractConfigurator.ContractType: Cancelling contract of type CleverSatCore (Put a new Satellite in orbit of Kerbin): Failed on contract requirement check.

 

I saw those errors, and thought it was a result of the random number being re-rolled (which I guess it kinda was).

Anyway, that seems to have fixed it, but you might want to update the docs - it says (emphasis mine):

Most requirements are not checked for active contracts (to
    // prevent the contract from being withdrawn while the player is
    // actively working to complete it). 

however, this seems to also be working on offered contracts (which is what I needed)

Link to comment
Share on other sites

On 8/8/2016 at 0:16 PM, nightingale said:

@pap1723 - At a glance your vessel stuff looks good. Can you provide a save from right before docking and I'll take a look?

As to the child group thing - I've fixed that check so that it works properly for the next release.

I've been doing some digging (I don't have a great saved file to share with you yet) and here is what I think is happening:

I have a contract called Mir that is to put up a space station core. Then I have a 2nd contract that is to attach a module to that core. This one completes fine. The next contract is to bring a crew to Mir, but this (and all subsequent contracts) no longer recognize Mir as a valid docking target. So after the docking happens, it would seem that the station is losing its Define attribute of Mir.

Is there a way I can set the Define value of the new contract even after it has other modules dock to it?

Link to comment
Share on other sites

Exception occured while attempt to generate contract of type 'STGUnmannedMissions.Kolniya Orbital Satellite':
System.ArgumentException: Cannot use a Kolniya orbit with Ike.
  at ContractConfigurator.Behaviour.OrbitGenerator.ValidateOrbitType (ContractConfigurator.Behaviour.OrbitData obData, ContractConfigurator.Behaviour.OrbitGeneratorFactory factory) [0x00000] in <filename unknown>:0 
  at ContractConfigurator.Behaviour.OrbitGenerator..ctor (ContractConfigurator.Behaviour.OrbitGenerator orig, Contracts.Contract contract) [0x00000] in <filename unknown>:0 
  at ContractConfigurator.Behaviour.OrbitGeneratorFactory.Generate (ContractConfigurator.ConfiguredContract contract) [0x00000] in <filename unknown>:0 
  at ContractConfigurator.BehaviourFactory.GenerateBehaviours (ContractConfigurator.ConfiguredContract contract, System.Collections.Generic.List`1 behaviourNodes) [0x00000] in <filename unknown>:0 
  at ContractConfigurator.ContractType.GenerateBehaviours (ContractConfigurator.ConfiguredContract contract) [0x00000] in <filename unknown>:0 
  at ContractConfigurator.ConfiguredContract.Initialize (ContractConfigurator.ContractType contractType) [0x00000] in <filename unknown>:0 

Just got this in my game. Not sure what it means, but it said to paste here so that's what I'm doing. 

Link to comment
Share on other sites

9 hours ago, severedsolo said:

I saw those errors, and thought it was a result of the random number being re-rolled (which I guess it kinda was).

Anyway, that seems to have fixed it, but you might want to update the docs - it says (emphasis mine):


Most requirements are not checked for active contracts (to
    // prevent the contract from being withdrawn while the player is
    // actively working to complete it). 

however, this seems to also be working on offered contracts (which is what I needed)

No, the check is only for active contracts, so after giving it some more thought, I'd be highly surprised if my fix actually fixed your problem (in fact, the change I made should be completely unnecessary).  So, a quick primer on the internals of data nodes and expressions is needed for background.  This is what happens when a contract generation attempt is made:

  1. Basic requirements are checked - this is stuff that should not depend on expressions (maxCompletions, maxSimultaneous).  This is done early to eliminate the need to execute expression (expensive!) if we can easily decide the contract should not generate
  2. Expressions for non-deterministic values are executed.  A non-deterministic value being something where the value can't be determined at game start.  HomeWorld().Children() is deterministic - we only need to run that once, and it's always going to be [ Mun, Minmus ] (yes, Kopernicus can change this, but not without restarting KSP, which is what's important). AllVessels() is non-deterministic, because the player creates/destroys vessels all the time.
    1. The values are stored in an internal DataNode (similar to the config DATA_NODE) against the ContractType (note - not the Contract).
  3. Data with a uniqueness check is stored against the contract.
  4. Extended requirements are checked.  This is everything that depends on expressions, such as uniqueness checks and REQUIREMENT nodes.
  5. Contract initialization is done. This is where the Parameters are generated from ParameterFactories (going from ContractType to Contract).  This step is what creates a Contract that is now independent from the ContractType.

If it gets through all that, it's stored internally and the periodic Update() calls will re-check requirements (and expiry date, and stuff like that).  What's missing is the copy of the requirement data from the ContractType to the Contract in the initialize setp - the refactor of 1.15 inadvertently moved that from contract generation to contract save time.  So the RNG value you were rolling could effectively be re-rolled for contracts for the time between contract generation and contract save (eg. doing a quick save).

TL;DR - this really was a bug, and I've fixed it for the next release.


5 hours ago, pap1723 said:

I have a contract called Mir that is to put up a space station core. Then I have a 2nd contract that is to attach a module to that core. This one completes fine. The next contract is to bring a crew to Mir, but this (and all subsequent contracts) no longer recognize Mir as a valid docking target. So after the docking happens, it would seem that the station is losing its Define attribute of Mir.

Is there a way I can set the Define value of the new contract even after it has other modules dock to it?

Docking is messy and nasty in KSP, so it's entirely possible that there's a bug here, and entirely possible that it needs the unique circumstances that you have set up (docking port vs. claw, relative position of root part vs. docking ports, which ship is active on docking).  So what you need to look for is a section called ContractVesselTracker in your save.  You should have an entry in there that looks something like this:

		VESSEL
		{
			key = Mir
			id = f6dc8fbc-9c90-4525-93f5-83d5e7a90571
			hash = 771082057
		}

The id can change (if you dock, the vessel with that id should cease to exist), but the hash should stay the same (the hash identifies a connected graph of parts that shouldn't detach under normal circumstances - so the minimum set of parts between docking ports/decouplers/claws).  If the Mir section is disappearing, you have a problem.  If the hash is changing...  you may have a lesser problem.

So it sounds like attaching the module is the trigger that is causing that section to get lost.  So what I need you to do is confirm that's what's happening in the save, and then provide me the quicksave from right before the docking so I can reproduce with your particular vessel.


@HoveringKiller - This was due to a change introduced in Contract Configurator 1.17.0 to prevent invalid Kolniya orbits from being generated.  @linuxgurugamer should've already released the update to Unmanned Contracts to prevent that error from occurring.
Link to comment
Share on other sites

13 minutes ago, nightingale said:

@HoveringKiller - This was due to a change introduced in Contract Configurator 1.17.0 to prevent invalid Kolniya orbits from being generated.  @linuxgurugamer should've already released the update to Unmanned Contracts to prevent that error from occurring.

It was released yesterday.

Link to comment
Share on other sites

Thanks @nightingale, I will get those to you hopefully tonight or tomorrow.

Also, sortKey is not working still. It is no longer spitting out a warning, but the sorttKey numbers are not being used, not for the order of the contract groups, nor for the contracts inside of the contract groups.

It is still sorted alphabetically.

Link to comment
Share on other sites

With the new version of Contract Configurator I'm starting to revisit some ideas I had for a techtree replacement contract pack. If you recall, I originally had the "scavenger" idea and it didn't work well (Nothing to do with Contract Configurator. It was just a bad idea that looked good on paper). I had another idea but it wouldn't have worked before and now (that you can see all possible contracts and they are always available) I think it might, but it needs one thing that I am not quite sure of how to do, or even if I can do it.

What I need is to be able to "toggle" contracts on and off in a simple, user-friendly way. For example, let's say you want to unlock some wing parts. You - as the player - should be able to do something (Perhaps take a "I want to unlock wings" contract that just completes automatically and thereby sets up a valid prereq for all the wing-related part contracts). Then, all wing contracts become available and you can select as many as you want. Then, you need to be able to toggle them off so the available wing contracts don't clutter up your contract list.

Is there a way to do this? I see from the documentation that I can do the first part. I can set it up to not enable the Wing contracts until the player has successfully completed the "I want to research wings" contract. However, I don't see how I could then disable the Wing contracts when the player successfully completes a "I don't want to research wings anymore" contract.

Also, is there a way for a contract to just auto-complete? Could I just do something like "Not plant a flag on Jool" and the game will just auto complete the contract as I've not done that? Or would that break something? If you don't know I can test this, but I don't want to start at all unless I can be at least reasonably sure I can also get the above - much harder in my mind - part working.

Link to comment
Share on other sites

26 minutes ago, 5thHorseman said:

With the new version of Contract Configurator I'm starting to revisit some ideas I had for a techtree replacement contract pack. If you recall, I originally had the "scavenger" idea and it didn't work well (Nothing to do with Contract Configurator. It was just a bad idea that looked good on paper). I had another idea but it wouldn't have worked before and now (that you can see all possible contracts and they are always available) I think it might, but it needs one thing that I am not quite sure of how to do, or even if I can do it.

What I need is to be able to "toggle" contracts on and off in a simple, user-friendly way. For example, let's say you want to unlock some wing parts. You - as the player - should be able to do something (Perhaps take a "I want to unlock wings" contract that just completes automatically and thereby sets up a valid prereq for all the wing-related part contracts). Then, all wing contracts become available and you can select as many as you want. Then, you need to be able to toggle them off so the available wing contracts don't clutter up your contract list.

I don't quite understand the idea (probably because I'm tired).  But let me make sure we're on the same page, as I'm worried there's a misunderstanding when you say "toggle" contracts.

A contract in Mission Control can have the following states:

  1. Unavailable (greyed out).  A contract can't be generated, for whatever reason
  2. Completed (greyed out, green checkmark).  Special case of unavailable for maxCompletions = 1 with the contract completed
  3. Offered (yellow)
  4. Active (green)

So when you say toggle - which two states are you looking to toggle between?

26 minutes ago, 5thHorseman said:

Is there a way to do this? I see from the documentation that I can do the first part. I can set it up to not enable the Wing contracts until the player has successfully completed the "I want to research wings" contract. However, I don't see how I could then disable the Wing contracts when the player successfully completes a "I don't want to research wings anymore" contract.

As I understand the question, I think you need to use expressions and set flags. So in your "enable wing" contract, do this:

BEHAVIOUR
{
    type = Expression

    CONTRACT_ACCEPTED
    {
        type = bool
        ResearchWings = true
    }
}

For "disable wing" do this:

BEHAVIOUR
{
    type = Expression

    CONTRACT_ACCEPTED
    {
        type = bool
        ResearchWings = false
    }
}

For each of the contracts in the wing "group":

REQUIREMENT
{
    type = Expression
    expression = $ResearchWings
}

The above should be checked on active contracts by default.  So they will fail if you set ResearchWings to false.

26 minutes ago, 5thHorseman said:

Also, is there a way for a contract to just auto-complete? Could I just do something like "Not plant a flag on Jool" and the game will just auto complete the contract as I've not done that? Or would that break something? If you don't know I can test this, but I don't want to start at all unless I can be at least reasonably sure I can also get the above - much harder in my mind - part working.

Not an easy way, but you can do what @inigma does and set a 1 second timer.  See here.

Link to comment
Share on other sites

1 hour ago, nightingale said:

A contract in Mission Control can have the following states:

  1. Unavailable (greyed out).  A contract can't be generated, for whatever reason
  2. Completed (greyed out, green checkmark).  Special case of unavailable for maxCompletions = 1 with the contract completed
  3. Offered (yellow)
  4. Active (green)

So when you say toggle - which two states are you looking to toggle between?

I believe I want to toggle between Unavailable and Offered. I want none of the part contracts available to even see, until toggled on. Then I want them to be Offered so you can accept the ones you want, and then I want whatever Offered ones are left to be able to be toggled back to Unavailable. Until such time as the player wants to toggle them back to Offered.

In theory this is unnecessary; I could just have all 200+ "Research this part" contracts available at all times. However I don't think this would be a good user experience :)

I'll fiddle with the examples you gave, and that 1 second timer seems perfect. I didn't even notice that in the wiki. Thanks!

Link to comment
Share on other sites

I have borrowed and used ideas from many of the great mod authors from this thread and I wanted to provide something that I thought works really well for Contract Packs. @nightingale has done a great job of making it so that these Contract Packs can work whether the player is using the stock system, or any other number of the custom universes that are out there.

One of the biggest things that I have found is that there is a big discrepancy in the amount of rewards that the player should receive depending on the size of the solar system they are using. I came up with what I think is a rather clever system. The Funds Rewards and Advances are all based on the Radius of the Home Planet. That way, if the player is playing on stock size, 2x, 6.4x or RSS scale, the payouts would scale with the sizes.

Now, there will obviously still need balancing based on your contract system, but these are the numbers that I have found work for what my contract pack looks to do. The great thing about this is that you can change the payouts of all of your contracts very quickly by changing only a couple of numbers.

The information for payouts is stored in a DATA node that is loaded with the CONTRACT_GROUP. This allows the payouts to be available for every contract. Here is my syntax:

DATA
	{
		type = double
		Kerbucks = ( HomeWorld().Radius() / 1000 ) * 20
		Kerbucks2 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 2
		Kerbucks3 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 3
		Kerbucks4 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 4
		Kerbucks5 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 5
		Kerbucks6 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 6
		Kerbucks7 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 7
		Kerbucks8 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 8
		Kerbucks9 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 9
		Kerbucks14 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 14
		Kerbucks17 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 17
		Kerbucks21 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 21
		Kerbucks42 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 42
		Kerbucks125 = (( HomeWorld().Radius() / 1000 ) * 20 ) * 125
		title = Money, money, money, money!
	}

I understand that the code cold be cleaned up a little, but this is what worked best for me. Here is what it is doing:

It takes the radius of the planet, which is returned in Meters and converts that to kilometers. Then it multiplies that value by 20 to get the base value for each contract.

Stock Kerbin = 12,000 base payout (600,000 m Radius / 1000 = 600 * 20)
2x Kerbin = 24,000
6.4x Kerbin = 76,800
Half Size RSS = 63,710
RSS = 127,420

The rest of the values allow me to control the rewards and payouts for each individual contract. My numbers correspond to the amounts that I want to reward for each contract. Obviously there are times where the numbers do not work out perfectly, but I believe those are rare situations.

You could also simplify it by just taking the radius of the planet and dividing it by 100. For Kerbin, that would give you a base value of $6,000 and for RSS it would give you a base value of 63,710.

 

When it comes time for you to set the rewards for your contracts, it is very easy to reference:

rewardFunds = 		@HistoricalProgression:Kerbucks
advanceFunds = 		@HistoricalProgression:Kerbucks2

The @ sign is what calls the data, the part before the : (colon) is the name of the Contract Group and then obviously afterwards are the variables that you are calling for each contract.

 

Hopefully this makes sense to all of you and please let me know if you have any questions about how I implemented it and anything that I may have not made clear.

Edited by pap1723
A little more clarity
Link to comment
Share on other sites

@5thHorseman - There's a bug in that Expression requirement that will cause you grief - the value for $ResearchWings in that example is calculated at contract offer time, but it really needs to be done at each check.  I'll need a bit to fix that one.

That being said, if you're okay with all contracts being offered, then I think maybe what you really want is child contract groups (so you can have a Wings contract group under your main group, and put all the wing contracts in there).

@pap1723 - Interesting approach!

Link to comment
Share on other sites

Hi there,

I'm looking to dress the list of monopropellants available in RO. So I dress the list like this :
 

DATA:NEEDS[RealFuels]
{
	type = List<Resource>
	monoPropellant = [ Hydrazine, Helium, UH25, Aerozine50, HTP, Nitrogen, Aniline, IWFNA, IRFNA-III, IRFNA-IV, Nitrogen, NitrousOxide ]
}

But I get an exception saying that the '-' in IRFNA-III and IRFNA-IV are interpreted as the minus operator.
Trying to use the Resource constructor Resource(string identifier) like this :
 

DATA:NEEDS[RealFuels]
{
	type = List<Resource>
	monoPropellant = [ Hydrazine, Helium, UH25, Aerozine50, HTP, Nitrogen, Aniline, IWFNA, Resource("IRFNA-III"), Resource("IRFNA-IV"), Nitrogen, NitrousOxide ]
}

Then I got an exception telling me that a string cannot be casted to a Resource object.
I tried also to expand the minus with a backquote, but that doesn't work too.
What's the way to get it to work?
Thanks

Link to comment
Share on other sites

@hargn - You managed to find not one, but two bugs/limitations in the resource parser.  I've fixed both for the next release (I only added - and _ to the list of value resource characters, so if there's any other ones you can always fall back on to the string method now).

Link to comment
Share on other sites

@nightingale,

I see that the notes say that the Kolniya method has been added, but I'm getting an error.  So, before I start with the debugging, can you tell me if this is correct.  the following is in the CONTRACT_GROUP:

  	DATA
  	{
  		type = CelestialBody
		hidden = true
		requiredValue = false

		// Following line works
 		UnmannedMissionPlanet = Prestige() == Trivial ? @/easyPlanets.Random() : Prestige() == Significant ? @/mediumPlanets.Random() : @/hardPlanets.Random()

		Following line seems to generate error
 		KolniyaMissionPlanet = Prestige() == Trivial ? @/easyPlanets.CanHaveKolniyaOrbit().Random() : Prestige() == Significant ? @/mediumPlanets.CanHaveKolniyaOrbit().Random() : @/hardPlanets.CanHaveKolniyaOrbit().Random()

  	}	

and the following is in the contract:

 	DATA
 	{
 		type = String
 
 		hidden = true
 		uniquenessCheck = GROUP_ALL
 		requiredValue = true
 
 		uid = KolniyaOrbitalSatellite:@STGUnmannedMissions:KolniyaMissionPlanet.Name()
 	}

 

Link to comment
Share on other sites

On 30/07/2016 at 7:20 PM, linuxgurugamer said:

 

1 hour ago, linuxgurugamer said:

@nightingale,

I see that the notes say that the Kolniya method has been added, but I'm getting an error.  So, before I start with the debugging, can you tell me if this is correct.  the following is in the CONTRACT_GROUP:


  	DATA
  	{
  		type = CelestialBody
		hidden = true
		requiredValue = false

		// Following line works
 		UnmannedMissionPlanet = Prestige() == Trivial ? @/easyPlanets.Random() : Prestige() == Significant ? @/mediumPlanets.Random() : @/hardPlanets.Random()

		Following line seems to generate error
 		KolniyaMissionPlanet = Prestige() == Trivial ? @/easyPlanets.CanHaveKolniyaOrbit().Random() : Prestige() == Significant ? @/mediumPlanets.CanHaveKolniyaOrbit().Random() : @/hardPlanets.CanHaveKolniyaOrbit().Random()

  	}	

and the following is in the contract:


 	DATA
 	{
 		type = String
 
 		hidden = true
 		uniquenessCheck = GROUP_ALL
 		requiredValue = true
 
 		uid = KolniyaOrbitalSatellite:@STGUnmannedMissions:KolniyaMissionPlanet.Name()
 	}

 

On mobile, so won't be full code.  You need something like this:

@/mediumPlanets.Where(cb => cb.CanHaveKolniyaOrbit()).Random()

Link to comment
Share on other sites

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