| Back to Index | Page generated: Sep 15, 2026, 9:03:40 PM |
| 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 | 7.0 | 7.0 |
| 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 | 1789431282 |
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 | /*
////////////////////////////////////////////////////////////////////////////////
This file: nexus_warhead_basicOrPremiumOrUltimate.js
Associated AI(s): extraThargoids_kamikazeAI.plist
extraThargoids_bugglyAI.plist
Part of: extraThargoids OXP
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike
//////////////////////////////////////////////////////////////////////////////////
*/
/*
==============
LINTER OPTIONS
==============
*/
/* jshint esversion: 6 */
/* jshint -W030 */
/*
======
HEADER
======
*/
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";
/*
==================
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.entityDestroyed = function() {
this.$deleteTimers();
};
this.playerWillEnterWitchspace = function() {
this.$deleteTimers();
};
this.shipDied = function() {
this.$deleteTimers();
};
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.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);
};
/*
------------
CALLED BY AI
------------
*/
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);
};
/*
-----
OTHER
-----
*/
this.$checkStunTimed = function $checkStunTimed() {
if (this.ship.AIState == 'STUNNED') {
this.ship.exitAI();
this.explode_notCausedByPlayer();
}
};
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.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.$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;
}
};
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.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);
};
/*
----------------------
JSLINT: end of wrapper
----------------------
*/
}).call(this);
// EOF |
| Scripts/extraThargoids_exploding_generic.js | /*
////////////////////////////////////////////////////////////////////////////////
This file: extraThargoids_exploding_generic.js
Associated AI(s): extraThargoids_exploding_causedByPlayerAI
extraThargoids_exploding_notCausedByPlayerAI.plist
Part of: extraThargoids OXP
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike
//////////////////////////////////////////////////////////////////////////////////
*/
/*
==============
LINTER OPTIONS
==============
*/
/* jshint esversion: 6 */
/* jshint -W030 */
/*
======
HEADER
======
*/
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' thargoid ships";
/*
==================
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 | /*
////////////////////////////////////////////////////////////////////////////////
This file: extraThargoids_frigatePoet.js
Associated AI(s): thargoidAI (which is inbuilt)
Part of: extraThargoids OXP
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike
//////////////////////////////////////////////////////////////////////////////////
*/
/*
==============
LINTER OPTIONS
==============
*/
/* jshint esversion: 6 */
/* jshint -W030 */
/*
======
HEADER
======
*/
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.entityDestroyed = function() {
this.$cleanUp();
};
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.shipDied = function() {
this.$cleanUp();
};
this.shipEnergyIsLow = function() {
if (Math.random() > 0.13) {
this.ship.isCloaked = false;
this.$displace();
}
};
this.shipSpawned = function() {
this.canDisplaceCurrently = true;
delete this.shipSpawned;
};
this.shipTargetCloaked = function() {
if (Math.random() > 0.82) {
this.$displace();
}
if (this.ship.target) {
this.ship.target = null;
}
};
/*
-----
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;
}
const ps = player.ship; // for speed, but changes won't affect the original variable
const xDistance = ((Math.random() * 2) - 1) * 8600;
const yDistance = ((Math.random() * 2) - 1) * 8600;
const 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);
}
const 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;
}
}
const 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 | /*
//////////////////////////////////////////////////////////////////////////////////
This file: extraThargoids_populator.js
Author: UK_Eliter
Part of: extraThargoids OXP
License: 2017 Creative Commons: attribution, non-commercial, sharealike
//////////////////////////////////////////////////////////////////////////////////
*/
/*
==============
LINTER OPTIONS
==============
*/
/* jshint esversion: 6 */
/* jshint -W030 */
/*
======
HEADER
======
*/
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';
/*
--------------
EVENT HANDLERS
--------------
*/
this.entityDestroyed = function () {
this.invasionExtantInCurrentSystem = false;
};
this.interstellarSpaceWillPopulate = function () {
// INTERSTELLAR POPULATOR
// Use 'callback: this._myFunction.bind(this)' - as Vs 'callback: this._myFunction' - in order to use global variables and global functions.
// if two populator entries have same 'priority', Oolite will randomly determine their order.
// ADD THARGOIDS
system.setPopulator('extraThargs-interstellarThargoids', {
priority: 101,
callback: this._perhapsAddInterstellarThargoids.bind(this)
});
};
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
};
// INTERSTELLAR _RE_POPULATOR - none
/*
this.interstellarSpaceWillRepopulate = function()
{
}
*/
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);
}
};
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.startUp = function () {
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.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.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;
this.repopulationsCounter++;
if (Math.random() > 0.05) return;
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);
s = system.addShips('interceptor', 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;
// 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
}
}
};
/*
-----
OTHER
-----
*/
this._addInvasionEntities = function (pos) {
var
baseThargoidNum,
basePoliceNum,
i,
n,
n2,
r,
s;
// THARGOIDS
if (player.score < 5000) {
baseThargoidNum = 18;
} else {
baseThargoidNum = 23;
}
// 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;
}
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 {
s = system.addShips('extraThargoids_uberBuggly', 2, pos, 37000); // has sweeper escorts
baseThargoidNum -= 2;
}
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;
}
if (Math.random() < 0.5) {
s = system.addShips('leviathan', 1, pos, 23000);
basePoliceNum -= 2;
if (s[0] && s[0].isValid) basePoliceNum -= 2;
}
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_uncontrolled', 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_uncontrolled', n2, Math.random(), 'wp');
if (Math.random() < 0.3) {
s = system.addShipsToRoute('alloy', 1, r, 'wp');
}
}
s = system.addShipsToRoute('extraThargoids_tharglet_uncontrolled', n, Math.random(), 'wp');
};
this._perhapsAddInterstellarThargoids = function () {
if (!player.ship.isValid) return;
// log('extraThargoids_populator.js', 'Considering adding thargoids to interstellar space by populator script.'); // TEST
const pos = player.ship.position;
var
n,
s;
if (player.score > 3750) {
n = 37;
} else {
n = 42;
}
switch (Math.ceil(Math.random() * n)) {
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, 19000);
break;
case 10:
s = system.addShips('extraThargoids_sweeper', 1, pos, 24000);
break;
case 11:
s = system.addShips('extraThargoids_sweeper', 1, pos, 28000);
break;
case 12:
s = system.addShips('extraThargoids_sweeper', 2, pos, 30000);
break;
case 13:
s = system.addShips('extraThargoids_meany', Math.ceil(Math.random() * 8), pos, 20000);
break;
default:
}
};
this.$is_targettedNonMainStation = function (e) {
return e.isStation &&
e.scanClass === 'CLASS_STATION' &&
(e.position.distanceTo(system.mainPlanet.position) < system.mainPlanet.radius * 13);
};
this.$is_witchpointBuoy = 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_targettedNonMainStation, system.mainStation);
for (i = 0; i < s.length; i++) {
if (!s[i].isValid) {
continue;
}
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.$is_witchpointBuoy);
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) continue;
if ((i % 2 === 0) && (s[i].distanceToPlayer > 30000)) {
s[i].explode();
} else {
s[i].remove(true); // no death action
}
}
};
this.$roleExists = function (roleString) {
const dummyShips = system.addShips(roleString, 1, [100000, 100000, 100000]);
if (dummyShips == null) return false;
const exists = (dummyShips.length == 1);
if (exists) dummyShips[0].remove(true);
return exists;
};
/*
----------------------
JSHINT: end of wrapper
----------------------
*/
}).call(this);
// EOF |
| Scripts/extraThargoids_sweeper.js | /*
////////////////////////////////////////////////////////////////////////////////
This file: extraThargoids_sweeper.js
Associated AI(s): extraThargoids_sweeperAI.plist
Part of: extraThargoids OXP
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike
//////////////////////////////////////////////////////////////////////////////////
*/
/*
==============
LINTER OPTIONS
==============
*/
/* jshint esversion: 6 */
/* jshint -W030 */
/*
======
HEADER
======
*/
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.entityDestroyed = function () {
this.$deleteTimers();
};
this.playerWillEnterWitchspace = function () {
this.$deleteTimers();
};
this.shipDied = 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.$_validateAttackerAsTarget = function () {
if (
this.ship.target &&
(!(this.ship.target.isThargoid) || this.ship.target.primaryRole === 'thargoidRebel')
) {
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
return;
}
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;
}
const ps = player.ship;
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 | /*
////////////////////////////////////////////////////////////////////////////////
This file: extraThargoids_uber.js
Associated AI(s): extraThargoids_uberAI.plist
Part of: extraThargoids OXP
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike
//////////////////////////////////////////////////////////////////////////////////
*/
/*
==============
LINTER OPTIONS
==============
*/
/* jshint esversion: 6 */
/* jshint -W030 */
/*
======
HEADER
======
*/
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' Thargoid 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.entityDestroyed = function() {
this.$_deleteTimers();
};
this.playerWillEnterWitchspace = function() {
this.$_deleteTimers();
};
this.shipDied = function() {
this.$_deleteTimers();
};
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);
};
/*
------------
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 |