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

Expansion Interstellar Tweaks

Content

Warnings

  1. Extreanous whitespace on key 'interstellar: 6 251 224 '
  2. Unresolved dependency reference to oolite.oxp.UK_Eliter.ferdelance_3G:6.5
  3. Unresolved dependency reference to InterstellarTweaks.oxp:0
  4. Unresolved dependency reference to oolite.oxp.UK_Eliter.ferdelance_3G:6.5
  5. No version in dependency reference to InterstellarTweaks.oxp:null
  6. Conflict Expansions mismatch between OXP Manifest and Expansion Manager at character position 0056 (DIGIT ZERO vs LATIN SMALL LETTER N)
  7. Unknown key 'upload_date' at https://wiki.alioth.net/img_auth.php/7/7c/Oolite.oxp.UK_Eliter.InterstellarTweaks.oxz!manifest.plist

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Adds variety to what happens in interstellar space (and makes Frame's FuelCollector OXP more compatible with Oolite >= 1.8). Adds variety to what happens in interstellar space (and makes Frame's FuelCollector OXP more compatible with Oolite >= 1.8).
Identifier oolite.oxp.UK_Eliter.InterstellarTweaks oolite.oxp.UK_Eliter.InterstellarTweaks
Title Interstellar Tweaks Interstellar Tweaks
Category Mechanics Mechanics
Author UK_Eliter UK_Eliter
Version 6.96 6.96
Tags interstellar, ambience, systems, thargoids interstellar, ambience, systems, thargoids
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
  • oolite.oxp.UK_Eliter.ferdelance_3G:6.5
  • oolite.oxp.UK_Eliter.ExtraThargoids:6.5
  • oolite.oxp.UK_Eliter.ferdelance_3G:6.5
  • oolite.oxp.UK_Eliter.ExtraThargoids:6.5
  • Conflict Expansions
  • InterstellarTweaks.oxp:0
  • InterstellarTweaks.oxp:
  • Information URL http://www.aegidian.org/bb/viewtopic.php?f=4&t=11864&hilit=interstellar+tweaks n/a
    Download URL https://wiki.alioth.net/img_auth.php/7/7c/Oolite.oxp.UK_Eliter.InterstellarTweaks.oxz http://wiki.alioth.net/img_auth.php/7/7c/Oolite.oxp.UK_Eliter.InterstellarTweaks.oxz
    License Creative Commons Attribution - Non-Commercial - Share Alike 4.0 license Creative Commons Attribution - Non-Commercial - Share Alike 4.0 license
    File Size n/a
    Upload date 1647017414

    Documentation

    Also read http://wiki.alioth.net/index.php/Interstellar%20Tweaks

    Readme & License.txt

     _        _                   _        _  _             ___                  _
    | |._ _ _| |_ ___  _ _  ___ _| |_ ___ | || | ___  _ _  |_ _|_ _ _  ___  ___ | |__ ___
    | || ' | | | / ._>| '_><_-<  | | / ._>| || |<_> || '_>  | || | | |/ ._><_> || / /<_-<
    |_||_|_| |_| \___.|_|  /__/  |_| \___.|_||_|<___||_|    |_||__/_/ \___.<___||_\_\/__/
    
    
    An expansion pack for Oolite
    
    by 'UK_Eliter'
    
    
    
    ---------------------------
    REQUIREMENTS
    ---------------------------
    
    � This expansion pack requires Oolite version *1.82* or above.
    � Various expansion packs are recommended (but not necessary) to complement this one.
    � See the 'General notes' section below.
    
    
    ------------------------
    GENERAL NOTES
    ------------------------
    
    � This expansion pack makes misjumps a little more likely and, fairly often, modifies what happens when one misjumps. One can encounter only the navy, or only thargoids, or empty witchspace or . . various other things. The expansion pack also gives you a chance of having your escape pod rescued in interstellar space by any nearby behemoths or leviathans (presuming you have such ships installed). That chance increased if you have the 'electronic thumb' equipment.
    
    � The load that Interstellar Tweaks will place on your computer will be, for the most part, light to moderate (and, mostly, via CPU much more than RAM and graphics card). But if you have many of the expansion packs recommended below installed, then that will increase the load.
    
    � The difficulty of this expansion pack varies automatically, in various ways, with the player score.
    
    � This expansion pack makes various uses of numerous other expansion packs, when they are installed. Most of those expansion packs are listed below. The ones marked '*' are especially recommended for use with Interstellar Tweaks.
    
    	- Armoury;
    	- *Behemoth;*
    	- Breakable WitchDrive (preferably version 1.3 or above);
    	- *Electronic Thumb;*
    	- Enhanced MisJump (which changes the 'tunnel' effect when one misjumps);*
    	- *Escape Pod Locator;*
    	- *Extra Thargoids (use version >= 3.0 );* 
    	- *Fer-de-Lance 3G (use version >= 5.01 [NB the version!] );*
    	- *Fuel Collector* [patching no longer necessary with this version of Interstellar Tweaks]
    	- *Galactic Navy;*
    	- *Generation Ships* (note: the present expansion pack will - for one thing - make generation ships rarer); 
    	- Griff's shipset expansion packs (for, especially, nice looking thargoids!);
    	- Interstellar Help;
    	- *Military Fiasco;*
    	- Misjump Analyzer;
    	- Missionaries;
    	- *mPakRedux (a.k.a. 'Rusties');*
    	- Spectre [patch no longer necessary];
    	- Star Destroyer (use version >= 1.5);
    	- Tionisla Orbital Graveyeard (>= 2.4; needs its 'Shipwrecks' supplement)
    	- TCAT (= 'To Catch a Thargoid');
    	- Thargoid Carrier (this will considerably increase the thargoid threat - though it can be offset somewhat via my Fer-de-Lance 3G expansion pack);
    	- *Thargorn_Threat (preferably version 1.5.2 or above);*
    	- Wormwhole Restoration.
    
    � Interstellar Tweaks is compatible with THARGOID WITCHSPACE DRIVE. Moreover, Interstellar Tweaks seems to work with the WORMWHOLE DRONE expansion pack. Interstellar Tweaks should be compatible with cim's 'Galactic Misjump', too.
    
    
    ---------------
    LICENSE
    ---------------
    
    This expansion pack is released under the Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. 
    
    You are free:
    
    � to copy, distribute, display, and perform the work;
    � to make derivative works. 
    
    But only under the following conditions.
    
    � Attribution: you must give the original author credit. 
    � Non-commercial use: you may not use this work for commercial purposes. 
    � Share Alike: if you alter, transform, or build upon this work, you may distribute the resulting work only under a license materially identical to this one. 
    
    Your fair use right and other rights are in no way affected by the above.
    
    
    -----------------------------
     ACKNOWLEDGEMENTS
    -----------------------------
    
    My thanks to the following (from some of whom I have adapted code):
    
    	Another Commander; Arexack Heretic; Capt. Murphy; cim; Commander McLane; Draco_Caeles; Duggan; Dr Nil and other contributors to the 'Your Ad Here' expansion pack; Eric Walch; Gimi; Norby; phkb; Rustem; SirAdrian; Thargoid; Solonar; Switeck. Other OOliters have contributed in smaller ways and I am grateful to them too.
    
    
    --------------------------------------------
     NOTE FOR EXPANSION PACK MAKERS
    --------------------------------------------
    
    This expansion pack takes over Oolite's populator and repopulator functions for interstellar space.  Sometimes, though, it will run Oolite's inbuilt populator together with populators from other expansion packs.
    
    Also, and partly because of the old way in which Oolite used to do population, my expansion pack populates and depopulates interstellar space in other, more hack-ish ways.
    
    
    ----------------- END OF FILE ----------------- 

    Equipment

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

    Ships

    Name
    IST_TCAT_droneAndControllerOVERRIDE
    IST_Tharglet
    IST_alien_cargopod
    IST_alloy
    IST_asteroid
    IST_asteroid_b
    IST_boulder
    IST_cargopod
    IST_derelict_Adder
    IST_derelict_AdderRusty
    IST_derelict_AdderRusty_tionisla
    IST_derelict_Anaconda
    IST_derelict_AnacondaRusty
    IST_derelict_AnacondaRusty_tionisla
    IST_derelict_Asp
    IST_derelict_AspRusty
    IST_derelict_AspRusty_tionisla
    IST_derelict_Boa
    IST_derelict_BoaRusty
    IST_derelict_BoaRusty2
    IST_derelict_BoaRusty2_tionisla
    IST_derelict_BoaRusty_tionisla
    IST_derelict_CobraI
    IST_derelict_CobraIII
    IST_derelict_CobraIIIRusty
    IST_derelict_CobraIIIRusty_tionisla
    IST_derelict_CobraIRusty
    IST_derelict_CobraIRusty_tionisla
    IST_derelict_Ferdelance
    IST_derelict_Krait
    IST_derelict_KraitRusty
    IST_derelict_KraitRusty_tionisla
    IST_derelict_MambaRusty
    IST_derelict_MambaRusty_tionisla
    IST_derelict_Moray
    IST_derelict_MorayMED
    IST_derelict_MorayRusty
    IST_derelict_Python
    IST_derelict_PythonRusty
    IST_derelict_PythonRusty_tionisla
    IST_derelict_Sidewinder
    IST_derelict_SidewinderRusty
    IST_derelict_Thargoid
    IST_derelict_Viper
    IST_derelict_ViperInterceptor
    IST_derelict_ViperInterceptorRusty
    IST_derelict_ViperRusty
    Star Destroyer (naval)
    IST_generation-ship-cylinder
    IST_generation-ship-dock
    IST_generation-ship-frame
    IST_generation-ship-thruster
    Generation Ship (Hijacked)
    IST_hunter1
    IST_hunter10
    IST_hunter11a
    IST_hunter12
    IST_hunter13
    IST_hunter14
    IST_hunter15
    IST_hunter16
    IST_hunter17
    IST_hunter18
    IST_hunter19
    IST_hunter19a
    IST_hunter19b
    IST_hunter2
    IST_hunter20
    IST_hunter21
    IST_hunter22
    IST_hunter23
    IST_hunter23n
    IST_hunter24
    IST_hunter25
    IST_hunter26
    IST_hunter27
    IST_hunter28
    IST_hunter29
    IST_hunter2a
    IST_hunter3
    IST_hunter31
    IST_hunter32
    IST_hunter33
    IST_hunter34
    IST_hunter3a
    IST_hunter4
    IST_hunter5
    IST_hunter5b
    IST_hunter6
    IST_hunter6a
    IST_hunter7
    IST_hunter8
    IST_hunter9
    IST_lobster
    Priest of the Witchspace Lobster
    Acolyte of the Witchspace Lobster
    Acolyte of the Witchspace Lobster
    GalCop Viper (naval)
    IST_mil10
    IST_mil11
    IST_mil12
    IST_mil13
    IST_mil14
    IST_mil15
    IST_mil16
    IST_mil17
    IST_mil19
    Super-Sidewinder (Military version)
    IST_mil4
    IST_mil5b
    IST_mil6
    IST_mil7
    IST_mil7a
    IST_mil8
    IST_mil9
    IST_miner1
    IST_miner1b
    IST_miner2
    IST_miner3
    IST_miner4
    IST_miner5
    IST_miner6
    IST_miner6b
    IST_miner7
    IST_miner8
    IST_pirate1
    IST_pirate10
    IST_pirate11
    IST_pirate11a
    IST_pirate12
    IST_pirate13
    IST_pirate14
    IST_pirate15
    IST_pirate16
    IST_pirate17
    IST_pirate18
    IST_pirate19
    IST_pirate19a
    IST_pirate2
    IST_pirate20
    IST_pirate21
    IST_pirate22
    IST_pirate23
    IST_pirate23b
    IST_pirate24
    IST_pirate25
    IST_pirate26
    IST_pirate27
    IST_pirate28
    IST_pirate29
    IST_pirate2a
    IST_pirate3
    IST_pirate30
    IST_pirate30b
    IST_pirate31
    IST_pirate32
    IST_pirate33
    IST_pirate33a
    IST_pirate34
    IST_pirate35
    IST_pirate3a
    IST_pirate3b
    IST_pirate4
    IST_pirate5
    IST_pirate5b
    IST_pirate6
    IST_pirate6a
    IST_pirate7
    IST_pirate8
    IST_pirate9
    IST_pod1
    IST_pod2
    IST_pod3
    IST_pod4
    IST_thargoidDefenceShip
    IST_thargoidLurker
    Thargoid Battleship (rebel)
    IST_thargoidRebelTougherWarship
    Thargoid Warship (rebel)
    IST_thargoidSweeper
    IST_thargoidWarship
    IST_thargoidWarship-buggly
    IST_thargoidWarship-buggly2
    IST_thargoidWarship-buggly2b
    IST_thargoidWarship-bugglyB
    IST_thargoidWarship-frigate
    IST_thargoidWarship2
    TIE Fighter (naval)

    Models

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

    Scripts

    Path
    Scripts/IST_derelict.js
    /*
    ========================================================================
    IST_derelict.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    ========================================================================
    */
    
    
    this.name = "IST_derelict.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A script for InterstellarTweaks OXP";
    
    /*
    --------------------------------------------
    Start of wrapper for JSHINT 
    See also Jshint options above.
    The following should be: 'function(){' (sic)
    --------------------------------------------
    */
    (
    	function() {
    
    		"use strict";
    
    		/*
    		------------------
    		DEBUGGING SWITCHES
    		------------------
    		*/
    
    		// this.logging = true;
    		var consoleDebugMessages = false; // do NOT comment this out. Rather, to disable, set to false.
    
    
    		/*
    		--------------
    		EVENT HANDLERS
    		--------------
    		*/
    
    		this.shipSpawned = function() {
    			var r = Math.random();
    			if (this.ship.hasRole("IST_derelictthargoid")) {
    				r += 0.1;
    			}
    			if (r < 0.2) {
    				var fuel = Math.random() * 2.4; // this is in lightyears
    				if (r < 0.12) {
    					fuel *= (1 + r);
    				}
    				this.ship.fuel = fuel;
    			}
    			r = Math.random();
    			if (r < 0.9) {
    				// energy *recharge* inaccessible via script. (But can use a script for isTakingDamage, or - as in fact I've done - set the rate in shipdata.)
    				if (r < 0.5) {
    					this.ship.energy *= 0.2;
    				} else {
    					this.ship.energy *= r;
    				}
    			}
    			delete this.shipSpawned;
    		};
    
    		this.shipTakingDamage = function(amount) {
    			if (this.ship.energy > amount) {
    				return;
    			}
    			if (this.ship.AI === "IST_bombAI.plist") {
    				return;
    			}
    			if (Math.random() <= 0.015) // 0.015
    			{
    				this.ship.energy = 50; // ship is about to explode, keep it alive for a moment.
    				this.ship.switchAI("IST_bombAI.plist");
    				return;
    			}
    			if (this.ship.cargoSpaceCapacity > 0 && Math.random() < 0.15) // 0.15
    			{
    				this.ship.energy = 50; // ship is about to explode, keep it alive for a moment.
    				var numOfPodsToEject;
    				if (this.ship.cargoSpaceCapacity < 8) // this number relates to one below, marked '*'
    				{
    					numOfPodsToEject = Math.ceil(Math.random() * (this.ship.cargoSpaceCapacity / 4));
    				} else {
    					numOfPodsToEject = Math.ceil(Math.random() * (this.ship.cargoSpaceCapacity / 7));
    					if (numOfPodsToEject > 30) {
    						numOfPodsToEject -= 10;
    					} else if (numOfPodsToEject > 15) {
    						numOfPodsToEject -= (Math.ceil(Math.random() * 12));
    					} else if ((numOfPodsToEject > 7) && (Math.random() < 0.5)) {
    						numOfPodsToEject = Math.ceil(Math.random() * (numOfPodsToEject / 2));
    					}
    				}
    				this.ship.spawn("cargopod", numOfPodsToEject);
    				this.ship.explode(true);
    			}
    		};
    
    		/*
    		------------------------------
    		End of wrapper for JSHINT.
    		See also Jshint options above.
    		------------------------------
    		*/
    
    	}).call(this);
    
    // EOF
    
    Scripts/IST_genship.js
    /* jshint esversion: 6 */
    
    /*
    ---------------------------------
    HEADER
    ---------------------------------
    */
    
    
    this.name = "IST_genship.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A ship script for the Interstellar Tweaks OXP";
    
    /*
    ---------------------------------
    DEBUGGING SWITCHES
    ---------------------------------
    */
    
    this.logging = false;
    //	Corresponds to, or needs, settings in logcontrol.plist?
    
    this.debug = false;
    //	false
    
    var consoleDebugMessages = false;
    //	Do NOT comment this out. Rather, to disable, set to false.
    
    
    /*
    ---------------------------------
    SOUNDS
    ---------------------------------
    */
    
    var mysound_Warning = new SoundSource();
    mysound_Warning.sound = "warning.ogg";
    //	This sound built-in to Oolite - and does not need to be declared in the 'customsounds' file.
    
    /*
    ---------------------------------
    JSLINT: start of wrapper
    ---------------------------------
    */
    
    (function() {
    	"use strict";
    
    	/*
    	---------------------------------
    	DEBUGGING
    	---------------------------------
    	*/
    
    	this.$debugMessage = function(debugTxt) {
    		if (!this.debug) {
    			return;
    		} // NB. THIS ROUTINE DOES NOTHING IF this.debug IS NOT TRUE
    		// else
    		if (!debugTxt) {
    			player.consoleMessage("Problem with debug message text!", 30);
    			return;
    		}
    		player.consoleMessage("Interstellar Tweaks - " + debugTxt, 12);
    		log("InterstellarTweaks - debugging", debugTxt);
    	};
    
    
    	/*
    	---------------------------------
    	MISC
    	---------------------------------
    	*/
    
    	this.$isEligibleTarget = function(e) {
    		return !e.isCloaked && ((e.isPlayer && !e.docked) || (e.isShip && e.ispiloted && (!e.isThargoid || e.primaryRole === "thargoidRebel")));
    	};
    
    
    	/*
    	---------------------------------
    	ROUTINES CALLED BY AI
    	---------------------------------
    	*/
    
    	this.$_findNearTargets = function() {
    		var nearArray = system.filteredEntities(this, this.$isEligibleTarget, this.ship, 25600);
    		if (nearArray.length == 0) {
    			this.ship.reactToAIMessage("NOTHING_FOUND");
    			return;
    		}
    		// Else ..
    		this.targetNumber = ~~(Math.random() * nearArray.length); // NB: ~~ (a.k.a.) math.floor (as Vs .ceil) is correct
    		if (this.targetNumber > nearArray.length) {
    			log(this.name + " script error, target number too high - please report");
    			this.targetNumber = 0;
    		}
    		this.ship.target = nearArray[this.targetNumber];
    		this.ship.reactToAIMessage("TARGET_FOUND");
    		if (this.debug) {
    			this.$debugMessage("Near target");
    		}
    	};
    
    	this.$_findFarTargets = function() {
    		var farArray = system.filteredEntities(this, this.$isEligibleTarget, this.ship, 70000);
    		if (farArray.length == 0) {
    			this.ship.reactToAIMessage("NOTHING_FOUND");
    			// this.$debugMessage("NO far target");
    			return;
    		}
    		// Else ..
    		this.ship.target = farArray[0]; // set to the closest target off-scanner but in range
    		this.ship.reactToAIMessage("TARGET_FOUND");
    		if (this.debug) {
    			this.$debugMessage("Far target");
    		}
    	};
    
    	this.$_validateTarget = function() {
    		if (this.ship.target && this.ship.target.isValid && this.$isEligibleTarget(this.ship.target)) {
    			this.ship.reactToAIMessage("TARGET_VALID");
    		} else {
    			this.ship.reactToAIMessage("TARGET_INVALID");
    		}
    	};
    
    	this.$_curse = function() {
    		this.ship.commsMessage(expandDescription("[thargoid_curses]"), player.ship);
    	};
    
    
    	/*
    	---------------------------------
    	JSLINT: end of wrapper
    	---------------------------------
    	*/
    
    }).call(this);
    
    
    // EOF
    Scripts/IST_liveOneScript.js
    /*
    ========================================================================
    IST_liveOneScript.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    ========================================================================
    */
    
    /*
    ------------------------
    JSHINT: Options
    ------------------------
    */
    
    /*jshint esversion: 6*/
    /*jshint sub:true*/
    
    
    this.name = "IST_liveOneScript.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A ship script for the Interstellar Tweaks OXP";
    
    
    /*
    --------------
    DEBUG SWITCHES
    --------------
    */
    
    // this.logging = true;
    var consoleDebugMessages = false; // do NOT comment this out. Rather, to disable, set to false.
    
    
    
    /*
    ------------------------
    JSHINT: start of wrapper
    ------------------------
    */
    
    (function() {
    	"use strict";
    
    
    	/*
    	-------------------------------------------------------------
    	EVENT HANDLERS
    	// Don't need the 'this.shipSpawned' from the 'dead derelict',
    	because all live derelicts start off dead.
    	--------------------------------------------------------------
    	*/
    
    	this.shipTakingDamage = function(amount, whom, type) {
    		if (this.isInFactDead || this.ship.podded) {
    			return;
    		}
    		if (this.ship.energy < 20) {
    			if (Math.random() < 0.8) {
    				this.$_pod();
    			}
    			return;
    		}
    		// Else ..
    		if (Math.random() < 0.25) {
    			this.$_pod();
    		}
    		// Don't need anything re cargo here, 'cos when the pod jettisoned the new script takes care of that (but have the podded check above just in case).
    		// EDIT: 'this.isInFactDead' messes with this a bit. Hey ho.
    	};
    
    	this.shipDied = this.entityDestroyed = this.playerWillEnterWitchspace = function() {
    		if (this.SOS_Timer) {
    			if (this.SOS_Timer.isRunning) {
    				this.SOS_Timer.stop();
    			}
    			delete this.SOS_Timer;
    		}
    	};
    
    	this.shipAttackedWithMissile = function() {
    		if (this.isInFactDead || this.ship.podded) {
    			return;
    		}
    		if (Math.random() < 0.9) {
    			this.$_pod();
    		}
    	};
    
    
    	/*
    	---------------------
    	ROUTINES CALLED BY AI
    	---------------------
    	*/
    
    	this.$_setFuelAndConsiderRegularSOS = function() {
    		this.isInFactDead = false;
    		if (this.ship.fuel > 0) {
    			var r = Math.random();
    			if ((this.ship.fuel > 3) || (r < 0.9)) {
    				this.ship.fuel = r; // can't do this on a shipSpawned, 'cos this ship doesn't get one of those. Fuel set before this by dead_derelict script.
    			}
    		}
    		if (Math.random() < 0.6) {
    			var t = 1 + Math.ceil(Math.random() * 8);
    			this.SOS_Timer = new Timer(this, this.$SOS, t);
    			// Following is to simulate dead ships that nonetheless broadcast SOS.
    			if (Math.random() < 0.1) {
    				this.isInFactDead = true;
    			}
    		}
    	};
    
    	this.$_pod = function() {
    		if (!this.ship || !this.ship.position || !player.ship || this.ship.podded || this.isInFactDead) {
    			return;
    		}
    		if (this.SOS_Timer && Math.random < 0.3) {
    			if (this.SOS_Timer.isRunning) {
    				this.SOS_Timer.stop();
    			}
    			delete this.SOS_Timer; // Timer likely to have been stopped before now, anyway.
    		}
    		this.ship.podded = true;
    		if (Math.random() > 0.04) {
    			var pod = this.ship.spawnOne("IST_pod");
    			this.ship.switchAI("nullAI.plist");
    			this.ship.setScript("IST_derelict.js");
    		} else {
    			if (this.SOS_Timer) {
    				if (this.SOS_Timer.isRunning) {
    					this.SOS_Timer.stop();
    				}
    				delete this.SOS_Timer;
    			}
    			if (Math.random() > 0.15) {
    				this.ship.commsMessage("Oh dear . . ");
    			}
    			this.ship.switchAI("nullAI.plist");
    			this.ship.explode();
    		}
    	};
    
    	this.$_plea = function() {
    		if (this.isInFactDead || this.ship.podded || !this.ship || !this.ship.position || !player.ship) {
    			return;
    		}
    		var messagePicker = Math.ceil(Math.random() * 35);
    		var txt;
    		if (this.SOS_Timer && Math.random < 0.8) {
    			if (this.SOS_Timer.isRunning) {
    				this.SOS_Timer.stop();
    			}
    			delete this.SOS_Timer;
    		}
    		switch (messagePicker) {
    			case 1:
    				txt = "Please pick up my capsule! I am completely stranded!";
    				break;
    			case 2:
    				txt = "Help me out, please!";
    				break;
    			case 3:
    				txt = "I am stuck out here!";
    				break;
    			case 4:
    				txt = "Take me back to normal space! I will pay you!";
    				break;
    			case 6:
    				txt = "Pick me up! I'll pay!";
    				break;
    			case 7:
    				txt = "Pick me up, and I will make you rich!";
    				break;
    			case 8:
    				txt = "My ship is broken!";
    				break;
    			case 9:
    				txt = "My ship is completely broken!";
    				break;
    			case 10:
    				txt = "Help! Broken ship!";
    				break;
    			case 11:
    				txt = "Help! No engines!";
    				break;
    			case 12:
    				txt = "Pick up my escape pod! Please!";
    				break;
    			case 13:
    				txt = "Help at last! Amazing! Please scoop me (carefully!).";
    				break;
    			case 14:
    				txt = "Any chance of a lift?";
    				break;
    			case 15:
    				txt = "Help!";
    				break;
    			case 16:
    				txt = "Please help!";
    				break;
    			case 17:
    				txt = "Help!";
    				break;
    			case 18:
    				txt = "Help!";
    				break;
    			case 19:
    				txt = "Help!";
    				break;
    			case 20:
    				txt = "I need help!";
    				break;
    			case 21:
    				txt = "Please pick up my capsule!";
    				break;
    			case 22:
    				txt = "<Static>";
    				break;
    			default:
    				txt = "S O S";
    				break;
    		}
    		this.ship.commsMessage(txt);
    		// always followed by 'podding'.
    	};
    
    
    	/*
    	---------------
    	OTHER FUNCTIONS
    	---------------
    	*/
    
    	this.$SOS = function $SOS() {
    		if (!this.ship) {
    			return;
    		}
    		if (!this.ship.position) {
    			return;
    		}
    		this.ship.commsMessage("S O S"); // this.ship.broadcastDistressMessage() is (1) only available in += 1.79, (2) perhaps applicable only to combat.
    	};
    
    
    
    	/*
    	---------------------------------
    	JSHINT: end of wrapper
    	---------------------------------
    	*/
    
    }).call(this);
    
    
    // EOF
    Scripts/IST_lobster.js
    /*
    ========================================================================
    IST_lobster.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    ========================================================================
    */
    
    
    /* jshint esversion: 6 */
    
    this.name = "IST_lobster.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A script for InterstellarTweaks OXP";
    
    
    /*
    ------------------
    DEBUGGING SWITCHES
    ------------------
    */
    
    // this.logging = true;
    var consoleDebugMessages = false; // do NOT comment this out. Rather, to disable, set to false.
    
    
    /*
    ---------------------------------
    JSHINT: start of wrapper
    ---------------------------------
    */
    
    (function() {
    	"use strict";
    
    
    	/*
    	--------
    	FUNCTION
    	--------s
    	*/
    
    	this.shipAttackedWithMissile = function() {
    		// This routine called by built-in handler
    		var shipWithECM_localVariable = this.$shipWithECM;
    		// log("InterstellarTweaks - debugging", "trying to ecm - 1");
    		if (shipWithECM_localVariable && shipWithECM_localVariable.isValid) {
    			// log("InterstellarTweaks - debugging", "trying to ecm - 2");
    			shipWithECM_localVariable.fireECM();
    			return;
    		}
    		// Else ..
    		this.ship.reactToAIMessage("ECM_UNAVAILABLE");
    		// log("InterstellarTweaks - debugging", "no ecm");
    	};
    
    
    	/*
    	----------------------
    	JSHINT: end of wrapper
    	----------------------
    	*/
    
    }).call(this);
    
    
    // EOF
    Scripts/IST_masterScript.js
    /*
    ===================================================================================================================
    
    IST_masterScript.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    
    _____   __________________  ___________________    __    ___    ____     ______         _________    __ _______
    /  _/ | / /_  __/ ____/ __ \/ ___/_  __/ ____/ /   / /   /   |  / __ \   /_  __/      __/ ____/   |  / //_/ ___/
    / //  |/ / / / / __/ / /_/ /\__ \ / / / __/ / /   / /   / /| | / /_/ /    / / | | /| / / __/ / /| | / ,<  \__ \
    _/ // /|  / / / / /___/ _, _/___/ // / / /___/ /___/ /___/ ___ |/ _, _/    / /  | |/ |/ / /___/ ___ |/ /| |___/ /
    /___/_/ |_/ /_/ /_____/_/ |_|/____//_/ /_____/_____/_____/_/  |_/_/ |_|    /_/   |__/|__/_____/_/  |_/_/ |_/____/
    
    For Oolite >= 1.82.
    
    ===================================================================================================================
    */
    
    
    /*
    ====================
    JSLINT: set options
    ====================
    */
    
    /*jshint esversion: 6*/
    /*jshint sub:true*/
    
    
    this.name = "IST_masterScript";
    this.author = "UK_Eliter";
    this.copyright = "2017-2022 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "Interstellar Tweaks";
    
    
    /*
    ================
    C O N T E N T S
    ================
    
    1	NOTES
    
    2	DEBUGGING: set switches
    
    3	SOUNDS
    
    4	CONSTANTS
    
    5	DEBUGGING: apply switches
    
    5	GLOBAL VARIABLES
    
    6	OVERVIEW OF THE MAIN ROUTINES
    
    7	EVENT HANDLERS (including startup and populator routines)
    	[At present this section seques into most of the code's other routines]
    
    8	WRAPPER FOR JSLINT, start
    
    9	OPTIMISATION ROUTINES
    
    10	ENTITY-PICKERS (/filters)
    
    11	MISC ROUTINES
    
    12	ERROR & MESSAGE HANDLING
    
    13	WRAPPER FOR JSLINT, end [the wrapper *begins*, perforce, above this table of contents]
    
    
    =============
    1.	N O T E S
    =============
    
    MUST END FUNCTION CALLS WITH '()' (or arguments)
    else ROUTINE DOES NOT RUN (but gives no error!)
    
    Functions that are run (immediately) by timers should have names
    of the following format, else the Oolite log won't give the function name:
    
    this.$<function name> = function $<function name>()
    
    E.g.:
    
    this.$die_timed = function $die()
    
    NB: ONE GETS ERRORS THAT ARE HARD TO TRACK, AND FLAGGED BY LINTER AT END OF SCRIPT, IF MISMATCH THOSE FUNCTION NAMES.
    	SAME GOES FOR IF HAVE *TWO* '{'s at start of function. So, as in Linux kernel convention, don't do that.
    
    Also, if use the Oolite 'profiler', need to name ALL functions
    like that, on pain of them showing as 'anonymous' in the profiler.
    
    The scrambledPseudoRandomNumber seeds in this OXP start at: 700000.
    
    Some faster equivalents of mathematical operations
    --------------------------------------------------
    
    Math.abs(x):	x >= 0 ? x : -x
    Math.max(x,y):	x > y ? x : y
    Math.min(x,y):	x<y ? x : y
    Math.floor(x):	~~x
    Math.round(x):	~~(x+0.5)
    Math.ceil(x):	~~(x+1)
    
    While loops of the 'while (i--)' form are faster than 'for' loops. On how those 'while' loops work, see:
    https://stackoverflow.com/questions/22181713/what-does-whilei-mean-in-javascript
    
    
    /*
    ====================
    2. D E B U G G I N G
    ====================
    */
    
    this.debug_full = false;
    //	false.
    //	See below for effects.
    //	If set to true, then, later, the script changes this.debug to true.
    
    this.debug = false;
    //	false
    
    // The only way to easily test the various interstellar scenarios - given how my code is - is to set the probability for them to 1, and to stop other stuff firing first. We set those probabilities in section 4. See also section 5.
    
    
    /*
    ==============
    3. S O U N D S
    ==============
    */
    
    // The following two sounds are built into Oolite.
    // So they the 'customsounds' file need not declare them.
    
    this.mySound_warning = new SoundSource();
    this.mySound_warning.sound = "warning.ogg";
    
    this.mySound_hullBang = new SoundSource();
    this.mySound_hullBang.sound = "hullbang.ogg";
    
    
    /*
    ====================
    4. C O N S T A N T S
    ====================
    */
    
    /*
    --------------
    SICKNESS stuff
    --------------
    */
    
    this.sickness_baseChanceOfGetting = 0;
    //	0
    //	Gets increased by jumps within witchspace.
    
    this.sickness_chanceKills = 0.39;
    //	0.39
    //	Can be slightly modified by player rank.
    
    /*
    ---------------------
    ESCAPE SEQUENCE stuff
    ---------------------
    */
    
    this.escapeSequence_baseBugsGetPodChance = 0.08;
    //	0.08
    //	Gets changed by circumstances. May get error if set below 0.
    //	There is a chance that the game itself will destroy the pod.
    //	The main cause of death here is simply not being picked up.
    
    this.escapeSequence_baseRescue_chance = 0.85;
    //	0.85
    //	Gets affected by various things, and is used, sometimes modified,
    //	to determine various chances of rescue.
    //	And there does need to be a ship to pick you up.
    //  See also, below: this.stellar_postRescueAmbush_chance
    
    /*
    ------------------
    SCENARIO - general
    ------------------
    */
    
    this.scenario_chanceMajorTweak = 0.49;
    //	0.49
    //	Chance script alters a misjump in any substantial way.
    //	Altered by presence of some particular OXPs.
    //	NB: 'this.debug_full = true' makes this 1.
    
    this.scenario_chanceModifiedAsVsNew = 0.51;
    //	0.51
    //	Chance of 'modified' as versus 'new' scenario.
    //	There are OXPs thi detection of which will alter the chance.
    
    this.scenario_chanceScriptInducedMisjump = 0.03;
    //	0.03
    //	Gets drastically lowered if the Misjump Analyzer is installed.
    
    this.scenario_interstellarPostWillExitTimed = 0.75;
    //	0.75
    //	= Delay after shipWillExitWitchspace for $willExit_interstellar_timed routine.
    //	Timed. For, if move player (= when this value is too low) too
    //	quickly can (1) lose player's witchspace rings, (2) crash Oolite,
    //	(3) create screen flash. & this value *VERY* sensitive.
    //	0.86 seems to crash. 0.75 works.
    
    this.scenario_delayBeforeReturnShipToGroundZero = 0.75;
    //	0.75.
    //	Delay after shipExitedWitchspace for my $postJump_timed routine.
    //	If set too low, get rings - but, if set much higher, can get crashes.
    
    this.scenario_genShipsRemovalChance = 0.76;
    //	0.76
    
    
    /*
    ------------------
    SCENARIO - default
    ------------------
    */
    
    this.scenario_default_chanceAsteroids = 0.035;
    //	0.035
    
    this.scenario_default_chanceExtraSeperateClash = 0.15;
    //	0.15
    
    /*
    -------------------
    SCENARIO - modified
    -------------------
    */
    
    this.scenario_modified_limitBattleships_chance = 0.87;
    //	0.87
    //	Only necessary, & only used, if the Thargorn Threat OXP is installed.
    
    this.scenario_modified_limitBattleships_maxShips = 3;
    //	3
    
    this.scenario_modified_wasBattle_chance = 0.28;
    //	0.28
    //	= chance that, on onlyBugs | onlyNavy, get wreckage too & fewer ships.
    //	Value is set slightly higher than would otherwise be.
    //	That is for this reason:
    //	if we have only a few navy, battle stuff (incl. wreckage) is ignored.
    
    this.scenario_modified_wasBattle_wreckageOnly_chance = 0.15;
    //	0.15
    
    this.scenario_modified_onlyBugs_addSweeperChance = 0.41;
    //	0.41
    //	Needs ExtraThargoids OXP (which might generate sweepers anyway).
    //	WasBattle can remove and damage sweepers.
    
    this.scenario_modified_onlyBugs_multiplyBugsChance = 0.07;
    //	0.07
    
    this.scenario_modified_onlyBugs_aliensChance = 0.1;
    //	0.1
    
    this.scenario_modified_onlyBugs_rebelChance = 0.09;
    //	0.09
    //	Exclusive with scenario_modified_onlyBugs_aliensChance.
    //	Gets increased in galaxy 2.
    //	NB: The 'new scenario' too allows internicine strife.
    
    this.scenario_modified_onlyBugs_3GChance = 0.11;
    //	0.11
    //	Various things modify this.
    
    this.scenario_modified_onlyBugs_thargGenship_chance = 0.02;
    //	0.02
    //	Gets inflected by player rank.
    //	The Thargoid GenShip can occur also in the NEW scenario.
    
    this.scenario_modified_chanceOffsetFromAction = 0.09;
    //	0.09
    
    this.scenario_modified_chanceNavyAsVBugs = 0.57;
    //	0.57
    //	Determines chance of 'OnlyBugs'.
    //	Includes possibility of just adding *extra* navy. Rank-inflected.
    
    this.scenario_modified_chanceOnlyNavyNotExtraNavy = 0.65;
    //	0.65
    
    this.scenario_modified_onlyNavy_replaceNavyChance = 0.65;
    //	0.65
    //	This is one method I use to stop the navy jumping out immediately.
    /*
    --------------
    SCENARIO - new
    ---------------
    */
    
    this.scenario_new_forceInitiallyEmpty_chance = 0.17;
    //	0.17
    
    this.scenario_new_radiation_chance = 0.082;
    //	0.082
    //	Gets increased in two of the galaxies.
    //	'Returns' afterwards.
    //	Thus, decreases chance of the scenarios that follows it.
    
    this.scenario_new_asteroids_chance = 0.00;
    //	0.09
    //	Chance increased in one of the galaxies.
    //	Asteroids are occasionally a long way from the player. 
    
    this.scenario_new_asteroids_chanceMiners = 0.18;
    //	0.18
    
    this.scenario_new_derelict_chance = 0.15;
    //	0.15
    //	Any derlict can be fairly far from the player.
    
    this.scenario_new_derelict_range = 24600;
    //	24600
    //	Derelicts get added within 4000 of this.
    
    this.scenario_new_derelict_chanceIsLive = 0.15;
    //	0.15
    
    this.scenario_new_derelict_dead_chanceMultiple = 0.2;
    //	0.2
    
    this.scenario_new_pirates_baseChance = 0.01;
    //	0.01
    //	Chance is increased by: criminality of the relevant systems; rank.
    //	Intra-interstellar jumps (*sic*) scale the chance back down.
    
    this.scenario_new_pirates_baseNumber = 3;
    //	3
    //	This is only part of the equation for the number of pirates.
    
    this.scenario_new_helpee_chance = 0.16;
    //	0.16
    //	Requires InterstellarHelp OXP.
    
    this.scenario_new_aliens_chance = 0.09;
    //	0.09
    //	Get increased in galaxy 8 (/7).
    
    this.scenario_new_lobster_chance = 0.06;
    //	0.06. Increased in galaxy 4 (/3).
    
    this.scenario_new_warships_chance = 0.45;
    //	0.45
    //	Get modified, in effect, by other things.
    //	One such thing is the detection of the Thargoid Jammers OXP.
    
    this.scenario_new_warships_baseNumber = 2;
    //	2
    
    this.scenario_new_sweeperChance = 0.1;
    //	0.1
    //	Requires ExtraThargoids OXP. Rank-inflected.
    //	There is a chance that a pre-existing Thargoid will be a sweeper.
    
    this.scenario_new_hunter_chance = 0.1;
    //	0.1
    //	Comes halfway down the chain. But can be added via miners, too.
    
    this.scenario_new_thargGenship_chance = 0.02;
    //	0.02
    //	Inflected later by player rank.
    //	Ultimate position in chain for new scenario.
    //	Cf. this.scenario_modified_onlyBugs_thargGenship_chance.
    
    /*
    -------------
    REPOPULATION
    ------------
    */
    
    //	Default scenario
    this.repopulate_chanceEver_default = 0.75;
    //	0.75
    this.repopulate_maxPossible_default = 100;
    //	100
    this.repopulate_chance_default = 0.8;
    //	0.8
    
    //	Modified scenario - Only navy
    this.repopulate_chanceEver_onlyNavy = 0.3;
    //	0.3
    this.repopulate_maxPossible_onlyNavy = 60;
    //	60
    this.repopulate_chance_onlyNavy = 0.2;
    //	0.2
    
    //	Modified scenario - Only bugs
    this.repopulate_chanceEver_onlyBugs = 0.5;
    //	0.5
    this.repopulate_maxPossible_onlyBugs = 40;
    //	40
    this.repopulate_chance_onlyBugs = 0.15;
    //	0.15
    
    //	New scenario
    this.repopulate_chanceEver_newScenario = 0.6;
    //	0.6
    this.repopulate_maxPossible_newScenario = 70;
    //	70
    this.repopulate_chance_newScenario = 0.1;
    //	0.1
    
    
    /*
    -------------------------------------------------
    STELLAR (as Vs rest, which is interstellar) stuff
    -------------------------------------------------
    */
    
    this.stellar_misplace_chance = 0.025;
    //	0.025
    //	= chance of being misplaced within the target system.
    //	Various things can increase this chance.
    
    this.stellar_misplace_delay = 0.83;
    //	0.83
    //	Fires at this time after ShipExitedWitchspace.
    
    this.stellar_misplace_nearSun_chance = 0.16;
    //	0.16
    //	Can kill immediately.
    
    this.stellar_postRescueAmbush_chance = 0.11;
    //	0.11
    //	Gets inflected by rank.
    //	Applies only to when rescued in interstellar space
    //	(and only to 'arriving' carriers).
    
    
    /*
    =======================================
    5. D E B U G G I N G - Apply switches
    =======================================
    */
    
    if (this.debug_full) {
    	this.debug = true;
    
    	// NB: DO NOT CHANGE VALUES OF THE FOLLOWING LINES. Rather, comment out if do not want them.
    	this.ignorePlayerRank = false;
    	this.testWithMisjumps = true;
    	// this.scenario_new_forceInitiallyEmpty_chance = 0;
    	this.scenario_chanceMajorTweak = 1;
    	// Does not foreclose scenario_default_chanceExtraSeperateClash; can be overridden by pseudorandom numbers. 
    } else {
    	// DEFAULT values are as in my comments.
    	this.ignorePlayerRank = false;
    	// false
    	this.testWithMisjumps = false;
    	// false
    }
    
    if (this.testWithMisjumps) {
    	log("InterstellarTweaks", "Testing with misjumps enabled.");
    	this.scenario_chanceScriptInducedMisjump = 1;
    }
    
    
    /*
    ==================================
    6. G L O B A L   V A R I A B L E S
    ==================================
    */
    
    this.beforeExitIsRunning = false;
    
    this.currentChanceOfSickness = this.sickness_baseChanceOfGetting;
    //	Gets raised by jumps into interstellar space.
    
    this.initialisedAtFirstLaunch = false;
    
    this.isSick = false;
    
    this.jumpIsGalactic = false;
    
    this.launch_thargAmbush = false;
    //	Can be set to 'true' by some event(s) treated elsewhere in the script.
    
    this.MASC_status = 0;
    
    /*
    The following two vectors do not get set here (so doing throws a runtime error - unless I did it wrongly).
    Instead they get initialised when first used.
    this.origin_ambush = new Vector3D(ps);
    this.origin_newScenario = new Vector3D(ps);
    */
    this.spoofStatus = 0;
    
    this.willDie = false;
    
    
    /*
    =============================================================
    7.	O V E R V I E W   O F   T H E   M A I N   R O U T I N E S
    Ordered by event, in time order.
    =============================================================
    
    (1) this.shipWillLaunchFromStation [Oolite event handler]
    
    On, only, the *first* run of this routine, my code does various things including making array of any OXP worldscripts that contain populator scripts and an array of any that contain repopulator scripts.
    
    (2) this.playerWillEnterWitchspace [Oolite event handler]
    
    If in INTERSTELLAR space, then decide the following, to be acted upon on later:
    	Will we tweak the jump?
    		If yes, will we do the 'new' scenario (which involves removing all ships and moving to a new area of space) or the 'modified' one (which involves staying where we are but fiddling). Each scenario has various versions.
    
    (3) this.iinterstellarTweaks_repopulate_interstellar_custom [Setup via planetinfo.plist. Runs immediately before this.shipWillExitWitchspace.]
    
    If doing tweak of the 'modified' type - or indeed doing no tweak at all - then run all worldscipts and inbuilt populators that would normally run. Or rather do so under certain conditions . .
    If doing tweak of the 'new type', run none of the above populators.
    NB: My code does no population, strictly defined, i.e. does not use 'system.setPopulator'. That is because it seems feasible (at least while few expansion packs use that method) only to remove various ships - and, after that, add ships - *later* on.
    
    (4) this.shipWillExitWitchspace [Oolite event handler]
    
    If in NORMAL space, then - sometimes - do various things . .
    If in INTERSTELLAR space, start a timer ('this.timer_interstellarPostWillExit') to run routine 'this.$willExit_interstellar_timed'.
    	(I have this on a timer because one thing that the routine does is to move the player and moving the player immediately crashes Oolite - or at least Oolite<1.79.)
    
    (5) this.$willExit_interstellar_timed [my timed routine]
    
    If in INTERSTELLAR space, actually start to implement the various tweaks.
    In case of all (major or major-ish) tweaks except extraNavy, this involves clearing (or parially clearing) space, moving the player - *temporarily* in all cases except for what the program call the 'new' scenario - and populating it.
    
    (6) this.shipExitedWitchspace [Oolite event handler]
    
    If doing any modification except extraNavy, set a timer (this.timer_returnEtc) which will run a routine (this.postJump_timed) described below.
    (Have this on timer in order to (1) have something closer to the final word on population, (2) keep player away from changes until they are finished.)
    
    (7) this.postJump_timed [my timed routine]
    
    Does any final removal of ships, and - except for when doing the newScenario, returns the player.
    
    There is also
    
    (8) this.interstellarTweaks_repopulate_interstellar_custom [Setup via planetinfo.plist. Runs every 20 seconds in interstellar space.]
    
    This sometimes adds various ships directly, and sometimes runs both Oolite's inbuilt interstellar repopulator and OXP interstellar repopulators.
    */
    
    
    /*
    ================================================
    8.	Start of wrapper for JSHINT 
    See also Jshint options above.
    The following should be: 'function(){' (sic)
    ================================================
    */
    // prettier-ignore
    (
    function() {
    
    "use strict";
    
    
    /*
    ============================================================
    9.	OPTIMISATION ROUTINES
    	See http://www.aegidian.org/bb/viewtopic.php?f=4&t=18837
    ============================================================
    */
    
    this._index_in_list = function(item, list) {
    	var k = list.length;
    	while (k--) {
    		if (list[k] === item) return k;
    	}
    	return -1;
    };
    
    /* Thus e.g.
    
    	if(targets.indexOf(ship))
    
    becomes (even within this very script)
    
    	var ws = worldScripts.IST_masterScript;
    	if(ws._index_in_list(ship,targets)
    	
    */
    
    
    /*
    =========================================================================================
    8.	E V E N T   H A N D L E R S   (including startup and population routines)
    	At present this section seques into most of the code's other routines.
     	NB: As per wise convention, all routines save inbuilt event handlers prefixed by '$'.
    =========================================================================================
    */
    
    this.startUp = function() {
    	var haveExcludedOwnScript = false;
    	var i = worldScriptNames.length;
    	var OXPworldScripts = [];
    	var scriptName;
    	var ws;
    	// 1st create array of all worldScripts
    	while (i--) {
    		if (!haveExcludedOwnScript && worldScriptNames[i] == this.name) {
    			haveExcludedOwnScript = true;
    		} else {
    			scriptName = worldScriptNames[i];
    			ws = worldScripts.IST_masterScript;
    			if (ws._index_in_list("oolite-", scriptName) !== 0) {
    				OXPworldScripts.push(scriptName);
    				// this.$debugMessage("ScriptName: "+scriptName);
    			}
    		}
    	}
    
    	// Now define various variables according to whether various OXPS installed
    	// (In the case of most but not all of those OXPs, we do so via the array of worldscripts just created).
    	if (this.$isArrayed("aliens_world_script", OXPworldScripts)) {
    		this.OXP_aliens = true;
    	} else {
    		this.OXP_aliens = false;
    	}
    
    	if (this.$isArrayed("behemoth", OXPworldScripts)) {
    		this.OXP_behemoth = true;
    	} else {
    		this.OXP_behemoth = false;
    	}
    
    	if (this.$isArrayed("Breakable_WitchDrive", OXPworldScripts)) {
    		this.breakableDrive = true;
    	} else {
    		this.breakableDrive = false;
    	}
    
    	if (this.$isArrayed("escapePodLocator.js", OXPworldScripts)) {
    		worldScripts["escapePodLocator.js"].ecl_interstellarSpaceRange = 15;
    		worldScripts["escapePodLocator.js"].ecl_normalSpaceRange = 20;
    	}
    
    	if (this.$isArrayed("extraThargoids_populator", OXPworldScripts)) {
    		this.OXP_extraThargoids = true;
    	} else {
    		this.OXP_extraThargoids = false;
    	}
    
    	if (this.$isArrayed("ferdelance3_populator", OXPworldScripts)) {
    		this.OXP_3G = true;
    	} else {
    		this.OXP_3G = false;
    	}
    
    	if (this.$isArrayed("Galactic Misjump", OXPworldScripts)) {
    		this.OXP_misJump = true;
    	} else {
    		this.OXP_misJump = false;
    	}
    
    	if (this.$isArrayed("hiredGuns_system", OXPworldScripts)) {
    		this.OXP_hiredGuns = true;
    	} else {
    		this.OXP_hiredGuns = false;
    	}
    
    	if (this.$isArrayed("military_fiasco", OXPworldScripts)) {
    		this.OXP_fiasco = true;
    	} else {
    		this.OXP_fiasco = false;
    	}
    
    	if (this.$isArrayed("Missiles & Bombs", OXPworldScripts)) {
    		this.OXP_bombs = true;
    	} else {
    		this.OXP_bombs = false;
    	}
    
    	if (this.$isArrayed("Mauiby's Wormhole Drones", OXPworldScripts)) {
    		this.OXP_wormDrones = true;
    	} else {
    		this.OXP_wormDrones = false;
    	}
    
    	if (this.$isArrayed("Fuel Collector", OXPworldScripts)) {
    		this.hackFuelCollectorOnInitialiseAtFirstLaunch = true;
    	} else {
    		this.hackFuelCollectorOnInitialiseAtFirstLaunch = false;
    	}
    
    	if (this.$isArrayed("misjump_analyser", OXPworldScripts)) {
    		this.OXP_misjumpAnalyzer = true;
    		if (!this.testWithMisjumps) {
    			this.scenario_chanceScriptInducedMisjump *= 0.2;
    		}
    	} else {
    		this.OXP_misjumpAnalyzer = false;
    	}
    
    	if (this.$isArrayed("murphy-thargoid-drive.js", OXPworldScripts)) {
    		this.OXP_TWD = true;
    	} else {
    		this.OXP_TWD = false;
    	}
    
    	if (EquipmentInfo.infoForKey("EQ_NEXUS_BUG_MISSILE")) {
    		this.OXP_Nexus = true;
    	} else {
    		this.OXP_Nexus = false;
    	}
    
    	if (this.$isArrayed("TCAT_masterScript", OXPworldScripts)) {
    		this.OXP_TCAT = true;
    	} else {
    		this.OXP_TCAT = false;
    	}
    
    	if (this.$isArrayed("Thargorn_Witchspace_Battle", OXPworldScripts)) {
    		this.OXP_ThargoidThreat = true;
    	} else {
    		this.OXP_ThargoidThreat = false;
    	}
    
    	if (this.$isArrayed("Generation Ships", OXPworldScripts)) {
    		this.OXP_GenShips = true;
    	} else {
    		this.OXP_GenShips = false;
    	} // This works for all versions of this OXP.
    
    	if (this.$isArrayed("stardestroyer", OXPworldScripts)) {
    		this.OXP_StarDestroyer = true;
    	} else {
    		this.OXP_StarDestroyer = false;
    	}
    
    	// Now check for some OXPS that don't have worldscripts; do so via roles.
    	if (this.$roleExists("interstellar_help_trader")) {
    		this.OXP_InterstellarHelp = true;
    	} else {
    		this.OXP_InterstellarHelp = false;
    	}
    
    	if (this.$roleExists("asteroid-billboard")) {
    		this.OXP_YAH = true;
    	} else {
    		this.OXP_YAH = false;
    	}
    
    	if (this.$roleExists("lobsterworshipper")) {
    		this.OXP_Missionaries = true;
    	} else {
    		this.OXP_Missionaries = false;
    	}
    
    	if (this.$roleExists("secondWave_toughTharglet")) {
    		this.OXP_SecondWave = true;
    	} else {
    		this.OXP_SecondWave = false;
    	}
    
    	if (this.$roleExists("spectre")) {
    		this.OXP_Spectre = true;
    		this.scenario_chanceMajorTweak += 0.05;
    		this.scenario_chanceModifiedAsVsNew -= 0.05;
    	} else {
    		this.OXP_Spectre = false;
    		this.scenario_default_chanceExtraSeperateClash += 0.05;
    	}
    
    	if (this.$roleExists("thargoid_carrier")) {
    		this.OXP_ThargoidCarriers = true;
    	} else {
    		this.OXP_ThargoidCarriers = false;
    	}
    
    	// ADJUST SOME (further) PROBABILITIES
    	if (!this.OXP_ThargoidCarriers && !this.OXP_ThargoidThreat) {
    		// If thargoid threat low-ish, increase threat in New. But if threat almost non-existent, then - cos that's way player wants it - reduce threat in New.
    		if (!this.OXP_Spectre || !this.OXP_SecondWave) {
    			this.scenario_new_warships_chance += 0.03;
    			this.scenario_new_warships_baseNumber += 1;
    		} else {
    			this.scenario_new_warships_chance -= 0.05;
    			if (this.scenario_new_warships_baseNumber > 1) {
    				this.scenario_new_warships_baseNumber -= 1;
    			}
    		}
    		scenario_modified_wasBattle_chance -= 0.05;
    	}
    
    	var populatorScripts_interstellar = [];
    	var repopulatorScripts_interstellar = [];
    
    	i = OXPworldScripts.length;
    	while (i--) {
    		scriptName = OXPworldScripts[i];
    		// this.$debugMessage("ScriptName: "+scriptName);
    		if (worldScripts[scriptName]) {
    			if (worldScripts[scriptName].interstellarSpaceWillPopulate && worldScripts[scriptName].interstellarSpaceWillPopulate !== undefined) {
    				populatorScripts_interstellar.push(scriptName);
    			}
    			// repopulators
    			if (worldScripts[scriptName].interstellarSpaceWillRepopulate && worldScripts[scriptName].interstellarSpaceWillRepopulate !== undefined) {
    				repopulatorScripts_interstellar.push(scriptName);
    			}
    		}
    		// Now make the local arrays global.
    		this.populatorScripts_interstellar = populatorScripts_interstellar.slice(0);
    		this.repopulatorScripts_interstellar = repopulatorScripts_interstellar.slice(0);
    	}
    
    	/*
    
    	// this.$debugMessage("Custom WS POPULATORS:");
    	i = this.populatorScripts_interstellar.length;
    	while (i--) {
    		this.$debugMessage("-- "+this.populatorScripts_interstellar[i]);
    	}
    	this.$debugMessage("Custom WS RE-POPULATORS:");
    	i = this.repopulatorScripts_interstellar.length;
    	while (i--) {
    		this.$debugMessage("-- "+this.repopulatorScripts_interstellar[i]);
    	}
    
    	*/
    
    	// MISC
    	if (this.debug_full) {
    		this.$debugMessage("Full test mode.");
    		if (this.doTestScenario) {
    			this.$debugMessage("- Test scenario.");
    		}
    	} else {
    		this.$debugMessage("Debugging.");
    	}
    };
    
    this.$probabilities_adjustbyPlayerRank = function() {
    	// NOTE: This runs AFTER the startUp routine
    	/*
    	harmless 		= 0,
    	mostlyHarmless	= 8,
    	poor			= 16,
    	average			= 32,
    	aboveAverage	= 64,
    	competent		= 128,
    	dangerous		= 512,
    	deadly			= 2560,
    	elite			= 6400,
    	archangel		= 19200;
    	*/
    
    	// Note also that chance of bugs in New Scenario is slightly reduced in galaxy 1/0.
    
    	var score = player.score; // an optimisation
    
    	// BELOW DEADLY
    	if (score < 2560) {
    		return;
    	}
    
    	// DEADLY
    	if (score < 6400) {
    		this.scenario_modified_onlyBugs_multiplyBugsChance *= 1.1;
    		this.scenario_new_sweeperChance *= 1.05;
    		this.scenario_new_warships_chance *= 1.05;
    		return; // NB: return
    	}
    	// ELITE
    	if (score < 19200) {
    		this.scenario_new_warships_baseNumber += 1;
    		this.scenario_new_pirates_baseNumber += 1;
    		this.scenario_new_derelict_chance *= 1.1;
    		this.scenario_modified_chanceNavyAsVBugs *= 0.96;
    		this.scenario_new_pirates_baseChance *= 1.1;
    		this.scenario_new_radiation_chance *= 1.2;
    		this.sickness_chanceKills *= 1.12;
    		this.scenario_new_sweeperChance *= 1.1;
    		this.scenario_new_thargGenship_chance *= 1.35;
    		this.scenario_new_warships_chance *= 1.1;
    		return; // NB: return
    	}
    	// Otherwise ..
    	// ARCHANGEL
    	this.escapeSequence_baseBugsGetPodChance *= 1.05;
    	this.scenario_modified_chanceNavyAsVBugs *= 0.94;
    	this.scenario_modified_onlyBugs_addSweeperChance *= 1.2;
    	this.scenario_modified_onlyBugs_thargGenship_chance *= 1.2;
    	this.scenario_new_derelict_chance *= 1.1;
    	this.scenario_new_hunter_chance *= 1.13;
    	this.scenario_new_lobster_chance *= 1.1;
    	this.scenario_new_pirates_baseChance *= 1.15;
    	this.scenario_new_pirates_baseNumber += 1;
    	this.scenario_new_radiation_chance *= 1.14;
    	this.scenario_new_sweeperChance *= 1.17;
    	this.scenario_new_thargGenship_chance *= 1.5;
    	this.scenario_new_warships_baseNumber += 1;
    	this.scenario_new_warships_chance *= 1.14;
    	this.sickness_chanceKills *= 1.14;
    	this.stellar_postRescueAmbush_chance *= 1.3;
    };
    
    
    /*
    -----------------------
    Launching, docking etc.
    -----------------------
    */
    
    this.shipWillLaunchFromStation = function() {
    	if (!this.initialisedAtFirstLaunch) {
    		// this.$debugMessage("Initialisation start");
    
    		// INITIALISATION
    		if (this.hackFuelCollectorOnInitialiseAtFirstLaunch) {
    			this.$debugMessage("Hacking fuel collector ..");
    			// REMOVE the role "shuttle" from the Fuel Collector's list.
    			// For, it allows at least some shuttles to be hacked *while still flying*.
    			if (this.$isArrayed("shuttle", worldScripts["Fuel Collector"].legitDerelictRoles)) {
    				worldScripts["Fuel Collector"].legitDerelictRoles.splice("shuttle");
    			}
    			// ADD some roles to Fuel Collector's list of hackable entities.
    			var legitDerelictRolesCopy = worldScripts["Fuel Collector"].legitDerelictRoles.slice(0);
    			// The above copies worldScripts["Fuel Collector"].legitDerelictRoles to legitDerelictRolesCopy.
    			var roles = new Array(
    				"assassin-heavy",
    				"assassin-light",
    				"assassin-medium",
    				"escort-heavy",
    				"escort-medium",
    				"hiredGuns_escortHigh",
    				"hiredGuns_escortLow",
    				"hiredGuns_escortMid",
    				"hunter-heavy",
    				"hunter-medium",
    				"IST_derelict",
    				"IST_derelictThargoid",
    				"IST_derelictViper",
    				"IST_liveDerelict",
    				"IST_mil",
    				"IST_miner",
    				"IST_pirate",
    				"pirate-aegis-raider",
    				"pirate-heavy-fighter",
    				"pirate-heavy-freighter",
    				"pirate-interceptor",
    				"pirate-light-fighter",
    				"pirate-light-freighter",
    				"pirate-medium-fighter",
    				"pirate-medium-freighter",
    				"trader-courier",
    				"trader-smuggler"
    			);
    			var i = roles.length;
    			while (i--) {
    				if (!this.$isArrayed(roles[i], legitDerelictRolesCopy)) {
    					worldScripts["Fuel Collector"].legitDerelictRoles.push(roles[i]);
    				}
    			}
    			log(this.description, "FOR INFO: fuel-collector elligible roles are now: " + worldScripts["Fuel Collector"].legitDerelictRoles);
    		}
    		if (!this.ignorePlayerRank) {
    			this.$probabilities_adjustbyPlayerRank();
    		}
    		this.initialisedAtFirstLaunch = true;
    		// this.$debugMessage("Initialisation end");
    	}
    
    	// MISJUMP
    	if ((!player.ship.scriptedMisjump) && (Math.random() <= this.scenario_chanceScriptInducedMisjump)) {
    		player.ship.scriptedMisjump = true;
    		var r = Math.random();
    		if (r <= 0.3) {
    			player.ship.scriptedMisjumpRange = r + 0.2; // traditional misjump value is 0.5.
    		}
    		this.$debugMessage("Misjump scheduleded");
    	}
    
    	// SICKNESS
    	if (!this.isSick) {
    		return;
    	}
    	// Otherwise
    	this.$messagePlayer("You still have WITCHSPACE SICKNESS. Dock at a main station! Do not jump!", 15);
    	this.mySound_warning.play();
    };
    
    
    this.shipLaunchedFromStation = function(station) {
    	// AMBUSH
    	if (!this.launch_thargAmbush) {
    		return;
    	}
    	// The following optimizes:: t = Math.ceil(Math.random()*60) +1;
    	var t = ~~(1 + (Math.random() * 50));
    	this.timer_thargAmbush = new Timer(this, this.$thargAmbush_timed, t);
    	this.origin_ambush = player.ship.position;
    	this.launch_thargAmbush = false;
    };
    
    this.shipWillDockWithStation = function(station) {
    	if (station.name === "Generation Ship (Hijacked)") {
    		station.suppressArrivalReports = true;
    	}
    };
    
    this.shipDockedWithStation = function(station) {
    	if (!player.ship.docked) {
    		return;
    	}
    	this.$timerDelete_all();
    	this.currentChanceOfSickness = this.sickness_baseChanceOfGetting;
    	if (player.ship.dockedStation.name === "Generation Ship (Hijacked)") {
    		this.showScreen = "rejectPage";
    		mission.runScreen({
    				title: "Generation Ship (Hijacked)",
    				color: "greenColor",
    				message: "You have docked at a highjacked generation ship.\n\nTen out of ten for style, but minus several million for good thinking, yeah?",
    				model: "thargoid",
    				choicesKey: "IST_genshipDocked"
    			},
    			function(choice) {
    				if (choice === "1_RETURN") {
    					if (Math.random() < 0.3) {
    						player.commsMessage("The thargoids got you!");
    						player.ship.launch(); // have to have this before explode the ship
    						if (!this.timer_die) {
    							this.timer_die = new Timer(this, this.$die_timed, 1.7);
    							return;
    						}
    					} else {
    						player.ship.launch();
    						station.reactToAIMessage("ATTACKED");
    						var damaged = false;
    						if (Math.random() < 0.6) {
    							var playerEquipmentList = player.ship.equipment;
    							if (player.ship.equipment.length > 0) {
    								var l;
    								if (Math.random() < 0.6) {
    									l = 1;
    								} else {
    									l = 1 + ~~(1 + (Math.random() * 5));
    								}
    								var i = l;
    								var equipmentToDamage;
    								while (i--) {
    									equipmentToDamage = playerEquipmentList[~~(playerEquipmentList.length * Math.random())];
    									if (player.ship.equipmentStatus(equipmentToDamage.equipmentKey) === "EQUIPMENT_OK") {
    										player.ship.setEquipmentStatus(equipmentToDamage.equipmentKey, "EQUIPMENT_DAMAGED");
    										damaged = true;
    									}
    								}
    							}
    						}
    						if (Math.random() < 0.5) {
    							var r = 50 + ~~(1 + (Math.random() * 150));
    							player.ship.energy = (player.ship.energy - r);
    							damaged = true;
    						}
    						if (damaged === true) {
    							this.mySound_hullBang.play();
    						}
    					}
    				}
    			}
    		);
    	} else {
    		if (player.ship.dockedStation.isMainStation) {
    			this.isSick = false;
    		} else if (Math.random() < 0.2) {
    			this.isSick = false;
    		}
    	}
    };
    
    
    /*
    ----------
    Escape pod
    ----------
    */
    
    this.escapePodSequenceOver = function() {
    	this.$TCAT_reset();
    	if (!system.isInterstellarSpace || player.alertCondition === 0) {
    		return;
    	}
    	// Latter condition = is docked already. NB: Apparently is no way of checking whether something else has already set the escape pod location. . So on we go!
    	//
    	/* FOR TESTING
    	if (this.stellar_postRescueAmbush_chance >= 1) {
    		navalCarriers = system.addShips("leviathan",1,ps,60000);
    		player.setEscapePodDestination(navalCarriers[0]);
    		this.launch_thargAmbush = true;
    		return;
    	}
    	*/
    	var ps = player.ship; // for speed, but changes won't affect the original variable
    	// See whether thargoids destroy pod.
    	var bugs = system.filteredEntities(this, this.$isThargoid_normal, ps, 40000);
    	if (bugs.length > 0) {
    		var actualChanceBugsGetPod = this.escapeSequence_baseBugsGetPodChance;
    		var nonBugs = system.filteredEntities(this, this.$isThargoid_not, ps, 40000);
    		// Any police?
    		if (nonBugs.length < 1) {
    			actualChanceBugsGetPod += (bugs.length / 60);
    		} else {
    			var difference = bugs.length - nonBugs.length;
    			actualChanceBugsGetPod *= (difference / 5);
    		}
    		if (actualChanceBugsGetPod > 0.85) {
    			actualChanceBugsGetPod = 0.85;
    		}
    		if (Math.random() <= actualChanceBugsGetPod) {
    			this.$timerDelete_die();
    			player.setEscapePodDestination(null); // = you die.
    			this.$messagePlayer("Thargoids destroyed your escape pod!", 15);
    			return;
    		}
    	}
    	// RESCUE
    	var actualEscapeSequence_baseRescue_chance = this.escapeSequence_baseRescue_chance;
    	if (this.timer_radiationStageOne_damage1 && this.timer_radiationStageOne_damage1.isRunning) {
    		actualEscapeSequence_baseRescue_chance *= 0.5;
    	}
    	this.$timerDelete_all_exceptDie();
    	// TIMERS: can remove radiation timer now.
    	if (player.bounty > 39 + ~~(1 + (Math.random() * 11))) {
    		player.setEscapePodDestination(null);
    		return;
    	}
    	var navalCarriers;
    	// Rescue - near
    	navalCarriers = system.filteredEntities(this, this.$isNavy_carrier, ps, 30000);
    	if (navalCarriers.length > 0) {
    		if (Math.random() <= actualEscapeSequence_baseRescue_chance) {
    			player.setEscapePodDestination(navalCarriers[0]);
    			return;
    		}
    	}
    	// Rescue - further away
    	navalCarriers = system.filteredEntities(this, this.$isNavy_carrier, ps, 100000);
    	if (navalCarriers.length > 0) {
    		if (Math.random() <= (actualEscapeSequence_baseRescue_chance / 2)) {
    			if (Math.random() < 0.7) {
    				player.bounty = 0;
    			}
    			player.setEscapePodDestination(navalCarriers[0]);
    			return;
    		}
    	}
    	// Arriving carriers
    	if ((this.OXP_behemoth || this.OXP_fiasco) && (Math.random() <= (actualEscapeSequence_baseRescue_chance / 10))) {
    		var carrierType;
    		//carrierType: 1 = Behemoth; 2 = Leviathan
    		if (this.OXP_behemoth && this.OXP_fiasco) {
    			carrierType = ~~(1 + Math.random());
    		} else if (this.OXP_behemoth) {
    			carrierType = 1;
    		} else {
    			carrierType = 2;
    		}
    		if (Math.random() < 0.2) {
    			player.bounty = 0;
    		}
    		if (carrierType == 1) {
    			navalCarriers = system.addShips("behemoth", 1, ps, 60000);
    		} else {
    			navalCarriers = system.addShips("leviathan", 1, ps, 60000);
    		}
    		player.setEscapePodDestination(navalCarriers[0]);
    		// Set a possibility of a later ambush.
    		if (Math.random() <= this.stellar_postRescueAmbush_chance) {
    			this.launch_thargAmbush = true;
    		}
    	}
    };
    
    /*
    ----------
    Jump stuff
    ----------
    */
    this.playerStartedJumpCountdown = function(jump) {
    	if (system.isInterstellarSpace) {
    		this.isIntraInterstellar = true;
    	} else {
    		this.isIntraInterstellar = false;
    	}
    	if (this.OXP_TWD && worldScripts["murphy-thargoid-drive.js"].jumping) {
    		return;
    	}
    	if (jump === "galactic" || (this.OXP_misJump && worldScripts["Galactic Misjump"].gmj_active === 1)) {
    		this.jumpIsGalactic = true;
    		return;
    	}
    	this.jumpIsGalactic = false;
    	// Proceed only if a misjump scripted.
    	if (!player.ship.scriptedMisjump) {
    		return;
    	}
    	// If the Analzyer doing its thing, end here. Else allow Analyzer to identify the misjump.
    	if (this.OXP_misjumpAnalyzer) {
    		if (worldScripts.misjump_analyser.misjump) {
    			return;
    		}
    		// Otherwise
    		if (player.ship.equipmentStatus("EQ_MISJUMP_ANALYSER") === "EQUIPMENT_OK") {
    			var chance;
    			if (system.isInterstellarSpace) {
    				chance = 0.8;
    			} else {
    				chance = 0.9;
    			}
    			var r = Math.random();
    			if (r > chance) {
    				return;
    			}
    			if (r < 0.5) {
    				this.timer_misjumpWarning = new Timer(this, this.$misjumpWarning_timed, 5);
    				return;
    			}
    			this.timer_misjumpWarning = new Timer(this, this.$misjumpWarning_timed, 6);
    		}
    	}
    };
    
    this.playerCancelledJumpCountdown = function() {
    	this.jumpIsGalactic = false; // I think that do not _really_ need this.
    	if (this.timer_misjumpWarning) {
    		if (this.timer_misjumpWarning.isRunning) {
    			this.timer_misjumpWarning.stop();
    		}
    		delete this.timer_misjumpWarning;
    	}
    };
    
    this.$misjumpWarning_timed = function $misjumpWarning_timed() {
    	var ps = player.ship; // for speed, but changes won't affect the original variable
    	var oldLocation = ps.galaxyCoordinates;
    	var newLocation = ps.cursorCoordinates;
    	var dx = newLocation.x - oldLocation.x;
    	var dy = (newLocation.y - oldLocation.y) / 2;
    	this.distance = ~~(0.5 + Math.sqrt(dx * dx + dy * dy) * 2) / 10; // half of jump distance.
    	// = this.distance = Math.round(Math.sqrt(dx*dx+dy*dy)*2)/10; // half of jump distance.
    	this.mySound_warning.play();
    	player.commsMessage("Warning: witchspace disturbance detected at " + this.distance + " LY ahead!");
    	delete this.timer_misjumpWarning;
    };
    
    
    /*
    ---------------------
    WILL ENTER witchspace
    ---------------------
    */
    
    // The shipWillEnterWitchspace handler is called immediately before a witchspace jump, while the player is still in the starting system.
    
    this.playerWillEnterWitchspace = function() {
    	/* 	This routine:
    			- sets 'this.scenario' to a value representing some scenario;
    			- sets repopulation variables accordingly;
    			- does various other vital stuff.
    	*/
    
    	// this.$debugMessage("STAGE *1* - PlayerWillEnterWitchspace");
    
    	// RESETS
    	// this.$timerDelete_interstellarPostWillExit(); // should be removed already
    	// this.$timerDelete_returnEtc(); // should be removed already
    	// this.$timerDelete_resched(); // should be removed already
    
    	/*
    	----------
    	ESSENTIALS
    	----------
    	*/
    	this.$timerDelete_radiation();
    	this.$TCAT_reset();
    	this.$threatOXP_reset();
    	this.scenario = "default";
    	this.repopulations_repopulationIteration = 0;
    	this.willDie = false;
    	if (this.jumpIsGalactic || (this.OXP_TWD && worldScripts["murphy-thargoid-drive.js"].jumping)) {
    		return;
    	}
    
    	/*
    	--------------------------------
    	DETERMINE TWEAKS - preliminaries
    	--------------------------------
    	*/
    
    	// Set 'systemAreLeavingGovLevel'
    	if (system.isInterstellarSpace) {
    		if (this.systemAreLeavingGovLevel < 10) {
    			this.systemAreLeavingGovLevel += 2;
    		}
    		// if jumping intrainterstellar, this.systemAreLeavingGovLevel will be set already, and make things progressively safer from pirates - up to a point.
    	} else {
    		this.systemAreLeavingGovLevel = system.government;
    	}
    
    	/*
    	-----------------------------------
    	DETERMINE TWEAKS - the thing itself
    	-----------------------------------
    	*/
    
    	var r;
    	if (Math.random() < 0.45) {
    		r = system.scrambledPseudoRandomNumber(700000);
    	} else {
    		r = Math.random();
    	}
    	if (r > this.scenario_chanceMajorTweak) {
    		this.$setScenario("default");
    		return;
    	}
    	// Otherwise ..
    	// Yes, major tweak. So, choose the major tweak.
    	if (Math.random() > this.scenario_chanceModifiedAsVsNew) {
    		// Set NEW SCENARIO
    		this.$setScenario("newScenario");
    		return;
    	}
    	if (Math.random() > this.scenario_modified_chanceNavyAsVBugs) {
    		// Set ONLY BUGS
    		this.$setScenario("onlyBugs");
    		return;
    	}
    	if (Math.random() <= this.scenario_modified_chanceOnlyNavyNotExtraNavy) {
    		// Set ONLY NAVY
    		this.$setScenario("onlyNavy");
    		return;
    	}
    	// Set EXTRA NAVY
    	this.$setScenario("extraNavy");
    };
    
    this.$setScenario = function(scenario) {
    	this.repopulation_maximum = 0;
    	switch (scenario) {
    		case "default":
    			if (Math.random() > this.repopulate_chanceEver_default) {
    				// The following is equivalent to:
    				// this.repopulation_maximum = Math.ceil(Math.random() * this.repopulate_maxPossible_default);
    				this.repopulation_maximum = ~~(1 + (Math.random() * this.repopulate_maxPossible_default));
    				this.repopulate_chance = this.repopulate_chance_default;
    			}
    			break;
    
    		case "newScenario":
    			this.$OXP_Threat_restrict(); // Override: Threat
    			this.$OXP_TCAT_override(); // Override: TCAT
    			if (Math.random() <= this.repopulate_chanceEver_newScenario) {
    				// The following is equivalent to:
    				// this.repopulation_maximum = Math.ceil(Math.random() * this.repopulate_maxPossible_newScenario);
    				this.repopulation_maximum = ~~(1 + (Math.random() * this.repopulate_maxPossible_newScenario));
    				this.repopulate_chance = this.repopulate_chance_newScenario;
    			}
    			break;
    
    		case "onlyBugs":
    			this.$OXP_Threat_restrict();
    			this.$OXP_TCAT_override(); // TCAT
    			if (Math.random() > this.repopulate_chanceEver_onlyBugs) {
    				// The following is equivalent to:
    				// this.repopulation_maximum = Math.ceil(Math.random() * this.repopulate_maxPossible_onlyBugs);
    				this.repopulation_maximum = ~~(1 + (Math.random() * this.repopulate_maxPossible_onlyBugs));
    				this.repopulate_chance = this.repopulate_chance_onlyBugs;
    			}
    			break;
    
    		case "onlyNavy":
    			this.$OXP_Threat_restrict();
    			if (Math.random() > 0.1) {
    				this.$OXP_TCAT_override(); // TCAT (which will cause ships to appear to witch-in)
    			}
    			if (Math.random() > this.repopulate_chanceEver_onlyNavy) {
    				// The following is equivalent to:
    				// this.repopulation_maximum = Math.ceil(Math.random() * this.repopulate_maxPossible_onlyNavy);
    				this.repopulation_maximum = ~~(1 + (Math.random() * this.repopulate_maxPossible_onlyNavy));
    				this.repopulate_chance = this.repopulate_chance_onlyNavy;
    			}
    			// By design there is no case for 'extraNavy'.
    	}
    	this.scenario = scenario;
    };
    
    
    /*
    --------------------------------
    POPULATION & REPOPULATION ROUTINES
    --------------------------------
    */
    
    // POPULATION
    
    // The name of this function must match the name given in the file planetinfo.plist.
    this.interstellarTweaks_populate_interstellar_custom = function() {
    	// Called immediately before the shipWillExitWitchspace event fires.
    	// this.$debugMessage("interstellarTweaks_repopulate_interstellar_custom:");
    	if (this.scenario != "default" && this.scenario != "onlyBugs") {
    		return;
    		// We run no populator for other scenarios, and one and the same populator for those two scenarios.
    	}
    	// Run the inbuilt populator
    	worldScripts["oolite-populator"].interstellarSpaceWillPopulate();
    	// Run OXP populators
    	var i = this.populatorScripts_interstellar.length;
    	// this.$debugMessage("Populators - inbuilt and OXP:"); 
    	while (i--) {
    		if (!worldScripts[this.populatorScripts_interstellar[i]]) {
    			this.$debugMessage("UNDEFINED POPULATOR!");
    		} else {
    			// this.$debugMessage("Populating :" +worldScripts[this.populatorScripts_interstellar[i]]);
    			// We can get errors here, reported in the log against my script, which seemingly owe to *other* OXPs.
    			try {
    				worldScripts[this.populatorScripts_interstellar[i]].interstellarSpaceWillPopulate();
    			} catch (err) {
    				this.$error("Problem with populator <" + worldScripts[this.populatorScripts_interstellar[i]] + "> : " + err.message);
    			}
    		}
    	}
    	// this.$debugMessage("Leaving function interstellarTweaks_repopulate_interstellar_custom");
    };
    
    // RE-REPOPULATION
    
    // The name of this function must match the name given in the file planetinfo.plist.
    this.interstellarTweaks_repopulate_interstellar_custom = function() {
    	if (!player.ship.isValid || !player.ship.position) {
    		return;
    	}
    	// Sanity check. For, do use player.ship.position in repopulation routines.
    	if (this.repopulation_maximum == null) {
    		this.$error("repopulation_maximum not set!");
    		this.repopulation_maximum = 1;
    		return;
    	}
    	if (this.repopulations_repopulationIteration === this.repopulation_maximum) {
    		this.$debugMessage("Max repops reached");
    		return;
    	}
    	// Otherwise ..
    	this.repopulations_repopulationIteration++;
    	// this.$debugMessage("Running repopulator for "+this.scenario);
    	// this.$debugMessage("Repop "+ this.repopulations_repopulationIteration +" of "+this.repopulation_maximum);
    	if (this.repopulations_repopulationIteration === 1) {
    		if (Math.random() < 0.8) {
    			return;
    		}
    		// The first repopulation arrives rather quickly, so let us tend to skip it.
    	}
    	// Otherwise ..
    	if (Math.random() < this.repopulate_chance) {
    		this.$repopulate_interstellar(this.scenario);
    	}
    };
    
    this.$repopulate_interstellar = function(tweak) {
    	switch (tweak) {
    		case "newScenario":
    			this.$repopulate_interstellar_newScenario();
    			break;
    		default:
    			this.$repopulate_interstellar_modifiedOrScenario_default();
    	}
    };
    
    this.$repopulate_interstellar_modifiedOrScenario_default = function() {
    	if (system.countShipsWithPrimaryRole("IST_thargoid") < 4) {
    		// have the above check 'cos inbuilt populator checks only for primary role 'thargoid' . .
    		// Run the INBUILT populator
    		worldScripts["oolite-populator"].interstellarSpaceWillRepopulate();
    		// this.$debugMessage("Re-populating: inbuilt");
    	}
    	// Run OXP repopulators
    	var i = this.repopulatorScripts_interstellar.length;
    	// this.$debugMessage("# repopulators: "+i);
    	while (i--) {
    		// this.$debugMessage("Re-populating: "+worldScripts[this.repopulatorScripts_interstellar[i]]);
    		worldScripts[this.repopulatorScripts_interstellar[i]].interstellarSpaceWillRepopulate();
    	}
    };
    
    this.$repopulate_interstellar_newScenario = function() {
    	// Need my own repopulator because inbuilt and OXP repopulators will put ships in the wrong place.
    	// Should use the 'rings' functions here.
    
    	// RADIATION?
    	if (this.timer_radiationStageOne_damage1 && this.timer_radiationStageOne_damage1.isRunning) {
    		return;
    	}
    	// this.$debugMessage("Re-populating: new");
    
    	var n;
    	var s;
    	var threshold;
    	var ps = player.ship; // for speed, but changes won't affect the original variable
    	var origin = this.origin_newScenario;
    	// THARGOIDS & GALCOP
    	var r = Math.random();
    	if (ps.equipmentStatus("EQ_ELECTRONIC_THUMB") === "EQUIPMENT_OK") {
    		n = system.countShipsWithPrimaryRole("interstellar_helper");
    		if (n.length > 0) {
    			r *= 1.15;
    		} // Make adding Thargoids more likely.
    	}
    	if (r > 0.45) {
    		// Add thargoids, if a check to do with extant thargoids is passed (or on small random chance).
    		s = system.filteredEntities(this, this.$isBug, ps, 50000);
    		// The following is equivalent to
    		threshold = ~~(1 + (Math.random() * 19));
    		if ((s.length <= threshold) || (Math.random() < 0.05)) {
    			if (r < 0.9) {
    				n = 1 + ~~(1 + (Math.random() * 2));
    			} else {
    				n = ~~(1 + (Math.random() * 7));
    			}
    			if (r < 0.65) {
    				var position = new Vector3D(ps);
    				var x = Math.random() * 2000;
    				var y = Math.random() * 2000;
    				var z = Math.random() * 2000;
    				position = position.add([x, y, z]);
    				s = this.$addShips_rings("thargoid", n, position, 25600);
    			} else {
    				s = this.$addShips_rings("thargoid", n, origin, 25600);
    			}
    		}
    	} else {
    		// Add Military - if number of extant military is below a threshold (or on a small random chance).
    		n = system.countShipsWithPrimaryRole("IST_mil", ps, 50000);
    		n += system.countShipsWithPrimaryRole("police", ps, 50000);
    		n += system.countShipsWithPrimaryRole("ferdelance3G_interstellar", ps, 50000);
    		// The following is equivalent to:
    		// threshold = 1+Math.ceil(Math.random()*8);
    		threshold = 1 + ~~(1 + (Math.random() * 8));
    		if ((n > threshold) && (Math.random() > 0.05)) {
    			return;
    		}
    		// Otherwise ..
    		if (this.OXP_3G) {
    			if (Math.random() < 0.06) {
    				// n = 2 + Math.ceil( Math.random()*6 );
    				n = 1 + ~~(1 + (Math.random() * 7));
    				s = this.$addShips_rings("ferdelance3G_interstellar", n, origin, 950);
    				return;
    			}
    		}
    		// Otherwise ..
    		// The following is equivalent to:
    		// n = 3+Math.ceil(Math.random()*6);
    		n = 3 + ~~(1 + (Math.random() * 6));
    		s = this.$addShips_rings("IST_mil", n, origin, 2000);
    	}
    };
    
    
    
    /*
    ------------------------------------------------------------------------
    WILL EXIT witchspace
    When this event handler fires, the player is (from a program perspective)
    in the destination system (which can be interstellar space),
    but the tunnel effect has not yet been shown.
    -------------------------------------------------------------------------
    */
    
    this.shipWillExitWitchspace = function() {
    	// this.$debugMessage("willExit_witchspace"); 
    	/* FOR TESTING:
    	var lobsters = system.addShips("IST_lobsterUber",1,[0,0,0],8000);
    	*/
    	if (this.jumpIsGalactic || (this.OXP_TWD && worldScripts["murphy-thargoid-drive.js"].jumping)) {
    		return;
    	}
    	if (!system.isInterstellarSpace) {
    		// STELLAR
    		this.beforeExitIsRunning = false;
    		this.$willExit_stellar();
    		return;
    	}
    	// Otherwise ..
    	// INTERSTELLAR
    	this.beforeExitIsRunning = true;
    	this.timer_interstellarPostWillExit = new Timer(this, this.$willExit_interstellar_timed, this.scenario_interstellarPostWillExitTimed);
    	// this.$debugMessage("STAGE *2* - willExit_witchspace finished OK");
    };
    
    // Consider misplacing the player.
    this.$willExit_stellar = function() {
    	if (!player.ship) {
    		return;
    	}
    	var realMisplaceChance = this.stellar_misplace_chance;
    	if (player.ship.energy < 60) {
    		realMisplaceChance += 0.02;
    	}
    	if (this.breakableDrive) {
    		if (player.ship.equipmentStatus("EQ_BREAKABLE_WITCHDRIVE") === "EQUIPMENT_DAMAGED") {
    			realMisplaceChance += 0.15;
    		}
    	}
    	if (Math.random() <= realMisplaceChance) {
    		this.$timerDelete_stellar();
    		this.timer_stellar = new Timer(this, this.$stellar_misplace_timed, this.stellar_misplace_delay);
    		// _Sic_ (this.stellar_misplace_delay).
    	}
    };
    
    this.$stellar_misplace_timed = function $stellar_misplace_timed() {
    	var x, y, z;
    	this.$messagePlayer("Drive malfunction - missed witchpoint!", 10);
    	if (Math.random() <= this.stellar_misplace_nearSun_chance && !system.sun.hasGoneNova) {
    		this.$messagePlayer("ALERT - Approaching the sun. Temperature monitoring is critical!", 10);
    		x = (Math.random() * 200000) - 50000;
    		y = (Math.random() * 200000) - 50000;
    		z = (Math.random() * 200000) - 50000;
    		player.ship.position = system.sun.position.subtract([x, y, z]);
    	} else {
    		x = (Math.random() * 4000000) + 50000;
    		y = (Math.random() * 4000000) + 50000;
    		z = (Math.random() * 4000000);
    		player.ship.position = player.ship.position.add([x, y, z]);
    	}
    	this.mySound_warning.play();
    };
    
    this.$willExit_interstellar_timed = function $willExit_interstellar_timed() {
    	// this.$debugMessage("STAGE *3* - willExit_interstellar_timed");
    	if (!system.isInterstellarSpace) {
    		this.beforeExitIsRunning = false;
    		return;
    	}
    	switch (this.scenario) {
    		case "newScenario":
    			this.$willExit_newScenario();
    			break;
    		case "onlyBugs":
    			this.$willExit_bugsOnly();
    			break;
    		case "onlyNavy":
    			this.$willExit_navyOnly();
    			break;
    		case "extraNavy":
    			this.$willExit_extraNavy();
    			break;
    		default:
    			this.$willExit_interstellar_timed_default();
    	}
    	if (this.OXP_GenShips) {
    		this.$willExit_interstellar_timed_considerRemovingAnyGenShips();
    	}
    	this.beforeExitIsRunning = false;
    	// This is a VITAL RESET, but performed above if this routine doesn't even reach 'switch (this.scenario)'.
    	// this.$debugMessage("willExit_interstellar_timed finished OK");
    };
    
    this.$willExit_interstellar_timed_default = function() {
    	var n, s;
    
    	if (this.OXP_ThargoidThreat && Math.random() <= this.scenario_modified_limitBattleships_chance) {
    		s = system.filteredEntities(this, this.$isThargoid_battleship);
    		if (s.length > this.scenario_modified_limitBattleships_maxShips) {
    			var numToRemove = s.length - this.scenario_modified_limitBattleships_maxShips;
    			while (numToRemove--) {
    				s[numToRemove].remove(true); // s[numToRemove] - *sic*.
    			}
    		}
    	}
    
    	var g, r;
    	g = system.info.galaxyID; // Make local for speed.
    	switch (g) {
    		case 3:
    			this.scenario_modified_onlyBugs_rebelChance *= 3;
    			break;
    		case 5:
    			r = this.scenario_default_chanceAsteroids * 1.25;
    			break;
    		default:
    			r = this.scenario_default_chanceAsteroids; // for asteroids.
    	}
    
    	// Asteroids
    	if (Math.random() <= r) {
    		n = 5 + ~~(1 + (Math.random() * 15));
    		s = system.addShips("IST_asteroid", n, [0, 0, 0], 38000);
    		n = ~~(1 + n);
    		s = system.addShips("IST_asteroid", n, [0, 0, 0], 50000);
    	}
    
    	// Separate clash
    	if (Math.random() <= this.scenario_default_chanceExtraSeperateClash) {
    		// this.$debugMessage("Extra seperate."); if (this.debug) {log("InterstellarTweaks", "EXTRA OK.");}
    		var x = (Math.random() - 0.5) * 40000;
    		var y = (Math.random() - 0.5) * 40000;
    		var z = (Math.random() - 0.5) * 40000;
    		n = ~~(1 + (Math.random() * 15));
    		s = this.$addShips_ringless("thargoid", n, [x, y, z], 25000);
    		n = ~~(1 + (Math.random() * 15));
    		s = this.$addShips_ringless("IST_mil", n, [x, y, z], 24000);
    	}
    };
    
    this.$willExit_interstellar_timed_considerRemovingAnyGenShips = function() {
    	var s = system.shipsWithRole("generationship");
    	var i = s.length;
    	if (i > 0 && (Math.random() <= this.scenario_genShipsRemovalChance)) {
    		while (i--) {
    			s[i].remove(true);
    		}
    	}
    };
    
    this.$remove_allFromNew = function() {
    	// Well, *nearly* all . . Also: will in fact work in scenarios other than 'new'.
    	// this.$debugMessage("Removing from new.");
    	// NB: we do need the isShip, because otherwise hasRole does not work.
    	var s = system.filteredEntities(this, this.$toRemove_newScenario);
    	var i = s.length;
    	while (i--) {
    		s[i].remove(true);
    	}
    };
    
    this.$scenario_new_populate = function() {
    	// NB: vectors are defined when used, and must always be with a new Vector3D
    
    	// this.$debugMessage("Populating new.");
    	// this.$debugMessage("this.origin_newScenario is: "+this.origin_newScenario); 
    
    	var actualChance;
    	var galNumber = system.info.galaxyID;
    
    	// FORCE EMPTY
    	if ((galNumber === 0) || (galNumber === 7)) {
    		actualChance = this.scenario_new_forceInitiallyEmpty_chance * 1.12;
    	} else {
    		actualChance = this.scenario_new_forceInitiallyEmpty_chance;
    	}
    	var r;
    	if (Math.random() < 0.7) {
    		r = system.scrambledPseudoRandomNumber(700001);
    	} else {
    		r = Math.random();
    	}
    	if (r <= actualChance) {
    		// this.$debugMessage("Empty");
    		this.$OXP_TCAT_override();
    		return; // i.e. end here, without populating the system.
    	}
    
    	// RADIATION
    	if ((galNumber === 4) || (galNumber === 7)) {
    		actualChance = this.scenario_new_radiation_chance * 1.3;
    	} else {
    		actualChance = this.scenario_new_radiation_chance;
    	}
    	if (Math.random() < 0.6) {
    		r = system.scrambledPseudoRandomNumber(700002);
    	} else {
    		r = Math.random();
    	}
    	if (r <= actualChance) {
    		this.$scenario_new_radiation();
    		return; // NB
    	}
    
    	// ASTEROIDS
    	if (galNumber === 5) {
    		actualChance = this.scenario_new_asteroids_chance * 1.23;
    	} else {
    		actualChance = this.scenario_new_asteroids_chance;
    	}
    	if (Math.random() > 0.7) {
    		r = system.scrambledPseudoRandomNumber(700004);
    	} else {
    		r = Math.random();
    	}
    	if (r <= actualChance) {
    		this.$scenario_new_asteroids();
    		if (Math.random() < 0.9) {
    			return;
    		}
    	}
    
    	// DERELICT
    	if (Math.random() <= this.scenario_new_derelict_chance) {
    		this.$scenario_new_derelict();
    		if (Math.random() < 0.7) {
    			return;
    		}
    	}
    
    	// PIRATES
    	var planetID = player.ship.targetSystem;
    	var targetSystemGovLevel = System.infoForSystem(galNumber, planetID).government;
    	actualChance = this.scenario_new_pirates_baseChance + (1 - ((this.systemAreLeavingGovLevel + targetSystemGovLevel) / 14)) * 0.4;
    	if (Math.random() > 0.2) {
    		r = Math.random();
    	} else {
    		r = system.scrambledPseudoRandomNumber(700005);
    	}
    	if (r <= actualChance) {
    		this.$scenario_new_pirates();
    		// Make it likely that (1) is nothing else later, (2) is nothing else now.
    		this.repopulate_chance *= 0.6;
    		if (Math.random() < 0.7) {
    			return;
    		}
    	}
    
    	// INTERSTELLAR HELP OXP's HELPEE
    	if (this.OXP_InterstellarHelp) {
    		if (Math.random() <= this.scenario_new_helpee_chance) {
    			this.$scenario_new_helpee();
    			return;
    		}
    	}
    
    	// ALIENS
    	if (this.OXP_aliens) {
    		if (galNumber === 7) {
    			this.scenario_new_aliens_chance *= 1.5;
    		}
    		if (Math.random() < 0.5) {
    			r = Math.random();
    		} else {
    			r = system.scrambledPseudoRandomNumber(700006);
    		}
    		if (r <= this.scenario_new_aliens_chance) {
    			this.$scenario_new_aliens();
    			if (Math.random() < 0.9) {
    				return;
    			}
    		}
    	}
    
    	// LOBSTERS
    	if (this.OXP_Missionaries) {
    		if (galNumber === 3) {
    			actualChance = this.scenario_new_lobster_chance * 1.6;
    		} else {
    			actualChance = this.scenario_new_lobster_chance;
    		}
    		if (Math.random() < 0.4) {
    			r = Math.random();
    		} else {
    			r = system.scrambledPseudoRandomNumber(700007);
    		}
    		if (r <= actualChance) {
    			this.$scenario_new_lobsters(galNumber);
    			// Make it likely that (1) is nothing else now, (2) is nothing else later.
    			if (Math.random() < 0.8) {
    				this.repopulate_chance *= 0.25;
    				return;
    			}
    		}
    	}
    
    	// HUNTERS
    	if (Math.random() <= this.scenario_new_hunter_chance) {
    		this.$scenario_new_hunters();
    	}
    
    	// THARGOIDS
    	if (galNumber === 0) {
    		actualChance = this.scenario_new_warships_chance * 0.9;
    	} else {
    		actualChance = this.scenario_new_warships_chance;
    	}
    	if (Math.random() < 0.4) {
    		r = Math.random();
    	} else {
    		r = system.scrambledPseudoRandomNumber(700008);
    	}
    	if (r <= actualChance) {
    		this.$scenario_new_thargoids();
    	}
    
    	// GENSHIPS
    	if (this.OXP_GenShips && Math.random() <= this.scenario_new_thargGenship_chance) {
    		this.$scenario_new_genship();
    	}
    	// NB: Sometimes - depending on how the numbers come out - this function will add no ships.
    };
    
    this.$scenario_new_radiation = function() {
    	// this.$debugMessage("Radiation");
    	this.$OXP_TCAT_override();
    	// this.$OXP_Threat_restrict(); // done already
    	this.mySound_warning.play();
    	// remove anything that would not have survived.
    	var s = system.allShips;
    	if (s.length > 1) {
    		if (this.OXP_hiredGuns) {
    			s = system.filteredEntities(this, this.$toRemove_radiationScenario_alt);
    		} else {
    			s = system.filteredEntities(this, this.$toRemove_radiationScenario);
    		}
    		var i = s.length;
    		while (i--) {
    			s[i].remove(true);
    		}
    	}
    	// Now do the actual radiation - which can be high or very high.
    	var r;
    	if (Math.random() < 0.7) {
    		r = system.scrambledPseudoRandomNumber(700003);
    	} else {
    		r = Math.random();
    	}
    	if (r < 0.25) {
    		if (r < 0.2) {
    			system.sendAllShipsAway();
    		}
    		this.$messagePlayer("WARNING - very high levels of space radiation! ADVICE: leave area immediately!", 15);
    		this.timer_radiationStageOne_damage1 = new Timer(this, this.$radiationDamageToPlayer_andPerhapsSendOtherShipsAway, 0.3, 0.3);
    		if (Math.random() < 0.8) {
    			this.timer_radiationStageOne_damage2 = new Timer(this, this.$radiationDamageToNPCs, 3.16, 3.16);
    		} else {
    			this.timer_radiationStageOne_damage2 = new Timer(this, this.$radiationDamageToNPCsWithSickness, 3.16, 3.16);
    		}
    	} else {
    		if (r < 0.95) {
    			system.sendAllShipsAway();
    		}
    		this.$messagePlayer("WARNING - high levels of space radiation! ADVICE: leave area quickly!", 15);
    		this.timer_radiationStageOne_damage1 = new Timer(this, this.$radiationDamageToPlayer_andPerhapsSendOtherShipsAway, 0.4, 0.4);
    		if (Math.random() < 0.8) {
    			this.timer_radiationStageOne_damage2 = new Timer(this, this.$radiationDamageToNPCs, 4, 4);
    		} else {
    			this.timer_radiationStageOne_damage2 = new Timer(this, this.$radiationDamageToNPCsWithSickness, 4, 4);
    		}
    	}
    	this.timer_radiationStageTwo = new Timer(this, this.$radiationStageTwo, 3);
    	// The 'stage two' timer does another system.sendAllShipsAway(), and then, sometimes, populates.
    };
    
    this.$radiationDamageToPlayer_andPerhapsSendOtherShipsAway = function $radiationDamageToPlayer_andPerhapsSendOtherShipsAway() {
    	if (!system.isInterstellarSpace) {
    		this.$timerDelete_radiation();
    		return;
    	}
    	if (Math.random() < 0.15) {
    		system.sendAllShipsAway();
    	}
    	if (!player.ship) {
    		this.$timerDelete_radiation();
    		return;
    	}
    	if (player.ship.equipmentStatus("EQ_HEAT_SHIELD") === "EQUIPMENT_OK") {
    		player.ship.energy -= 3.5;
    	} else {
    		player.ship.energy -= 4.5;
    	}
    };
    
    this.$radiationDamageToNPCs = function $radiationDamageToNPCs() {
    	if (!system.isInterstellarSpace) {
    		this.$timerDelete_radiation();
    		return;
    	}
    	if (!player.ship) {
    		this.$timerDelete_radiation();
    		return;
    	}
    	var s = system.filteredEntities(this, this.$NPCsToIrradiate);
    	var i = s.length;
    	var damage;
    	// Since we may have done a sendAllShipsAway, let's check that ships still exist before we do anything to them.
    	while (i--) {
    		if (!s[i] || !s[i].isValid) {
    			continue;
    		}
    		if (s[i].isThargoid) {
    			damage = 23;
    		} else {
    			if (s[i].heat_insulation > 1) {
    				damage = 35;
    			} else {
    				damage = 45;
    			}
    		}
    		if (s[i].energy <= damage) {
    			s[i].explode();
    		} else {
    			s[i].energy -= damage;
    		}
    	}
    };
    
    this.$radiationDamageToNPCsWithSickness = function $radiationDamageToNPCsWithSickness() {
    	this.$radiationDamageToNPCs();
    	if (this.isSick) {
    		return;
    	}
    	// Otherwise ..
    	var r = Math.random();
    	// The following condition works out as approximately every 2.5 minutes.
    	if (r < 0.02) {
    		if (r < 0.005) {
    			this.isSick = true;
    			this.$messagePlayer("You have developed WITCHSPACE SICKNESS.", 15);
    			this.mySound_warning.play();
    		} else {
    			if (this.currentChanceOfSickness < 0.6) {
    				this.currentChanceOfSickness += 0.04;
    			}
    		}
    	}
    };
    
    this.$radiationStageTwo = function $radiationStageTwo() // ensure delete this, and radiation timers
    {
    	if (this.timer_radiationStageTwo) {
    		if (this.timer_radiationStageTwo.isRunning) {
    			this.timer_radiationStageTwo.stop();
    		}
    		delete this.timer_radiationStageTwo;
    	}
    	system.sendAllShipsAway();
    	if (Math.random() > (this.scenario_new_derelict_chance / 2)) {
    		return;
    	}
    	// this.$debugMessage("Derelict");
    	this.$scenario_new_derelict_deadOneOrOnes();
    };
    
    this.$scenario_new_asteroids = function() {
    	// this.$debugMessage("Asteroids");
    	// IST_asteroids are like_shipped from Oolite's inbuilt one, and so shouldn't be computationally demanding.
    	var i, n, r, s, x, y, z;
    	var offset;
    	var position = new Vector3D(this.origin_newScenario);
    
    	r = Math.random();
    	if (r > 0.15) {
    		offset = ~~(Math.random() * 200000);
    	} else {
    		offset = 800000;
    	}
    	x = (Math.random() - 0.5) * offset;
    	y = (Math.random() - 0.5) * offset;
    	z = (Math.random() - 0.5) * offset;
    	position = position.add([x, y, z]);
    
    	// 1st group
    	s = system.addShips("IST_asteroid", 26, position, 34000);
    
    	// 2nd group
    	n = 6 + ~~(1 + (r * 55));
    	s = system.addShips("IST_asteroid", n, position, 44000);
    
    	// Perhaps add various further rocks
    	if (r < 0.5) {
    		n = 5 + ~~(1 + (r * 40));
    		s = system.addShips("IST_asteroid", n, position, 60000);
    		s = system.addShips("IST_asteroid", n, position, 70000);
    		if (r < 0.2) {
    			s = system.addShips("IST_asteroid", 10, position, 95000);
    		}
    	}
    
    	// Miners
    	if (Math.random() <= this.scenario_new_asteroids_chanceMiners) {
    		// this.$debugMessage("Miners");
    		n = ~~(1 + (Math.random() * 6));
    		if (Math.random() < 0.45) {
    			s = system.addShips("splinter", n, position, 10000);
    		} else {
    			s = system.addShips("IST_boulder", n, position, 28000);
    		}
    		n = ~~(1 + (Math.random() * 10));
    		s = this.$addShips_ringless("IST_miner", n, position, 12000);
    		// Miners tend to come with escorts. But, still, consider adding hunters as protection.
    		if (n > 5) {
    			n = 1 + ~~(1 + (Math.random() * 4));
    			var g = system.addGroup("hunter", n, position, 30000);
    			if (g.ships) {
    				s = g.ships;
    				i = s.length;
    				while (i--) {
    					if (s[i]) {
    						s[i].setAI("IST_hunterAI.plist");
    					}
    				}
    			} else {
    				this.$error("Problem adding hunters to miners");
    			}
    		}
    	}
    
    	// The billboards OXP adds them near asteroids, so, remove any billboards that will have been added.
    	if (this.OXP_YAH) {
    		s = system.filteredEntities(this, this.$isBillboard);
    		i = s.length;
    		while (i--) {
    			s[i].remove(true);
    		}
    	}
    };
    
    this.$scenario_new_derelict = function() {
    	// this.$debugMessage("Derelict");
    	if (Math.random() <= this.scenario_new_derelict_chanceIsLive) {
    		this.$scenario_new_derelict_liveOne();
    		if (Math.random() < 0.75) {
    			return;
    		} // allow possibility here of other (but dead) derelicts.
    	}
    	this.$scenario_new_derelict_deadOneOrOnes(); // keep this as function as something else calls it.
    };
    
    this.$scenario_new_derelict_liveOne = function() {
    	// this.$debugMessage("IS LIVE");
    
    	var localRange = this.scenario_new_derelict_range;
    	var x = Math.random() * localRange;
    	var y = Math.random() * localRange;
    	var z = Math.random() * localRange;
    	var position = new Vector3D(this.origin_newScenario);
    	position = position.add([x, y, z]);
    	var s = this.$addShips_ringless("IST_liveDerelict", 1, position, 4000);
    	if (s.length < 1) {
    		return;
    	} // Sanity check
    	// s[0].lightsActive = false; // done by AI
    	if (!s[0].isValid) {
    		return;
    	} // Sanity check
    	// Otherwise ..
    	s[0].switchAI("IST_liveOneAI.plist");
    	s[0].setScript("IST_liveOneScript.js");
    	// Now remove any persistent escorts.
    	var s2 = system.filteredEntities(this, this.$isEscort, s[0], 100000); // Construction requires an entity.
    	var i = s2.length;
    	while (i--) {
    		if (s2[i]) {
    			s2[i].remove(true);
    		}
    	}
    };
    
    this.$scenario_new_derelict_deadOneOrOnes = function() {
    	var i, s;
    
    	// Decide how many dead derelicts to add.
    	if (Math.random() <= this.scenario_new_derelict_dead_chanceMultiple) {
    		var n = ~~(1 + (Math.random() * 4));
    		if (n === 4 && Math.random() < 0.15) {
    			n += ~~(1 + (Math.random() * 6));
    		}
    		i = n;
    	} else {
    		i = 1;
    	}
    	// Now add the dead derelict(s).
    	var localRange = this.scenario_new_derelict_range;
    	var position, x, y, z;
    	while (i--) {
    		x = Math.random() * localRange;
    		y = Math.random() * localRange;
    		z = Math.random() * localRange;
    		// this.$debugMessage("dead derelict");
    		// this.$debugMessage("Origin is: "+this.origin_newScenario);
    		position = new Vector3D(this.origin_newScenario);
    		position = position.add([x, y, z]);
    		s = system.addShips("IST_derelict", 1, position, 2050);
    		if (s[i] && s[i].isValid) {
    			s[i].lightsActive = false;
    		}
    	}
    	// (Awarding cargo by plist doesn't seem to work - so do it by SHIP script. That script awards fuel too - which set in shipdata, as default, as zero.
    
    	// Somehow, despite the shipdate forbidding it, some derelicts still end up with escorts. So, zap them:
    	// (Actually, I may have fixed this. Still, leave the following code in here as a failsafe.)
    	if (s[0] && s[0].isValid) {
    		// this.$debugMessage("starting escort sweep");
    		var s2 = system.filteredEntities(this, this.$isEscort, s[0], 100000); // Construction requires an entity.
    		i = s2.length;
    		while (i--) {
    			if (s2[i]) {
    				// this.$debugMessage("removed one");
    				s2[i].remove(true);
    			}
    		}
    	}
    };
    
    this.$scenario_new_pirates = function() {
    	// this.$debugMessage("Pirates");
    	// Add a group. Many of these ships have escorts.
    	var n = this.scenario_new_pirates_baseNumber + ~~(1 + (Math.random() * 2));
    	var g = system.addGroup("IST_pirate", n, this.origin_newScenario, 15500);
    };
    
    this.$scenario_new_helpee = function() {
    	var s = this.$addShips_ringless("interstellar_help_trader", 1, this.origin_newScenario, 25600);
    };
    
    this.$scenario_new_aliens = function() {
    	// this.$debugMessage("Aliens");
    	var n = ~~(1 + (Math.random() * 17));
    	var s = this.$addShips_ringless("scorpax", n, this.origin_newScenario, 28000);
    };
    
    this.$scenario_new_lobsters = function(galNumber) {
    	// this.$debugMessage("Lobsters");
    	var n;
    	if (galNumber === 3 || galNumber === 7) {
    		n = 4 + ~~(1 + (Math.random() * 19));
    	} else {
    		n = 4 + ~~(1 + (Math.random() * 30));
    		if (n > 24 && Math.random() < 0.22) n *= 2;
    	}
    	var g = system.addGroup("IST_lobster", n, this.origin_newScenario, 15000);
    	var s = g.ships;
    	// Give first lobster an ECM, and, for each lobster, tell it which one has the ECM.
    	if (s[0]) {
    		s[0].awardEquipment("EQ_ECM");
    	}
    	var i = s.length;
    	while (i--) {
    		if (s[i]) {
    			s[i].script.$shipWithECM = s[0];
    		}
    	}
    };
    
    this.$scenario_new_thargoids = function() {
    	var group;
    	var i;
    	var n;
    	var offset;
    	var origin = new Vector3D();
    	var position;
    	var r;
    	var s;
    	var scenario;
    	var x;
    	var y;
    	var z;
    
    	// this.$debugMessage("Thargoids");
    	// Don't use system.setPopulator, because that only works within a short time window - which my shannanigans places us outside of.
    
    	origin = this.origin_newScenario;
    	n = this.scenario_new_warships_baseNumber + ~~(1 + (Math.random() * 6));
    	if (n > 4) {
    		if (n < 33 && Math.random() > 0.95) {
    			n *= 2;
    		}
    	}
    
    	scenario = ~~(1 + (Math.random() * 26));
    	// Can't get the linter's 'fall through' option to work, so have reworked the following.
    	switch (scenario) {
    		case 1:
    			s = this.$addShips_ringless("IST_thargoid", n, origin, 14000);
    			if ((n > 3) && (Math.random() <= this.scenario_new_sweeperChance)) {
    				s = this.$addShips_ringless("extraThargoids_sweeper", 1, origin, 18000);
    				n++;
    			}
    			s = this.$addShips_ringless("thargoid", n, origin, 14000);
    			break;
    		case 2:
    			s = this.$addShips_ringless("thargoid", n, origin, 14000);
    			r = ~~(Math.random() * 60000);
    			s = this.$addShips_ringless("IST_thargoid", n, origin, r);
    			break;
    		case 3:
    			r = ~~(Math.random() * 60000);
    			s = this.$addShips_ringless("IST_thargoid", n, origin, r);
    			break;
    		case 4:
    			if (Math.random() < 0.8) {
    				s = this.$addShips_ringless("IST_thargoid", n, origin, 50000);
    				s = this.$addShips_ringless("thargoid", 5, origin, 50000);
    			} else {
    				n *= 12;
    				if (n > 64) {
    					n = 60;
    				}
    				s = this.$addShips_ringless("thargoid", n, origin, 250000);
    				s = this.$addShips_ringless("extraThargoids_sweeper", 3, origin, 250000);
    				if (this.OXP_ThargoidCarriers) {
    					s = this.$addShips_ringless("thargoid_carrier", 3, origin, 250000);
    				}
    				if ((score > 7000) && (Math.random() < 0.4)) {
    					s = this.$addShips_ringless("thargoid", 40, origin, 300000);
    					if (this.OXP_ThargoidCarriers) {
    						s = this.$addShips_ringless("thargoid_carrier", 6, origin, 250000);
    					}
    					if ((score > 10000) && (Math.random() < 0.3)) {
    						s = this.$addShips_ringless("IST_thargoid", 30, origin, 300000);
    						s = this.$addShips_ringless("extraThargoids_sweeper", 6, origin, 300000);
    						s = this.$addShips_ringless("thargoid", 15, [0, 0, 0], 20000);
    						if (this.OXP_ThargoidCarriers) {
    							s = this.$addShips_ringless("thargoid_carrier", 5, origin, 400000);
    						}
    					}
    				}
    			}
    			break;
    		case 5:
    			s = this.$addShips_ringless("thargoid", n, origin, 15000);
    			if (this.OXP_extraThargoids) {
    				s = this.$addShips_ringless("extraThargoids_frigatePoet", 4, origin, 17000);
    			}
    			break;
    		case 6, 7:
    			if (Math.random() > 0.1) {
    				offset = ~~(Math.random() * 20000);
    			} else {
    				offset = 80000;
    			}
    			x = Math.random() * offset;
    			y = Math.random() * offset;
    			z = Math.random() * offset;
    			position = new Vector3D(origin);
    			position = position.add([x, y, z]);
    			s = this.$addShips_ringless("thargoid", n, position, 15000);
    			break;
    		case 8:
    			s = system.addGroup("thargoidRebel", n, origin, 17000);
    			// log("InterstellarTweaks","Thargoid rebels added.");
    			if (Math.random() < 0.35) {
    				x = Math.random() * offset;
    				y = Math.random() * offset;
    				z = Math.random() * offset;
    				position = new Vector3D(origin);
    				position = position.add([x, y, z]);
    				s = this.$addShips_ringless("thargoid", n, position, 15000);
    			} else {
    				s = system.addGroup("thargoidRebel", 10, origin, 20000);
    			}
    			break;
    		case 9:
    			this.$wreckage(origin);
    			s = this.$addShips_ringless("thargoid", n, origin, 15000);
    			break;
    		case 10:
    			if (Math.random() > 0.1) {
    				offset = ~~(Math.random() * 20000);
    			} else {
    				offset = 80000;
    			}
    			x = Math.random() * offset;
    			y = Math.random() * offset;
    			z = Math.random() * offset;
    			position = new Vector3D(origin);
    			position = position.add([x, y, z]);
    			s = this.$addShips_ringless("IST_thargoid", n, position, 15000);
    			break;
    		default:
    			// Make this scenario resemble the BBC Elite scenario.
    			s = this.$addShips_ringless("thargoid", n, origin, 17000);
    	}
    };
    
    this.$scenario_new_hunters = function() {
    	var hunters;
    	var i;
    	var l;
    	var n;
    	var ordinanceAvailable;
    	var ordinanceCount;
    	var origin = new Vector3D();
    	var r;
    	var s;
    
    	// this.$debugMessage("Hunters");
    
    	origin = this.origin_newScenario;
    
    	// Add ships
    	// -----------
    
    	// Add a heavy-hunter, in a group of its own.
    	hunters = system.addGroup("hunter-heavy", 1, origin, 17000);
    
    	if (hunters == null || hunters.ships == null) {
    		this.$error("Problem adding hunters");
    		return;
    	}
    
    	// Add a medium hunter and add it to the group
    	s = system.addShips("hunter-medium", 1, origin, 17000);
    	hunters.addShip(s[0]);
    	// Now ensure that all the members of the group-as-it-is-presently are somewhat beefy, and set their AI.
    	s = hunters.ships;
    	l = s.length;
    	i = l;
    	while (i--) {
    		if (s[i] && s[i].isValid) {
    			s[i].setAI("IST_hunterAI.plist");
    			if (s[i].energyRechargeRate < 6) {
    				s[i].energyRechargeRate *= 1.5; // equivalent of adding an energy unit.
    			}
    			if (s[i].canAwardEquipment("EQ_ECM")) {
    				s[i].awardEquipment("EQ_ECM");
    			}
    			if (s[i].canAwardEquipment("EQ_FUEL_INJECTION")) {
    				s[i].awardEquipment("EQ_FUEL_INJECTION");
    			}
    			if (s[i].accuracy < 5) {
    				s[i].accuracy += 3;
    			}
    		}
    	}
    
    	// Add some of the hunters defined by this OXP (though those hunters depend heavily on OXPs).
    	n = ~~(1 + (Math.random() * 8));
    	s = system.addShips("IST_hunter", n, origin, 16750);
    	if (s) {
    		l = s.length;
    		i = l;
    		while (i--) {
    			if (s[i] && s[i].isValid) {
    				hunters.addShip(s[i]);
    			}
    		}
    	}
    
    
    	// Now, for all the ships: add some ordinance and perhaps a bounty.
    	// ----------------------------------------------------------------
    
    	// First, create list of available ordinance.
    	ordinanceAvailable = ["EQ_QC_MINE"];
    	if (this.OXP_bombs) {
    		ordinanceAvailable.push("EQ_RMB_FRAG_MISSILE", "EQ_RMB_OVERRIDE_MISSILE", "EQ_RMB_THARGOID_MISSILE", "EQ_RMB_THARGOID_MISSILE");
    	}
    	if (this.OXP_Nexus) {
    		ordinanceAvailable.push("EQ_NEXUS_BUG_MISSILE", "EQ_NEXUS_BUG_MISSILE");
    		ordinanceAvailable.push("EQ_NEXUS_PREMIUM_MISSILE");
    		ordinanceAvailable.push("EQ_NEXUS_BASIC_MISSILE");
    	}
    	ordinanceCount = ordinanceAvailable.length;
    	i = ordinanceCount;
    	while (i--) {
    		ordinanceAvailable.push("EQ_HARDENED_MISSILE");
    	}
    
    	// Now run through the whole group . .
    	s = hunters.ships;
    	l = s.length;
    	i = l;
    	while (i--) {
    		if (s[i] && s[i].isValid) {
    			// this.$debugMessage("i is: "+i);
    			// Substitute a missile.
    			if (s[i].equipmentStatus("EQ_MISSILE") === "EQUIPMENT_OK") {
    				s[i].removeEquipment("EQ_MISSILE");
    				n = ~~(1 + (r * ordinanceCount));
    				s[i].awardEquipment(ordinanceAvailable[n]);
    			}
    		}
    	}
    	// Consider upping the bounty of one of the ships.
    	if (s[0] && s[0].isValid) {
    		r = Math.random();
    		if (r > 0.65) {
    			s[0].bounty = s[0].bounty + ~~(1 + (60 * r));
    		}
    	}
    };
    
    this.$scenario_new_genship = function() {
    	// this.$debugMessage("Tharg genship");
    
    	var offset = 185000;
    	var x = (Math.random() - 0.5) * offset;
    	var y = (Math.random() - 0.5) * offset;
    	var z = (Math.random() - 0.5) * offset;
    	var position = new Vector3D(this.origin_newScenario);
    	position = position.add([x, y, z]);
    	if (position.distanceTo(player.ship.position) < 27500) {
    		if (x > 0) {
    			x += 5000;
    		} else {
    			x -= 5000;
    		}
    		if (y > 0) {
    			y += 5000;
    		} else {
    			y -= 5000;
    		}
    		if (z > 0) {
    			z += 5000;
    		} else {
    			z -= 5000;
    		}
    		position.add([x, y, z]);
    	}
    	var n;
    	var s;
    	s = system.addShips("IST_genship", 1, position);
    	if (this.OXP_extraThargoids) {
    		n = 1 + ~~(1 + (Math.random() * 6));
    		s = system.addShips("extraThargoids_sweeper", n, position, 34000);
    		if (Math.random() < 0.7) {
    			n = ~~(1 + (Math.random() * 5));
    			s = system.addShips("IST_thargoidLurker", n, position, 34000);
    		}
    		return;
    	}
    	var r = Math.random();
    	if (r > 0.6) {
    		return;
    	}
    	n = ~~(1 + (r * 15));
    	s = system.addShips("IST_thargoidLurker", n, position, 34000);
    };
    
    
    // -----------
    // NAVY STUFF
    // ----------
    
    this.$willExit_extraNavy = function() {
    	this.$extraNavyCore();
    };
    
    this.$willExit_navyOnly = function() {
    	// this.$debugMessage("OnlyNavy onWillExit - start");
    
    	// postJump_timed removes non-navy. Yet, if we leave it at that, then Thargoids flash up on the scanner. 
    	// So, do 'this.$remove_removeMostNonNaval()' later in *this* routine, as well.
    	// Need also to stop various populators running - my 'iinterstellarTweaks_repopulate_interstellar_custom' fixes that.
    	// The REpopulator takes account of the 'onlyNavy' scenario, too.
    
    	this.$interstellarShift_forModifiedScenario();
    	// Requires, in 'postJump_timed', 'this.$returnShipToGroundZero_butPerhapsOffset'.
    
    	// Decide whether to fiddle with the navy (if there's more than a few naval ships extant).
    	var s = system.filteredEntities(this, this.$isNavy);
    	if (s.length > 2) {
    		// Do we replace it with my custom navy? (Largely to prevent the navy jumping out immediately)
    		if (Math.random() > this.scenario_modified_onlyNavy_replaceNavyChance) {
    			this.$willExit_navyOnlyNoReplacement();
    		} else {
    			this.$willExit_navyOnlyWithReplacement();
    		}
    	}
    	// else {
    	// 	this.$debugMessage("OnlyNavy - nothing special doing");
    	//}
    	// Do we add extra navy?
    	if (Math.random() < 0.2) {
    		this.$extraNavyCore();
    	}
    	this.$remove_removeMostNonNaval();
    	this.$stopMostNavyLeaving();
    };
    
    this.$stopMostNavyLeaving = function() {
    	var s = system.filteredEntities(this, this.$isNavy);
    	var i = s.length;
    	while (i--) {
    		if (s[i].ai !== "IST_milAI.plist" && s[i].ai !== "ferdelance3G_interstellarAI" && s[i].ai !== "spectreAI.plist" && s[i].ai !== "TCAT_raptorAI.plist" && s[i].ai !== "militaryFiascoCarrierAI" && s[i].ai !== "IST_navyPootleAI.plist") {
    			if (s[i].ai === "behemothFighterInterceptAI.plist") {
    				s[i].sendAIMessage("TARGET_LOST");
    				// The above should should prompt the ship to switch into behemothFighterDockingAI.plist.
    				// this.$debugMessage("$stopMostNavyLeaving - found behemothFighterInterceptAI AI");
    			} else {
    				// this.$debugMessage("$stopMostNavyLeaving - found a desired AI but not behemothFighterInterceptAI");
    				s[i].setAI("IST_navyPootleAI.plist");
    				// seems to miss ships with navyfrigateAI. They are added too late? Workaround is below.
    			}
    		}
    	}
    	this.timer_checkAndActOnNavyFrigates = new Timer(this, this.$checkAndActOnNavyFrigatesTimed, 0.1);
    	// this.$debugMessage("ONLY NAVY END");
    };
    
    
    // NO REPLACEMENT. Decide whether has been a battle.
    
    this.$willExit_navyOnlyNoReplacement = function() {
    	// this.$debugMessage("No replacement");
    	// See whether had a BATTLE.
    	if (Math.random() < scenario_modified_wasBattle_chance) {
    		return;
    	}
    	this.$willExit_navyOnlyNoReplacementWithBattle();
    };
    
    
    // REPLACEMENT. Decide whether has been a battle.
    
    this.$willExit_navyOnlyWithReplacement = function() {
    	// this.$debugMessage("Replacing ships");
    	// See if had a BATTLE
    	if (Math.random() <= scenario_modified_wasBattle_chance) {
    		this.$willExit_navyOnlyWithReplacementWithBattle();
    	} else {
    		this.$willExit_navyOnlyWithReplacement_noBattle();
    	}
    };
    
    // Replacement WITHOUT battle.
    
    this.$willExit_navyOnlyWithReplacement_noBattle = function() {
    	// REMOVE navy. (We will replace them shortly.)
    	var s = system.filteredEntities(this, this.$isNavy);
    	if (s == null) {
    		return;
    	}
    	var l = s.length;
    	if (l === 0) {
    		return;
    	}
    	if (l > 60) {
    		l = 60;
    	} // Do not remove more than this, 'cos causes problems for adding back.
    	var i = l;
    	while (i--) {
    		s[i].remove(true);
    	}
    	// Now REPLACE the navy with my navy.
    	s = system.addShips("IST_mil", l, [0, 0, 0], 25000);
    };
    
    // Replacement WITH BATTLE.
    this.$willExit_navyOnlyWithReplacementWithBattle = function() {
    	// this.$debugMessage("Was battle");
    
    	// REMOVE navy. (We will replace most of them shortly.)
    	var s = system.filteredEntities(this, this.$isNavy);
    	var l = s.length;
    	if (l > 0) {
    		if (l > 60) {
    			l = 60;
    		} // Do not remove more than this, 'cos causes problems for adding back.
    		var i = l;
    		while (i--) {
    			s[i].remove(true);
    		}
    		// Now REPLACE SOME the navy with mine - *some* because there has been a battle.
    		var n = ~~(1 + (Math.random() * l));
    		if (n > 60) {
    			n = 60;
    		}
    		s = system.addShips("IST_mil", n, [0, 0, 0], 25000);
    
    		// DAMAGE some of the ships.
    		n = s.length; // Get this length, rather than using old l, in case some of the ships could not be added.
    		i = ~~(1 + (Math.random() * n));
    		if (n > 15) {
    			n = 15;
    		}
    		// this.$debugMessage("Damaging "+n);
    		var d;
    		while (i--) {
    			if (s[i].isValid) {
    				d = 50 + (i * 25);
    				if (s[i].energy > d) {
    					s[i].energy -= d;
    					// i.e. if ship can take the damage without being destroyed, then deal the damage.
    				} else {
    					s[i].energy = d;
    				}
    			}
    		}
    	}
    	// WRECKAGE
    	this.$wreckage([0, 0, 0]);
    };
    
    
    // NO REPLACEMENT, BUT HAS BEEN BATTLE.
    this.$willExit_navyOnlyNoReplacementWithBattle = function() {
    	// this.$debugMessage("Was battle");
    	var s = system.filteredEntities(this, this.$isNavy);
    	if (s.length === 0) {
    		return;
    	}
    	var i;
    	if (Math.random() <= this.scenario_modified_wasBattle_wreckageOnly_chance) {
    		// Remove ALL ships; leave WRECKAGE ONLY
    		i = s.length;
    		while (i--) {
    			s[i].remove(true);
    		}
    		this.$wreckage([0, 0, 0]);
    	} else {
    		// Damage and remove ships
    		i = ~~(1 + (Math.random() * (s.length - 1)));
    		// Determine the faction to remove or damage.
    		var d;
    		while (i--) {
    			// The line below evaluates to true if and only if the variable is divisible by 2.
    			if (i % 2 === 0) {
    				if (s[i].isValid) {
    					s[i].remove(true);
    					// this.$debugMessage("Removed a ship");
    				}
    			} else {
    				d = 100 + (i * 2);
    				if (s[i].isValid) {
    					if (s[i].energy > d) {
    						s[i].energy -= d; // If the ship can take the damage, then deal it.
    					} else {
    						s[i].remove(true);
    					}
    				}
    			}
    		}
    		this.$wreckage([0, 0, 0]);
    	}
    };
    
    this.$checkAndActOnNavyFrigatesTimedCore = function() {
    	var s = system.filteredEntities(this, this.$isNavy_frigate);
    	if (s.length === 0) {
    		return;
    	}
    	var i = s.length;
    	while (i--) {
    		if (s[i].isValid && s[i].ai === "navyfrigateAI.plist") {
    			if (s[i].AIState === "HYPER_OUT" || s[i].AIState === "STAY_INTERSTELLAR" || s[i].AIState === "GLOBAL") {
    				// this.$debugMessage("$checkAndActOnNavyFrigatesTimedCore - found plist AI, in a desired state.");
    				s[i].setAI("IST_navyPootleAI.plist");
    			} else {
    				this.$debugMessage("$checkAndActOnNavyFrigatesTimedCore - found plist AI, but wrong state.");
    			}
    		} else if (s[i].ai === "nullAI.plist") {
    			// This could happen when there is a Javascript AI.
    			s[i].setAI("IST_navyPootleAI.plist");
    			// this.$debugMessage("$checkAndActOnNavyFrigatesTimedCore - Found null (Javascript?) AI.");
    		}
    	}
    };
    
    this.$checkAndActOnNavyFrigatesTimed = function $checkAndActOnNavyFrigatesTimed() {
    	// this.$debugMessage("$checkAndActOnNavyFrigatesTimed - fired.");
    	// Remove the timer.
    	if (this.timer_checkAndActOnNavyFrigates) {
    		if (this.timer_checkAndActOnNavyFrigates.isRunning) {
    			this.timer_checkAndActOnNavyFrigates.stop();
    		}
    		delete this.timer_checkAndActOnNavyFrigates;
    	}
    	this.$checkAndActOnNavyFrigatesTimedCore();
    };
    
    this.$wreckage = function(pos) {
    	this.$wreckageCore(pos);
    	// Consider doing it again:
    	if (Math.random() < 0.25) {
    		this.$wreckageCore(pos);
    	}
    };
    
    this.$wreckageCore = function(pos) {
    	var n;
    	var pos_new;
    	var r;
    	var s;
    	var x, y, z;
    
    	// Alloys
    	r = ~~(1 + (Math.random() * 6));
    	switch (r) {
    		case 1:
    			s = system.addShips("IST_alloy", r, pos, 19000);
    			break;
    		case 2:
    			s = system.addShips("IST_alloy", 2, pos, 20000);
    			break;
    		case 3:
    			n = 3 + ~~(1 + (Math.random() * 13));
    			s = system.addShips("IST_alloy", n, pos, 35000);
    			break;
    		default:
    			s = system.addShips("IST_alloy", r, pos, 18000);
    	}
    
    	// Tharglets
    	r = Math.random();
    	if (r < 0.6) {
    		n = ~~(1 + (Math.random() * 14));
    		if (r < 0.15) {
    			n += 10;
    		}
    		s = system.addShips("IST_Tharglet", n, pos, 29000);
    	}
    
    	// Derelicts
    	// Vipers
    	r = Math.random();
    	if (r < 0.12) {
    		x = (Math.random() * 56000) - 28000;
    		y = (Math.random() * 56000) - 28000;
    		z = (Math.random() * 56000) - 28000;
    		pos_new = new Vector3D(pos);
    		pos_new = pos_new.add([x, y, z]);
    		if (r < 0.07) {
    			n = 1;
    		} else {
    			n = 1 + ~~(1 + Math.random);
    		}
    		while (n--) {
    			x = (Math.random() * 56000) - 28000;
    			y = (Math.random() * 56000) - 28000;
    			z = (Math.random() * 56000) - 28000;
    			pos_new = pos_new.add([x, y, z]);
    			s = system.addShips("IST_derelictViper", 1, pos_new);
    		}
    	}
    	// Thargoids
    	r = Math.random();
    	if (r < 0.15) {
    		pos_new = new Vector3D(pos);
    		if (r < 0.05) {
    			n = 1;
    		} else {
    			n = 2 + ~~(1 + Math.random);
    		}
    		while (n--) {
    			x = (Math.random() * 56000) - 28000;
    			y = (Math.random() * 56000) - 28000;
    			z = (Math.random() * 56000) - 28000;
    			pos_new = pos_new.add([x, y, z]);
    			s = system.addShips("IST_derelictThargoid", 1, pos_new);
    		}
    	}
    };
    
    this.$remove_removeMostNonNaval = function() {
    	// this.$debugMessage("Removing non-navy");
    	var s;
    	if (this.OXP_InterstellarHelp && worldScripts.interstellar_help.interstellarHelp === "FOLLOWING") {
    		s = system.filteredEntities(this, this.$toRemove_nonNavy_butKeepInterstellarHelpShip);
    	} else {
    		s = system.filteredEntities(this, this.$toRemove_nonNavy);
    	}
    	var i = s.length;
    	// this.$debugMessage("Removing non-naval: "+i);
    	while (i--) {
    		s[i].remove(true);
    	}
    };
    
    
    // --------------------------
    // General New Scenario stuff
    // --------------------------
    
    this.$willExit_newScenario = function() {
    	this.$newScenarioOnExitCore();
    	this.$scenario_new_populate(); // Note: Can't do another '$remove_allFromNew' after this.
    };
    
    this.$newScenarioOnExitCore = function() {
    	var d, offset, x, y, z;
    
    	this.$remove_allFromNew();
    	offset = 300000000;
    	// Determine future ship position a.k.a. this.origin_newScenario.
    	// (Note: can't easily get rid of Thargoid carriers, so just ensure player a long way from them.)
    	x = 150000 + ~~(Math.random() * offset);
    	y = 150000 + ~~(Math.random() * offset);
    	z = 150000 + ~~(Math.random() * offset);
    	d = ~~(Math.random() * 9);
    	switch (d) {
    		case 1:
    			x *= -1;
    			break;
    		case 2:
    			y *= -1;
    			break;
    		case 3:
    			z *= -1;
    			break;
    		case 4:
    			x *= -1;
    			y *= -1;
    			break;
    		case 5:
    			x *= -1;
    			y *= -1;
    			z *= -1;
    			break;
    		case 6:
    			y *= -1;
    			z *= -1;
    			break;
    		case 7:
    			x *= -1;
    			z *= -1;
    			break;
    		default:
    			break;
    	}
    	this.$interstellarShift_forNewScenario(x, y, z);
    	this.$remove_allFromNew(); // again
    };
    
    // Carrier mass:	3016,637184	hex: B3CE3B00
    // Crusier mass:	1201996	hex: 12574C
    // Warship mass:	848632
    this.$extraNavyCore = function() {
    	// Some code here adapted from "Thargorn_Witchspace_Battle" by Arexack Heretic and Eric Walch.
    	if (!player.ship) {
    		return;
    	}
    	var s;
    	var baseNumberNavyToAdd = ~~(1 + (Math.random() * 5));
    	if (this.scenario !== "onlyNavy") {
    		s = system.entitiesWithScanClass("CLASS_THARGOID");
    		var c = s.filter(this.$shipWeight_heavy).length;
    		if (c > 2) {
    			baseNumberNavyToAdd += (3 + ~~(1 + (Math.random() * 5)));
    		}
    		if (baseNumberNavyToAdd < 12) {
    			c = s.filter($shipWeight_medium).length;
    			if (c > 4) {
    				baseNumberNavyToAdd += 3;
    			}
    		}
    	}
    	// Now actually add the ship(s)
    	s = system.addShips("IST_mil", baseNumberNavyToAdd, [0, 0, 0], 24500);
    	if (this.OXP_StarDestroyer && (system.allShips.length < 50) && (Math.random() < 0.05)) {
    		s = system.addShips("IST_stardestroyer", 1, [0, 0, 0], 25000);
    	}
    };
    
    this.$willExit_bugsOnly = function() {
    	this.$willExit_bugsOnlyPreliminaries();
    	if (Math.random() <= scenario_modified_wasBattle_chance) {
    		this.$willExit_bugsOnlyWasBattle();
    	} else {
    		this.$willExit_bugsOnlyNoBattle();
    	}
    	this.$willExit_bugsOnlyPostscript();
    	// this.$debugMessage("ONLY BUGS END");
    };
    
    this.$willExit_bugsOnlyPreliminaries = function() {
    	this.$remove_removeMostThargoid();
    	this.$interstellarShift_forNewScenario();
    	if ((this.OXP_extraThargoids) && (Math.random() <= this.scenario_modified_onlyBugs_addSweeperChance)) {
    		var s = system.addShips("extraThargoids_sweeper", 1, [0, 0, 0], 25000);
    	}
    };
    
    this.$willExit_bugsOnlyWasBattle = function() {
    	// this.$debugMessage("Only bugs - Was battle");
    	var s = system.entitiesWithScanClass("CLASS_THARGOID");
    	var l = s.length;
    	var i;
    	if ((l < 3) || (Math.random() <= this.scenario_modified_wasBattle_wreckageOnly_chance)) {
    		i = l;
    		while (i--) {
    			s[i].remove(true);
    		}
    		// this.$debugMessage("Wreckage only");
    	} else {
    		i = ~~(1 + (Math.random() * (l - 1)));
    		// = number of thargoids to remove or damage.
    		// this.$debugMessage("Was "+l); this.$debugMessage("Removing or damaging "+i);
    		while (i--) {
    			if (i > 3) {
    				s[i].remove(true);
    			} else {
    				s[i].energy -= 40 + (i * 40);
    				if (s[i].energy < 1) {
    					s[i].remove(true);
    				}
    			}
    		}
    	}
    	this.$wreckage([0, 0, 0]);
    };
    
    this.$willExit_bugsOnlyNoBattle = function() {
    	var r;
    	if (Math.random() > 0.5) {
    		r = system.scrambledPseudoRandomNumber(700010);
    	} else {
    		r = Math.random();
    	}
    	// scrambledPseudoRandomNumber seed here SAME as scenario_new_warships_chance
    	if (r > this.scenario_modified_onlyBugs_multiplyBugsChance) {
    		return;
    	}
    	// Otherwise ..
    	var s;
    	s = system.addShips("IST_thargoid", 4, [0, 0, 0], 27000);
    	if (!this.OXP_extraThargoids) {
    		return;
    	}
    	// Otherwise ..
    	r = Math.random();
    	if (r > 0.3) {
    		return;
    	}
    	// Otherwise ..
    	var l;
    	if (r > 0.1) {
    		l = 2;
    	} else {
    		l = 3;
    	}
    	s = system.addShips("uberBuggly", l, [0, 0, 0], 20000);
    };
    
    this.$willExit_bugsOnlyPostscript = function() {
    	var l, offset, s, x, y, z;
    	if (this.OXP_StarDestroyer && (Math.random() < 0.03)) {
    		offset = 15000;
    		x = (Math.random() - 0.5) * offset;
    		y = (Math.random() - 0.5) * offset;
    		z = (Math.random() - 0.5) * offset;
    		s = system.addShips("IST_stardestroyer", 1, [x, y, z]);
    	}
    	if (this.OXP_GenShips) {
    		if (Math.random() <= this.scenario_modified_onlyBugs_thargGenship_chance) {
    			offset = 175000;
    			x = (Math.random() - 0.5) * offset;
    			y = (Math.random() - 0.5) * offset;
    			z = (Math.random() - 0.5) * offset;
    			s = system.addShips("IST_genship", 1, [x, y, z]);
    		}
    	}
    	if (this.OXP_aliens && Math.random() <= this.scenario_modified_onlyBugs_aliensChance) {
    		l = 2 + ~~(1 + (Math.random() * 20));
    		s = system.addShips("scorpax", l, [0, 0, 0], 27000);
    		if (Math.random() < 0.2) {
    			s = system.addShips("scorpax", 7, [0, 0, 0], 25000);
    		}
    	} else if (Math.random() <= this.scenario_modified_onlyBugs_rebelChance) {
    		l = 2 + ~~(1 + (Math.random() * 15));
    		if (l > 9 && Math.random() < 0.1) {
    			l += 20;
    		}
    		s = system.addGroup("thargoidRebel", l, [0, 0, 0], 15000);
    		log("InterstellarTweaks", "Thargoid rebels added.");
    	}
    };
    
    
    /*
    ----------------------------------------------------------------------------------------------
    EXITED witchspace.
    This code is called after a witchspace jump has concluded and the tunnel effect has been shown.
    -----------------------------------------------------------------------------------------------
    */
    
    this.shipExitedWitchspace = function() {
    	// this.$debugMessage("STAGE *4* - shipExitedWitchspace");
    	if (!player.ship || (this.OXP_TWD && worldScripts["murphy-thargoid-drive.js"].jumping)) {
    		return;
    	}
    	if (this.jumpIsGalactic) {
    		this.jumpIsGalactic = false;
    		return;
    	}
    	this.jumpIsGalactic = false;
    	this.$exited_timed(); // Need this as a seperate routine, so that rescheduled timer can, if necessary, call it
    };
    
    this.$exited_timed = function $exited_timed() {
    	if (!system.isInterstellarSpace) {
    		// STELLAR
    		this.$willExit_constants_modular();
    		return;
    	}
    	// Otherwise ..
    	// INTERSTELLAR SPACE
    	if (this.beforeExitIsRunning) {
    		if (this.timer_resched && this.timer_resched.isRunning) {
    			this.$error("Problem 1 with modified WS exit. There may be a syntax error elsewhere in the script.");
    			return;
    		} else {
    			this.$timerDelete_resched();
    			this.timer_resched = new Timer(this, this.$exited_timed, 0.4);
    			return; // N.B.
    		}
    	}
    	// Otherwise ..
    	if (this.timer_interstellarPostWillExit && this.timer_interstellarPostWillExit.isRunning) {
    		if (this.timer_resched && this.timer_resched.isRunning) {
    			this.$error("Problem 2 with modified WS exit. There may be a syntax error elsewhere in the script.");
    			return;
    		} else {
    			this.$timerDelete_resched();
    			this.timer_resched = new Timer(this, this.$exited_timed, 0.4);
    		}
    		return; // N.B.
    	}
    	// Otherwise ..
    	this.$timerDelete_resched();
    	this.$timerDelete_interstellarPostWillExit();
    	this.$timerDelete_returnEtc();
    	if (this.scenario === "" || this.scenario === "extraNavy") {
    		this.$willExit_constants_modular();
    	} else {
    		// In this case - case of onlyBugs, onlyNavy, or newScenario - do 'alwaysApplicable' later.
    		this.$awardMASCetc(); // this removed later on
    		this.timer_returnEtc = new Timer(this, this.$postJump_timed, this.scenario_delayBeforeReturnShipToGroundZero);
    		// What this routine does depends on the modification. But will always do $willExit_constants_modular.
    	}
    	// this.$debugMessage("EXIT: "+this.scenario);
    };
    
    this.$awardMASCetc = function() {
    	if (!player.ship) {
    		return;
    	}
    	var ps = player.ship; // for speed, but changes won't affect the original variable
    	// 1 = none = 1; 2 = had already; 3 = damaged.
    	this.MASC_status = 0;
    	this.spoofStatus = 0;
    	var equipmentStatus;
    	equipmentStatus = ps.equipmentStatus("EQ_MILITARY_JAMMER");
    	if (equipmentStatus === "EQUIPMENT_OK") {
    		this.MASC_status = 2;
    	} else if (equipmentStatus === "EQUIPMENT_DAMAGED") {
    		player.ship.setEquipmentStatus("EQ_MILITARY_JAMMER", "EQUIPMENT_OK");
    		this.MASC_status = 3;
    	} else {
    		this.MASC_status = 1;
    		player.ship.awardEquipment("EQ_MILITARY_JAMMER");
    	}
    	// REMOVE SPOOF
    	equipmentStatus = ps.equipmentStatus("EQ_MISSILE_SPOOF");
    	if (equipmentStatus === "EQUIPMENT_OK") {
    		this.spoofStatus = 2;
    		player.ship.removeEquipment("EQ_MISSILE_SPOOF");
    	} else if (equipmentStatus === "EQUIPMENT_DAMAGED") {
    		this.spoofStatus = 3;
    	} else {
    		this.spoofStatus = 1;
    	}
    };
    
    this.$stripMASC_etc = function() {
    	if (!player.ship) {
    		return;
    	}
    	// MASC
    	// 1 = none = 1; 2 = had already; 3 = damaged.
    	switch (this.MASC_status) {
    		case 1:
    			player.ship.removeEquipment("EQ_MILITARY_JAMMER");
    			break;
    			// Didn't have it before, so remove
    		case 2:
    			break;
    			// Had it before, so leave it on ship.
    		case 3:
    			player.ship.setEquipmentStatus("EQ_MILITARY_JAMMER", "EQUIPMENT_DAMAGED");
    			break;
    			// Restore it to broken condition
    	}
    	// SPOOF
    	switch (this.spoofStatus) {
    		case 1:
    			break;
    			// Didn't have it before, so didn't remove it, so need do nothing.
    		case 2:
    			player.ship.awardEquipment("EQ_MISSILE_SPOOF");
    			break;
    			// Had it before, so restore.
    		case 3:
    			player.ship.awardEquipment("EQ_MISSILE_SPOOF");
    			player.ship.setEquipmentStatus("EQ_MISSILE_SPOOF", "EQUIPMENT_DAMAGED");
    			break;
    			// Return it to damaged.
    	}
    	this.MASC_status = 0;
    	this.spoofStatus = 0;
    };
    
    this.$postJump_timed = function $postJump_timed() {
    	// this.$debugMessage("STAGE *5* - postJump_timed. Tweak value is: "+this.scenario);
    	if (system.isInterstellarSpace) {
    		switch (this.scenario) {
    			case "onlyNavy":
    				this.$remove_removeMostNonNaval();
    				this.$returnShipToGroundZero_butPerhapsOffset();
    				break;
    			case "onlyBugs":
    				this.$remove_removeMostThargoid();
    				this.$returnShipToGroundZero_butPerhapsOffset();
    				break;
    			case "newScenario":
    				if (!this.origin_newScenario) {
    					this.$debugMessage("NO FUTURE POSITION!");
    					this.$stripMASC_etc();
    					this.$willExit_constants_modular();
    					return;
    				}
    				// Otherwise ..
    				if (!player.ship) {
    					this.$stripMASC_etc();
    					return;
    				}
    				player.ship.position = this.origin_newScenario;
    				break;
    		}
    		this.$stripMASC_etc(); // Don't need this if in normal space, 'cos won't have fiddled with equipment.
    		if (this.OXP_hiredGuns) {
    			this.$hiredGunsStuff();
    		}
    	}
    	this.$willExit_constants_modular();
    	// this.$debugMessage("End of returnEtc");
    };
    
    this.$willExit_constants_modular = function() {
    	// this.$debugMessage("$willExit_constants_modular");
    	if (!player.ship) {
    		return;
    	}
    	if (system.isInterstellarSpace) {
    		var i, s;
    		if (this.OXP_InterstellarHelp && (Math.random() < 0.7)) {
    			// Do this here = as late as possible.
    			// Note that the interstellar_help OXP only spawns these ships on a< 0.3 chance.
    			s = system.filteredEntities(this, this.$isInterstellarHelpee);
    			i = s.length;
    			while (i--) {
    				s[i].remove(true);
    			}
    		}
    		if (this.OXP_aliens && (Math.random() < 0.35)) {
    			s = system.filteredEntities(this, this.$isAlien);
    			i = s.length;
    			while (i--) {
    				s[i].remove(true);
    			}
    		}
    	}
    	// End of 'if (system.isInterstellarSpace)'
    
    	if (!this.willDie) {
    		this.$check_getSickOrIfDieFromIt();
    		// Having this here, rather than below the increase to sickness chance, prevents getting sick on first jump (presuming that initial sickness chance set to zero).
    	}
    	// Now check whether STILL not scheduled to die.
    	if (!this.willDie) {
    		if (!this.isSick && this.currentChanceOfSickness < 0.5) {
    			this.currentChanceOfSickness += 0.007;
    			// 0.007. This is where, through withchspace jumps, we increase the chance of the player getting sick.
    		}
    	} else {
    		// Don't destroy the player ship before other OXPs have chance to do their stuff. Also, need delay to allow user to read messages.
    		// Disable escape pod.
    		if (player.ship.equipmentStatus("EQ_ESCAPE_POD") === "EQUIPMENT_OK" || player.ship.equipmentStatus("EQ_ESCAPE_POD") === "EQUIPMENT_DAMAGED") {
    			player.ship.removeEquipment("EQ_ESCAPE_POD");
    		}
    		if (!this.timer_die) {
    			// this.$debugMessage("setting die timer");
    			this.timer_die = new Timer(this, this.$die_timed, 4);
    			// 4 Seems the right value.
    			// this.$debugMessage("set die timer OK");
    		}
    	}
    };
    
    this.$hiredGunsStuff = function() {
    	if (!player.ship.isValid || !player.ship.position) {
    		return;
    	}
    	// this.$debugMessage("Removing - escort stuff");
    	var s = system.filteredEntities(this, this.$isHiredGun);
    	if (s.length < 1) {
    		return;
    	}
    	var d, i, x, y, z;
    	var ps = player.ship; // for speed, but changes won't affect the original variable
    	i = s.length;
    	while (i--) {
    		d = s[i].position.distanceTo(ps.position);
    		if (d > 40000) {
    			x = ~~((Math.random() - 0.5) * 25600);
    			y = ~~((Math.random() - 0.5) * 25600);
    			z = ~~((Math.random() - 0.5) * 25600);
    			s[i].position = ps.position.add([x, y, z]);
    			// displace it / them a bit. (If leave them VERY displaced, throws exceptions, I think.)
    		}
    	}
    };
    
    this.$returnShipToGroundZero_butPerhapsOffset = function() {
    	if (!player.ship) {
    		return;
    	}
    	if (Math.random() > this.scenario_modified_chanceOffsetFromAction) {
    		player.ship.position = [0, 0, 0];
    		return;
    	}
    	// Otherwise ..
    	var r, x, y, z;
    	// this.$debugMessage("OFFSET");
    	x = (Math.random() * 35000) + 2000;
    	y = (Math.random() * 35000) + 2000;
    	z = (Math.random() * 35000) + 2000;
    	r = ~~(1 + (Math.random() * 8));
    	switch (r) {
    		case 1:
    			x *= -1;
    			break;
    		case 2:
    			y *= -1;
    			break;
    		case 3:
    			z *= -1;
    			break;
    		case 4:
    			x *= -1;
    			y *= -1;
    			break;
    		case 5:
    			x *= -1;
    			y *= -1;
    			z *= -1;
    			break;
    		case 6:
    			y *= -1;
    			z *= -1;
    			break;
    		case 7:
    			x *= -1;
    			z *= -1;
    			break;
    		default:
    			break;
    	}
    	player.ship.position = [x, y, z];
    };
    
    this.$die_timed = function $die_timed() {
    	// The above format, with its repetition of the function name, is right. See http://aegidian.org/bb/viewtopic.php?p=257147#p257147.
    	this.$timerDelete_die();
    	// Do not automatically delete it, because it might not be running; other things can call this.
    	if (!player.ship) {
    		return;
    	}
    	// Next two lines are to avoid auto-eject nonsense, etc.
    	if (player.ship.equipmentStatus("EQ_AUTO_EJECT") === "EQUIPMENT_OK") {
    		player.ship.removeEquipment("EQ_AUTO_EJECT");
    	}
    	if (player.ship.equipmentStatus("EQ_EEU") === "EQUIPMENT_OK") {
    		player.ship.removeEquipment("EQ_EEU");
    	}
    	player.ship.explode();
    };
    
    this.$check_getSickOrIfDieFromIt = function() {
    	if (this.willDie) {
    		return;
    	}
    	if (this.isSick) {
    		if (Math.random() > this.sickness_chanceKills) {
    			this.$messagePlayer("You still have WITCHSPACE SICKNESS. Dock at a main station! Do not jump!", 15);
    			this.mySound_warning.play();
    		} else {
    			this.willDie = true;
    			this.$messagePlayer("You have TERMINAL WITCHSPACE SICKNESS!", 15);
    			this.mySound_warning.play();
    		}
    		return;
    	}
    	// Otherwise ..
    	var r;
    	if (this.OXP_wormDrones) {
    		if ((missionVariables.mauiby_multipleJumps) && (this.currentChanceOfSickness > 0)) {
    			r = this.currentChanceOfSickness / 1.7;
    		} else {
    			r = this.currentChanceOfSickness;
    		}
    	} else {
    		r = this.currentChanceOfSickness;
    	}
    	// this.$debugMessage("Sickness chance: "+r);
    	if (Math.random() < r) {
    		this.isSick = true;
    		this.$messagePlayer("You have developed WITCHSPACE SICKNESS. Jumping before docking at a main station may kill you!", 15);
    		this.mySound_warning.play();
    		this.currentChanceOfSickness = this.sickness_baseChanceOfGetting; // Let us, thusly, reset this here.
    	}
    };
    
    this.$damageDrive = function() {
    	if (!player.ship) {
    		return;
    	}
    	if (player.ship.equipmentStatus("EQ_BREAKABLE_WITCHDRIVE") != "EQUIPMENT_OK") {
    		return;
    	}
    	player.ship.setEquipmentStatus("EQ_BREAKABLE_WITCHDRIVE", "EQUIPMENT_DAMAGED");
    };
    
    this.$OXP_TCAT_override = function() {
    	if (this.OXP_TCAT) {
    		missionVariables.otherOXPs_TCAT_override = true;
    		this.TACT_overrode = true;
    	} else {
    		this.TACT_overrode = false;
    	}
    };
    
    this.$TCAT_reset = function() {
    	if (this.TACT_overrode) {
    		missionVariables.otherOXPs_TCAT_override = false;
    		this.TACT_overrode = false;
    	}
    };
    
    this.$OXP_Threat_restrict = function() {
    	this.threatOXP_modify = true;
    	// sic - and cannot change this variable name (without changing the Threat OXP)
    };
    
    this.$threatOXP_reset = function() {
    	this.threatOXP_modify = false;
    	// sic - and cannot change this variable name (without changing the Threat OXP)
    };
    
    this.$remove_removeMostThargoid = function() {
    	var s;
    	// this.$debugMessage("Removing non-bugs");
    	if ((this.OXP_InterstellarHelp) && (worldScripts.interstellar_help.interstellarHelp === "FOLLOWING")) {
    		s = system.filteredEntities(this, this.toRemove_nonThargoid_alt);
    	} else {
    		s = system.filteredEntities(this, this.toRemove_nonThargoid);
    	}
    	var i = s.length;
    	while (i--) {
    		s[i].remove(true);
    	}
    };
    
    this.$interstellarShift_forNewScenario = function(x, y, z) {
    	this.origin_newScenario = [x, y, z];
    	// Vital. This is where this.origin_newScenario gets set, for the new scenario.
    	this.$interstellarShiftCore();
    };
    
    this.$interstellarShift_forModifiedScenario = function() {
    	this.$interstellarShiftCore();
    };
    
    this.$interstellarShiftCore = function() {
    	// this.$debugMessage("Interstellar shift");
    	if (!player.ship.isValid || !player.ship.position) {
    		return;
    	}
    	player.ship.position = [350000000, 350000000, 350000000];
    };
    
    
    /*
    ======
    TIMERS
    ======
    */
    
    this.$timerDelete_all_exceptDie = function() {
    	// Remove short interval timers before other timers.
    	this.$timerDelete_returnEtc();
    	this.$timerDelete_interstellarPostWillExit();
    	this.$timerDelete_resched();
    	this.$timerDelete_radiation();
    	this.$timerDelete_checkAndActOnNavyFrigates();
    	this.$timerDelete_stellar();
    	this.$timerDelete_misjumpWarning();
    	this.$timerDelete_thargAmbush();
    };
    
    this.$timerDelete_all = function() {
    	this.$timerDelete_die();
    	this.$timerDelete_all_exceptDie();
    };
    
    this.$timerDelete_radiation = function() {
    	if (this.timer_radiationStageOne_damage1) {
    		if (this.timer_radiationStageOne_damage1.isRunning) {
    			this.timer_radiationStageOne_damage1.stop();
    		}
    		delete this.timer_radiationStageOne_damage1;
    	}
    	if (this.timer_radiationStageOne_damage2) {
    		if (this.timer_radiationStageOne_damage2.isRunning) {
    			this.timer_radiationStageOne_damage2.stop();
    		}
    		delete this.timer_radiationStageOne_damage2;
    	}
    	if (this.timer_radiationStageTwo) {
    		if (this.timer_radiationStageTwo.isRunning) {
    			this.timer_radiationStageTwo.stop();
    		}
    		delete this.timer_radiationStageTwo;
    	}
    };
    
    this.$timerDelete_thargAmbush = function() {
    	if (!this.timer_thargAmbush) {
    		return;
    	}
    	if (this.timer_thargAmbush.isRunning) {
    		this.timer_thargAmbush.stop();
    	}
    	delete this.timer_resched;
    };
    
    this.$timerDelete_resched = function() {
    	if (!this.timer_resched) {
    		return;
    	}
    	if (this.timer_resched.isRunning) {
    		this.timer_resched.stop();
    	}
    	delete this.timer_resched;
    };
    
    this.$timerDelete_returnEtc = function() {
    	if (!this.timer_returnEtc) {
    		return;
    	}
    	if (this.timer_returnEtc.isRunning) {
    		this.timer_returnEtc.stop();
    	}
    	delete this.timer_returnEtc;
    };
    
    this.$timerDelete_interstellarPostWillExit = function() {
    	if (!this.timer_interstellarPostWillExit) {
    		return;
    	}
    	if (this.timer_interstellarPostWillExit.isRunning) {
    		this.timer_interstellarPostWillExit.stop();
    	}
    	delete this.timer_interstellarPostWillExit;
    };
    
    this.$timerDelete_checkAndActOnNavyFrigates = function() {
    	if (!this.timer_checkAndActOnNavyFrigates) {
    		return;
    	}
    	if (this.timer_checkAndActOnNavyFrigates.isRunning) {
    		this.timer_checkAndActOnNavyFrigates.stop();
    	}
    	delete this.timer_checkAndActOnNavyFrigates;
    };
    
    this.$timerDelete_stellar = function() {
    	if (!this.timer_stellar) {
    		return;
    	}
    	if (this.timer_stellar.isRunning) {
    		this.timer_stellar.stop();
    		delete this.timer_stellar;
    	}
    };
    
    this.$timerDelete_die = function() {
    	if (!this.timer_die) {
    		return;
    	}
    	if (this.timer_die.isRunning) {
    		this.timer_die.stop();
    	}
    	delete this.timer_die;
    };
    
    this.$timerDelete_misjumpWarning = function() {
    	if (!this.timer_misjumpWarning) {
    		return;
    	}
    	if (this.timer_misjumpWarning.isRunning) {
    		this.timer_misjumpWarning.stop();
    	}
    	delete this.timer_misjumpWarning;
    };
    
    
    /*
    ============================================================
    10.	ENTITY-PICKERS (/filters) etc.
    	NB: Breaking such lines for readability breaks the code!
    ============================================================
    */
    
    this.$isHiredGun = function(e) {
    	return e.isShip && e.hasRole("hiredGuns_escort");
    };
    
    this.$isEscort = function(e) {
    	return e.isShip && (e.primaryRole === "escort" || e.primaryRole === "escort-medium" || e.primaryRole === "escort-heavy");
    };
    
    this.$isAlien = function(e) {
    	return e.primaryRole === "kephalan" || e.primaryRole === "odonatean" || e.primaryRole === "scorpax";
    };
    
    // Function for telling whether item is in array.
    this.$isArrayed = function(value, array) {
    	return (worldScripts.IST_masterScript._index_in_list(value, array) > -1);
    };
    
    this.$isBillboard = function(e) {
    	return e.isShip && e.hasRole("asteroid-billboard");
    };
    
    this.$isBug = function(e) {
    	return e.isShip && e.isThargoid;
    };
    
    this.$isInterstellarHelpee = function(e) {
    	return e.primaryRole === "interstellar_help_trader";
    };
    
    this.$isNavy = function(e) {
    	return e.isShip && (e.isPolice || e.scanClass === "CLASS_MILITARY");
    };
    
    this.$isNavy_carrier = function(e) {
    	return e.isShip && (e.hasRole("behemoth") || e.hasRole("leviathan"));
    };
    
    this.$isNavy_frigate = function(e) {
    	return e.isShip && e.primaryRole === "navy-frigate";
    };
    
    this.$isThargoid_not = function(e) {
    	return e.isShip && !e.isThargoid;
    };
    
    this.$isThargoid_normal = function(e) {
    	return e.isShip && e.isThargoid && e.primaryRole !== "thargoidRebel";
    };
    
    this.$isThargoid_battleship = function(e) {
    	return e.isShip && e.isThargoid && e.name === "Thargoid Thargorn Battleship";
    };
    // Note: the battleship lacks a distinct role, so we have to use its name.
    
    this.$NPCsToIrradiate = function(e) {
    	return e.isShip && !e.isPlayer;
    };
    
    this.$shipWeight_heavy = function(e) {
    	return e.mass >= 120000000;
    };
    
    this.$shipWeight_medium = function(e) {
    	return e.mass > 1200000 && e.mass < 120000000;
    };
    
    this.$toRemove_newScenario = function(e) {
    	return e.isShip && !e.isPlayer && !e.hasRole("hiredGuns_escort") && e.primaryRole !== "interstellar_help_trader" && !e.hasRole("ecl_escape_pod_beacon") && !e.hasRole("escape-capsule") && !e.hasRole("uberBuggly") && !e.hasRole("generationship");
    };
    
    this.$toRemove_nonNavy = function(e) {
    	return e.isShip && !e.isPlayer && !e.isPolice && e.scanClass !== "CLASS_MILITARY" && !e.hasRole("IST_mil") && !e.hasRole("spectre") && !e.hasRole("IST_alien_cargopod") && !e.hasRole("asteroid") && !e.hasRole("IST_derelict") && !e.hasRole("escape-capsule") && !e.hasRole("uberBuggly") && !e.hasRole("generationship") && e.primaryRole !== "IST_alloy" && e.primaryRole !== "IST_Tharglet" && e.primaryRole !== "IST_cargopod" && e.primaryRole !== "hiredGuns_escort" && e.primaryRole !== "ecl_escape_pod_beacon";
    };
    
    this.$toRemove_nonNavy_butKeepInterstellarHelpShip = function(e) {
    	return e.isShip && !e.isPlayer && !e.isPolice && e.scanClass !== "CLASS_MILITARY" && !e.hasRole("IST_mil") && !e.hasRole("spectre") && !e.hasRole("IST_alien_cargopod") && !e.hasRole("asteroid") && !e.hasRole("IST_derelict") && !e.hasRole("escape-capsule") && !e.hasRole("uberBuggly") && !e.hasRole("generationship") && e.primaryRole !== "IST_alloy" && e.primaryRole !== "IST_Tharglet" && e.primaryRole !== "IST_cargopod" && e.primaryRole !== "hiredGuns_escort" && e.primaryRole !== "ecl_escape_pod_beacon" && e.primaryRole !== "interstellar_help_trader";
    	// The last entry is how this function diverges from its other version.
    };
    
    this.toRemove_nonThargoid = function(e) {
    	return e.isShip && !(e.isPlayer || e.isThargoid || e.primaryRole === "IST_Tharglet" || e.primaryRole === "hiredGuns_escort" || e.primaryRole === "IST_alloy" || e.primaryRole === "IST_alien_cargopod" || e.primaryRole === "IST_cargopod");
    };
    
    this.toRemove_nonThargoid_alt = function(e) {
    	return e.isShip && !(e.isPlayer || e.isThargoid || e.primaryRole === "IST_Tharglet" || e.primaryRole === "hiredGuns_escort" || e.primaryRole === "IST_alloy" || e.primaryRole === "IST_alien_cargopod" || e.primaryRole === "IST_cargopod" || e.primaryRole !== "interstellar_help_trader");
    };
    
    this.$toRemove_radiationScenario = function(e) {
    	return e.isShip && !e.isPlayer && !e.hasRole("hiredGuns_escort") && e.energy < 150;
    };
    
    this.$toRemove_radiationScenario_alt = function(e) {
    	return e.isShip && !e.isPlayer && e.energy < 150;
    };
    
    
    /*
    =================
    11. MISC ROUTINES
    =================
    */
    
    this.$thargAmbush_timed = function $thargAmbush_timed() {
    	this.$timerDelete_thargAmbush();
    	var r = Math.random();
    	var s;
    	var n = 1 + ~~(1 + (Math.random() * 6));
    	if (this.OXP_extraThargoids && (r < 0.7)) {
    		s = system.addShips("extraThargoids_buggly", n, this.origin_ambush, 8000);
    	} else {
    		s = system.addShips("thargoid", n, this.origin_ambush, 8000);
    	}
    };
    
    
    // The 'no rings' routines are not needed in the 'new scenario'
    // - because ships are added there far from the 'witchpoint'.
    this.$addShips_ringless = function(role, count, position, radius) {
    	// this.$debugMessage("ADD SHIPS WITH NO RINGS");
    	// Sanity (/argument) check.
    	var i;
    	if (count < 1) {
    		this.$error("Bad count argument <" + count + "> for function addShips_ringless");
    		i = 1; // fix the problem.
    	} else {
    		i = count;
    	}
    
    	var offset, s;
    	offset = new Vector3D([50000, 50000, 50000]);
    	s = system.addShips(role, count, offset, radius);
    	if (s == null) {
    		return;
    	}
    	// Create ship at position 'offset', which far from WP.
    
    	if (position == null) {
    		if (this.debug) {
    			this.$error("position is null: addShips_ringless");
    		}
    		return;
    	}
    
    	// Move the ships.
    	offset = new Vector3D(position).subtract(offset);
    	while (i--) {
    		if (s[i].isValid) {
    			s[i].position = s[i].position.add(offset);
    			// move s to (position-to-have plus offset).
    		}
    	}
    	return s;
    };
    
    // The following function seems unused. So, I have commented it out.
    /*
    this.$addGroup_ringless = function(role,count,position,radius) 
    {
    	var i;
    
    	// Sanity (/argument) check.
    	if (count < 1) {
    		this.$error("Bad count argument <" + count + "> for function $addGroup_ringless");
    		i = 1; // fix the problem.
    	} else {
    		i = count;
    	}
    
    	var offset;
    	var g;
    	var s;
    	// Create the ships
    	offset = new Vector3.D([50000,50000,50000]);
    	g = system.addGroup(role,count,offset,radius);
    	s = g.ships;
    	if (s == null) {return;}
    
    	if (position == null) {
    		if (this.debug) {this.$error("position is null: addGroup_ringless");}
    		return;
    	}
    
    	// Move the ships.
    	offset = new Vector3D(position).subtract(offset);
    	while (i--) {
    		if (s[i] && s[i].isValid) {
    			s[i].position=s[i].position.add(offset);
    		}
    	}
    	return g;
    };
    */
    
    // The 'ring' code below adapted from the YourAdHere expansion pack, by Dr Nil and contributors.
    // But I am unsure it is working.
    
    this.$addShips_rings = function(role, count, position, radius) {
    	// this.$debugMessage("ADD SHIPS WITH RINGS");
    	var i;
    
    	// Sanity (/argument) check.
    	if (count < 1) {
    		this.$error("Bad count argument <" + count + "> for function $addShips_rings");
    		i = 1; // fix the problem.
    	} else {
    		i = count;
    	}
    
    	// Create the ships at near WP - so that they have rings.
    	var s = system.addShips(role, count, [0, 0, 0], radius);
    
    	if (position == null) {
    		if (this.debug) {
    			this.$error("position is null: addShips_rings");
    		}
    		return;
    	}
    
    	// Move the ships.
    	while (i--) {
    		if (s[i] && s[i].isValid) {
    			s[i].position = s[i].position.add(position);
    		}
    	}
    	return s;
    };
    
    this.$roleExists = function(roleString) {
    	var dummyShips = system.addShips(roleString, 1, [100000, 100000, 100000]);
    	if (dummyShips == null) {
    		return false;
    	}
    	var exists = (dummyShips.length == 1);
    	if (exists) {
    		if (dummyShips[0].isValid) {
    			dummyShips[0].remove(true);
    		}
    	}
    	return exists;
    };
    
    
    /*
    ============================
    12.	ERROR & MESSAGE HANDLING
    ============================
    */
    
    this.$messagePlayer = function(txt, t) {
    	if (this.debug) {
    		if (!txt) {
    			player.consoleMessage("Problem with message text!", 30);
    			return;
    		}
    		if (!t) {
    			player.consoleMessage("Problem with message time!", 30);
    			return;
    		}
    		if (t < 1) {
    			player.consoleMessage("Problem with message time!", 30);
    			return;
    		}
    	}
    	player.consoleMessage(txt, t);
    };
    
    // THIS ROUTINE DOES NOTHING IF this.debug IS NOT TRUE.
    this.$debugMessage = function(debugTxt) {
    	if (!this.debug) {
    		return;
    	} // NB.
    	// Otherwise ..
    	if (!debugTxt) {
    		player.consoleMessage("Problem with debug message text!", 30);
    		return;
    	}
    	player.consoleMessage("Interstellar Tweaks - " + debugTxt, 12);
    	log("InterstellarTweaks - DEBUG", debugTxt);
    };
    
    this.$error = function(debugTxt) {
    	if (!debugTxt) {
    		player.consoleMessage("Problem with error message text!", 30);
    		log("InterstellarTweaks - debugging: problem with error message text!");
    		return;
    	}
    	if (this.debug) {
    		player.consoleMessage("Interstellar Tweaks - ERROR: " + debugTxt, 30);
    	}
    	log("InterstellarTweaks - debugging", debugTxt);
    };
    
    
    /*
    ======================================
    13.		End of wrapper for JSHINT.
    		See also Jshint options above.
    ======================================
    */
    
    }).call(this);
    
    
    // EOF
    Scripts/IST_pirate.js
    /*
    ========================================================================
    IST_pirate.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    ========================================================================
    */
    
    
    /*
    ====================
    JSLINT: set options
    ====================
    */
    
    /*jshint esversion: 6*/
    /*jshint sub:true*/
    
    
    this.name = "IST_pirate.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A ship script for the Interstellar Tweaks OXP";
    
    
    /*
    ------------------
    DEBUGGING SWITCHES
    ------------------
    */
    
    // this.logging = true;
    
    var consoleDebugMessages = false;
    // Do NOT comment this out. Rather, to disable, set to false.
    
    this.debug = false;
    // false
    
    
    /*
    ------------------------
    JSLINT: start of wrapper
    ------------------------
    */
    
    (function() {
    	"use strict";
    
    
    	/*
    	--------------
    	EVENT HANDLERS
    	--------------
    	*/
    
    	this.shipSpawned = function() {
    		var r = Math.random();
    		if (r < 0.6) {
    			// Try to replace a normal missile with a more interesting type.
    			this.ship.removeEquipment("EQ_MISSILE");
    			var missileDeficit = this.ship.missileCapacity - this.ship.missiles.length;
    			if (worldScripts["CT_masterScript"] !== undefined) {
    				this.ship.awardEquipment("EQ_ARMOURY_CUTPURSE_MISSILE");
    			} else {
    				this.ship.awardEquipment("EQ_HARDENED_MISSILE");
    			}
    		}
    		// Bounty
    		if (r > 0.2) {
    			if (r > 0.94) {
    				this.ship.bounty = 50 + (r * Math.ceil(200));
    			} else {
    				this.ship.bounty = 7 + (r * Math.ceil(90));
    			}
    		}
    		this.ship.script.$playerHasAttackedPirates = false;
    		// this.$debugMessage("Set variable to "+this.ship.script.$playerHasAttackedPirates);
    		delete this.shipSpawned;
    	};
    
    	this.shipDied = this.entityDestroyed = this.playerWillEnterWitchspace = function() {
    		this.$_deleteDetectDecloakTimer();
    	};
    
    	this.shipTakingDamage = function(amount, whom, type) {
    		if (whom !== player.ship) {
    			return;
    		}
    		// Else
    		if (this.ship.script.$playerHasAttackedPirates === false) {
    			this.ship.script.$playerHasAttackedPirates = true;
    			// this.$debugMessage("Set variable to "+this.ship.script.$playerHasAttackedPirates);
    		}
    	};
    
    	this.shipBeingAttackedByCloaked = function() {
    		// From the wiki: 'There is no parameter provided to identify the cloaked ship.'
    		if (!this.cloakedTarget) {
    			this.cloakedTarget = system.filteredEntities(this, this.$isCloaked, this.ship, 25600)[0];
    		}
    		if (this.cloakedTarget && this.cloakedTarget.isCloaked) {
    			if (this.detectDecloakTimer) {
    				if (!this.detectDecloakTimer.isRunning) {
    					this.detectDecloakTimer.start();
    				}
    				// This shouldn't happen - because deleted after each use.
    			} else {
    				var num = 0.2 + Math.random();
    				this.detectDecloakTimer = new Timer(this, $detectDecloakTimed, num, 2.65);
    			}
    		}
    	};
    
    	/*
    	---------------------
    	ROUTINES CALLED BY AI
    	---------------------
    	*/
    
    	this.$_deleteDetectDecloakTimer = function $_deleteDetectDecloakTimer() {
    		if (this.detectDecloakTimer) {
    			if (this.detectDecloakTimer.isRunning) {
    				this.detectDecloakTimer.stop();
    			}
    			delete this.detectDecloakTimer;
    		}
    	};
    
    	// This function called by AI
    	this.$_seekVictim = function() {
    		if (!this.ship || !this.ship.isPiloted) {
    			return;
    		}
    		var potentialTargets = system.filteredEntities(this, this.$isPotentialTarget, this.ship, 25600);
    		var numPotentialTargets = potentialTargets.length;
    		if (numPotentialTargets < 1) {
    			this.ship.reactToAIMessage("NOTHING_FOUND");
    			return;
    			// No need to scan for dead tharglets, 'cos they'll be got via AI's SCAN_FOR_LOOT.
    		}
    		// Else
    		var r = Math.random();
    		if ((numPotentialTargets === 1) || (r < 0.5)) {
    			this.ship.target = potentialTargets[0];
    		} else {
    			if ((numPotentialTargets === 2) || (r > 0.6)) {
    				this.ship.target = potentialTargets[1];
    			} else {
    				this.ship.target = potentialTargets[2];
    			}
    		}
    		this.ship.reactToAIMessage("TARGET_FOUND");
    	};
    
    	this.$_haveEngaged = function() {
    		// Rationale: if this ship is attacking the player, then either this ship or a group-mate OKed it; since it might have been a group mate, tell THIS ship that the player is henceforth a target.
    		if (this.ship.target !== player.ship) {
    			return;
    		}
    		// Otherwise
    		if (this.ship.script.$playerHasAttackedPirates === false) {
    			this.ship.script.$playerHasAttackedPirates = true;
    			// this.$debugMessage("Set variable to "+this.ship.script.$playerHasAttackedPirates);
    		}
    	};
    
    
    	/*
    	--------------
    	OTHER ROUTINES
    	--------------
    	*/
    
    	this.$isCloaked = function(e) {
    		return e.isShip && e.isCloaked;
    	};
    
    	this.$isPotentialTarget = function(e) {
    		return e.isShip && !e.isCloaked && e.isPiloted && (((e.isPirateVictim || e.hasRole("hiredGuns_escort") || e.isPlayer || e.primaryRole === "IST_lobster") && (e.bounty < 50 || e.primaryRole === "IST_lobster")) || (e.isPlayer && this.ship.script.$playerHasAttackedPirates));
    	};
    	// Cf. this.shipSpawned and this.shipTakingDamage
    
    	this.$detectDecloakTimed = function() {
    		if (!this.ship || !this.ship.isPiloted) {
    			this.$_deleteDetectDecloakTimer();
    			return;
    		}
    		if (!this.cloakedTarget || !this.cloakedTarget.isValid) {
    			this.$_deleteDetectDecloakTimer();
    			this.ship.reactToAIMessage("TARGET_LOST");
    			return;
    		}
    		if (this.ship.position.distanceTo(this.cloakedTarget) > 25600) {
    			this.$_deleteDetectDecloakTimer();
    			this.ship.reactToAIMessage("TARGET_LOST");
    			return;
    		}
    		if (this.cloakedTarget.isCloaked) {
    			return;
    		} // keep checking
    		this.$_deleteDetectDecloakTimer();
    		this.ship.target = this.cloakedTarget;
    		this.ship.reactToAIMessage("TARGET_DECLOAKED");
    	};
    
    
    	/*
    	--------------
    	DEBUGGING CODE
    	--------------
    	*/
    
    	// this.$debugMessage = function(debugTxt)
    	// {
    	// 	if ( !this.debug ) { return; } // NB. THIS ROUTINE DOES NOTHING IF this.debug IS NOT TRUE
    	// 	// else
    	// 	if ( !debugTxt ) {
    	// 		player.consoleMessage( "Problem with debug message text!", 30 );
    	// 		return;
    	// 	}
    	// 	player.consoleMessage( "Interstellar Tweaks, PIRATES - "+debugTxt, 12 );
    	// 	log( "InterstellarTweaks, PIRATES - debugging", debugTxt );
    	// };
    
    
    	/*
    	----------------------
    	JSHINT: end of wrapper
    	----------------------
    	*/
    
    }).call(this);
    
    
    // EOF
    Scripts/IST_thargoid.js
    /*
    ========================================================================
    IST_thargoid.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    ========================================================================
    */
    
    
    
    /*
    ====================
    JSLINT: set options
    ====================
    */
    
    /*jshint esversion: 6*/
    /*jshint sub:true*/
    
    
    this.name = "IST_thargoid.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A script for InterstellarTweaks OXP";
    
    
    /*
    ------------------
    DEBUGGING SWITCHES
    ------------------
    */
    
    this.logging = false; // Corresponds to, or needs, settings in logcontrol.plist?
    this.debug = false; // false
    var consoleDebugMessages = false; // do NOT comment this out. Rather, to disable, set to false.
    
    
    /*
    ------------------------
    JSLINT: start of wrapper
    -----------------------
    */
    
    (function() {
    	"use strict";
    
    
    	/*
    	--------------
    	EVENT HANDLERS
    	--------------
    	*/
    
    	// Toggle out the following when not debugging.
    
    	// this.shipSpawned = function() {
    	// 	this.ship.reportAIMessages = true;
    	// 	delete this.shipSpawned;
    	// }
    
    
    	/*
    	---------------------
    	ROUTINES CALLED BY AI
    	---------------------
    	*/
    
    	this.$_findTarget = function() {
    		var nearArray = system.filteredEntities(this, this.$isEligibleTarget, this.ship, 25600);
    		// The above will exclude escorts marked as CLASS_ROCK. But if those attack the ship, it will respond.
    		var l = nearArray.length;
    		if (l > 0) {
    			if (l > 1) {
    				var targetNumber = ~~(Math.random() * l);
    				// if ( targetNumber > l ) {
    				// 	log( this.name + " script ERROR, target number too high - please report." );
    				// 	targetNumber = 0;
    				// }
    				this.ship.target = nearArray[targetNumber];
    			} else {
    				this.ship.target = nearArray[0];
    			}
    			if (Math.random() < 0.2) {
    				this.$cursePlayer();
    			}
    			this.ship.reactToAIMessage("TARGET_FOUND");
    			return;
    		}
    		// Otherwise
    		var farArray = system.filteredEntities(this, $isEligibleTarget, this.ship, 75000);
    		if (farArray.length > 0) {
    			if (Math.random() < 0.1) {
    				this.$cursePlayer();
    			}
    			this.ship.target = farArray[0]; // set to the closest target off-scanner but in range
    			this.ship.reactToAIMessage("INTERCEPT");
    		} else {
    			this.ship.reactToAIMessage("NOTHING_FOUND");
    		}
    	};
    
    	this.$_validateAttackerAsTarget = function() {
    		if (this.ship.target && this.ship.target.isValid && this.$isEligibleTarget(this.ship.target)) {
    			this.ship.reactToAIMessage("TARGET_VALID");
    		} else {
    			this.ship.reactToAIMessage("TARGET_INVALID");
    		}
    	};
    
    
    	/*
    	---------------
    	OTHER FUNCTIONS
    	---------------
    	*/
    
    	this.$isEligibleTarget = function(e) {
    		return !e.isCloaked && ((e.isPlayer && !e.docked) || (e.isShip && e.ispiloted && (!e.isThargoid || e.primaryRole === "thargoidRebel")));
    	};
    
    	this.$cursePlayer = function() {
    		this.ship.commsMessage(expandDescription("[thargoid_curses]", player.ship));
    	};
    
    
    	/*
    	---------
    	DEBUGGING
    	---------
    	*/
    
    	// this.$debugMessage = function( debugTxt )
    	// {
    	// 	if (!this.debug) { return; } // NB. THIS ROUTINE DOES NOTHING IF this.debug IS NOT TRUE
    	// 	// else
    	// 	if ( !debugTxt ) {
    	// 		player.consoleMessage( "Problem with debug message text!", 30 );
    	// 		return;
    	// 	}
    	// 	player.consoleMessage( "Interstellar Tweaks - "+debugTxt, 12 );
    	// 	log( "InterstellarTweaks - debugging", debugTxt );
    	// };
    
    
    	/*
    	----------------------
    	JSHINT: end of wrapper
    	----------------------
    	*/
    
    }).call(this);
    
    
    // EOF
    Scripts/IST_thargoidDefenceShip.js
    /*
    ========================================================================
    IST_thargoidDefenceShip.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    ========================================================================
    */
    
    
    /*
    ====================
    JSLINT: set options
    ====================
    */
    
    /*jshint esversion: 6*/
    /*jshint sub:true*/
    
    
    this.name = "IST_thargoidDefenceShip.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A script for InterstellarTweaks OXP";
    
    
    /*
    ------------------
    DEBUGGING SWITCHES
    ------------------
    */
    
    this.logging = false; // Corresponds to, or needs, settings in logcontrol.plist?
    this.debug = false; // false
    var consoleDebugMessages = false; // do NOT comment this out. Rather, to disable, set to false.
    
    
    /*
    ------------------------
    JSHINT: start of wrapper
    ------------------------
    */
    
    (function() {
    	"use strict";
    
    
    	/*
    	--------------
    	EVENT HANDLERS
    	--------------
    	*/
    
    	// Toggle out the following when not debugging.
    
    	// this.shipSpawned = function() {
    	// 	this.ship.reportAIMessages = true;
    	// 	delete this.shipSpawned;
    	// }
    
    
    	/*
    	---------------------
    	ROUTINES CALLED BY AI
    	---------------------
    	*/
    
    	this.$_findTarget = function() {
    		var nearArray = system.filteredEntities(this, this.$isEligibleTarget, this.ship, 25600);
    		// The above will exclude escorts marked as CLASS_ROCK. But if those attack the ship, it will respond.
    		var l = nearArray.length;
    		if (l > 0) {
    			if (l > 1) {
    				var targetNumber = ~~(Math.random() * l);
    				// if ( targetNumber > l ) {
    				// 	log(this.name + " script ERROR, target number too high - please report.");
    				// 	targetNumber = 0;
    				// }
    				this.ship.target = nearArray[targetNumber];
    			} else {
    				this.ship.target = nearArray[0];
    			}
    			this.$cursePlayer();
    			this.ship.reactToAIMessage("TARGET_FOUND");
    			return;
    		}
    		// Otherwise
    		var farArray = system.filteredEntities(this, $isEligibleTarget, this.ship, 75000);
    		if (farArray.length > 0) {
    			this.ship.target = farArray[0]; // set to the closest target off-scanner but in range
    			this.ship.reactToAIMessage("INTERCEPT");
    		} else {
    			this.ship.reactToAIMessage("NOTHING_FOUND");
    		}
    	};
    
    	this.$_validateAttackerAsTarget = function() {
    		if (this.ship.target && this.ship.target.isValid && this.$isEligibleTarget(this.ship.target)) {
    			this.ship.reactToAIMessage("TARGET_VALID");
    		} else {
    			this.ship.reactToAIMessage("TARGET_INVALID");
    		}
    	};
    
    
    	/*
    	---------------
    	OTHER FUNCTIONS
    	---------------
    	*/
    
    	this.$isEligibleTarget = function(e) {
    		return !e.isCloaked && ((e.isPlayer && !e.docked) || (e.isShip && e.ispiloted && (!e.isThargoid || e.primaryRole === "thargoidRebel")));
    	};
    
    	this.$cursePlayer = function() {
    		this.ship.commsMessage(expandDescription("[thargoid_curses]", player.ship));
    	};
    
    
    	/*
    	---------
    	DEBUGGING
    	---------
    	*/
    
    	// this.$debugMessage = function(debugTxt)
    	// {
    	// 	if (!this.debug) { return; } // NB. THIS ROUTINE DOES NOTHING IF this.debug IS NOT TRUE
    	// 	// else
    	// 	if ( !debugTxt ) {
    	// 		player.consoleMessage( "Problem with debug message text!", 30 );
    	// 		return;
    	// 	}
    	// 	player.consoleMessage( "Interstellar Tweaks - "+debugTxt, 12 );
    	// 	log( "InterstellarTweaks - debugging", debugTxt );
    	// };
    
    
    
    	/*
    	----------------------
    	JSHINT: end of wrapper
    	----------------------
    	*/
    
    }).call(this);
    
    
    // EOF
    Scripts/IST_thargoidRebel.js
    /*
    ========================================================================
    IST_thargoidRebel.js
    This file is part of the Interstellar Tweaks expansion pack.
    Author: UK_Eliter
    License: 2017 Creative Commons: attribution, non-commercial, sharealike.
    ========================================================================
    */
    
    
    /*
    --------------------
    JSHINT: set options
    --------------------
    */
    
    /*jshint esversion: 6*/
    /*jshint sub:true*/
    
    
    
    this.name = "IST_thargoidRebel.js";
    this.author = "UK_Eliter";
    this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
    this.licence = "CC-NC-SA 3";
    this.description = "A script for InterstellarTweaks OXP";
    
    
    /*
    ------------------
    DEBUGGING SWITCHES
    ------------------
    */
    
    // this.logging = true;
    var consoleDebugMessages = false;
    // do NOT comment out the above line. Rather, to disable, set to false.
    
    
    /*
    ------------------------
    JSHINT: start of wrapper
    ------------------------
    */
    
    (function() {
    	"use strict";
    
    
    	/*
    	---------
    	MAIN CODE
    	---------
    	*/
    
    	// The AI ensures that a rebel ship can never use its own drive to enter normal space.
    	// But rebels can enter each others' wormwholes and thereby (despite the above) enter normal space. Hence this function.
    	this.shipSpawned = function() {
    		// Fix witchspace.
    		this.ship.scriptedMisjump = true;
    		delete this.shipSpawned;
    	};
    
    
    	this.$targetShips = function(e) {
    		return e.isShip && e.isThargoid && !e.isCloaked && e.primaryRole !== "thargoidRebel";
    	};
    
    	this.$thargoidAIfindEnemy = function() {
    		var nearArray = system.filteredEntities(this, this.$targetShips, this.ship, 25600);
    		if (nearArray.length > 0) {
    			var targetNumber = ~~(Math.random() * nearArray.length);
    			this.ship.target = nearArray[targetNumber];
    			this.ship.reactToAIMessage("TARGET_FOUND");
    			return;
    		}
    		var farArray = system.filteredEntities(this, $targetShips, this.ship, 60000);
    		if (farArray.length > 0) {
    			this.ship.target = farArray[0]; // set to the closest target off-scanner but in range.
    			this.ship.reactToAIMessage("INTERCEPT_TARGET");
    		} else {
    			this.ship.reactToAIMessage("NO_TARGET_FOUND");
    		}
    	};
    
    	this.$validateTarget = function() {
    		if (!this.ship.target || !this.ship.target.isValid || this.ship.target.isCloaked) {
    			this.ship.reactToAIMessage("TARGET_INVALID");
    			return;
    		}
    		if (this.ship.target.isThargoid && this.ship.target.primaryRole != "thargoidRebel") {
    			this.ship.reactToAIMessage("TARGET_VALID");
    			return;
    		}
    		if (this.ship.target.isPolice || this.ship.target.scanClass == "CLASS_MILITARY") {
    			this.ship.reactToAIMessage("TARGET_GALCOP");
    			return;
    		}
    		this.ship.reactToAIMessage("TARGET_INVALID");
    	};
    
    
    	/*
    	----------------------
    	JSLINT: end of wrapper
    	----------------------
    	*/
    
    }).call(this);
    
    
    // EOF