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 |