Back to Index Page generated: May 8, 2024, 6:16:03 AM

Expansion Planetfall

Content

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 Thargoid
Version 1.51 1.51
Tags dockables, system dockables, system
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Information URL http://wiki.alioth.net/index.php/Planetfall_OXP n/a
Download URL https://wiki.alioth.net/img_auth.php/2/24/PlanetFall_1.51.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 1610873250

Documentation

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

Planetfall v1.51 Developers ReadMe.txt

Planetfall OXP by Thargoid.

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.PlanetFall.lastPlanet - this is the last planet to be approached.
worldScripts.PlanetFall.lastPlanetType - the type of the last planet landed on ("Prime", "Sub" or "Moon") or approached ("Sun" or "GasGiant").
worldScripts.PlanetFall.planetCount - how many planets (bodies with atmospheres) in the system.
worldScripts.PlanetFall.moonCount - how many moons (bodies without atmospheres) in the system.
worldScripts.PlanetFall.globes - an array of the planetary bodies (suns, moons, planets and gas giants) in the system, in order of distance from the player ship.
worldScripts.PlanetFall.globeRange - distance from the nearest planetary body.

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

To add additional locations, use a shipdata.plist entry as in the two above examples. The entry for the hoOpy casino on the main planets for example is:

	"planetFall_mainSurface_hoopyCasino" =
		{
		like_ship = "planetFall_genericSurface";
		name = "CoachWhip hOopy Casino"; 
		roles = "planetFall_mainSurface_hoopyCasino planetFall_mainSurface_externalOXP station(0) planetFall_mainSurface planetFall_surface";
		};

The first role should be replaced by the appropriate one, 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 planetFall_<main/sub/moon>Surface_externalOXP role, so the use of commodities.plist is strongly discouraged (as it will affect all added locations, including the monks and hoOpy casino's).

Newly added with version 1.12:

If the variable worldScripts.PlanetFall.planetFallOverride is set to true, only external OXP locations are spawned. 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.

Newly added with version 1.50:

If the variable worldScripts.PlanetFall.overrideRole is set, that specific role will be used for the next landing attempt (if worldScripts.PlanetFall.planetFallOverride is set to true). This will allow external OXPs to set a specific role to be used. Care should of course be taken that a second OXP may also make a similar setting. When the player launches from the custom location the variable is reset back to "default". If the variable is not set then the standard default roles of planetFall_<main/sub/moon>Surface_externalOXP are used.

If any assistance is needed to make such an OXP location, just let me know!

Thargoid

13/02/2011

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. 

--------------------------------------------------------------

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

Equipment

Name Visible Cost [deci-credits] Tech-Level
Planetary Landing Capability yes 50000 9+

Ships

Name
PlanetFall Dock
Generic Surface Template
Capital City
Rubbish Dump
Factory Complex
Hydro Farm
Open Fields
Leisure Complex
Military Base
A Seedy Space Bar
Shipyard
Colony Dome
Robot Factory
Leisure Dome
Mine
Penal Colony
Research Complex
A Seedy Space Bar
Lunar Wasteland
PlanetFall Scene Prison
Colony City
Rubbish Dump
Factory Complex
Hydro Farm
Open Fields
Leisure Complex
Military Base
A Seedy Space Bar
Shipyard

Models

This expansion declares no models.

Scripts

Path
Scripts/planetFall_landingFX.js
this.name = "planetFall_landingFX";
this.author = "Svengali & Thargoid";
this.copyright = "CC-by";
this.description = "FX script";
this.version = "1.0";
"use strict";

this.effectSpawned = function()
	{
	this.getRid = 0;
	this.firstFrame = true;
	this.ovFCBID = addFrameCallback(this.repos.bind(this));
	}

this.effectRemoved = function()
	{ removeFrameCallback(this.ovFCBID); }
	
this.repos = function(delta)
	{
	if(!player.ship.isValid || getRid > 2.5) 
		{ 
		this.visualEffect.remove();
		return;
		}
		
	if(this.firstFrame || !delta)
		{
		this.firstFrame = false;
		return;
		}
	
	this.visualEffect.position = player.ship.position.add(player.ship.vectorForward.multiply(150 - ((getRid / 2.5) * 100)));
	this.visualEffect.orientation = player.ship.orientation;
	this.getRid += delta;
	return;
	}
Scripts/planetFall_launchFX.js
this.name = "planetFall_launchFX";
this.author = "Svengali & Thargoid";
this.copyright = "CC-by";
this.description = "FX script";
this.version = "1.0";
"use strict";

this.effectSpawned = function()
	{
	this.firstFrame = true;
	this.getRid = 0;
	this.ovFCBID = addFrameCallback(this.repos.bind(this));
	}

this.effectRemoved = function()
	{ removeFrameCallback(this.ovFCBID); }
	
this.repos = function(delta)
	{
	if(!player.ship.isValid || this.getRid >= 3) 
		{ 
		this.visualEffect.remove();
		return;
		}
	
	if(this.firstFrame || !delta)
		{
		this.firstFrame = false;
		return;
		}
		
	this.tex = "planetFall_launchFX" + Math.floor(this.getRid)+".png";
	this.visualEffect.setMaterials({"planetFall_launchFX0.png": {diffuse_map: this.tex }});
	this.visualEffect.position = player.ship.position.add(player.ship.vectorForward.multiply(150));
	this.visualEffect.orientation = player.ship.orientation;
	this.getRid += (2 * delta); // to get the effect finished before true launch into realspace
	return;
	}
Scripts/planetFall_worldScript.js
this.name			= "PlanetFall";
this.author			= "Thargoid, 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.version		= "1.51";

this.startUp = function()
	{ 
	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
	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.messageBlock = false; // flag to stop request/cancel messages at launch from planet
	this.planetCount = 1; // default setting
	this.moonCount = 0; // default setting
	this.$systemScan(); // set up the initial planet and moon count
	this.planetFallOverride = false; // flag to allow other OXPs to override PlanetFall locations
	this.overrideRole = "default"; // if other OXPs want to ensure a specific role is used
	this.$checkForSpecialPlanets();

/* For convenience of mission writers, access for other OXPs is via "worldScripts.PlanetFall.lastPlanet" and "worldScripts.PlanetFall.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). */
	}

this.$turnStation = function(tempStation)
	{
	if(!tempStation) { return; } // just in case the station doesn't survive spawning.
	let stationVector = tempStation.position.subtract(this.lastPlanet.position).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
	tempStation.position = tempStation.position.add(stationVector.multiply(3000));
	tempStation.breakPattern = false;
	}

this.shipApproachingPlanetSurface = function(planet) 
	{
	if(!planet || player.ship.equipmentStatus("EQ_PLANETFALL") != "EQUIPMENT_OK" || planet.hasOwnProperty("PFNoLandQuiet"))
		{
		return;
		}

	if(planet.hasOwnProperty("PFNoLand"))
		{
		player.commsMessage(system.name + " Planetary Control - Urgent warning - landing is not possible here!", 6);
		return;	
		}	
	
	this.lastPlanet = planet;	
	
	if(!this.landingTimer)  
		{
		if(!planet.isSun && !planet.hasOwnProperty("solarGasGiant") && !planet.hasOwnProperty("isGasGiant"))
			{
			this.messageBlock = true;
			if(planet === system.mainPlanet)
				{
				this.lastPlanetType = "Prime";
				this.landingChoice = (Math.random()*10);				
				if(this.planetFallOverride)
					{
					if(this.overrideRole === "default")
						{ this.overrideRole = "planetFall_mainSurface_externalOXP" };
					this.port = player.ship.spawnOne(this.overrideRole);
					this.$turnStation(this.port);
					this.overrideRole = "default";
					}
				else
					{
					if(this.landingChoice < 3) // spawn capital city
						{
						this.port = player.ship.spawnOne("planetFall_mainSurface_capitalCity"); 
						this.$turnStation(this.port);
						} 
					if(this.landingChoice >= 3 && this.landingChoice < 4.5) // spawn external OXP location, or if none then Capital City
						{
						if(this.overrideRole !== "default") 
							{ this.port = player.ship.spawnOne(this.overrideRole); }
							else
							{ this.port = player.ship.spawnOne("planetFall_mainSurface_externalOXP"); }
						if(!this.port)
							{
							log(this.name, "Main surface external spawn failure");
							this.port = player.ship.spawnOne("planetFall_mainSurface_capitalCity"); 
							}						
						this.$turnStation(this.port);
						this.overrideRole = "default";			
						} 
					if(this.landingChoice >= 4.5 && this.landingChoice < 6.5) // spawn a shipyard
						{
						this.port = player.ship.spawnOne("planetFall_mainSurface_shipYard");
						this.$turnStation(this.port);
						} 
					if(this.landingChoice >= 6.5 && this.landingChoice < 7.5) // spawn a military base
						{
						this.port = player.ship.spawnOne("planetFall_mainSurface_militaryBase"); 
						this.$turnStation(this.port);
						} 
					if(this.landingChoice >= 7.5 && this.landingChoice < 8.9) // spawn seedy bar or leisure complex
						{
						if((system.government == 0 || this.landingChoice < 8.05) && worldScripts["Random_Hits"])
							{
							this.port = player.ship.spawnOne("planetFall_mainSurface_seedyBar");
							this.$turnStation(this.port);
							this.barName = expandDescription('[planetFall_barName]');
						    missionVariables.random_hits_seedy_spacebar_header = worldScripts["Random_Hits"].barDescription(barName);
							this.port.displayName = this.barName;
							}
						else
							{
							this.port = player.ship.spawnOne("planetFall_mainSurface_leisureComplex");
							this.$turnStation(this.port);
							}
						} 
					if(this.landingChoice >= 8.9 && this.landingChoice < 9.8) // spawn factory or farm
						{
						if(system.economy < 4)
							{
							this.port = player.ship.spawnOne("planetFall_mainSurface_factory");
							this.$turnStation(this.port);
							}
						else
							{
							this.port = player.ship.spawnOne("planetFall_mainSurface_farm");
							this.$turnStation(this.port);
							}
						} 
					if(this.landingChoice >= 9.8) // spawn open fields or waste dump
						{
						if(system.economy < 4)
							{
							this.port = player.ship.spawnOne("planetFall_mainSurface_dump");
							this.$turnStation(this.port);
							}
						else
							{
							this.port = player.ship.spawnOne("planetFall_mainSurface_fields");
							this.$turnStation(this.port);
							}
						} 
					}
					
				if(this.lastPlanet.name)
					{ this.port.displayName = this.lastPlanet.name + " - " + this.port.displayName; }
				else
					{ this.port.displayName = system.name + " Prime - " + this.port.displayName; } // set the name to the surface of the prime planet in the system
				}
			else
				{
				if(planet.hasAtmosphere)
					{
					this.lastPlanetType = "Sub";
					this.landingChoice = (Math.random()*10);
					if(this.planetFallOverride)
						{
						if(this.overrideRole == "default") { this.overrideRole = "planetFall_subSurface_externalOXP"; };
						this.port = player.ship.spawnOne(this.overrideRole);
						this.$turnStation(this.port);
						this.overrideRole = "default";
						}
					else
						{
						if(this.landingChoice < 3) // spawn capital city
							{
							this.port = player.ship.spawnOne("planetFall_subSurface_colony"); 
							this.$turnStation(this.port);
							} 
						if(this.landingChoice >= 3 && this.landingChoice < 4.5) // spawn external OXP location, or if none then a colony
							{
							if(this.overrideRole !== "default") 
								{ this.port = player.ship.spawnOne(this.overrideRole); }
								else
								{ this.port = player.ship.spawnOne("planetFall_subSurface_externalOXP"); }	
							if(!this.port)
								{
								log(this.name, "Sub surface external spawn failure");
								this.port = player.ship.spawnOne("planetFall_subSurface_colony"); 
								}	
						this.$turnStation(this.port);
							this.overrideRole = "default";
							} 
						if(this.landingChoice >= 4.5 && this.landingChoice < 6.5) // spawn a shipyard
							{
							this.port = player.ship.spawnOne("planetFall_subSurface_shipYard");
							this.$turnStation(this.port);
							} 
						if(this.landingChoice >= 6.5 && this.landingChoice < 7.5) // spawn a military base
							{
							this.port = player.ship.spawnOne("planetFall_subSurface_militaryBase"); 
							this.$turnStation(this.port);
							} 
						if(this.landingChoice >= 7.5 && this.landingChoice < 8.9) // spawn seedy bar or leisure complex
							{	
							if((system.government == 0 || this.landingChoice < 8.05) && worldScripts["Random_Hits"])
								{
								this.port = player.ship.spawnOne("planetFall_subSurface_seedyBar");
								this.$turnStation(this.port);
								this.barName = expandDescription('[planetFall_barName]');
								missionVariables.random_hits_seedy_spacebar_header = worldScripts["Random_Hits"].barDescription(barName);
								this.port.displayName = this.barName;
								}
							else
								{
								this.port = player.ship.spawnOne("planetFall_subSurface_leisureComplex");
								this.$turnStation(this.port);
								}
							} 
						if(this.landingChoice >= 8.9 && this.landingChoice < 9.8) // spawn factory or farm
							{
							if(system.economy < 4)
								{
								this.port = player.ship.spawnOne("planetFall_subSurface_factory");
								this.$turnStation(this.port);
								}
							else
								{
								this.port = player.ship.spawnOne("planetFall_subSurface_farm");
								this.$turnStation(this.port);
								}
							} 
						if(this.landingChoice >= 9.8) // spawn open fields or waste dump
							{
							if(system.economy < 4)
								{
								this.port = player.ship.spawnOne("planetFall_subSurface_dump");
								this.$turnStation(this.port);
								}
							else
								{
								this.port = player.ship.spawnOne("planetFall_subSurface_fields");
								this.$turnStation(this.port);
								}
							} 
						}

					if(this.lastPlanet.name)
						{ this.port.displayName = this.lastPlanet.name + " - " + this.port.displayName; }
					else
						{ this.port.displayName = system.name + " Minor - " + this.port.displayName; } // set the name to just the surface, so we can identify easily the main planet
					}
				else
					{
					this.lastPlanetType = "Moon";
					this.landingChoice = (Math.random()*10);
					if(this.planetFallOverride)
						{
						if(this.overrideRole == "default") { this.overrideRole = "planetFall_moonSurface_externalOXP" };
						this.port = player.ship.spawnOne(this.overrideRole);
						this.$turnStation(this.port);
						this.overrideRole = "default";
						}
					else
						{
						if(this.landingChoice < 3) // spawn capital city
							{
							this.port = player.ship.spawnOne("planetFall_moonSurface_dome"); 
							this.$turnStation(this.port);
							} 
						if(this.landingChoice >= 3 && this.landingChoice < 4.5) // spawn external OXP location, or if none then a dome
							{
							if(this.overrideRole !== "default") 
								{ this.port = player.ship.spawnOne(this.overrideRole); }
								else
								{ this.port = player.ship.spawnOne("planetFall_moonSurface_externalOXP"); }
							if(!this.port)
								{
								log(this.name, "Moon external spawn failure");
								this.port = player.ship.spawnOne("planetFall_moonSurface_dome"); 
								}	
							this.$turnStation(this.port);
							this.overrideRole = "default";
							} 
						if(this.landingChoice >= 4.5 && this.landingChoice < 6.5) // spawn a mine
							{
							this.port = player.ship.spawnOne("planetFall_moonSurface_mine");
							this.$turnStation(this.port);
							} 
						if(this.landingChoice >= 6.5 && this.landingChoice < 8) // spawn a bar or leisure dome
							{	
							if((system.government == 0 || this.landingChoice < 7.5) && worldScripts["Random_Hits"])
								{
								this.port = player.ship.spawnOne("planetFall_moonSurface_seedyBar");
								this.$turnStation(this.port);
								this.barName = expandDescription('[planetFall_barName]');
								missionVariables.random_hits_seedy_spacebar_header = worldScripts["Random_Hits"].barDescription(barName);
								this.port.displayName = this.barName;
								}
							else
								{
								this.port = player.ship.spawnOne("planetFall_moonSurface_leisureDome");
								this.$turnStation(this.port);
								}
							} 
						if(this.landingChoice >= 8 && this.landingChoice < 8.9) // spawn a prison
							{
							this.port = player.ship.spawnOne("planetFall_moonSurface_prison"); 
							this.$turnStation(this.port);
							} 
						if(this.landingChoice >= 8.9 && this.landingChoice < 9.8) // spawn a research complex or factory
							{
							if(system.techLevel > 11)
								{
								this.port = player.ship.spawnOne("planetFall_moonSurface_researchComplex");
								this.$turnStation(this.port);
								}
							else
								{
								this.port = player.ship.spawnOne("planetFall_moonSurface_factory");
								this.$turnStation(this.port);
								}
							} 
						if(this.landingChoice >= 9.8) // spawn wasteland
							{
							this.port = player.ship.spawnOne("planetFall_moonSurface_wasteland"); 
							this.$turnStation(this.port);
							} 
						}

					if(this.lastPlanet.name)
						{ this.port.displayName = this.lastPlanet.name + " - " + this.port.displayName; }
					else
						{ this.port.displayName = "Moon of " + system.name + " - " + this.port.displayName; } // set the name to the moon, so we can identify it as a moon
					}
				}
			this.fx = system.addVisualEffect("planetFall_landingFX",player.ship.position.add(player.ship.vectorForward.multiply(170)));	
			this.port.dockPlayer();	
			}
		else
			{
			if(planet.hasOwnProperty("solarGasGiant") || planet.hasOwnProperty("isGasGiant"))
				{
				this.lastPlanetType = "GasGiant";
				}
			else
				{
				this.lastPlanetType = "Sun";
				}
			}
		}
	else
		{ // if the PF landing timer is still running
		player.commsMessage(system.name + " Planetary Control - Pull up, you have no landing clearance!", 6);
		player.commsMessage("Return to orbit and approach again.", 6);
		this.landingTimer.stop();
		delete this.landingTimer;
		}
	}

this.shipWillDockWithStation = function(station)
	{
	if(station.hasRole("planetFall_surface") || station.hasRole("planetFall_mainSurface_externalOXP") || station.hasRole("planetFall_subSurface_externalOXP") || station.hasRole("planetFall_moonSurface_externalOXP") )
		{
		if(!this.fx) { this.fx = system.addVisualEffect("planetFall_landingFX",player.ship.position.add(player.ship.vectorForward.multiply(170))); }
		this.selectTexture = 1 + (Math.floor(Math.random() * 9));
		if(station.hasRole("planetFall_moonSurface"))
			{ this.fx.setMaterials({"planetFall_planet1.png": {diffuse_map: "planetFall_moon" + this.selectTexture + ".png" }}); }
		else
			{ this.fx.setMaterials({"planetFall_planet1.png": {diffuse_map: "planetFall_planet" + this.selectTexture + ".png" }}); }
	}
		
	if((station.hasRole("planetFall_mainSurface_seedyBar") || station.hasRole("planetFall_subSurface_seedyBar") || station.hasRole("planetFall_moonSurface_seedyBar")) && worldScripts["Random_Hits"])
		{ // Player is docked at a planet-side seedy bar
		worldScripts["Random_Hits"].random_hits_docked = true;
		}
	}
	
this.shipWillLaunchFromStation = function(station)
	{
	if(station)
		{ 
		this.planetFallLaunch = true;
		if(station.hasRole("planetFall_surface"))
			{
			this.fx = system.addVisualEffect("planetFall_launchFX",player.ship.position.add(player.ship.vectorForward.multiply(150)));
			this.fx.orientation = player.ship.orientation;
			}
		} 
	}	
	
this.alertConditionChanged = function()
	{
	if(this.planetFallLaunch)
		{
		this.planetFallLaunch = false;
		return;
		}

	if(player.alertAltitude && !this.lastPlanet.isSun && !this.lastPlanet.hasOwnProperty("solarGasGiant") && !this.lastPlanet.hasOwnProperty("PFNoLand") && !this.lastPlanet.hasOwnProperty("PFNoLandQuiet") && !this.lastPlanet.hasOwnProperty("isGasGiant"))
		{
		if(player.ship.equipmentStatus("EQ_PLANETFALL") != "EQUIPMENT_OK")
			{
			player.commsMessage(system.name + " Planetary Control - Your ship is not equipped for planetfall.", 10);
			player.commsMessage("Do not attempt landing, your ship will be destroyed!", 10);
			}
		else
			{
			if(!this.messageBlock)
				{
				player.commsMessage(system.name + " Planetary Control - Landing clearance request received.", 6);
				player.commsMessage("Please await confirmation before beginning final approach.", 6);
				}
			this.clearanceDelay = 5 + (Math.ceil(Math.random()*15)); // delay between 6 and 20 seconds
			this.landingTimer = new Timer(this, this.$landingClearance, this.clearanceDelay);
			}
		}

	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;
		}
		
	if(!player.alertAltitude && this.landingTimer && this.landingTimer.isRunning && !player.ship.docked && EquipmentInfo.infoForKey("EQ_FRAME_SAVE") == null)
		{
		this.landingTimer.stop();
		delete this.landingTimer;
		missionVariables.planetFallBreak += 0.01; // 1% cumulative chance of equipment failure
		if(!this.messageBlock)
			{
			player.commsMessage(system.name + " Planetary Control - Landing clearance request cancelled.", 6);
			player.commsMessage("Goodbye Commander " + player.name + ".", 6);
			this.messageBlock = false;
			}
		}
	}

this.$landingClearance = function()
	{
	this.landingTimer.stop();
	delete this.landingTimer;
	player.commsMessage(system.name + " Planetary Control - Landing clearance granted.",6);
	player.commsMessage("Please approach the surface slowly.", 6);
	}

this.shipLeavingPlanetSurface = function(planet)
	{
	this.lastPlanet = planet;
	this.messageBlock = false;
	}

this.shipDied = function()
	{
	let ports = system.shipsWithRole("planetFall_surface"); // an array of any rogue "surface stations" in the system
	this.portCount = ports.length; // how many rogues we have that need to be removed
	if(this.portCount > 0) for (let i=0; i<this.portCount; i++) // if there are any, loop through and remove them
		{ this.$removePort(ports[i]); }
	if(this.landingTimer && this.landingTimer.isRunning)
		{
		this.landingTimer.stop();
		delete this.landingTimer;	
		}
	}

this.shipEnteredPlanetaryVicinity = function(planet)
	{
	if(!planet) { return; }

	this.lastPlanet = planet;
	if(!planet.isSun && !planet.hasOwnProperty("solarGasGiant") && !planet.hasOwnProperty("isGasGiant") && !planet.hasOwnProperty("PFNoLand") && !planet.hasOwnProperty("PFNoLandQuiet") && player.ship.equipmentStatus("EQ_PLANETFALL") == "EQUIPMENT_OK")
		{
		player.commsMessage(system.name + " Planetary Control - for planetfall please approach and request landing clearance.",5);
		}
	else
		{
		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"))
			{ player.commsMessage("ALERT - Landing is not possible here, please pull up!", 10); }
		}
	}

this.shipExitedPlanetaryVicinity = function()
	{ 
	this.messageBlock = false; 
	this.shipDied(); // clean-up of any unremoved surface stations.
	}

this.shipLaunchedFromStation = function(station)
	{
	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("planetFall_surface"))
		{
		if(this.landingTimer) 
			{ delete this.landingTimer; }	
		player.commsMessage(system.name + " Planetary Control - orbital boost complete.",5);
		player.commsMessage("Farewell Commander " + player.name + ".",5);
		this.$removePort(station); // remove the surface-simulating station
		this.messageBlock = false;
		missionVariables.planetFallBreak += 0.02; // 2% cumulative chance of equipment failure 
		if(Math.random() < missionVariables.planetFallBreak) // landing equipment needs maintenance
			{
			player.ship.setEquipmentStatus("EQ_PLANETFALL", "EQUIPMENT_DAMAGED");
			player.consoleMessage("ALERT - Planetary landing modifications require urgent maintenance.", 10);
			player.consoleMessage("Do not attempt to land again before they are repaired!", 10);
			missionVariables.planetFallBreak = -0.04; // first two launches guaranteed not to break equipment
			}
		}

	this.$systemScan();
	}
	
this.playerBoughtEquipment = function(equipment)  // guarantee first two launches won't break equipment
	{
	if(equipment == "EQ_PLANETFALL")
		{ missionVariables.planetFallBreak = -0.04; }
	}

this.shipExitedWitchspace = function()
	{
	this.$checkForSpecialPlanets();
	this.overrideRole = "default";
	this.$systemScan();
	}

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;
	}

this.$removePort = function(port)
	{	
	if(port.hasRole("planetFall_surface"))
		{ port.remove(); };
	}

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.guiScreenChanged = function()
	{
	if(!player.ship.docked) // for GUI screen changes whilst in flight, which we can ignore
		{ return; }

	if(!player.ship.dockedStation.hasRole("planetFall_surface")) // if we're at a trunk or other OXP's station
		{ return; }

	 // 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("planetFall_mainSurface_militaryBase") || player.ship.dockedStation.hasRole("planetFall_subSurface_militaryBase") || player.ship.dockedStation.hasRole("planetFall_moonSurface_prison"))
			{
				if(guiScreen == "GUI_SCREEN_EQUIP_SHIP" || guiScreen == "GUI_SCREEN_MARKET" || guiScreen == "GUI_SCREEN_SHIPYARD")
				{
				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("planetFall_prison");
					var t2 = t1.split(".");
					var obj = {
						role:"planetFall_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);
					return;	
					}
				else
				 { mission.runScreen({title:"Do not pass GO, do not collect 200cr", messageKey:"planetFall_prison", background:"planetFall_cell.png"}, this.$jailRelease); }
				}
			}
		}

	if(!player.ship.dockedStation.hasRole("planetFall_noTrade")) // if we're at a location where trading is possible
		{ return; }

	// no-one to trade with on the empty lunar surface
	if(player.ship.dockedStation.hasRole("planetFall_moonSurface_wasteLand") ) 
		{
		if(guiScreen == "GUI_SCREEN_EQUIP_SHIP" || guiScreen == "GUI_SCREEN_MARKET")
			{
			mission.runScreen({title:"Lonely on the moon", messageKey:"planetFall_noTrade", background:"planetFall_lunarScape.png"});
			}
		}

	 // no-one to trade with in empty fields
	if(player.ship.dockedStation.hasRole("planetFall_mainSurface_fields") || player.ship.dockedStation.hasRole("planetFall_subSurface_fields")) 
		{
		if(guiScreen == "GUI_SCREEN_EQUIP_SHIP" || guiScreen == "GUI_SCREEN_MARKET")
			{
			mission.runScreen({title:"Nothing but fields...", messageKey:"planetFall_noTrade", background:"planetFall_fields.png"});
			}
		}

	// no-one to trade with in refuse dump
	if(player.ship.dockedStation.hasRole("planetFall_mainSurface_dump") || player.ship.dockedStation.hasRole("planetFall_subSurface_dump")) 
		{
		if(guiScreen == "GUI_SCREEN_EQUIP_SHIP" || guiScreen == "GUI_SCREEN_MARKET" || guiScreen == "GUI_SCREEN_SHIPYARD")
			{
			mission.runScreen({title:"All muck, no brass!", messageKey:"planetFall_noTrade", background:"planetFall_dump.png"});
			}
		}
	}
	
this.$checkForSpecialPlanets = function()
	{ this.scriptDelay = new Timer(this, this.$setFlags, 0.25); }

this.$setFlags = function()
	{	
	if(galaxyNumber === 0 && system.ID === 246) // if we're at Tianve (G0, S227), set up the pulsar
		{
		for (let i=0; i<system.planets.length; i++) 
			{ 
			if(system.planets[i].texture === "tianve_pulsar.png") 
				{ system.planets[i].PFNoLand = true; } 
			}
		}
	}