Back to Index Page generated: Dec 20, 2024, 7:22:09 AM

Expansion Planetfall

Content

Warnings

  1. Required Expansions mismatch between OXP Manifest and Expansion Manager at character position 0070 (DIGIT ZERO vs LATIN SMALL LETTER N)
  2. No version in dependency reference to oolite.oxp.phkb.PlanetFall_Resources:null
  3. No version in dependency reference to oolite.oxp.Svengali.GNN:null
  4. No version in dependency reference to oolite.oxp.Svengali.Library:null
  5. No version in dependency reference to oolite.oxp.phkb.MarketScriptInterface:null
  6. No version in dependency reference to oolite.oxp.phkb.PlanetRotationCosmetics:null
  7. No version in dependency reference to oolite.oxp.SMax.PlanetFallMarketSaver:null
  8. No version in dependency reference to oolite.oxp.Norby.Planetfall_Markets:null
  9. Optional Expansions mismatch between OXP Manifest and Expansion Manager at character position 0073 (DIGIT ZERO vs LATIN SMALL LETTER N)
  10. Conflict Expansions mismatch between OXP Manifest and Expansion Manager at character position 0071 (DIGIT ZERO vs LATIN SMALL LETTER N)

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Allows landing on planets and moons in the system at various locations. Allows landing on planets and moons in the system at various locations.
Identifier oolite.oxp.Thargoid.Planetfall oolite.oxp.Thargoid.Planetfall
Title Planetfall Planetfall
Category Dockables Dockables
Author Thargoid, phkb Thargoid, phkb
Version 2.15 2.15
Tags dockables, system dockables, system
Required Oolite Version
Maximum Oolite Version
Required Expansions
  • oolite.oxp.phkb.PlanetFall_Resources:0
  • oolite.oxp.Svengali.GNN:0
  • oolite.oxp.Svengali.Library:0
  • oolite.oxp.phkb.MarketScriptInterface:0
  • oolite.oxp.phkb.ExternalDockSystem:1.7
  • oolite.oxp.phkb.PlanetFall_Resources:
  • oolite.oxp.Svengali.GNN:
  • oolite.oxp.Svengali.Library:
  • oolite.oxp.phkb.MarketScriptInterface:
  • oolite.oxp.phkb.ExternalDockSystem:1.7
  • Optional Expansions
  • oolite.oxp.phkb.PlanetRotationCosmetics:0
  • oolite.oxp.phkb.PlanetRotationCosmetics:
  • Conflict Expansions
  • oolite.oxp.SMax.PlanetFallMarketSaver:0
  • oolite.oxp.Norby.Planetfall_Markets:0
  • oolite.oxp.SMax.PlanetFallMarketSaver:
  • oolite.oxp.Norby.Planetfall_Markets:
  • Information URL http://wiki.alioth.net/index.php/Planetfall2_OXP n/a
    Download URL https://wiki.alioth.net/img_auth.php/1/1f/PlanetFall2.oxz n/a
    License Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme file Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme file
    File Size n/a
    Upload date 1725843326

    Documentation

    Also read http://wiki.alioth.net/index.php/Planetfall

    Developers ReadMe.txt

    Planetfall OXP by Thargoid and phkb
    ===================================
    
    This OXP is designed to be extendable to add new locations on planets and moons, and to give locations for mission events to take place. For this a number of variables are made available within the scripting. These scripts are accessible from any javascript worldscript within a game OXP.
    
    worldScripts.PlanetFall2.lastPlanet - this is the last planet to be approached.
    worldScripts.PlanetFall2.lastPlanetType - the type of the last planet landed on ("Prime", "Sub" or "Moon") or approached ("Sun" or "GasGiant").
    worldScripts.PlanetFall2.planetCount - how many planets (bodies with atmospheres) in the system.
    worldScripts.PlanetFall2.moonCount - how many moons (bodies without atmospheres) in the system.
    
    When the player is planet-side, and they utilise the transit system, they could end up a long way from where they initially landed. To know when the player is not near their ship, use the following function:
    
    worldScripts.PlanetFall2.playerShipIsLocal()
    
    This will return true if the player is near their ship, or false if they're at a location other than where their ship is parked.
    
    For expansion purposes, three example OXPs are also available.
    
    * PlanetFall Mission - Taxi - This example mission gives intra-system taxi ride offers (available on 25% of the manifest (F5-F5) screens whilst docked). it shows how some of the above variables can be used to determine where the player is docked and what state the system is in.
    * PlanetFall Link - Black Monks (requires the full BlackMonks OXP)
    * PlanetFall Link - hoOpy Casino (requires the full hoOpy casino OXP)
    
    These last two link OXPs add new planetary locations, allowing Black Monk and HoOpy Casino OXP mission offerings when their full OXPs are also installed on the system. 
    
    Scenario 1: Adding new locations into the pool of locations
    -----------------------------------------------------------
    To add additional locations into the pool of default locations, use a shipdata.plist entry as in the two above examples. For example, the entry for the hoOpy casino on the main planets is:
    
    	"planetFall2_mainSurface_hoopyCasino" =	{
    		like_ship = "planetFall2_genericSurface";
    		name = "CoachWhip hOopy Casino"; 
    		roles = "planetFall2_mainSurface_hoopyCasino planetFall2_mainSurface station(0) planetFall2_surface planetFall_surface";
    	};
    
    The first role should be replaced by the appropriate one (one unique to this location), and the other four are also necessary. For locations on additional (sub, not main) planets, replace "main" with "sub", and for those on moons replace "main" with "moon". The location will be called via the planetFall2_<main/sub/moon>Surface role.
    
    You can control the when the custom location will spawn by using these values in script_info:
    	spawn_chance: decimal percentage chance of space (eg 0.2 = 20%). Chance will be the same for any given system. Scaled with TechLevel of system.
    	seed: seed value for randomisation process.
    	always_spawn: boolean to indicate this location should always spawn.
    
    Scenario 2: Replacing all default locations with a single overridden role
    -------------------------------------------------------------------------
    If the variable worldScripts.PlanetFall2.planetFallOverride is set to true, only external OXP locations are spawned. These are shipdata entries with one of the planetFall2_<main/sub/moon>Surface_externalOXP roles. Please use sparingly, and don't forget to set it back to false once you've finished with it!
    
    Also the ownProperties ".solarGasGiant" and ".isGasGiant" are both available for recognition of gas giant planets (for Frame & Commander Cheyn, plus anyone else who may want to use them).
    
    Lastly the ownProperties of ".PFNoLand" and ".PFNoLandQuiet" are added to give warnings (or not) if approaching OXP planetary objects where landing should not be allowed, for example Tionisla pulsar.
    
    If you want to use a role other than the default roles listed above, use worldScripts.PlanetFall2.overrideRole to set the role. Once set, that specific role will be used to create landing sites (as long as worldScripts.PlanetFall2.planetFallOverride is set to true). Care should of course be taken that a second OXP may also make a similar setting. If the variable is not set then the standard default roles of planetFall2_<main/sub/moon>Surface_externalOXP are used.
    
    While the systemWillPopulate world event is best suited for setting the planetFallOverride flag and the overrideRole, problems with sequencing can mean
    the values are not set at the right time. To work around this, an additional function call is required. In your script file, normally in the "startUp"
    world event function, add the following line:
    
    	worldScripts.PlanetFall2.$addPrepopulationFunction(this.name, "extraPopulation");
    
    Then add the function "extraPopulation" to your script:
    
    	this.extraPopulation = function() {
    		if (...perform checks to see whether we need to override PlanetFall...) {
    			// if so...
    			worldScripts.PlanetFall2.planetFallOverride = true;
    			// optionally set the override role
    			worldScripts.PlanetFall2.overrideRole = "mySpecialPlanetFallRole";
    		}
    	}
    
    This will ensure the values are set in the correct order.
    
    Scenario 3: Disabling all planetary locations
    ---------------------------------------------
    If you want to disable all planetary locations for a particular system, so that nothing is set up on any planet, set worldScripts.PlanetFall2.disable = true in the shipWillEnterWitchspace world event prior to jumping into the system where you want to disable planetary locations.
    
    Scenario 4: Adding custom planets, but not with the "Additional Planets OXP"
    ----------------------------------------------------------------------------
    PlanetFall 2.0 is designed to integrate with the Additional Planets OXP. If you are adding a planet or moon outside of that OXP, you need to run the following code during the systemWillPopulate world event:
    
    	worldScripts.PlanetFall2.$addExtraPlanetDocksForPlanet(myPlanet);
    
    If you don't have a planet entity to work with yet (because the creation takes place in a system.setPopulator callback, for instance), but you do know the position the planet will have, the radius of the planet, and whether it has an atmosphere, use the following code:
    
    	worldScripts.PlanetFall2.$addExtraPlanetDocks(position, radius, hasAtmosphere, false);
    
    However, do *not* run this command inside a system.setPopulator callback script, as no planetary locations will be added in that scenario.
    
    Scenario 5: Adding a fully customised and predefined set of landing sites
    -------------------------------------------------------------------------
    A fully customised system can be defined. See the "Custom Systems.txt" document for more details.
    

    Planetfall v1.51 ReadMe & License.txt

    Planetfall OXP by Thargoid.
    
    A little OXP which allows the Commander to land on planets and moons (but not suns, even at night), and there to trade. To achieve this just fly toward the body, although take care not to go too fast or else you risk burning up in the atmosphere of planets, and don't try and land before you've got landing permission from planetary control!
    
    To land, your ship needs to be firstly equipped with heat shields and docking computers. Then at all reputable (and a few not so reputable) tech 9+ systems you can purchase planetary landing capabilities. These consist of some tweaks to your ship, plus all of the relevant permits, permissions and registrations with authorities to allow landing.
    
    Once your ship is suitably equipped, landing is done by flying down towards the planet. Your systems will automatically make all the necessary requests, and once permission is granted then just fly down to the planet. 
    
    Planetary take-off is via a launch booster, with control being returned to the Commander once orbital insertion is achieved.
    
    This OXP requires a minimum of Oolite v1.77 to run, and will not work with 1.76.1 or lower.
    
    --------------------------------------------------------------
    
    License:
    
    This OXP is released under the Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with the following clauses:
    
    * Whilst you are free (and encouraged) to re-use any of the scripting, models or texturing in this OXP, the usage must be distinct from that within this OXP. Unique identifiers such as (but not limited to) unique shipdata.plist entity keys, mission variables, script names (this.name), equipment identity strings (EQ_), description list arrays and entity roles must not be re-used without prior agreement. Basically if it's unique or would identify or overwrite anything in the original OXP, then you may not re-use it (for obvious compatibility reasons).
    * rebundling of this OXP within another distribution is permitted as long as it is unchanged. The following derivates however are permitted and except from the above:
    	* the conversion of files between XML and openStep.
    	* the merging of files with other files of the same type from other OXPs.
    * The license information (either as this file or merged into a larger one) must be included in the OXP.
    * Even though it is not compulsory, if you are re-using any sizable or recognisable piece of this OXP, please let me know :)
    
    --------------------------------------------------------------
    Instructions:
    
    Unzip the file, and then move the folder "PlanetFall 1.51.oxp" to the AddOns directory of your Oolite installation. Then start the game up and the capability should be there for purchase as detailed above. 
    
    --------------------------------------------------------------
    
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_20850610.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_21988050.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_23326348.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_21988072.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_23326337.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_21835246.htm Image by user6702303 on Freepik
    
    https://www.freepik.com/free-photo/blue-sky-with-scattered-white-clouds_12110221.htm Freepik
    https://www.freepik.com/free-photo/beautiful-skyscape-during-daytime_22542965.htm Freepik
    https://www.freepik.com/free-photo/cloudy-sky-daylight-background_19380968.htm Freepik
    https://www.freepik.com/free-photo/beautiful-skyscape-during-daytime_22543011.htm Freepik
    https://www.freepik.com/free-photo/blue-sky-with-cloud-closeup_6133056.htm Image by photogenia on Freepik
    https://www.freepik.com/free-photo/beautiful-skyscape-during-daytime_22542943.htm Freepik
    
    Version History:
    
    30/11/2008 - Version 1.00, Initial release.
    19/12/2008 - Version 1.09 Beta, upgraded test release.
    04/01/2009 - Version 1.1, full release.
    06/01/2009 - Version 1.11, bugfix release.
    19/01/2009 - Version 1.12, bugfix, plus external OXP override option
    27/08/2009 - Version 1.2, compatibility with v1.73
    09/09/2009 - Version 1.21, script tweak to stop planet-splatting when using v1.73 (thanks to Eric, A_C and Kaks for helping look into this one).
    29/09/2009 - Version 1.22, further script tweaking to stop the planet-splat. This time by re-orienting the temporary station.
    01/10/2009 - Version 1.23, commodities.plist units problem fix.
    15/04/2010 - Version 1.30, update for v1.74. Now incompatible with lower versions of Oolite. Also added compatibility for own property .isGasGiant, for System Redux 2.0 usage.
    13/02/2011 - Version 1.40, removal of upper limit to enable 1.75 usage. Also some script update to add ownProperties .PFNoLand and PFNoLandQuiet for other OXPs to use to stop landing on added planetary objects (e.g. Tionisla Pulsar).
    20/02/2011 - Version 1.41, script tweaking to make no landing more accessible and robust
    05/08/2012 - Version 1.50, some script modifications for better compatibility with other OXPs, plus some changes to this documentation (see the developers read-me for more details).
    08/01/2013 - Version 1.51, update for v1.77 (incompatible with lower versions). Changed station model due to new docking trunk code, and added landing effect in collaboration with Svengali.
    
    --------------------------------------------------------------
    
    Acknowledgements:
    
    With thanks to:
    * Lestradae for the discussions in getting the concept correct and for the original inspiration.
    * Eric Walch for the ship orientation script code (from his script from Anarchies OXP) and various discussions.
    * LittleBear for assistance in getting the interaction with Random Hits for the Seedy Bars working and for letting me add them to the surface locations.
    * Frame for the code snippets borrowed from Save Anywhere for the temporary station (how to land in a barrel!).
    * PAGroove for the landing equipment script glitch bug catch!
    * Svengali for inspiration and co-work on the landing effect, and production of some of the images (some moon images are from NASA).

    readme.txt

    Planetfall2 OXP 
    by Thargoid and phkb
    ====================
    
    An OXP which allows the Commander to land at specific locations on planets and moons (but not suns, even at night). Each main planet has up to 5 designated landing sites, while additional planets can have 3, and each moon can have 2 (configurable via Library Config). Pick your landing site and point your ship at the flashing marker near the surface that indicates the Ground Control Interface Point for the landing zone. Ensure your flight path is not too steep, otherwise you may sustain damage when the automated landing protocol engages. 
    
    Be careful of turbulence as you enter the atmosphere. To assist with atmospheric turbulence, the "Atmospheric Stabilisers" can be purchased at any TL9+ system for 5000cr. When equipped, this will reduce the impact of turbulence on your ship. Speed will have an impact on how much your ship is effected by turbulence. Slowing down will decrease the effect.
    
    Your approach will trigger an automatic landing request. You should receive a response after a few seconds, indicating you are either cleared for landing or not. If you have clearance, continue towards the Ground Control Interface Point at less than 100 m/s until the automated system engages, captures your ship and lowers you to a landing pad. 
    
    Planetary take-off is via a launch booster, with control being returned to the Commander once orbital insertion is achieved.
    
    For information in making use of Planet Fall systems, see the "Developers ReadMe.txt" file.
    
    Options:
    ========
    There are a lot of options available to help configure the system the way you want it. Library Config has the following sections for PlanetFall2:
    
    - General settings
    - F3/F8: Main planet
    - Spawn chances: Main planet
    - F3/F8: Extra planets
    - Spawn chances: Extra planets
    - F3/F8: Moons
    - Spawn chances: Moons
    - Spawn chances: TL factors
    - Transit costs
    - Ship transfer costs
    
    General settings:
    -----------------
    Flags:
    	Move shipyards to planet: Controls whether shipyards are moved to planet-side locations.
    	Move maintenance to planet: Controls whether the "Maintenance Overhaul" item is moved to only be offered on planet-side locations.
    	Atmosphere turbulence: Controls whether the turbulence effect, when entering the atmosphere of a planet, is active or not.
    	Use landing images: Controls whether the images displayed after landing at a planetary site are displayed.
    	Use Almanac names: Controls whether the names of planetary locations are given names based on the methodology from the Galactic Almanac.
    	Allow planetary transit: Controls whether it is possible to fast travel to other planetary sites after landing.
    	Planet rotation tweaks: Controls whether planetary rotation is slowed on approach (to reduce the visual impact of scaling issues).
    	
    Values:
    	Main planet max: Maximum number of locations that could be spawned on the main planet.
    	Extra planet max: Maximum number of locations that could be spawned on a secondary planet with an atmosphere.
    	Moon max: Maximum number of locations that could be spawned on a moon with no atmosphere.
    	Atmosphere max altitude: Maximum height (in km) of the atmosphere of a planet.
    	Beacon range: Max distance (in km) that planetary beacons become visible to the player.
    	Service Level dec: Amount that service level will be reduced by when launching from a planet.
    	Transfer Fee: Fee amount to be charged to the player when transferring their ship to the current location.
    	Transfer Time: Amount of time (in hours) that will pass when transferring player ship to the current location.
    	Train speed: Base average speed of trains (in kph), which is scaled up or down based on the TL of the system.
    
    F3/F8: Main planet:
    -------------------
    Flags:
    	Capital cities: Whether capital cities will have access to the F3 Equip Ship screen.
    	Military bases: Whether military bases will have access to the F3 Equip Ship screen.
    	Leisure complexes: Whether leisure complexes will have access to the F3 Equip Ship screen.
    	Factories: Whether factories will have access to the F3 Equip Ship screen.
    	Rubbish dumps: Whether rubbish dumps will have access to the F3 Equip Ship screen.
    
    Values:
    	Capital cities: What type of market will be available at capital cities.
    	Military bases: What type of market will be available at military bases.
    	Leisure complexes: What type of market will be available at military bases.
    	Factories: What type of market will be available at factories.
    	Rubbish dumps: What type of market will be available at rubbish dumps.
    
    	0 = No market; 
    	1 = Default market, which will likely be the main station market; 
    	2 = SFEP (Stations for Extra Planets) method, which adjusts prices and quantities based on the distance of the site from the main station.
    	3 = Original market, as defined in PlanetFall v1.51. (but pre-Oolite 1.84).
    
    Spawn chances: Main planet:
    ---------------------------
    Values:
    	Spawn city: Chance of spawning a capital city.
    	Spawn military base: Chance of spawning a military base.
    	Spawn leisure complex: Chance of spawning a leisure complex.
    	Spawn factory: Chance of spawning a factory.
    	Spawn rubbish dump: Chance of spawning a rubbish dump.
    
    	eg 0.4 = 40% chance. The chance will be adjusted slightly by the TechLevel factor (see below).
    
    F3/F8: Extra planets:
    ---------------------
    Flags:
    	Colony cities: Whether colony cities will have access to the F3 Equip Ship screen.
    	Military bases: Whether military bases will have access to the F3 Equip Ship screen.
    	Leisure complexes: Whether leisure complexes will have access to the F3 Equip Ship screen.
    	Factories: Whether factories will have access to the F3 Equip Ship screen.
    	Rubbish dumps: Whether rubbish dumps will have access to the F3 Equip Ship screen.
    
    Values:
    	Colony cities: What type of market will be available at colony cities.
    	Military bases: What type of market will be available at military bases.
    	Leisure complexes: What type of market will be available at leisure complexes.
    	Factories: What type of market will be available at factories.
    	Rubbish dumps: What type of market will be available at rubbish dumps.
    
    	0 = No market; 
    	1 = Default market, which will likely be the main station market; 
    	2 = SFEP (Stations for Extra Planets) method, which adjusts prices and quantities based on the distance of the site from the main station.
    	3 = Original market, as defined in PlanetFall v1.51 (but pre-Oolite 1.84).
    
    Spawn chances: Extra planets:
    -----------------------------
    Values:
    	Spawn colony city: Chance of spawning a colony city.
    	Spawn military base: Chance of spawning a military base.
    	Spawn leisure complex: Chance of spawning a leisure complex.
    	Spawn factory: Chance of spawning a factory.
    	Spawn rubbish dump: Chance of spawning a rubbish dump.
    
    	eg 0.4 = 40% chance. The chance will be adjusted slightly by the TechLevel factor (see below).
    
    F3/F8: Moons:
    -------------
    Flags:
    	Colony domes: Whether colony domes will have access to the F3 Equip Ship screen.
    	Mines: Whether mines will have access to the F3 Equip Ship screen.
    	Prisons: Whether prisons will have access to the F3 Equip Ship screen.
    	Leisure domes: Whether leisure domes will have access to the F3 Equip Ship screen.
    	Robot factories: Whether robot factories will have access to the F3 Equip Ship screen.
    	Research complexes: Whether research complexes will have access to the F3 Equip Ship screen.
    	Wastelands: Whether wastelands will have access to the F3 Equip Ship screen.
    
    Values:
    	Colony domes: What type of market will be available at colony domes.
    	Mines: What type of market will be available at mines.
    	Prison: What type of market will be available at prisons.
    	Leisure domes: What type of market will be available at leisure domes.
    	Robot factories: What type of market will be available at robot factories.
    	Research complexes: What type of market will be available at research complexes.
    	Wastelands: What type of market will be available at wastelands.
    
    	0 = No market; 
    	1 = Default market, which will likely be the main station market; 
    	2 = SFEP (Stations for Extra Planets) method, which adjusts prices and quantities based on the distance of the site from the main station.
    	3 = Original market, as defined in PlanetFall v1.51 (but pre-Oolite 1.84).
    
    Spawn chances: Moons:
    ---------------------
    Values:
    	Spawn colony dome: Chance of spawning a colony dome.
    	Spawn mine: Chance of spawning a mine.
    	Spawn prison: Chance of spawning a prison.
    	Spawn leisure dome: Chance of spawning a leisure dome.
    	Spawn robot factory: Chance of spawning a robot factory.
    	Spawn research complex: Chance of spawning a research complex.
    	Spawn wasteland: Chance of spawning a wasteland.
    
    	eg 0.4 = 40% chance. The chance will be adjusted slightly by the TechLevel factor (see below).
    
    Spawn chances: TL factors:
    --------------------------
    Values:
    	Main planet min/max: Factor to apply to spawn chance of main planet locations based on the TL of the system.
    	Extra planets min/max: Factor to apply to spawn chance of extra planet locations based on the TL of the system.
    	Moons min/max: Factor to apply to spawn chance of moon locations based on the TL of the system.
    
    	The min value would be applied at the lowest TL, while the max value would apply to the highest TL. 
    	TL's in between would get a scaled value between min and max.
    
    Transit costs:
    --------------
    Values:
    	Fee: Base cost for a single trip (cr).
    	Anarchy factor: Factor applied to fee in Anarchy systems
    	Feudal factor: Factor applied to fee in Feudal systems.
    	Multi-government factor: Factor applied to fee in Multi-Government systems.
    	Dictatorship factor: Factor applied to fee in Dictatorship systems.
    	Communist factor: Factor applied to fee in Communist systems.
    	Confederacy factor: Factor applied to fee in Confederacy systems.
    	Democracy factor: Factor applied to fee in Democracy systems.
    	Corporate State factor: Factor applied to fee in Corporate State systems.
    
    	eg 0.0 = All trips are free; 1.0 = Use base cost; 0.5 = 50% of base cost.
    
    Ship transfer costs:
    --------------------
    Values:
    	Fee: Base cost for ship transfer (cr).
    	Anarchy factor: Factor applied to fee in Anarchy systems
    	Feudal factor: Factor applied to fee in Feudal systems.
    	Multi-government factor: Factor applied to fee in Multi-Government systems.
    	Dictatorship factor: Factor applied to fee in Dictatorship systems.
    	Communist factor: Factor applied to fee in Communist systems.
    	Confederacy factor: Factor applied to fee in Confederacy systems.
    	Democracy factor: Factor applied to fee in Democracy systems.
    	Corporate State factor: Factor applied to fee in Corporate State systems.
    
    	eg 0.0 = Ship transfers are free; 1.0 = Use base cost; 1.5 = 150% base cost.
    
    License:
    ========
    This OXP is released under the Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with the following clauses:
    
    * Whilst you are free (and encouraged) to re-use any of the scripting, models or texturing in this OXP, the usage must be distinct from that within this OXP. Unique identifiers such as (but not limited to) unique shipdata.plist entity keys, mission variables, script names (this.name), equipment identity strings (EQ_), description list arrays and entity roles must not be re-used without prior agreement. Basically if it's unique or would identify or overwrite anything in the original OXP, then you may not re-use it (for obvious compatibility reasons).
    * rebundling of this OXP within another distribution is permitted as long as it is unchanged. The following derivates however are permitted and except from the above:
    	* the conversion of files between XML and openStep.
    	* the merging of files with other files of the same type from other OXPs.
    * The license information (either as this file or merged into a larger one) must be included in the OXP.
    * Even though it is not compulsory, if you are re-using any sizable or recognisable piece of this OXP, please let me know :)
    
    Image files:
    ------------
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_20850610.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_21988050.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_23326348.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_21988072.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_23326337.htm Image by user6702303 on Freepik
    https://www.freepik.com/free-photo/empty-dark-room-modern-futuristic-sci-fi-background-3d-illustration_21835246.htm Image by user6702303 on Freepik
    
    https://www.freepik.com/free-photo/blue-sky-with-scattered-white-clouds_12110221.htm Freepik
    https://www.freepik.com/free-photo/beautiful-skyscape-during-daytime_22542965.htm Freepik
    https://www.freepik.com/free-photo/cloudy-sky-daylight-background_19380968.htm Freepik
    https://www.freepik.com/free-photo/beautiful-skyscape-during-daytime_22543011.htm Freepik
    https://www.freepik.com/free-photo/blue-sky-with-cloud-closeup_6133056.htm Image by photogenia on Freepik
    https://www.freepik.com/free-photo/beautiful-skyscape-during-daytime_22542943.htm Freepik
    https://www.freepik.com/free-vector/20-vehicles-outline-icon-presentation_38543743.htm Image by flatart on Freepik
    
    https://www.freepik.com/free-ai-image/subway-dark-atmosphere_76653967.htm Image by freepik
    https://www.freepik.com/free-ai-image/new-york-city-subway-train-motion_69844323.htm Image by freepik
    https://www.freepik.com/free-photo/motion-blur-automatic-train-moving-inside-tunnel-tokyo-japan_10824408.htm Image by tawatchai07 on Freepik
    
    Some images were generated by AI at https://www.freepik.com/pikaso/ai-image-generator
    
    Sound files:
    ------------
    "e train 140kmh 04 190613_0029.wav" by klankbeeld -- https://freesound.org/s/476298/ -- License: Attribution 4.0
    "Arrival of a passenger electric train.1950km station_2(Eq,lmtr).wav" by newlocknew -- https://freesound.org/s/580464/ -- License: Attribution 4.0
    
    Instructions:
    =============
    To manually install the mod, unzip the file, and then move the folder "PlanetFall2.oxp" to the AddOns directory of your Oolite installation. Ensure you remove any previous version of PlanetFall before installing this one.
    
    Requirements:
    =============
    The following OXP's are required in order to use this one:
    - PlanetFall2 Resources (oolite.oxp.phkb.PlanetFall_Resources): Required for various graphical displays.
    - Library (oolite.oxp.Svengali.Library): For changing configuration settings.
    - GNN (oolite.oxp.Svengali.GNN): Used for random station naming functionality.
    - Market Script Interface (oolite.oxp.phkb.MarketScriptInterface): Used to update market info on planetary locations.
    - External Docking System (oolite.oxp.phkb.ExternalDockSystem): Used as part of the updated docking methodology.
    
    Version History:
    ================
    2.15
    - Increased the number of shipdata entities to better handle high values for the number of planetary landing points.
    
    2.14
    - Added protection for instances where a planet or moon has no air color value set.
    - Fixed issue where the reason for the denial of a landing request was not being transmitted to the player.
    
    2.13
    - Further fixes to linkage between landing sites and planets.
    
    2.12
    - Fixed incorrect property setting in shipdata.
    - Changed allegiance setting for research complexes to be neutral.
    - Fixed issue where landing sites could spawn too close together.
    
    2.11
    - Fixed issue where link between landing sites and planets could occasionally break due to rounding errors.
    
    2.10
    - Prevented things like "Immigration Control" from appearing in Anarchy systems.
    - Prevented turbulence frame callback from being started twice.
    - Fixed error: this.serviceLevelDecrease is not a function.
    - Tweaks to hopefully permanently fix issue where turbulence effect keeps running after a witchspace jump or docking.
    
    2.9
    - Fixed JS error in transit process code.
    - Fixed issue where Vimana-X HUD was not resetting correctly on launch after using transit system.
    
    2.8
    - Split off planet rotation slowing into separate OXP, and made optional for this OXP.
    
    2.7
    - Dying while turbulence is active will now stop the frame callback.
    - Added tweak to planet rotation when approaching planet, slowing it down to make scale issues less obvious (can be configured with Library Config).
    - Code refactoring.
    
    2.6
    - Small tweak to the market script.
    - Small fix to the name generation process for Capital Cities.
    
    2.5
    - Refined some text in messages for better understanding and integration with the built in voice.
    - Added a pre-spawn check for a condition script on custom (ie non-built-in) surface locations.
    - Fixed issue that was preventing custom names from being applied to custom system setups.
    - Added a PDF document outlining how to create custom systems, for non-coders.
    - Updates for the PlanetFall Oo-haul mission pack.
    - Added conflict with PlanetFallMarketSaver - this OXP shouldn't be necessary with PlanetFall2.
    - Added conflict with PlanetFall Markets - this OXP shouldn't be necessary with PlanetFall2.
    - Removed some unused settings in config.
    - Split off graphical assets into separate OXP, to make updating the core code easier for everyone.
    - Added a second train FX image, so that the second animation doesn't just look completely like the first.
    - Tweaked train FX images to make them more centred.
    - Added scan class to station entities.
    
    2.4
    - Adjusted calculations to make landing when pointing at the GCIP more consistent.
    
    2.3
    - Added a planet-side transit system, so you don't have to launch and re-dock to visit another landing site on the same planet.
    - Transit costs are adjusted based on government types. Configurable via Library Config.
    - Ship transfer costs are adjusted based on government types. Configurable via Library Config.
    - Fixed shipyard transfer process to not run more than once per system.
    - Added fragment and vertex shaders to ensure all break patterns appear clearly and without shadow.
    - Removed yaw turbulence factor. Only pitch and roll turbulence will be now be set.
    - Fixed issue that was preventing subSurface colonies and moonSurface domes from being spawned.
    - Amount of reduction to service level is now configurable via Library Config.
    - Added a function (PlanetFall2.playerShipIsLocal) that can be called to determine if the player is near their ship or not.
    - Removed the Blackmonks and HoOpy Casino config options, and incorporated spawn chances in script_info object of shipdata and condition script.
    
    2.2
    - Fixed issue where, if "Additional Planets" doesn't create any planets, no landing sites are created on the main planet.
    - Reapplied monkey match for Market Inquirer to address issue with beacons not showing when more than 100000m from the player when docked.
    - Removed conflicts with SW Planetary Systems and Moons, although it is unlikely any created moons will get landing sites.
    
    2.1
    - Added methods to allow for a fully customised system to be defined (with multiple sites per planet/moon).
    - Moved Feudal States override code into a separate OXP.
    - Fixed missing semi-colon in shipdata.plist.
    - Switched ground control interface point to be a normal ship object (rather than a visual effect) to gain better compatibility with OXP's like Telescope.
    - Made the ground control interface points more visible.
    - Reduced the number of monkey patches required.
    - Made the maximum range at which the space compass will detect ground control interface points configurable via Library Config, and changed the default value to 200km.
    - Added some conflict oxps ("Planetary Systems" and "Moons" by stranger).
    - Improved compatibility with Market Inquirer.
    - Tweaked spawning methods to better reflect the original PlanetFall results, where OXP station roles are not added unless override flag is set.
    - Added a warning screen for players, informing them that ship maintenance services are only available on the planet.
    - Added a chance of a misjump when executing a witchspace jump inside the atmosphere.
    - Fixed issue where entering witchspace while the turbulence effect is still active would result in it staying active.
    - Fixed bug that was setting service level to the minimum value when launching from a planetary location.
    - Turbulence now doesn't end when speed is zero.
    - Added a config item to manage how much the service level of the player ship is reduced.
    - Added shipdata entries to allow for multiple military bases, leisure complexes, factories and dumps on the main planet in custom systems. 
    - Fixed issues where NaN, NaN, Nan is calculated for a vector.
    - Log messages now controllable via a debug flag.
    - Removed some unused code.
    
    2.0
    - Updated landing FX, with clouds and landing pads.
    - Updated launching FX.
    - Changed docking method to have a fixed location (rather than just descending towards the planet surface anywhere), which means you can now save your game at planetary locations.
    - Access to equipment sales (F3 Equip Ship) configuration via Library Config.
    - Updated market information to allow for 3 different methods to be applied to any of the locations. (Configurable via Library Config)
    - Added a variety of arrival report screen backgrounds. (Can be turned off via Library Config)
    - Added a turbulence effect when in the atmosphere of a planet. (Can be turned off via Library Config)
    - Equipment item renamed to "Atmospheric Stabilisers", but is optional for planetary landings.
    - Moved ships from shipyards on other stations to planetary locations. (Configurable via Library Config)
    - Moved "Maintenance Overhaul" to only be available on the main planet. (Configurable via Library Config)
    - Added script updates to Feudal Systems, Aquatics, Market Inquirer, Galactic Almanac and In-System cargo delivery to maintain compatibility.
    - Additional compatibility settings updated via shipdata-overrides.plist.
    
    For information about versions 1.51 and previous, see the "Planetfall v1.51 ReadMe & License.txt" file.

    Equipment

    Name Visible Cost [deci-credits] Tech-Level
    Atmospheric Stabilisers yes 50000 9+

    Ships

    Name
    Planetary Control
    PlanetFall Dock
    Generic Surface Template
    Capital City
    planetFall2_mainSurface_capitalCity02
    planetFall2_mainSurface_capitalCity03
    planetFall2_mainSurface_capitalCity04
    planetFall2_mainSurface_capitalCity05
    planetFall2_mainSurface_capitalCity06
    planetFall2_mainSurface_capitalCity07
    planetFall2_mainSurface_capitalCity08
    planetFall2_mainSurface_capitalCity09
    planetFall2_mainSurface_capitalCity10
    Rubbish Dump
    planetFall2_mainSurface_dump02
    planetFall2_mainSurface_dump03
    planetFall2_mainSurface_dump04
    planetFall2_mainSurface_dump05
    planetFall2_mainSurface_dump06
    planetFall2_mainSurface_dump07
    Factory Complex
    planetFall2_mainSurface_factory02
    planetFall2_mainSurface_factory03
    planetFall2_mainSurface_factory04
    planetFall2_mainSurface_factory05
    planetFall2_mainSurface_factory06
    planetFall2_mainSurface_factory07
    planetFall2_mainSurface_factory08
    planetFall2_mainSurface_factory09
    planetFall2_mainSurface_factory10
    Leisure Complex
    planetFall2_mainSurface_leisureComplex02
    planetFall2_mainSurface_leisureComplex03
    planetFall2_mainSurface_leisureComplex04
    planetFall2_mainSurface_leisureComplex05
    planetFall2_mainSurface_leisureComplex06
    planetFall2_mainSurface_leisureComplex07
    planetFall2_mainSurface_leisureComplex08
    planetFall2_mainSurface_leisureComplex09
    planetFall2_mainSurface_leisureComplex10
    Military Base
    planetFall2_mainSurface_militaryBase02
    planetFall2_mainSurface_militaryBase03
    planetFall2_mainSurface_militaryBase04
    planetFall2_mainSurface_militaryBase05
    planetFall2_mainSurface_militaryBase06
    planetFall2_mainSurface_militaryBase07
    planetFall2_mainSurface_militaryBase08
    planetFall2_mainSurface_militaryBase09
    planetFall2_mainSurface_militaryBase10
    Colony Dome
    planetFall2_moonSurface_dome02
    planetFall2_moonSurface_dome03
    planetFall2_moonSurface_dome04
    planetFall2_moonSurface_dome05
    planetFall2_moonSurface_dome06
    planetFall2_moonSurface_dome07
    planetFall2_moonSurface_dome08
    planetFall2_moonSurface_dome09
    planetFall2_moonSurface_dome10
    planetFall2_moonSurface_dome11
    planetFall2_moonSurface_dome12
    planetFall2_moonSurface_dome13
    planetFall2_moonSurface_dome14
    planetFall2_moonSurface_dome15
    planetFall2_moonSurface_dome16
    planetFall2_moonSurface_dome17
    planetFall2_moonSurface_dome18
    planetFall2_moonSurface_dome19
    planetFall2_moonSurface_dome20
    Robot Factory
    planetFall2_moonSurface_factory02
    planetFall2_moonSurface_factory03
    planetFall2_moonSurface_factory04
    planetFall2_moonSurface_factory05
    planetFall2_moonSurface_factory06
    planetFall2_moonSurface_factory07
    planetFall2_moonSurface_factory08
    planetFall2_moonSurface_factory09
    planetFall2_moonSurface_factory10
    Leisure Dome
    planetFall2_moonSurface_leisureDome02
    planetFall2_moonSurface_leisureDome03
    planetFall2_moonSurface_leisureDome04
    planetFall2_moonSurface_leisureDome05
    planetFall2_moonSurface_leisureDome06
    planetFall2_moonSurface_leisureDome07
    planetFall2_moonSurface_leisureDome08
    planetFall2_moonSurface_leisureDome09
    planetFall2_moonSurface_leisureDome10
    Mine
    planetFall2_moonSurface_mine02
    planetFall2_moonSurface_mine03
    planetFall2_moonSurface_mine04
    planetFall2_moonSurface_mine05
    planetFall2_moonSurface_mine06
    planetFall2_moonSurface_mine07
    planetFall2_moonSurface_mine08
    planetFall2_moonSurface_mine09
    planetFall2_moonSurface_mine10
    Penal Colony
    planetFall2_moonSurface_prison02
    planetFall2_moonSurface_prison03
    planetFall2_moonSurface_prison04
    planetFall2_moonSurface_prison05
    planetFall2_moonSurface_prison06
    planetFall2_moonSurface_prison07
    planetFall2_moonSurface_prison08
    planetFall2_moonSurface_prison09
    planetFall2_moonSurface_prison10
    Research Complex
    planetFall2_moonSurface_researchComplex02
    planetFall2_moonSurface_researchComplex03
    planetFall2_moonSurface_researchComplex04
    planetFall2_moonSurface_researchComplex05
    planetFall2_moonSurface_researchComplex06
    planetFall2_moonSurface_researchComplex07
    planetFall2_moonSurface_researchComplex08
    planetFall2_moonSurface_researchComplex09
    planetFall2_moonSurface_researchComplex10
    Lunar Wasteland
    planetFall2_moonSurface_wasteLand02
    planetFall2_moonSurface_wasteLand03
    planetFall2_moonSurface_wasteLand04
    planetFall2_moonSurface_wasteLand05
    planetFall2_moonSurface_wasteLand06
    planetFall2_moonSurface_wasteLand07
    PlanetFall Scene Prison
    Ground Control Interface Point
    Colony City
    planetFall2_subSurface_colony02
    planetFall2_subSurface_colony03
    planetFall2_subSurface_colony04
    planetFall2_subSurface_colony05
    planetFall2_subSurface_colony06
    planetFall2_subSurface_colony07
    planetFall2_subSurface_colony08
    planetFall2_subSurface_colony09
    planetFall2_subSurface_colony10
    planetFall2_subSurface_colony11
    planetFall2_subSurface_colony12
    planetFall2_subSurface_colony13
    planetFall2_subSurface_colony14
    planetFall2_subSurface_colony15
    planetFall2_subSurface_colony16
    planetFall2_subSurface_colony17
    planetFall2_subSurface_colony18
    planetFall2_subSurface_colony19
    planetFall2_subSurface_colony20
    Rubbish Dump
    planetFall2_subSurface_dump02
    planetFall2_subSurface_dump03
    planetFall2_subSurface_dump04
    planetFall2_subSurface_dump05
    planetFall2_subSurface_dump06
    planetFall2_subSurface_dump07
    Factory Complex
    planetFall2_subSurface_factory02
    planetFall2_subSurface_factory03
    planetFall2_subSurface_factory04
    planetFall2_subSurface_factory05
    planetFall2_subSurface_factory06
    planetFall2_subSurface_factory07
    planetFall2_subSurface_factory08
    planetFall2_subSurface_factory09
    planetFall2_subSurface_factory10
    Leisure Complex
    planetFall2_subSurface_leisureComplex02
    planetFall2_subSurface_leisureComplex03
    planetFall2_subSurface_leisureComplex04
    planetFall2_subSurface_leisureComplex05
    planetFall2_subSurface_leisureComplex06
    planetFall2_subSurface_leisureComplex07
    planetFall2_subSurface_leisureComplex08
    planetFall2_subSurface_leisureComplex09
    planetFall2_subSurface_leisureComplex10
    Military Base
    planetFall2_subSurface_militaryBase02
    planetFall2_subSurface_militaryBase03
    planetFall2_subSurface_militaryBase04
    planetFall2_subSurface_militaryBase05
    planetFall2_subSurface_militaryBase06
    planetFall2_subSurface_militaryBase07
    planetFall2_subSurface_militaryBase08
    planetFall2_subSurface_militaryBase09
    planetFall2_subSurface_militaryBase10

    Models

    This expansion declares no models. This may be related to warnings.

    Scripts

    Path
    Scripts/planetFall2_conditions.js
    "use strict";
    this.name = "PlanetFall2_Conditions";
    this.author = "phkb";
    this.copyright = "CC-BY-SA-NC 4.0";
    this.description = "Condition script";
    
    //-------------------------------------------------------------------------------------------------------------
    // equipment condition script
    this.allowAwardEquipment = function(equipment, ship, context) {
        if (equipment == "EQ_RENOVATION") {
            if (worldScripts.PlanetFall2._config.moveRenovation == true && player.ship.dockedStation && player.ship.dockedStation.hasRole("planetFall2_mainSurface") == false) {
                return false;
            }
        }
    
        // OXP hook to allow stations to forbid specific equipment
    	if (context == "purchase" && player.ship.dockedStation && player.ship.dockedStation.scriptInfo["oolite-barred-equipment"])
    	{
    		if (player.ship.dockedStation.scriptInfo["oolite-barred-equipment"].indexOf(equipment) != -1)
    		{
    			return false;
    		}
    	}
    
    	// OXP hook to allow ships to forbid specific "available to all" equipment
    	if (ship.scriptInfo && ship.scriptInfo["oolite-barred-equipment"] && ship.scriptInfo["oolite-barred-equipment"].indexOf(equipment) != -1)
    	{
    		return false;
    	}
    
    	// otherwise allowed
    	return true;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // ship condition script
    this.allowSpawnShip = function(shipKey) {
    	switch (shipKey) {
    		case "planetFall_mainSurface_OoHaulDist":
    			if (!worldScripts.PlanetFall_Oohaul) return false;
    			if (system.government > 0 && system.population > 30) return true;
    			break;
    		case "planetFall_mainSurface_blackMonks":
    		case "planetFall_subSurface_blackMonks":
    		case "planetFall_moonSurface_blackMonks":
    			if (!worldScripts.blackmonks) return false;
    			if (worldScripts.blackmonks.$monkSystemIDs.indexOf(system.ID) >= 0) return true;
    			break;
    		case "planetFall_mainSurface_hoopyCasino":
    		case "planetFall_subSurface_hoopyCasino":
    		case "planetFall_moonSurface_hoopyCasino":
    			if (!worldScripts["hoopy_populator"]) return false;
    			if (system.techLevel >= 10 && system.government != 4 || system.info.description.indexOf('hoopy casinos') > -1) return true;
    			break;
    	}
    	return false;
    }
    Scripts/planetFall2_landingFX.js
    "use strict";
    this.name = "planetFall2_landingFX";
    this.author = "Svengali & Thargoid, phkb";
    this.copyright = "CC-by";
    this.description = "FX script";
    this.version = "1.0";
    
    this.effectSpawned = function () {
    	this.getRid = 0;
    	this.zooming = 0;
    	this.slide = worldScripts.PlanetFall2.fx_start;
    	this.forward = worldScripts.PlanetFall2.fx_land_dist;
    	this.step = worldScripts.PlanetFall2.fx_step;
    	this.padType = worldScripts.PlanetFall2.fx_landing_pad;
    	this.firstFrame = true;
    	this.changed = false;
    	// size and align ve
    	this.visualEffect.scale(0.81);
    	this.visualEffect.orientation = player.ship.orientation;
    	// start the frame callback
    	this.ovFCBID = addFrameCallback(this.repos.bind(this));
    }
    
    this.effectRemoved = function () {
    	removeFrameCallback(this.ovFCBID);
    }
    
    this.repos = function (delta) {
    	var p = player.ship;
    	if (!p.isValid || this.getRid > 2.5) {
    		this.visualEffect.remove();
    		return;
    	}
    
    	if (this.firstFrame || !delta) {
    		this.firstFrame = false;
    		return;
    	}
    
    	if (this.getRid <= 1.7) {
    		this.slide += this.step;
    		this.visualEffect.position = p.position.add(p.vectorForward.multiply(this.forward)).add(p.vectorUp.multiply(this.slide));
    		this.visualEffect.orientation = p.orientation;
    	}
    	if (this.getRid > 1.7) {
    		if (this.changed == false) {
    			this.changed = true
    			this.visualEffect.setMaterials({
    				"planetFall2_clouds.png": {
    					fragment_shader: "planetFall2_breakPattern.fragment",
    					vertex_shader: "planetFall2_breakPattern.vertex",
    					textures: ["planetFall2_landingPad" + this.padType + ".png"],
    				}
    			});
    		}
    		this.visualEffect.position = p.position.add(p.vectorForward.multiply(this.forward));
    		this.visualEffect.orientation = p.orientation;
    		this.zooming += delta;
    		this.visualEffect.scale(0.81 + (this.zooming / 10));
    	}
    	this.getRid += delta;
    	return;
    }
    
    Scripts/planetFall2_launchFX.js
    "use strict";
    this.name = "planetFall2_launchFX";
    this.author = "Svengali & Thargoid";
    this.copyright = "CC-by";
    this.description = "FX script";
    this.version = "1.0";
    
    this.effectSpawned = function () {
    	this.firstFrame = true;
    	this.getRid = 0;
    	this.tex = worldScripts.PlanetFall2.launchTexture;
    	// orient the visual effect
        this.visualEffect.orientation = player.ship.orientation;
    	// start the frame callback
    	this.ovFCBID = addFrameCallback(this.repos.bind(this));
    }
    
    this.effectRemoved = function () { 
    	removeFrameCallback(this.ovFCBID); 
    }
    
    this.repos = function (delta) {
    	var p = player.ship;
    	if (!p.isValid || this.getRid >= 3) {
    		this.visualEffect.remove();
    		return;
    	}
    
    	if (this.firstFrame || !delta) {
    		this.firstFrame = false;
    		return;
    	}
    
    	var tex = "planetFall2_launchFX" + this.tex + "_" + Math.floor(this.getRid) + ".png";
    	this.visualEffect.setMaterials({ 
    		"planetFall2_launchFX0.png": { 
    			fragment_shader: "planetFall2_breakPattern.fragment",
    			vertex_shader: "planetFall2_breakPattern.vertex",
    			textures: [tex],
    	} 
    	});
    	this.visualEffect.position = p.position.add(p.vectorForward.multiply(worldScripts.PlanetFall2.fx_launch_dist));
    	this.visualEffect.orientation = p.orientation;
    	this.getRid += (2 * delta); // to get the effect finished before true launch into realspace
    	return;
    }
    
    Scripts/planetFall2_market.js
    "use strict";
    this.name = "planetFall2_Markets";
    this.author = "phkb";
    this.copyright = "2023 phkb";
    this.license = "CC BY-NC-SA 4.0";
    
    this.$originalDefs = {
    	"planetFall2_mainSurface_capitalCity": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 65, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 40, -5, -5, 226, 31, 31, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 235, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 124, 13, 13, 29, 7, 7, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 53, 15, 0, 0, 7, 0, 0]
    	},
    
    	/*"planetFall2_mainSurface_shipYard": {
    		"food": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 65, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 40, -5, -5, 226, 31, 31, 0],
    		"liquor_wines": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 53, 15, 0, 0, 7, 0, 0]
    	},*/
    
    	"planetFall2_mainSurface_militaryBase": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 1],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 1],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 2],
    		"alien_items": [0, 0, 53, 15, 0, 0, 7, 0, 0]
    	},
    
    	/*"planetFall2_mainSurface_seedyBar": {
    		"food": [0, 0, 38, 6, -8, 2, 0, -2, 0],
    		"textiles": [0, 0, -1, 3, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 2, 3, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, -10, 15, 9, 27, 0, 0, 0],
    		"liquor_wines": [0, 0, 130, 7, -12, 2, 3, -2, 0],
    		"luxuries": [0, 0, 0, 4, 6, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, -12, -16, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 3, 2, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, -1, -4, 0, 0, 0],
    		"alloys": [0, 0, 87, -4, 12, 32, -2, 3, 0],
    		"firearms": [0, 0, 0, 11, 43, -2, 0, 0, 0],
    		"furs": [0, 0, 7, 2, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 2, -1, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 6, -3, 0, 0, 0, 1],
    		"platinum": [0, 0, 0, 2, -1, 0, 0, 0, 1],
    		"gem_stones": [0, 0, 0, 1, 5, 0, 0, 0, 2],
    		"alien_items": [0, 0, 84, -2, 0, 0, -3, 0, 0]
    	},*/
    
    	"planetFall2_mainSurface_leisureComplex": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 235, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	"planetFall2_mainSurface_factory": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 65, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	/*"planetFall2_mainSurface_farm": {
    		"food": [0, 0, 15, -2, -2.5, 20, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 40, -5, -5, 226, 31, 31, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 124, 13, 13, 29, 7, 7, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
        "planetFall2_mainSurface_fields": {
    		"food": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"textiles": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"luxuries": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},*/
    
    	"planetFall2_mainSurface_dump": {
    		"food": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"textiles": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"luxuries": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	// Sub planet surface locations.
    	"planetFall2_subSurface_colony": {
    		"food": [0, 0, 22, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 24, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 70, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 43, -5, -5, 226, 31, 31, 0],
    		"liquor_wines": [0, 0, 90, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 200, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 235, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 160, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 120, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 85, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 127, 13, 13, 29, 7, 7, 0],
    		"furs": [0, 0, 180, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 36, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 100, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 175, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 48, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 57, 15, 0, 0, 7, 0, 0]
    	},
    
    	/*"planetFall2_subSurface_shipYard": {
    		"food": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"textiles": [0, 0, 23, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 68, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 43, -5, -5, 226, 31, 31, 0],
    		"liquor_wines": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"luxuries": [0, 0, 200, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 158, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 120, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 80, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 180, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 36, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 100, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 175, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 48, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 56, 15, 0, 0, 7, 0, 0]
    	},*/
    
    	"planetFall2_subSurface_militaryBase": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 1],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 1],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 2],
    		"alien_items": [0, 0, 53, 15, 0, 0, 7, 0, 0]
    	},
    
    	/*"planetFall2_subSurface_seedyBar": {
    		"food": [0, 0, 38, 6, -8, 2, 0, -2, 0],
    		"textiles": [0, 0, -1, 3, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 2, 3, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, -10, 15, 9, 27, 0, 0, 0],
    		"liquor_wines": [0, 0, 130, 7, -12, 2, 3, -2, 0],
    		"luxuries": [0, 0, 0, 4, 6, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, -12, -16, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 3, 2, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, -1, -4, 0, 0, 0],
    		"alloys": [0, 0, 87, -4, 12, 32, -2, 3, 0],
    		"firearms": [0, 0, 0, 11, 43, -2, 0, 0, 0],
    		"furs": [0, 0, 7, 2, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 2, -1, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 6, -3, 0, 0, 0, 1],
    		"platinum": [0, 0, 0, 2, -1, 0, 0, 0, 1],
    		"gem_stones": [0, 0, 0, 1, 5, 0, 0, 0, 2],
    		"alien_items": [0, 0, 84, -2, 0, 0, -3, 0, 0]
    	},*/
    
    	"planetFall2_subSurface_leisureComplex": {
    		"food": [0, 0, 21, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 23, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 86, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 200, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 235, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 158, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 120, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 180, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 100, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 174, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 49, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	"planetFall2_subSurface_factory": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 65, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	/*"planetFall2_subSurface_farm": {
    		"food": [0, 0, 17, -2, -2.5, 20, 1, 1, 0],
    		"textiles": [0, 0, 22, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 40, -5, -5, 226, 31, 31, 0],
    		"liquor_wines": [0, 0, 85, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 198, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 157, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 120, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 127, 13, 13, 29, 7, 7, 0],
    		"furs": [0, 0, 180, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 35, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 99, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 174, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 48, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	"planetFall2_subSurface_field": {
    		"food": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"textiles": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"luxuries": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},*/
    
    	"planetFall2_subSurface_dump": {
    		"food": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"textiles": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"luxuries": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
        // Moon locations.
    	"planetFall2_moonSurface_dome": {
    		"food": [0, 0, 19, -2, -2, 3, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 6, 3, 3, 0],
    		"radioactives": [0, 0, 65, -3, -3, 5, 7, 7, 0],
    		"slaves": [0, 0, 40, -5, -5, 150, 31, 31, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 220, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 45, 3, 3, 0],
    		"narcotics": [0, 0, 235, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 23, 31, 31, 0],
    		"firearms": [0, 0, 124, 13, 13, 20, 7, 7, 0],
    		"furs": [0, 0, 176, -9, -9, 180, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 90, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 73, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 74, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 53, 15, 0, 0, 7, 0, 0]
    	},
    
    	/*"planetFall2_moonSurface_seedyBar": {
    		"food": [0, 0, 38, 6, -8, 2, 0, -2, 0],
    		"textiles": [0, 0, -1, 3, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 2, 3, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, -10, 15, 9, 27, 0, 0, 0],
    		"liquor_wines": [0, 0, 130, 7, -12, 2, 3, -2, 0],
    		"luxuries": [0, 0, 0, 4, 6, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, -12, -16, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 3, 2, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, -1, -4, 0, 0, 0],
    		"alloys": [0, 0, 87, -4, 12, 32, -2, 3, 0],
    		"firearms": [0, 0, 0, 11, 43, -2, 0, 0, 0],
    		"furs": [0, 0, 7, 2, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 2, -1, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 6, -3, 0, 0, 0, 1],
    		"platinum": [0, 0, 0, 2, -1, 0, 0, 0, 1],
    		"gem_stones": [0, 0, 0, 1, 5, 0, 0, 0, 2],
    		"alien_items": [0, 0, 84, -2, 0, 0, -3, 0, 0]
    	},*/
    
    
    	"planetFall2_moonSurface_leisureDome": {
    		"food": [0, 0, 21, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 24, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 87, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 204, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 243, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 162, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 121, 6, 0, 40, 7, 7, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	"planetFall2_moonSurface_mine": {
    		"food": [0, 0, 19, 0, 0, 0, 1, 0, 0],
    		"textiles": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 42, -3, 0, 20, 7, 3, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 105, -5, 0, 0, 15, 0, 0],
    		"luxuries": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 51, 14, 0, 0, 3, 0, 0],
    		"machinery": [0, 0, 117, 6, 0, 0, 7, 0, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 60, -1, 0, 85, 3, 3, 0],
    		"gold": [0, 0, 23, -1, 0, 25, 7, 3, 1],
    		"platinum": [0, 0, 45, -2, 0, 46, 31, 7, 1],
    		"gem_stones": [0, 0, 25, -1, 0, 56, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	"planetFall2_moonSurface_prison": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 235, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 124, 13, 13, 29, 7, 7, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 1],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 1],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	"planetFall2_moonSurface_researchComplex": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 65, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 40, -5, -5, 226, 31, 31, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 235, 29, 29, 8, 120, 120, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 124, 13, 13, 29, 7, 7, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 53, 15, 0, 0, 7, 0, 0]
    	},
    
    	"planetFall2_moonSurface_factory": {
    		"food": [0, 0, 19, -2, -2, 6, 1, 1, 0],
    		"textiles": [0, 0, 20, -1, -1, 10, 3, 3, 0],
    		"radioactives": [0, 0, 65, -3, -3, 2, 7, 7, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 83, -5, -5, 251, 15, 15, 0],
    		"luxuries": [0, 0, 196, 8, 8, 54, 3, 3, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 154, 14, 14, 56, 3, 3, 0],
    		"machinery": [0, 0, 117, 6, 6, 40, 7, 7, 0],
    		"alloys": [0, 0, 78, 1, 1, 17, 31, 31, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 176, -9, -9, 220, 63, 63, 0],
    		"minerals": [0, 0, 32, -1, -1, 53, 3, 3, 0],
    		"gold": [0, 0, 97, -1, -1, 66, 7, 7, 1],
    		"platinum": [0, 0, 171, -2, -2, 55, 31, 31, 1],
    		"gem_stones": [0, 0, 45, -1, -1, 250, 15, 15, 2],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    
    	"planetFall2_moonSurface_wasteLand": {
    		"food": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"textiles": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"radioactives": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"slaves": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"liquor_wines": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"luxuries": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"narcotics": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"computers": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"machinery": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alloys": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"firearms": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"furs": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"minerals": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gold": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"platinum": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"gem_stones": [0, 0, 0, 0, 0, 0, 0, 0, 0],
    		"alien_items": [0, 0, 0, 0, 0, 0, 0, 0, 0]
    	},
    };
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function() {
    	var msi = worldScripts.MarketScriptInterface_Main;
    	msi.$addMarketInterface("station_local", "$updateLocalCommodityDefinition", this.name);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$updateLocalCommodityDefinition = function (goodDefinition, station) {
    
    	if (!station) return goodDefinition;
    	if (!station.hasRole("planetFall2_surface")) return goodDefinition;
    
    	var key = station.dataKey.substring(0, station.dataKey.length - 2);
    	// watch for a market_key setting in script info of the station
    	// allows stations to become equivalent to one of the built in stations.
    	if (station.scriptInfo && station.scriptInfo.market_key) 
    		key = station.scriptInfo.market_key;
    
    	var marketType = worldScripts.PlanetFall2._config.marketMethod[key]
    
    	// watch for a market_type setting in script info of the station
    	if (station.scriptInfo && station.scriptInfo.market_type && !isNaN(station.scriptInfo.market_type)) 
    		marketType = parseInt(station.scriptInfo.market_type);
    
    	// no market
    	if (marketType == 0) {
    		goodDefinition.price = 0;
    		goodDefinition.quantity = 0;
    		return goodDefinition;
    	}
    	// copy main station market
    	if (marketType == 1) {
    		return goodDefinition;
    	}
    
    	// sfep method (adjust by distance from main station)
    	if (marketType == 2) {
    		if (!station.dockPos) return goodDefinition;
    
    		var distance = station.dockPos.distanceTo(system.mainStation);
    		
    		//scale max price difference with distance
    		//1000 km -> 0.05, 5000 km -> 0.15
    		var maxPriceDiff = 0.000000025 * distance + 0.025;
    		var priceDiff = Math.random() * maxPriceDiff;
    		
    		//cheaper or more expensive?
    		var coinToss = Math.round(Math.random());
    		if (coinToss === 0)  var priceMultiplier = 1 - priceDiff;
    		else var priceMultiplier = 1 + priceDiff;
    		
    		goodDefinition.price *= priceMultiplier;
    		
    		//scale quantity with random +/- 100 % scale
    		
    		var quantityDiff = Math.random();
    		var coinToss = Math.round(Math.random());
    		if (coinToss === 0) var quantityMultiplier = 1 - quantityDiff;
    		else var quantityMultiplier = 1 + quantityDiff;
    		
    		goodDefinition.quantity = Math.round(quantityMultiplier * goodDefinition.quantity);
    
    		return goodDefinition;
    	}
    
    	// original
    	if (marketType == 3) {
    		// this method is the markets from the original version of planetfall
    		if (!station) return goodDefinition;
    		var commodity = goodDefinition.key;
    		if (this.$originalDefs[key] == undefined) return goodDefinition;
    		var oldDefs = this.$originalDefs[key][commodity];
    		//old style definition found for the good. calculate it the old way
    		if (oldDefs) {
    			var market_base_price = oldDefs[2];
    			var market_eco_adjust_price = oldDefs[3];
    			var market_eco_adjust_quantity = oldDefs[4];
    			var market_base_quantity = oldDefs[5];
    			var market_mask_price = oldDefs[6];
    			var market_mask_quantity = oldDefs[7];
    			var market_rnd = Math.floor(Math.random() * 256);
    
    			var economy = system.economy;
    
    			var price = (market_base_price + (market_rnd & market_mask_price) + (economy * market_eco_adjust_price)) & 255;
    			price *= 0.4;
    
    			var quantity = (market_base_quantity + (market_rnd & market_mask_quantity) - (economy * market_eco_adjust_quantity)) & 255;
    			if (quantity > 127) quantity = 0;
    			quantity &= 63;
    
    			goodDefinition.price = price * 10;
    			goodDefinition.quantity = quantity;
    		}
    		//no definition found. nullify the goods.
    		else {
    			goodDefinition.price = 0;
    			goodDefinition.quantity = 0;
    		}
    		return goodDefinition;
    	}
    }
    
    Scripts/planetFall2_monkeyPatch.js
    "use strict";
    this.name = "PlanetFall2_MonkeyPatch";
    this.author = "phkb";
    this.copyright = "Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme.txt.";
    this.description = "Script that updates other scripts for compatibility";
    
    /*
        Note: For Aquatics, we've moved the setting of planetFallOverride into the systemWillPopulate world event.
        However, there is no guarantee by default that those scripts will be run before the systemWillPopulate function in Additional Planets.
        This is a problem because, if the planetFallOverride isn't set yet, all the default landing points will be generated.
        We could move the planetFallOverride setting to be in shipWillEnterWitchspace, but that doesn't help when loading a new game.
        Instead, we've created a callback process, where functions can be entered and then called before the Additional Planets 
        systemWillPopulate function, which ensures they will happen at the right time.
    */
    this.debug = true;
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function () {
        var pf = worldScripts.PlanetFall2;
    
        // this is so we can insert our code to add planetary docks at the same time a planet is created
        if (worldScripts["System Redux"]) {
            if (this.debug) log(this.name, "Monkey-patching systemWillPopulate and $addPlanets functions of Additional Planets");
            worldScripts["System Redux"].systemWillPopulate = this.sysredux_systemWillPopulate;
            worldScripts["System Redux"].$addPlanets = this.sysredux_$addPlanets;
        }
        // only monkey patch Planetary Systems if the SWBeforePopulators OXP is present.
        if (worldScripts["PlanetOrbits"] && worldScripts["SWBeforePopulators_main"]) {
            if (this.debug) log(this.name, "Monkey-patching addPlanets function of Planetary Systems");
            worldScripts["PlanetOrbits"].addPlanets = this.planetarysystems_addPlanets;
        }
        // aquatics 
        if (worldScripts.aquatics_populator) {
            pf.$addPrepopulationFunction("aquatics_populator", "extraPopulation");
            if (this.debug) log(this.name, "Monkey-patching shipWillEnterWitchspace and shipWillLaunchFromStation functions of Aquatics populator script");
            var a = worldScripts.aquatics_populator;
            a.extraPopulation = this.aquatics_extraPopulation;
            a.shipWillEnterWitchspace = this.aquatics_shipWillEnterWitchspace
            a.shipWillLaunchFromStation = this.aquatics_shipWillLaunchFromStation;
        }
        // market inquirer - this seems to be a bug fix, rather than something specific for PlanetFall2
        if (worldScripts.market_inquirer) {
            if (this.debug) log(this.name, "Monkey-patching $showDistances function of Market Inquirer script");
            worldScripts.market_inquirer.$showDistances = this.marketInquirer_showDistances;
        }
        // in-system cargo delivery
        if (worldScripts["In-System Cargo Delivery"]) {
            if (this.debug) log(this.name, "Monkey-patching $missionActualInfo function of In-System Cargo Delivery");
            worldScripts["In-System Cargo Delivery"].$missionActualInfo = this.insystemdelivery_missionActualInfo;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.sysredux_systemWillPopulate = function () {
        //sort the pools on first launch so that the textures stay consistently regardless of the load order of the texture packs
        if (this.runOnce) {
            this.$planetPool.sort();
            this.$moonPool.sort();
            this.runOnce = false;
        }
    
        // make sure some things are run before all planets are set up
        worldScripts.PlanetFall2.$prepopulationControls();
    
        if (this.excl[galaxyNumber].indexOf(system.ID) === -1) {
            //init station array in sfap oxp
            if (worldScripts["stations_for_extra_planets"])
                worldScripts["stations_for_extra_planets"].initStationArray();
            this.$addPlanets();
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // injecting links to additionally spawn planetary locations when spawning planets and moons
    this.sysredux_$addPlanets = function () {
        //temporary arrays to be used with splice so that no two planet/moons/giant get the same texture in one system
        var tempPlanets = new Array();
        tempPlanets = tempPlanets.concat(this.$planetPool);
        var tempMoons = new Array();
        tempMoons = tempMoons.concat(this.$moonPool);
        var tempGiants = new Array();
        tempGiants = tempGiants.concat(this.$giantPool);
        var usedTextures = new Array();
    
        //function to manage textures so that if the same texture is used as moon and planet, it won't get shown twice in the same system
        function getTexture(pool, seed) {
            while (true) {
                if (pool.length !== 0) {
                    var texNum = Math.floor(system.scrambledPseudoRandomNumber(seed) * pool.length);
                    var texture = pool.splice(texNum, 1)[0];
                    if (usedTextures.indexOf(texture) === -1) {
                        usedTextures.push(texture);
                        return texture;
                    }
                }
                else return null;
            }
        }
    
        //function to add moons around given planet
        function addMoons(planet_position, planet_radius, seed) {
            //number of moon sizes defined in planetinfo.plist
            var moonSizes = 4;
    
            //number of moons to be added. extremes have probability weight of 0.5, others 1.
            var numberOfMoons = Math.round(system.scrambledPseudoRandomNumber(seed) * worldScripts["System Redux"].max_moons);
    
            //orbits. lowest is 2.5 * planet radius. station is usually at 2 * planet radius.
            var moonOrbits = new Array();
            for (var i = 0; i < worldScripts["System Redux"].max_moons; i++) moonOrbits.push(i);
            var baseMoonOrbit = planet_radius * worldScripts["System Redux"].moon_mult;
            var moonOrbitDifference = 30000;
    
            //for cinematic reasons moons are positioned so that when you view the main planet from wp, you should be able to see all the moons around it.
            //wp-planet line is kept empty.
            for (var i = 0; i < numberOfMoons; i++) {
    
                //texture
                var moonTexture = getTexture(tempMoons, system.scrambledPseudoRandomNumber(2 * (seed + i)));
                if (moonTexture === null) return;//if we're out of textures, abort.
    
                //body
                var moonBody = "ap-moon" + Math.floor(system.scrambledPseudoRandomNumber(3 * (seed + i)) * moonSizes);
    
                //position
                var moonOrbit = moonOrbits.splice(Math.floor(system.scrambledPseudoRandomNumber(11 * (seed + i)) * moonOrbits.length), 1)[0];
                var polar = Math.acos(1.4 * system.scrambledPseudoRandomNumber(5 * (seed + i)) - 0.7);
                var azimuth = 2.0 * Math.PI * system.scrambledPseudoRandomNumber(7 * (seed + i));
                var directionV = Vector3D(Math.sin(polar) * Math.cos(azimuth), Math.sin(polar) * Math.sin(azimuth), Math.cos(polar));
                var distance = baseMoonOrbit + moonOrbitDifference * moonOrbit;
                var moonPosition = planet_position.toCoordinateSystem("pwm").add(directionV.multiply(distance)).fromCoordinateSystem("pwm");
    
                setPopulatorMoon(moonTexture, moonBody, moonPosition);
            }
        }
    
        function setPopulatorPlanet(texture, body, coords, giant, radius) {
            system.setPopulator("ap_planet" + texture, {
                callback: function (pos) {
                    var addedPlanet = system.addPlanet(body);
                    addedPlanet.texture = texture;
                    if (giant) {
                        //for planetfall
                        addedPlanet.solarGasGiant = true;
                        //for gas giant skimmer
                        addedPlanet.isGasGiant = true;
                    }
                    addedPlanet.position = pos;
                }.bind(this),
                location: "COORDINATES",
                coordinates: coords,
                priority: 100
            });
            //add surface docks
            if (!giant) {
                worldScripts.PlanetFall2.$addExtraPlanetDocks(coords, radius, true, false);
            }
            //add station to planets with atmosphere
            if (worldScripts["stations_for_extra_planets"] && !giant) 
                worldScripts["stations_for_extra_planets"].setStationPopulator(coords, radius);
        }
    
        function setPopulatorMoon(texture, body, coords) {
            system.setPopulator("ap_moon" + texture, {
                callback: function (pos) {
                    var addedMoon = system.addMoon(body);
                    addedMoon.texture = texture;
                    addedMoon.position = pos;
                }.bind(this),
                location: "COORDINATES",
                coordinates: coords,
                priority: 101
            });
            var radius = 0;
            switch (body) {
                case "ap-moon0": radius = 7000; break;
                case "ap-moon1": radius = 8000; break;
                case "ap-moon2": radius = 9000; break;
                case "ap-moon3": radius = 10000; break;
            }
            worldScripts.PlanetFall2.$addExtraPlanetDocks(coords, radius, false, false);
        }
    
        //all extra planets are positioned on incrementing distances calculated from the main planet. baseOrbit is the distance of the closest possible planet and orbitDifference is the increment from there on. These are multiples of unit calculated from wp-planet distance, so they differ from system to system. unit range is ~ 300 km - 400 km. For reference wp-planet range is ~ 300 km - 900 km.
        var orbits = new Array();
        for (var i = 0; i < this.max_planets; i++) orbits.push(i);
        var baseUnit = 1.0 / 6.0 * system.mainPlanet.position.magnitude() + 250000;
        var baseOrbit = this.planet_mult * baseUnit;//I would not go under 5. With 4, it's possible that an added planet is as close to the wp buoy as the main planet.
        var orbitDifference = 2.5 * baseUnit;
    
        //the number of extra planets in system. using Math.round gives smaller probabilities to the extremes, 0 and this.max_planets. With max planets 4, you'll be seeing more 1-3 extra planet systems than 0 or 4 extra planet systems. Probabitity weights are 0.5, 1, 1, 1, 0.5.
        var planetsInSystem = Math.round(system.pseudoRandomNumber * this.max_planets);
    
        for (var i = 0; i < planetsInSystem; i++) {
    
            //orbit.
            var orbit = orbits.splice(Math.floor(system.scrambledPseudoRandomNumber(galaxyNumber + 7 * (i + 1)) * orbits.length), 1)[0];
            //planet size. there are 9+1 different sizes defined in planetinfo.plist. 10th is reserved for gas giants that can only appear on outer orbits.
            var planetSizes = 9;
            if (orbit > 1 && tempGiants.length > 0) planetSizes = 10;
            var planetInd = Math.floor(system.scrambledPseudoRandomNumber(galaxyNumber + 2 * (i + 1)) * planetSizes);
            
            //texture
            if (planetInd === 9)
                var planetTexture = getTexture(tempGiants, system.scrambledPseudoRandomNumber(galaxyNumber + 11 * (i + 1)));
            else
                var planetTexture = getTexture(tempPlanets, system.scrambledPseudoRandomNumber(galaxyNumber + 11 * (i + 1)));
            if (planetTexture === null) continue; //if we're out of textures, skip to the next iteration.
    
            //body
            var planetBody = "ap-planet" + planetInd;
            if (planetInd === 9) var giant = true;
            else var giant = false;
    
            //position. planet is placed on a zone of a sphere around the main planet opposite to the sun.
            var polar = Math.acos(1.4 * system.scrambledPseudoRandomNumber(galaxyNumber + 5 * (i + 1)) - 1);
            var azimuth = 2.0 * Math.PI * system.scrambledPseudoRandomNumber(galaxyNumber + 3 * (i + 1));
            var directionV = Vector3D(Math.sin(polar) * Math.cos(azimuth), Math.sin(polar) * Math.sin(azimuth), Math.cos(polar));
            var distance = baseOrbit + orbitDifference * orbit;
            var planetPosition = directionV.multiply(distance).fromCoordinateSystem("psm");
    
            var radiuses = [5000, 5250, 5500, 5750, 6000, 6250, 6500, 6750, 7000, 20000];
            setPopulatorPlanet(planetTexture, planetBody, planetPosition, giant, radiuses[planetInd] * 10);
    
    
            //moons for extra planets
            if (system.scrambledPseudoRandomNumber(galaxyNumber + 17 * (i + 1)) < this.extraPlanetMoonsProbability) {
                //positioning depends on planet radius. Moon populator is set before the planet is added. Hence radiuses are given here.
                addMoons(planetPosition, radiuses[planetInd] * 10, galaxyNumber + 13);
            }
        }
        addMoons(system.mainPlanet.position, system.mainPlanet.radius, galaxyNumber + 19);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.planetarysystems_addPlanets = function (id) {
        // Add planets in system dependent order. Id is used here in two
        // ways:
        // - Its lower bits determine the planets in planetinfo.plist
        // - It represents a permutation and hence the order how the selected
        //   planets are added (see wikipedia for factoradic) and Entity-IDs
        //   are assigned.
    
        var selectPlanet1 = system.scrambledPseudoRandomNumber(163);
        var selectPlanet2 = system.scrambledPseudoRandomNumber(171);
        var selectPlanet3 = system.scrambledPseudoRandomNumber(179);
        var selectPlanet4 = system.scrambledPseudoRandomNumber(187);
        var selectPlanet5 = system.scrambledPseudoRandomNumber(195);
        var selectPlanet6 = system.scrambledPseudoRandomNumber(203);
        var selectPlanet7 = system.scrambledPseudoRandomNumber(211);
        var selectPlanet8 = system.scrambledPseudoRandomNumber(219);
    
        var selectPlanetData = [
            selectPlanet1,
            selectPlanet2,
            selectPlanet3,
            selectPlanet4,
            selectPlanet5,
            selectPlanet6,
            selectPlanet7,
            selectPlanet8
        ];
    
        var v = new Array(this.MaxPlanets), w = new Array(this.MaxPlanets);
        // Avoid huge factorials by grouping up to 12 planets.
        var mask = id;
        for (var i = 0; i < this.MaxPlanets && mask != 0 && id != 0;) {
            var m = 0, f = 1;
            // Type conversion prohibits use of the shift operator. Kind
            // of weird to apply "&" on a floating point number!
            for (; m < 12 && i < this.MaxPlanets; ++i, mask = Math.floor(mask / 2))
                if ((mask & 1) != 0)
                    v[m] = i, w[m] = m, f *= ++m;
            var fn = id % f;	// fn = sum(j in [0..m-1]:j!*c[j]), c[j] <= j
            id = Math.floor(id / f);
            for (; m > 0; --m) {
                f /= m;
                var c = Math.floor(fn / f);
                fn -= f * c;
                this.Log(this.Verbose,
                    "" + m + ":selecting oplanet" +
                    (v[w[c]] + 1) + "," + w[c] + "," +
                    c + "," + f + "," + fn);
    
                var addPlanetTagIn = v[w[c]];
                var addPlanetTagOut = 10 * (addPlanetTagIn + 1) + Math.floor(selectPlanetData[addPlanetTagIn] * 10);
    
                var pl = system.addPlanet("oplanet" + addPlanetTagOut);
                worldScripts.PlanetFall2.$addExtraPlanetDocksForPlanet(pl);
    
                // system.addPlanet("oplanet" + (v[w[c]] + 1));
                for (; c + 1 < m; ++c)
                    w[c] = w[c + 1];
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.aquatics_extraPopulation = function () {
        if (galaxyNumber == 2 && system.ID == 99 && worldScripts.PlanetFall2) { // if Planetfall is loaded
            worldScripts.PlanetFall2.planetFallOverride = true;  // set the override, so only external OXP locations appear 
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.aquatics_shipWillEnterWitchspace = function () {
        this.platformMessage = null;
        this.launchFlag = null;
    
        if (galaxyNumber == 2 && system.ID == 99 && worldScripts.PlanetFall2) {// if Planetfall is loaded and we're leaving Aqualina
            worldScripts.PlanetFall2.planetFallOverride = false; // reset the override 
        }
    
        if (missionVariables.aquatics_krakenMission == "BEGUN") {
            missionVariables.aquatics_krakenMission = "FAILED";
            mission.setInstructionsKey(null);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // all we're doing with this function is removing the planetfall integration code. it's now all in systemWillPopulate
    this.aquatics_shipWillLaunchFromStation = function (station) {
        this.launchFlag = true;
    
        if (galaxyNumber == 2 && system.ID == 99 && station.hasRole("aquatics_HQ")) {
            if (missionVariables.aquatics_krakenMission == "BRIEFING_1" || missionVariables.aquatics_krakenMission == "BRIEFING_2" || missionVariables.aquatics_krakenMission == "IMMEDIATE_OFFER")
                missionVariables.aquatics_krakenMission = "MAKE_OFFER";
    
            if (missionVariables.aquatics_krakenMission == "NOT_WELCOME" || missionVariables.aquatics_krakenMission == "KICK_OUT")
                missionVariables.aquatics_krakenMission = "CASE_CLOSED";
    
            if (missionVariables.aquatics_krakenMission == "BEGUN" && system.countShipsWithRole("aquatics_kraken") == 0)
                this.addKraken();
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.marketInquirer_showDistances = function () {
        var text = "";
        //No asc
        if (player.ship.docked && player.ship.equipmentStatus("EQ_ADVANCED_COMPASS") !== "EQUIPMENT_OK" && !player.ship.dockedStation.isMainStation && !this.$stations(player.ship.dockedStation)) {
            text = "No distance data available.";
            this.$removeInterfaces();
        }
        //sanity check;
        else if (system.isInterstellarSpace) {
            text = "No distance data available.";
        }
        else {
            //define distance unit
            var unitBase = 1000;
            var unit = "km";
            var rnd = 3;
            //use the same unit as Updating TSC
            if (worldScripts.navi_mfd) {
                var ver = worldScripts.navi_mfd.version.split(".");
                if (parseInt(ver[0]) > 1 || (ver[0] === "1" && parseInt(ver[1]) >= 9)) {
                    unitBase = worldScripts.navi_mfd.$ostronomicalUnits[worldScripts.navi_mfd.$unitSetting];
                    unit = worldScripts.navi_mfd.$distUnits[worldScripts.navi_mfd.$unitSetting];
                    rnd = worldScripts.navi_mfd.$rounding[worldScripts.navi_mfd.$unitSetting]
                } else {
                    unitBase = worldScripts.navi_mfd.$ostronomicalUnit;
                    unit = worldScripts.navi_mfd.$distUnit;
                }
            }
            var i;
            var lines = new Array();
            //star
            if (system.sun) {
                var name = "Sun";
                if (system.info.sun_name) name = system.info.sun_name;
                lines.push(["Star:", ""]);
                lines.push(["* " + name, dist(system.sun, rnd)]);
                lines.push([" ", ""]);
            };
            //planets
            var planets = system.filteredEntities(this, fn_planets, player.ship);
            if (planets.length !== 0) {
                lines.push(["Planets:", ""]);
                for (i = 0; i < planets.length; i++) {
                    if (planets[i].displayName)
                        lines.push(["* " + planets[i].displayName.replace(" (Planet)", ""), dist(planets[i], rnd)]);
                    else lines.push(["* Planet " + (i + 1), dist(planets[i], rnd)]);
                }
                lines.push([" ", ""]);
            };
            //moons
            var moons = system.filteredEntities(this, fn_moons, player.ship);
            if (moons.length !== 0) {
                lines.push(["Moons:", ""]);
                for (i = 0; i < moons.length; i++) {
                    if (moons[i].displayName)
                        lines.push(["* " + moons[i].displayName.replace(" (Moon)", ""), dist(moons[i], rnd)]);
                    else lines.push(["* Moon " + (i + 1), dist(moons[i], rnd)]);
                }
                lines.push([" ", ""]);
            };
            //beacons
            var beacons = system.filteredEntities(this, fn_beacons, player.ship);
            if (beacons.length !== 0) {
                lines.push(["Beacons:", ""]);
                for (i = 0; i < beacons.length; i++) {
                    if (beacons[i].displayName) {
                        // not sure why this is not adding beacons greater than 100000m away if you're docked.
                        //if (!player.ship.docked || player.ship.position.distanceTo(beacons[i]) > 10E4) {
                        if (beacons[i].displayName === "Navigation Buoy" && system.mainStation.position.distanceTo(beacons[i]) <= 10E4)
                            lines.push(["* " + "Main Station Buoy", dist(beacons[i], rnd)]);
                        else
                            lines.push(["* " + beacons[i].displayName, dist(beacons[i], rnd)]);
                        //}
                    }
                    else lines.push(["* Beacon " + (i + 1) + ": ", dist(beacons[i], rnd)]);
                }
            }
            //build lines for mission screen
            var column1 = lines;
            var column2 = new Array();
            if (column1.length > 19)
                column2 = column1.splice(19, column1.length - 19);
            for (i = 0; i < column1.length; i++) {
                if (column2.length > i)
                    text = text + formatStrToCol(column1[i][0], column1[i][1], 15.5) + formatStrToCol(column2[i][0], column2[i][1], 15.5) + "\n";
                else
                    text = text + formatStrToCol(column1[i][0], column1[i][1], 31) + "\n";
            }
        }
        //show mission screen
        var bgImage = "sfep_flight.png";
        if (player.ship.docked) bgImage = "sfep_docked.png";
        var options = {
            "1_QUIT": "Exit"
        }
        mission.runScreen({
            title: "Distances of " + system.name,
            screenID: "marketinquirer-distances",
            message: text,
            choices: options,
            background: bgImage,
            exitScreen: "GUI_SCREEN_INTERFACES"
        });
    
        //helper functions
        function fn_planets(entity) { return (entity.isPlanet && entity.hasAtmosphere) };
        function fn_moons(entity) { return (entity.isPlanet && !entity.hasAtmosphere) };
        function fn_beacons(entity) { return (entity.isBeacon) };
        function dist(entity, rounding) {
            var distInKm = (player.ship.position.distanceTo(entity) - entity.collisionRadius) / unitBase;
            return (distInKm.toFixed(rounding) + " " + unit);
        };
        //format columns
        function formatStrToCol(name, distStr, colWidth) {
            //if too wide, truncate
            var punct = "";
            if (distStr !== "") punct = ": ";
            if (global.defaultFont.measureString(name + punct + distStr) > colWidth) {
                var lastChar = "";
                while (global.defaultFont.measureString(name + punct + distStr) > colWidth) {
                    lastChar = name.charAt(name.length - 1);
                    name = name.slice(0, -1);
                }
                if (name.charAt(name.length - 1) === " ")
                    name = name.slice(0, -1);
                else if (lastChar !== " ")
                    name = name + ".";
            }
            //if too narrow, add spaces to end 
            while (global.defaultFont.measureString(name + punct + distStr) < colWidth) {
                distStr = distStr + " ";
            };
            if (distStr.charAt(distStr.length - 1) === " ")
                distStr = distStr.slice(0, -1);
            return name + punct + distStr;
        };
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // the planetfall equipment item (EQ_PLANETFALL) is now optional, so we're tweaking this code to remove it as 
    // an option when checking if the player is equipped for a mission
    this.insystemdelivery_missionActualInfo = function () {
        var u = -1;
        var s = -1;
        this.$destinationPort = system.info.name + " " + this.$planetInfoSelected;
        var deliveryInfo = "";
        // emergency missions
        // *** item selection
        if (this.$urgentMissionFlag >= 0) {
            u = this.$urgentMissionFlag;
            this.$urgentBreef = this.$accidentEventLegend[u];
            this.$urgentMissionList = this.$accidentCargoSheet[u];
            var l = Math.floor(Math.random() * 10);
            this.$urgentCargoTag = this.$urgentMissionList[l];
            var t = this.$urgentCargoTag;
            this.$urgentCargoItem = this.$accidentCargoList[t];
            this.$urgentCargoLegend = this.$accidentCargoLegend[t];
            this.$deliveryItem = this.$urgentCargoItem;
        }
        if (u >= 0) {
            deliveryInfo = "Urgent cargo delivery - "
                + this.$urgentCargoItem + "\n\n"
                + this.$urgentBreef + "\n\n"
                + this.$urgentCargoLegend + "\n\n"
                + "Destination port: " + this.$destinationPort + "\n\n"
                + "Insurance fee " + this.$insuranceFee + " Cr will be removed from your cash if you will assign this contract." + "\n"
                + "This fee will be returned with " + this.$urgentPremium.toFixed(0) + " Cr premium only in case of successful cargo delivery.";
            // *** case 1 - ship is not equipped for mission
            if ((player.ship.cargoSpaceAvailable < 5) || (player.credits < this.$insuranceFee)) {
                deliveryInfo = this.$missionRefuse;
                mission.runScreen({
                    title: "Cargo Delivery Info",
                    background: { name: "specialCargoLoad.png", height: 480 },
                    message: deliveryInfo,
                });
            }
            // *** case 2 - mission available
            else {
                mission.runScreen({
                    title: "Cargo Delivery Info",
                    background: { name: "specialCargoLoad.png", height: 480 },
                    message: deliveryInfo,
                    choicesKey: "cargo_contract"
                },
                    function (choice) {
                        if (choice === "1_Accept_Contract") this.$cargoLoad();
                    }
                );
            }
        }
    
        // special missions
        if (u >= 0) return; // check for emergency missions priority!
        s = this.$specialMissionFlag;
        this.$deliveryItem = this.$specialCargoList[s];
        if (s >= 0) {
            deliveryInfo = "Special cargo delivery - "
                + this.$specialCargoList[s] + "\n\n"
                + this.$specialCargoLegend[s] + "\n\n"
                + "Destination port: " + this.$destinationPort + "\n\n"
                + "Insurance fee " + this.$insuranceFee + " Cr will be removed from your cash if you will assign this contract." + "\n"
                + "This fee will be returned with " + this.$specialPremium.toFixed(0) + " Cr premium only in case of successful cargo delivery.";
        }
    
        // *** case 1 - ship is not equipped for mission
        if ((player.ship.cargoSpaceAvailable < 5) || (player.credits < this.$insuranceFee)) {
            deliveryInfo = this.$missionRefuse;
            mission.runScreen({
                title: "Cargo Delivery Info",
                background: { name: "specialCargoLoad.png", height: 480 },
                message: deliveryInfo,
            });
        }
        else {
            if (s >= 0) { // *** case 2 - mission available
                mission.runScreen({
                    title: "Cargo Delivery Info",
                    background: { name: "specialCargoLoad.png", height: 480 },
                    message: deliveryInfo,
                    choicesKey: "cargo_contract"
                },
                    function (choice) {
                        if (choice === "1_Accept_Contract") this.$cargoLoad();
                    }
                );
            }
            else { // *** case 3 - no mission
                deliveryInfo = this.$missionEmpty;
                mission.runScreen({
                    title: "Cargo Delivery Info",
                    background: { name: "specialCargoLoad.png", height: 480 },
                    message: deliveryInfo,
                }
                );
            }
        }
    }
    
    Scripts/planetFall2_names.js
    "use strict";
    this.name = "PlanetFall2_Names";
    this.author = "Littlebear, phkb";
    this.copyright = "Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme.txt.";
    this.description = "Naming routines for planetfall stations";
    
    /*
    	This script will give each landing site a unique name. Names are either generated, or retrieved from saved data. 
    	If you reload a system without saving, all planetary locations will have new names (although the type site will be the same)
    	Once the names for a system have been saved, they will remain consistent over time.
    */
    
    this.nameStore = {};
    
    this.rsnInUse = false;
    
    this.planetFall_opening_words1_alt = [
    	"Centre","Hub","Facility"
    ];
    
    this.planetFall_opening_words1_alt4 = [
    	"Information","Trade","Tourism","Commerce"
    ];
    
    this.planetFall_opening_words1_alt5 = [
    	"Ground","Immigration","Traffic","Passport","Customs"
    ];
    
    this.planetFall_opening_words1_alt6 = [
    	"GalCop","Imperial","Federation","Planetary"
    ];
    
    this.planetFall_opening_words2_alt = [
    	"Facility","Complex","Centre","Depot"
    ];
    
    this.planetFall_opening_words3_alt = [
    	"Military","Naval","Airforce","Army"
    ];
    
    this.planetFall_opening_words3_alt2 = [
    	"Base","Compound","Headquarters","Outpost"
    ];
    
    this.planetFall_opening_words4_alt = [
    	"Cafe","Restaurant"
    ];
    
    this.planetFall_opening_words4_alt2 = [
    	"Seedy","Underground","Disreputable","Insalubrious","Sketchy"
    ];
    
    this.planetFall_opening_words4_alt3 = [
    	"Joint","Club"
    ];
    
    this.planetFall_opening_words4_alt3a = [
    	"House","Bar"
    ];
    
    this.planetFall_opening_words4_alt4 = [
    	"Tavern","Establishment"
    ];
    
    this.planetFall_opening_words5a = [
    	"Industrial","Manufacturing","Urban"
    ];
    
    this.planetFall_opening_words5b = [
    	"Zone","District","Complex","Area","Heartland","Sector","Region","Quadrant"
    ];
    
    this.planetFall_opening_words6a = [
    	"Agricultural","Rural","Pastoral","Horticultural","Arable"
    ];
    
    this.planetFall_opening_words6b = [
    	"Zone","District","Area","Sector","Region","Quadrant"
    ];
    
    this.planetFall_opening_words7a = [
    	"Corn","Rice","Barley","Poppy","Tulip","Orchid","Potato","Tobacco"
    ];
    
    this.planetFall_opening_words7b = [
    	"Field","Plantation"
    ];
    
    this.planetFall_opening_words7c = [
    	"Windswept","Fertile","Cultivated","Marshy","Barren","Swampy"
    ];
    
    this.planetFall_opening_words7d = [
    	"Fields","Meadows","Farmland","Grassland","Pastures","Countryside","Wetlands"
    ];
    
    this.planetFall_opening_words8a = [
    	"Radioactive","Biohazardous","Recycling","Disposal","Contaminated","Infected","Quarantined"
    ];
    
    this.planetFall_opening_words9_alt = [
    	"Retail","Mercantile","Diplomatic","Demilitarized","Urban"
    ];
    
    this.planetFall_opening_words9_alt2 = [
    	"Residential","Suburban","Habitation"
    ];
    
    this.planetFall_opening_words9_alt3 = [
    	"Commercial","Business","Banking","Trading"
    ];
    
    this.planetFall_opening_words9_ending = [
    	"Zone","District","Complex","Area","Sector","Region","Quadrant"
    ];
    
    this.planetFall_opening_words9_ending2 = [
    	"Zone","District","Complex","Sector","Quadrant"
    ];
    
    this.planetFall_opening_words10_alt1 = [
    	"Aerodrome","Airstrip","Port","Encampment","Fortress","Safehouse","Fort","Bastion","Camp","Stronghold","Stockade","Barracks"
    ];
    
    this.planetFall_ending_words1 = [
    	"City","Metropolis","Landing","Township","Citadel","Anchorage","Dockyard","Harbour","Starbase","Spaceport",
    	"Astrodome","Cosmodrome"
    ];
    
    this.planetFall_ending_words2 = [
    	"Outpost","Docks","Shipyard","Base","Terminus","Warehouse","Depot","Waystation","Anchorage","Dockyard"
    ];
    
    this.planetFall_mainSurface_militaryBase_name2 = [
    	"Camp","Port"
    ];
    
    this.planetFall_mainSurface_militaryBase_name3 = [
    	"Keep","Fortress","Armoury","Bunker","Castle","Arsenal"
    ];
    
    this.planetFall_ending_words4 = [
    	"Workshop","Foundry","Forge","Cannery","Brewery","Refinery","Mill","Steelworks","Mine","Abattoir"
    ];
    
    this.planetFall_ending_words5 = [
    	"Ranch","Hatchery","Homestead","Orchard","Farmstead","Estate","Vineyard","Hacienda","Apiary","Stables"
    ];
    
    this.planetFall_ending_words6 = [
    	"Hermitage","Mansion","Manor","Hamlet","Village","Lodge","Villa","Stockade"
    ];
    
    this.planetFall_ending_words7 = [
    	"Dump","Depot","Cesspool","Sewage Plant","Junkyard","Scrapyard","Boneyard","Crematorium","Mortuary","Cemetery","Graveyard"
    ];
    
    this.planetFall_ending_words8 = [
    	"Chateau","Penthouse","Bastion","Settlement","Portico","Colony","Arcade","Colonnade","Plaza","Bazaar","Galleria"
    ];
    
    this.planetFall_ending_words9 = [
    	"Cathedral","Monastery","Abbey","Temple","Church","Nave"
    ];
    
    this.planetFall_ending_words10 = [
    	"Point","Palisade","Towers","Springs","Watchtower","Outpost","Base","Bunker","Armoury","Redoubt","Arsenal"
    ];
    
    this.planetFall_ending_words11 = [
    	"Harbour","Compound","Citadel","Terminus","Central"
    ];
    
    this.planetFall_mainSurface_capitalCity_name1a = [
    	"London","Cambridge","Belfast","Birmingham","Bradford","Brighton","Bristol","Canterbury","York",
    	"Worcester","Winchester","Westminster","Wakefield","Swansea","Sunderland","Southampton","Sheffield",
    	"Salisbury","Ripon","Preston","Plymouth","Perth","Oxford","Nottingham","Norwich","Manchester","Liverpool",
    	"Lisburn","Lincoln","Lichfield","Leicester","Leeds"
    ];
    
    this.planetFall_mainSurface_capitalCity_name1b = [
    	"Lancaster","Kingston","Inverness","Hereford","Gloucester","Exeter","Edinburgh","Durham","Derby",
    	"Chichester","Chester","Chelmsford","Carlisle","Cardiff","Canterbury","Colorado","Kansas","Atlanta",
    	"Sacramento","Baltimore","Memphis","Portland","Detroit","Nashville","Boston","Washington","Denver",
    	"Seattle","Columbus","Texas","Dallas","Houston"
    ];
    
    this.planetFall_mainSurface_capitalCity_name1c = [
    	"Chicago","Albania","Belgium","Prague","Estonia","Finland","Paris","Helsinki","Berlin","Athens",
    	"Dublin","Rome","Pristina","Liechtenstein","Valletta","Amsterdam","Oslo","Warsaw","Lisbon","Moscow",
    	"Belgrade","Stockholm","Madrid","Bratislava","Brussels","Minsk","Sarajevo","Macedonia","Ankara",
    	"Kazakhstan","Canberra","Tarawa"
    ];
    
    this.planetFall_Surface_hoopy_name1a = [
    	"Venetian","Bellagio","Monte Carlo","Manhattan","Groucho","Grand Lisboa","Foxwood","Las Vegas",
    	"Canberra","Mindil Beach","Reef","Treasury","Paradise","Gateway","Hard Rock","Niagara","Woodbine",
    	"Rama","Blue Heron","Galaxy Macau","Homburg","Genting","Dragonara","Dunedin","Auckland","Wild Orchid",
    	"Waterfront","Solaire","Constanta","Vatra Dornei","Suncoast","Grosvenor"
    ];
    
    this.planetFall_Surface_hoopy_name1b = [
    	"Crockford","Aspinall","Wild Creek","Apache Gold","Blue Water","Spirit Mountain","Twin Arrows","Talking Tree",
    	"Bear River","Black Sheep","Deuces Wild","Eagle Mountain","Golden Acorn","Hawaiian Gardens","Limelight",
    	"Livermore","Nineteenth Hole","Red Earth","Rolling Hills","Silver Fox","San Pablo","Spotlight",
    	"Thunder Valley","Tortoise Rock","Twin Pines","Black Hawk","Brass Eye","Bullpen","Colorado","Doc Holliday",
    	"Double Eagle","Midnight Rose"
    ];
    
    this.planetFall_Surface_hoopy_name2 = [
    	"Ballroom","Club","Resort","Hippodrome","Hotel","Hilton","Ritz","Card Room"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name_alt1 = [
    	"Complex","Centre"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name_alt2 = [
    	"Leisure","Entertainment"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name1 = [
    	"Wild Rapids","Penguin Village","Ocean Dome","Boogie Mountain","Caribbean Cove","Disney World","Lake Coloures",
    	"Paradise Landing","Pleasure Island","Wonderland","Sea World","Splash Down","Magic Mountain","Galaxy Land",
    	"Adventure Island","Rattlesnake Canyon","Tinker Town","Blue Mountain","Clifton Hill","Sandpit Beach","La Ronde",
    	"Funland","Water World","Enchanted Island","Crystal Falls","Hot Springs","Little Rock","Adventure City","Bear Lake",
    	"Fairyland","Fun Town","Happy Hollow"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name2 = [
    	"Pacific Boardwalk","Pixie Land","Sesame Palace","Discovery Kingdom","Steamboat Springs","Adventure Ridge",
    	"Ocean Beach","The Dream Machine","Gatorland","Perry Fair","Enchanted Castle","Carousel Corner","Lost Island",
    	"Pumpkin Patch","Indiana Beach","Kentucky Kingdom","Dixie Land","Splash Town","Playland Palace","Orchard Beach",
    	"Jolly Roger Pier","Salem Willows","Sterling Heights","Spirit Mountain","Silver Dollar City","Mountain Creek",
    	"Seaside Hights","Point Pleasant","Morey Pier","Adventure Zone","Crystal Castle","Atlantic Beach"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name3 = [
    	"Pong","Tetris","Mario","Sonic","Zelda","Metroid","Zalaga","Minecraft","Contra","Galaxian","Pokemon","Halo"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name3a = [
    	"World","Palace","Land","City","House","Central","Multiplex"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name5a = [
    	"Hothouse","Greenhouse","Arboretum","Orchard","Park","Nursery","Forest"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name6 = [
    	"Out of Africa","Lion Country","Kings Dominion","Jurassic Park","Ivory Coast","Africano Zoo","Parc Endemika",
    	"Dream Village","World of Birds","Mystic Monkeys","Panda Base","Tropical World","Sea World","The Lost World",
    	"Tiger Country","Wild World","The Reptile House","Danga Bay","Sunway Lagoon","Animal Wonderland","Crocolandia Zoo",
    	"Caledonia Aquarium","Kiwi House","Willowbank Reserve","London Zoo","Nature World","Planete Sauvage","Sevilla Zoo",
    	"Valley of Ostriches","Amazon World","Bird World","Borth Animalarium"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name8 = [
    	"Multiplex","Odeon","Playhouse","Theatre","Auditorium","Amphitheatre"
    ];
    
    this.planetFall_mainSurface_leisureComplex_name9 = [
    	"Fight Club","Cobra Kai","Bulletproof Monk","Tiger Claw","Ninja Garden","Enter the Dragon","Game of Death",
    	"Exploding Fist","Vibrating Palm","Shadow Boxer","Silent Knight","Steel Fist","Order of Iron","Secret Way",
    	"Empty Hand","Atomic Cat","Knight of Ni","Crouching Tiger","Hidden Dragon","Way of the Rat","Deadly Viper",
    	"Suicide Squad","Praying Mantis","Circling Poet","Streets of Rage","Whirling Dervish","Art of War","Deadly Poet",
    	"Glass Cannon","Red Devil","Unseen Hand","House of Suns"
    ];
    
    this.planetFall_mainSurface_oohaul_name2 = [
    	"Depot","Outpost","Terminus","Anchorage","Warehouse","Dockyard","Anchorage","Waystation"
    ];
    
    this.planetFall_subSurface_colony_name1 = [
    	"Debt","Mammon","Greed","Lending","Credit","Default","Insolvency","Bankruptcy","Austerity","Poverty",
    	"Capital","Equity","Servitude","Repayment","Ruin","Penury"
    ];
    
    this.planetFall_subSurface_colony_name2 = [
    	"Terminus","Central","Citadel","City","Township"
    ];
    
    this.planetFall_moon_describe1 = [
    	"Volcanic","Luna","Glacial","Cratered"
    ];
    
    this.planetFall_moon_describe_rocks = [
    	"Granite","Basalt","Limestone"
    ];
    
    this.planetFall_moon_describe2 = [
    	"Gorge","Canyon","Cavern","Outcrop","Ravine","Valley"
    ];
    
    this.planetFall_moon_describe3 = [
    	"Frozen","Hydrocarbon","Methane","Lava","Magma"
    ];
    
    this.planetFall_moon_describe4 = [
    	"Lake","Lagoon","Ocean","Sea"
    ];
    
    this.planetFall_moon_describe5 = [
    	"Luna","Mountainous","Barren","Volcanic","Rocky"
    ];
    
    this.planetFall_moon_describe6 = [
    	"Desert","Plateau","Tundra","Plain","Crater"
    ];
    
    this.planetFall_moon_describe_place1 = [
    	"Sea of","Lake of","Ocean of","Bay of","Valley of","Mountains of","Plain of","Canyon of","Cavern of",
    	"Abyss of","Chasm of","Plateau of","Isle of","Hills of"
    ];
    
    this.planetFall_moon_describe_place2a = [
    	"Concord","Serenity","Tranquility","Storms","Sorrow","Solitude","Dreams","Madness","Despair","Time",
    	"Fear","Harmony","Obscurity","Decay","Gloom","Twilight","Silence","Rapture","Inspiration","Souls",
    	"Elation","Passion","Bliss","Glory","Shadow","Light","Doom","Eternity","Discord","Euphoria","Hysteria",
    	"Dystopia"
    ];
    
    this.planetFall_moon_describe_place2b = [
    	"Utopia","Dread","Terror","Dismay","Horror","Adventure","Trepidation","Uncertainty","Doubt","Faith","Reason",
    	"Rage","Fortune","Fate","Chivalry","Courage","Equity","Tyranny","Hope","Audacity","Daring","Endurance","Fortitude",
    	"Gallantry","Tenacity","Valour","Enterprise","Reflection","Nostalgia","Absolution","Redemption","Regret"
    ];
    
    this.planetFall_moon_describe_place2c = [
    	"Stoicism","Atonement","Resolve","Certitude","Persistence","Wisdom","Insight","Resolve","Resolution","Dedication",
    	"Clemency","Cordiality","Grace","Solicitude","Sympathy","Empathy","Destiny","Perception","Brilliance","Intellect",
    	"Aptitude","Judgment","Intuition","Sentience","Foresight","Discretion","Devotion","Accord","Integrity",
    	"Creation","Imagination","Perfection"
    ];
    
    this.planetFall_moonSurface_dome_ending = [
    	"Village","Hermitage","Lodge","Hamlet","Hideout","Refuge","Belfry","Clinic","Sanatorium","Sanctuary",
    	"Asylum","Seminary","Orphanage","Haven"
    ];
    
    this.planetFall_moonSurface_seedyBar_name_alt = [
    	"Bar","Pub","Cafe","Bistro"
    ];
    
    this.planetFall_moon_describe_bar1 = [
    	"City","Metropolis","Township","Spaceport","Astrodome","Cosmodrome","Base","Colony","Outpost","Terminus","Starbase"
    ];
    
    this.planetFall_moon_describe_bar2 = [
    	"Camp","Port"
    ];
    
    this.planetFall_moon_describe_mine1 = [
    	"Volcanic","Luna","Magma","Lava","Barren","Desolate","Cratered","Rocky"
    ];
    
    this.planetFall_moon_describe_mine2 = [
    	"Gorge","Canyon","Cavern","Ravine","Valley","Plateau","Wasteland","Plain","Promontory"
    ];
    
    this.planetFall_moon_describe_prison1 = [
    	"Ominous","Uncanny","Shadowy","Barren","Desolate","Eerie","Spooky","Mysterious","Misty","Lonely","Sinister","Gloomy","Perilous"
    ];
    
    this.planetFall_moon_describe_prison2 = [
    	"Abyss","Chasm","Valley","Plateau","Canyon","Mountain","Island"
    ];
    
    this.planetFall_moon_describe_prison3 = [
    	"Prison","Penitentiary","Jail","Borstal","Gaol","Workhouse"
    ];
    
    this.planetFall_moon_describe_base1 = [
    	"Underground","Hidden","Subterranean","Secluded"
    ];
    
    this.planetFall_moon_describe_base2 = [
    	"Cave","Cove","Hollow","Cavern","Volcano","Crater","Anchorage"
    ];
    
    this.planetFall_moon_describe_base3 = [
    	"Bioweapons","Torpedoes","Ballistics","Disrupters","Armaments","Sidearms","Lasers","Railguns","Neurotoxins",
    	"Landmines","Pistols","Blasters","Disintegrators","Sonics","Propulsion","Terraforming","Pharmaceuticals",
    	"Defence","Armaments","Genetics","Computing","Deflectors","Armour","Plating","Ablatives","Shipwrights",
    	"Munitions","Carbines"
    ];
    
    this.planetFall_moonSurface_factory_name2 = [
    	"Mechanoids","Droids","Positronics","Bionics","Prosthetics","Mechanicals","Cybernetics","Robotics","Replicants","Clones"
    ];
    
    this.planetFall_moonSurface_wasteLand_name1 = [
    	"Irradiated","Devastated","Contaminated"
    ];
    
    this.planetFall_moonSurface_wasteLand_name2 = [
    	"Wasteland","Plain","Plateau","Cavern","Crater"
    ];
    
    this.planetFall_moonSurface_wasteLand_name3a = [
    	"03","08","11","12","13","15","17","19","21","22","29","34","51","63","75",
    	"76","77","79","81","87","88","92","94","95","96","101","106","108","111","112",
    	"114","118"
    ];
    
    this.planetFall_moonSurface_wasteLand_name3b = [
    	"Bunker","Shelter","Refuge"
    ];
    
    this.planetFall_moonSurface_wasteLand_name3c = [
    	"Listening","Surveillance","Monitoring"
    ];
    
    this.named_stations_custom_101 = [
    	"Brahma","Vednatha","Chaturmukha","Prajapati","Vedagarbha","Devi","Parvati","Durga","Kali","Bhumi","Lakshmi",
    	"Saraswati","Gayatri","Ganga","Narmada","Yami","Sati","Shashthi","Savitri","Manasa","Svaha","Dakshina","Shiva",
    	"Vishnu","Narayana","Narayana","Thirumal","Perumal","Jagannatha","Hayagriva","Achyuta","Madhava"
    ];
    
    this.named_stations_custom_102 = [
    	"Menaka","Pramlocha","Rambha","Tara","Tilottama","Urvashi","Adrika","Astika","Kaliya","Karkotaka","Susna",
    	"Shesha","Takshaka","Ulupi","Vasuki","Erawan","Gajasimha","Ganesha","Iravati","Vinayaki","Pundarika","Vamana",
    	"Kumunda","Supratika","Anjana","Hanuman","Kesari","Nala","Sugriva","Tara","Vishwakarma","Dhenu"
    ];
    
    this.list_of_oldgods_subtable1 = [
    	"Zeus","Hera","Poseidon","Demeter","Ares","Athena","Apollo","Arthemis","Hephaestus","Aphrodite","Hermes",
    	"Dionysus","Hades","Hypnos","Janus","Nemesis","Iris","Hecate","Tyche","Fortuna","Chronos","Eros","Gaia",
    	"Hemera","Nyx","Nesoi","Phanes","Pontus","Tartarus","Thanatos","Cronus","Hyperion"
    ];
    
    this.list_of_oldgods_subtable2 = [
    	"Prometheus","Atlas","Tethys","Helios","Dagon","Pallas","Styx","Alcyoneus","Damysus","Mimas","Odin",
    	"Balder","Loki","Thor","Heimdall","Odinl","Vidar","Cthulhu","Shoggoth","Azathoth","Bokrug","Dagon",
    	"Shaggai","Shantak","Gobogeg","Hastar","Yuggoth","Osiris","Nepit","Aker","Amum","Khepri"
    ];
    
    this.list_of_oldgods_subtable3 = [
    	"Osiris","Sobek","Caturix","Anhur","Horus","Khepri","Norton","Thoth","Amunet","Hathor","Odin",
    	"Nepit","Neit","Ogma","Tethra","Achall","Canola","Niamh","Cermait","Clidna","Belenus","Caturix",
    	"Cernunnos","Leno","Nemausus","Niskus","Ogmois","Hesus","Andraste","Arito","Erecura","Urien"
    ];
    
    this.list_of_heros_subtable1 = [
    	"Abderus","Acadermus","Achilles","Acrisius","Aeneas","Agamemnon","Alcon","Alcyoneus","Alexanor",
    	"Amazonius","Andropompus","Areclepius","Asclepius","Bellerophon","Cadmus","Castor","Pollux",
    	"Ceryx","Diomedes","Electryone","Erechtheus","Eynostus","Eurytus","Cteatus","Evander","Heracles",
    	"Hippothoon","Hyacinth","Iphigenia","Leons","Leucon","Lycurgus"
    ];
    
    this.list_of_heros_subtable2 = [
    	"Menelaus","Messene","Muichus","Myrtilus","Odysseus","Oedipus","Orestes","Palamedes","Pandion",
    	"Parrhasius","Peleus","Pelops","Perseus","Phalanthus","Pleuron","Podalirius","Protesilaus","Sostratus",
    	"Theseus","Trophonius","Zarex","Ajax","Amgrim","Bjaki","Egil","Helgi","Northbrodd","Loki","Odin",
    	"Starkad","Scipdagr","Pwyll"
    ];
    
    this.list_of_heros_subtable3 = [
    	"Honorius","Cuchulainn","Gwydion","Odysseus","Oisin","Pryderi","Pwyll","Cangjie","Ulysses","Mulan",
    	"Almos","Laozi","Mazu","Nuwa","Shennony","Gilgamesh","Wukong","Nezha","Enkidu","Marcus","Beowulf",
    	"Hengist","Horsa","Scefa","Tarchon","Tyrrhenus","Karna","Arjuna","Arash","Rostam","Sohrab","Watonga"
    ];
    
    this.general_names_list_subtable_1 = [
    	"Bell","Braben","Ahruman","Rodriguez","Perez","Walch","Martinez","Selezen","McLane","Hernandez",
    	"Duval","Lopez","Mosser","Clark","Garcia","Miller","Ryder","Holdstock","Zetter","Jameson","Jackson",
    	"Anderson","Wilson","McReno","Taylor","Moore","McNab","Thompson","Asimov","Havilland","McJamefire","Bowman"
    ];
    
    this.general_names_list_subtable_2 = [
    	"Robinson","Asher","Livingstone","Walker","Hickman","Wright","Dent","Baker","Campbell","Zorath",
    	"Goldberg","Pullman","Weston","Blake","Carter","Rimmer","Lister","Turner","Saxton","Kubrick",
    	"Cook","Ortiz","Peterson","Parker","Kelly","Watson","Bennet","Alvarez","Stovin","Fisher",
    	"Carpenter","McLaren"
    ];
    
    this.general_names_list_subtable_3 = [
    	"Rowlling","Zahn","Castillo","Baldwin","Tarrant","Foster","Aherne","Tyler","Jimenez","Callaghan",
    	"Callen","Zheaton","Clancey","Silverberg","Greenberg","O'Neil","Banfield","Pinkman","McGeavy",
    	"Barker","Baily","Boden","Sharrock","Greenwood","Silversmith","Bowden","Boylan","Tarkin","Capone",
    	"Cahall","Wexler","Redfield"
    ];
    
    this.general_names_list_subtable_4 = [
    	"McCloud","Dexter","Haussmann","McCartney","Lennon","Sangwan","Wesker","Cokeley","Nielsen",
    	"Dhillon","Bunter","Scoresby","Goodwin","Jenner","Wodehouse","Comerford","Marple","Hickson",
    	"Hinchcliff","Connally","Wharton","Darby","Kapoor","Kochavi","Eagan","Fitzgerald","Jellico",
    	"Feehan","McTurk","Grey","Garrahan","Lovecraft"
    ];
    
    this.general_names_list_subtable_5 = [
    	"Gaffey","Karpov","Ripley","Walker","Polard","Gatchell","Barton","Goldrick","Gosnell","Paterson",
    	"Doyle","Johnson","Goyne","Dhal","Pratchett","Windham","Haggerty","Newman","Halferty","Halligan",
    	"Spencer","Hanifin","Yadin","Hanlon","Laskov","Timberman","Hassan","O'Rook","Townsend","Bryson",
    	"O'Donald","Heagerty"
    ];
    
    this.named_stations_custom_119 = [
    	"Ghazni","Medina","Damascus","Baghdad","Cairo","Timbuktu","Cordoba","Samarra","Hibabiya","Hamdallashi",
    	"Jerusalem","Bukhara","Mosul","Neyshabur","Harran","Palmyra","Decapolis","Edom","Gadara","Holon",
    	"Hebron","Jabbok","Legio","Madon","Migdol","Narbata","Naveh","Ramoth","Resen","Sabea","Sarid","Samaria"
    ];
    
    this.named_stations_custom_120 = [
    	"Memphis","Carthage","Alexandria","Benin","Kano","Laibela","Aksum","Djenne","Meroe","Tulum","Teotihuacan",
    	"Xochicalco","Palenque","Uxmal","Calakul","Chacchoben","Cuicuico","Kabah","Labna","Mitla","Sayil","Xlapak",
    	"Yagul","Dwarka","Kalpi","Chirand","Jajpur","Kannauj","Devkot","Lothal","Lashkar","Madurai"
    ];
    
    this.named_stations_custom_121 = [
    	"Ossian","Nashik","Sangrur","Rajapura","Quilon","Sagala","Prayag","Allahabad","Sopara","Taluk","Vidisha",
    	"Avanti","Vellore","Taxila","Uraiyur","Bhopal","Hagi","Kanazawa","Kitsuki","Tsuwano","Usuki","Matsue",
    	"Uchiko","Yokaichi","Asuka","Sakurai","Bitchu","Takahashi","Kawagoe","Naramachi","Matsumoto","Kyoto"
    ];
    
    this.custom_habitat_type3_style1b_1 = [
    	"Berlepsch","Leptos","Glaucous","Salamanca","Latham","Scopili","Surdus","Opterus","Puratus", 
    	"Temminck","Bavicus","Touit","Tepui","Andean","Dachilleae","lineola","Rufous","Aymara","Aurifrons", 
    	"Amoro","Auri","Taczanowski","Xanthops","Spengeli","Linnaeus","Modestus","Coelestis","Occidental", 
    	"Spicillatus","Pitrinus","Deroptyus","Homerius"
    ];
    
    this.custom_habitat_type3_style1b_2 = [
    	"Solitarius","Almeria","Nucha","Nochrous","Hypoi","Seram","Haruku","Saparua","Domicella","Goldiei", 
    	"Versi","Teuteles","Kakapo","Strigops","Notabilis","Productus","Nestor","Nestoridae","Rostris", 
    	"Tenui","Sulphurea","Sanguinea","Nator","Pasti","Ophthalmica","Saparua","Seram","Moluc","Censis", 
    	"Roselaar","Yamdena","Larat"
    ];
    
    this.custom_habitat_type3_style1b_3 = [
    	"Hausrot","Phoeni","Ficedula","Albicollis","Hypoleuca","Parva","Albicilla","Luscinia","Secica", 
    	"Nachti","Hynchos","Ruribit","Tarsiger","Cyaus","Irania","Calliope","Larviora","Sibilans","Cephei", 
    	"Rubecula","Erithacus","Muscicapa","Striata","Daurica","Musci","Cerco","Trichas","Migra","Toria", 
    	"Vorus","Visci","Iliacus", 
    ];
    
    this.custom_habitat_type3_style1b_4 = [
    	"Paradoxus","Fratercula","Arctica","Antiquus","Perdix","Ramphus","Impennis","Alca","Torda","Aalge", 
    	"Paradisaea","Bengalensis","Alphard","Censis","Elegans","Chlidonias","Hybrida","Caspia","Nilotica", 
    	"Albifrons","Chelidon","Sternula","Onychoprion","Anaethetus","Fuscata","Sterna","Aleutica","Larus", 
    	"Marinus","Glaucoides","Sonianus","Cachinan", 
    ];
    
    this.custom_habitat_type3_style2a_1 = [
    	"Cainhoe","Etonbury","Gobion","Odell","Podington","Renhold","Someries","Hampstead","Donnington","Windsor",
    	"Bolbec","Bradwell","Desborough","Lavendon","Kimble","Missenden","Turville","Wolverton","Boarstall","Aldreth",
    	"Bourn","Burwell","Cheveley","Eaton","Huntingdon","Rampton","Wisbech","Buckden","Elton","Kimbolton","Longthorpe",
    	"Woodcroft"
    ];
    
    this.custom_habitat_type3_style2a_2 = [
    	"Aldford","Dodlestone","Kingsley","Frodsham","Malpas","Nantwich","Newhall","Northwich","Pulford","Shipbrook",
    	"Shocklach","Shotwick","Warrington","Halton","Chester","Peckforton","Bishopton","Cotherstone","Dalden",
    	"Ludworth","Auckland","Barnard","Lambton","Mortham","Scargill","Helston","Penstowe","Upton","Launceston",
    	"Pendennis","Trematon","Denebola"
    ];
    
    this.list_of_scientists_subtable1 = [
    	"Newton","Halley","Copernicus","Galilei","Kepler","Cavendish","Lagrange","Dalton","Young","Hamilton",
    	"Earnshaw","Liouville","Drake","Planck","Schwarzschild","Born","Bohr","Heffern","Chapman","Hogarty",
    	"Oppengeimer","Feynman","Sakharov","Lehmann","Hubbard","Howley","Gottfried","Otacon","Fisher","Hawking",
    	"Binder","Freeman"
    ];
    
    this.list_of_scientists_subtable2 = [
    	"Cooper","Dyson","Sinclaire","Mendel","Keeling","Boyle","Hahn","Mendeleev","Lomonosov","Ostwald",
    	"Wegener","Malpighi","Dutrochet","Galvani","Ettinger","Starzl","Freud","Keller","Teller","Zhukobsky",
    	"Cayley","Kerans","Curie","Kissane","Lemaitre","Leacitt","Hubble","Plank","Susskind","Tsiolkovsky",
    	"Oberth","Turing"
    ];
    
    this.list_of_scientists_subtable3 = [
    	"Lovelace","Noether","Bolyai","Lobachevsky","Cardano","Fermat","Pascal","Huygems","Pointcare",
    	"Carwright","Lorenz","Wiener","Bellman","Zadeh","Shannon","Lafferty","Keynes","Koch","Cohn",
    	"Pasteur","Lamore","Aristotle","Chekov","Kilpatrick","Blackwood","McKay","Anaximander","Sarek",
    	"Battula","Koothrappali","Heriot","Ptolemy"
    ];
    
    this.list_of_military_leaders_subtable1 = [
    	"Brooke","Montgomery","Alexander","Wavell","Gort","Mohanty","Dowding","Cunningham","Montbatten",
    	"Lavell","Juin","Gamelin","Wayland","Darian","Eisenhower","MacArthur","Bradley","Lordan","Patton",
    	"Nimitz","Halsey","Fletcher","Spruance","Singh","Eaker","Spaatz","Zhukov","Vasilevsky","Kosovska",
    	"Shaposhnikov","Bagramyan","Konev"
    ];
    
    this.list_of_military_leaders_subtable2 = [
    	"Timoshenko","Isakov","Kuznetov","Yamasee","Khudyakov","Shukia","Pande","Winkelman","Kler",
    	"McNaughton","Rommel","Cromwell","Pym","Fairfax","Grant","Sherman","McCellan","Jackson",
    	"Washington","Rawat","Kosciuszko","Pulaski","Greene","Knox","Burgoyne","Morgan","Tarleton",
    	"Stark","Sharp","Hamilton","Lincoln","Lowery"
    ];
    
    this.list_of_military_leaders_subtable3 = [
    	"Howe","Caldwalader","Ashe","Haig","Pasha","Hindenburg","Petain","Foch","Haller","Falkenhagn",
    	"Diaz","Aleksegev","Zhekov","Schwarzkopf","Yeosock","Woodward","Lombardo","Geronimo","Pontiac",
    	"Teloses","Kintpuash","Osceola","Wovoka","Wellington","Murat","Radetz","Davout","Marmont",
    	"Saladin","Charlemagne","Ludden","Saini"
    ];
    
    this.list_of_astronauts_subtable1 = [
    	"Lydon","Macken","Conrad","Madden","Michell","Mannion","Irwin","Yong","Mansfield","Cernan","Schmitt",
    	"Borman","Lovell","Stafford","Gordon","Haise","Swigert","Roosa","Worden","Mattingly","Grissom","McCahon",
    	"Schirra","McDivitt","Stafford","Eisele","Schweickart","McCally","Brand","Engle","McAnnally","McAuliffee"
    ];
    
    this.list_of_astronauts_subtable2 = [
    	"Resnik","McNair","McClearn","Scobee","Chawla","Onizaka","Sullivan","McClenaghan","McBreen","Jemison",
    	"McCleave","Hurley","Melroy","Hadfield","Bowersox","Shuttleworth","Llewellyn","Llwei","Yang","Yaping",
    	"Heipeng","Zhigang","Junlong","Booming","Wang","Xiaoguang","Remek","Gargarin","Jahn","Ivanov","Tuan","Shepard"
    ];
    
    this.list_of_astronauts_subtable3 = [
    	"Mendez","Prunariu","Cretien","Sharma","Garneau","Vela","Mohmand","Kaleri","Viktorenko","Firmout","Bella",
    	"Pontes","Mansouri","Aimbetov","Mogensen","Shkor","Fuglesang","Ansari","McEnery","McGinity","Wolowitz",
    	"Hofstadter","Floyd","Chandra","Cochrane","Tsuno","Taylor","Urkel","Grayson","Simpson","Sedikh","McCauley"
    ];
    
    this.custom_bio_type3_style3a_1 = [
    	"Zalagar","Repton","Zircon","Discus","Arowana","Limpkin","Kelpie","Hellebore","Tarragon","Wendigo",
    	"Orphic","Jellico","Astromech","Dinton","Andoran","Lustrix","Hellespont","Mendham","Sacrado","Texlos",
    	"Babylon","Drennan","Barcella","Constantin","Gorton","Kingsley","Thorpe","Marshall","Goliath","Tokasha",
    	"Lootera","Olivetti"
    ];
    
    this.custom_bio_type3_style3a_2 = [
    	"Ironhold","Tokasha","Mualang","Irece","Dharma","Galileo","Kirin","Mangon","Gargain","Sheridan","Mercer",
    	"Holden","Alshain","Buhallin","Bulldog","Midway","Daisho","Matabushi","Luthien","Samarkand","Raimei",
    	"Nissan","Turanian","Tanadi","Surinami","Kankoku","Kurita","Banzai","Browning","Lexicon","Mendham","Laurent"
    ];
    
    this.custom_bio_type4_style2a_1 = [
    	"Firebird","Whitman","Indenture","Beckman","Anatass","Rosenkov","Kassa","Rodam","Haribon","Kedar",
    	"Haliat","Gateway","Devlon","Cerberus","Batarian","Armax","Aldrin","Parohe","Nashan","Borkat","Hislop",
    	"Cision","Jenan","Krishna","Burgat","Tiburon","Elanus","Narhu","Merida","Kore","Sonax","Phoenix"
    ];
    
    this.custom_bio_type4_style2a_2 = [
    	"Guanghui","Ashland","Skywire","Scopuli","Sirenum","Heleus","Isenberg","Insight","Saronis","Delumcore",
    	"Apex","Pyrena","Noveria","Baria","Janey","Micah","Cepheid","Heyuan","Genex","Sirta","Conatix","Bantam",
    	"Manatee","Ibex","Fenris","Palantir","Ragnarok","Warlock","Chimera","Philomela","Amalthea","Nemus"
    ];
    
    this.custom_bio_type4_style3a_1 = [
    	"Mosser","Darkes","Annalise","Berihn","Alioth","Ericsen","Nomura","Jannah","Rowan","Spartacus","Stenson",
    	"Vasquith","Dioscuri","Sheehan","Faust","Tanase","Corbeau","Draconis","Achenar","Rambert","Rasche","Dalibor",
    	"Pritchard","Arexack","Hansen","Pradesh","Hesperus","Calliope","Zeinali","Altera","Saunders","Juanita"
    ];
    
    this.custom_bio_type4_style3a_2 = [
    	"Kabden","Soladies","Munchausen","Onrira","Larais","Rhinitis","Acturan","Ruffalo","Nervosa","Keenan",
    	"Microsoft","Laurentiis","Rafaella","Atreides","Stockwell","Rautha","Haderach","Kardashian","Hudson",
    	"Fukunaga","Leiter","Krasinki","Romanoff","Hamilton","Mobius","Wahlberg","Banderas","Wachowski","Westwood",
    	"McLaren","Kronthaler","Versace"
    ];
    
    this.custom_bio_type5_style3_1 = [
    	"Kobol","Aerelon","Aquaria","Canceron","Caprica","Gemenon","Leonis","Libris","Bosporus","Aragona",
    	"Scorpia","Tauron","Virgon","Hibernia","Borgia","Baltar","Espenson","Atlanticus","Hestia","Pavia",
    	"Gramadas","Artemis","Queenstown","Minos","Zarek","Celeste","Hypatia","Nagala","Celtan","Tamara","Kellan",
    	"Columbia"
    ];
    
    this.custom_bio_type5_style3_2 = [
    	"Archeron","Inviere","Roslin","Agathon","Thorne","Cecere","Kendra","Burton","Versace","Rihanna",
    	"Toronto","Zurich","Laurent","Harper","Kronthaler","Ahluwalia","Galliano","Beaton","Princeton",
    	"Gherardini","Planck","Cepheid","Florence","Ludovico","Vasari","Gabriel","Caterina","Giocondo","Cecilia",
    	"Gallerani","Bernardino","Vercellina"
    ];
    
    this.custom_bio_type6_type1a_1 = [
    	"Hyperion","Atlas","Maliwan","Dahl","Torgue","Tediore","Stingray","Skyfall","Pandora","Marcus","Zoltan",
    	"Gearbox","Eridian","Seraph","Dexidous","Lynchwood","Southpaw","Triquetra","Morphous","Archer","Fremington",
    	"Paragon","Frostburn","Lascaux","Chulainn","Foster","Hammerlock","Jackenstein","Nakayama","Harpoon","Vermion",
    	"Siren","Tundra"
    ];
    
    this.custom_bio_type6_type1a_2 = [
    	"Thrall","Spycho","Firehawk","Tector","Hellfire","Bartlesby","Pitchfork","Jackpot","Longbow","Reinhart","Eridium",
    	"Hyperious","Rapier","Hornet","Thunderball","Logan","Sawtooth","Veruc","Mobley","McNally","Firefox","Seraphim",
    	"Seraph","Ahab","Deadwood","Stallion","Maverick","Patriot","Falchion","Paritisan","Flamerock","Banbury","Jinx"
    ];
    
    this.custom_habitat_type1_3a = [
    	"Richelieu","Noelle","Gaelle","Arnaude","Sartre","Pascale","Langlois","Laudine","Clotilde","Honorine",
    	"Flavie","Janvier","Albertine","Comtois","Berdine","Severine","Legrand","Fabien","Moulin","Plamondon", 
    	"Anastaise","Eustacia","Doriane","Bellerose","Armelle","Proulx","Daniau","Voclain","Faucher","Anouk", 
    	"Rosette","Capucine"
    ];
    
    this.custom_habitat_type1_3b = [
    	"Lamia","Mara","Agrona","Medeia","Layal","Zelda","Semele","Lailah","Adrienne","Persephone","Empusa", 
    	"Nishay","Persefoni","Loralai","Mallory","Narkissa","Delaynie","Lilitu","Megaera","Kakarauri","Jezebeth", 
    	"Cecilia","Melania","Nimue","Alekto","Cessair","Tisiphone","Sarka","Morana","Libitina","Aeron","Hadria", 
    ];
    
    this.custom_habitat_type1_3c = [
    	"Gideon","Jomei","Pravit","Chirag","Horatius","Geronimo","Bevan","Tlacelel","Rostam","Sinuhe","Luthais", 
    	"Raiden","Calhoun","Pharris","Luken","Laertes","Akio","Partho","Partho","Ingvar","Alih","Lesedi","Oran", 
    	"Fenyang","Sukhbataar","Kulvir","Kikosi","Hyldeihera","Aetheleorn","Karamveer","Omeet","Oisin", 
    ];
    
    this.custom_habitat_type1_3d = [
    	"Kalil","Raguel","Lele","Nobuo","Bakarsi","Nitis","Elden","Arluin","Greyn","Daemyn","Iyayi","Amit","Kelvin", 
    	"Wynn","Oswin","Ortwin","Samiul","Raham","Besnik","Ronan","Amnon","Takoda","Tomomi","Khalil","Samir","Derwin", 
    	"Alfwin","Auden","Liesel","Pamphilos","Besnik","Pamphilos", 
    ];
    
    this.custom_habitat_type2a_1 = [
    	"Timoren","Rhyncha","Austral","Patagonus","Cognathus","Sordox","Maculata","Eupsitula","Jandaya","Auricapillus", 
    	"Couloni","Aratinga","Couloni","Auricollis","Primolius","Severus","Militaris","Linnaeus","Macao","Gularis", 
    	"Chloropterus","Ararauna","Ambiguus","Bechstein","Orthops","Carolinensis","Salvadori","Guarouba","Nobilis", 
    	"Icterotis","Ognor","Hynchus"
    ];
    
    this.custom_habitat_type2a_2 = [
    	"Personatus","Reichenow","Fischer","Agapornis","Nithinae","Agapor","Oustalet","Desmarest","Hombron","Reichenbach", 
    	"Undulatus","Melops","Neopsitacus","Arfaki","Toxopei","Amabilis","Vereaux","Diadema","Notata","Rubro", 
    	"Pulchella","Placentis","Papuan","Palmarum","Palmlo","Margarethae","Josefinae","Richsen","Rocephala","Peuviana", 
    	"Stepheni","Australis"
    ];
    
    this.custom_habitat_type2a_3 = [
    	"Motacilla","Citreola","Calcarata","Tomohon","Tschut","Schensis","Flava","Petronia","Montanus","Eurasia", 
    	"Passer","Hispanica","Prunella","Montanella","Collaris","Dunnock","Modularis","Oenanthe","Leucopyga","Ipsilou", 
    	"Melano","Leuca","Chanka","Deserti","Oenanthe","Rubicola","Saxicola","Maurus","Solitarius","Saxatilis","Phoenicurus", 
    	"Mousieri"
    ];
    
    this.custom_habitat_type2a_4 = [
    	"Aegyptius","Caprimulgus","Europaeus","Funereus","Tengmalm","Asio","Flammeus","Otus","Strix","Noctua", 
    	"Surnia","Scandiacus","Scops","Tyto","Alba","Americanus","Tytonidae","Cuculus","Canorus","Clamator","Glandarius", 
    	"Cuculidae","Krameri","Turtur","Zenaida","Macroura","Orientalis","Decaocto","Columba","Palumbus","Oenas", 
    	"Columbidae"
    ];
    
    this.custom_habitat_style2_planets1 = [
    	"Ventris","Crassus","Crypto","Fuscicollis","Rufi","Rueppe","Pacifica","Rhodocephala","Hoematotis","Calliptera",
    	"Rupicola","Orcesi","Colombia","Melanura","Dicata","Egregia","Leucotis","Peruviana","Luciani","Santarem", 
    	"Amazonum","Caerulei","Subandina","Picta","Molinae","Lepida","Perlata","Devillei","Frontalis","Ochre","Cruentata","Terrisi"
    ];
    
    this.custom_habitat_style2_planets2 = [
    	"Schlegel","Ventris","Occidentalis","Neopsephotus","Splendida","Pulchella","Petrophila","Anthopeplus","Desmarest","Polytelis", 
    	"Vieillot","Jonquil","Aprosmictus","Lichtenstein","Scapularis","Molucca","Nensis","Amboi","Alisterus","Vernalis","Pusillus",  
    	"Stigmatus","Taliabu","Sclateri","Catamene","Auranti","Molucca","Loriculus","Nianus","Pullarius","Taranta","Reichenow", 
    ];
    
    this.custom_habitat_style2_planets3 = [
    	"Acanthis","Flammea","Carduelis","Cabaret","Spinus","Eurasia","Rostris","Flavi","Linaria","Cannabina","Linet", 
    	"Chloris","Serinus","Serin","Fringilla","Coelebs","Rubescens","Anthus","Oregon","Spinoletta","Petros","Cervinus", 
    	"Pratens","Gustavi","Pechora","Triviallis","Hodgsoni","Campestris","Argentatus","Leucopsis","Acilla","Motacilla", 
    ];
    
    this.custom_habitat_style2_planets4 = [
    	"Sayornis","Dryobates","Picoides","Buntspecht","Dendrocopos","Sphyrapicus","Viridis","Varius","Torquilla", 
    	"Jynx","Picidae","Botbotik","Upupa","Epops","Bucero","Upupidae","Coracias","Apiaster","Merops","Persicus", 
    	"Alcyon","Meropidae","Megaceryle","Alcedo","Alcedinidae","Apus","Tachymarptis","Pacificus","Palidus","Chaetura", 
    	"Pelagica","Hirundapus"
    ];
    
    this.list_of_place_names_subtable_1 = [
    	"England","Scotland","Sailsbury","Austria","Belgium","Bulgaria","Croatia","Kingston","Denmark","Estonia",
    	"Finland","France","Germany","Greece","Hungary","Ireland","Italy","Latvia","Lithuania","Luxembourg","Malta",
    	"Poland","Portugal","Romainia","Slovakia","Slovenia","Spain","Sweden","America","Africa","Australia","Antarctica"
    ];
    
    this.list_of_place_names_subtable_2 = [
    	"Europe","Amsterdam","Ankara","Winchester","Belgrade","Berlin","Preston","Bucharest","Budapest","Copenhagen",
    	"Dublin","Gibraltar","Helsinki","Kiev","Lisbon","London","Cardiff","Luxembough","Madrid","Minsk","Monaco",
    	"Moscow","Oslo","Chichester","Prague","Rome","Stockholm","Vienna","Warsaw","Sarajevo","Valietta","York"
    ];
    
    this.list_of_place_names_subtable_3 = [
    	"Alabama","Montgomery","Alaska","Mexico","Arizona","Phoenix","Ripon","California","Sacramento","Colorado",
    	"Denver","Connecticut","Halford","Delaware","Dover","Florida","Georgia","Atlanta","Hawaii","Honolulu","Idaho",
    	"Tamworth","Chicago","Indiana","Ely","Iowa","Matlock","Kentucky","Louisiana","Brighton","Maine","Portland"
    ];
    
    this.list_of_place_names_subtable_4 = [
    	"Maryland","Dover","Boston","Michigan","Detroit","Minnesota","Dorchester","Mississippi","Bangor","Missouri",
    	"Montana","Helena","Nebraska","Nevada","Omaha","Hampshire","Manchester","Jersey","Mexico","Alburquerque",
    	"Carolina","Bismark","Dakota","Caerlon","Oklahoma","Oregon","Salem","Pennsylvania","Philadelphia","Columbia",
    	"Nashvile","Tennessee"
    ];
    
    this.list_of_place_names_subtable_5 = [
    	"Texas","Houston","Utah","Vermont","Montipelier","Washington","Olympia","Seattle","Virginia","Charleston",
    	"Belfast","Bristol","Cambidge","Canterbury","Chelmsford","Coventry","Dundee","Durham","Exeter","Glasgow",
    	"Lancaster","Asaph","Leicster","Lincoln","Liverpool","Newcastle","Norwich","Perth","Nottingham","Plymouth",
    	"Sheffield","Southampton"
    ];
    
    this.list_of_place_names_subtable_6 = [
    	"Swansea","Westminster","Yorkshire","Essex","Cornwall","Devon","Sussex","Kent","Lancashire","Somerset","Algeria",
    	"Angola","Kenya","Cameroon","Zambia","Morocco","Egypt","Madagascar","Russia","Singapore","Taiwan","India",
    	"Indonesia","China","Japan","Pakistan","Malaysia","Canada","Cuba","Haiti","Holyhead","Jamaica"
    ];
    
    this.list_of_place_names_subtable_7 = [
    	"Bermuda","Panama","Argentina","Bolivia","Chile","Fiji","Mumbai","Delhi","Bangalore","Jaipur","Bhopal","Karachi",
    	"Lahore","Multan","Larkana","Islamabad","Okazaki","Toyokawa","Tsushima","Tokyo","Hiroshima","Hong Kong",
    	"Macau","Beijing","Shanghai","Tianjin","Cairo","Preroria","Mercury","Venus","Earth","Pluto"
    ];
    
    this.list_of_place_names_subtable_8 = [
    	"Mars","Tregaron","Harlech","Jupiter","Europa","Ganymede","Callistro","Saturn","Titan","Conway","Pembroke",
    	"Wrexham","Cowbridge","Neptune","Mercury","Charon","Mars","Lave","Betelgeuse","Rigel","Vega","Fomalhaut",
    	"Jupiter","Deneb","Alderbaran","Alitair","Penarth","Bala","Achermar","Capella","Pollux","Acrux"
    ];
    
    this.list_of_place_names_subtable_9 = [
    	"Algol","Bellatrix","Saiph","Vulcan","Bajor","Cardassia","Andor","Risa","Brecon","Vega","Orion","Rigel",
    	"Alderaan","Dabtooine","London","Colindale","Essex","Manchester","Yorkshire","Traal","Kakrafoon","Scotland",
    	"Magrathea","Kidwelly","Caladan","Madrid","Barcelona","Servile","Cartagena","Palma","Pamplona","Huelva"
    ];
    
    this.list_of_place_names_subtable_10 = [
    	"Almeria","Salamanca","Rhayader","Manresa","Marbella","Lugo","Palencia","Toledo","Xeer","Lave","Ceesexe",
    	"Ususor","Gerete","Reorte","Zaonce","Tionisla","Diso","Oreve","Riedquat","Leesti","Lampeter","Pryan",
    	"Chelestra","Abarrach","Bradford","Gallifrey","Skaro","Ruthin","Elgin","Oban","Arcadia","Eden"
    ];
    
    this.custom_buoy_repair1_list1 = [
    	"Lucius","Andre","Jenico","Piers","Klaus","Stefan","Walter","Gustavus","Mervyn","Jurgen","Karl","Wentworth",
    	"Ivor","Janric","Rupert","Casper","Archibald","Nathaniel","Laszio","Peregrine","Maximillian","Quintin",
    	"Hugo","Herwald","Bernardo","Louis","Aubin","Francois","Amable","Ivan","Igor","Leonid"
    ];
    
    this.custom_buoy_repair1_list2 = [
    	"Abhay","Ajay","Akhil","Amarjit","Bhavesh","Bhupinder","Chandrajit","Devendra","Devesh","Deepak","Eswar",
    	"Ganesh","Ganpatrao","Gurunath","Hansraj","Harish","Ishana","Jitendra","Karthik","Kishor","Lakshan","Mansukh",
    	"Mohindra","Munish","Nirupam","Prakash","Pranav","Rakesh","Ramakant","Ranbir","Shishira","Wasim"
    ];
    
    this.custom_buoy_repair1_list3 = [
    	"Arne","Birger","Bjon","Gorm","Halfdan","Harald","Knud","Skarde","Svend","Torsten","Leif","Tygve","Odger",
    	"Bodil","Frida","Hilda","Gudrun","Helga","Randi","Signe","Sigrid","Revna","Tora","Tove","Thyra","Thurid","Yrsa",
    	"Frode","Ulfhild","Njal","Sune","Troels"
    ];
    
    this.custom_buoy_repair1_list4 = [
    	"Alastair","Arran","Bram","Caelan","Clyde","Ewan","Graeme","Lennox","Malcolm","Kampbell","Keithen","Tavish",
    	"Aidan","Beacun","Blaine","Branigan","Brody","Breccan","Devin","Cullen","Cathal","Darcy","Eoin","Ferris",
    	"Fionn","Egan","Liam","Lorcan","Oscar","Roan","Rafferty","Torin"
    ];
    
    this.custom_buoy_repair1_list5 = [
    	"Abbad","Abdul","Adham","Badi","Bagher","Baha","Caden","Daud","Djamal","Ehsanullah","Fadel","Faisal","Farhat",
    	"Farooq","Gaffar","Ghanem","Hussein","Imran","Jabari","Jameel","Kadeem","Muhsin","Nabih","Omar","Osman","Samir",
    	"Qaid","Rabia","Rahim","Wazir","Yasser","Zabit"
    ];
    
    this.custom_buoy_repair1_list6 = [
    	"Akifumi","Akitomo","Bunta","Chikao","Daihachi","Eisaku","Fujio","Fuyukichi","Giichi","Hakaru","Harukichi",
    	"Hiromoto","Junnosuke","Junto","Kagetaka","Kazumichi","Masahiro","Masakage","Nariakira","Okimoto","Osamu",
    	"Otohiko","Rikiya","Ryu","Sadaharu","Sadakatsu","Shinta","Tadaaki","Tadamitsu","Tsunehiko","Tasuku","Yashiro"
    ];
    
    this.custom_buoy_repair1_list7 = [
    	"Aurick","Bernhard","Christof","Conrad","Dagobert","Egbert","Felix","Ferdinand","Fritz","Gerwin","Gunther",
    	"Gottfried","Harald","Heiner","Ignatz","Johann","Kaspar","Leopold","Lorentz","Ludwig","Luther","Magnus","Otto",
    	"Ottomar","Siegfried","Valter","Vollrath","Waldemar","Wilhelm","Ruprecht","Wolfgang","Xavier"
    ];
    
    this.custom_buoy_repair2_list1 = [
    	"Elizabeth","Victoria","Matilda","Eleanor","Catherine","Natalya","Anastasia","Ekaterina","Miriam","Veronica",
    	"Viktoriya","Adrienne","Elise","Fleur","Hermine","Isabella","Jacquelin","Juliette","Melanie","Nadia","Olivia",
    	"Heidi","Helena","Hildegard","Isabella","Johanna","Nadine","Rachel","Leopoldine","Karolina","Theresia","Cornelia"
    ];
    
    this.custom_buoy_repair2_list2 = [
    	"Sophia","Amelia","Augusta","Charlotte","Mary","Alexandrina","Josephine","Marie","Henrietta","Katharine",
    	"Beatrice","Margaret","Anne","Diana","Louise","Alice","Sarah","Camilla","Meghan","Sophie","Alberta","Lucy",
    	"Jane","Cynthia","Claire","Aisling","Shauna","Siobhan","Imogen","Deirdre","Nessa","Adel"
    ];
    
    this.custom_buoy_repair2_list4 = [
    	"Emily","Lillian","Edith","Madeline","Harriette","Helen","Florence","Lillian","Mabel","Judith","Veronica",
    	"Zara","Dorothy","Nancy","Jill","Josephine","Isobel","Beryl","Barbara","Rosalina","Rachael","Ingrid","Carol",
    	"Averil","Judith","Sally","Geraldine","Clare","Jacqueline","Constance","Susan","Jane"
    ];
    
    this.custom_astro_type1a_new = [
    	"Silverleaf","Romulus","Remus","De Beers","Coriolanus","Ardiente","Maximilian","Palpatine","Oceania","Aladeen",
    	"Comstock","Adami","Daredevil","Voldemort","Osborne","Wildflower","Cersei","Tarkin","Abstergo","Fontaine",
    	"Hyperion","Aesir","Shinra","Armitage","Paleocene","Honeypot","Baratheon","Sidious","Morlock","Amidala",
    	"Odessa","Bonaparte"
    ];
    
    this.custom_astro_type1b_new = [
    	"Cove","Hollow","Rock","Harbour","Bay","Wharf","Mine","Quarry","Goldmine"
    ];
    
    this.custom_astro_type1f_new = [
    	"Nicodemus","Rassilon","Thulsa","Krull","Malkoth","Komodo","Rendain","Varesh","Maestro","Solus","Astaroth",
    	"Balor","Bertoldo","Domenico","Moloch","Orthon","Tacito","Cormac","Naoise","Morbius"
    ];
    
    this.list_of_military_leaders_subtable1 = [
    	"Brooke","Montgomery","Alexander","Wavell","Gort","Mohanty","Dowding","Cunningham","Montbatten","Lavell","Juin",
    	"Gamelin","Wayland","Darian","Eisenhower","MacArthur","Bradley","Lordan","Patton","Nimitz","Halsey","Fletcher",
    	"Spruance","Singh","Eaker","Spaatz","Zhukov","Vasilevsky","Kosovska","Shaposhnikov","Bagramyan","Konev"
    ];
    
    this.list_of_military_leaders_subtable2 = [
    	"Timoshenko","Isakov","Kuznetov","Yamasee","Khudyakov","Shukia","Pande","Winkelman","Kler","McNaughton","Rommel",
    	"Cromwell","Pym","Fairfax","Grant","Sherman","McCellan","Jackson","Washington","Rawat","Kosciuszko","Pulaski",
    	"Greene","Knox","Burgoyne","Morgan","Tarleton","Stark","Sharp","Hamilton","Lincoln","Lowery"
    ];
    
    this.list_of_military_leaders_subtable3 = [
    	"Howe","Caldwalader","Ashe","Haig","Pasha","Hindenburg","Petain","Foch","Haller","Falkenhagn","Diaz","Aleksegev",
    	"Zhekov","Schwarzkopf","Yeosock","Woodward","Lombardo","Geronimo","Pontiac","Teloses","Kintpuash","Osceola",
    	"Wovoka","Wellington","Murat","Radetz","Davout","Marmont","Saladin","Charlemagne","Ludden","Saini"
    ];
    
    this.custom_science_type3_unique2_1 = [
    	"Blowpipe","Piranha","Hemlock","Colt","Lawman","Warlord","Nova","Messiah","Kendo","Remington","Glock","Ruger","Sauer",
    	"Beretta","Springfield","Browning","Winchester","Walther","Kimber","Mauser","Dallera","Hellfire","Brimstone","Albatros",
    	"Henschel","Rafael","Novator","Fireflash","Firestreak","Skyflash","Stinger","Hawker"
    ];
    
    this.custom_science_type3_unique2_2 = [
    	"Armadillo","Bulldog","Boomerang","Caudron","Helldiver","Blackhawk","Dassault","Nimrod","Kawanishi","Starfire",
    	"Lockheed","Nieuport","Tigershark","Hammerhead","Lancer","Zeppelin","Rockwell","Snark","Supermarine","Tololoche","Vickers",
    	"Vanguard","Whirlwind","Dornier","Communis","Firebrand","Hornet","Swordfish","Aardvark","Nighthawk","Hudson","Bronco"
    ];
    
    this.custom_science_type3_unique2_3 = [
    	"Gladius","Lansen","Vindicator","Vultee","Westland","Tokarev","Makarov","Lobaev","Simonov","Kalashnikov","Claymore","Solitare",
    	"Cerulean","Pancor","Rheinmetall","Sandia","Takoma","Versicorps","Littlehorn","Cordex","Rapier","Falchion","Doomsday","Gatling",
    	"Direwolf","Ravenskull","Warhawk","Warlord","Chessmaster","Antelope","Maxim","Fairchild"
    ];
    
    this.custom_bio_type1_style1_end = [
    	"Plc","Ltd","Inc"
    ];
    
    this.custom_science_type4_unique1 = [
    	"Hadron","Innes","Moredun","Quadram","Franklin","Denhart","Heseinberg","Scully","Hardwick","Heinrich","Skinner","Spender",
    	"Kersh","Kennedy","Whitestone","Blacksand","Gibson","Mahler","Mandel","Neider","Rahman","Reinhart","Schaeffer","Rademaker",
    	"Ophoven","Waterman","Bashar","Darwish","Hamdi","Kader","Khalid","Rahim"
    ];
    
    this.custom_science_type4_unique2 = [
    	"Ingman","Kafer","Kalbach","Kuehler","Mahler","Mulder","Armando","Bautista","Castellano","Florentino","Jaramillo","Lorenzo",
    	"Maduro","Mathias","Puerta","Sanchez","Santana","Valenciano","Riversong","Freeman","Abiodun","Adeleke","Chidubem","Obiakolam",
    	"Temitope","Beltran","Gallardo","Maldonado","Pacheco","Palacios","Quintero","Velasco"
    ];
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function () {
    	this._phraseGen = worldScripts.GNN_PhraseGen;
    	if (missionVariables.PlanetFall2_StoredNames) {
    		this.nameStore = JSON.parse(missionVariables.PlanetFall2_StoredNames);
    		delete missionVariables.PlanetFall2_StoredNames;
    	}
    	if (this.nameStore[galaxyNumber] == undefined) {
    		for (var i = 0; i <= 7 ; i++) {
    			this.nameStore[i] = {};
    			for (var j = 0; j <= 255; j++) {
    				this.nameStore[i][j] = {};
    			}
    		}
    	}
    	if (worldScripts.RandomStationNames) this.rsnInUse = true;
    	// override the rsn flag if we've specifically turned it off.
    	if (worldScripts.PlanetFall2._config.useGANames == false) this.rsnInUse = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function() {
    	missionVariables.PlanetFall2_StoredNames = JSON.stringify(this.nameStore);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_CapitalCity = function $PF_CapitalCity(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.planetFall_mainSurface_capitalCity_name1a),
    			fieldB: [].concat(this.planetFall_mainSurface_capitalCity_name1b),
    			fieldC: [].concat(this.planetFall_mainSurface_capitalCity_name1c),
    			fieldD: ["[1]","[2]","[3]"],
    			fieldE: [].concat(this.planetFall_opening_words1_alt), //5
    			fieldF: [].concat(this.planetFall_opening_words1_alt4),
    			fieldG: [].concat(this.planetFall_opening_words1_alt5),
    			fieldH: [].concat(this.planetFall_opening_words1_alt6),
    			fieldI: ["[7] Control","[7] Control","Tourist [5]","(D50=Ministry|Department) of [6]","Visitors [5]","[8] Embassy","Planetary Capital","Trading [5]"],
    			
    			fieldJ: [].concat(this.list_of_oldgods_subtable1).concat(this.list_of_oldgods_subtable2).concat(this.list_of_oldgods_subtable3).concat(this.named_stations_custom_101).concat(this.named_stations_custom_102),
    			fieldK: [],
    			fieldL: [],
    			fieldM: [].concat(this.planetFall_ending_words1),
    			fieldN: [].concat(this.list_of_heros_subtable1).concat(this.list_of_heros_subtable2).concat(this.list_of_heros_subtable3),
    			fieldO: [].concat(this.named_stations_custom_119).concat(this.named_stations_custom_120).concat(this.named_stations_custom_121),
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"New 4 (9)",
    				"{1 4 (}9)",
    				"{5 4 (}9)",
    				"{6 4 (}9)"
    			],
    		};
    		// special case for anarchies, that shouldn't have things like "Immigration Control"
    		if (system.government == 0) def.fieldI = ["Tourist [5]","(D50=Ministry|Department) of [6]","Visitors [5]","[8] Embassy","Planetary Capital","Trading [5]"];
    
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_LeisureComplex = function $PF_LeisureComplex(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.planetFall_mainSurface_leisureComplex_name1).concat(this.planetFall_mainSurface_leisureComplex_name2),
    			fieldB: [].concat(this.planetFall_mainSurface_leisureComplex_name3),
    			fieldC: [].concat(this.planetFall_mainSurface_leisureComplex_name3a),
    			fieldD: [].concat(this.general_names_list_subtable_4),
    			fieldE: [].concat(this.general_names_list_subtable_5),
    			fieldF: [].concat(this.planetFall_mainSurface_leisureComplex_name5a),
    			fieldG: ["[4]","[5]"],
    			fieldH: [].concat(this.general_names_list_subtable_1).concat(this.general_names_list_subtable_2).concat(this.general_names_list_subtable_3).concat(this.general_names_list_subtable_4).concat(this.general_names_list_subtable_5),
    			fieldI: ["Bristol Zoo","Flamingo Land","Lakeland Oasis","Longleat Zoo","Monkey World",
    			"The Living Rainforest","Bermuda Aquarium","Holdstock Serpentarium","World of Snakes","[8] Hive","[8] Zoo","[8] Serpentarium","[8] Aviary",
    			"[8] Apiary","[8] Vespiary","[8] Cattery","[8] Kennels","[8] Aquarium","[8] Reserve","[8] Sanctuary","[8] Wetlands","[8] Vivarium",
    			"[8] Zoo","[8] Aviary","[8] Apiary","[8] Cattery","[8] Vivarium","[8] Aquarium","[8] Zoo","[8] Kennels","[8] Wetlands","[8] Aquarium"].concat(this.planetFall_mainSurface_leisureComplex_name6),
    
    			fieldJ: [].concat(this.planetFall_mainSurface_leisureComplex_name8),
    			fieldK: [].concat(this.planetFall_mainSurface_leisureComplex_name_alt1),
    			fieldL: [].concat(planetFall_mainSurface_leisureComplex_name9),
    			fieldM: [].concat(this.planetFall_mainSurface_leisureComplex_name1).concat(this.planetFall_mainSurface_leisureComplex_name2).concat(this.planetFall_mainSurface_leisureComplex_name6),
    			fieldN: [].concat(this.planetFall_mainSurface_leisureComplex_name_alt2),
    			fieldO: [].concat(this.custom_habitat_type3_style2a_1).concat(this.custom_habitat_type3_style2a_2),
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 (Water Park)",
    				"2 3 (Games Arcade)",
    				"7 6 (Botanical Gardens)",
    				"9 (Public Menagerie)",
    				"The {6 1 (Cinema 2)",
    				"9 (Safari Park)",
    				"{3 (Vacuum Karate Dojo)",
    				"The {6 1 (Videodrome 2)",
    				"{4 (Theme Park)",
    				"{4 (5 2)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_MilitaryBase = function $PF_MilitaryBase(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.planetFall_mainSurface_militaryBase_name2),
    			fieldB: [].concat(this.planetFall_mainSurface_militaryBase_name3),
    			fieldC: [].concat(this.general_names_list_subtable_1).concat(this.general_names_list_subtable_2).concat(this.general_names_list_subtable_3),
    			fieldD: [].concat(this.planetFall_opening_words3_alt),
    			fieldE: [].concat(this.planetFall_opening_words3_alt2),
    			fieldF: [].concat(this.list_of_military_leaders_subtable1).concat(this.list_of_military_leaders_subtable2).concat(this.list_of_military_leaders_subtable3),
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 6 (4 5)",
    				"3 2 (4 5)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_Factory = function $PF_Factory(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_bio_type3_style3a_1),
    			fieldB: [].concat(this.custom_bio_type3_style3a_2),
    			fieldC: [].concat(this.planetFall_ending_words4),
    			fieldD: [].concat(this.planetFall_opening_words5a),
    			fieldE: [].concat(this.planetFall_opening_words5b),
    			fieldF: ["[1]","[2]"],
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"6 3 (4 5)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_Dump = function $PF_Dump(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_bio_type5_style3_1),
    			fieldB: [].concat(this.custom_bio_type5_style3_2),
    			fieldC: [].concat(this.planetFall_ending_words7),
    			fieldD: [].concat(this.planetFall_opening_words8a),
    			fieldE: [].concat(this.planetFall_opening_words6b),
    			fieldF: ["[1]","[2]"],
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"6 3 (4 5)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
    	return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_ColonyCity = function $PF_ColonyCity(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_bio_type6_type1a_1).concat(this.custom_bio_type6_type1a_2),
    			fieldB: ["[4] [7]","[5] [7]","[6] [8]"],
    			fieldC: [].concat(this.planetFall_ending_words8),
    			fieldD: [].concat(this.planetFall_opening_words9_alt),
    			fieldE: [].concat(this.planetFall_opening_words9_alt2),
    			fieldF: [].concat(this.planetFall_opening_words9_alt3),
    			fieldG: [].concat(this.planetFall_opening_words9_ending),
    			fieldH: [].concat(this.planetFall_opening_words9_ending2),
    			fieldI: [].concat(this.custom_habitat_type2a_1).concat(this.custom_habitat_type2a_2).concat(this.custom_habitat_type2a_3).concat(this.custom_habitat_type2a_4),
    			fieldJ: [].concat(this.planetFall_subSurface_colony_name2),
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 3 (2)",
    				"9 {1 (}2)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_ColonyMilitaryBase = function $PF_ColonyMilitaryBase(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_habitat_type1_3a),
    			fieldB: [].concat(this.custom_habitat_type1_3b),
    			fieldC: [].concat(this.custom_habitat_type1_3c),
    			fieldD: [].concat(this.custom_habitat_type1_3d),
    			fieldE: [].concat(this.planetFall_ending_words10),
    			fieldF: [].concat(this.planetFall_opening_words10_alt1),
    			fieldG: ["Military [6]","Naval [6]"],
    			fieldH: ["[1]","[2]","[3]","[4]"],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"8 5 (7)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_OOHaul = function $PF_OOHaul(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.list_of_heros_subtable1),
    			fieldB: [].concat(this.list_of_heros_subtable2),
    			fieldC: [].concat(this.list_of_heros_subtable3),
    			fieldD: [].concat(this.list_of_oldgods_subtable1),
    			fieldE: [].concat(this.list_of_oldgods_subtable2),
    			fieldF: [].concat(this.list_of_oldgods_subtable3),
    			fieldG: [].concat(this.planetFall_mainSurface_oohaul_name2),
    			fieldH: ["[1]","[2]","[3]","[4]","[5]","[6]"],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"8 7 (Distribution Centre)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_Blackmonks = function $PF_Blackmonks(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.planetFall_ending_words9),
    			fieldB: [].concat(this.planetFall_subSurface_colony_name1),
    			fieldC: [].concat(this.planetFall_opening_words9_ending),
    			fieldD: ["Monastic [3]","Ecclesiastic [3]","Clerical [3]",],
    			fieldE: [],
    			fieldF: [],
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 2 (4)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_HoopyCasino = function $PF_HoopyCasino(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.planetFall_Surface_hoopy_name1a).concat(this.planetFall_Surface_hoopy_name1b),
    			fieldB: [].concat(this.planetFall_Surface_hoopy_name2),
    			fieldC: [],
    			fieldD: [],
    			fieldE: [],
    			fieldF: [],
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 2 (HoOpy Casino)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_MoonDome = function $PF_MoonDome(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_habitat_type3_style1b_1).concat(this.custom_habitat_type3_style1b_2).concat(this.custom_habitat_type3_style1b_3).concat(this.custom_habitat_type3_style1b_4),
    			fieldB: [],
    			fieldC: [],
    			fieldD: [],
    			fieldE: [].concat(this.planetFall_moonSurface_dome_ending),
    			fieldF: [].concat(this.planetFall_moon_describe1).concat(this.planetFall_moon_describe_rocks),
    			fieldG: [].concat(this.planetFall_moon_describe2),
    			fieldH: [].concat(this.planetFall_moon_describe3),
    			fieldI: [].concat(this.planetFall_moon_describe4),
    
    			fieldJ: [].concat(this.planetFall_moon_describe5),
    			fieldK: [].concat(this.planetFall_moon_describe6),
    			fieldL: [].concat(this.planetFall_moon_describe_place1),
    			fieldM: [].concat(this.planetFall_moon_describe_place2a).concat(this.planetFall_moon_describe_place2b).concat(this.planetFall_moon_describe_place2c),
    			fieldN: [],
    			fieldO: ["[1]","[2]","[3]","[4]"],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 5 (6 7)",
    				"1 5 (8 9)",
    				"1 5 ({1 2)",
    				"1 5 ({3 4)",
    				"1 5 ({3 4)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_MoonMine = function $PF_MoonMine(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_astro_type1a_new).concat(this.custom_astro_type1f_new),
    			fieldB: [].concat(this.custom_astro_type1b_new),
    			fieldC: [].concat(this.planetFall_moon_describe_mine1),
    			fieldD: [].concat(this.planetFall_moon_describe_mine2),
    			fieldE: [],
    			fieldF: [],
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 2 (3 4)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_MoonPrison = function $PF_MoonPrison(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.list_of_military_leaders_subtable1).concat(this.list_of_military_leaders_subtable2).concat(this.list_of_military_leaders_subtable3),
    			fieldB: [].concat(this.planetFall_moon_describe_prison3),
    			fieldC: [].concat(this.planetFall_moon_describe_prison1),
    			fieldD: [].concat(this.planetFall_moon_describe_prison2),
    			fieldE: [],
    			fieldF: [],
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 2 (3 4)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_MoonResearch = function $PF_MoonResearch(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_science_type3_unique2_1).concat(this.custom_science_type3_unique2_2).concat(this.custom_science_type3_unique2_3),
    			fieldB: [].concat(this.planetFall_moon_describe_base3),
    			fieldC: [].concat(this.custom_bio_type1_style1_end),
    			fieldD: [].concat(this.planetFall_moon_describe_base1),
    			fieldE: [].concat(this.planetFall_moon_describe_base2),
    			fieldF: [],
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 2 3 (4 5)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_MoonFactory = function $PF_MoonFactory(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: [].concat(this.custom_science_type4_unique1).concat(this.custom_science_type4_unique2),
    			fieldB: [].concat(this.planetFall_moonSurface_factory_name2),
    			fieldC: [].concat(this.custom_bio_type1_style1_end),
    			fieldD: [].concat(this.planetFall_moon_describe_base1),
    			fieldE: [].concat(this.planetFall_moon_describe_base2),
    			fieldF: [].concat(this.planetFall_moon_describe1).concat(this.planetFall_moon_describe_rocks),
    			fieldG: [].concat(this.planetFall_moon_describe2),
    			fieldH: [].concat(this.planetFall_moon_describe3),
    			fieldI: [].concat(this.planetFall_moon_describe4),
    			fieldJ: [].concat(this.planetFall_moon_describe5),
    			fieldK: [].concat(this.planetFall_moon_describe6),
    			fieldL: [].concat(this.planetFall_moon_describe_place1),
    			fieldM: [].concat(this.planetFall_moon_describe_place2a).concat(this.planetFall_moon_describe_place2b).concat(this.planetFall_moon_describe_place2c),
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 2 3 (6 7)",
    				"1 2 3 (8 9)",
    				"1 2 3 ({1 2)",
    				"1 2 3 ({3 4)",
    				"1 2 3 ({3 4)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$PF_MoonWasteland = function $PF_MoonWasteland(dataKey) {
    	if (!this.rsnInUse) return "";
    	var stored = this.nameStore[galaxyNumber][system.ID][dataKey];
    	if (!stored) {
    		var def = {
    			fieldA: ["Vault [2]","Fallout Shelter [2]","Emergency [3] [2]","[4] Post [2]"],
    			fieldB: [].concat(this.planetFall_moonSurface_wasteLand_name3a),
    			fieldC: [].concat(this.planetFall_moonSurface_wasteLand_name3b),
    			fieldD: [].concat(this.planetFall_moonSurface_wasteLand_name3c),
    			fieldE: [].concat(this.planetFall_moonSurface_wasteLand_name1),
    			fieldF: [].concat(this.planetFall_moonSurface_wasteLand_name2),
    			fieldG: [],
    			fieldH: [],
    			fieldI: [],
    			fieldJ: [],
    			fieldK: [],
    			fieldL: [],
    			fieldM: [],
    			fieldN: [],
    			fieldO: [],
    			fieldP: [],
    			fieldQ: [],
    			fieldR: [],
    			sentences: [
    				"1 (5 6)"
    			],
    		};
    		var text = this._phraseGen._makePhrase(def);
    		this.nameStore[galaxyNumber][system.ID][dataKey] = text;
    	} else {
    		var text = stored;
    	}
        return text;
    }
    
    Scripts/planetFall2_shipyards.js
    "use strict";
    this.name = "PlanetFall2_Shipyards";
    this.author = "phkb";
    this.copyright = "CC-BY-SA-NC 4.0";
    this.description = "Controls shipyard populations";
    
    /*
        This script moves the majority of ships on orbital station shipyards to planetary shipyards instead.
    */
    this.index = 0; // indicates where in the process we're up to.
    this.transferred = false; // indicates whether the transfer process has completed
    this.shipTransfer = false; // indicates whether we're up to the actual ship transfer part
    this.mainShipyards = [];
    this.otherShipyards = [];
    this.orbitalShipyards = [];
    this.debug = true;
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function () {
        if (this.index != -1) {
            missionVariables.PlanetFall2_ShipyardTransfer = (this.transferred == true ? "1" : "0");
            missionVariables.PlanetFall2_ShipTransferPhase = (this.shipTransfer == true ? "1" : "0")
            missionVariables.PlanetFall2_ShipyardProgress = this.index;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.systemWillPopulate = function () {
        this.mainShipyards.length = 0
        this.otherShipyards.length = 0;
        this.orbitalShipyards.length = 0;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function () {
        this.playerShipKeys = Ship.keysForRole("player");
    
        if (missionVariables.PlanetFall2_ShipyardProgress) {
            this.index = parseInt(missionVariables.PlanetFall2_ShipyardProgress);
        } else {
            this.index = -1;
        }
        if (this.index != -1) {
            if (missionVariables.PlanetFall2_ShipyardTransfer) this.transferred = (missionVariables.PlanetFall2_ShipyardTransfer == "0" ? false : true);
            if (missionVariables.PlanetFall2_ShipTransferPhase) this.shipTransfer = (missionVariables.PlanetFall2_ShipTransferPhase == "0" ? false : true);
        } else {
            this.transferred = true;
            this.shipTransfer = false;
        }
        delete missionVariables.PlanetFall2_ShipyardProgress;
        delete missionVariables.PlanetFall2_ShipyardTransfer;
        delete missionVariables.PlanetFall2_ShipTransferPhase;
        if (!worldScripts.PlanetFall2._config.moveShipyards) this.transferred = true;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function() {
        this.shipDockedWithStation();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillEnterWitchspace = function() {
        // if shipyards are being moved, reset the flag to indicate the transfer hasn't happened yet
        if (worldScripts.PlanetFall2._config.moveShipyards) {
            this.transferred = false;
            this.index = 0;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDockedWithStation = function() {
        if (worldScripts.PlanetFall2._config.moveShipyards && this.transferred == false) {
            this._timer0 = new Timer(this, this.$moveShipsFromShipyards.bind(this), 3, 0);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillLaunchFromStation = function() {
        // stop everything if we launch - too much stuttering
        this.$stopTimers();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$stopTimers = function() {
        if (this._timer0 && this._timer0.isRunning) this._timer0.stop();
        if (this._timer1 && this._timer1.isRunning) this._timer1.stop();
        if (this._timer2 && this._timer2.isRunning) this._timer2.stop();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$moveShipsFromShipyards = function $moveShipsFromShipyards() {
        function mainPlanetShipyards(entity) { return (entity.isStation && entity.hasRole("planetFall2_mainSurface") && entity.hasShipyard) };
        function otherPlanetShipyards(entity) { return (entity.isStation && entity.hasRole("planetFall2_subSurface") && entity.hasShipyard) };
        function stationShipyards(entity) { return (entity.isStation && !entity.hasRole("planetFall2_surface") && entity.maxSpeed == 0 && !entity.scriptInfo["planetFall_leaveShipyard"] && entity.hasShipyard) };
        // first, get a set of planet stations with shipyards
        // including secondary planets
        if (this.mainShipyards.length == 0) this.mainShipyards = system.filteredEntities(system.stations, mainPlanetShipyards);
        if (this.otherShipyards.length == 0) this.otherShipyards = system.filteredEntities(system.stations, otherPlanetShipyards);
        if (this.orbitalShipyards.length == 0) {
            this.orbitalShipyards = system.filteredEntities(system.stations, stationShipyards);
            // if we're docked at an orbital shipyard, we only need to process that station
            // if we aren't docked at an orbital shipyard, we need to process everything
            if (this.orbitalShipyards.indexOf(player.ship.dockedStation) >= 0) {
                // empty the orbital shipyards array, then add a single station
                this.orbitalShipyards.length = 0;
                this.orbitalShipyards.push(player.ship.dockedStation);
            }
        }
        if (this.orbitalShipyards.length == 0) return; // no orbitals with shipyards
        if (this.mainShipyards.length == 0 && this.otherShipyards.length == 0) return; // no planet sites with shipyards (should be *very* rare)
        // only reset the index if it's in the "finished" state
        if (this.index == -1) this.index = 0;
        // we'll process each station one at a time to limit slowdowns
        if (this.shipTransfer == true) {
            this._timer2 = new Timer(this, this.$processStationShips.bind(this), 0.3, 0);
            return;
        }
        if (this.debug) log(this.name, "initialising station shipyards");
        if (this._timer1 && this._timer1.isRunning) this._timer1.stop();
        this._timer1 = new Timer(this, this.$processStation.bind(this), 1.5, 0);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // all we're doing first is forcing shipyards to populate, one station at a time
    this.$processStation = function $processStation() {
        // if we've got to the end of populating shipyards, we can now start the process of moving ships
        if (this.index > this.orbitalShipyards.length - 1) {
            this.index = 0;
            this.shipTransfer = true;
            if (this.debug) {
                log(this.name, "station shipyards setup complete");
                log(this.name, "starting shipyards transfer process")
            }
            this._timer2 = new Timer(this, this.$processStationShips.bind(this), 0.3, 0);
            return;
        }
        var stn = this.orbitalShipyards[this.index];
        // set up for the next station now, in case the shipyard creation runs overtime
        this.index += 1;
        if (this._timer1 && this._timer1.isRunning) this._timer1.stop();
        this._timer1 = new Timer(this, this.$processStation.bind(this), 1.5, 0);
        var num = stn.shipyard.length; // force shipyard to load
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // once all the stations have a populated shipyard, we do things one ship at a time to prevent timeouts
    this.$processStationShips = function $processStationShips() {
        if (this.index > this.orbitalShipyards.length - 1) {
            this.transferred = true;
            this.shipTransfer = false;
            this.index = -1;
            if (this.debug) log(this.name, "processing shipyards complete");
            return;
        }
        var skeys = this.playerShipKeys;
        var stn = this.orbitalShipyards[this.index];
        var i = stn.shipyard.length - 1;
        if (i >= 0) {
            // work out if we're going to stop now
            if (i < 2) {
                // 33% chance of stopping when 2 ships remain
                // 67% chance of stopping when 1 ship remains
                if (Math.random() > ((i + 1) / 3)) {
                    i = -1;
                }
            } 
            if (i >= 0) {
                var shp = stn.shipyard[i];
                // if the data key for this ship isn't in the list of player keys, skip the adding process and just delete it
                // the player wouldn't be able to fly it anyway
                if (skeys.indexOf(shp.shipdata_key) >= 0) {
                    // build up the object from the source
                    var obj = {};
                    obj.short_description = shp.short_description;
                    obj.shipdata_key = shp.shipdata_key;
                    obj.price = shp.price;
                    obj.personality = shp.personality;
                    obj.extras = (shp.extras ? shp.extras : []);
    
                    //log(this.name, "station " + stn);
                    // pick a destination, with weighting towards main planet
                    if (Math.random() < 0.75 || this.otherShipyards.length == 0) {
                        var idx = Math.floor(Math.random() * this.mainShipyards.length);
                        //log(this.name, "main yards shipkey " + obj.shipdata_key);
                        this.mainShipyards[idx].addShipToShipyard(obj);
                    } else {
                        var idx = Math.floor(Math.random() * this.otherShipyards.length);
                        //log(this.name, "other yards shipkey " + obj.shipdata_key);
                        this.otherShipyards[idx].addShipToShipyard(obj);
                    }
                }
                // remove the ship from the source
                stn.removeShipFromShipyard(i);
            }
        }
        if (i <= 0) {
            // set up for the next station
            this.index += 1;
        }
        this._timer2 = new Timer(this, this.$processStationShips.bind(this), 0.3, 0);
    }
    
    Scripts/planetFall2_trainFX.js
    "use strict";
    this.name = "planetFall2_trainFX";
    this.author = "Svengali & Thargoid";
    this.copyright = "CC-by";
    this.description = "FX script";
    this.version = "1.0";
    
    this.effectSpawned = function () {
    	this.firstFrame = true;
    	this.getRid = 0;
        this.zooming = 0;
    	this.mult = worldScripts.PlanetFall2.fx_mult;
    	// orient the visual effect
        this.visualEffect.orientation = player.ship.orientation;
    	// start the frame callback
    	this.ovFCBID = addFrameCallback(this.repos.bind(this));
    	player.ship.hudHidden = true;
    }
    
    this.effectRemoved = function () { 
    	removeFrameCallback(this.ovFCBID); 
    }
    
    this.repos = function (delta) {
    	var p = player.ship;
    	if (!p.isValid || this.getRid >= 3) {
    		this.visualEffect.remove();
    		return;
    	}
    
    	if (this.firstFrame || !delta) {
    		this.firstFrame = false;
    		return;
    	}
    
    	this.visualEffect.position = p.position.add(p.vectorForward.multiply(worldScripts.PlanetFall2.fx_launch_dist));
    	this.visualEffect.orientation = p.orientation;
        this.visualEffect.scale(1 + this.zooming);
        this.zooming += delta * this.mult;
    	this.getRid += delta; // to get the effect finished before true launch into realspace
    	return;
    }
    
    Scripts/planetFall2_transit.js
    "use strict";
    this.name = "PlanetFall2_Transit";
    this.author = "Thargoid, phkb, with bits from Eric Walch, Frame and Svengali";
    this.copyright = "Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme.txt.";
    this.description = "Allows player to move between planetary locations without manually launching and redocking";
    
    this._pf;
    this._default = "";
    this._hairSpace = String.fromCharCode(31);
    this._hairSpaceLength = defaultFont.measureString(this._hairSpace);
    this._ellip = "…";
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function() {
        this._pf = worldScripts.PlanetFall2;
        // make sure we have the variable set
        if (!missionVariables.PlanetFall2_DockedStation && player.ship.dockedStation.hasRole("planetFall2_surface")) {
            missionVariables.PlanetFall2_DockedStation = player.ship.dockedStation.dataKey;
        }
        this.shipDockedWithStation(player.ship.dockedStation);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDockedWithStation = function(station) {
        if (station.hasRole("planetFall2_surface") && this._pf._config.transit.allowed) {
            // count the number of sites on this planet
            var sub = this.$surfaceSites();
            if (sub.length == 1) {
                station.setInterface(this.name, null);
                station.setInterface(this.name + "_2", null);
                return;
            }
            this.$initInterface(station);
        } else {
            station.setInterface(this.name, null);
            station.setInterface(this.name + "_2", null);
        }
        this.$clearUpF4Interfaces();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$surfaceSites = function(excl) {
    	var pl = this._pf.$getPlanetFromCoords(player.ship.dockedStation.linkedPlanetPos)
        var stns = system.shipsWithRole("planetFall2_surface");
        var sub = [];
        var i = stns.length;
        while (i--) {
            if (this._pf.$getPlanetFromCoords(stns[i].linkedPlanetPos) == pl && stns[i].allegiance != "restricted") {
                if (!excl || stns[i] != excl) sub.push(stns[i]);
            }
        }
        return sub;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$initInterface = function $initInterface(station) {
        station.setInterface(this.name, {
            title: "Planetary Transit System",
            category: "Planet-side Services",
            summary: "Subterranean train system to enable fast travel to other destinations on the planet.",
            callback: this.$showStationList.bind(this)
        });
        if (missionVariables.PlanetFall2_DockedStation != station.dataKey) {
            station.setInterface(this.name + "_2", {
                title: "Ship Transfer Service",
                category: "Planet-side Services",
                summary: "Transfer your ship to your current location, for a fee.",
                callback: this.$transferShip.bind(this)
            });
        } else {
            station.setInterface(this.name + "_2", null);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$showStationList = function() {
        var curChoices = {};
        var text = "";
        var col1 = 23;
        var col2 = 2
        var col3 = 30 - (col1 + col2);
        var tffee = parseInt(this._pf._config.shipTransfer.fee * this._pf._config.shipTransfer.governmentFactor[system.government]);
        var tm = this._pf._config.shipTransfer.time;
        var fee = parseInt(this._pf._config.transit.fee * this._pf._config.transit.governmentFactor[system.government]);
    
        text = "Current location: " + player.ship.dockedStation.displayName + "\n";
        text += "Trains depart every 15 minutes. " + 
            (fee > 0 ? "Cost: " + formatCredits(fee, false, true) : "All trips are free.") +
            "  Check board for travel times.\n\n";
    
        var top = 13;
        if (player.ship.hudAllowsBigGui) top = 19;
    
        if (missionVariables.PlanetFall2_DockedStation == player.ship.dockedStation.dataKey) {
            text += "Your ship is berthed at this location.\n\nPlease note: " + 
                "Launching from one of these other destinations will incur a ship transfer fee of " + formatCredits(tffee, false, true) + 
                ", and delivery will take approximately " + tm.toFixed(1) + " hours.";
            top -= 2;
        } else {
            text += "Please note: Requesting a launch from your current location will incur a transfer fee of " + formatCredits(tffee, false, true) + 
                ", and delivery will take approximately " + tm.toFixed(1) + " hours.";
        }
        var sites = this.$surfaceSites(player.ship.dockedStation);
        
        curChoices["00_A"] = {
            text: this.$padText("Destination", col1 + col2) + this.$padText("Travel Time", col3, true),
            color: "0 0.6 0 1",
            alignment: "LEFT",
            unselectable: true
        };
        for (var i = 0; i < sites.length; i++) {
            curChoices["0" + i.toString() + "_SITE"] = {
                text: this.$padText(sites[i].displayName, col1) + 
                    this.$padText((missionVariables.PlanetFall2_DockedStation == sites[i].dataKey ? "*" : ""), col2) +
                    this.$padText(this.$travelTime(sites[i]).toString() + " mins", col3, true),
                color: (player.credits < fee && missionVariables.PlanetFall2_DockedStation != sites[i].dataKey ? "darkGrayColor" : "greenColor"),
                alignment: "LEFT",
                unselectable: (player.credits < fee && missionVariables.PlanetFall2_DockedStation != sites[i].dataKey ? true : false)
            };
        }
        var extra = 0;
        if (missionVariables.PlanetFall2_DockedStation != player.ship.dockedStation.dataKey) {
            extra += 1;
            curChoices["90_A"] = {
                text: "* = Location where ship is berthed",
                color: "grayColor",
                alignment: "LEFT",
                unselectable: true
            };
        }
    
        if (fee > 0 && player.credits < fee * 2 && player.credits >= fee) {
            extra += 1;
            curChoices["91_A"] = {
                text: "**ATTENTION** You have insufficient funds to make a return journey!",
                color: "whiteColor",
                unselectable: true
            };
        }
    
        for (var i = 0; i < (top - (sites.length + extra)); i++) {
            curChoices["98_SPACER_" + i.toString()] = {
                text: "",
                unselectable: true
            };
        }
    
        curChoices["99_EXIT"] = "Exit";
        if (this._default == "") this._default = "99_EXIT";
    
        var opts = {
            screenID: "oolite-planetfall-dockside-map",
            title: "Planetary Transit System",
            overlay: {name:"planetFall2_train_ovr.png", height:546},
            allowInterrupt: true,
            exitScreen: "GUI_SCREEN_INTERFACES",
            initialChoicesKey: this._default,
            choices: curChoices,
            message: text
        };
        mission.runScreen(opts, this.$screenHandler, this);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$screenHandler = function (choice) {
        if (choice == null) return;
    
        if (choice.indexOf("_SITE") >= 0) {
            if (!missionVariables.PlanetFall2_DockedStation) {
                missionVariables.PlanetFall2_DockedStation = player.ship.dockedStation.dataKey;
            }
            delete player.ship.dockedStation._dockedViaED;
            var idx = parseInt(choice.substring(0, 2));
            var sub = this.$surfaceSites(player.ship.dockedStation);
    
            // change the player for the trip
            var fee = parseInt(this._pf._config.transit.fee * this._pf._config.transit.governmentFactor[system.government]);
            if (fee > player.credits) fee = player.credits;
            player.credits -= fee;
    
            this.$beginJourney(sub[idx]);
            return;
        }
        if (choice != "99_EXIT") {
            this.$showStationList();
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns traveltime in minutes
    this.$travelTime = function(dest) {
        var point1 = player.ship.dockedStation.linkedVE;
        var point2 = dest.linkedVE;
        // this is the direct distance between two points
        var dist = this.$distance(this._pf.$getPlanetFromCoords(player.ship.dockedStation.linkedPlanetPos), point1.position, point2.position);
        // because the journey is unlikely to be perfectly straight, lets add some variation.
        // something between 1.5 and 2.5
        var mult = system.scrambledPseudoRandomNumber(point1._seed + point2._seed) + 1;
        dist *= mult;
        return Math.floor(((dist / 1000) / this.$getTrainSpeed() * 60));
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // gets distance between two points on a sphere
    this.$distance = function(planet, point1, point2) {
        var p1 = Vector3D(point1.x - planet.position.x, point1.y - planet.position.y, point1.z - planet.position.z);
        var p2 = Vector3D(point2.x - planet.position.x, point2.y - planet.position.y, point2.z - planet.position.z);
        return planet.radius * Math.acos((p1.dot(p2)) / (planet.radius * planet.radius));
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$getTrainSpeed = function() {
        var tlFactor = this._pf.$getTLFactor("main"); // we'll just use the main planet's TL factor for this
        return this._pf._config.transit.trainSpeed * tlFactor;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$transferShip = function() {
        var curChoices = {};
        var text = "";
        var fee = parseInt(this._pf._config.shipTransfer.fee * this._pf._config.shipTransfer.governmentFactor[system.government]);
        var tm = this._pf._config.shipTransfer.time;
    
        text = "This service will arrange for your ship to be transferred to this star port.\n\nCost: " + formatCredits(fee, false, true) + "\nTime: " + tm.toFixed(1) + " hours.\n\nDo you want to proceed?";
        curChoices["01_YES"] = {
            text: "Yes",
            unselectable: (player.credits < fee ? true : false)
        };
        curChoices["02_NO"] = {
            text: "No",
            unselectable: false
        };
    
        var opts = {
            screenID: "oolite-planetfall-dockside-map",
            title: "Ship Transfer Services",
            overlay: {name:"planetFall2_rocket.png", height:546},
            allowInterrupt: true,
            exitScreen: "GUI_SCREEN_INTERFACES",
            choices: curChoices,
            message: text
        };
        mission.runScreen(opts, this.$transferHandler, this);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$transferHandler = function(choice) {
        if (!choice || choice == "02_NO") return;
    
        if (choice == "01_YES") {
            var fee = this._pf._config.shipTransfer.fee;
            player.credits -= fee;
            var tm = this._pf._config.shipTransfer.time * 3600;
            clock.addSeconds(tm);
            player.consoleMessage("Ship transferred to local star port. " + formatCredits(fee, false, true) + " deducted from your account.");
    
            // repoint eds at the new station
            var station = player.ship.dockedStation;
            station.setInterface(this.name + "_2", null);
            missionVariables.PlanetFall2_DockedStation = station.dataKey;
    
            var ed = worldScripts.ExternalDockSystem._externalDocks;
            for (var i = 0; i < ed.length; i++) {
                if (ed[i].station.dataKey == station.dataKey) {
                    // set the property on the new station
                    station._dockedViaED = ed[i];
                } else {
                    // remove it from any other station
                    if (ed[i].station.hasOwnProperty("_dockedViaED")) {
                        delete ed[i].station._dockedViaED;
                    }
                }
            }
    
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // appends space to currentText to the specified length in 'em'
    this.$padText = function _pfShipyards_padText(currentText, desiredLength, leftSwitch, centreSwitch) {
        var that = _pfShipyards_padText;
        var hairSpace = (that.hairSpace = that.hairSpace || this._hairSpace);
        var ellip = (that.ellip = that.ellip || this._ellip);
        var hairSpaceLength = (that.hairSpaceLength = that.hairSpaceLength || this._hairSpaceLength);
        var measure = (that.measure = that.measure || defaultFont.measureString);
    
        if (currentText == null) currentText = "";
        var currentLength = measure(currentText.replace(/%%/g, "%"));
        // calculate number needed to fill remaining length
        var padsNeeded = ~~((desiredLength - currentLength) / hairSpaceLength);
        if (padsNeeded < 1) {
            // text is too long for column, so start pulling characters off
            var tmp = currentText;
            do {
                tmp = tmp.substring(0, tmp.length - 2) + ellip;
                if (tmp === ellip) break;
            } while (measure(tmp.replace(/%%/g, "%")) > desiredLength);
            currentLength = measure(tmp.replace(/%%/g, "%"));
            padsNeeded = ~~((desiredLength - currentLength) / hairSpaceLength);
            currentText = tmp;
        }
        // quick way of generating a repeated string of that number
        if (!leftSwitch || leftSwitch === false) {
            if (!centreSwitch || centreSwitch === false) {
                return currentText + new Array(padsNeeded).join(hairSpace);
            } else {
                return currentText + new Array(parseInt(padsNeeded / 2)).join(hairSpace);
            }
        } else {
            if (!centreSwitch || centreSwitch === false) {
                return new Array(padsNeeded).join(hairSpace) + currentText;
            } else {
                return new Array(parseInt(padsNeeded / 2)).join(hairSpace) + currentText;
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillLaunchFromStation_train = function() {
        player.ship.hudHidden = true;
        this.$playSound("depart");
    
        this.planetFallLaunch = true;
        // create the image behind the player initially, to give it time to load
        var fx = system.addVisualEffect("planetFall2_trainFX1", Vector3D(25, 25, 25).fromCoordinateSystem("psu"));
        // then put it in front of the player.
        fx.position = player.ship.position.add(player.ship.vectorForward.multiply(this.fx_launch_dist));
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLaunchedFromStation_train = function() {
    	if (this.destination && this.destination.isValid) {
    		this.destination.dockOK = true;
    		this.destination.performedDockRequest = true;
    		this.destination.dockPlayer();
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillDockWithStation_train = function(station) {
    	// just turn off docking fees for this dock, rather than doing anything else funky
    	if (worldScripts["Docking Fees"]) {
    		worldScripts["Docking Fees"]._simulator = true;
    	}
        this.$playSound("arrive");
    
    	player.addMessageToArrivalReport("You exit the transit system at " + station.displayName);
    	this.background = "planetFall2_train_" + (Math.floor(Math.random() * 7) + 1) + ".png";
    	this.overlay = "";
    
    	var p = player.ship;
    	this.$clearStationState();
    
        this.fx_mult = 1.0;
    	// initially place the image behind the player to give it time to load in.
    	var fx = system.addVisualEffect("planetFall2_trainFX2", Vector3D(25, 25, 25).fromCoordinateSystem("psu"));
    	fx.orientation = p.orientation;
    	// then put it in front of the player
    	fx.position = p.position.add(p.vectorForward.multiply(this.fx_launch_dist));
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDockedWithStation_train = function(station) {
    	worldScripts.PlanetFall2_Transit.$resetEvents();
        this.destination = null;
        var p = player.ship;
        p.hudHidden = false;
        p.hud = this.savedHUD;
        this.savedHUD = "";
    
        // repoint eds at the new station
        var ed = worldScripts.ExternalDockSystem._externalDocks;
        for (var i = 0; i < ed.length; i++) {
            if (ed[i].station.dataKey == station.dataKey) {
                p.dockedStation._dockedViaED = ed[i];
            } else {
                // remove it from any other station
                if (ed[i].station.hasOwnProperty("_dockedViaED")) {
                    delete ed[i].station._dockedViaED;
                }
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$resetEvents = function() {
    	this._pf.shipWillLaunchFromStation = this._pf.hold_shipWillLaunchFromStation;
    	this._pf.shipLaunchedFromStation = this._pf.hold_shipLaunchedFromStation;
    	this._pf.shipWillDockWithStation = this._pf.hold_shipWillDockWithStation;
    	delete this._pf.shipDockedWithStation;
    
        var eds = worldScripts.ExternalDockSystem;
        eds.shipWillLaunchFromStation = eds.hold_shipWillLaunchFromStation;
        delete eds.hold_shipWillLaunchFromStation;
    
        if (worldScripts.VimanaX_HUD) {
            var vx = worldScripts.VimanaX_HUD;
            vx.shipDockedWithStation = vx.hold_shipDockedWithStation;
            delete vx.hold_shipDockedWithStation;
            vx.shipWillLaunchFromStation = vx.hold_shipWillLaunchFromStation;
            delete vx.hold_shipWillLaunchFromStation;
        }
    
        if (worldScripts.hudselector) {
            var hs = worldScripts.hudselector;
            hs.shipWillLaunchFromStation = hs.hold_shipWillLaunchFromStation;
            delete hs.hold_shipWillLaunchFromStation;
            hs.shipLaunchedFromStation = hs.hold_shipLaunchedFromStation;
            delete hs.hold_shipLaunchedFromStation;
            hs.shipWillDockWithStation = hs.hold_shipWillDockWithStation;
            delete hs.hold_shipWillDockWithStation;
        }
    
        if (worldScripts.CommsLogMFD) {
            var cl = worldScripts.CommsLogMFD;
            cl.shipLaunchedFromStation = cl.hold_shipLaunchedFromStation;
            cl.shipWillDockWithStation = cl.hold_shipWillDockWithStation;
            delete cl.hold_shipLaunchedFromStation;
            delete cl.hold_shipWillDockWithStation;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$beginJourney = function(destination) {
        this._pf.destination = destination;
        var time = (this.$travelTime(destination) + 15) * 60; // convert to seconds
        clock.addSeconds(time);
    
        // set up events for train travel
    	this._pf.hold_shipWillLaunchFromStation = this._pf.shipWillLaunchFromStation;
    	this._pf.hold_shipLaunchedFromStation = this._pf.shipLaunchedFromStation;
    	this._pf.hold_shipWillDockWithStation = this._pf.shipWillDockWithStation;
    	this._pf.shipWillLaunchFromStation = this.shipWillLaunchFromStation_train;
    	this._pf.shipLaunchedFromStation = this.shipLaunchedFromStation_train;
    	this._pf.shipWillDockWithStation = this.shipWillDockWithStation_train;
    	this._pf.shipDockedWithStation = this.shipDockedWithStation_train;
    
        var eds = worldScripts.ExternalDockSystem;
        eds.hold_shipWillLaunchFromStation = eds.shipWillLaunchFromStation;
        delete eds.shipWillLaunchFromStation;
    
        if (worldScripts.VimanaX_HUD) {
            var vx = worldScripts.VimanaX_HUD;
            vx.hold_shipDockedWithStation = vx.shipDockedWithStation;
            delete vx.shipDockedWithStation;
            vx.hold_shipWillLaunchFromStation = vx.shipWillLaunchFromStation;
            delete vx.shipWillLaunchFromStation;
        }
    
        if (worldScripts.hudselector) {
            var hs = worldScripts.hudselector;
            hs.hold_shipWillLaunchFromStation = hs.shipWillLaunchFromStation;
            delete hs.shipWillLaunchFromStation;
            hs.hold_shipLaunchedFromStation = hs.shipLaunchedFromStation;
            delete hs.shipLaunchedFromStation;
            hs.hold_shipWillDockWithStation = hs.shipWillDockWithStation;
            delete hs.shipWillDockWithStation;
        }
    
        // prevent commslog MFD from transmitting the "launched in"/"docked in" messages
        if (worldScripts.CommsLogMFD) {
            var cl = worldScripts.CommsLogMFD;
            cl.hold_shipLaunchedFromStation = cl.shipLaunchedFromStation;
            cl.hold_shipWillDockWithStation = cl.shipWillDockWithStation;
            delete cl.shipLaunchedFromStation;
            delete cl.shipWillDockWithStation;
        }
    
        this._pf.fx_mult = 2.0;
        this._pf.savedHUD = player.ship.hud;
        player.ship.hud = "planetFall2_hud.plist";
        // "launch" the player onto the train!
        player.ship.launch();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // removes some interfaces that wouldn't make sense if the player isn't local to their ship anymore
    this.$clearUpF4Interfaces = function() {
        if (missionVariables.PlanetFall2_DockedStation != player.ship.dockedStation.dataKey) {
            var stn = player.ship.dockedStation;
            stn.setInterface("LaserArrangement", null);
            stn.setInterface("LMSS_Core", null);
        }
    }
    Scripts/planetFall2_turbulence.js
    "use strict";
    this.name = "PlanetFall2_Turbulence";
    this.author = "phkb";
    this.copyright = "CC-BY-SA-NC 4.0";
    this.description = "Controls atmospheric turbulence";
    
    /*
        progressively applies force to player's ship, impacting on pitch/roll/yaw.
        impact increases as altitude decreases and/or speed increases
    */
    
    this._swap = 0;
    this._maxImpact = 0.0025;
    
    //-------------------------------------------------------------------------------------------------------------
    this.systemWillPopulate = function() {
        // this will add turbulence settings to all planets that have an atmosphere
    	system.setPopulator("pf_turbulence", {
    		callback: function (pos) {
                var pl = system.planets;
                var i = pl.length;
                while (i--) {
                    if (pl[i].isSun) continue;
                    if (pl[i].solarGasGiant || pl[i].isGasGiant || !pl[i].hasAtmosphere) {
                        pl[i]._turbulence = [0, 0, 0];
                        continue;
                    }
                    var c = Math.random();
                    var max = 0.02;
                    var half = max / 2;
                    if (c < 45) { // 2 types
                        // always pitch and roll
                        pl[i]._turbulence = [Math.random() * max - half, Math.random() * max - half, 0]; 
                    } else { // only 1 type
                        var s = Math.random()
                        if (s < 50) pl[i]._turbulence = [Math.random() * max - half, 0, 0]; 
                        else pl[i]._turbulence = [0, Math.random() * max - half, 0];
                    }
                }
    		}.bind(this),
    		location: "COORDINATES",
    		coordinates: Vector3D(0, 0, 0),
    		priority: 500
    	});    
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$nearestPlanet = function() {
        var p = player.ship;
        var pp = p.position;
        var c = null;
        var d = 100000000000000000000.0; //10^20m for sure
        var pl = system.planets;
        var i = pl.length;
        while (i--) { //find the smallest distance
            var s = pp.distanceTo(pl[i].position) - pl[i].radius;
            if (d > s) {
                d = s;
                c = pl[i];
            }
        }
        if (c) {
            return c;
        } else {
            return null;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLaunchedFromStation = function() {
        var pl = this.$nearestPlanet();
        if (pl && this.$altitude(player.ship, pl) < (pl.radius * 3)) this.$startFCB(pl);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillEnterWitchspace = function() {
        this.$stopFCB();
        // check to see if we're jumping inside the atmosphere
        // if so, there's a 50% chance of a misjump
        var pl = this.$nearestPlanet();
        if (pl && this.$altitude(player.ship, pl) < (worldScripts.PlanetFall2._config.atmosphereMax * 1000) & isValidFrameCallback(this._fcb)) {
            worldScripts.PlanetFall2.$serviceLevelDecrease();
            if (Math.random() > 0.5) player.ship.scriptedMisjump = true;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipEnteredPlanetaryVicinity = function(entity) {
        this.$startFCB(entity);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipExitedPlanetaryVicinity = function() {
        this.$stopFCB();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDied = function() {
        this.$stopFCB();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillDockWithStation = function() {
        this.$stopFCB();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$startFCB = function $startFCB(entity) {
        if (worldScripts.PlanetFall2._config.useTurbulence == false) return;
        if (entity.isSun || !entity.hasAtmosphere || entity.isGasGiant || entity.solarGasGiant) return;
        this._swap = 0;
        if (player.ship.hasEquipmentProviding("EQ_PLANETFALL")) {
            this._setMaxImpact = 0.00125;
        } else {
            this._setMaxImpact = this._maxImpact;
        }
        if (isValidFrameCallback(this._fcb)) removeFrameCallback(this._fcb);
        this._fcb = addFrameCallback(this.$turbulence_FCB.bind(this, entity));
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$stopFCB = function $stopFCB() {
        if (isValidFrameCallback(this._fcb)) removeFrameCallback(this._fcb);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$turbulence_FCB = function _turbulence_FCB(entity, delta) {
        function sign(val) {
            if (val > 0) return 1
            else if (val < 0) return -1;
            else return 0;
        }
        function min(x, y) {
            return (x < y ? x : y);
        }
    
        var that = _turbulence_FCB;
        var _rnd = (that._rnd = that._rnd || Math.random);
        var _min = (that._min = that._min || min);
        var _sign = (that._sign = that._sign || sign);
        var _alt = (that._alt = that._alt || this.$altitude);
        var _maxalt = (that._maxalt = that._maxalt || worldScripts.PlanetFall2._config.atmosphereMax * 1000);
        var _maximp = (that._maximp = that._maximp || this._setMaxImpact);
        var _p = (that._p = that._p || player.ship);
    
        if (!_p || !_p.isValid) return;
    
        // every 8 secs or so, possibly swap directions on one of the turbulence properties
        this._swap += delta;
        if (this._swap > 8) {
            this._swap = 0;
            if (_rnd() < 0.2) {
                // swap directions on one of the turbulence properties
                if (_rnd() > 0.5 && entity._turbulence[0] != 0) entity._turbulence[0] *= -1;
                else if (_rnd() > 0.5 && entity._turbulence[1] != 0) entity._turbulence[1] *= -1;
                //else if (_rnd() > 0.5 && entity._turbulence[2] != 0) entity._turbulence[2] *= -1;
            }
        }
    
        var alt = _alt(_p, entity);
        if (alt < _maxalt && _rnd() < ((_maxalt - alt) / _maxalt)) {
            // the impact of the turbulence is increased with lower altitude and higher speeds
            var impact = ((_maxalt - alt) + (_p.maxSpeed - _p.speed)) / (_maxalt + _p.maxSpeed);
            // pitch
            if (entity._turbulence[0] != 0) _p.orientation = _p.orientation.rotate(_p.orientation.vectorRight(), _min(_maximp * _sign(entity._turbulence[0]), entity._turbulence[0] * impact));
            // roll
            if (entity._turbulence[1] != 0) _p.orientation = _p.orientation.rotate(_p.orientation.vectorForward(), _min(_maximp * _sign(entity._turbulence[1]), entity._turbulence[1] * impact));
            // yaw
            //if (entity._turbulence[2] != 0) _p.orientation = _p.orientation.rotate(_p.orientation.vectorUp(), _min(_maximp * _sign(entity._turbulence[2]), entity._turbulence[2] * impact));
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$altitude = function(p, planet) {
        var alt = 999999
        if (planet) {
            alt = p.position.distanceTo(planet) - planet.radius - p.collisionRadius;
        }
        return alt;
    }
    
    Scripts/planetFall2_worldScript.js
    "use strict";
    this.name = "PlanetFall2";
    this.author = "Thargoid, phkb, with bits from Eric Walch, Frame and Svengali";
    this.copyright = "Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme.txt.";
    this.description = "Enables planetary landing";
    
    this.fx_mult = 1.0;
    this.fx_step = 2; // controls how fast the cloud frame moves
    this.fx_land_dist = 200; // controls how far in front of player to position landing visual effects
    this.fx_start = -120;
    this.fx_launch_dist = 250; // controls how far in front of player to position launching visual effects
    this.boostAmount = 3500; // how far past the dock to jump the player to when launching
    this.planetFallLaunch = false; // as in 1.77 the alert condition is still set on launch - need a mask
    this.lastPlanetType = "Prime"; // what type of planet/moon we landed on
    this.planetCount = 1; // default setting
    this.moonCount = 0; // default setting
    this.messageBlock = false; // flag to stop request/cancel messages at launch from planet
    this.planetFallOverride = false; // flag to allow other OXPs to override PlanetFall locations
    this.overrideRole = "default";
    this.disable = false; // turns off the spawning of planetary locations
    this.landingTimer = null;
    this.landingMonitor = null; // timer to monitor proximity to planetary locations and thus when to trigger docking requests
    this.permitMilitaryDock = false; // flag to indicate player is permitted to dock at military bases
    this.additionalPlanets = false;
    this.globalCount = 0;
    this.indexPlanets = 0;
    this.indexMoons = 0;
    this.subServiceLevel = 0.0;
    this.destination = null;
    this.debug = true;
    
    this._landingImages = {
    	"city": ["planetFall2_city_1.png", "planetFall2_city_2.png", "planetFall2_city_3.png", "planetFall2_city_4.png", "planetFall2_city_5.png",
    		"planetFall2_city_6.png", "planetFall2_city_7.png", "planetFall2_city_8.png", "planetFall2_city_9.png", "planetFall2_city_10.png",
    		"planetFall2_city_11.png", "planetFall2_city_12.png"],
    	"military": ["planetFall2_military_1.png", "planetFall2_military_2.png", "planetFall2_military_3.png", "planetFall2_military_4.png"],
    	"leisure": ["planetFall2_leisure_1.png", "planetFall2_leisure_2.png", "planetFall2_leisure_3.png", "planetFall2_leisure_4.png",
    		"planetFall2_leisure_5.png", "planetFall2_leisure_6.png", "planetFall2_leisure_7.png", "planetFall2_leisure_8.png"],
    	"factory": ["planetFall2_factory_1.png", "planetFall2_factory_2.png", "planetFall2_factory_3.png", "planetFall2_factory_4.png", "planetFall2_factory_5.png"],
    	"dump": ["planetFall2_dump_1.png", "planetFall2_dump_2.png", "planetFall2_dump_3.png", "planetFall2_dump_4.png"],
    	"colony": ["planetFall2_colony_1.png", "planetFall2_colony_2.png", "planetFall2_colony_3.png", "planetFall2_colony_4.png"],
    	"moon_dome": ["planetFall2_moon_1.png", "planetFall2_moon_2.png", "planetFall2_moon_3.png", "planetFall2_moon_4.png", "planetFall2_moon_5.png",
    		"planetFall2_moon_6.png", "planetFall2_moon_7.png", "planetFall2_moon_8.png"],
    	"moon_leisure": ["planetFall2_moonleisure_1.png", "planetFall2_moonleisure_2.png", "planetFall2_moonleisure_3.png"],
    	"moon_military": ["planetFall2_moonmilitary_1.png", "planetFall2_moonmilitary_2.png", "planetFall2_moonmilitary_3.png"],
    	"moon_research": ["planetFall2_research_1.png", "planetFall2_research_2.png", "planetFall2_research_3.png", "planetFall2_research_4.png"],
    	"moon_mine": ["planetFall2_moonmine_1.png", "planetFall2_moonmine_2.png", "planetFall2_moonmine_3.png", "planetFall2_moonmine_4.png", "planetFall2_moonmine_5.png",
    		"planetFall2_moonmine_6.png"],
    	"moon_factory": ["planetFall2_moonfactory_1.png", "planetFall2_moonfactory_2.png", "planetFall2_moonfactory_3.png", "planetFall2_moonfactory_4.png"],
    	"moon_wasteland": ["planetFall2_wasteland_1.png", "planetFall2_wasteland_2.png", "planetFall2_wasteland_3.png", "planetFall2_wasteland_4.png",
    		"planetFall2_wasteland_5.png"],
    };
    
    // short versions of the roles because (a) they're easier to type in, and (b) some of them have multiple copies (ie 01, 02, 03 etc)
    this._builtInLocations = {
    	main: {
    		"capitalCity": "planetFall2_mainSurface_capitalCity",
    		"militaryBase": "planetFall2_mainSurface_militaryBase",
    		"leisureComplex": "planetFall2_mainSurface_leisureComplex",
    		"factory": "planetFall2_mainSurface_factory",
    		"dump": "planetFall2_mainSurface_dump"
    	},
    	planet: {
    		"colony": "planetFall2_subSurface_colony",
    		"militaryBase": "planetFall2_subSurface_militaryBase",
    		"leisureComplex": "planetFall2_subSurface_leisureComplex",
    		"factory": "planetFall2_subSurface_factory",
    		"dump": "planetFall2_subSurface_dump"
    	},
    	moon: {
    		"colonyDome": "planetFall2_moonSurface_dome",
    		"leisureDome": "planetFall2_moonSurface_leisureDome",
    		"mine": "planetFall2_moonSurface_mine",
    		"prison": "planetFall2_moonSurface_prison",
    		"researchComplex": "planetFall2_moonSurface_researchComplex",
    		"factory": "planetFall2_moonSurface_factory",
    		"wasteLand": "planetFall2_moonSurface_wasteLand"
    	},
    };
    
    this._locationOverrides = {
    };
    
    // all the config you can eat (which will be saved with the players save game)
    this._config = {
    	equipShip: {
    		planetFall2_mainSurface_capitalCity: true,
    		planetFall2_mainSurface_militaryBase: true,
    		planetFall2_mainSurface_leisureComplex: false,
    		planetFall2_mainSurface_factory: true,
    		planetFall2_mainSurface_dump: false,
    		planetFall2_subSurface_colony: true,
    		planetFall2_subSurface_militaryBase: true,
    		planetFall2_subSurface_leisureComplex: false,
    		planetFall2_subSurface_factory: true,
    		planetFall2_subSurface_dump: false,
    		planetFall2_moonSurface_dome: true,
    		planetFall2_moonSurface_leisureDome: false,
    		planetFall2_moonSurface_mine: false,
    		planetFall2_moonSurface_prison: false,
    		planetFall2_moonSurface_researchComplex: false,
    		planetFall2_moonSurface_factory: true,
    		planetFall2_moonSurface_wasteLand: false
    	},
    	marketMethod: { // 0 = none, 1 = copy main planet, 2 = sfep, 3 = original
    		planetFall2_mainSurface_capitalCity: 0,
    		planetFall2_mainSurface_militaryBase: 0,
    		planetFall2_mainSurface_leisureComplex: 0,
    		planetFall2_mainSurface_factory: 0,
    		planetFall2_mainSurface_dump: 0,
    		planetFall2_subSurface_colony: 0,
    		planetFall2_subSurface_militaryBase: 0,
    		planetFall2_subSurface_leisureComplex: 0,
    		planetFall2_subSurface_factory: 0,
    		planetFall2_subSurface_dump: 0,
    		planetFall2_moonSurface_dome: 0,
    		planetFall2_moonSurface_leisureDome: 0,
    		planetFall2_moonSurface_mine: 0,
    		planetFall2_moonSurface_prison: 0,
    		planetFall2_moonSurface_researchComplex: 0,
    		planetFall2_moonSurface_factory: 0,
    		planetFall2_moonSurface_wasteLand: 0
    	},
    	maxLocations: { main: 5, planet: 3, moon: 2 },
    	chances: {
    		main: { city: 0.7, militaryBase: 0.6, leisureComplex: 0.5, factory: 0.5, dump: 0.4 },
    		planet: { city: 0.7, militaryBase: 0.25, leisureComplex: 0.2, factory: 0.3, dump: 0.3 },
    		moon: { dome: 0.3, leisureComplex: 0.1, mine: 0.3, prison: 0.1, researchComplex: 0.2, factory: 0.2, wasteLand: 0.1 },
    		tlFactors: { main: { min: 0.75, max: 1.2 }, planet: { min: 0.5, max: 1.1 }, moon: { min: 0.3, max: 0.8 } },
    	},
    	transit: {
    		allowed: true,
    		fee: 20, // cr
    		trainSpeed: 90, //kph
    		governmentFactor: { "0": 1.3, "1": 0.0, "2": 1.3, "3": 1.5, "4": 0.5, "5": 0.8, "6": 0.0, "7": 0.75 },
    	},
    	shipTransfer: {
    		fee: 1000,
    		time: 2.0,
    		governmentFactor: { "0": 1.8, "1": 1.7, "2": 1.3, "3": 1.6, "4": 0.5, "5": 0.8, "6": 0.75, "7": 0.5 },
    	},
    	moveShipyards: true,
    	moveRenovation: true,
    	useTurbulence: true,
    	useLandingImages: true,
    	useGANames: true,
    	atmosphereMax: 15, // km
    	beaconRange: 200, // km
    	serviceLevelDecrease: 1.0,
    	renovationMessage: false,
    };
    
    // configuration settings for use in Lib_Config
    // first, location limits
    this._pfConfig = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "General settings",
    	Alive: "_pfConfig",
    	Notify: "$changeFlags",
    	Bool: {
    		B0: { Name: "_config.moveShipyards", Def: true, Desc: "Move shipyards to planet" },
    		B1: { Name: "_config.moveRenovation", Def: true, Desc: "Move maintenance to planet" },
    		B2: { Name: "_config.useTurbulence", Def: true, Desc: "Atmospheric turbulence" },
    		B3: { Name: "_config.useLandingImages", Def: true, Desc: "Use landing images" },
    		B4: { Name: "_config.useGANames", Def: true, Desc: "Use Almanac names" },
    		B5: { Name: "_config.transit.allowed", Def: true, Desc: "Allow planetary transit" },
    		Info: "0: Move most shipyards to planet, 1: Move 'Maintenance Overhaul' to main planet, 2: Planets have turbulence, 3: Use images for arrival reports, 4: Use Galactic Almanac naming style, 5: Allow planetary transit"
    	},
    	SInt: {
    		S0: { Name: "_config.maxLocations.main", Def: 5, Min: 2, Max: 10, Desc: "Main planet max" },
    		S1: { Name: "_config.maxLocations.planet", Def: 3, Min: 2, Max: 7, Desc: "Extra planet max" },
    		S2: { Name: "_config.maxLocations.moon", Def: 2, Min: 0, Max: 5, Desc: "Moon max" },
    		S3: { Name: "_config.atmosphereMax", Def: 15, Min: 5, Max: 25, Desc: "Atmosphere max alt" },
    		S4: { Name: "_config.beaconRange", Def: 200, Min: 100, Max: 10000, Desc: "Beacon range" },
    		S5: { Name: "_config.serviceLevelDecrease", Def: 1.0, Min: 0.0, Max: 1.0, Desc: "serviceLevel dec", Float: true },
    		S6: { Name: "_config.shipTransfer.time", Def: 2.0, Min: 0.5, Max: 10.0, Desc: "Ship transfer time (hrs)", Float: true },
    		S7: { Name: "_config.transit.trainSpeed", Def: 90, Min: 50, Max: 300, Desc: "Avr train speed (kph)" },
    		Info: "0: Max main planet locations, 1: Max extra planet locations, " +
    			"2: Max moon locations, 3: Alt (km) for atmosphere, 4: Range (km) of beacons, " +
    			"5: SL decrease amt on launch, 6: Ship transfer time (hrs), 7: Avr train speed (kph)"
    	}
    };
    
    // then spawning chances for the main planet ...
    this._pfConfigMainSpawn = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "Spawn chances: Main planet",
    	Alive: "_pfConfigMainSpawn",
    	SInt: {
    		S0: { Name: "_config.chances.main.city", Def: 0.6, Min: 0.0, Max: 1, Desc: "Spawn city", Float: true },
    		S1: { Name: "_config.chances.main.militaryBase", Def: 0.6, Min: 0.0, Max: 1, Desc: "Spawn military base", Float: true },
    		S2: { Name: "_config.chances.main.leisureComplex", Def: 0.5, Min: 0.0, Max: 1, Desc: "Spawn leisure complex", Float: true },
    		S3: { Name: "_config.chances.main.factory", Def: 0.5, Min: 0.0, Max: 1, Desc: "Spawn factory", Float: true },
    		S4: { Name: "_config.chances.main.dump", Def: 0.4, Min: 0.0, Max: 1, Desc: "Spawn rubbish dump", Float: true },
    		Info: "Chances of spawning various entities. eg 0.4 = 40% chance. There will be at least 1 city. Chance is for additional cities."
    	}
    };
    // market methods for main planet locations
    this._pfConfigMainServices = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "F3/F8: Main planet",
    	Alive: "_pfConfigMainServices",
    	Notify: "$changeSettings",
    	Bool: {
    		B0: { Name: "_config.equipShip.planetFall2_mainSurface_capitalCity", Def: true, Desc: "Capital cities" },
    		B1: { Name: "_config.equipShip.planetFall2_mainSurface_militaryBase", Def: true, Desc: "Military bases" },
    		B2: { Name: "_config.equipShip.planetFall2_mainSurface_leisureComplex", Def: false, Desc: "Leisure complexes" },
    		B3: { Name: "_config.equipShip.planetFall2_mainSurface_factory", Def: true, Desc: "Factories" },
    		B4: { Name: "_config.equipShip.planetFall2_mainSurface_dump", Def: false, Desc: "Rubbish dumps" },
    		Info: "True means site has F3 Equip Ship screen."
    	},
    	SInt: {
    		S0: { Name: "_config.marketMethod.planetFall2_mainSurface_capitalCity", Def: 0, Min: 0, Max: 3, Desc: "Capital cities" },
    		S1: { Name: "_config.marketMethod.planetFall2_mainSurface_militaryBase", Def: 0, Min: 0, Max: 3, Desc: "Military bases" },
    		S2: { Name: "_config.marketMethod.planetFall2_mainSurface_leisureComplex", Def: 0, Min: 0, Max: 3, Desc: "Leisure complexes" },
    		S3: { Name: "_config.marketMethod.planetFall2_mainSurface_factory", Def: 0, Min: 0, Max: 3, Desc: "Factories" },
    		S4: { Name: "_config.marketMethod.planetFall2_mainSurface_dump", Def: 0, Min: 0, Max: 3, Desc: "Rubbish dumps" },
    		Info: "0 = No market, 1 = Copy main station, 2 = SFEP (adjust by distance from main station), 3 = Original"
    	}
    };
    
    // .. extra planets ...
    this._pfConfigPlanetSpawn = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "Spawn chances: Extra planets",
    	Alive: "_pfConfigPlanetSpawn",
    	SInt: {
    		S0: { Name: "_config.chances.planet.city", Def: 0.6, Min: 0.0, Max: 1, Desc: "Spawn colony city", Float: true },
    		S1: { Name: "_config.chances.planet.militaryBase", Def: 0.25, Min: 0.0, Max: 1, Desc: "Spawn military base", Float: true },
    		S2: { Name: "_config.chances.planet.leisureComplex", Def: 0.2, Min: 0.0, Max: 1, Desc: "Spawn leisure complex", Float: true },
    		S3: { Name: "_config.chances.planet.factory", Def: 0.3, Min: 0.0, Max: 1, Desc: "Spawn factory", Float: true },
    		S4: { Name: "_config.chances.planet.dump", Def: 0.3, Min: 0.0, Max: 1, Desc: "Spawn dump", Float: true },
    		Info: "Chances of spawning various entities. eg 0.4 = 40% chance. There will be at least 1 colony city. Chance is for additional cities."
    	}
    };
    // market methods for extra planet locations
    this._pfConfigPlanetServices = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "F3/F8: Extra planets",
    	Alive: "_pfConfigPlanetServices",
    	Notify: "$changeSettings",
    	Bool: {
    		B0: { Name: "_config.equipShip.planetFall2_subSurface_colony", Def: true, Desc: "Colony cities" },
    		B1: { Name: "_config.equipShip.planetFall2_subSurface_militaryBase", Def: true, Desc: "Military bases" },
    		B2: { Name: "_config.equipShip.planetFall2_subSurface_leisureComplex", Def: false, Desc: "Leisure complexes" },
    		B3: { Name: "_config.equipShip.planetFall2_subSurface_factory", Def: true, Desc: "Factories" },
    		B4: { Name: "_config.equipShip.planetFall2_subSurface_dump", Def: false, Desc: "Rubbish dumps" },
    		Info: "True means site has F3 Equip Ship screen."
    	},
    	SInt: {
    		S0: { Name: "_config.marketMethod.planetFall2_subSurface_colony", Def: 0, Min: 0, Max: 3, Desc: "Colony cities" },
    		S1: { Name: "_config.marketMethod.planetFall2_subSurface_militaryBase", Def: 0, Min: 0, Max: 3, Desc: "Military bases" },
    		S2: { Name: "_config.marketMethod.planetFall2_subSurface_leisureComplex", Def: 0, Min: 0, Max: 3, Desc: "Leisure complexes" },
    		S3: { Name: "_config.marketMethod.planetFall2_subSurface_factory", Def: 0, Min: 0, Max: 3, Desc: "Factories" },
    		S4: { Name: "_config.marketMethod.planetFall2_subSurface_dump", Def: 0, Min: 0, Max: 3, Desc: "Rubbish dumps" },
    		Info: "0 = No market, 1 = Copy main station, 2 = SFEP (adjust by distance from main station), 3 = Original"
    	}
    };
    
    // .. and moons.
    this._pfConfigMoonSpawn = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "Spawn chances: Moons",
    	Alive: "_pfConfigMoonSpawn",
    	SInt: {
    		S0: { Name: "_config.chances.moon.dome", Def: 0.3, Min: 0.0, Max: 1, Desc: "Spawn colony dome", Float: true },
    		S1: { Name: "_config.chances.moon.mine", Def: 0.3, Min: 0.0, Max: 1, Desc: "Spawn mine", Float: true },
    		S2: { Name: "_config.chances.moon.leisureComplex", Def: 0.1, Min: 0.0, Max: 1, Desc: "Spawn leisure dome", Float: true },
    		S3: { Name: "_config.chances.moon.factory", Def: 0.2, Min: 0.0, Max: 1, Desc: "Spawn robot factory", Float: true },
    		S4: { Name: "_config.chances.moon.wasteLand", Def: 0.1, Min: 0.0, Max: 1, Desc: "Spawn wasteland", Float: true },
    		S5: { Name: "_config.chances.moon.prison", Def: 0.1, Min: 0.0, Max: 1, Desc: "Spawn prison", Float: true },
    		S6: { Name: "_config.chances.moon.researchComplex", Def: 0.2, Min: 0.0, Max: 1, Desc: "Spawn research complex", Float: true },
    		Info: "Chances of spawning various entities. eg 0.4 = 40% chance."
    	}
    };
    // market methods for moon locations
    this._pfConfigMoonServices = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "F3/F8: Moons",
    	Alive: "_pfConfigMoonServices",
    	Notify: "$changeSettings",
    	Bool: {
    		B0: { Name: "_config.equipShip.planetFall2_moonSurface_dome", Def: true, Desc: "Colony domes" },
    		B1: { Name: "_config.equipShip.planetFall2_moonSurface_mine", Def: false, Desc: "Mines" },
    		B2: { Name: "_config.equipShip.planetFall2_moonSurface_prison", Def: false, Desc: "Prisons" },
    		B3: { Name: "_config.equipShip.planetFall2_moonSurface_leisureDome", Def: false, Desc: "Leisure domes" },
    		B4: { Name: "_config.equipShip.planetFall2_moonSurface_factory", Def: true, Desc: "Robot factories" },
    		B5: { Name: "_config.equipShip.planetFall2_moonSurface_researchComplex", Def: false, Desc: "Research complexes" },
    		B6: { Name: "_config.equipShip.planetFall2_moonSurface_wasteLand", Def: false, Desc: "Wastelands" },
    		Info: "True means site has F3 Equip Ship screen."
    	},
    	SInt: {
    		S0: { Name: "_config.marketMethod.planetFall2_moonSurface_dome", Def: 0, Min: 0, Max: 3, Desc: "Colony domes" },
    		S1: { Name: "_config.marketMethod.planetFall2_moonSurface_mine", Def: 0, Min: 0, Max: 3, Desc: "Mines" },
    		S2: { Name: "_config.marketMethod.planetFall2_moonSurface_prison", Def: 0, Min: 0, Max: 3, Desc: "Prisons" },
    		S3: { Name: "_config.marketMethod.planetFall2_moonSurface_leisureDome", Def: 0, Min: 0, Max: 3, Desc: "Leisure domes" },
    		S4: { Name: "_config.marketMethod.planetFall2_moonSurface_factory", Def: 0, Min: 0, Max: 3, Desc: "Robot factories" },
    		S5: { Name: "_config.marketMethod.planetFall2_moonSurface_researchComplex", Def: 0, Min: 0, Max: 3, Desc: "Research complexes" },
    		S6: { Name: "_config.marketMethod.planetFall2_moonSurface_wasteLand", Def: 0, Min: 0, Max: 3, Desc: "Wastelands" },
    		Info: "0 = No market, 1 = Copy main station, 2 = SFEP (adjust by distance from main station), 3 = Original"
    	}
    };
    
    // additional factors applied to spawn chances, based on TL
    this._pfConfigTLFactors = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "Spawn chances: TL factors",
    	Alive: "_pfConfigTLFactors",
    	SInt: {
    		S0: { Name: "_config.chances.tlFactors.main.min", Def: 0.75, Min: 0.0, Max: 2, Desc: "Main planet min", Float: true },
    		S1: { Name: "_config.chances.tlFactors.main.max", Def: 1.2, Min: 0.0, Max: 2, Desc: "Main planet max", Float: true },
    		S2: { Name: "_config.chances.tlFactors.planet.min", Def: 0.5, Min: 0.0, Max: 2, Desc: "Extra planets min", Float: true },
    		S3: { Name: "_config.chances.tlFactors.planet.max", Def: 1.1, Min: 0.0, Max: 2, Desc: "Extra planets max", Float: true },
    		S4: { Name: "_config.chances.tlFactors.moon.min", Def: 0.3, Min: 0.0, Max: 2, Desc: "Moons min", Float: true },
    		S5: { Name: "_config.chances.tlFactors.moon.max", Def: 0.8, Min: 0.0, Max: 2, Desc: "Moons max", Float: true },
    		Info: "Additional factor applied to spawn chances, based on TL of system. TL1 would use min, TL15 would use max."
    	}
    };
    
    // transit costs
    this._pfConfigTransit = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "Transit costs",
    	Alive: "_pfConfigTransit",
    	SInt: {
    		S0: { Name: "_config.transit.fee", Def: 20, Min: 0, Max: 2000, Desc: "Trip base cost (cr)" },
    		S1: { Name: "_config.transit.governmentFactor.0", Def: 1.3, Min: 0.0, Max: 100.0, Desc: "Anarchy factor", Float: true },
    		S2: { Name: "_config.transit.governmentFactor.1", Def: 0.0, Min: 0.0, Max: 100.0, Desc: "Feudal factor", Float: true },
    		S3: { Name: "_config.transit.governmentFactor.2", Def: 1.3, Min: 0.0, Max: 100.0, Desc: "Multi-government factor", Float: true },
    		S4: { Name: "_config.transit.governmentFactor.3", Def: 1.5, Min: 0.0, Max: 100.0, Desc: "Dictatorship factor", Float: true },
    		S5: { Name: "_config.transit.governmentFactor.4", Def: 0.5, Min: 0.0, Max: 100.0, Desc: "Communist factor", Float: true },
    		S6: { Name: "_config.transit.governmentFactor.5", Def: 0.8, Min: 0.0, Max: 100.0, Desc: "Confederacy factor", Float: true },
    		S7: { Name: "_config.transit.governmentFactor.6", Def: 0.0, Min: 0.0, Max: 100.0, Desc: "Democracy factor", Float: true },
    		S8: { Name: "_config.transit.governmentFactor.7", Def: 0.75, Min: 0.0, Max: 100.0, Desc: "Corporate State factor", Float: true },
    		Info: "Factor applied to base cost based on government type. 0.0 = Free, 1.0 = no change, 0.5 = 50% of base."
    	}
    };
    
    // ship transfer costs
    this._pfConfigTransfer = {
    	Name: this.name,
    	Alias: "PlanetFall",
    	Display: "Ship transfer costs",
    	Alive: "_pfConfigTransfer",
    	SInt: {
    		S0: { Name: "_config.shipTransfer.fee", Def: 1000, Min: 0, Max: 10000, Desc: "Transfer base cost (cr)" },
    		S1: { Name: "_config.shipTransfer.governmentFactor.0", Def: 1.8, Min: 0.0, Max: 10.0, Desc: "Anarchy factor", Float: true },
    		S2: { Name: "_config.shipTransfer.governmentFactor.1", Def: 1.7, Min: 0.0, Max: 10.0, Desc: "Feudal factor", Float: true },
    		S3: { Name: "_config.shipTransfer.governmentFactor.2", Def: 1.3, Min: 0.0, Max: 10.0, Desc: "Multi-government factor", Float: true },
    		S4: { Name: "_config.shipTransfer.governmentFactor.3", Def: 0.5, Min: 0.0, Max: 10.0, Desc: "Dictatorship factor", Float: true },
    		S5: { Name: "_config.shipTransfer.governmentFactor.4", Def: 0.5, Min: 0.0, Max: 10.0, Desc: "Communist factor", Float: true },
    		S6: { Name: "_config.shipTransfer.governmentFactor.5", Def: 0.8, Min: 0.0, Max: 10.0, Desc: "Confederacy factor", Float: true },
    		S7: { Name: "_config.shipTransfer.governmentFactor.6", Def: 0.75, Min: 0.0, Max: 10.0, Desc: "Democracy factor", Float: true },
    		S8: { Name: "_config.shipTransfer.governmentFactor.7", Def: 0.5, Min: 0.0, Max: 10.0, Desc: "Corporate State factor", Float: true },
    		Info: "Factor applied to base cost based on government type. 0.0 = Free, 1.0 = no change, 0.5 = 50% of base."
    	}
    };
    
    this._prePopulationFunctions = [];
    
    //-------------------------------------------------------------------------------------------------------------
    this.$changeFlags = function () {
    	if (worldScripts.RandomStationNames) {
    		worldScripts.PlanetFall2_Names.rsnInUse = this._config.useGANames;
    		if (worldScripts.Feudal_PlanetFall2) {
    			worldScripts.Feudal_PlanetFall2.rsnInUse = this._config.useGANames;
    		}
    	}
    	worldScripts.PlanetFall2_Transit.shipDockedWithStation(player.ship.dockedStation);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$changeSettings = function () {
    	var mi = worldScripts["market_inquirer"];
    	if (!mi) return;
    	var ar = mi.$inquirerStations;
    	var keys = Object.keys(this._config.marketMethod);
    	var i = keys.length;
    	while (i--) {
    		// check for a disabled market
    		if (this._config.marketMethod[keys[i]] == 0 && ar.indexOf(keys[i]) >= 0) {
    			ar.splice(ar.indexOf(keys[i]), 1);
    		}
    		// check for a newly established market
    		if (this._config.marketMethod[keys[i]] > 0 && ar.indexOf(keys[i]) == -1) {
    			ar.push(keys[i]);
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$addPrepopulationFunction = function (wsName, fnName) {
    	this._prePopulationFunctions.push({ ws: wsName, fn: fnName });
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$prepopulationControls = function () {
    	var i = this._prePopulationFunctions.length;
    	while (i--) {
    		var item = this._prePopulationFunctions[i];
    		worldScripts[item.ws][item.fn]();
    	}
    	// run the main scripts extra population function after all the others
    	this.$extraPopulation();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // public function to allow OXP's to determine whether player ship is currently local to them or not.
    this.playerShipIsLocal = function () {
    	if (!missionVariables.PlanetFall2_DockedStation) return true;
    	if (player.ship.dockedStation.hasRole("planetFall2_surface")) {
    		if (missionVariables.PlanetFall2_DockedStation == player.ship.dockedStation.dataKey) {
    			return true;
    		} else {
    			return false;
    		}
    	} else {
    		return true;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function () {
    	if (missionVariables.PlanetFall2_Config) {
    		this._config = JSON.parse(missionVariables.PlanetFall2_Config);
    		// make sure any newly added properties are added into the config.
    		if (!this._config.hasOwnProperty("beaconRange")) {
    			this._config.beaconRange = 200;
    		}
    		if (this._config.hasOwnProperty("planetRotation")) {
    			this._config.planetRotation = null;
    		}
    		if (!this._config.hasOwnProperty("serviceLevelDecrease")) {
    			this._config.serviceLevelDecrease = 1.0;
    		}
    		if (!this._config.hasOwnProperty("transit")) {
    			this._config.transit = {
    				allowed: true,
    				fee: 20,
    				trainSpeed: 90,
    				governmentFactor: { "0": 1.3, "1": 0.0, "2": 1.3, "3": 1.5, "4": 0.5, "5": 0.8, "6": 0.0, "7": 0.75 },
    			};
    		}
    		if (!this._config.hasOwnProperty("shipTransfer")) {
    			this._config.shipTransfer = {
    				fee: 1000,
    				time: 2.0,
    				governmentFactor: { "0": 1.8, "1": 1.7, "2": 1.3, "3": 1.6, "4": 0.5, "5": 0.8, "6": 0.75, "7": 0.5 },
    			};
    		}
    		// a bit of cleanup, if required.
    		if (this._config.chances.main.oohaul) {
    			delete this._config.chances.main.oohaul;
    			delete this._config.chances.main.blackmonks;
    			delete this._config.chances.main.hoopyCasino;
    			delete this._config.chances.planet.oohaul;
    			delete this._config.chances.planet.blackmonks;
    			delete this._config.chances.planet.hoopyCasino;
    			delete this._config.chances.moon.oohaul;
    			delete this._config.chances.moon.blackmonks;
    			delete this._config.chances.moon.hoopyCasino;
    		}
    	}
    	this.lastPlanet = system.mainPlanet; // details of the last planet to be landed on, so we know what to move the player away from on launch
    
    	if (missionVariables.hasOwnProperty("PlanetFall2_SubServiceLevel")) {
    		this.subServiceLevel = parseFloat(missionVariables.PlanetFall2_SubServiceLevel);
    	}
    
    	if (missionVariables.hasOwnProperty("PlanetFall2_Override")) {
    		this.planetFallOverride = (missionVariables.PlanetFall2_Override == "yes" ? true : false);
    		this.overrideRole = missionVariables.PlanetFall2_OverrideRole;
    	}
    
    	if (worldScripts["System Redux"]) this.additionalPlanets = true;
    
    	/* For convenience of mission writers, access for other OXPs is via "worldScripts.PlanetFall2.lastPlanet" and "worldScripts.PlanetFall2.lastPlanetType". 
    	Values for lastPlanetType are "Prime" for the main planet, "Sub" for every other planet, "Moon" for any moon and "Sun" / "GasGiant" for a sun or a Solar System OXP 
    	gas giant (for completeness - cannot land on either of the last two). */
    
    	// sdc integration
    	// because planetfall docks only exist for the player, we need to tell SDC to ignore all of them
    	if (worldScripts.StationDockControl) {
    		var sdc = worldScripts.StationDockControl;
    		sdc._trafficNone.push("planetFall2_surface");
    	}
    	this.shipWillEnterWitchspace();
    
    	// update docking fees (if installed)
    	if (worldScripts["Docking Fees"]) {
    		worldScripts["Docking Fees"].$addFee("planetFall2_surface", { multiplier: 1.2, messageKey: "dockfee_planet" }); // planets are slightly more to discourage spacers
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function () {
    	// register our settings, if Lib_Config is present
    	if (worldScripts.Lib_Config) {
    		var lib = worldScripts.Lib_Config;
    		lib._registerSet(this._pfConfig);
    		lib._registerSet(this._pfConfigMainServices);
    		lib._registerSet(this._pfConfigPlanetServices);
    		lib._registerSet(this._pfConfigMoonServices);
    		lib._registerSet(this._pfConfigMainSpawn);
    		lib._registerSet(this._pfConfigPlanetSpawn);
    		lib._registerSet(this._pfConfigMoonSpawn);
    		lib._registerSet(this._pfConfigTLFactors);
    		lib._registerSet(this._pfConfigTransit);
    		lib._registerSet(this._pfConfigTransfer);
    	}
    	// make sure the lastPlanet and lastPlanetType are populated after a reload
    	if (player.ship.dockedStation.hasRole("planetFall2_surface")) {
    		this.shipApproachingPlanetSurface(this.$getPlanetFromCoords(player.ship.dockedStation.linkedPlanetPos));
    	}
    	this.monitorPoints = system.shipsWithRole("planetFall2_surface")
    	this.$turnOnAllBeacons();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function () {
    	missionVariables.PlanetFall2_Config = JSON.stringify(this._config);
    	missionVariables.PlanetFall2_SubServiceLevel = this.subServiceLevel;
    	if (this.planetFallOverride) {
    		missionVariables.PlanetFall2_Override = "yes";
    		missionVariables.PlanetFall2_OverrideRole = this.overrideRole;
    	} else {
    		delete missionVariables.PlanetFall2_Override;
    		delete missionVariables.PlanetFall2_OverrideRole;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillEnterWitchspace = function () {
    	// reset the list of available keys for the next system
    	this.usedKeys = [];
    	this.overrideRole = "default";
    	if (this.landingMonitor && this.landingMonitor.isRunning) this.landingMonitor.stop();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipExitedWitchspace = function () {
    	this.disable = false; // reset the disabled flag
    	this.monitorPoints = system.shipsWithRole("planetFall2_surface");
    	this.landingMonitor = new Timer(this, this.$monitorDockPoints.bind(this), 1, 1);
    }
    
    
    //-------------------------------------------------------------------------------------------------------------
    this.systemWillPopulate = function () {
    	if (this.disable) return;
    	this.globalCount = 0;
    	this.doRepopulate = true
    	if (!additionalPlanets) this.$prepopulationControls();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // called either by the PlanetFall2_MonkeyPatch.$prepopulationControls
    this.$extraPopulation = function () {
    	this.$addExtraPlanetDocks(system.mainPlanet.position, system.mainPlanet.radius, system.mainPlanet.hasAtmosphere, true);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.systemWillRepopulate = function () {
    	// we only do this once per system
    	if (this.doRepopulate) {
    		this.doRepopulate = false;
    		this.indexPlanets = 0;
    		this.indexMoons = 0;
    		this.$systemScan();
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$removeUsedKeys = function (keylist) {
    	if (!keylist) return [];
    	var i = keylist.length;
    	var used = this.usedKeys;
    	while (i--) {
    		if (used.indexOf(keylist[i]) >= 0) keylist.splice(i, 1);
    	}
    	return keylist;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$removeOXPKeys = function (keylist, ovr) {
    	if (!keylist) return [];
    	if (!ovr || ovr.length == 0) return keylist;
    	var i = keylist.length;
    	while (i--) {
    		if (ovr.indexOf(keylist[i]) >= 0) keylist.splice(i, 1);
    	}
    	return keylist;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // if we have the planet object to work with
    this.$addExtraPlanetDocksForPlanet = function (planet) {
    	this.$addExtraPlanetDocks(planet.position, planet.radius, planet.hasAtmosphere, planet.isMainPlanet);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // if we only have the specs of the planet
    this.$addExtraPlanetDocks = function $addExtraPlanetDocks(coords, radius, hasAtmosphere, isMain) {
    	function compare(a, b) {
    		return (b > a ? -1 : 1);
    	}
    	if (this.disable) return;
    
    	var pfKeys = new Array();
    	var role = "";
    	var distOffset = 16;
    	var maxLocations = 0;
    	var ovr = "";
    	var tlFactor = 1;
    	var typ = "";
    	var names = [];
    	var isCustom = false;
    	var idx = 0;
    
    	if (isMain) {
    		typ = "main";
    		role = "planetFall2_mainSurface";
    		maxLocations = this._config.maxLocations.main;
    		ovr = "planetFall2_mainSurface_externalOXP";
    		tlFactor = this.$getTLFactor("main");
    	} else if (hasAtmosphere) {
    		typ = "planet";
    		role = "planetFall2_subSurface";
    		maxLocations = this._config.maxLocations.planet;
    		distOffset = 17;
    		ovr = "planetFall2_subSurface_externalOXP";
    		tlFactor = this.$getTLFactor("planet");
    		idx = this.indexPlanets;
    		this.indexPlanets += 1;
    	} else {
    		typ = "moon";
    		role = "planetFall2_moonSurface";
    		maxLocations = this._config.maxLocations.moon;
    		distOffset = 18;
    		ovr = "planetFall2_moonSurface_externalOXP";
    		tlFactor = this.$getTLFactor("moon");
    		idx = this.indexMoons;
    		this.indexMoons += 1;
    	}
    
    	if (this.planetFallOverride == true) {
    		if (this.overrideRole != "default") ovr = this.overrideRole;
    		// get the OXP keys for the override role
    		pfKeys = this.$removeUsedKeys(Ship.keysForRole(ovr));
    	} else {
    		// check to see if a custom setup has been defined for this system
    		var custom = this._locationOverrides[galaxyNumber + " " + system.ID];
    		if (custom && custom[typ]) {
    			// check that we have a definition for this planet/moon
    			if (idx <= custom[typ].length - 1) {
    				isCustom = true;
    				var list = custom[typ][idx].roles;
    				names = custom[typ][idx].names;
    				for (var i = 0; i < list.length; i++) {
    					role = list[i];
    					var comp = Object.keys(this._builtInLocations[typ]);
    					var rolelookup = "";
    					if (comp.indexOf(role) >= 0) {
    						rolelookup = this._builtInLocations[typ][role];
    					} else {
    						rolelookup = role;
    					}
    					var keys = this.$removeUsedKeys(Ship.keysForRole(rolelookup));
    					if (!keys || keys.length == 0) {
    						log(this.name, "no shipkeys found for role " + rolelookup);
    					} else {
    						// only add one key per custom entry
    						pfKeys.push(keys[0]);
    						// add this role into 
    						this.usedKeys.push(keys[0]);
    					}
    				}
    			}
    		}
    		// otherwise, it's a default system setup
    		if (!isCustom) {
    			pfKeys = this.$removeUsedKeys(Ship.keysForRole(role));
    		}
    	}
    
    	if (pfKeys.length == 0) { // no more keys to allocate!
    		log(this.name, "No more keys available to allocate!");
    		return;
    	}
    
    	// only sort these if we aren't using a custom set
    	// when using a custom set, we need the order to stay the same as what's in the data
    	if (!isCustom) pfKeys.sort(compare);
    
    	var pfn = worldScripts.PlanetFall2_Names;
    	var chances = this._config.chances;
    
    	// array for tracking what we've added to this planet, so we don't end up adding everything to the one place
    	var types = [];
    	var locationCount = 0;
    
    	for (var i = 0; i < pfKeys.length; i++) {
    		var name = ""; // holds the displayName we generate
    		var addDock = false; // flag to determine if a particular dock is to be added
    		// get a copy of the ship key, but with the last character removed (which is normally something like 1-10)
    		var seedOffset = parseInt(pfKeys[i].substring(pfKeys[i].length - 2, pfKeys[i].length)) - 1;
    		var generalKey = pfKeys[i].substring(0, pfKeys[i].length - 2);
    		// some OXP keys won't have a numeric last character, in which case the seedOffset would be NaN
    		// so switch the generalKey back to being the actual key
    		if (isNaN(seedOffset)) { generalKey = pfKeys[i]; seedOffset = 0; }
    
    		switch (pfKeys[i]) {
    			case "planetFall2_mainSurface_capitalCity01":
    				// always add one of these
    				addDock = true;
    				name = pfn.$PF_CapitalCity(pfKeys[i]);
    				break;
    			case "planetFall2_mainSurface_capitalCity02":
    			case "planetFall2_mainSurface_capitalCity03":
    			case "planetFall2_mainSurface_capitalCity04":
    			case "planetFall2_mainSurface_capitalCity05":
    			case "planetFall2_mainSurface_capitalCity06":
    			case "planetFall2_mainSurface_capitalCity07":
    			case "planetFall2_mainSurface_capitalCity08":
    			case "planetFall2_mainSurface_capitalCity09":
    			case "planetFall2_mainSurface_capitalCity10":
    				// additional cities are random chances (that reduces each loop)
    				if (isCustom || (locationCount < (maxLocations * 0.6) && system.scrambledPseudoRandomNumber(2023 + seedOffset) < ((chances.main.city * tlFactor) - (0.08 * i)))) {
    					addDock = true;
    					name = pfn.$PF_CapitalCity(pfKeys[i]);
    				}
    				break;
    			case "planetFall2_mainSurface_militaryBase01":
    			case "planetFall2_mainSurface_militaryBase02":
    			case "planetFall2_mainSurface_militaryBase03":
    			case "planetFall2_mainSurface_militaryBase04":
    			case "planetFall2_mainSurface_militaryBase05":
    			case "planetFall2_mainSurface_militaryBase06":
    			case "planetFall2_mainSurface_militaryBase07":
    			case "planetFall2_mainSurface_militaryBase08":
    			case "planetFall2_mainSurface_militaryBase09":
    			case "planetFall2_mainSurface_militaryBase10":
    					if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.government > 2 && system.government < 6 && system.techLevel > 7 && system.scrambledPseudoRandomNumber(333) < (chances.main.militaryBase * tlFactor))) {
    						addDock = true;
    						name = pfn.$PF_MilitaryBase(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_mainSurface_leisureComplex01":
    			case "planetFall2_mainSurface_leisureComplex02":
    			case "planetFall2_mainSurface_leisureComplex03":
    			case "planetFall2_mainSurface_leisureComplex04":
    			case "planetFall2_mainSurface_leisureComplex05":
    			case "planetFall2_mainSurface_leisureComplex06":
    			case "planetFall2_mainSurface_leisureComplex07":
    			case "planetFall2_mainSurface_leisureComplex08":
    			case "planetFall2_mainSurface_leisureComplex09":
    			case "planetFall2_mainSurface_leisureComplex10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.government > 2 && system.techLevel > 4 && system.scrambledPseudoRandomNumber(220) < (chances.main.leisureComplex * tlFactor))) {
    						addDock = true;
    						name = pfn.$PF_LeisureComplex(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_mainSurface_factory01":
    			case "planetFall2_mainSurface_factory02":
    			case "planetFall2_mainSurface_factory03":
    			case "planetFall2_mainSurface_factory04":
    			case "planetFall2_mainSurface_factory05":
    			case "planetFall2_mainSurface_factory06":
    			case "planetFall2_mainSurface_factory07":
    			case "planetFall2_mainSurface_factory08":
    			case "planetFall2_mainSurface_factory09":
    			case "planetFall2_mainSurface_factory10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.economy < 4 && system.scrambledPseudoRandomNumber(823) < (chances.main.factory * tlFactor))) {
    						addDock = true;
    						name = pfn.$PF_Factory(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_mainSurface_dump01":
    			case "planetFall2_mainSurface_dump02":
    			case "planetFall2_mainSurface_dump03":
    			case "planetFall2_mainSurface_dump04":
    			case "planetFall2_mainSurface_dump05":
    			case "planetFall2_mainSurface_dump06":
    			case "planetFall2_mainSurface_dump07":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.economy < 4 && system.scrambledPseudoRandomNumber(63) < (chances.main.dump * tlFactor))) {
    						addDock = true;
    						name = pfn.$PF_Dump(pfKeys[i]);
    					}
    				}
    				break;
    
    			case "planetFall2_subSurface_colony01":
    			case "planetFall2_subSurface_colony02":
    			case "planetFall2_subSurface_colony03":
    			case "planetFall2_subSurface_colony04":
    			case "planetFall2_subSurface_colony05":
    			case "planetFall2_subSurface_colony06":
    			case "planetFall2_subSurface_colony07":
    			case "planetFall2_subSurface_colony08":
    			case "planetFall2_subSurface_colony09":
    			case "planetFall2_subSurface_colony10":
    			case "planetFall2_subSurface_colony11":
    			case "planetFall2_subSurface_colony12":
    			case "planetFall2_subSurface_colony13":
    			case "planetFall2_subSurface_colony14":
    			case "planetFall2_subSurface_colony15":
    			case "planetFall2_subSurface_colony16":
    			case "planetFall2_subSurface_colony17":
    			case "planetFall2_subSurface_colony18":
    			case "planetFall2_subSurface_colony19":
    			case "planetFall2_subSurface_colony20":
    				// we will add at least 1 colony city, after which it's a random chance (which reduces each loop)
    				if (isCustom || (locationCount < (maxLocations * 0.6) && (types.indexOf(generalKey) == -1 || system.scrambledPseudoRandomNumber(4113 + seedOffset) < ((chances.planet.city * tlFactor) - (0.04 * i))))) {
    					addDock = true;
    					name = pfn.$PF_ColonyCity(pfKeys[i]);
    				}
    				break;
    			case "planetFall2_subSurface_militaryBase01":
    			case "planetFall2_subSurface_militaryBase02":
    			case "planetFall2_subSurface_militaryBase03":
    			case "planetFall2_subSurface_militaryBase04":
    			case "planetFall2_subSurface_militaryBase05":
    			case "planetFall2_subSurface_militaryBase06":
    			case "planetFall2_subSurface_militaryBase07":
    			case "planetFall2_subSurface_militaryBase08":
    			case "planetFall2_subSurface_militaryBase09":
    			case "planetFall2_subSurface_militaryBase10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.government > 2 && system.government < 6 && system.techLevel > 7 && system.scrambledPseudoRandomNumber(24 + seedOffset) < ((chances.planet.militaryBase * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_ColonyMilitaryBase(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_subSurface_leisureComplex01":
    			case "planetFall2_subSurface_leisureComplex02":
    			case "planetFall2_subSurface_leisureComplex03":
    			case "planetFall2_subSurface_leisureComplex04":
    			case "planetFall2_subSurface_leisureComplex05":
    			case "planetFall2_subSurface_leisureComplex06":
    			case "planetFall2_subSurface_leisureComplex07":
    			case "planetFall2_subSurface_leisureComplex08":
    			case "planetFall2_subSurface_leisureComplex09":
    			case "planetFall2_subSurface_leisureComplex10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.government > 2 && system.techLevel > 4 && system.scrambledPseudoRandomNumber(220 + seedOffset) < ((chances.planet.leisureComplex * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_LeisureComplex(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_subSurface_factory01":
    			case "planetFall2_subSurface_factory02":
    			case "planetFall2_subSurface_factory03":
    			case "planetFall2_subSurface_factory04":
    			case "planetFall2_subSurface_factory05":
    			case "planetFall2_subSurface_factory06":
    			case "planetFall2_subSurface_factory07":
    			case "planetFall2_subSurface_factory08":
    			case "planetFall2_subSurface_factory09":
    			case "planetFall2_subSurface_factory10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.economy < 4 && system.scrambledPseudoRandomNumber(1190 + seedOffset) < ((chances.planet.factory * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_Factory(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_subSurface_dump01":
    			case "planetFall2_subSurface_dump02":
    			case "planetFall2_subSurface_dump03":
    			case "planetFall2_subSurface_dump04":
    			case "planetFall2_subSurface_dump05":
    			case "planetFall2_subSurface_dump06":
    			case "planetFall2_subSurface_dump07":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.economy < 4 && system.scrambledPseudoRandomNumber(87 + seedOffset) < ((chances.planet.dump * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_Dump(pfKeys[i]);
    					}
    				}
    				break;
    
    			case "planetFall2_moonSurface_dome01":
    			case "planetFall2_moonSurface_dome02":
    			case "planetFall2_moonSurface_dome03":
    			case "planetFall2_moonSurface_dome04":
    			case "planetFall2_moonSurface_dome05":
    			case "planetFall2_moonSurface_dome06":
    			case "planetFall2_moonSurface_dome07":
    			case "planetFall2_moonSurface_dome08":
    			case "planetFall2_moonSurface_dome09":
    			case "planetFall2_moonSurface_dome10":
    			case "planetFall2_moonSurface_dome11":
    			case "planetFall2_moonSurface_dome12":
    			case "planetFall2_moonSurface_dome13":
    			case "planetFall2_moonSurface_dome14":
    			case "planetFall2_moonSurface_dome15":
    			case "planetFall2_moonSurface_dome16":
    			case "planetFall2_moonSurface_dome17":
    			case "planetFall2_moonSurface_dome18":
    			case "planetFall2_moonSurface_dome19":
    			case "planetFall2_moonSurface_dome20":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.scrambledPseudoRandomNumber(342 + seedOffset) < ((chances.moon.dome * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_MoonDome(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_moonSurface_leisureDome01":
    			case "planetFall2_moonSurface_leisureDome02":
    			case "planetFall2_moonSurface_leisureDome03":
    			case "planetFall2_moonSurface_leisureDome04":
    			case "planetFall2_moonSurface_leisureDome05":
    			case "planetFall2_moonSurface_leisureDome06":
    			case "planetFall2_moonSurface_leisureDome07":
    			case "planetFall2_moonSurface_leisureDome08":
    			case "planetFall2_moonSurface_leisureDome09":
    			case "planetFall2_moonSurface_leisureDome10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && !worldScripts["Random_Hits"] && system.government > 2 && system.techLevel > 4 && system.scrambledPseudoRandomNumber(477 + seedOffset) < ((chances.moon.leisureComplex * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_LeisureComplex(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_moonSurface_mine01":
    			case "planetFall2_moonSurface_mine02":
    			case "planetFall2_moonSurface_mine03":
    			case "planetFall2_moonSurface_mine04":
    			case "planetFall2_moonSurface_mine05":
    			case "planetFall2_moonSurface_mine06":
    			case "planetFall2_moonSurface_mine07":
    			case "planetFall2_moonSurface_mine08":
    			case "planetFall2_moonSurface_mine09":
    			case "planetFall2_moonSurface_mine10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.scrambledPseudoRandomNumber(20 + seedOffset) < ((chances.moon.mine * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_MoonMine(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_moonSurface_prison01":
    			case "planetFall2_moonSurface_prison02":
    			case "planetFall2_moonSurface_prison03":
    			case "planetFall2_moonSurface_prison04":
    			case "planetFall2_moonSurface_prison05":
    			case "planetFall2_moonSurface_prison06":
    			case "planetFall2_moonSurface_prison07":
    			case "planetFall2_moonSurface_prison08":
    			case "planetFall2_moonSurface_prison09":
    			case "planetFall2_moonSurface_prison10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.scrambledPseudoRandomNumber(95 + seedOffset) < ((chances.moon.prison * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_MoonPrison(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_moonSurface_researchComplex01":
    			case "planetFall2_moonSurface_researchComplex02":
    			case "planetFall2_moonSurface_researchComplex03":
    			case "planetFall2_moonSurface_researchComplex04":
    			case "planetFall2_moonSurface_researchComplex05":
    			case "planetFall2_moonSurface_researchComplex06":
    			case "planetFall2_moonSurface_researchComplex07":
    			case "planetFall2_moonSurface_researchComplex08":
    			case "planetFall2_moonSurface_researchComplex09":
    			case "planetFall2_moonSurface_researchComplex10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.techLevel > 11 && system.scrambledPseudoRandomNumber(1178 + seedOffset) < ((chances.moon.researchComplex * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_MoonResearch(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_moonSurface_factory01":
    			case "planetFall2_moonSurface_factory02":
    			case "planetFall2_moonSurface_factory03":
    			case "planetFall2_moonSurface_factory04":
    			case "planetFall2_moonSurface_factory05":
    			case "planetFall2_moonSurface_factory06":
    			case "planetFall2_moonSurface_factory07":
    			case "planetFall2_moonSurface_factory08":
    			case "planetFall2_moonSurface_factory09":
    			case "planetFall2_moonSurface_factory10":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.techLevel <= 11 && system.scrambledPseudoRandomNumber(4783 + seedOffset) < ((chances.moon.factory * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_MoonFactory(pfKeys[i]);
    					}
    				}
    				break;
    			case "planetFall2_moonSurface_wasteLand01":
    			case "planetFall2_moonSurface_wasteLand02":
    			case "planetFall2_moonSurface_wasteLand03":
    			case "planetFall2_moonSurface_wasteLand04":
    			case "planetFall2_moonSurface_wasteLand05":
    			case "planetFall2_moonSurface_wasteLand06":
    			case "planetFall2_moonSurface_wasteLand07":
    				if (types.indexOf(generalKey) == -1) {
    					if (isCustom || (locationCount < maxLocations && system.scrambledPseudoRandomNumber(7861 + seedOffset) < ((chances.moon.wasteLand * tlFactor) - (0.01 * seedOffset)))) {
    						addDock = true;
    						name = pfn.$PF_MoonWasteland(pfKeys[i]);
    					}
    				}
    				break;
    
    			default:
    				var sh = Ship.shipDataForKey(pfKeys[i]);
    				var allowed = true;
    				if (sh.condition_script) {
    					// create a dummy object to attach the script to so it can be executed
    					// we should have a sun and main planet by this stage so this should work.
    					var temppos = system.sun.position.cross(system.mainPlanet.position).direction().multiply(4E9).subtract(system.mainPlanet.position);
    					var tempalloy = system.addShips("alloy", 1, temppos, 0);
    					tempalloy[0].setScript(sh.condition_script);
    					allowed = tempalloy[0].script.allowSpawnShip(pfKeys[i]);
    					tempalloy[0].remove(true);
    				}
    				if (allowed) {
    					var chance = 1;
    					var seed = 8888;
    					var alwaysSpawn = false;
    					if (sh && sh.hasOwnProperty("script_info")) {
    						if (sh.script_info.hasOwnProperty("spawn_chance") && !isNaN(sh.script_info.spawn_chance)) {
    							chance = parseFloat(sh.script_info.spawn_chance) * tlFactor;
    						}
    						if (sh.script_info.hasOwnProperty("always_spawn")) {
    							alwaysSpawn = (sh.script_info.always_spawn == "yes" ? true : false);
    							if (alwaysSpawn) chance = 1;
    						}
    						if (sh.script_info.hasOwnProperty("seed") && !isNaN(sh.script_info.seed)) {
    							seed = parseInt(sh.script_info.seed);
    						}
    					}
    					if (isCustom || ((alwaysSpawn || locationCount < maxLocations) && system.scrambledPseudoRandomNumber(seed) < chance)) {
    						addDock = true;
    					}
    					// check if we've for a naming function to use.
    					if (sh && sh.hasOwnProperty("script_info")) {
    						if (sh.script_info.hasOwnProperty("naming_function") && sh.script_info.hasOwnProperty("naming_ws")) {
    							if (worldScripts[sh.script_info.naming_ws][sh.script_info.naming_function]) {
    								name = worldScripts[sh.script_info.naming_ws][sh.script_info.naming_function](pfKeys[i]);
    							}
    						}
    					}
    				}
    				break;
    		}
    		if (!addDock) continue; // nothing to add? continue the loop
    
    		// get the custom name to override whatever was generated
    		//log(this.name, "isCustom " + isCustom + ", names " + names.length + ", i = " + i.toString() + ", names[0] = " + names[0]);
    		if (isCustom && names && (names.length - 1) >= i) name = names[i];
    
    		var popRef = "pf_sub_" + pfKeys[i]; // unique key to use for the populator name
    		locationCount += 1;
    		this.globalCount += 1;
    		// put each station in a different position so they don't "bump" each other
    		var posPF = Vector3D(distOffset * this.globalCount, distOffset * this.globalCount, distOffset * this.globalCount).fromCoordinateSystem("psu");
    		if (!isCustom) {
    			types.push(generalKey);
    			// add key to the used array (for custom setups this is done much earlier)
    			this.usedKeys.push(pfKeys[i]);
    		}
    		this.$addPopulatorFunction(popRef, posPF, pfKeys[i], name, coords, radius);
    	}
    	if (isMain) {
    		if (this.debug) log(this.name, "final count for main planet: " + locationCount);
    	} else {
    		if (this.debug) log(this.name, "final count for " + (hasAtmosphere ? "planet" : "moon") + " with radius " + radius + ": " + locationCount);
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$addPopulatorFunction = function (reference, stnPosition, dataKey, name, planetPosition, planetRadius) {
    	system.setPopulator(reference, {
    		callback: function (pos, key, displayName, entPos, radius) {
    			function calcLetters(text) {
    				var ret = 0;
    				var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
    				for (var i = 0; i < text.length; i++) {
    					ret += letters.indexOf(text[i]);
    				}
    				return ret;
    			}
    			var militaryBaseRestriction = function (ship) {
    				if (!(ship instanceof PlayerShip)) { // Only for the player ship
    					return true;
    				}
    				if (worldScripts.PlanetFall2.permitMilitaryDock) {
    					return true;
    				}
    				this.commsMessage("WARNING - This is a restricted military zone, Commander. Docking at this station is prohibited without explicit permissions.", player.ship);
    				return false;
    			};
    
    			var ws = worldScripts.PlanetFall2;
    			var pfAdd = system.addShips("[" + key + "]", 1, pos, 0);
    			if (pfAdd && pfAdd.length > 0) {
    				var pf = pfAdd[0];
    				// add a docking restriction for military bases
    				if (pf.allegiance == "restricted") {
    					var ses = pf.subEntities, y = ses.length;
    					while (y--) {
    						var se = ses[y];
    						if (se.isDock) {
    							se.script.acceptDockingRequestFrom = militaryBaseRestriction.bind(pf);
    							break;
    						}
    					}
    				}
    				pf.linkedPlanetPos = entPos;
    				if (displayName != "") pf.displayName = displayName;
    				// use the characters in the key to generate a seed value, offset by the last two characters (which should be 01-20)
    				var idx = parseInt(key.substring(key.length - 1, key.length)) - 1;
    				if (isNaN(idx)) idx = 0;
    				var safe = false;
    				var loop = 0;
    				var dockPos;
    				var seed = 0;
    				while (safe == false) {
    					safe = true;
    					seed = calcLetters(key) + idx + loop;
    
    					var x1 = system.scrambledPseudoRandomNumber(system.ID + seed + 1) * 2 - 1;
    					var y1 = system.scrambledPseudoRandomNumber(system.ID + seed + 2) * 2 - 1;
    					var z1 = system.scrambledPseudoRandomNumber(system.ID + seed + 3) * 2 - 1;
    					var x2 = (x1 * (1 / Math.sqrt(x1 * x1 + y1 * y1 + z1 * z1))) * (radius + 750);
    					var y2 = (y1 * (1 / Math.sqrt(x1 * x1 + y1 * y1 + z1 * z1))) * (radius + 750);
    					var z2 = (z1 * (1 / Math.sqrt(x1 * x1 + y1 * y1 + z1 * z1))) * (radius + 750);
    					dockPos = entPos.add(Vector3D(x2, y2, z2));
    					if (ws.$checkDockPosition(dockPos) == false) {
    						//log("PlanetFall2_populatorCB", key + ": whoops! too close to another site");
    						safe = false;
    						loop += 1;
    					};
    					if (loop > 10) safe = true; // in case we can't find a spot
    				}
    				pf.dockPos = dockPos;
    				ws.$addExternalDock(pf, entPos, seed);
    			}
    		}.bind(this, stnPosition, dataKey, name, planetPosition, planetRadius),
    		location: "COORDINATES",
    		coordinates: stnPosition,
    		deterministic: true,
    		priority: 500
    	});
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks a position against all other surface points, making sure they are not too close together
    this.$checkDockPosition = function (pos) {
        function surface(entity) { return (entity.isStation && entity.hasRole("planetFall2_surface")) };
    	
    	var minDist = player.ship.scannerRange * 1.5;
    	var s = system.filteredEntities(system.stations, surface);
    	for (var i = 0; i < s.length; i++) {
    		if (s[i].position.distanceTo(pos) < minDist) return false;
    	}
    	return true;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$preDockSetup = function (station) {
    	if (!station.hasOwnProperty("_dockOK")) {
    		this.$checkingForDockingClearance();
    	}
    };
    
    //-------------------------------------------------------------------------------------------------------------
    this.$postDockSetup = function (station) {
    	delete station.dockOK;
    	delete station.performedDockRequest;
    	if (this.prefx) this.prefx.remove();
    	this.prefx = null;
    };
    
    //-------------------------------------------------------------------------------------------------------------
    this.$addExternalDock = function (pf, entPos, seed) {
    	var eds = worldScripts.ExternalDockSystem;
    	var ve = eds.$addExternalDock({
    		station: pf,
    		realPosition: pf.dockPos,
    		allowLaunch: true,
    		launchSubEntityIndex: 0,
    		launchDistanceBoost: this.boostAmount,
    		dockRange: 2000,
    		preDockCallback: this.$preDockSetup.bind(this),
    		postDockCallback: this.$postDockSetup.bind(this)
    	});
    	this.$turnStation(pf, ve, entPos);
    
    	var dve = system.addShips("[planetFall2_stnVE]", 1, ve.position, 0)[0];
    	dve._seed = seed;
    	dve.orientation = ve.orientation;
    	if (pf.scriptInfo && pf.scriptInfo.hasOwnProperty("beacon_code")) {
    		dve.hold_beaconCode = pf.scriptInfo.beacon_code;
    	} else {
    		dve.hold_beaconCode = "P";
    	}
    	dve.hold_beaconLabel = (pf.dataKey.indexOf("moon") >= 0 ? "Moon: " : "Planet: ") + pf.displayName;
    	dve.displayName = pf.displayName;
    	pf.linkedVE = dve;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$turnStation = function (tempStation, altEntity, planetPos) {
    	if (!tempStation || !altEntity) {
    		return;
    	} // just in case the station doesn't survive spawning.
    	let stationVector = altEntity.position.subtract(planetPos).direction(); // unit vector pointing away from the planet
    	let angle = tempStation.heading.angleTo(stationVector); // angle between current heading and target heading
    	let cross = tempStation.heading.cross(stationVector).direction(); // set the plane where we should rotate in
    	tempStation.orientation = tempStation.orientation.rotate(cross, -angle); // re-orient the station away from the planet
    	altEntity.orientation = tempStation.orientation; // re-orient our alt entity the same way
    	tempStation.breakPattern = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipApproachingPlanetSurface = function (planet) {
    	if (!planet || planet.hasOwnProperty("PFNoLandQuiet")) {
    		return;
    	}
    
    	if (planet.hasOwnProperty("PFNoLand")) {
    		this.$sendPlanetaryComms("Urgent warning - landing is not possible here!");
    		return;
    	}
    
    	this.lastPlanet = planet;
    	if (!planet.isSun && !planet.hasOwnProperty("solarGasGiant") && !planet.hasOwnProperty("isGasGiant")) {
    		if (planet === system.mainPlanet) {
    			this.lastPlanetType = "Prime";
    		} else {
    			if (planet.hasAtmosphere) {
    				this.lastPlanetType = "Sub";
    			} else {
    				this.lastPlanetType = "Moon";
    			}
    		}
    	} else {
    		if (planet.hasOwnProperty("solarGasGiant") || planet.hasOwnProperty("isGasGiant")) {
    			this.lastPlanetType = "GasGiant";
    		} else {
    			this.lastPlanetType = "Sun";
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipEnteredPlanetaryVicinity = function (planet) {
    	if (!planet) return;
    
    	this.lastPlanet = planet;
    
    	if (planet.isSun) {
    		player.consoleMessage("ALERT - Approaching the Sun. Temperature monitoring is critical!", 10);
    	}
    	if (planet.hasOwnProperty("solarGasGiant") || planet.hasOwnProperty("isGasGiant")) {
    		player.consoleMessage("ALERT - You are approaching a Gas Giant. Landing here is not possible!", 10);
    	}
    	if (planet.hasOwnProperty("PFNoLand")) {
    		this.$sendPlanetaryComms("ALERT - Landing is not possible here, please pull up!");
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLeavingPlanetSurface = function (planet) {
    	this.lastPlanet = planet;
    	this.messageBlock = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipExitedPlanetaryVicinity = function () {
    	this.messageBlock = false;
    	this.shipDied();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillLaunchFromStation = function (station) {
    	if (station && station.hasRole("planetFall2_surface")) {
    		if (station.dataKey != missionVariables.PlanetFall2_DockedStation) {
    			var tm = this._config.shipTransfer.time * 3600;
    			clock.addSeconds(tm);
    			var fee = parseInt(this._config.shipTransfer.fee * this._config.shipTransfer.governmentFactor[system.government]);
    			if (player.credits < fee) {
    				fee = player.credits;
    			}
    			player.credits -= fee;
    			player.consoleMessage("Ship transferred to local star port. " + formatCredits(fee, false, true) + " deducted from your account.");
    		}
    
    		this.holdStation = station;
    		// we're adding a dummy station at the ve point for the real station.
    		// this is because the "shipLaunchedFromStation" function searches for the nearest station and assumes you launched from that.
    		// but because our real station is nowhere near the player by that point, it will probably lock onto the main station
    		this.dummy = system.addShips("[" + station.dataKey + "]", 1, station.dockPos, 0)[0];
    		this.dummy.name = station.name;
    		this.dummy.displayName = station.displayName;
    		// make sure the eds script has run first
    		var eds = worldScripts.ExternalDockSystem;
    		if (!isValidFrameCallback(eds._fcb)) {
    			eds.shipWillLaunchFromStation(station);
    		}
    		this.planetFallLaunch = true;
    		this.launchTexture = Math.floor(system.scrambledPseudoRandomNumber(772) * 6) + 1;
    		// create the image behind the player initially, to give it time to load
    		var fx = system.addVisualEffect("planetFall2_launchFX", player.ship.position.add(player.ship.vectorForward.multiply(this.fx_launch_dist * -1)));
    		fx.setMaterials({
    			"planetFall2_launchFX0.png": {
    				fragment_shader: "planetFall2_breakPattern.fragment",
    				vertex_shader: "planetFall2_breakPattern.vertex",
    				textures: ["planetFall2_launchFX" + this.launchTexture + "_0.png"],
    			}
    		});
    		// then put it in front of the player.
    		fx.position = player.ship.position.add(player.ship.vectorForward.multiply(this.fx_launch_dist));
    		station.state = 3;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLaunchedFromStation = function (station) {
    	this._beaconRange = this._config.beaconRange * 1000;
    
    	if (EquipmentInfo.infoForKey("EQ_FRAME_SAVE") != null) { // if launch is for Save Anywhere, don't want to move the player or nuke the station
    		return;
    	}
    
    	if (station && station.hasRole("planetFall2_surface")) {
    		if (this.landingTimer) {
    			delete this.landingTimer;
    		}
    		this.$sendPlanetaryComms("Orbital boost complete.");
    		this.$sendPlanetaryComms("Farewell Commander " + player.name + ".");
    		this.messageBlock = false;
    		this.$serviceLevelDecrease();
    		// in case the player turns around immediately to redock
    		// because the "station" object passed to this function won't be the true station, 
    		// we're pointing to the holding variable to get the real station object
    		this.holdStation.dockOK = true;
    		this.holdStation.performedDockRequest = true;
    		this.holdStation = null;
    		this.dummy.remove(true);
    	}
    	this.monitorPoints = system.shipsWithRole("planetFall2_surface")
    	this.landingMonitor = new Timer(this, this.$monitorDockPoints.bind(this), 1, 1);
    
    	delete missionVariables.PlanetFall2_DockedStation;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillDockWithStation = function (station) {
    	if (this.landingMonitor && this.landingMonitor.isRunning) this.landingMonitor.stop();
    
    	this.$clearStationState();
    
    	if (!station.hasRole("planetFall2_surface")) return;
    
    	var p = player.ship;
    	var break_chance = this.$damageChance();
    
    	if (Math.abs(station.linkedVE.heading.dot(p.heading)) > 0.7) {
    		if (Math.random() < 0.9) {
    			var result = p.takeInternalDamage();
    			if (result) {
    				this.$playSound("explosion");
    				player.addMessageToArrivalReport("Your ship experienced some damage during re-entry. Cause: Approach to ground control interface point was too steep.");
    			}
    		}
    	}
    
    	// load landing fx for planets with atmosphere
    	if (station.hasRole("planetFall2_surface") || station.hasRole("planetFall2_mainSurface_externalOXP") || station.hasRole("planetFall2_subSurface_externalOXP") || station.hasRole("planetFall2_moonSurface_externalOXP")) {
    		var texture = Math.floor(system.scrambledPseudoRandomNumber(772) * 4) + 1;
    		var color = this.$returnMainColor(this.$getPlanetFromCoords(station.linkedPlanetPos));
    		this.fx_landing_pad = Math.floor(system.scrambledPseudoRandomNumber(446) * 6) + 1;
    		// initially place the image behind the player to give it time to load in.
    		var fx = system.addVisualEffect("planetFall2_landingFX", Vector3D(25, 25, 25).fromCoordinateSystem("psu"));
    		fx.orientation = p.orientation;
    		fx.setMaterials({
    			"planetFall2_clouds.png": {
    				fragment_shader: "planetFall2_breakPattern.fragment",
    				vertex_shader: "planetFall2_breakPattern.vertex",
    				textures: ["planetFall2_clouds" + texture + "_" + color + ".png"],
    			}
    		});
    		// then put it in front of the player
    		fx.position = p.position.add(p.vectorForward.multiply(this.fx_land_dist)).add(p.vectorUp.multiply(this.fx_start));
    	}
    	// load landing fx for planets with no atmosphere
    	if (station.hasRole("planetFall2_moonSurface") || station.hasRole("planetFall2_moonSurface_externalOXP")) {
    		this.fx_landing_pad = Math.floor(system.scrambledPseudoRandomNumber(446) * 6) + 1;
    		// initially place the image behind the player to give it time to load in.
    		var fx = system.addVisualEffect("planetFall2_landingFX", Vector3D(25, 25, 25).fromCoordinateSystem("psu"));
    		fx.orientation = p.orientation;
    		fx.setMaterials({
    			"planetFall2_clouds.png": {
    				fragment_shader: "planetFall2_breakPattern.fragment",
    				vertex_shader: "planetFall2_breakPattern.vertex",
    				textures: ["planetFall2_stars.png"],
    			}
    		});
    		// then put it in front of the player
    		fx.position = p.position.add(p.vectorForward.multiply(this.fx_land_dist)).add(p.vectorUp.multiply(this.fx_start));
    	}
    
    	// make sure the eds link is added to our station (in case some other function forced the player to dock)
    	if (!station.hasOwnProperty("_dockedViaED")) {
    		var eds = worldScripts.ExternalDockSystem;
    		var ed = eds._externalDocks;
    		for (var i = 0; i < ed.length; i++) {
    			if (ed[i].station == station) {
    				station._dockedViaED = ed[i];
    				break;
    			}
    		}
    	}
    
    	if (!station.dockOK) {
    		var fine = parseInt(player.credits * 0.05);
    		if (fine > 5000) fine = 5000;
    		player.credits -= fine;
    		var txt = expandDescription("[station-docking-clearance-fined-@-cr]").replace("%@", formatCredits(fine, false, true));
    		player.addMessageToArrivalReport(txt);
    	}
    
    	if (Math.random() < break_chance) {
    		if (Math.random() < break_chance) this.$serviceLevelDecrease();
    	}
    	player.addMessageToArrivalReport("You have landed successfully at " + station.displayName + ".");
    
    	// so things like galactic almanac have visibility of everything
    	this.$turnOnAllBeacons();
    
    	missionVariables.PlanetFall2_DockedStation = station.dataKey;
    
    	// pick the background image to go on the arrival report
    	var seedOffset = parseInt(station.dataKey.substring(station.dataKey.length - 2, station.dataKey.length)) - 1;
    	var generalKey = station.dataKey.substring(0, station.dataKey.length - 2);
    	// some OXP keys won't have a numeric last character, in which case the seedOffset would be NaN
    	// so switch the generalKey back to being the actual key
    	if (isNaN(seedOffset)) { generalKey = station.dataKey; seedOffset = 0; }
    	if (generalKey.indexOf("subSurface")) seedOffset += 10;
    
    	this.background = "";
    	this.overlay = "";
    	var imagekey = station.scriptInfo.landing_image_set;
    	if (!imagekey) return; // no image set specified - assume it's an OXP and allow it to do what it wants
    
    	var keys = Object.keys(this._landingImages);
    	var arr = this._landingImages[imagekey];
    	if (!arr || arr.length == 0) return; // no images in array or invalid key
    	var idx = Math.floor(system.scrambledPseudoRandomNumber(100 + (keys.indexOf(imagekey) * 30) + seedOffset) * arr.length);
    	this.background = arr[idx];
    
    	if (this.background != "") {
    		var color = this.$returnMainColor(this.$getPlanetFromCoords(station.linkedPlanetPos));
    		if (color != "") this.overlay = "planetFall2_filter_" + color + ".png";
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.alertConditionChanged = function () {
    	if (this.planetFallLaunch) {
    		this.planetFallLaunch = false;
    		return;
    	}
    
    	if (player.alertAltitude && (this.lastPlanet.hasOwnProperty("solarGasGiant") || this.lastPlanet.hasOwnProperty("isGasGiant"))) {
    		player.consoleMessage("ALERT - You are approaching a Gas Giant. Landing here is not possible!", 10);
    	}
    
    	if (player.alertAltitude && this.lastPlanet.hasOwnProperty("PFNoLand")) {
    		player.consoleMessage("ALERT - Landing here is not possible!", 10);
    		return;
    	}
    
    	// player left without docking
    	if (!player.alertAltitude && this.landingTimer && this.landingTimer.isRunning && !player.ship.docked && EquipmentInfo.infoForKey("EQ_FRAME_SAVE") == null) {
    		this.landingTimer.stop();
    		delete this.landingTimer;
    		this.$serviceLevelDecrease();
    		if (!this.messageBlock) {
    			this.$sendPlanetaryComms("Landing clearance request cancelled.");
    			this.$sendPlanetaryComms("Goodbye Commander " + player.name + ".");
    			this.messageBlock = false;
    			this.$clearStationState();
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDied = function () {
    	if (this.landingTimer && this.landingTimer.isRunning) {
    		this.landingTimer.stop();
    		delete this.landingTimer;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$landingClearance = function () {
    	this.landingTimer.stop();
    	delete this.landingTimer;
    	if (player.ship.docked) return;
    	this.$checkingForDockingClearance();
    	if (!this.checkingStation.dockOK) {
    		if (this.checkingStation.hasOwnProperty("storeCommsMessage") && this.checkingStation.storeCommsMessage != "") {
    			this.$sendPlanetaryComms(this.checkingStation.storeCommsMessage);
    		} else {
    			this.$sendPlanetaryComms("Landing clearance denied.");
    		}
    		this.$sendPlanetaryComms("Please clear the area, commander.");
    		return;
    	}
    	this.$sendPlanetaryComms("Landing clearance granted.");
    	this.$sendPlanetaryComms("Please approach the ground control interface point slowly, at less than 100 meters per second.");
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$checkingForDockingClearance = function () {
    	var stn = this.checkingStation;
    	stn.storeCommsMessage = "";
    	// check for the following condition:
    	// the dock has an "acceptDockingRequestFrom" function, and we haven't run it yet.
    	if (!stn.performedDockRequest) {
    		var align = Math.abs(stn.linkedVE.heading.dot(player.ship.heading));
    		if (align > 0.7) {
    			stn.dockOK = false;
    			stn.storeCommsMessage = "Your approach angle is too steep. Landing clearance cannot be given.";
    			return;
    		}
    		// find dock entity of station
    		var dock = null;
    		for (var j = 0; j < stn.subEntities.length; j++) {
    			if (stn.subEntities[j].isDock) {
    				dock = stn.subEntities[j];
    				break;
    			}
    		}
    		if (dock && dock.script && dock.script.acceptDockingRequestFrom && !stn.performedDockRequest) {
    			// run the function and store the result
    			// intercept the commsMessage function for the station, so anything sent to the player when requesting docking can be stored
    			stn.adjustCommsMessage = stn.commsMessage;
    			stn.commsMessage = function (msg, tgt) {
    				stn.adjustCommsMessage(msg, tgt);
    				stn.storeCommsMessage = msg;
    			}
    			stn.dockOK = dock.script.acceptDockingRequestFrom(player.ship);
    			stn.performedDockRequest = true;
    			stn.commsMessage = stn.adjustCommsMessage;
    			delete stn.adjustCommsMessage;
    		} else {
    			stn.dockOK = true;
    			stn.performedDockRequest = true;
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$turnOnAllBeacons = function () {
    	var stns = this.monitorPoints;
    	var i = stns.length;
    	var stn = null;
    	while (i--) {
    		stn = stns[i];
    		stn.linkedVE.beaconCode = stn.linkedVE.hold_beaconCode;
    		stn.linkedVE.beaconLabel = stn.linkedVE.hold_beaconLabel;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$monitorDockPoints = function $monitorDockPoints() {
    	var p = player.ship;
    	if (!p || !p.isValid) return;
    
    	var stns = this.monitorPoints;
    	var i = stns.length;
    	var stn = null;
    	var state = 0;
    	while (i--) {
    		stn = stns[i];
    		if (stn.state > 2) continue;
    		var check = stn.dockPos.distanceTo(p);
    		if (check < this._beaconRange) {
    			stn.linkedVE.beaconCode = stn.linkedVE.hold_beaconCode;
    			stn.linkedVE.beaconLabel = stn.linkedVE.hold_beaconLabel;
    		} else {
    			stn.linkedVE.beaconCode = "";
    			stn.linkedVE.beaconLabel = "";
    		}
    		// only start doing checks if we're inside 20km
    		if (check < 20000) {
    			var align = stn.linkedVE.heading.dot(p.heading);
    			if (align < 0) align = -align;
    			// we're multiplying the deviation by the distance to eliminate the impact of the increasing angle as you get closer.
    			var deviation = p.vectorForward.angleTo(stn.linkedVE.position.subtract(p.position)) * check;
    			if (check < 3000 && !stn.dockOK && !stn.dockWarning && deviation < 245) {
    				stn.dockWarning = true;
    				this.$sendPlanetaryComms("WARNING! Landing clearance has not been granted. Pull up, Commander!");
    				break;
    			}
    			if (check < 3000 && stn.dockOK && align > 0.9 && deviation < 245 && !stn.alignWarning3) {
    				stn.alignWarning3 = true;
    				this.$sendPlanetaryComms("WARNING! Your approach angle is too steep! Landing clearance has been cancelled. Pull up, Commander!");
    				stn.state = 1; // reset state back so that a correct alignment will trigger a docking request
    				stn.dockOK = false;
    				break;
    			}
    			if (check < 7000 && stn.state == 2 && align > 0.7 && deviation < 245 && !stn.alignWarning2) {
    				stn.alignWarning2 = true;
    				this.$sendPlanetaryComms("WARNING! Your approach angle is too steep! Make your approach from a shallow angle or you risk damaging your ship!");
    				break;
    			}
    			if (check < 12000 && stn.state < 2 && align > 0.7 && deviation < 245 && !stn.alignWarning1) {
    				stn.alignWarning1 = true;
    				this.$sendPlanetaryComms("WARNING! Your approach angle is too steep. You must make your approach from a shallow angle before landing clearance will be given.");
    				break;
    			}
    			if (check < 12000 && stn.state < 2 && align <= 0.7 && deviation < 245) {
    				stn.state = 2;
    				state = 2;
    				stn.alignWarning1 = false;
    				stn.alignWarning2 = false;
    				stn.alignWarning3 = false;
    				stn.dockWarning = false;
    				break;
    			}
    			if (check < 18000 && (!stn.state || stn.state == 0)) {
    				stn.state = 1;
    				state = 1;
    				break;
    			}
    			if (check > 18000) {
    				stn.state = 0;
    				stn.alignWarning1 = false;
    				stn.alignWarning2 = false;
    				stn.alignWarning3 = false;
    				stn.dockWarning = false;
    			}
    		}
    	}
    	if (state == 1) {
    		this.$sendPlanetaryComms("For planet-side landing please approach and your automated landing clearance request will be triggered.");
    	}
    	if (state == 2) {
    		if (!this.messageBlock) {
    			this.$sendPlanetaryComms("Landing clearance request received.");
    			this.$sendPlanetaryComms("Please await confirmation before beginning final approach.");
    		}
    		this.clearanceDelay = 5 + (Math.ceil(Math.random() * 15)); // delay between 6 and 20 seconds
    		this.landingTimer = new Timer(this, this.$landingClearance, this.clearanceDelay);
    		this.checkingStation = stn;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$clearStationState = function () {
    	var stns = system.shipsWithRole("planetFall2_surface");
    	var i = stns.length;
    	while (i--) {
    		stns[i].state = 0;
    		stns[i].dockWarning = false;
    		stns[i].alignWarning1 = false;
    		stns[i].alignWarning2 = false;
    		stns[i].alignWarning3 = false;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.missionScreenOpportunity = function () {
    	// Player is docked at a military base or penal colony - not somewhere a criminal should make himself known ;)
    	if (player.ship.bounty > 25) { // player is mid-level offender or fugitive
    		if (player.ship.dockedStation.hasRole("planetFall2_mainSurface_militaryBase") || player.ship.dockedStation.hasRole("planetFall2_subSurface_militaryBase") || player.ship.dockedStation.hasRole("planetFall2_moonSurface_prison")) {
    			missionVariables.planetFallFine = 20 + (Math.ceil(Math.random() * 480)); // fine of 21-500 credits
    			if (player.ship.bounty > 50) { // if the player is a fugitive
    				// raise fine by another 1-500 credits
    				missionVariables.planetFallFine += (Math.ceil(Math.random() * 500));
    			}
    
    			if (worldScripts.Cabal_Common_Functions) {
    				var t1 = expandMissionText("planetFall2_prison");
    				var t2 = t1.split(".");
    				var obj = {
    					role: "planetFall2_scene_prison",
    					absolutePos: [0, -5, 150],
    					briefing: [
    						[1, "walk", [0, -1, 6, 10, 0.15, 2, 0, 0], t2[0].trim() + "."],
    						[24, "rot", [0, -1, 4.5, 0.0015, 0.0015, 0, 0, 1, 1], t2[1].trim() + "."],
    						[25, "stopVelo", [0, -1]],
    						[100, "mes", t2[2].trim() + "."],
    						[101, "kill"],
    						[102, 0]
    					],
    					title: "Do not pass GO, do not collect 200cr",
    					callback: this.name,
    					callbackf: "$jailRelease"
    				};
    				worldScripts.Cabal_Common_Briefing.startBriefing(obj);
    			} else {
    				mission.runScreen({
    					title: "Do not pass GO, do not collect 200cr",
    					messageKey: "planetFall2_prison",
    					model: "[planetFall2_scene_prison]",
    					spinModel: false,
    				}, this.$jailRelease);
    				var m = mission.displayModel;
    				m.position = Vector3D(0, 0, m.collisionRadius * 1.82);
    			}
    			return;
    		}
    	}
    	if (player.ship.dockedStation.allegiance == "restricted" && player.ship.dockedStation.hasRole("planetFall2_surface") && !this.permitMilitaryDock) {
    		mission.runScreen({
    			title: "Restricted Military Location",
    			messageKey: "planetFall2_restricted",
    			overlay: { name: "planetFall2_noEntry.png", height: 546 }
    		}, this.$kickedOut);
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.guiScreenChanged = function (to, from) {
    	var p = player.ship;
    
    	if (!p.docked) { // for GUI screen changes whilst in flight, which we can ignore
    		return;
    	}
    
    	// if we going to the equip ship screen, and we have a service level less than 85
    	// and this isn't a planetary location, and maintenance overhauls have been move to the planet
    	// and we haven't told the player about this yet...better let them know.
    	if (guiScreen == "GUI_SCREEN_EQUIP_SHIP" && p.serviceLevel < 85 && !p.dockedStation.hasRole("planetFall2_surface") && this._config.moveRenovation && !this._config.renovationMessage) {
    		this._config.renovationMessage = true;
    		mission.runScreen({
    			title: "Maintenance Warning",
    			messageKey: "planetFall2_renovation",
    			overlay: { name: "planetFall2_equipship.png", height: 546 },
    			exitScreen: "GUI_SCREEN_EQUIP_SHIP"
    		});
    	}
    
    	if (!p.dockedStation.hasRole("planetFall2_surface")) { // if we're at a non-PlanetFall location
    		return;
    	}
    
    	if (guiScreen == "GUI_SCREEN_REPORT" && this.background != "" && this._config.useLandingImages) {
    		this.showImage = new Timer(this, function () {
    			if (typeof this.background == "string") {
    				setScreenBackground({ name: this.background, height: 492 });
    			} else {
    				setScreenBackground(this.background);
    			}
    			if (this.overlay != "") {
    				setScreenOverlay({ name: this.overlay, height: 492 });
    			} else {
    				setScreenOverlay(null);
    			}
    		}, 0.25, 0);
    		return;
    	}
    
    	var key = p.dockedStation.dataKey.substring(0, p.dockedStation.dataKey.length - 2);
    	var noTrade = false;
    	var noEquip = false;
    	var noShip = false;
    
    	if (guiScreen == "GUI_SCREEN_MARKET") {
    		if (p.dockedStation.hasRole("planetFall2_noTrade") || this._config.marketMethod[key] == 0) noTrade = true;
    		if (missionVariables.PlanetFall2_DockedStation != p.dockedStation.dataKey) noShip = true;
    	}
    	if (guiScreen == "GUI_SCREEN_EQUIP_SHIP") {
    		if (p.dockedStation.hasRole("planetFall2_noEquip") || this._config.equipShip[key] == false) noEquip = true;
    		if (p.dockedStation.scriptInfo && p.dockedStation.scriptInfo.hasOwnProperty("allow_f3")) noEquip = !p.dockedStation.scriptInfo.allow_f3;
    		if (missionVariables.PlanetFall2_DockedStation != p.dockedStation.dataKey) noShip = true;
    	}
    
    	if (noTrade || noEquip) {
    		mission.runScreen({
    			title: "Service Unavailable",
    			messageKey: "planetFall2_noTrade",
    			overlay: { name: "planetFall2_noEntry.png", height: 546 },
    			exitScreen: "GUI_SCREEN_STATUS"
    		});
    		return;
    	}
    
    	if (noShip) {
    		mission.runScreen({
    			title: "Service Unavailable",
    			messageKey: "planetFall2_noShip",
    			overlay: { name: "planetFall2_noEntry.png", height: 546 },
    			exitScreen: "GUI_SCREEN_STATUS"
    		});
    		return;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$jailRelease = function () {
    	if (player.credits > missionVariables.planetFallFine) {
    		player.credits -= missionVariables.planetFallFine;
    		player.ship.bounty -= (Math.ceil(missionVariables.planetFallFine * 0.05)); // lower bounty corresponding to fine.
    	} else {
    		player.credits = 10;
    	}
    	player.ship.launch();
    	this.jailTime = 21600 + (Math.random() * 43200); // between 6 and 18 hours in the cells
    	clock.addSeconds(this.jailTime);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$kickedOut = function () {
    	player.ship.launch();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // this is to avoid the issue where player.ship.commsMessages appear to come out of nowhere.
    this.$sendPlanetaryComms = function (msg) {
    	if (!player.ship || !player.ship.isValid) return;
    	var temp = system.addShips("[planetFall2_commObject]", 1, player.ship.position.add(player.ship.vectorUp.multiply(300)))[0];
    	temp.displayName = system.name + " Planetary Control";
    	temp.commsMessage(msg, player.ship);
    	temp.remove(true);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // play sound effects
    this.$playSound = function $playSound(soundtype) {
    	var mySound = new SoundSource;
    	switch (soundtype) {
    		case "explosion":
    			mySound.sound = "[player-scrape-damage]";
    			break;
    		case "depart":
    			mySound.sound = "planetFall2_depart.ogg";
    			break;
    		case "arrive":
    			mySound.sound = "planetFall2_arrive.ogg";
    			break;
    		default:
    			return;
    	}
    	mySound.loop = false;
    	mySound.play();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$getPlanetFromCoords = function (coords) {
    	var pl = system.planets;
    	var i = pl.length;
    	while (i--) {
    		if (parseInt(pl[i].position.distanceTo(coords)) == 0) return pl[i];
    	}
    	return null;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$systemScan = function () {
    	function isMoon(entity) { return (entity.isPlanet && !entity.hasAtmosphere) };
    	this.systemArray = system.planets;
    	this.systemCount = this.systemArray.length;
    	this.moonCount = system.filteredEntities(this.systemArray, isMoon).length;
    	this.planetCount = this.systemCount - this.moonCount;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // reduces airColor of planet to 1 of 8 color descriptors
    this.$returnMainColor = function (planet) {
    	if (!player.ship.isSunlit) return "night";
    	var ac = planet.airColor;
    	if (!ac) ac = [0, 0, 1];
    
    	var hsv = this.rgb2hsv(ac[0], ac[1], ac[2]);
    	if (hsv.s > 30) {
    		// note: in the core game, only cyan, blue and purple will be returned, based on the aircolor property
    		// OXPs may change things to broaden the range (for instance, TionislaIsMars)
    		if (hsv.h >= 338 || hsv.h < 22) return "red";
    		if (hsv.h >= 22 && hsv.h < 45) return "orange";
    		if (hsv.h >= 45 && hsv.h < 70) return "yellow";
    		if (hsv.h >= 70 && hsv.h < 140) return "green";
    		if (hsv.h >= 140 && hsv.h < 202) return "clear"; //"cyan";
    		if (hsv.h >= 202 && hsv.h < 251) return "clear"; //"blue"; // I'm calling this as equivalent to clear
    		if (hsv.h >= 251 && hsv.h < 292) return "clear"; //"purple";
    		if (hsv.h >= 292 && hsv.h < 338) return "violet"; // this doesn't turn up very often.
    	} else {
    		return "clear"; // ie no filter
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // assumes r g b are all between 0 and 1
    this.rgb2hsv = function rgb2hsv(r, g, b) {
    	let v = Math.max(r, g, b), c = v - Math.min(r, g, b);
    	let h = c && ((v == r) ? (g - b) / c : ((v == g) ? 2 + (b - r) / c : 4 + (r - g) / c));
    	return { h: 60 * (h < 0 ? h + 6 : h), s: (v && c / v) * 100, v: v * 100 };
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // gets the TL factor for a particular landing zone type (main, planet or moon)
    this.$getTLFactor = function (type) {
    	var tl = system.techLevel + 1;
    	var r_min = this._config.chances.tlFactors[type].min;
    	var r_max = this._config.chances.tlFactors[type].max;
    	var inc = (r_max - r_min) / 15;
    	return (tl * inc) + r_min;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$damageChance = function () {
    	var chance = 0;
    	var p = player.ship;
    	if (!p.hasEquipmentProviding("EQ_HEAT_SHIELD")) chance += 0.05;
    	return chance;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // we're utilising a secondary value so if the player choose a decrease value of between 0 and 1, we can still track it.
    this.$serviceLevelDecrease = function () {
    	this.subServiceLevel += this._config.serviceLevelDecrease;
    	if (this.subServiceLevel >= 1) {
    		player.ship.serviceLevel -= 1;
    		this.subServiceLevel -= 1;
    	}
    }