| Back to Index | Page generated: Oct 27, 2025, 5:37:22 AM | 
 Expansion Extra Thargoids
 Expansion Extra Thargoids| from Expansion Manager's OXP list | from Expansion Manifest | |
|---|---|---|
| Description | Adds new types of Thargoid, which are to be encountered especially in interstellar space. | Adds new types of Thargoid, which are to be encountered especially in interstellar space. | 
| Identifier | oolite.oxp.UK_Eliter.ExtraThargoids | oolite.oxp.UK_Eliter.ExtraThargoids | 
| Title | Extra Thargoids | Extra Thargoids | 
| Category | Ships | Ships | 
| Author | UK_Eliter | UK_Eliter | 
| Version | 6.73 | 6.73 | 
| Tags | thargoids, ships, system | thargoids, ships, system | 
| Required Oolite Version | ||
| Maximum Oolite Version | ||
| Required Expansions | ||
| Optional Expansions |  |  | 
| Conflict Expansions | ||
| Information URL | http://aegidian.org/bb/viewtopic.php?t=10154&p=143763 | n/a | 
| Download URL | https://wiki.alioth.net/img_auth.php/8/8a/Oolite.oxp.UK_Eliter.Extra_Thargoids.oxz | http://wiki.alioth.net/img_auth.php/8/8a/Oolite.oxp.UK_Eliter.Extra_Thargoids.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 | 1746401291 | 
Also read http://wiki.alioth.net/index.php/Extra%20Thargoids
==================================== 'Extra Thargoids' OXP by 'UK_Eliter' ==================================== ------------- GENERAL NOTES ------------- � This OXP adds various types of Thargoid. The most commonly (or least infrequently) encountered of these are (/will be) the 'Gruntbuggly' (which itself comes in various versions), the 'anti-poet' Frigate, the minesweeper. � This OXP works best with the 'Thargorn_Threat' OXP. (I have tested it with Thargorn_Threat version 1.5.) ------- LICENSE ------- This OXP is released under the Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license. This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 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 ---------------- This OXP derives in considerable part from the Thargoid Threat OXP. That OXP was created by 'Arexack_Heretic' and modified by Eric Walch, who himself in so doing drew upon a version of the 'freaky thargoid shader' by Ahruman. The Thargoid Threat OXP contains this statement: 'Created under Creative Commons Licence, as expansion on Oolite, created by Giles Williams (Aegidian). Look the relevant stuff up at http://oolite.aegidian.org. In short however; anyone is welcome to expand to or use parts of this OXP as long as credit is given where due, and as long as not in any commercial enterprise.' I am happy to give that credit! The 'displacement' code in one of my scripts owes to Thargoid's Armoury OXP. The displacement sound is an OGG conversion of 'stk-DM300_18.wav', which is a sound provided, under the Creative Commons License and via www.freesound.org/, by user 'stk'. Other materials are adapted from stuff built-in to Oolite. For the license for Oolite itself, see the OoliteReadMe.pdf file included with that program. My thanks to the following for help with debugging and for ideas (though probably I omit some people here, by accident): cag; Fleurghber; Milo; Nite Owl; Staer9. ----------------- END -----------------
| Path | |
|---|---|
| Scripts/extraThargoids_buggly.js | /*
========================================================================
extraThargoids_buggly.js
This file is part of the ExtraThargoids expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/
/*
-------------------
JSLINT: set options
-------------------
*/
/*jshint esversion: 6*/
/*jshint sub:true*/
this.name = "extraThargoids_buggly";
this.author = "UK_Eliter";
this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
this.licence = "CC-NC-SA 3";
this.description = "Script for the 'Gruntbuggly' Thargon ships";
/*
-----------------------------------------------------------------------
Corresponding AIs:
	- extraThargoids_bugglyAI.plist (which sends no messages to script)
	- extraThargoids_kamikazeAI
-----------------------------------------------------------------------
*/
/*
------------------
DEBUGGING SWITCHES
------------------
*/
// this.logging = true;
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 is built-in to Oolite - and does not need to be declared in the 'customsounds' file.
/*
------------------------
JSHINT: start of wrapper
------------------------
*/
(function() {
	"use strict";
	/*
	--------------
	EVENT HANDLERS
	--------------
	*/
	this.shipSpawned = function() {
		// set timer to check for stun bomb from Armoury OXP - and give some buggly models missiles
		if (worldScripts["armoury_machineScript.js"]) {
			this.checkStun = new Timer(this, this.$checkStunTimed, 12, 12);
		}
		delete this.shipSpawned;
	};
	this.shipDied = this.entityDestroyed = this.playerWillEnterWitchspace = function() {
		this.$deleteTimers();
	};
	this.shipTakingDamage = function(amount, whom, type) {
		if ((amount < 50) && (this.ship.energy > 19)) {
			return;
		}
		var chance;
		if (amount > 49) {
			if (this.ship.energy < 20) {
				chance = 0.5;
			} else {
				chance = 0.1;
			}
		} else {
			chance = 0.2; // this will mean both (this.ship.energy < 20) AND NOT (amount > 49)
		}
		if (this.ship.target && this.ship.target.isValid) {
			this.distanceToTarget = this.ship.position.distanceTo(this.ship.target);
			if (this.distanceToTarget < 650) {
				chance += 0.67;
			} else {
				if (this.distanceToTarget < 1000) {
					chance += 0.55;
				} else if (this.distanceToTarget < 3000) {
						chance += 0.3;
				}
			}
		}
		if (Math.random() < chance) {
			this.ship.energy += 100 + amount; // stop it blowing up normally 
			if (whom && whom.isPlayer) {
				this.$explode_causedByPlayer();
			} else {
				this.explode_notCausedByPlayer();
			}
		}
	};
	this.shipTargetCloaked = function() {
		if (this.decloakTargetTimer && this.decloakTargetTimer.isRunning) {
			return;
		}
		if (this.ship.target.isThargoid) {
			return;
		}
		var r = Math.random();
		if (r < 0.16) {
			return;
		}
		if (r > 0.75) {
			this.ship.commsMessage(expandDescription("[thargoid_curses]"));
		}
		this.ship.cloakedTarget = this.ship.target;
		var seconds = 0.5 + ~~(Math.random() * 8);
		if (this.decloakTargetTimer) {
			delete this.decloakTargetTimer;
		}
		this.decloakTargetTimer = new Timer(this, this.$decloakTargetTimed, seconds);
	};
	/*
	---------------------------------------------------
	ROUTINES CALLED BY EVENT HANDLERS
	or called by the routines called by event handlers.
	---------------------------------------------------
	*/
	this.explode_notCausedByPlayer = function() {
		this.$deleteTimers();
		if (!this.ship) {
			return;
		}
		this.explodingShip = this.ship.spawnOne("extraThargoids_exploding_notCausedByPlayer");
		this.explodingShip.newBounty = this.ship.bounty;
		this.explodingShip.bounty = this.ship.bounty;
		this.explodingShip.orientation = this.ship.orientation;
		this.explodingShip.position = this.ship.position;
		if (Math.random() < 0.4) {
			this.ship.commsMessage("We boom your bases!");
		}
		if (!this.ship) {
			return;
		}
		this.ship.remove(true);
	};
	this.$explode_causedByPlayer = function() {
		this.$deleteTimers();
		if (!this.ship) {
			return;
		}
		if (Math.random() < 0.7) {
			this.ship.commsMessage("We boom your bases!");
		}
		this.explodingShip = this.ship.spawnOne("extraThargoids_exploding_causedByPlayer");
		this.explodingShip.newBounty = this.ship.bounty;
		this.explodingShip.bounty = this.ship.bounty;
		this.explodingShip.orientation = this.ship.orientation;
		this.explodingShip.position = this.ship.position;
		if (!this.ship) {
			return;
		}
		this.ship.remove(true);
	};
	this.$decloakTargetTimed = function $decloakTargetTimed() {
		this.decloakTargetTimer.stop();
		if (!this.ship || !this.ship.isValid) {
			delete this.decloakTargetTimer;
			return;
		}
		if (!this.ship.cloakedTarget || !this.ship.cloakedTarget.isValid) {
			delete this.decloakTargetTimer;
			return;
		}
		if (!this.ship.cloakedTarget.isCloaked) {
			delete this.decloakTargetTimer;
			return;
		}
		this.distanceToTarget = this.ship.position.distanceTo(this.ship.cloakedTarget);
		if (this.distanceToTarget < 10000) {
			mysound_Warning.play();
			this.ship.cloakedTarget.lightsActive = true;
			if (Math.random() > 0.91) {
				this.ship.cloakedTarget.setEquipmentStatus("EQ_CLOAKING_DEVICE", "EQUIPMENT_DAMAGED");
				if (this.ship.cloakedTarget.isPlayer && !player.ship) {
					delete this.decloakTargetTimer;
					return;
				}
				this.ship.commsMessage("CLOAKING DEVICE DAMAGED!", this.ship.cloakedTarget);
			} else {
				player.consoleMessage("CLOAKING FAILURE!", 10);
				player.ship.isCloaked = false;
				this.ship.target = this.ship.cloakedTarget;
				this.ship.reactToAIMessage("ATTACK_SHIP");
			}
		}
		if (Math.random() < 0.25) {
			this.ship.commsMessage(expandDescription("[thargoid_curses]"));
		}
		delete this.decloakTargetTimer;
	};
	this.$checkStunTimed = function $checkStunTimed() {
		if (this.ship.AIState == "STUNNED") {
			this.ship.exitAI();
			this.explode_notCausedByPlayer();
		}
	};
	this.$deleteTimers = function() {
		if (this.decloakTargetTimer) {
			if (this.decloakTargetTimer.isRunning) {
				this.decloakTargetTimer.stop();
			}
			delete this.decloakTargetTimer;
		}
		if (this.checkStunTimed) {
			if (this.checkStunTimed.isRunning) {
				this.checkStunTimed.stop();
			}
			delete this.checkStunTimed;
		}
	};
	/*
	--------------------------------------------------------------------------
	CALLED BY AI
	These routines are called by this AI: 
	extraThargoids_kamikazeAI (which itself is invoked, only, by the shipdata)
	--------------------------------------------------------------------------
	*/
	this.$_seekPrimaryTarget = function() {
		if (!this.ship) {
			return;
		}
		var primaryTargetsArray = system.shipsWithRole("behemoth", this.ship, 25600);
		if (primaryTargetsArray.length > 0) {
			this.ship.target = primaryTargetsArray[0];
			this.ship.reactToAIMessage("TARGET_FOUND");
			return;
		}
		primaryTargetsArray = system.shipsWithRole("leviathan", this.ship, 25600);
		if (primaryTargetsArray.length > 0) {
			this.ship.target = primaryTargetsArray[0];
			this.ship.reactToAIMessage("TARGET_FOUND");
			return;
		}
		primaryTargetsArray = system.shipsWithRole("patrol-frigate", this.ship, 25600);
		if (primaryTargetsArray.length > 0) {
			this.ship.target = primaryTargetsArray[0];
			this.ship.reactToAIMessage("TARGET_FOUND");
			return;
		}
		primaryTargetsArray = system.shipsWithRole("navy-frigate", this.ship, 25600);
		if (primaryTargetsArray.length > 0) {
			this.ship.target = primaryTargetsArray[0];
			this.ship.reactToAIMessage("TARGET_FOUND");
		} else {
			this.ship.reactToAIMessage("NO_PRIMARY");
		}
	};
	this.$_rangeAchieved = function() {
		if (!this.ship || !this.ship.isValid) {
			return;
		}
		// else
		this.explode_notCausedByPlayer();
		var explosiveBits = this.ship.spawn("explosive_shrapnel", 5);
	};
	/*
	----------------------
	JSLINT: end of wrapper
	----------------------
	*/
}).call(this);
// EOF | 
| Scripts/extraThargoids_exploding_generic.js | /*
========================================================================
extraThargoids_exploding_generic.js
This file is part of the ExtraThargoids expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/
/*
-------------------
JSLINT: set options
-------------------
*/
/*jshint esversion: 6*/
/*jshint sub:true*/
this.name = "extraThargoids_exploding_generic";
this.author = "UK_Eliter";
this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
this.licence = "CC-NC-SA 3";
this.description = "Script for exploding 'Gruntbuggly' Thargon ships";
/*
------------------------------------------------------
CORRESPONDING AIs:
  
  	- extraThargoids_exploding_causedByPlayerAI.plist
	- extraThargoids_exploding_notCausedByPlayerAI.plist
------------------------------------------------------
/*
------------------
DEBUGGING SWITCHES
------------------
*/
// this.logging = true; // THIS SHOULD BE COMMENTED OUT WHEN NOT TESTING
// this.ship.reportAIMessages = true; // if set to true, continuously dumps AI stuff to log - and produces vector lines.
// var consoleDebugMessages = false;
/*
------
SOUNDS
------
*/
this.bigBang = new SoundSource();
this.bigBang.sound = "bigbang.ogg";
this.mediumBang = new SoundSource();
this.mediumBang.sound = "extraThargoids_mediumBang.ogg";
this.quietBang = new SoundSource();
this.quietBang.sound = "extraThargoids_quietBang.ogg";
/*
------------------------
JSLINT: start of wrapper
------------------------
*/
(function() {
	"use strict";
	/*
	--------------
	EVENT HANDLERS
	--------------
	*/
	this.shipDied = this.entityDestroyed = function() {
		var frags = this.ship.spawn("explosive_shrapnel", 3);
	};
	/*
	-------------
	CALLED BY AIs
	-------------
	*/
	this.$_bountyHack = function() {
		if (this.ship.isValid && this.ship.newBounty && (this.ship.newBounty > 0)) {
			this.ship.bounty = this.ship.newBounty;
		}
	};
	this.$_explode_core = function() {
		this.ship.dealEnergyDamage(980, 1750);
		// SYNTAX: function dealEnergyDamage(damage : Number, idealRange : Number [, velocityBias : Number])
		this.$bangSoundEffect();
	};
	this.$_explode_notCausedByPlayer = function() {
		this.$_explode_core();
	};
	this.$_explode_causedByPlayer = function() {
		var bounty;
		this.$_explode_core();
		player.score += 1;
		if (!this.ship.isValid || !this.ship || this.ship.bounty == 0) {
			bounty = 200;
		} else {
			bounty = this.ship.bounty;
		}
		var string = "Bounty: " + bounty;
		player.consoleMessage(string, 6);
		player.credits += bounty;
		if (player.ship.isValid && Math.random() < 0.15) {
			string = "The navy has awarded a 500 credit bonus!";
			player.consoleMessage(string, 8);
			player.credits += 500;
		}
	};
	/*
	-----
	OTHER
	-----
	*/
	this.$bangSoundEffect = function() {
		if (!this.ship || !this.ship.position || !player.ship.position) {
			return;
		}
		var ps = player.ship; // for speed, but changes won't affect the original variable
		if (this.ship.position.distanceTo(ps.position) < 2000) {
			this.bigBang.play(); // this one really is VERY loud, so only use for VERY close
			return;
		}
		if (this.ship.position.distanceTo(ps.position) < 15000) {
			this.mediumBang.play();
			return;
		}
		if (this.ship.position.distanceTo(ps.position) < 27000) {
			this.quietBang.play();
		}
	};
	/*
	-----------------------
	JSHINT: end of wrapper
	----------------------
	*/
}).call(this);
// EOF | 
| Scripts/extraThargoids_frigatePoet.js | /*
========================================================================
extraThargoids_frigatePoet.js
This file is part of the ExtraThargoids expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/
/*
-------------------
JSLINT: set options
-------------------
*/
/*jshint esversion: 6*/
/*jshint sub:true*/
this.name = "extraThargoids_frigatePoet";
this.author = "UK_Eliter";
this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
this.licence = "CC-NC-SA 3";
this.description = "extraThargoids_frigatePoet";
// NB: There is no special AI - but rather an inbuilt one - corresponding to this script.
/*
-------------
VARIABLES etc
-------------
*/
this.displace = new SoundSource();
this.displace.sound = "extraThargoids_displacement.ogg";
this.quietDisplace = new SoundSource();
this.quietDisplace.sound = "[extraThargods_displacementQuiet.ogg]";
this.warning = new SoundSource();
this.warning.sound = "warning.ogg"; // this sound built-in to Oolite - and does not need to be declared in the 'customsounds' file.
/*
------------------------
JSHINT: start of wrapper
------------------------
*/
(function() {
	"use strict";
	/*
	--------------
	EVENT HANDLERS
	--------------
	*/
	this.shipSpawned = function() {
		this.canDisplaceCurrently = true;
		delete this.shipSpawned;
	};
	this.shipDied = this.entityDestroyed = this.playerWillEnterWitchspace = function() {
		this.$cleanUp();
	};
	this.shipAttackedWithMissile = function() // run by oolite core itself {
	{
		if (Math.random() > 0.7) {
			return;
		}
		this.ship.isCloaked = true;
		// but if can't cloak . .
		if (this.ship.isCloaked === false) {
			this.$displace();
		}
	};
	this.shipTargetCloaked = function() {
		if (Math.random() > 0.82) {
			this.$displace();
		}
		if (this.ship.target) {
			this.ship.target = null;
		}
	};
	this.shipEnergyIsLow = function() {
		if (Math.random() > 0.13) {
			this.ship.isCloaked = false;
			this.$displace();
		}
	};
	/*
	-----
	OTHER
	-----
	*/
	// Following code includes parts adapted from Thargoid's armoury_displacerMissile.js script in his Armoury OXP.
	this.$displace = function() {
		if (this.canDisplaceCurrently === false || !this.ship) {
			return;
		}
		if (this.ship.fuel < 4) {
			this.canDisplaceCurrently = false;
			return;
		}
		this.canDisplaceCurrently = false;
		if (this.timerToReenableDisplace) {
			if (this.timerToReenableDisplace.isRunning) {
				this.timerToReenableDisplace.stop(); // should never happen
			}
			delete this.timerToReenableDisplace;
		}
		if (!player.ship.position) {
			return;
		}
		var ps = player.ship; // for speed, but changes won't affect the original variable
		var xDistance = ((Math.random() * 2) - 1) * 8600;
		var yDistance = ((Math.random() * 2) - 1) * 8600;
		var zDistance = ((Math.random() * 2) - 1) * 8600;
		this.ship.position = this.ship.position.add([xDistance, yDistance, zDistance]);
		if (Math.random() < 0.7) {
			this.ship.commsMessage(expandDescription("[thargoid_curses]"), ps);
		}
		var shipDistanceToDisplacedShip = this.ship.position.distanceTo(ps.position); // would be good to alter the following to occur to ANY ship within the specified range . .
		var displacementChance = 0;
		this.ship.position = this.ship.position.add([xDistance, yDistance, zDistance]);
		this.ship.isCloaked = false;
		if (shipDistanceToDisplacedShip < 1200) {
			if (shipDistanceToDisplacedShip < 500) {
				displacementChance = 0.5;
			} else {
				displacementChance = 0.2;
			}
		}
		if (shipDistanceToDisplacedShip < 12000) {
			this.displace.play();
		} else if (shipDistanceToDisplacedShip < 18000) {
			this.quietDisplace.play();
		}
		this.ship.fuel -= (Math.ceil(Math.random() * 5)); // drain off some fuel to simulate the jump
		if (this.ship.target) {
			if (Math.random() < 0.5) {
				this.ship.target = null;
			}
		}
		if (Math.random() <= displacementChance) {
			player.ship.position = player.ship.position.add([xDistance, yDistance, zDistance]);
			this.warning.play();
			player.consoleMessage("EMERGENCY - position changed by nearby displacement device", 6);
			if (Math.random() < 0.1) {
				player.ship.scriptedMisjump = true;
				player.ship.scriptedMisjumpRange = r;
			}
		}
		var t = 8 + Math.ceil(Math.random() * 6);
		this.timerToReenableDisplace = new Timer(this, this.$reenableDisplace, t);
	};
	this.$reenableDisplace = function $reenableDisplace() {
		this.canDisplaceCurrently = true;
	};
	this.$cleanUp = function() {
		this.canDisplaceCurrently = true;
		if (this.timerToReenableDisplace) {
			if (this.timerToReenableDisplace.isRunning) {
				this.timerToReenableDisplace.stop();
			}
			delete this.timerToReenableDisplace;
		}
	};
	/*
	----------------------
	JSLINT: end of wrapper
	----------------------
	*/
}).call(this);
// EOF | 
| Scripts/extraThargoids_populator.js | /*
========================================================================
extraThargoids_populator.js
This file is part of the ExtraThargoids expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/
/*
-------------------
JSLINT: set options
-------------------
*/
/*jshint esversion: 6*/
/*jshint sub:true*/
this.name = "extraThargoids_populator";
this.author = "UK_Eliter";
this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
this.licence = "CC-NC-SA 3";
this.description = "This script adds some of the 'Extra Thargoids' to the game";
/*
--------
SWITCHES
--------
*/
this.logging = false; // NB: Most log lines are commented out at present.
/*
----------------
GLOBAL VARIABLES
----------------
*/
this.invasionChance = 0.003;
// 0.003. Increased somewhat by player score . . - see this.startUp.
/*
------------------------
JSHINT: start of wrapper
------------------------
*/
(function() {
	"use strict";
	/*
	---------
	MAIN CODE
	---------
	*/
	this.startUp = function() {
		this.threeG_Installed = (worldScripts.ferdelance3G_populator !== undefined);
		var score = player.score;
		if (score > 7000) {
			if (score > 19200) {
				this.invasionChance += 0.0035;
			} else {
				this.invasionChance += 0.0025;
			} // 'Elite' score is 6400.
		}
		this.invasionExtantInCurrentSystem = false;
		// log("Extra Thargoids", "Initialised OK");
	};
	this.playerWillEnterWitchspace = function() {
		if (this.invasionExtantInCurrentSystem || this.invasionChance === 0 || player.score < 1500 || Math.random() > this.invasionChance) {
			this.invasionExtantInCurrentSystem = false;
		} else {
			this.repopulationsCounter = 0;
			this.invasionExtantInCurrentSystem = true; // well, will occur in the NEXT system.
			this.maxRepopulations = 40 + Math.ceil(Math.random() * 100);
			this.repopulationsCounter = 0;
		}
		// this.invasionExtantInCurrentSystem = true; // TEST
	};
	this.entityDestroyed = function() {
		this.invasionExtantInCurrentSystem = false;
	};
	this.interstellarSpaceWillPopulate = function() {
		// INTERSTELLAR POPULATOR
		// Use 'callback: this._myFunction.bind(this)' not callback: this._myFunction' in order to use global variables and functions.
		// if two populator entries have same 'priority', Oolite will randomly determine their order.
		// if (Math.random() > 0.86) {return;}
		// ADD THARGOIDS
		system.setPopulator("extraThargs-interstellarThargoids", {
			priority: 101,
			callback: this._perhapsAddInterstellarThargoids.bind(this)
		});
	};
	this._perhapsAddInterstellarThargoids = function(pos) {
		//
		// log("extraThargoids_populator.js", "One or more Thargoid(s) added to interstellar space by populator script.");
		var n;
		if (player.score > 3750) {
			n = 36;
		} else {
			n = 40;
		}
		var c = Math.ceil(Math.random() * n);
		var s;
		switch (c) {
			case 1:
				s = system.addShips("extraThargoid", 1, pos, 27000);
				break;
			case 2:
				s = system.addShips("extraThargoid", 1, pos, 27000);
				break;
			case 3:
				s = system.addShips("extraThargoid", 2, pos, 27000);
				break;
			case 4:
				s = system.addShips("extraThargoid", 3, pos, 30000);
				break;
			case 5:
				s = system.addShips("extraThargoids_buggly3", 3, pos, 15000);
				break;
			case 6:
				s = system.addShips("extraThargoid", 2, pos, 60000);
				break;
			case 7:
				s = system.addShips("extraThargoid", 2, pos, 27000); /* falls through */
			case 8:
				s = system.addShips("extraThargoids_buggly2", 1, pos, 27000);
				break;
			case 9:
				s = system.addShips("extraThargoids_sweeper", 1, pos, 20000);
				break;
			case 10:
				s = system.addShips("extraThargoids_sweeper", 1, pos, 25000);
				break;
			case 11:
				s = system.addShips("extraThargoids_sweeper", 1, pos, 28000);
				break;
			case 12:
				s = system.addShips("extraThargoids_sweeper", 2, pos, 40000);
				break;
			default:
		}
	};
	// INTERSTELLAR REPOPULATOR - NONE
	/*
	this.interstellarSpaceWillRepopulate = function()
	{
	}
	*/
	this.systemWillPopulate = function() {
		// STELLAR POPULATOR
		// LANE_PS, LANE_WP, LANE_WS, STATION_AEGIS, PLANET_ORBIT, OUTER_SYSTEM, OUTER_SYSTEM_OFFPLANE
		// INVASION stuff
		// Use 'callback: this._myFunction.bind(this)' not callback: this._myFunction' in order to use global variables and functions
		if (this.invasionExtantInCurrentSystem === false) {
			return;
		} // Else - INVASION
		// Add thargoids and other ships
		system.setPopulator("extraThargs-invasionShips", {
			groupCount: 1,
			priority: 100,
			location: "LANE_WP",
			callback: this._addInvasionEntities.bind(this)
		});
		if (Math.random() > 0.8) {
			return;
		}
		var gc = 1;
		if (Math.random() < 0.3) {
			gc += 1;
		}
		system.setPopulator("extraThargs-invasionShips_More", {
			groupCount: gc,
			priority: 101,
			location: "LANE_WPS",
			callback: this._addInvasionEntities.bind(this)
		});
	};
	this.shipWillExitWitchspace = function() {
		if (!this.invasionExtantInCurrentSystem) {
			return;
		}
		// Under certain conditions, cancel it. (And can't do this earlier, i.e. not initiate in the first place, because of technical problems. .
		// Or, rather, because cannot cancel in sense of undo the population function, just try to make sure all ships I've added leave.
		if (system.isInterstellarSpace) {
			this.invasionExtantInCurrentSystem = false;
			return;
			// This will not actually cancel anything, because interstellar - rather than stellar - populator will have been called.
		}
		// Else
		if (system.sun.isGoingNova || system.sun.hasGoneNova) {
			system.sendAllShipsAway();
			this.invasionExtantInCurrentSystem = false;
			return;
		}
		// Else
		//
		// Remove some existing ships - try to do this as late as possible
		this.$removeShipsEtcForInvasion();
	};
	this.shipExitedWitchspace = function() {
		if (this.invasionExtantInCurrentSystem) {
			// this.invasionExtantInCurrentSystem will have been set to false if we are in interstellar space.
			player.consoleMessage("** POLICE ALERT **: Thargoid invasion!", 300);
		}
		// var s = system.addShips("extraThargoids_uberBuggly", 1, [0,0,0], 22000); // TEST
	};
	this.$is_a_targettedNonMainStation = function(e) {
		return e.isStation && e.scanClass === "CLASS_STATION" && (e.position.distanceTo(system.mainPlanet.position) < system.mainPlanet.radius * 13);
	};
	this.$isWitchpointBuoy = function(e) {
		return e.isShip && e.scanClass === "CLASS_BUOY" && e.hasRole("buoy-witchpoint") && (e.position.distanceTo(system.mainPlanet.position) < system.mainPlanet.radius * 50);
	};
	this.$removeShipsEtcForInvasion = function() {
		// Some populators might add stuff *after* this, so err on removing too much
		var i, l, f, r, s;
		// Stations
		s = system.filteredEntities(this, this.$is_a_targettedNonMainStation, system.mainStation);
		for (i = 0; i < s.length; i++) {
			r = Math.random();
			if (r < 0.5) {
				if (r < 0.4) {
					s[i].explode();
				} else {
					s[i].remove(true); // no death action
				}
			}
		}
		// Buoys
		s = system.filteredEntities(this, this.$isWitchpointBuoy);
		l = s.length;
		if (l > 0) {
			i = s.length;
			while (i--) {
				if (Math.random() < 0.6) {
					s[i].remove(true);
				}
			}
		}
		// Neutral ships
		s = system.entitiesWithScanClass("CLASS_NEUTRAL");
		l = s.length;
		if (l > 9) {
			if (Math.random() < 0.6) {
				f = 0.9;
			} else {
				f = 0.75;
			}
			// NB: The following will run before various (old-style) OXP populators
			l = Math.ceil(s.length * f);
			i = l;
			while (l--) {
				if (
					(s[i].isValid) &&
					s[i].isShip &&
					!s[i].isPlayer &&
					s[i].primaryRole !== "hunter-medium" &&
					s[i].primaryRole !== "hunter-heavy" &&
					!s[i].hasRole("ecl_escape_pod_beacon") &&
					!s[i].hasRole("escape-capsule") &&
					!s[i].hasRole("hiredGuns_escort")
				) {
					if ((i % 3 === 0) && (s[i].distanceToPlayer > 30000) && (s[i].distanceToPlayer < 3072000)) {
						if (s[i].abandonShip === true) {
							s[i].energy = (s[i].energy * f) - 100 - i;
						} else if (i % 6 === 0) {
							s[i].explode();
						} else {
							s[i].remove(true);
						}
					}
				}
			}
		}
		// Remove some rocks
		s = system.entitiesWithScanClass("CLASS_ROCK", player.ship, 3072000);
		if (s.length < 1) {
			return;
		}
		l = Math.ceil(s.length * 0.35);
		i = l;
		while (i--) {
			if (s[i].isValid) {
				if ((i % 2 === 0) && (s[i].distanceToPlayer > 30000)) {
					s[i].explode();
				} else {
					s[i].remove(true); // no death action
				}
			}
		}
	};
	this._addInvasionEntities = function(pos) {
		var baseThargoidNum, basePoliceNum, i, n, n2, r, s;
		// THARGOIDS
		if (player.score < 5000) {
			baseThargoidNum = 18;
		} else {
			baseThargoidNum = 23;
		}
		// log("ET TESTING", "OK");
		// Main action - carriers and other ships
		if (this.$roleExists("thargoidCarrier") !== undefined && system.mainStation && Math.random() < 0.9) {
			n = 1 + Math.ceil(Math.random() * 2);
			if (n === 1 && Math.random() < 0.5) {
				n++;
			}
			i = n;
			while (i--) {
				s = system.addShips("thargoid_carrier", 1, pos, 26000);
				s[0].script.targetStation = system.mainStation;
				s[0].script.destinationCoordinates = system.mainStation.position;
				if (Math.random() < 0.6) {
					s = system.addShips("extraThargoids_sweeper", 1, pos, 15000);
				}
			}
			baseThargoidNum -= 5; // if (baseThargoidNum < 10) {baseThargoidNum = 10;}
			if (Math.random() < 0.7) {
				s = system.addShips("extraThargoids_uberBuggly", 1, pos, 20000); // has sweeper escorts
				baseThargoidNum -= 1;
			}
		} else if (Math.random() < 0.92) {
			s = system.addShips("extraThargoids_uberBuggly", 1, pos, 17000); // has sweeper escorts
			baseThargoidNum -= 2;
			if (Math.random() < 0.57) {
				s = system.addShips("extraThargoids_uberBuggly", 1, pos, 20000); // has sweeper escorts
				baseThargoidNum -= 1;
			}
		}
		s = system.addShips("thargoid", baseThargoidNum, pos, 20000);
		// Witchspace - planet
		n = Math.ceil(Math.random() * baseThargoidNum);
		s = system.addShipsToRoute("thargoid", baseThargoidNum, Math.random(), "wp");
		// POLICE
		// Main action - normal ships and carriers
		basePoliceNum = baseThargoidNum + 2 + Math.ceil(Math.random() * 4);
		if (Math.random() < 0.7) {
			n = 1 + Math.ceil(Math.random() * 5);
			s = system.addShips("interceptor", n, pos, 23000);
			if (s[0] && s[0].isValid) {
				basePoliceNum--;
			}
		}
		r = Math.random();
		if (r < 0.7) {
			s = system.addShips("behemoth", 1, pos, 23000);
			if (r < 0.35) {
				s = system.addShips("behemoth", 1, pos, 32000);
			}
			if (s[0] && s[0].isValid) {
				basePoliceNum -= 2;
			} // have done no check actually are these ships installed
		}
		if (Math.random() < 0.5) {
			s = system.addShips("leviathan", 1, pos, 23000);
			basePoliceNum -= 2;
			if (s[0] && s[0].isValid) {
				basePoliceNum -= 2;
			} // have done no check actually are these ships installed
		}
		if (basePoliceNum > 0) {
			s = system.addShips("police", basePoliceNum, pos, 20000);
		}
		// Witchpoint - planet
		if (Math.random() < 0.5) {
			n = 1 + Math.ceil(Math.random() * basePoliceNum);
			s = system.addShipsToRoute("police", n, Math.random(), "wp");
		}
		// HUNTERS
		r = Math.random();
		if (r < 0.25) {
			n = 1 + Math.ceil(Math.random() * 2);
			s = system.addShips("hunter-medium", n, pos, 35000);
		}
		if (r < 0.2) {
			n = 1 + Math.ceil(Math.random() * 3);
			s = system.addShips("hunter-heavy", n, pos, 30000);
		}
		// WRECKAGE. Note that removal of entities via removeShipsEtcForInvasion will tend to generate some wreckage.
		// At the site of the main action
		n = 1 + Math.ceil(Math.random() * 4);
		s = system.addShips("alloy", n, pos, 45000);
		n = 1 + Math.ceil(Math.random() * 9);
		s = system.addShips("extraThargoids_tharglet", n, pos, 40000);
		// Witchpoint
		r = Math.random();
		if (r < 0.6) {
			n = 1 + Math.ceil(r * 3);
			s = system.addShips("alloy", n, [0, 0, 0], 45000);
			n = 1 + Math.ceil(r * 13);
			s = system.addShips("extraThargoids_tharglet", n, [0, 0, 0], 40000);
			if (Math.random() < 0.5) {
				n2 = 1 + Math.ceil(Math.random() * 4);
				s = system.addShips("cargopod", n2, [0, 0, 0], 4000);
			}
		}
		// Witchpoint - planet
		n = 1 + Math.ceil(Math.random() * 7);
		i = n;
		while (i--) {
			n2 = 1 + Math.ceil(Math.random() * 4);
			s = system.addShipsToRoute("cargopod", n2, Math.random(), "wp");
		}
		n = 1 + Math.ceil(Math.random() * 4);
		i = n;
		while (i--) {
			n2 = 1 + Math.ceil(Math.random() * 4);
			s = system.addShipsToRoute("extraThargoids_tharglet", n2, Math.random(), "wp");
			if (Math.random() < 0.3) {
				s = system.addShipsToRoute("alloy", 1, r, "wp");
			}
		}
		s = system.addShipsToRoute("extraThargoids_tharglet", n, Math.random(), "wp");
	};
	this.systemWillRepopulate = function() {
		// It is important for smooth gameplay that this function runs very quickly. If calculations are needed, run as many as possible in the populator function to save the result.
		// 'systemWillRepopulate' does *not* use system.setPopulator 
		if (this.invasionExtantInCurrentSystem === false) {
			return;
		}
		// THE FOLLOWING ONLY RUNS *WHEN IS AN INVASION*
		if (this.repopulationsCounter > this.maxRepopulations) {
			return;
		}
		// Else
		this.repopulationsCounter++;
		if (Math.random() > 0.04) {
			return;
		}
		// Else
		var i, g, n, s, s2;
		// Perhaps add police
		if (Math.random() < 0.45) {
			n = system.countShipsWithRole("police");
			if (n > 50) {
				return;
			}
			// Else
			n = 3 + Math.ceil(Math.random() * 8);
			if (this.threeG_Installed && r < 0.015) {
				s = system.addShips("ferdelance3G_interstellar", n);
				i = s.length;
				while (i--) {
					s[i].ai.switchAI("route1patrolAI.plist");
					// Need to set AI to stop them trying to go interstellar
				}
			} else {
				s = system.addShips("police", n);
			}
			return;
		}
		// perhaps add thargoids
		if (Math.random() < 0.35) {
			n = system.countShipsWithRole("thargoid");
			if (n > 150) {
				return;
			}
			n = 2 + Math.ceil(Math.random() * 30);
			s = system.addShips("thargoid", n);
			return;
		}
		// Else, add hunters
		s = system.addShips("hunter-heavy", 1);
		if (s[0]) {
			g = new ShipGroup("hunter group vs invasion", s[0]);
			s[0].group = g;
			log("ET TESTING", "add hunter-heavy(" + g.name + ") to ...");
			// TODO: Set weapons, skill, AI
			if (s[0].autoAI) {
				s[0].switchAI("oolite-bountyHunterLeaderAI.js");
			}
			n = 2 + Math.ceil(Math.random() * 5);
			s2 = system.addShips("hunter", n);
			for (i = 0; i < n; i++) {
				s2[i].group = g;
				g.addShip(s2[i]);
				// s2[i].setAI("oolite-bountyHunterAI.js"); // autoAI
			}
			// log("ET TESTING", "added "+n+" hunters("+g.name+") to ...");
		}
	};
	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) dummyShips[0].remove(true);
		return exists;
	};
	/*
	----------------------
	JSHINT: end of wrapper
	----------------------
	*/
}).call(this);
// EOF | 
| Scripts/extraThargoids_sweeper.js | /*
========================================================================
extraThargoids_sweeper.js
This file is part of the ExtraThargoids expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/
/*
-------------------
JSLINT: set options
-------------------
*/
/*jshint esversion: 6*/
/*jshint sub:true*/
this.name = "extraThargoids_sweeper";
this.author = "UK_Eliter";
this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
this.licence = "CC-NC-SA 3";
this.description = "Script for Thargon sweepers";
/*
------------------
DEBUGGING SWITCHES
------------------
*/
//this.logging = true; // THIS SHOULD BE COMMENTED OUT WHEN NOT TESTING
//var consoleDebugMessages = false;
/*
--------------
VARIABLES etc.
--------------
*/
this.sweep = new SoundSource();
this.sweep.sound = "extraThargoids_sweep.ogg";
this.mediumSweep = new SoundSource();
this.mediumSweep.sound = "extraThargoids_mediumSweep.ogg";
this.quietSweep = new SoundSource();
this.quietSweep.sound = "extraThargoids_quietSweep.ogg";
/*
------------------------
JSHINT: start of wrapper
------------------------
*/
(function() {
	"use strict";
	/*
	--------------
	EVENT HANDLERS
	--------------
	*/
	this.shipSpawned = function() {
		// If the scanTimer does not exist, create it.
		// If it does exist, and it is not running, start it.
		// Then - as usual - remove the ship object created by this function.
		if (!this.$scanTimer) {
			this.$scanTimer = new Timer(this, this.$scan, 1, 2.8);
		} else if (!this.$scanTimer.isRunning) {
			this.$scanTimer.start();
		}
		delete this.shipSpawned;
	};
	this.shipDied = this.entityDestroyed = this.playerWillEnterWitchspace = function() {
		this.$deleteTimers();
	};
	/*
	------------
	CALLED BY AI
	------------
	*/
	this.$_incomingMissile = function() {
		// This run (only) by extraThargoids_sweeperAI
		if (this.$incomingMissileTimer) {
			if (this.$incomingMissileTimer.isRunning) {
				return;
			} else {
				this.$incomingMissileTimer.start();
			}
		} else {
			this.$incomingMissileTimer = new Timer(this, this.$incomingMissileActual, 0.2);
		}
	};
	this.$_validateTarget = function() {
		if (this.ship.target && !this.ship.target.isThargoid) {
			this.ship.reactToAIMessage("TARGET_VALID");
		} else {
			this.ship.reactToAIMessage("TARGET_INVALID");
		}
	};
	this.$_sophistatedBeligerentAttackResponse = function() {
		// = if has this missile type, fire it, else . .
		if (this.ship.fireMissile("EQ_THARGON") == null) {
			this.ship.reactToAIMessage("DO_ATTACK");
		}
	};
	this.$_checkForPossiblyFarThargoids = function() {
		var s = system.filteredEntities(this, this.$isBug, this.ship, 55000);
		if (s.length > 0) {
			this.ship.reactToAIMessage("TARGET_FOUND"); // AI does actual SETTING of the target
		} else if (s.length > 0) {
			this.ship.reactToAIMessage("NOTHING_FOUND");
		}
	};
	/*
	-------
	FILTERS
	-------
	*/
	this.$poppable = function(e) {
		return e.isShip && (e.isMissile || e.isMine);
	};
	this.$isBug = function(e) {
		return (e.isShip && e.isThargoid);
	};
	this.$isTarget = function(e) {
		return e.isShip && (e.isMissile || e.isMine) && e.primaryRole !== "EQ_BUGGLYMISSILE" && e.name !== "Thargoid Projectile";
	};
	/*
	-------
	GENERAL
	-------
	*/
	this.$scan = function() {
		/*
		MASSES:
			MM Hardened Missile: 114 (!)M
			Nexus premium warhead: 67ish
			mini-missile mass: 114
			intercept missile mass: 210.3
			q-bomb: 135
			normal mass: 1324
			hardhead mass: 1638
			TCAT_claw: 472.5
			TCAT_talon: 135
			s[c].hasRole("EQ_HARDENED_MISSILE") || s[c].hasRole("armoury_MMHardMissile" || s[c].hasRole("EQ_MISSILE")
		*/
		if (!this.ship) {
			return;
		}
		if (this.$incomingMissileTimer && this.$incomingMissileTimer.isRunning) {
			return;
		}
		this.ship.lightsActive = false; // turn them off, in case they've been turned on before
		if (this.ship.energy < 45) {
			return;
		}
		this.ship.energy -= 1; // merely scanning takes a bit of energy
		var s = system.filteredEntities(this, this.$isTarget, this.ship, 26000);
		var num = s.length;
		if (num === 0) {
			return;
		}
		// What follows  starts going through all ordinance at large, and stops when the sweeper detects one of those pieces (or when reaches end of list)
		var detected = false;
		var chance;
		var c = num;
		while (c--) {
			if (s[c].mass < 125) {
				chance = 0.05;
			} else {
				chance = 0.86;
			}
			if (this.ship.position.distanceTo(s[c]) < 15000) {
				chance += 0.12;
			}
			if (Math.random() <= chance) {
				detected = true;
				break;
			}
		}
		// if has been a detection, sweeper fires its special ECM . .
		if ((detected) && (this.ship.energy > 14)) {
			this.$actualSweep();
		}
	};
	this.$actualSweep = function() {
		this.ship.lightsActive = true;
		this.ship.energy -= 14; // takes more energy to destroy (or try to destroy, anyway) something
		var s = system.filteredEntities(this, this.$poppable, this.ship, 26000);
		var num = s.length;
		if (num > 0) {
			var c = num;
			var chance;
			while (c--) {
				// log("EXTRA", s[c].primaryRole);
				switch (s[c].primaryRole) {
					case "TCAT_talon":
						chance = 0.05;
						break;
					case "TCAT_claw":
						chance = 0.035;
						break;
					case "EQ_BUGGLYMISSILE":
						chance = 0.01;
						break;
					case "EQ_F3G_ANTISWEEP_MISSILE":
						chance = 0.02;
						break;
					default:
						chance = 0.97;
				}
				if (Math.random() <= chance) {
					var damage = 16 + (Math.ceil(Math.random() * 40));
					if (s[c].energy <= damage) {
						s[c].explode();
					} else {
						s[c].energy -= damage;
					}
				}
			}
		}
		if (!this.ship || !player.ship) {
			return;
		}
		var ps = player.ship; // for speed, but changes won't affect the original variable
		var distanceToPlayer = this.ship.position.distanceTo(ps);
		if (distanceToPlayer < 28000) {
			if (distanceToPlayer < 13000) {
				this.sweep.play();
				if (Math.random() > 0.83) {
					this.ship.commsMessage(expandDescription("[thargoid_curses]", ps));
				}
			} else if (distanceToPlayer < 17500) {
				this.mediumSweep.play();
				if (Math.random() > 0.9) {
					this.ship.commsMessage(expandDescription("[thargoid_curses]", ps));
				}
			} else {
				this.quietSweep.play();
				if (Math.random() > 0.95) {
					this.ship.commsMessage(expandDescription("[thargoid_curses]", ps));
				}
			}
		}
	};
	this.$incomingMissileActual = function $incomingMissileActual() {
		this.$incomingMissileTimer.stop();
		if (this.ship.energy > 14) {
			this.$actualSweep();
		} else {
			this.ship.reactToAIMessage("GO_FLEE");
		}
	};
	/*
	-------
	CLEANUP
	-------
	*/
	this.$deleteTimers = function() {
		this.$deleteIncomingMissileTimer();
		this.$deleteScanTimer();
	};
	this.$deleteIncomingMissileTimer = function() {
		if (!this.$incomingMissileTimer) {
			return;
		}
		if (this.$incomingMissileTimer.isRunning) {
			this.$incomingMissileTimer.stop();
		}
		delete this.$incomingMissileTimer;
	};
	this.$deleteScanTimer = function() {
		if (!this.$scanTimer) {
			return;
		}
		if (this.$scanTimer.isRunning) {
			this.$scanTimer.stop();
		}
		delete this.$scanTimer;
	};
	/*
	----------------------
	JSHINT: end of wrapper
	----------------------
	*/
}).call(this);
// EOF | 
| Scripts/extraThargoids_uber.js | /*
========================================================================
extraThargoids_uber.js
This file is part of the ExtraThargoids expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/
/*
-------------------
JSLINT: set options
-------------------
*/
/*jshint esversion: 6*/
/*jshint sub:true*/
this.name = "thargoid_uberbuggly";
this.author = "UK_Eliter";
this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
this.licence = "CC-NC-SA 3";
this.description = "Script for the 'uberbuggly' Thargon ships";
/*
------------------
DEBUGGING SWITCHES
------------------
*/
// this.logging = true;
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.
/*
------------------------
JSHINT: start of wrapper
------------------------
*/
(function() {
	"use strict";
	/*
	--------------
	EVENT HANDLERS
	--------------
	*/
	this.shipTargetCloaked = function() {
		var seconds;
		if (this.decloakTargetTimer && this.decloakTargetTimer.isRunning) {
			return;
		}
		if (this.ship.target.isThargoid) {
			return;
		}
		if (Math.random() < 0.13) {
			return;
		}
		if (Math.random() > 0.4) {
			this.ship.commsMessage(expandDescription("[thargoid_curses]"));
		}
		this.ship.cloakedTarget = this.ship.target;
		seconds = (1 + Math.floor(Math.random() * 6));
		if (this.decloakTargetTimer) {
			delete this.decloakTargetTimer;
		}
		this.decloakTargetTimer = new Timer(this, this.$decloakTargetTimed, seconds);
	};
	this.shipDied = this.entityDestroyed = this.playerWillEnterWitchspace = function() {
		this.$_deleteTimers();
	};
	/*
	------------
	CALLED BY AI
	------------
	*/
	this.$_deleteTimers = function() {
		if (!this.decloakTargetTimer) {
			return;
		}
		if (this.decloakTargetTimer.isRunning) {
			this.decloakTargetTimer.stop();
		}
		delete this.decloakTargetTimer;
	};
	this.$_deleteTimersAndSetMisJump = function() {
		this.ship.scriptedMisjump = true;
		this.$_deleteTimers();
	};
	this.$_curse = function() {
		this.ship.commsMessage(expandDescription("[thargoid_curses]"));
	};
	this.$_possiblyCurse = function() {
		if (Math.random() < 0.35) {
			this.ship.commsMessage(expandDescription("[thargoid_curses]"));
		}
	};
	this.$_fireQuirium = function() {
		this.ship.awardEquipment("EQ_QC_MINE");
		this.ship.fireMissile("EQ_QC_MINE");
		this.$_possiblyCurse();
		this.$_deleteTimers();
	};
	/*
	-----
	OTHER
	-----
	*/
	this.$decloakTargetTimed = function() {
		this.decloakTargetTimer.stop();
		if (!this.ship || !this.ship.isValid) {
			delete this.decloakTargetTimer;
			return;
		}
		if (!this.ship.cloakedTarget || !this.ship.cloakedTarget.isValid) {
			delete this.decloakTargetTimer;
			return;
		}
		if (!this.ship.cloakedTarget.isCloaked) {
			delete this.decloakTargetTimer;
			return;
		}
		this.distanceToTarget = this.ship.position.distanceTo(this.ship.cloakedTarget);
		if (this.distanceToTarget < 10000) {
			mysound_Warning.play();
			this.ship.cloakedTarget.lightsActive = true;
			if (Math.random() > 0.9) {
				this.ship.cloakedTarget.setEquipmentStatus("EQ_CLOAKING_DEVICE", "EQUIPMENT_DAMAGED");
				if (this.ship.cloakedTarget.isPlayer && !player.ship) {
					delete this.decloakTargetTimer;
					return;
				}
				this.ship.commsMessage("CLOAKING DEVICE DAMAGED!", this.ship.cloakedTarget);
				this.ship.target = this.ship.cloakedTarget;
				this.ship.reactToAIMessage("TARGET_REGAINED");
			} else {
				player.consoleMessage("CLOAKING FAILURE!", 10);
				player.ship.isCloaked = false;
				this.ship.target = this.ship.cloakedTarget;
				this.ship.reactToAIMessage("TARGET_REGAINED");
			}
		}
		if (Math.random() < 0.26) {
			this.ship.commsMessage(expandDescription("[thargoid_curses]"));
		}
		delete this.decloakTargetTimer;
	};
	/*
	----------------------
	JSHINT: end of wrapper
	----------------------
	*/
}).call(this);
// EOF |