| Scripts/IST_masterScript.js |
/*
===============================================================================================
This file: IST_masterScript.js
Part of Interstellar Tweaks OXP
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike
____ __ __ ____ ______ __
/ _/___ / /____ __________/ /____ / / /___ ______ /_ __/ _____ ____ _/ /_______
/ // __ \/ __/ _ \/ ___/ ___/ __/ _ \/ / / __ `/ ___/ / / | | /| / / _ \/ __ `/ //_/ ___/
_/ // / / / /_/ __/ / (__ ) /_/ __/ / / /_/ / / / / | |/ |/ / __/ /_/ / ,< (__ )
/___/_/ /_/\__/\___/_/ /____/\__/\___/_/_/\__,_/_/ /_/ |__/|__/\___/\__,_/_/|_/____/
For Oolite >= 1.82.
===============================================================================================
*/
/*
=====================
C O N T E N T S table
for what follows
=====================
1 SET LINTER OPTIONS
2 HEADER
3 DEBUGGING: set switches
4 SOUNDS
5 CONSTANTS & VARIABLES
6 DEBUGGING: apply switches
7 WRAPPER FOR JSLINT, start
8 ERROR & MESSAGE HANDLING
9 FINDING & MOVING, ADDING & REMOVING
10 TIMER HANDLING
11 MISCELLANEOUS
12 EVENT HANDLERS
13 MAIN TWEAKING ROUTINES
14 End of WRAPPER FOR JSLINT
*/
/*
======================
1 SET LINTER OPTIONS
======================
*/
/* jshint esversion: 6 */
/* jshint -W030 */
/*
==========
2 HEADER
==========
*/
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';
/*
===========================
3 DEBUGGING: set switches
===========================
*/
this.dbg_full = false;
// false.
// See below (5) for effects.
// If set to true, then, later, the script changes this.dbg to true.
this.dbg = 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.
/*
==========
4 SOUNDS
==========
*/
// 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';
/*
=========================
5 CONSTANTS & VARIABLES
=========================
*/
this.escapeSequence = {
prob_thargoidsGetPod: 0.08,
rescueProb: 0.86
};
this.galNum = 0; // We set this in this.playerEnteredNewGalaxy and in
this.initialisedAtFirstLaunch = false;
this.interstellar_data = {
// origin, // Set on fly
misJumpInducedByScript_prob: 0.03, // 0.03
scenario: '',
subScenario: '',
scenarios: {
all: {
genShipsRemove_prob: 0.85, // 0.85. Applies to ALL scenarios. The generationShips OXP seems to spawn a genship on a 0.3 chance.
thargoidBattleshipsLimit: {
prob: 0.87, // 0.87
maxShips: 3 // 3
},
wouldBeHelpee_remove_prob: 0.85 // 0.85
},
tweak_prob: 0.57, // 0.57; the chance of just about any tweak.
versions: {
modifiedOrNovel: {
derelict_range: 27000, // 27000; can be 'offset', though.
offset: {
distance_biasTowardsMin: 5,
// Oolite scanner range is 25600 meters
distance_max: 140000, // 140000
distance_min: 7000, // 7000
prob: 0.08, // 0.08
},
novel_prob: 0.59, // 0.59. As Vs 'modified'.
repopulation: {
num: 0,
num_max_current: 0,
num_max_ever: 50, // 50
prob: 0.12, // 0.12
probEver: 0.49 // 0.49
}, // Cf. scenarios.novel.repopulation
},
modified: {
battleOccured: {
prob: 0.6, // 0.6
prob_derelict: 0.14, // 0.14
prob_wreckageOnly: 0.25 // 0.25
},
probOverrideThargoidOXPs: 0.8,
/*
^ 0.8. As a comment below says, this 'override' does not actually prevent ships being added.
See also above on `thargoidBattleshipsLimit`.
*/
subScenarios: {
navyAdd: {
maxNum: 15 // 15
},
navyOnly: {
maxNum: 7, // 7
prob: 0.5 // 0.5
},
thargoidsOnly: {
baseNum: 6, // 6
prob: 0.6 // 0.6
},
},
},
novel: {
chosenSubScenario: null,
repopulation: {
navy: {
baseNum: 4,
maxMil: 15,
probIgnoreParity: 0.2, // 0.2
threeG: {
prob: 0.18, // 0.18
squadSize: 5
}
},
thargoid: {
maxThargs: 35, // 35
probIgnoreMax: 0.15 // 0.15
},
},
subScenarios_individual: {
aliens: {
maxNum: 13 // 13
},
asteroids: {
miners_prob: 0.18 // 0.18
},
derelict: {
lives_prob: 0.14 // 0.14
},
hunters: {
baseNum: 3 // 3
},
lobsters: {
num: 11 // 11
},
pirates: {
baseNum: 4 // 4
},
radiation: {
player: {
damagePerRun: {
heatShield: 2.85, // 2.95
standard: 3.8, // 3.8. If one changes this, then change 'heatshield' proportionally.
}, // Interval gets set by 'standard'
},
nonPlayer: {
damagePerRun: {
heatShield: 33.75, // 33.75
standard: 45, // 45. If one changes this, then change the other two values proportionally.
thargoid: 30 // 30
}, // interval gets set by via 'standard' and calculated damage-to-player-per-second
},
},
thargoids: {
baseNum: 4, // 4
prob_genShip: 0.02, // 0.02
},
thargoidsRebels: {
baseNum: 1, // 1
}
},
// To force a subscenario, may need to set a probability to something like 100.
subScenarios: [{
key: 'aliens',
weight: 0.05, // 0.05
members: ['aliens']
}, {
key: 'aliens+asteroids',
weight: 0.01, // 0.01
members: ['aliens', 'asteroids']
}, {
key: 'aliens+hunters',
weight: 0.015, // 0.015
members: ['aliens', 'hunters']
}, {
key: 'aliens+pirates',
weight: 0.014, // 0.014
members: ['aliens', 'pirates']
}, {
key: 'aliens+hunters+pirates',
weight: 0.01, // 0.01
members: ['aliens', 'hunters', 'pirates']
}, {
key: 'asteroids',
weight: 0.06, // 0.06. Asteroid (sub)scenarios get inflected by galaxy.
members: ['asteroids']
}, {
key: 'asteroids+hunters',
weight: 0.01, // 0.01
members: ['asteroids', 'hunters']
}, {
key: 'derelicts',
weight: 0.04, // 0.04
members: ['derelicts']
}, {
key: 'derelicts+asteroids',
weight: 0.02, // 0.02
members: ['derelicts', 'asteroids']
}, {
key: 'empty',
weight: 0.19, // 0.19
members: ['empty']
}, {
key: 'hunters',
weight: 0.07, // 0.07
members: ['hunters']
}, {
key: 'lobsters',
weight: 0.04, // 0.04. Lobster (sub)scenarios get inflected by galaxy.
members: ['lobsters']
}, {
key: 'pirates',
weight: 0.02, // 0.02. Pirate (sub)scenarios get inflected by government levels.
members: ['pirates']
}, {
key: 'radiation',
weight: 0.05, // 0.05. Gets inflected by galaxy.
members: ['radiation']
}, {
key: 'thargoids',
weight: 0.32, // 0.32
members: ['thargoids']
}, {
key: 'thargoids+aliens',
weight: 0.05, // 0.05
members: ['thargoids', 'aliens']
}, {
key: 'thargoids+aliens+hunters',
weight: 0.02, // 0.02
members: ['thargoids', 'aliens', 'hunters']
}, {
key: 'thargoids+aliens+hunters+pirates',
weight: 0.01, // 0.01
members: ['thargoids', 'aliens', 'hunters', 'pirates']
}, {
key: 'thargoids+hunters',
weight: 0.09, // 0.09
members: ['thargoids', 'hunters']
}, {
key: 'thargoids+hunters+pirates',
weight: 0.01, // 0.01
members: ['thargoids', 'hunters', 'pirates']
}, {
key: 'thargoids+lobsters',
weight: 0.01, // 0.01
members: ['thargoids', 'lobsters']
}, {
key: 'thargoids+pirates',
weight: 0.02, // 0.02
members: ['thargoids', 'pirates']
}, {
key: 'thargoidsRebels',
weight: 0.012, // 0.012. Rebel (sub)scenarios get inflected by galaxy.
members: ['thargoidsRebels']
}, {
key: 'thargoidsRebels+aliens',
weight: 0.01, // 0.01
members: ['thargoidsRebels', 'aliens']
}, {
key: 'thargoidsRebels+thargoids',
weight: 0.015, // 0.015. Occasionally this combination will occur via other means.
members: ['thargoidsRebels', 'thargoids']
},
// NB: forbidden combinations are simply omitted.
]
// See also: this.playerEnteredNewGalaxy
},
unmodified: {}
}
},
scripts: {
populators: {},
repopulators: {}
},
timing: {
// Values are in seconds (decimals allowed); the relevant routine fires that amount of seconds after the relevant event.
runTweak_2: 0.25,
/*
^ 0.25. Needs to be high enough to: 1) be able to zap OXP ships added at WillExitWitchspace; 2) help (other) ships to get moving by the time of tweak_3.
*/
runTweak_3: 0.25,
/*
^ 0.25. Needs to be high enough to: 1) be able to zap OXP ships added at exitedWitchspace; 2) help ships get moving.
Yet, needs to be low enough not to keep player waiting.
*/
},
};
const script = this; // Needed (under Oolite's javascript engine) for this.interstellar_codeForNovel.
this.interstellar_codeForNovel = {
_chosenSubScenario: null,
novelSubScenario_choose: function () {
var data = script.interstellar_data.scenarios.versions.novel;
var total = 0;
var i;
for (i = 0; i < data.subScenarios.length; i++) {
total += data.subScenarios[i].weight;
}
var r = script.$randomOrPseudo(0.2, 700000) * total;
var cumulative = 0;
var chosenSubScenario = data.subScenarios[data.subScenarios.length - 1];
for (i = 0; i < data.subScenarios.length; i++) {
cumulative += data.subScenarios[i].weight;
if (r < cumulative) {
chosenSubScenario = data.subScenarios[i];
break;
}
}
data.chosenSubScenario = chosenSubScenario;
return chosenSubScenario.key;
},
novelSubScenario_run: function (args) {
var data = script.interstellar_data.scenarios.versions.novel;
var subScenario = data.chosenSubScenario;
if (!subScenario) return;
var i;
for (i = 0; i < subScenario.members.length; i++) {
var key = subScenario.members[i];
this.executors[key](args);
}
data.chosenSubScenario = null;
},
executors: {
aliens: function (args) {
const cfg = script.interstellar_data.scenarios.versions.novel.subScenarios_individual.aliens;
script.$scenarioAdd_ships_aliens(
(1 + ~~(Math.random() * cfg.maxNum)),
args.origin,
26000,
false // rings
);
},
asteroids: function (args) {
const cfg = script.interstellar_data.scenarios.versions.novel.subScenarios_individual.asteroids;
script.$scenarioAdd_ships_asteroids(
args.origin,
cfg.miners_prob
);
},
derelict: function (args) {
script.$scenarioAdd_ships_derelicts(
args.origin
);
},
hunters: function (args) {
const cfg = script.interstellar_data.scenarios.versions.novel.subScenarios_individual.hunters;
script.$scenarioAdd_ships_hunters(
cfg.baseNum,
args.origin,
15500,
false // rings
);
},
empty: function () {},
lobsters: function (args) {
const cfg = script.interstellar_data.scenarios.versions.novel.subScenarios_individual.lobsters;
script.$scenarioAdd_ships_lobsters(
cfg.num,
args.origin,
15000, // range
false // rings
);
},
pirates: function (args) {
const cfg = script.interstellar_data.scenarios.versions.novel.subScenarios_individual.pirates;
script.$scenarioAdd_ships_pirates(
cfg.baseNum,
args.origin,
15500, // range
false // rings
);
},
// radiation: function (args) { // TEST
radiation: function () {
// script.$scenarioAdd_radiation(args.origin); // Argument: TEST
script.$scenarioAdd_radiation();
},
thargoids: function (args) {
const cfg = script.interstellar_data.scenarios.versions.novel.subScenarios_individual.thargoids;
script.$scenarioAdd_ships_thargoids(
cfg.baseNum,
args.origin,
20000, // range
cfg.prob_genShip
);
},
thargoidsRebels: function (args) {
const cfg = script.interstellar_data.scenarios.versions.novel.subScenarios_individual.thargoidsRebels;
script.$scenarioAdd_ships_thargoidsRebels(
cfg.baseNum,
args.origin,
20000 // range
);
},
},
// === Call this once after setup so the originals are remembered ===
novelSubScenario_saveOriginalWeights: function () {
var data = script.interstellar_data.scenarios.versions.novel;
data._originalWeights = {};
var i;
for (i = 0; i < data.subScenarios.length; i++) {
data._originalWeights[data.subScenarios[i].key] = data.subScenarios[i].weight;
}
},
// === Change one specific subscenario by its key (e.g. 'radiation') ===
novelSubScenario_multiplyWeight: function (key, multiplier) {
var data = script.interstellar_data.scenarios.versions.novel;
if (!data._originalWeights || data._originalWeights[key] === undefined) return;
var i;
for (i = 0; i < data.subScenarios.length; i++) {
if (data.subScenarios[i].key === key) {
data.subScenarios[i].weight = data._originalWeights[key] * multiplier;
return;
}
}
},
// === Change ALL subscenarios that contain a given member (e.g. 'pirates') ===
novelSubScenario_multiplyByMember: function (member, multiplier) {
var data = script.interstellar_data.scenarios.versions.novel;
if (!data._originalWeights) return;
var i;
for (i = 0; i < data.subScenarios.length; i++) {
var sub = data.subScenarios[i];
var j;
for (j = 0; j < sub.members.length; j++) {
if (sub.members[j] === member) {
if (data._originalWeights[sub.key] !== undefined) {
sub.weight = data._originalWeights[sub.key] * multiplier;
}
break;
}
}
}
},
// === Revert one specific subscenario to its original weight ===
novelSubScenario_revertWeight: function (key) {
var data = script.interstellar_data.scenarios.versions.novel;
if (!data._originalWeights || data._originalWeights[key] === undefined) return;
var i;
for (i = 0; i < data.subScenarios.length; i++) {
if (data.subScenarios[i].key === key) {
data.subScenarios[i].weight = data._originalWeights[key];
return;
}
}
},
// === Revert ALL subscenarios that contain a given member to their original weight ===
novelSubScenario_revertByMember: function (member) {
var data = script.interstellar_data.scenarios.versions.novel;
if (!data._originalWeights) return;
var i;
for (i = 0; i < data.subScenarios.length; i++) {
var sub = data.subScenarios[i];
var j;
for (j = 0; j < sub.members.length; j++) {
if (sub.members[j] === member) {
if (data._originalWeights[sub.key] !== undefined) {
sub.weight = data._originalWeights[sub.key];
}
break;
}
}
}
},
// === Revert everything back to original ===
novelSubScenario_revertAllWeights: function () {
var data = script.interstellar_data.scenarios.versions.novel;
if (!data._originalWeights) return;
var i;
for (i = 0; i < data.subScenarios.length; i++) {
var key = data.subScenarios[i].key;
if (data._originalWeights[key] !== undefined) {
data.subScenarios[i].weight = data._originalWeights[key];
}
}
}
};
this.msgPrefix = 'Interstellar Tweaks: '; // Including a colon and trailing space
this.oxp = {};
this.oxp_overrides = {
TCAT: {
overrode: false
},
thargoidThreat: {
overrode: false
// ^ This is used to set the key for which that OXP looks, viz., this.threatOXP_modify.
}
};
this.sickness = {
isSick: false, // changed on-fly
prob_fatal: 0.4, // 0.4
prob_getting: 0, // changed on-fly
prob_getting_current: 0, // changed on-fly
willDie: false // changed on-fly
};
this.stellar = {
misplace: {
secsAfterWillExitWitchspace: 0.25,
// ^ 0.83. Cf. this.interstellar_data.timing.runTweak_2, which fires on a delay after shipWillExitWitchspace
prob: 0.025, // 0.025.
prob_nearSun: 0.16 // 0.16
}
};
/*
==============================
6 DEBUGGING: apply switches
==============================
*/
if (this.dbg_full) {
// To disable these effects, comment out the relevant lines (thereby preventing them from overriding values above).
this.dbg = true;
this.dbg_ignorePlayerRank = false; // false // NB
this.dbg_testWithMisjumps = true; // true // NB
// this.interstellar_data.scenarios.tweak_prob = 1; // NB
} else {
// DEFAULT values are as in my comments.
this.dbg_ignorePlayerRank = false;
// false
this.dbg_testWithMisjumps = false;
// false
}
if (this.dbg_testWithMisjumps) {
log('InterstellarTweaks', 'Testing with misjumps enabled.');
this.interstellar_data.scenarios.misJumpInducedByScript_prob = 1;
}
/*
==================================================
7 Start of wrapper for JSHINT
See also JSHint options above.
The following should be: 'function(){' (_sic_)
==================================================
*/
(
function () {
'use strict';
/*
============================
8 ERROR & MESSAGE HANDLING
============================
*/
this.$msg_dbg = function (txt) {
// Note in the function name the '$' and the 'this'.
if (!txt) {
player.consoleMessage('Problem with debug message text!', 30);
return;
}
player.consoleMessage(this.msgPrefix + txt, 12);
log('InterstellarTweaks', 'DEBUG: ' + txt);
};
this.$msg_err = function (txt) {
txt = txt || 'Problem with error message text!';
log('InterstellarTweaks', 'ERROR (please report): ' + txt);
this.dbg && player.consoleMessage(this.msgPrefix + 'ERROR ' + txt, 30);
};
this.$msg_player = function (txt, displaySecs) {
if (!txt || !displaySecs || displaySecs < 1) {
txt = 'Problem with message!';
this.dbg && player.consoleMessage(txt, 30);
log('InterstellarTweaks', 'ERROR (please report): ' + txt);
return;
}
player.consoleMessage(txt, displaySecs);
/*
NB: Debug text can push console messages off the screen! If that happens, then, to test the console messages,
temporarily comment out, above,
player.consoleMessage(this.msgPrefix + txt, 12);
*/
};
/*
=======================================
9 FINDING & MOVING, ADDING & REMOVING
=======================================
*/
this.$isWithinArray = function (item, array) {
return worldScripts.IST_masterScript._index_in_list(item, array) > -1;
};
/*
^ _Sic_ - see http://www.aegidian.org/bb/viewtopic.php?f=4&t=18837.
See also this script's '_index_in_list'.
*/
this.$is_thargoid = function (e) {
return e.isShip &&
e.isThargoid &&
!e.isPlayer;
};
this.$is_thargoid_battleship = function (e) {
return e.isShip &&
e.isThargoid &&
e.name === 'Thargoid Thargorn Battleship';
// The battleship lacks a distinct role, so we have to use its name.
};
this.$is_thargoid_not = function (e) {
return e.isShip &&
!e.isThargoid &&
!e.isPlayer;
};
this.$is_thargoid_obedient = function (e) {
return e.isShip &&
e.isThargoid &&
e.primaryRole !== 'thargoidRebel';
};
this.$is_navyIncompatible = function (e) {
return e.isShip &&
e.scanClass !== 'CLASS_MILITARY' &&
!e.isPlayer;
}; // Is there something wrong with this, such that it is leaving thargoids?
this.$is_navyIncompatible_allowFollowingHelpee = function (e) {
return e.isShip &&
e.scanClass !== 'CLASS_MILITARY' &&
!e.isPlayer &&
(e.primaryRole !== 'interstellar_help_trader');
};
this.$is_ship = function (e) {
return e.isShip;
};
// this.$is_ship_heavy = function (e) {
// return e.mass >= 120000000;
// };
// this.$is_ship_medium = function (e) {
// return e.mass > 1200000 && e.mass < 120000000;
// };
this.$is_unwantedInNovelInitially = function (e) {
return e.isShip &&
!e.isPlayer &&
!e.hasRole('hiredGuns_escort') &&
!e.hasRole('ecl_escape_pod_beacon') &&
!e.hasRole('escape-capsule') &&
!e.hasRole('uberBuggly') &&
!e.hasRole('generationship');
};
this.$is_unwantedInNovelInitially_allowHelpees = 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.$is_helpShip = function (e) {
return e.isShip && e.primaryRole === 'interstellar_help_trader';
};
this.$is_nonPlayer_lowEnergy_notHiredGun = function (e) {
return e.isShip &&
!e.isPlayer &&
!e.hasRole('hiredGuns_escort') &&
e.energy < 150;
};
this.$is_nonPlayer_lowEnergy = function (e) {
return e.isShip &&
!e.isPlayer &&
e.energy < 150;
};
this.$remove_navyIncompatible = function () {
// this.dbg && this.$debugMessage('Removing non-navy');
var s;
if (this.oxp.interstellarHelp && worldScripts.interstellar_help.interstellarHelp === 'FOLLOWING') {
s = system.filteredEntities(this, this.$is_navyIncompatible_allowFollowingHelpee);
} else {
s = system.filteredEntities(this, this.$is_navyIncompatible);
}
var i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].remove(true);
}
}
};
this.$remove_nonThargoids = function () {
const s = system.filteredEntities(this, this.$is_thargoid_not);
var i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].remove(true);
}
}
};
// this.$remove_thargoids = function () {
// var s = system.filteredEntities(this, $is_thargoid);
// var i = s.length;
// while (i--) {
// if (s[i].isValid) s[i].remove(true);
// }
// };
// Argument - TEST; needs argument in calling function = 'radiation: function (args)'
// this.$scenarioAdd_radiation = function (origin) {
this.$scenarioAdd_radiation = function () {
this.dbg && this.$msg_dbg('$scenarioAdd_radiation - entered');
// Remove anything that would not have survived much radiation.
var
l,
s;
s = system.allShips;
l = s.length;
if (l > 0) {
if (this.oxp.hiredGuns) {
s = system.filteredEntities(this, this.$is_nonPlayer_lowEnergy_notHiredGun);
} else {
s = system.filteredEntities(this, this.$is_nonPlayer_lowEnergy);
}
l = s.length;
while (l--) {
if (s[l].isValid) {
s[l].remove(true);
}
}
}
if (Math.random() < 0.5) {
system.sendAllShipsAway(); // Will send this message, for definite, later and then repeatedly.
}
/*
Now implement the radiation, such that: players & NPCs get same damage (if we bracket heat shielding),
but with players timer running more frequently than NPCs - in order to avoid sudden player energy jumps.
And we need to do all that without passing an argument to a timer-run function (because one cannot),
though if we had to we could use a global variable.
*/
const radiation = this.interstellar_data.scenarios.versions.novel.subScenarios_individual.radiation;
const
nonPlayer_damagePerRun = radiation.nonPlayer.damagePerRun.standard,
player_damagePerRun = radiation.player.damagePerRun.standard,
player_interval = 0.35 + Math.round((system.scrambledPseudoRandomNumber(700003) * 10) / 10); // Rounds to 2 decimals
const player_damagePerSecond = player_damagePerRun / player_interval;
const player_damagePerSecond_rounded = Number(player_damagePerSecond.toFixed(2));
const nonPlayer_interval = nonPlayer_damagePerRun / player_damagePerSecond;
const nonPlayer_interval_rounded = Number(nonPlayer_interval.toFixed(2));
// nonPlayer_interval: needs to come out, for efficiency, at > c. 4 seconds.
const nonPlayer_damagePerSecond = nonPlayer_damagePerRun / nonPlayer_interval;
const nonPlayer_damagePerSecond_rounded = Number(nonPlayer_damagePerSecond.toFixed(2));
if (this.dbg) {
this.$msg_dbg('Player, radiation damage per run (preset): ' +
player_damagePerRun
);
this.$msg_dbg('Player, radiation run interval (preset + random): ' +
player_interval
);
this.$msg_dbg('Player, damage per second (calculated, rounded): ' +
player_damagePerSecond_rounded
);
this.$msg_dbg('NonPlayer, radiation damage per run (calculated): ' +
nonPlayer_damagePerRun
);
this.$msg_dbg('NonPlayer, radiation run interval (calculated; will round): ' +
nonPlayer_interval
);
this.$msg_dbg('Non-player, damage per second (calculated, rounded, should match the player): ' +
nonPlayer_damagePerSecond_rounded
);
}
this.timer_radiation_1 = new Timer(
this,
this.$radiation_timed_1,
player_interval,
player_interval
);
this.timer_radiation_2 = new Timer(
this,
this.$radiation_timed_2,
nonPlayer_interval_rounded,
nonPlayer_interval_rounded
);
this.timer_radiation_3 = new Timer(
this,
this.$radiation_timed_3,
3,
14
); // This is the timer that sends ships away, and increases the player's sickness chance.
this.mySound_warning.play();
this.$msg_player('WARNING - high levels of space radiation!', 30);
// TEST:
// s = system.addShips(
// 'thargoid',
// 4,
// origin, // Needs that argument passed to function.
// 11000
// );
};
// Always returns a _ship_ array, even if have added a _group_.
this.$scenarioAdd_ships = function (
role,
count,
p, // must be an initialised vector, on pain of 'TypeError: position.distanceTo is not a function'
radius,
toHaveRings,
isGroup
) {
const witchPoint = new Vector3D(); // Creates the vector and sets it to [0, 0, 0].
// NB: Comment out the following when not debugging.
if (this.dbg) {
this.$msg_dbg('$scenarioAdd_ships - role is ' + role);
this.$msg_dbg('$scenarioAdd_ships - count is ' + count);
this.$msg_dbg('$scenarioAdd_ships - p is ' + p);
// ^ If the number appears without parentheses then it is no vector!
this.$msg_dbg('$scenarioAdd_ships - toHaveRings is ' + toHaveRings);
this.$msg_dbg('$scenarioAdd_ships - isGroup is ' + isGroup);
// this.$msg_dbg('$scenarioAdd_ships - witchPoint is ' + witchPoint);
}
// NB: In 'foo.distanceTo(bar)', foo must be a vector but bar can be a vector or else an entity-that-has-a-postion.
var
g,
i,
s;
if (toHaveRings) {
if (p.distanceTo(witchPoint) < 25600) {
// The intended position is within range of the witchPoint; so, we merely add the ships.
if (isGroup) {
g = system.addGroup(
role,
count,
p,
radius
);
s = g.ships;
} else {
s = system.addShips(
role,
count,
p,
radius
);
}
} else {
// The intended position is without the witchPoint range.
// So: add them at the witchPoint; then move them (but with their range offsets from the position).
// So, first create.
if (isGroup) {
g = system.addGroup(
role,
count,
witchPoint,
radius
);
s = g.ships;
} else {
s = system.addShips(
role,
count,
witchPoint,
radius
);
}
this.dbg && this.$msg_dbg('$scenarioAdd_ships - moving ships from witchpoint');
i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].position = s[i].position.add(p);
// this.dbg && this.$msg_dbg('$scenarioAdd_ships - moved a ship'); // TEST
}
}
}
} else {
// RINGLESS
if (p.distanceTo(witchPoint) >= 25600) {
// The intended position is not near the witchPoint; so, merely add them.
if (isGroup) {
g = system.addGroup(
role,
count,
p,
radius
);
s = g.ships;
} else {
s = system.addShips(
role,
count,
p,
radius
);
}
} else {
// The intended position is near the witchPoint.
// So: create the ships further away; then move them.
// First: create.
const farPosition = new Vector3D([500000, 500000, 500000]);
if (isGroup) {
g = system.addGroup(
role,
count,
farPosition,
radius
);
s = g.ships;
} else {
s = system.addShips(
role,
count,
farPosition,
radius
);
}
this.dbg && this.$msg_dbg('$scenarioAdd_ships - moving ships to near witchpoint');
var offset = new Vector3D(p).subtract(farPosition);
i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].position = s[i].position.add(offset);
}
}
}
}
return s;
};
this.$scenarioAdd_ships_aliens = function (
n,
p,
range,
toHaveRings
) {
const s = this.$scenarioAdd_ships(
'scorpax',
n,
p,
range,
false, // rings
false // group
);
};
this.$scenarioAdd_ships_asteroids = function (
origin,
minersProb
) {
this.dbg && this.$msg_dbg('$scenarioAdd_ships_asteroids - entered');
var
n,
p2,
r,
s;
/*
-------------------------------------------------------------------
Rocks of various sorts
Use system.addShips directly, because there is no question of rings.
-------------------------------------------------------------------
*/
this.dbg && this.$msg_dbg('$scenarioAdd_ships_asteroids - group 1');
const
x = (Math.random() - 0.5) * 51200,
y = (Math.random() - 0.5) * 51200,
z = (Math.random() - 0.5) * 51200;
p2 = new Vector3D();
p2 = origin.add([x, y, z]);
s = system.addShips(
'IST_asteroid',
26,
p2,
33000
);
r = Math.random(); // Used for groups 2 and 3.
this.dbg && this.$msg_dbg('$scenarioAdd_ships_asteroids - group 2');
n = 1 + ~~(r * 56); // Do not exceed Oolite's limit of 64.
s = system.addShips(
'IST_asteroid',
n,
p2,
44000
);
this.dbg && this.$msg_dbg('$scenarioAdd_ships_asteroids - group 3');
if (r < 0.5) {
n = 5 + ~~(1 + (r * 38));
s = system.addShips(
'IST_asteroid',
n,
p2,
60000
);
s = system.addShips(
'IST_asteroid',
6,
p2,
70000
);
if (r < 0.2) {
s = system.addShips(
'IST_asteroid',
8,
p2,
95000
);
}
}
/*
----------
Billboards
----------
The billboards OXP adds them near asteroids, so, remove any billboards.
*/
if (this.oxp.YAH) {
s = system.shipsWithRole('asteroid-billboard');
var i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].remove(true);
}
}
}
/*
------
Miners
------
*/
// minersProb = 1; // TEST
r = Math.random();
if (r > minersProb) return;
this.dbg && this.$msg_dbg('$scenarioAdd_ships_asteroids - miners');
var grouped;
if (r < (minersProb / 3)) {
grouped = false;
} else {
grouped = true;
}
n = ~~(1 + (Math.random() * 5));
if (Math.random() < 0.45) {
s = system.addShips('splinter', n, p2, 10000);
} else {
s = system.addShips('IST_boulder', n, p2, 28000);
}
n = ~~(1 + (Math.random() * 10));
s = this.$scenarioAdd_ships(
'IST_miner',
n,
p2,
12000,
false, // rings
grouped
);
if (Math.random() < 0.45) {
s = this.$scenarioAdd_ships(
'miner', // A normal miner, as against one of ours
1,
p2,
12500,
false, // rings
false // group
);
this.dbg && this.$msg_dbg('$scenarioAdd_ships_asteroids - added normal miner');
}
};
this.$scenarioAdd_ships_derelicts = function (p) {
this.dbg && this.$msg_dbg('$scenarioAdd_ships_derelicts - entered');
const
n = 1 + (~~(8 * Math.pow(Math.random(), 4))), // number between 1 and 9, with the '4' is the bias towards 1.
versions = this.interstellar_data.scenarios.versions;
const s = this.$scenarioAdd_ships(
'IST_derelict',
n,
p,
versions.modifiedOrNovel.derelict_range,
false, // rings
false // group
);
this.dbg && this.$msg_dbg('$scenarioAdd_ships_derelicts - added ' + n + ' derelict(s)');
if (
s[0] &&
s[0].isValid &&
(Math.random() <= versions.novel.subScenarios.derelict.lives_prob)
) {
if (s[0].hasRole('IST_derelict_thargoid')) {
this.dbg && this.$msg_dbg(
'$scenarioAdd_ships_derelicts - would have made a derelict live, but it was a thargoid'
);
} else {
s[0].switchAI('IST_derelict_live.plist');
s[0].setScript('IST_derelict_live.js');
this.dbg && this.$msg_dbg('$scenarioAdd_ships_derelicts - made a derelict live');
}
}
if (Math.random() < 0.2) this.$scenarioAdd_debris(p);
};
this.$scenarioAdd_ships_hunters = function (
baseNum,
p, // must be an initialised vector
range,
toHaveRings
) {
if (this.dbg) {
this.$msg_dbg('$scenarioAdd_ships_hunters - entered');
this.$msg_dbg('$scenarioAdd_ships_hunters - p is <' + p + '>');
}
var
i,
n;
// Place some of the hunters defined by this OXP (though those hunters depend heavily on OXPs).
n = 2 + ~~(Math.random() * baseNum);
this.dbg && this.$msg_dbg('$scenarioAdd_ships_hunters - adding <' + n + '> of my hunters');
const s = this.$scenarioAdd_ships(
'IST_hunter',
n,
p,
range,
toHaveRings,
false // group
);
// Add some heavy-hunters, in a group (not the same group as the first), and set their AIs.
n = baseNum;
const g = this.$scenarioAdd_ships(
'hunter-heavy',
n,
p,
range,
toHaveRings,
true // group
);
if (!g || !g.ships) {
this.$msg_err('Problem adding second hunter group');
return;
}
i = g.ships.length;
while (i--)
if (g.ships[i].isValid) {
g.ships[i].setAI('IST_hunter.plist');
}
};
this.$scenarioAdd_ships_lobsters = function (
baseNum,
p,
range,
toHaveRings
) {
var
i,
n = baseNum;
if (system.info.galaxyID === 7) {
n = baseNum * 2;
}
if (n > 64) n = 64;
const s = this.$scenarioAdd_ships(
'IST_lobster',
n,
p,
range,
toHaveRings,
true // group
);
// Give first lobster an ECM, and, for each lobster, tell it which one has the ECM.
if (s[0]) s[0].awardEquipment('EQ_ECM');
i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].script.$shipWithECM = s[0];
}
}
};
this.$scenarioAdd_ships_navy = function (
n,
p,
range,
toHaveRings
) {
var
i,
s;
// Prevent any extant military from leaving immediately.
s = system.entitiesWithScanClass('CLASS_MILITARY');
i = s.length;
while (i--) {
if (
s[i].isValid &&
s[i].ai !== 'IST_mil.plist' &&
s[i].ai !== 'ferdelance3G_milInterstellarAI' &&
s[i].ai !== 'spectreAI.plist' &&
s[i].ai !== 'TCAT_raptorAI.plist' &&
s[i].ai !== 'militaryFiascoCarrierAI' &&
s[i].ai !== 'IST_escapePod.plist'
) {
if (s[i].ai === 'behemothFighterInterceptAI.plist') {
s[i].sendAIMessage('TARGET_LOST');
} else {
s[i].setAI('IST_milPootle.plist');
}
}
}
// Add ships.
s = this.$scenarioAdd_ships(
'IST_mil',
n,
p,
24500,
false, // rings - so only use this function if one wants the ships to lack rings.
false // group
);
// Return - and we do need to return _some_ ship
return s;
};
this.$scenarioAdd_ships_pirates = function (
baseNum,
p,
range,
toHaveRings
) {
const s = this.$scenarioAdd_ships(
'IST_pirate',
baseNum,
p,
range,
toHaveRings,
true // group
);
};
this.$scenarioAdd_ships_thargoids = function (
baseNum,
p,
range,
prob_thargGenShip
) {
var
n,
s,
x,
y,
z;
this.dbg && this.$msg_dbg('$scenarioAdd_ships_thargoids - entered');
// THARGOID GENERATION SHIP
if (this.oxp.genShips && Math.random() <= prob_thargGenShip) {
x = (Math.random() - 0.5) * 175000;
y = (Math.random() - 0.5) * 175000;
z = (Math.random() - 0.5) * 175000;
var offsetPosition = new Vector3D(p).subtract([x, y, z]);
this.$scenarioAdd_ships(
'IST_thargoid_genShip',
1,
offsetPosition,
0, // range
false, // rings
false // group
);
if (this.oxp.extraThargoids) {
n = 1 + ~~(1 + (Math.random() * 6));
this.$scenarioAdd_ships('extraThargoids_sweeper', n, offsetPosition, 34000, false);
if (Math.random() < 0.7) {
n = ~~(1 + (Math.random() * 5));
this.$scenarioAdd_ships(
'IST_thargoid_lurker',
n,
offsetPosition,
34000,
false, // rings
true // group
);
}
}
}
// GENERAL
const situation = ~~(2 + (Math.random() * 10));
this.dbg && this.$msg_dbg('$scenarioAdd_ships_thargoids: situation ' + situation);
switch (situation) {
case 1:
s = this.$scenarioAdd_ships(
'IST_thargoid',
baseNum,
p,
14000,
false, // rings
false // group
);
if (
(baseNum > 2) &&
(
(this.oxp.extraThargoids) && (Math.random() < 0.2)
)
) {
s = this.$scenarioAdd_ships(
'extraThargoids_sweeper',
1,
p,
18000,
false, // rings
false // group
);
}
s = this.$scenarioAdd_ships(
'thargoid',
baseNum,
p,
14000,
false, // rings
false // group
);
break;
case 2, 3:
s = this.$scenarioAdd_ships(
'thargoid',
baseNum,
p,
14000,
false, // rings
false // group
);
s = this.$scenarioAdd_ships(
'IST_thargoid',
baseNum,
p,
(~~(Math.random() * 60000)),
false, // rings
false // group
);
break;
case 4:
if (Math.random() < 0.8) {
s = this.$scenarioAdd_ships(
'IST_thargoid',
baseNum,
p,
50000,
false,
false // group
);
s = this.$scenarioAdd_ships(
'thargoid',
2,
p,
50000,
false, // rings
false // group
);
} else {
n = baseNum * 5;
s = this.$scenarioAdd_ships(
'thargoid',
n,
p,
250000,
false, // rings
false // group
);
if (this.oxp.extraThargoids) {
s = this.$scenarioAdd_ships(
'extraThargoids_sweeper',
1,
p,
250000,
false, // rings
false // group
);
}
if (this.oxp.thargoidCarriers) {
s = this.$scenarioAdd_ships(
'thargoid_carrier',
1,
p,
250000,
false, // rings
false // group
);
}
if (Math.random() < 0.3) {
s = this.$scenarioAdd_ships(
'thargoid',
20,
p,
300000,
false, // rings
false // group
);
if (this.oxp.thargoidCarriers) {
s = this.$scenarioAdd_ships(
'thargoid_carrier',
2,
p,
250000,
false, // rings
false // group
);
}
}
}
break;
case 5:
this.dbg && this.$msg_dbg('$scenarioAdd_ships_thargoids: offsetting');
var o = ~~(Math.random() * 36000);
x = (Math.random() - 0.5) * o;
y = (Math.random() - 0.5) * o;
z = (Math.random() - 0.5) * o;
var p2 = new Vector3D(p);
p2 = p.add([x, y, z]);
s = this.$scenarioAdd_ships(
'thargoid',
baseNum,
p2,
15500,
false, // rings
false // group
);
break;
default:
// Make this scenario resemble the BBC Elite scenario.
if (Math.random() > 0.75) {
n = baseNum * 2;
} else {
n = baseNum;
}
if (n > 64) n = 64;
s = this.$scenarioAdd_ships(
'IST_thargoidWarship_standard',
n,
p,
16000,
false, // rings
false // grouo
);
return s; // NB
}
return s; // We need to return _some_ ship
};
this.$scenarioAdd_ships_thargoidsRebels = function (
baseNum,
p,
range
) {
// I'd like them in little groups, but that would require modifing not only range but position.
var s;
this.dbg && this.$msg_dbg('$scenarioAdd_ships_thargoidsRebels - entered');
if ((baseNum === 1) && (Math.random() < 0.1)) {
s = this.$scenarioAdd_ships(
'thargoidRebel',
1,
p,
range,
false, // rings
false // group
);
return s;
}
var n = baseNum + 1;
s = this.$scenarioAdd_ships(
'thargoidRebel',
n,
p,
range,
false, // rings
true // group
);
var r = Math.random();
if (r > 0.7) return s;
n = ~~(1 + (r * 15));
s = this.$scenarioAdd_ships(
'thargoidRebel',
n,
p,
range,
false, // rings
true // group
);
return s;
};
this.$scenarioAdd_debris = function (p) {
var
n,
r,
s;
this.dbg && this.$msg_dbg('$scenarioAdd_debris: entered');
r = ~~(1 + (Math.random() * 7));
switch (r) {
case 1:
s = system.addShips('IST_alloy', 1, p, 19000);
break;
case 2:
s = system.addShips('IST_alloy', 2, p, 20000);
break;
case 3:
n = 3 + ~~(1 + (Math.random() * 14));
s = system.addShips('IST_alloy', n, p, 30000);
break;
default:
if (r === 4) {
s = system.addShips('cargopod', 1, p, 30000);
}
s = system.addShips('IST_alloy', r, p, 18000);
}
r = Math.random();
if (r > 0.6) return;
this.dbg && this.$msg_dbg('$scenarioAdd_debris: tharglets');
n = ~~(1 + (Math.random() * 19));
if (r < 0.15) {
s = system.addShips('cargopod', n, p, 10000);
n += 11;
}
s = system.addShips('IST_Tharglet', n, p, 29000);
};
/*
==================
10 TIMER HANDLERS
==================
*/
this.$timer_delete_all_exceptDie = function () {
// We proceed through the timers in order of increasing interval.
this.$timer_delete_runTweak_2();
this.$timer_delete_radiation();
this.$timer_delete_runTweak_3();
this.$timer_delete_stellar();
this.$timer_delete_misjumpWarning();
};
this.$timer_delete_all = function () {
this.$timer_delete_die();
this.$timer_delete_all_exceptDie();
};
this.$timer_delete_die = function () {
if (!this.timer_sickness_die) return;
(this.timer_sickness_die.isRunning) && this.timer_sickness_die.stop();
delete this.timer_sickness_die;
};
this.$timer_delete_misjumpWarning = function () {
if (!this.timer_misjumpWarning) return;
(this.timer_misjumpWarning.isRunning) && this.timer_misjumpWarning.stop();
delete this.timer_misjumpWarning;
};
this.$timer_delete_radiation = function () {
if (this.timer_radiation_1) {
(this.timer_radiation_1.isRunning) && this.timer_radiation_1.stop();
delete this.timer_radiation_1;
}
if (this.timer_radiation_2) {
(this.timer_radiation_2.isRunning) && this.timer_radiation_2.stop();
delete this.playerIntervaltimer_radiation_nonPlayer_1;
}
if (this.timer_radiation_3) {
(this.timer_radiation_3.isRunning) && this.timer_radiation_3.stop();
delete this.timer_radiation_3;
}
};
this.$timer_delete_runTweak_2 = function () {
if (!this.timer_runTweak_2) return;
(this.timer_runTweak_2.isRunning) && this.timer_runTweak_2.stop();
delete this.timer_runTweak_2;
};
this.$timer_delete_runTweak_3 = function () {
if (!this.timer_runTweak_3) return;
(this.timer_runTweak_3.isRunning) && this.timer_runTweak_3.stop();
delete this.timer_runTweak_3;
};
this.$timer_delete_stellar = function () {
if (!this.timer_stellar) return;
(this.timer_stellar.isRunning) && this.timer_stellar.stop();
delete this.timer_stellar;
};
/*
=================
11 MISCELLANEOUS
=================
*/
this._index_in_list = function (item, list) {
var k = list.length;
while (k--) {
if (list[k] === item) return k;
}
return -1;
};
this.$randomOrPseudo = function (pseudoRandomChance, pseudoRandomSeed) {
const r = Math.random();
// if (this.dbg_full) return r; // TEST. COMMENT THIS OUT WHEN NOT USING
return r <= pseudoRandomChance ?
system.scrambledPseudoRandomNumber(pseudoRandomSeed) :
r;
};
this.$shipDockedWithStation_hijacked = function (station) {
// The respective values of 'choicesKey' and 'choice' must match values in missiontext.plist
this.showScreen = 'rejectPage';
mission.runScreen({
title: 'Generation Ship (Hijacked)',
color: 'greenColor',
message: 'You have docked at a highjacked generation ship.\num\nTen out of ten for style, but minus several million for good thinking, yeah?',
model: 'thargoid',
choicesKey: 'IST_thargoid_genShipDocked'
},
function (choice) {
if (choice !== '1_RETURN') 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_sickness_die) {
this.timer_sickness_die = new Timer(
this,
this.$sickness_die_timed,
1.7
);
return;
}
} else {
player.ship.launch();
station.reactToAIMessage('ATTACKED');
var damaged = false;
if (Math.random() < 0.6) {
if (player.ship.equipment.length > 0) {
var
i,
equipmentToEffect,
l;
const
ps_equip_list = player.ship.equipment,
ps_equip_status = player.ship.equipmentStatus;
if (Math.random() < 0.6) {
l = 1;
} else {
l = 1 + ~~(1 + (Math.random() * 5));
}
i = l;
while (i--) {
equipmentToEffect = ps_equip_list[~~(ps_equip_list.length * Math.random())];
if (ps_equip_status(equipmentToEffect.equipmentKey) === 'EQUIPMENT_OK') {
player.ship.setEquipmentStatus(equipmentToEffect.equipmentKey, 'EQUIPMENT_DAMAGED');
}
}
damaged = true;
}
}
if (Math.random() < 0.5) {
const r = 50 + ~~(1 + (Math.random() * 150));
player.ship.energy = (player.ship.energy - r);
damaged = true;
}
if (damaged === true) this.mySound_hullBang.play();
}
} // End 'function choice'
);
};
// Takes: nothing.
// Moves the player ship.
// Returns: new position of player ship.
this.$shift_stellar_timed = function () {
this.dbg && this.$msg_dbg('$shift_stellar_timed: entered');
if (!player.ship.isValid) return;
if (system.isInterstellarSpace) return;
var
newPosition = new Vector3D(), // Creates the vector and sets it to [0, 0, 0]
x,
y,
z;
this.$msg_player('Drive malfunction - missed witchPoint!', 10);
if (Math.random() > this.stellar.misplace.prob_nearSun && !system.sun.hasGoneNova) {
x = (Math.random() * 4000000) + 50000;
y = (Math.random() * 4000000) + 50000;
z = (Math.random() * 4000000);
const oldPosition = new Vector3D([0, 0, 0]);
newPosition = oldPosition.add([x, y, z]);
} else {
this.$msg_player('ALERT - Approaching the sun.', 10);
x = (Math.random() * 200000) - 50000;
y = (Math.random() * 200000) - 50000;
z = (Math.random() * 200000) - 50000;
newPosition = system.sun.position.subtract([x, y, z]);
}
player.ship.position = newPosition;
this.mySound_warning.play();
};
this.$sickness_die_timed = function () {
// The above format, with its repetition of the function name, is right. See http://aegidian.org/bb/viewtopic.php?position=257147#p257147.
this.$timer_delete_die();
// Do not automatically delete it, because it might not be running; other things can call this.
if (!player.ship.isValid) return;
const playerShip = player.ship;
// Next two lines are to avoid auto-eject nonsense, etc.
if (playerShip.equipmentStatus('EQ_AUTO_EJECT') === 'EQUIPMENT_OK') player.ship.removeEquipment('EQ_AUTO_EJECT');
if (playerShip.equipmentStatus('EQ_EEU') === 'EQUIPMENT_OK') player.ship.removeEquipment('EQ_EEU');
player.ship.explode();
};
this.$radiation_timed_1 = function () {
if (!system.isInterstellarSpace || !player.ship.isValid) {
this.$timer_delete_radiation();
return;
}
const radiation = this.interstellar_data.scenarios.versions.novel.subScenarios_individual.radiation;
if (player.ship.equipmentStatus('EQ_HEAT_SHIELD') === 'EQUIPMENT_OK') {
player.ship.energy -= radiation.player.damagePerRun.heatShield;
} else {
player.ship.energy -= radiation.player.damagePerRun.standard;
}
};
this.$radiation_timed_2 = function () {
if (!system.isInterstellarSpace || !player.ship.isValid) {
this.$timer_delete_radiation();
return;
}
// this.dbg && this.$msg_dbg('$radiation_timed_nonPlayer.1 - entered'); // TEST
// Treat only (up to 32) ships (powered or unpowered) within player's scanner range - for speed.
const
radiation = this.interstellar_data.scenarios.versions.novel.subScenarios_individual.radiation,
s = player.ship.checkScanner();
var
d,
i = s.length;
while (i--) {
if (!s[i].isValid) {
continue;
}
if (s[i].isThargoid) {
d = radiation.nonPlayer.damagePerRun.thargoid;
} else {
if (s[i].heat_insulation > 1) {
d = radiation.nonPlayer.damagePerRun.heatShield;
} else {
d = radiation.nonPlayer.damagePerRun.standard;
}
}
if (s[i].energy > d) {
s[i].energy -= d;
} else {
if (s[i].isCargo && s[i].commodity === 'radioactives') {
s[i].becomeCascadeExplosion();
} else {
s[i].explode();
}
}
// this.dbg && this.$msg_dbg('dealt damage: ' + d); // TEST
}
};
this.$radiation_timed_3 = function () {
if (!system.isInterstellarSpace || !player.ship.isValid) {
this.$timer_delete_radiation();
return;
}
this.sickness.prob_getting_current += 0.001;
system.sendAllShipsAway();
};
this.$playerStartedJumpCountdown_misjumpWarningTimed = function () {
const
playerShip = player.ship;
const
newPlace = playerShip.cursorCoordinates,
oldPlace = playerShip.galaxyCoordinates;
const dx = newPlace.x - oldPlace.x;
const dy = (newPlace.y - oldPlace.y) / 2;
const d = ~~(0.5 + Math.sqrt(dx * dx + dy * dy) * 2) / 10; // half of jump distance.
this.mySound_warning.play();
player.commsMessage('Warning: witchspace disturbance detected at ' + d + ' LY ahead!');
delete this.timer_misjumpWarning;
};
/*
===================
12 EVENT HANDLERS
alphabetically ordered and comprising only the top-level handlers,
i.e. the ones that the game itself calls.
But excluding (re)populator functions.
===================
*/
this.escapePodSequenceOver = function () {
// Is no player ship by this point.
this.overrideThargoidOXPs(false)();
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!
var s;
/*
------------------
Thargoids get pod?
------------------
*/
s = system.filteredEntities(this, this.$is_thargoid_obedient);
const l = s.length;
if (l > 0) {
var actualChanceBugsGetPod = this.escapeSequence.prob_thargoidsGetPod;
s = system.filteredEntities(this, this.$is_thargoid_not);
if (l === 0) {
actualChanceBugsGetPod += (l / 60);
} else {
const difference = l - l;
actualChanceBugsGetPod *= (difference / 5);
}
if (actualChanceBugsGetPod > 0.85) actualChanceBugsGetPod = 0.99;
if (Math.random() <= actualChanceBugsGetPod) {
this.$timer_delete_die();
player.setEscapePodDestination(null); // = you die.
this.$msg_player('Thargoids destroyed your escape pod.', 15);
return;
}
}
/*
--------------------
Delete (most) timers
--------------------
*/
this.$timer_delete_all_exceptDie();
// Let us ignore any radiation - which, anyway, will make the presence of ships very unlikely.
/*
-------------------------------
Rescue (and deletion of timers)
-------------------------------
*/
var actualEscapeSequence_rescueProb;
if (
player.bounty > 39 + ~~(1 + (Math.random() * 11))
) {
actualEscapeSequence_rescueProb = this.escapeSequence.rescueProb / 3;
} else {
actualEscapeSequence_rescueProb = this.escapeSequence.rescueProb;
}
if (
(player.bounty > 39 + ~~(1 + (Math.random() * 11))) &&
(Math.random() > 0.2)
) {
// No chance of rescue, because legally too dirty.
player.setEscapePodDestination(null);
return;
}
s = system.shipsWithRole('behemoth');
const s2 = system.shipsWithRole('leviathan');
s = s.concat(s2);
if (s.length > 0) {
if (Math.random() <= actualEscapeSequence_rescueProb) {
player.setEscapePodDestination(s[0]);
return;
}
}
/*
By this stage of the function/game, it is certain - or nearly - that the player will not get picked up.
If there was radiation, we could display a message about that, but let us not.
*/
};
this.playerCancelledJumpCountdown = function () {
this.jumpIsGalactic = false; // I think that do not _really_ need this.
this.$timer_delete_misjumpWarning();
};
this.playerEnteredNewGalaxy = function (galaxyNumber) {
this.galNum = galaxyNumber;
// Store galaxy number (because we use it in $tweak_1_beforeWillExit_choose_move_setOrigin_InitRepop).
// Adjust various probabilities by galaxy
const code = script.interstellar_codeForNovel;
// Galaxies are numbered 0-7.
switch (galaxyNumber) {
case 0:
code.novelSubScenario_multiplyWeight('thargoids', 0.85);
code.novelSubScenario_multiplyWeightByMember('thargoidsRebels', 0);
code.novelSubScenario_revertWeight('asteroids');
code.novelSubScenario_revertWeight('empty');
break;
case 1:
code.novelSubScenario_multiplyWeightByMember('thargoidsRebels', 0);
code.novelSubScenario_revertWeight('asteroids');
code.novelSubScenario_revertWeight('empty');
code.novelSubScenario_revertWeight('thargoids');
break;
case 2:
code.novelSubScenario_revertWeight('asteroids');
code.novelSubScenario_revertWeight('empty');
code.novelSubScenario_revertWeight('thargoids');
break;
case 3:
code.novelSubScenario_multiplyWeight('empty', 1.15);
code.novelSubScenario_multiplyWeight('thargoids', 0.9);
code.novelSubScenario_multiplyWeightByMember('thargoidsRebels', 2);
code.novelSubScenario_revertWeight('asteroids');
break;
case 4:
code.novelSubScenario_multiplyWeight('radiation', 1.05);
code.novelSubScenario_multiplyWeightByMember('thargoidsRebels', 1.5);
code.novelSubScenario_revertWeight('asteroids');
code.novelSubScenario_revertWeight('empty');
code.novelSubScenario_revertWeight('thargoids');
break;
case 5:
code.novelSubScenario_multiplyByMember('asteroids', 1.23);
code.novelSubScenario_revertWeight('empty');
code.novelSubScenario_revertWeight('thargoids');
break;
case 6:
code.novelSubScenario_multiplyWeightByMember('thargoidsRebels', 0);
code.novelSubScenario_revertWeight('asteroids');
code.novelSubScenario_revertWeight('empty');
code.novelSubScenario_revertWeight('thargoids');
break;
case 7:
code.novelSubScenario_multiplyWeight('radiation', 1.3);
code.novelSubScenario_multiplyWeightByMember('thargoidsRebels', 0);
code.novelSubScenario_revertWeight('empty');
code.novelSubScenario_revertWeight('thargoids');
if (this.oxp.missionaries) {
script.interstellar_codeForNovel.novelSubScenario_multiplyByMember('lobsters', 1.2);
// The adding function itself - this.$scenarioAdd_ships_lobsters - increases the number of lobsters in this galaxy.
// TO DO: REMOVE LOBSTERS etc. IF NO OXP
}
}
};
this.playerStartedJumpCountdown = function (jump) {
if (system.isInterstellarSpace) {
this.isIntraInterstellar = true;
} else {
this.isIntraInterstellar = false;
}
if (this.oxp.thargoidDrive && worldScripts['murphy-thargoid-drive.js'].jumping) return;
if (
jump === 'galactic' ||
(this.oxp.galacticMisJump && worldScripts['Galactic Misjump'].gmj_active === 1)
) {
this.jumpIsGalactic = true;
return;
}
this.jumpIsGalactic = false;
// Proceed only if a misjump scripted.
if (!player.ship.scriptedMisjump) return;
// MisJump Analyzer: make it do something if it is not doing something already.
if (
this.oxp.misJumpAnalyzer &&
!worldScripts.misjump_analyser.misjump &&
(player.ship.equipmentStatus('EQ_MISJUMP_ANALYSER') == 'EQUIPMENT_OK')
) {
var prob;
if (system.isInterstellarSpace) {
prob = 0.8;
} else {
prob = 0.9;
}
var r = Math.random();
if (r > prob) return;
// Otherwise . .
if (r < 0.5) {
this.timer_misjumpWarning = new Timer(
this,
this.$playerStartedJumpCountdown_misjumpWarningTimed,
5
);
return;
}
// Otherwise . .
this.timer_misjumpWarning = new Timer(
this,
this.$playerStartedJumpCountdown_misjumpWarningTimed,
6
);
}
};
this.playerWillEnterWitchspace = function () {
this.dbg && this.$msg_dbg('playerWillEnterWitchspace - entered');
/*
The shipWillEnterWitchspace handler is called immediately before a witchspace jump, while the player is still in the starting system.
*/
this.$timer_delete_radiation();
this.sickness.willDie = false;
this.govLevelLeaving = system.government;
};
this.shipDockedWithStation = function (station) {
if (!player.ship.docked) return;
this.$timer_delete_all();
this.sickness.prob_getting_current = this.sickness.prob_getting;
if (player.ship.dockedStation.name === 'Generation Ship (Hijacked)') {
this.$shipDockedWithStation_hijacked(station);
return;
}
// Otherwise . .
if (player.ship.dockedStation.isMainStation) {
this.sickness.isSick = false;
return;
}
// Otherwise . .
if (Math.random() < 0.2) {
this.sickness.isSick = false;
}
};
this.shipExitedWitchspace = function () {
// this.dbg && this.$msg_dbg('shipExitedWitchspace');
if (
!player.ship.isValid ||
(this.oxp.thargoidDrive && worldScripts['murphy-thargoid-drive.js'].jumping)
) {
return;
}
if (this.jumpIsGalactic) {
this.jumpIsGalactic = false;
// TO DO: recompute weights
return;
}
this.jumpIsGalactic = false;
};
// this.shipLaunchedFromStation = function (station) {
// };
this.shipWillDockWithStation = function (station) {
if (station.name === 'Generation Ship (Hijacked)') {
station.suppressArrivalReports = true;
}
};
this.shipWillExitWitchspace = function () {
// From the wiki: 'The shipWillExitWitchspace handler is called as a witchspace jump concludes. When it is called, the player is (from a program perspective) in the destination system, but the tunnel effect has not yet been shown.'
this.dbg && this.$msg_dbg('shipWillExitWitchspace: entered');
if (system.isInterstellarSpace) return;
/*
=============================
TWEAK 2: STELLAR - misplacing
=============================
*/
var realProb = this.stellar.misplace.prob;
if (player.ship.energy < 60) {
realProb += 0.02;
}
if (
this.breakableDrive &&
player.ship.equipmentStatus('EQ_BREAKABLE_WITCHDRIVE') === 'EQUIPMENT_DAMAGED'
) {
realProb += 0.15;
}
if (Math.random() > realProb) return;
this.$timer_delete_stellar();
this.timer_stellar = new Timer(
this,
this.$shift_stellar_timed,
this.stellar.misplace.secsAfterWillExitWitchspace
);
};
this.shipWillLaunchFromStation = function () {
var i;
/*
===================
GAME INITIALISATION
===================
*/
if (!this.initialisedAtFirstLaunch) {
/*
--------------
Fuel collector
--------------
*/
if (this.oxp.fuelCollector) {
// this.dbg && this.$msg_dbg('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.$isWithinArray('shuttle', worldScripts['Fuel Collector'].legitDerelictRoles)) {
worldScripts['Fuel Collector'].legitDerelictRoles.splice('shuttle');
}
// Add some roles to Fuel Collector's list of hackable entities.
const rolesCopy = worldScripts['Fuel Collector'].legitDerelictRoles.slice(0);
// The above copies worldScripts['Fuel Collector'].legitDerelictRoles to rolesCopy.
const 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_derelict_thargoid',
'IST_derelict_viper',
'IST_derelict_live',
'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'
);
// ^ FIX ME: somehow, the fuel collector cannot hack the live derelict.
i = roles.length;
while (i--) {
if (!this.$isWithinArray(roles[i], rolesCopy))
worldScripts['Fuel Collector'].legitDerelictRoles.push(roles[i]);
}
log(
this.description,
'FOR INFO: fuel-collector elligible roles are now: ' +
worldScripts['Fuel Collector'].legitDerelictRoles
);
}
/*
----
Rank
----
*/
if (!this.dbg_ignorePlayerRank) {
const score = player.score;
if (score > 2560) {
// 'Deadly'
const
modified = this.interstellar_data.scenarios.versions.modified,
novel = this.interstellar_data.scenarios.versions.novel;
if ((modified.probOverrideThargoidOXP > 0) && (modified.probOverrideThargoidOXP < 1)) {
modified.probOverrideThargoidOXP *= 0.2;
}
this.interstellar_codeForNovel.novelSubScenario_multiplyByMember('thargoids', 1.1);
if (score > 6400) {
// 'Elite'
novel.subScenarios_individual.pirates.baseNum += 1;
novel.subScenarios_individual.thargoids.baseNum += 1;
if (score > 19200) {
// Way above 'Elite'
const podProb = this.escapeSequence.prob_thargoidsGetPod;
if ((podProb > 0) && (podProb < 1)) {
this.escapeSequence.prob_thargoidsGetPod *= 1.1;
}
if (
(modified.subScenarios.thargoidsOnly.sweeper_prob > 0) &&
(modified.subScenarios.thargoidsOnly.sweeper_prob < 1)
) {
modified.subScenarios.thargoidsOnly.sweeper_prob *= 1.11;
}
const battleShipLimitProb = this.interstellar_data.scenarios.all.thargoidBattleshipsLimit.prob;
if ((battleShipLimitProb > 0) && (battleShipLimitProb < 1)) {
this.interstellar_data.scenarios.all.thargoidBattleshipsLimit.prob *= 0.75;
}
} // End above-Elite
} // End Elite
} // End Deadly
} // End `if (!this.dbg_ignorePlayerRank)`
/*
-------------------------------------------
Save probabilities for novel scenarios.
If debugging then print possible scenarios.
-------------------------------------------
*/
script.interstellar_codeForNovel.novelSubScenario_saveOriginalWeights;
// ^ This saves the probabilities in their current form, i.e. including any rank-inflection.
if (this.dbg) {
var data = script.interstellar_data.scenarios.versions.novel;
var names = [];
for (i = 0; i < data.subScenarios.length; i++) {
if (data.subScenarios[i].weight !== 0) {
names.push(data.subScenarios[i].key);
}
}
var output = 'Active novel subscenarios: ' + names.join('; ');
this.$msg_dbg(output);
}
/*
-----------------
Get galaxy number
-----------------
*/
this.galNum = system.info.galaxyID;
/*
-----------------------------
Mark that we have initialised
-----------------------------
*/
this.initialisedAtFirstLaunch = true;
// this.dbg && this.$msg_dbg('Initialisation end');
}
/*
=======
MISJUMP
=======
*/
if (
(!player.ship.scriptedMisjump) &&
(Math.random() <= this.interstellar_data.scenarios.misJumpInducedByScript_prob)
) {
player.ship.scriptedMisjump = true;
// The wiki on ship.scriptedMisjump: 'When true, the next hyperspace jump will be a misjump. The scriptedMisjump flag will remain true during the shipWillExitWitchspace() event handler, and will be set to false after the shipExitedWitchspace() event.'
const r = Math.random();
if (r <= 0.3) player.ship.scriptedMisjumpRange = r + 0.2;
// ship.scriptedMisjumpRange: again, an Oolite value; traditional misjump value is 0.5.
this.dbg && this.$msg_dbg('Misjump scheduled');
}
/*
========
SICKNESS
========
*/
if (this.sickness.isSick) {
this.$msg_player('You still have WITCHSPACE SICKNESS. Dock at a main station! Do not jump!', 15);
this.mySound_warning.play();
}
};
/*
--------------------------
AUTORUN 'startUp' function
and a helper function
--------------------------
*/
this.$roleExists = function (role) {
const s = system.addShips(role, 1, [1000000, 1000000, 1000000]);
if (s && (s.length == 1) && s[0].isValid) {
s[0].remove(true);
return true;
}
return false;
};
this.startUp = function () {
/*
============================================
This function is run automatically by Oolite
============================================
*/
const
thisVeryScript = worldScripts.IST_masterScript;
var
didExcludeSelf = false,
i,
populators = [],
repopulators = [],
worldScriptNames_local_barOwn = [],
worldScriptNames_local = worldScriptNames;
var worldScripts_local = worldScripts; // worldScripts is an Oolite global.
this.dbg && this.$msg_dbg('startUp');
/*
========================================================================================
Populate our global array this.worldScriptNames_local_barOwn.
We do so by making a copy of the Oolite global 'worldScripts' and
removing the name of our own script from it.
WorldScriptNames and worldScripts are Oolite global.
(Some?) properties with worldScripts, and thus within the worlds scripts of other OXPs,
are editable, allowing us to hack them here.
=======================================================================================
*/
i = worldScriptNames.length;
while (i--) {
if (
!didExcludeSelf &&
worldScriptNames_local[i] == this.name
) {
didExcludeSelf = true;
continue;
}
const names = worldScriptNames_local[i];
worldScriptNames_local_barOwn.push(names);
this.dbg && this.$msg_dbg('found worldscript ' + names);
if (worldScripts_local[names]) {
if (
worldScripts_local[names].interstellarSpaceWillPopulate &&
worldScripts_local[names].interstellarSpaceWillPopulate !== undefined
) {
populators.push(names);
this.dbg && this.$msg_dbg(' - script HAS interstellar populator');
} else {
this.dbg && this.$msg_dbg(' - script lacks interstellar populator');
}
if (
worldScripts_local[names].interstellarSpaceWillRepopulate &&
worldScripts_local[names].interstellarSpaceWillRepopulate !== undefined
) {
repopulators.push(names);
this.dbg && this.$msg_dbg(' - script HAS interstellar re-populator');
} else {
this.dbg && this.$msg_dbg(' - script lacks interstellar re-populator');
}
} else {
this.dbg && this.$msg_dbg(' - script lacks detectable (re)populator');
}
}
// Now make the local arrays global.
this.interstellar_data.scripts.populators.length = 0;
Array.prototype.push.apply(this.interstellar_data.scripts.populators, populators);
this.interstellar_data.scripts.repopulators.length = 0;
Array.prototype.push.apply(this.interstellar_data.scripts.repopulators, repopulators);
/*
NB: Without checking that worldScripts[names] is valid, Missionaries throws an exception, perhaps because it lacks a manifest file.
TO DO: the list includes Oolite's own populator!
TO DO: see whether can remove routines that try to undo populators.
/*
/*
====================================================================================================
Record which OXPS are installed
(In the case of most but not all of those OXPs, we do so via the array of worldscripts just created.
Note though that only some worldscripts end with '.js'!)
====================================================================================================
*/
const oxp = this.oxp;
oxp.aliens = this.$isWithinArray('aliens_world_script', worldScriptNames_local_barOwn);
oxp.behemoth = this.$isWithinArray('behemoth', worldScriptNames_local_barOwn);
oxp.bombs = this.$isWithinArray('Missiles & Bombs', worldScriptNames_local_barOwn);
oxp.breakableDrive = this.$isWithinArray('Breakable_WitchDrive', worldScriptNames_local_barOwn);
oxp.escapePodLocator = this.$isWithinArray('escapePodLocator.js', worldScriptNames_local_barOwn);
oxp.genShips = this.$isWithinArray('Generation Ships', worldScriptNames_local_barOwn);
oxp.extraThargoids = this.$isWithinArray('extraThargoids_populator', worldScriptNames_local_barOwn);
oxp.ferDeLance3G = this.$isWithinArray('ferdelance3G_populator', worldScriptNames_local_barOwn);
// oxp.fiasco = this.$isWithinArray('military_fiasco', worldScriptNames_local_barOwn); // we use its ships, but need no key
oxp.fuelCollector = this.$isWithinArray('Fuel Collector', worldScriptNames_local_barOwn);
oxp.galacticMisJump = this.$isWithinArray('Galactic Misjump', worldScriptNames_local_barOwn);
oxp.hiredGuns = this.$isWithinArray('hiredGuns_system', worldScriptNames_local_barOwn);
oxp.interstellarHelp = this.$roleExists('interstellar_help_trader');
oxp.misJumpAnalyzer = this.$isWithinArray('misjump_analyser', worldScriptNames_local_barOwn);
oxp.missionaries = this.$roleExists('lobsterworshipper');
oxp.nexus = this.$roleExists('EQ_NEXUS_BUG_MISSILEb');
oxp.secondWave = this.$roleExists('secondWave_toughTharglet');
oxp.spectre = this.$roleExists('spectre');
// oxp.starDestroyer = this.$isWithinArray('stardestroyer');
oxp.thargoidDrive = this.$isWithinArray('murphy-thargoid-drive.js', worldScriptNames_local_barOwn);
oxp.TCAT = this.$isWithinArray('TCAT_masterScript', worldScriptNames_local_barOwn);
oxp.thargoidCarriers = this.$roleExists('thargoid_carrier');
oxp.thargoidThreat = this.$isWithinArray('Thargorn_Witchspace_Battle', worldScriptNames_local_barOwn);
oxp.wormDrones = this.$isWithinArray("Mauiby's Wormhole Drones", worldScriptNames_local_barOwn);
oxp.YAH = this.$roleExists('asteroid-billboard');
if (this.dbg) {
this.$msg_dbg('=== Detection of relevant OXPs ===');
var
key,
keys = Object.keys(oxp),
value;
for (i = 0; i < keys.length; i++) {
key = keys[i];
value = oxp[key];
this.$msg_dbg('- ' + key + ': ' + value);
}
}
/*
------------------
React to some OXPs
------------------
*/
const data = this.interstellar_data;
if (!oxp.aliens) {
novelSubScenario_multiplyByMember('aliens', 0);
}
if (oxp.escapePodLocator) {
worldScripts['escapePodLocator.js'].ecl_interstellarSpaceRange = 15;
worldScripts['escapePodLocator.js'].ecl_normalSpaceRange = 20;
}
if (oxp.misJumpAnalyzer && !this.dbg_testWithMisjumps) {
data.misJumpInducedByScript_prob *= 0.2;
}
if (!oxp.missionaries) {
novelSubScenario_multiplyByMember('lobsters', 0);
}
if (oxp.spectre) {
data.scenarios.prob_tweak += 0.05;
data.scenarios.prob_modifiedAsVsNew -= 0.05;
}
if (oxp.thargoidCarriers) {
/*
thargoidCarriers OXP spawns carriers on shipExitedWitchspace, at the witchPoint, but only on a (score-inflected) probability.
So, if that OXP is installed, then:
- substantially increase the chance of (what is now only so-called) onlyNavy;
- increase the likely number of naval ships in onlyNavy and in addNavy;
- make the novel scenario, which avoids the carriers altogether (or puts them very far away) more likely.
*/
data.scenarios.versions.modified.subScenarios.navyOnly.prob *= 1.25;
data.scenarios.versions.modifiedOrNovel.novel_prob *= 1.1;
}
/*
--------------
More DEBUGGING
--------------
*/
this.dbg_full && this.$msg_dbg('Full test mode.');
};
/*
------------------------------------------------------------------------------------------------------------
ON 'OVERRIDING' THE THARGORN THREAT OXP
Due to decisions that I now regret, overriding the thargoidThreat OXP does not actually stop it adding ships.
Rather, it makes it less likely that it does, though it adds a chance of adding them a bit later.
And where it adds them is always near the witchpoint.
So, it makes sense, in our 'novel' scenario, always to 'override' the OXP
(though in that situation the OXP might still add ships to the witchpoint).
The relevant code in the Threat OXP is in ThargornWitchspaceBattle.js.
------------------------------------------------------------------------------------------------------------
*/
this.overrideThargoidOXPs = function (override) {
if (override) {
// DO the override
if (this.oxp.thargoidThreat) {
this.dbg && this.$msg_dbg('interstellarSpaceWillPopulate: overriding Threat');
this.threatOXP_modify = true;
this.oxp_overrides.thargoidThreat.overrode = true;
// this.threatOXP_modify is the variable that thargoidThreat actually looks for and acts on.
// We ourselves do nothing but set (and unset) it.
}
if (this.oxp.TCAT && missionVariables.otherOXPs_TCAT_override) {
this.dbg && this.$msg_dbg('interstellarSpaceWillPopulate: overriding TCAT');
missionVariables.otherOXPs_TCAT_override = true;
this.oxp_overrides.TCAT.overrode = true;
}
} else {
// UNDO any override
if (this.oxp.thargoidThreat) {
this.dbg && this.$msg_dbg('interstellarSpaceWillPopulate: allowing Threat');
this.threatOXP_modify = false;
this.oxp_overrides.thargoidThreat.overrode = false;
// this.threatOXP_modify is the variable that thargoidThreat actually looks for and acts on.
// We ourselves do nothing but set (and unset) it.
}
if (this.oxp_overrides.TCAT.overrode) {
this.dbg && this.$msg_dbg('interstellarSpaceWillPopulate: allowing TCAT');
missionVariables.otherOXPs_TCAT_override = false;
this.oxp_overrides.TCAT.overrode = false;
}
}
};
/*
=====================================================================
13 MAIN TWEAKING ROUTINES, including official (re)populator routines
=====================================================================
*/
this.interstellarSpaceWillPopulate = function _$tweak_1_beforeWillExit_choose_move_setOrigin_InitRepop() {
/*
This function runs immediately before this.playerWillExitWitchspace.
The function's name must match the one given in planetinfo.plist, only without this script's 'this.' prefix.
Moreover, only if the function is called (this.)interstellarSpaceWillPopulate will it be detected by other scripts.
My '=' in the function is only for reading (and/or profiling) purposes.
The function as I implement it does not actually do any population, except for, in some circumstances,
running Oolite's inbuilt populator and/or the populators of other OXPs.
(For we, via the plist, we have taken over population of interstellar space.)
*/
this.dbg && this.$msg_dbg('$tweak_1: entered');
/*
------------------------------------------------------------
TWEAK 1: SET SCENARIO
& some preliminaries, including at least one abort condition
------------------------------------------------------------
*/
if (this.jumpIsGalactic) return;
const data = this.interstellar_data;
var scenarioToSet;
if (
(
(this.oxp.thargoidDrive && worldScripts['murphy-thargoid-drive.js'].jumping) ||
(this.oxp.wormDrones && missionVariables.mauiby_multipleJumps)
) ||
(this.$randomOrPseudo(0.4, 700001) > data.scenarios.tweak_prob)
) {
/*
//////////////////////
Tweak 1: set unchanged
//////////////////////
*/
scenarioToSet = 'U';
if (Math.random() <= this.interstellar_data.scenarios.versions.modified.probOverrideThargoidOXP) {
this.overrideThargoidOXPs(true);
} else {
this.overrideThargoidOXPs(false);
}
} else {
if (this.$randomOrPseudo(0.6, 700002) > data.scenarios.versions.modifiedOrNovel.novel_prob) {
/*
//////////////////////
Tweak 1: set modified
//////////////////////
*/
scenarioToSet = 'M';
if (Math.random() <= this.interstellar_data.scenarios.versions.modified.probOverrideThargoidOXP) {
this.overrideThargoidOXPs(true);
} else {
this.overrideThargoidOXPs(false)();
}
} else {
/*
//////////////////
Tweak 1: set novel
//////////////////
*/
scenarioToSet = 'N';
this.overrideThargoidOXPs(true); // It makes no sense not to do this here. See a comment above.
}
} // End scenario chooser. Now, actually set it.
data.scenario = scenarioToSet;
/*
-------------------------
TWEAK 1: SET SUB-SCENARIO
-------------------------
*/
var subScenarioToSet;
switch (scenarioToSet) {
case 'U':
subScenarioToSet = '[none]';
break;
case 'M':
/*
//////////////////////////////////////
Tweak 1: set sub-scenario for modified
//////////////////////////////////////
*/
const modified_subScenarios = data.scenarios.versions.modified.subScenarios;
if (this.$randomOrPseudo(0.45, 700003) <= modified_subScenarios.thargoidsOnly.prob) {
// Only thargoids
subScenarioToSet = 'OT';
} else if (Math.random() <= modified_subScenarios.navyOnly.prob) {
// Only navy
subScenarioToSet = 'ON';
} else {
/*
Add navy (our default)
*/
subScenarioToSet = 'NA';
}
break;
case 'N':
/*
-----------------------
NOVEL - set subscenario
-----------------------
*/
// PIRATES
const multiplier = 1.25 -
(
(this.govLevelLeaving + System.infoForSystem(this.galNum, player.ship.targetSystem).government) / 14
) * 0.25;
script.interstellar_codeForNovel.novelSubScenario_multiplyByMember('pirates', multiplier);
// ^ We revert this after implementing the subscenario.
// ACTUALLY SET
subScenarioToSet = this.interstellar_codeForNovel.novelSubScenario_choose();
// ^ e.g., 'aliens+asteroids'
break;
default:
this.$msg_err('Bad scenario for this.$tweak_1');
}
data.subScenario = subScenarioToSet;
this.dbg && this.$msg_dbg('$tweak_1: set scenario <' + scenarioToSet + '>, subScenario <' + subScenarioToSet + '>');
/*
------------------------------------------
TWEAK 1: CONSIDER RUNNING OTHER POPULATORS
------------------------------------------
*/
if (this.interstellar_data.scenario !== 'N') {
const
populators = this.interstellar_data.scripts.populators,
worldScripts_local = worldScripts; // worldScripts is an Oolite global.
var i;
worldScripts_local['oolite-populator'].interstellarSpaceWillPopulate();
i = populators.length;
while (i--) {
if (!worldScripts_local[populators[i]]) {
this.$msg_err('this.interstellarTweaks_populate_interstellar - undefined populator');
} else {
try {
worldScripts_local[populators[i]].interstellarSpaceWillPopulate();
} catch (err) {
this.$msg_err(
'interstellarTweaks_populate_interstellar: problem with populator ' +
worldScripts_local[populators[i]]
);
}
}
}
}
/*
-------------------------------------------
TWEAK 1: MOVE PLAYER, SET ORIGIN, SET TIMER
-------------------------------------------
*/
const scenario = this.interstellar_data.scenario;
var origin; // Scenarios M and N define this; scenario U leaves it undefined
this.dbg && this.$msg_dbg('$tweak_1: scenario <' + scenario + '>');
/*
In scenarios N and M, we move the player to a temporary location; we should do this as soon as possible.
Set the 'origin' to [0, 0, 0] (which happens just by creating a new 'Vector3D').
Or rather set the function variable 'origin'; at the end of the function we assign that variable to a global.
The origin is where the player will go later and where we will populate with NPCs.
*/
if (!player.ship.isValid) {
this.$msg_err('$tweak_1: problem with player.ship');
return;
}
var playerPositionTemporary = new Vector3D();
switch (scenario) {
case 'M':
// Move player & set origin (or rather leave origin at the [0,0,0] that, via 'new Vector3D', it was created with).
playerPositionTemporary = ([350000000, 350000000, 350000000]);
player.ship.position = playerPositionTemporary;
origin = new Vector3D([0, 0, 0]);
this.dbg && this.$msg_dbg(
'$tweak_1: scenario <M> - moved player temporarily to <' +
playerPositionTemporary +
'>; set local origin to <(0,0,0)>'
);
break;
case 'N':
/*
As in 'M'. move player to temporary location & set local origin - except that the origin we set is not that of 'M'.
*/
const x = 150000 + ~~(Math.random() * 300000000);
const y = 150000 + ~~(Math.random() * 300000000);
const z = 150000 + ~~(Math.random() * 300000000);
playerPositionTemporary = ([350000000, 350000000, 350000000]);
origin = new Vector3D([x, y, z]);
player.ship.position = playerPositionTemporary;
this.dbg && this.$msg_dbg(
'$tweak_1: scenario <N> - moved player to temporary location ' +
playerPositionTemporary +
'; have set local origin to' +
origin
);
break;
case 'U':
// Leave the origin at default.
break;
default:
this.$msg_err('$tweak_1: bad scenario <' + scenario + '>');
// Do not return, because if we do not, below, set the origin, then we will have other problems.
}
/*
///////////////////////////////////////////
TWEAK 1: MOVE PLAYER, SET ORIGIN, SET TIMER
///////////////////////////////////////////
*/
// SET GLOBAL ORIGIN, if we've defined the local origin.
if (origin) {
this.interstellar_data.origin = origin;
this.dbg && this.$msg_dbg(
'$tweak_1: have set global origin to: ' +
origin
);
}
// SET TIMER - which we should run even in 'U', because the timed routine treats, inter alia, sickness.
this.timer_runTweak_2 = new Timer(
this,
this.$tweak_2_afterWillExit_populate,
this.interstellar_data.timing.runTweak_2
);
};
this.$tweak_2_afterWillExit_populate = function () {
this.dbg && this.$msg_dbg('$tweak_2: entered');
this.$timer_delete_runTweak_2(); // Delete the timer that called the current function.
if (!player.ship.isValid) {
this.$msg_err('$tweak_2: problem with player.ship');
return;
}
/*
=====================
TWEAK 2: INTERSTELLAR
=====================
*/
const
scenario = this.interstellar_data.scenario,
scenarios = this.interstellar_data.scenarios,
subScenario = this.interstellar_data.subScenario;
var
i,
n,
s;
if (this.dbg) {
this.$msg_dbg('$tweak_2: further implementing <' + scenario + '-' + subScenario + '>');
}
/*
----------------------------------------
Tweak 2: ANY INTERSTELLAR - ship removal
----------------------------------------
*/
var scenariosAll = scenarios.all;
// GENERATION SHIPS (but not thargoid ones)
if (this.oxp.genShips) {
if (Math.random() <= scenariosAll.genShipsRemove_prob) {
this.dbg && this.$msg_dbg('$tweak_2: removing any genShips');
s = system.shipsWithRole('generationship');
i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].remove(true); // 'true' = suppress any death event
}
}
} else if (this.dbg) {
this.$msg_dbg('$tweak_2: leaving any genShips');
}
}
/*
THARGOID BATTLESHIPS
Ignore here the so-called 'overriding' .
*/
if (this.oxp.thargoidThreat) {
if (Math.random() <= scenariosAll.thargoidBattleshipsLimit.prob) {
s = system.filteredEntities(this, this.$is_thargoid_battleship);
n = scenariosAll.thargoidBattleshipsLimit.maxShips;
if (s.length > n) {
i = s.length - n;
while (i--) s[i].remove(true);
}
this.dbg && this.$msg_dbg('$tweak_2: limited any battleships to ' + n);
} else if (this.dbg) {
this.$msg_dbg('$tweak_2: ignored battleships');
}
}
// HELPERS / HELPEES
if (this.oxp.interstellarHelp) {
if (
(Math.random() <= scenariosAll.wouldBeHelpee_remove_prob) &&
worldScripts.interstellar_help.interstellarHelp !== 'FOLLOWING'
) {
this.dbg && this.$msg_dbg('$tweak_2: removing any would-be helpees');
s = system.filteredEntities(this, this.$is_helpShip);
i = s.length;
while (i--) {
if (s[i].isValid) {
s[i].remove(true); // 'true' = suppress any death event
}
}
} else if (this.dbg) {
this.$msg_dbg('$tweak_2: left any would-be helpees alone');
}
}
/*
---------------------------
Tweak 2: SPECIFIC SCENARIOS
---------------------------
*/
/*
///////////////////////////
Tweak 2: UNCHANGED SCENARIO
///////////////////////////
*/
if (scenario === 'U') {
this.dbg && this.$msg_dbg('$tweak_2: scenario is <U>; ending here');
return; // NB
}
/*
//////////////////////////
Tweak 2: MODIFIED OR NOVEL
//////////////////////////
*/
/* Initialise repopulation */
const repopulation = this.interstellar_data.scenarios.versions.modifiedOrNovel.repopulation;
if (Math.random() > repopulation.probEver) {
repopulation.num_max_current = 0;
} else {
repopulation.num_max_current = ~~(
1 + (Math.random() * repopulation.num_max_ever)
);
}
repopulation.num = 0;
this.dbg && this.$msg_dbg(
'$tweak_2: repopulation.num_max_current set to ' +
repopulation.num_max_current +
' of a possible ' +
repopulation.num_max_ever
);
/* Set up origin alias */
const origin = this.interstellar_data.origin;
if (scenario === 'M') {
/*
//////////////////////////
Tweak 2: MODIFIED SCENARIO
//////////////////////////
*/
const
battleOccured = this.interstellar_data.scenarios.versions.modified.battleOccured,
subScenarios = this.interstellar_data.scenarios.versions.modified.subScenarios;
switch (subScenario) {
case 'ON':
/*
**************************************
Tweak 2: modified scenario - only navy
**************************************
*/
this.$remove_navyIncompatible();
if (system.countEntitiesWithScanClass('CLASS_MILITARY') < 4) {
s = this.$scenarioAdd_ships_navy(
subScenarios.navyOnly.maxNum,
origin,
24500,
false // rings
);
}
break;
case 'OT':
/*
*******************************************
Tweak 2: modified scenario - only thargoids
*******************************************
*/
this.$remove_nonThargoids();
if (system.countEntitiesWithScanClass('CLASS_THARGOID') === 0) {
s = this.$scenarioAdd_ships_thargoids(
subScenarios.thargoidsOnly.baseNum,
origin,
25000,
0, // = rebel chance; add rebels only in the novel scenario
0, // = thargoid genShip chance; add a thargoid genShip only in the novel scenario
false // rings
);
}
break;
case 'NA':
/*
*************************************
Tweak 2: modified scenario - add navy
*************************************
*/
s = this.$scenarioAdd_ships_navy(
subScenarios.navyAdd.maxNum,
origin,
21500,
false // rings
);
break;
default:
this.$msg_err(
'$tweak_3_afterExit_tempShift_setOrigin_populate_setTimer: bad modified subScenario <' +
subScenario +
'>'
);
} // End 'switch (subScenario)'
if (Math.random() <= battleOccured.prob) {
/*
************************************
Tweak 2: modified scenario - battle?
************************************
*/
this.dbg && this.$msg_dbg('$tweak_2: battle occurred');
/*
The following needs us to have defined some 's', which we use to (!) scan the area.
(If we were to do it without that, then it would be hard and expensive.)
*/
if (
s &&
s[0] &&
s[0].isValid
) {
if (Math.random() > battleOccured.prob_wreckageOnly) {
var l;
this.dbg && this.$msg_dbg('$tweak_2: damaging');
s = s[0].checkScanner(true);
l = s.length;
i = ~~(Math.random() * l);
while (i--) {
if (s[i].isValid) {
s[i].energy -= 40 + (i * 40);
}
}
}
} // End if-s-etc.
this.$scenarioAdd_debris(origin);
if (Math.random() <= battleOccured.prob_derelict) {
this.dbg && this.$msg_dbg('$tweak_2: derelict');
s = this.$scenarioAdd_ships(
'IST_derelict',
1,
origin,
50000,
false, // rings
false // group
);
}
} // End if-battle
} else if (scenario === 'N') {
/*
///////////////////////
TWEAK 2: NOVEL SCENARIO
///////////////////////
/*
/////////////////////////////////////////
Tweak 2: novel scenario - remove unwanted
/////////////////////////////////////////
*/
if (
this.oxp.interstellarHelp && (
worldScripts.interstellar_help.interstellarHelp === 'FOLLOWING' ||
Math.random() > 0.75
)
) {
s = system.filteredEntities(this, this.$is_unwantedInNovelInitially_allowHelpees);
} else {
s = system.filteredEntities(this, this.$is_unwantedInNovelInitially);
}
i = s.length;
this.dbg && this.$msg_dbg('$tweak_2: removing any unwanted');
while (i--) {
if (s[i].isValid) {
s[i].remove(true);
}
}
/*
////////////////////////////////////////////////////////
Tweak 2: novel scenario - execute pre-chosen subScenario
////////////////////////////////////////////////////////
*/
this.interstellar_codeForNovel.novelSubScenario_run({
origin: origin
});
/*
If need to pass > 1 argument, do:
var myArgs = { origin: origin };
this.interstellar_codeForNovel.novelSubScenario_run(myArgs);
*/
/*
///////////////////////////////////////////////////////////////////////////////
Tweak 2: novel scenario - revert any per-interstellar-jump probability changes.
///////////////////////////////////////////////////////////////////////////////
*/
this.interstellar_codeForNovel.novelSubScenario_revertByMember('pirates');
} // End 'if scenario'
/*
/////////////////////////////////////////////////////////////////////////////////////////////
Tweak 2: set timer
(Were we to move the player - if the player has moved - to the permanent location immediately,
then any ships at the latter have little time to get busy.
Also, tweak_3 removes anything from 0,0,0, if the player is not there.
//////////////////////////////////////////////////////////////////////////////////////////////
*/
this.dbg && this.$msg_dbg('$tweak_2: setting timer for tweak3');
this.timer_runTweak_3 = new Timer(
this,
this.$tweak_3_afterExitedWitchspace_move_sickness_clearWP,
this.interstellar_data.timing.runTweak_3
);
};
this.$tweak_3_afterExitedWitchspace_move_sickness_clearWP = function () {
/*
This function is to run, only, on a timer started by shipExitedWitchspace.
But that timer should be started only if we are in the 'novel scenario' and only if 'wormDrones' is not installed.
(For, I fear the latter OXP could cause problems here. Probably though I could handle the OXP better here.)
What the function does: revove everything near the witchPoint.
*/
this.dbg && this.$msg_dbg('$tweak_3: entered');
this.$timer_delete_runTweak_3(); // Delete the timer that called the current function.
const scenario = this.interstellar_data.scenario;
if (system.isInterstellarSpace) {
if (scenario !== 'U') {
/*
//////////////////////////////////////////////////////////////
Tweak 3: MODIFIED OR NOVEL - move player to permanent location
//////////////////////////////////////////////////////////////
*/
const
offset = this.interstellar_data.scenarios.versions.modifiedOrNovel.offset,
origin = this.interstellar_data.origin,
scenarios = this.interstellar_data.scenarios;
// OFFSETTING
if (Math.random() < offset.prob) {
// Displace, ensuring that the vector is above a particular magnitude.
const countPerSide = offset.distance_max - offset.distance_min + 1;
const total = 2 * countPerSide;
var
index,
newPlayerPos = new Vector3D(),
x,
y,
z;
// x
index = ~~(Math.pow(Math.random(), offset.biasTowardsMin) * total);
if (index < countPerSide) {
x = -(offset.distance_max - index);
} else {
x = offset.distance_min + (index - countPerSide);
}
// y
index = ~~(Math.pow(Math.random(), offset.biasTowardsMin) * total);
if (index < countPerSide) {
y = -(offset.distance_max - index);
} else {
y = offset.distance_min + (index - countPerSide);
}
index = ~~(Math.pow(Math.random(), offset.biasTowardsMin) * total);
// z
index = ~~(Math.pow(Math.random(), offset.biasTowardsMin) * total);
if (index < countPerSide) {
z = -(offset.distance_max - index);
} else {
z = offset.distance_min + (index - countPerSide);
}
// Apply the new co-ordinates
newPlayerPos = origin.add([x, y, z]);
player.ship.position = newPlayerPos;
this.dbg && this.$msg_dbg(
'$tweak_3: scenario ' + scenario + '-' + this.interstellar_data.scenario.subScenario +
' moved player to permanent location ' +
newPlayerPos +
', OFFSET from <' +
origin
);
} else {
// No offset.
player.ship.position = origin;
this.dbg && this.$msg_dbg(
'$tweak_3: moved player to permanent location ' +
origin
);
}
if (scenario === 'N') {
/*
///////////////////////////////////////////////////////////////
Tweak 3: interstellar - clear witchpoint, if scenario is novel
///////////////////////////////////////////////////////////////
*/
// One hopes there is a better way than this.
const dummy = system.addShips('alloy', 1, [0, 0, 0]);
if (dummy && (dummy.length == 1) && dummy[0].isValid) {
var toRemove = system.filteredEntities(this, this.$is_ship, dummy[0], 51200);
// Scanner range: 25600.
// Genship max possible distance from witchpoint: 250000 = 10 x scanner range.
dummy[0].remove(true);
var i = dummy.length;
while (i--) {
if (dummy[i].isValid) {
dummy[i].remove(true);
}
}
}
this.dbg && this.$msg_dbg('$tweak_3: cleared witchpoint area');
}
}
} // End if-interstellar
/*
//////////////////////////////////////////
Tweak 3: stellar | interstellar - sickness
//////////////////////////////////////////
*/
if (!this.sickness.willDie) {
// Is not currently set to die.
const sickness = this.sickness;
if (sickness.isSick) {
// But is sick
if (Math.random() > sickness.prob_fatal) {
this.$msg_player('You still have WITCHSPACE SICKNESS. Dock at a main station! Do not jump!', 15);
this.mySound_warning.play();
} else {
sickness.willDie = true;
this.$msg_player('You have TERMINAL WITCHSPACE SICKNESS!', 15);
this.mySound_warning.play();
}
} else {
// Is not sick
var r;
if (this.oxp.wormDrones) {
if ((missionVariables.mauiby_multipleJumps) && (sickness.prob_getting_current > 0)) {
r = sickness.prob_getting_current / 1.7;
} else {
r = sickness.prob_getting_current;
}
} else {
r = sickness.prob_getting_current;
}
// this.dbg && this.$msg_dbg('Sickness prob: '+r);
if (Math.random() < r) {
sickness.isSick = true;
this.$msg_player(
'You have developed WITCHSPACE SICKNESS. Jumping before docking at a main station may kill you!',
15
);
this.mySound_warning.play();
sickness.prob_getting_current = sickness.prob_getting; // Let us, thusly, reset this here.
}
}
}
// Now check whether STILL not scheduled to die from sickness.
if (sickness.willDie) {
/* Destroy the player ship _after_ other OXPs have prob to do their stuff.
Also, need delay to allow user to read messages.
*/
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_sickness_die) {
// this.dbg && this.$msg_dbg('setting die timer');
this.timer_sickness_die = new Timer(
this,
this.$sickness_die_timed,
4
);
// this.dbg && this.$msg_dbg('set die timer OK');
}
} else if (!sickness.isSick && sickness.prob_getting_current < 0.5) {
sickness.prob_getting_current += 0.007;
// 0.007. This is where, through withchspace jumps, we increase the prob of the player getting sick.
}
};
this.interstellarSpaceWillRepopulate = function () {
/*
The function's name must match the one given in planetinfo.plist, only without this script's 'this.' prefix.
Moreover, only if the function is called (this.)interstellarSpaceWillRepopulate will it be detected by other scripts.
For (Wiki): 'OXPs which wish to 'take over' a system or systems should use planetinfo.plist to set a different populator function which is unique to their worldscript(s). This then prevents normal system population, including modifications from other more generic OXPs (provided those OXPs have been written to use this new population method, of course).'
Wiki: 'The repopulator function is called every twenty seconds of game real time.'
*/
var
i,
repopulators,
worldScripts_local;
this.dbg && this.$msg_dbg('interstellarSpaceWillRepopulate: entered');
if (!player.ship.isValid) return;
this.dbg && !this.interstellar_data.scenario && this.$msg_err('this.$repopulateInterstellar: scenario undefined');
var scenario = this.interstellar_data.scenario;
if (scenario === 'U') {
/*
-----------------------
REPOPULATION: UNCHANGED
-----------------------
*/
repopulators = this.interstellar_data.scripts.repopulators;
worldScripts_local = worldScripts;
this.dbg && this.$msg_dbg('$repopulateInterstellar: repopulating unchanged scenario');
// Run repopopulators from other worldscripts (and those repopulators include Oolite's own)
i = repopulators.length;
while (i--) {
try {
worldScripts_local[repopulators[i]].interstellarSpaceWillRepopulate();
} catch (err) {
this.msg_err(
'Problem with repopulator <' +
worldScripts_local[repopulators[i]] +
'> : ' +
err.message);
}
}
return; // NB
}
/*
----------------------------------------
REPOPULATION: MODIFIED OR NOVEL SCENARIO
----------------------------------------
*/
const repopulation = this.interstellar_data.scenarios.versions.modifiedOrNovel.repopulation;
// Increment run count; we have initialised it at zero.
repopulation.num++;
if (repopulation.num > repopulation.num_max_current) {
this.dbg && this.$msg_dbg(
'$repopulateInterstellar, modified/novel scenario: repopulation count beyond the maximum of <' +
repopulation.num_max_current +
'>; aborting');
return;
// Seeming some OXP(s) still adds thargoids.
}
this.dbg && this.$msg_dbg(
'$repopulateInterstellar, modified/novel scenario: repopulation ' + repopulation.num +
' of ' + repopulation.num_max_current
);
if (Math.random() > repopulation.prob) {
this.dbg && this.$msg_dbg('$repopulateInterstellar: aborting, by probability');
return;
}
if (scenario === 'M') {
/*
-------------------------------
REPOPULATION: MODIFIED SCENARIO
-------------------------------
*/
if (repopulation.num === 1) {
this.dbg && this.$msg_dbg('$repopulateInterstellar, modified scenario: skipping first re-pop');
return; // The repopulation comes too early.
}
worldScripts_local = worldScripts;
// The above two entities do need to be variables, not constants.
this.dbg && this.$msg_dbg('$repopulateInterstellar: repopulating modified scenario');
/*
Run repopulators from other worldscripts (including Oolite's own)
*/
repopulators = this.interstellar_data.scripts.repopulators;
i = repopulators.length;
while (i--) {
try {
worldScripts_local[repopulators[i]].interstellarSpaceWillRepopulate();
} catch (err) {
this.msg_err(
'Problem with repopulator <' +
worldScripts_local[repopulators[i]] +
'> : ' +
err.message);
}
}
return; // NB
}
/*
----------------------------
REPOPULATION: NOVEL SCENARIO
----------------------------
*/
this.dbg && this.$msg_dbg('$repopulateInterstellar: novel scenario');
// For variety of experience, let us _not_ skip the first repopulation here in the novel scenario.
if (
this.timer_radiation_1 &&
this.timer_radiation_1.isRunning &&
(Math.random() < 0.8)
) {
this.dbg && this.$msg_dbg('$repopulateInterstellar: aborting radioactive repop');
return;
}
if (this.dbg && !this.interstellar_data.origin) {
this.$msg_err('$repopulateInterstellar: origin unset');
return;
}
const
novelRepopulation = this.interstellar_data.scenarios.versions.novel.repopulation,
playerShip = player.ship;
var
n,
numMil,
numTharg,
r,
s,
whereAdd; // needs setting later as 'new Vector3D(vector_value_in_some_format)'
numMil = system.countEntitiesWithScanClass('CLASS_MILITARY', playerShip, 500000);
numTharg = system.countEntitiesWithScanClass('CLASS_THARGOID', playerShip, 500000);
/*
////////////////////
Consider adding navy
////////////////////
*/
r = this.$randomOrPseudo(0.6, 700004);
if (
(numTharg >= numMil) ||
(r <= novelRepopulation.navy.probIgnoreParity)
) {
if (r < (novelRepopulation.navy.probIgnoreParity / 3)) {
whereAdd = new Vector3D(playerShip.position);
this.dbg && this.$msg_dbg('$repopulateInterstellar: whereAdd is playerShipPosition: <' + whereAdd + '>');
} else {
whereAdd = new Vector3D(this.interstellar_data.origin);
this.dbg && this.$msg_dbg('$repopulateInterstellar: whereAdd is origin: <' + whereAdd + '>');
}
if (
this.oxp.ferDeLance3G && (Math.random() < novelRepopulation.navy.threeG.prob)
) {
// The 3G's own populator script adds only to the witchPoint.
this.dbg && this.$msg_dbg('$repopulateInterstellar: adding navy (3G)');
s = this.$scenarioAdd_ships(
'ferdelance3G_milInterstellar',
novelRepopulation.navy.threeG.squadSize,
whereAdd,
10000, // range
true, // rings
true // group
);
} else {
this.dbg && this.$msg_dbg('$repopulateInterstellar: adding navy');
n = novelRepopulation.navy.baseNum + ~~(1 + (Math.random() * 6));
s = this.$scenarioAdd_ships(
'IST_mil',
n,
whereAdd,
10000, // range
true, // rings
false // group
);
}
return; // NB
}
/*
/////////////////////////
Consider adding thargoids
/////////////////////////
*/
r = this.$randomOrPseudo(0.6, 700005);
if (
(numTharg > novelRepopulation.thargoid.maxThargs) &&
(r > novelRepopulation.thargoids.probIgnoreMax)
) {
return;
}
this.dbg && this.$msg_dbg('$repopulateInterstellar: adding thargoid');
r = Math.random();
if (
(
playerShip.equipmentStatus('EQ_ELECTRONIC_THUMB') === 'EQUIPMENT_OK' &&
system.countShipsWithPrimaryRole('interstellar_helper')
) || Math.random() < 0.3
) {
whereAdd = new Vector3D(playerShip.position);
} else {
whereAdd = new Vector3D(this.interstellar_data.origin);
}
const u = Math.random();
const x = Math.pow(u, 2);
n = 1 + ~~(1 + x * 9); // Number 2-9, biased towards low.
s = this.$scenarioAdd_ships(
'thargoid',
n,
whereAdd,
10000,
true, // rings
false // group
);
};
/*
==================================
14 End of wrapper for JSHINT
See also JSHint options above.
==================================
*/
}).call(this);
// EOF |