Proposals for Oolite 1.79/1.80, 4 of 5: New system populator
Posted: Tue Jun 18, 2013 6:08 pm
Here's the fourth one for comments. As with the last one there's a block in italics near the end where I can see arguments for doing this either way and don't have a strong preference.
Scriptable System Populator
A rewrite of the system populator to allow more JS control of system population.
Problem:
System populator is inflexible and does not expose enough information about the system. Difficult for OXPs to determine what system contents other OXPs are adding if interactions needed. Difficult for OXPs to override aspects of system populator either selectively or fully. Timing of system population for OXPs is variable - startUp, and various launch/witchspace events.
Ships added near witchpoint generate rings, which are often unwanted but require silly hacks to avoid.
If we later bring in support for adding new systems/galaxies will need easier way for OXPers to stop them looking exactly like the old ones.
Proposal:
Populator is controlled by an dictionary of dictionaries.systemWillPopulate()
orinterstellarSpaceWillPopulate()
event will be called in worldscripts to allow modification of it (two separate events because virtually no-one wants to do the same thing for both!). Called at usual system population time (just beforeshipWillExitWitchspace
).
It will then be possible to set a different function name inplanetinfo.plist
or through theSystemInfo
object to call when populating the system. (For example, the nova mission would change the function tonovaSystemWillPopulate
after the event has occurred) This makes it easy for specific systems to have completely different population rules.
Event order on game start would be modified slightly so that only planet(s), sun, mainStation and player added initially. Then JSstartUp()
called. Then populator functions called.
Ships added by populator don't generate rings.
Addition from other JS functions (or even legacy code) of course still possible, but discouraged as a means of populating the system.
To fix minor bug with compass and commie astromines, nav/witchbuoy addition to happen before asteroids added.
Populator functions return a dictionary of dictionaries. Later-running populator functions may overwrite entries from earlier ones - though of course beyond "core scripts run before OXP scripts" inter-script communications may be needed to manage this as execution order is undefined; in practice changing the name of the population function is likely to be a better way to adjust system population ... this is mainly intended to allow overriding of the core populator. Asystem.populator
read-only property may be used to query the existing entries, which would look like this.(Note: these are examples, not the values actually used by the current or future system populator)Code: Select all
"oolite-route2-pirates" : { priority: 2, // default 100 location: "LANE_PS", // default "LANE_WP" locationSeed: 0, // optional, default 0 groupCount: 10 - system.government, // default 1 callback: function(pos) { var num = 1+Math.floor(Math.random()*5); system.addGroup("pirate",num,pos,5E3); }, // required, no default deterministic: false // optional, default false }
priority
: 0..65535. All priority X run in arbitrary order, then move on to next lowest X.
location
can be "LANE_WP", "LANE_PS", "LANE_WS", "WITCHPOINT", "STATION_AEGIS", "PLANET_ORBIT", "STAR_ORBIT", "PLANET_ORBIT_HIGH", "STAR_ORBIT_HIGH", "PLANET_ORBIT_LOW", "STAR_ORBIT_LOW", "TRIANGLE", "INNER_SYSTEM", "OUTER_SYSTEM", "INNER_SYSTEM_OFFPLANE", "OUTER_SYSTEM_OFFPLANE", or a vector expression. In interstellar space, all named locations are equivalent to WITCHPOINT. Named locations are translated to a vector at callback time to spread out groups.
- WITCHPOINT: picks a location within scanner range of the witchpoint.
- STATION_AEGIS: picks a location within twice scanner range of the main station.
- LANE_*: picks a location within LANE_WIDTH (probably set to 2x scanner range) of a random point between the two endpoints, at least three radii from the centre of the object and at least scanner range from the witchpoint.
- *_ORBIT: picks a random point between 1 and 3 radii from the surface of the main planet or sun. The _LOW suffix changes this to be between 0.1 and 1 radii, and _HIGH is between 3 and 7 radii.
- TRIANGLE: picks a random point on the triangle formed by sun, witchpoint, and planet, at least 3 radii from the sun and planet, and 3 scanner radii from the witchpoint
- INNER_SYSTEM: picks a random point closer to the sun than the planet is (but at least 3 radii out), within 50km of the triangle plane
- OUTER_SYSTEM: picks a random point further from the sun than the planet is (but not more than 10^7 metres away), within 1% of the triangle plane
- *_OFFPLANE: picks a point as for *_SYSTEM but without the orbital plane constraints.
locationSeed
if set and greater than zero seeds the random number generator used for the named locations. Seeded locations would be system-specific: PLANET_ORBIT 3 is not going to be in the same place relative to the witchpoint and sun from one system to another.
Other named regions could be added if needed, though since at the start of the populator run the only known positions are the planet, sun, main station, and witchpoint, they would have to be relative to those in some way.
The *_SYSTEM and especially *_SYSTEM_OFFPLANE placements depend on the coordinate precision being improved to double-precision to be much use, so might be left for a later version.
Thecallback
function will be calledgroupCount
times. If the location was not a vector expression, then the callback will get a new random position each time (if it was a vector expression, there's not much point in havinggroupCount
> 1). If the named location is seeded, the RNG will only be seeded before generating the first location: so the rest will also be deterministic based on the seed and the count, but distinct from the first location.
deterministic
is a statement (unenforceable) that if the system is regenerated later (at least using the same populator function, and without the player leaving the system and returning with some state changed), this populator call will be made again in exactly the same way and will achieve the same results. It is forced to false if the location is an unseeded named location, and perhaps in other circumstances (e.g. sun gone nova).
At the moment, this doesn't do anything, but my reason for including it now is that for some later version is that stations populated with the deterministic flag could have save/load. So save at the local Constore, which will 'always' be there (with fallbacks for OXPset changes (re)moving it, of course) but not on that Super Bulk Hauler that happens to be there right now but won't be later.
Oolite would for 1.79/1.80 add default population functions to approximately match the current situation. The semi-persistent rock hermits might change location on the switchover, since keeping identical RNG behaviour would be trickier, but that's probably not important since they were going to move anyway.
OXPs callingsystem.addShips
/addGroup
onshipWillExitWitchspace
,startUp
and oftenshipWillLaunchFromStation
should then be encouraged to use the system populator instead. This will allow other OXPs to completely remake a system, sector or even galaxy without needing to worry too much about which of the more generic flavour OXPs a player has installed.
Repopulation
The current repopulation mechanism is that ships exiting the system to witchspace usually cause a new ship with the same primary role to be added later on. In general most ships leaving this way are traders launched from stations, so the system tends over time to only have traders in it.
This could be replaced by a set of repopulation functions using the same methods as above: default namessystemWillRepopulate()
orinterstellarSpaceWillRepopulate()
. These would be called from time to time and would add new ships to the system - most likely byaddShips
at the witchpoint but equally these functions might call the various launch methods of stations.
How often should they run? Every minute? Every five minutes? Every time a ship leaves and/or is destroyed? Should the expectation be for the core Oolite populator that it adds something every time repopulation is called, or should it be called more often and most of the time not queue anything?
In general the repopulation functions would not be doing anywhere near as much ship addition as the initial population, of course. Witchspace exit rings would be generated as usual for repopulating the system.