Scripts/harderHermits.js |
/*
========================================================================
harderHermits.js
This file is part of the Harder Hermits expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/
/*
===================
JSHINT: set options
===================
*/
/*jshint esversion: 6*/
/*jshint sub:true*/
// Needs oolite >=1.82 (or, er, higher?)
/*
*/
this.name = "harderHermits"; // should be 'harderHermits.js'?
this.author = "UK_Eliter";
this.copyright = "See the license field";
this.description = "harderHermits.js";
this.license = "2014 CC-by-nc-sa 3.0";
/*
==================
DEBUGGING SWITCHES
==================
*/
// this.logging = true;
// Do NOT comment-out any of the following three assignments. Rather, to disable any one of them, set it to false.
var consoleDebugMessages = false;
this.debug = false;
this.debug_testResurrection = false;
// Requires this.debug to be true, but does not *make* that variable true,
/*
========================
JSLINT: start of wrapper
========================
*/
(function() {
"use strict";
/*
=======
GLOBALS
=======
*/
this.name = "harderHermits";
this.abandoned_chanceAct = 0.15;
// 0.15
this.installed_spicyHermits = false;
// Gets changed to true if the OXP is installed.
this.installed_hermitage = false;
// Gets changed to true if the OXP is installed.
this.installed_pirateCove = false;
// Gets changed to true if the OXP is installed.
/*
=========
DEBUGGING
=========
*/
this.$msg_dbg = function(debugTxt) {
if (!debugTxt) {
player.consoleMessage("Problem with debug message text!", 30);
return;
}
player.consoleMessage(this.name + " - " + debugTxt, 12);
log(this.name + " - DEBUG", debugTxt);
};
this.$msg_info = function(msgTxt) {
// if( !msgTxt ) { player.consoleMessage( "Problem with info message text!", 30 ); return; }
log(this.name + " - INFO", msgTxt);
};
/*
================
SOUNDS
================
*/
this.mySound_hullBang = new SoundSource();
this.mySound_hullBang.sound = "hullbang.ogg";
// this sound built-in to Oolite - and does not need to be declared in the 'customsounds' file.
/*
================
ENTITY PICKER(S)
================
The following roles are from Oolite itself:
rockhermit
rockhermit-chaotic
rock-hermit-pirate
The following role is from SpicyHermits:
spicy_hermits_abandoned
*/
this.$isCove = function(e) {
return e.isShip && e.AI === "pirateCoveAI.plist";
// Seemingly there is no more efficient way of doing the above.
};
this.$isAbandonedHermit = function(e) {
return e.isShip && (e.primaryRole === "asteroid" && e.name === "Abandoned Rock Hermit");
};
this.$isHermit = function(e) {
return e.isShip &&
(e.primaryRole === "rockhermit" || e.primaryRole === "rockhermit-chaotic" || e.primaryRole === "rockhermit-pirate");
};
this.$isHermitButNotHermitage = function(e) {
return e.isShip &&
(e.primaryRole === "rockhermit" || e.primaryRole === "rockhermit-chaotic" || e.primaryRole === "rockhermit-pirate") &&
!e.hasRole("hermitage");
};
/*
======
TIMERS
======
*/
this.$timer_delete_hermitAction_warn = function() {
if (!this.timer_hermitAction_warn) {
return;
}
if (this.timer_hermitAction_warn.isRunning) {
this.timer_hermitAction_warn.stop();
}
delete this.timer_hermitAction_warn;
};
this.$timer_delete_hermitAction_warnThenExplode = function() {
if (!this.timer_hermitAction_warnThenExplode) {
return;
}
if (this.timer_hermitAction_warnThenExplode.isRunning) {
this.timer_hermitAction_warnThenExplode.stop();
}
delete this.timer_hermitAction_warnThenExplode;
};
this.$timer_delete_hermitAction_explode = function() {
if (!this.timer_hermitAction_explode) {
return;
}
if (this.timer_hermitAction_explode.isRunning) {
this.timer_hermitAction_explode.stop();
}
delete this.timer_hermitAction_explode;
};
this.$timer_delete_hermitAction_resurrect = function() {
if (!this.timer_hermitAction_resurrect) {
return;
}
if (this.timer_hermitAction_resurrect.isRunning) {
this.timer_hermitAction_resurrect.stop();
}
delete this.timer_hermitAction_resurrect;
};
this.$timer_delete_die = function() {
if (!this.timer_die) {
return;
}
if (this.timer_die.isRunning) {
this.timer_die.stop();
}
delete this.timer_die;
};
this.$timer_delete_treatHermits_coves = function() {
if (!this.timer_treatHermits_coves) {
return;
}
if (this.timer_treatHermits_coves.isRunning) {
this.timer_treatHermits_coves.stop();
}
delete this.timer_treatHermits_coves;
};
this.$timer_delete_all = function() {
this.$timer_delete_die();
this.$timer_delete_treatHermits_coves();
this.$timer_delete_hermitAction_resurrect();
this.$timer_delete_hermitAction_warn();
this.$timer_delete_hermitAction_warnThenExplode();
this.$timer_delete_hermitAction_explode();
if (this.abandonedHermit) {
delete this.abandonedHermit;
}
};
/*
===============
TIMED FUNCTIONS
===============
*/
this.$treatHermits_coves = function() {
var s = system.filteredEntities(this, this.$isCove);
if (this.debug) {
// DEBUGGING version
if (s.length === 0) {
this.$msg_dbg("Seeking coves: none found.");
return;
}
this.$msg_dbg("Seeking coves: at least one found ..");
this.$treatHermits_core(s);
return;
}
// NON-DEBUGGING VERSION
if (s.length === 0) {
return;
}
this.$treatHermits_core(s);
};
this.$die_timed = function $die_timed() {
// The above format, with its repetition of the function name, is right. See http://aegidian.org/bb/viewtopic.php?p=257147#p257147.
this.$timer_delete_die();
// Do not automatically delete it, because it might not be running; other things can call this.
if (!player.ship) {
return;
}
// Next two lines are to avoid auto-eject shenanigans, etc.
if (player.ship.equipmentStatus("EQ_AUTO_EJECT") === "EQUIPMENT_OK") {
player.ship.removeEquipment("EQ_AUTO_EJECT");
}
if (player.ship.equipmentStatus("EQ_EEU") === "EQUIPMENT_OK") {
player.ship.removeEquipment("EQ_EEU");
}
player.ship.explode();
};
this.$timed_hermitAction_message_warn = function(e) {
if (!e || !e.isValid) {
return;
}
e.commsMessage("WARNING: This station will explode. Clear the area.");
e.broadcastCascadeImminent();
};
this.$timed_hermitAction_warn = function() {
if (this.debug) {
this.$msg_dbg("timed_hermitAction_warn.");
}
this.$timer_delete_hermitAction_warn();
if (!this.abandonedHermit) {
return;
}
if (!this.abandonedHermit.isValid) {
delete this.abandonedHermit;
return;
}
var e = this.abandonedHermit;
this.$timed_hermitAction_message_warn(e);
};
this.$timed_hermitAction_warnThenExplode = function() {
if (this.debug) {
this.$msg_dbg("timed_hermitAction_warnThenExplode.");
}
this.$timer_delete_hermitAction_warnThenExplode();
if (!this.abandonedHermit) {
return;
}
if (!this.abandonedHermit.isValid) {
delete this.abandonedHermit;
return;
}
this.$timed_hermitAction_message_warn(this.abandonedHermit);
var seconds = ~~((Math.random() * 60) + 0.5); // * 60
this.timer_hermitAction_explode = new Timer(this, this.$timed_hermitAction_explode, seconds);
};
this.$timed_hermitAction_explode = function() {
if (this.debug) {
this.$msg_dbg("timed_hermitAction_explode.");
}
this.$timer_delete_hermitAction_explode();
if (!this.abandonedHermit) {
return;
}
if (!this.abandonedHermit.isValid) {
delete this.abandonedHermit;
return;
}
this.abandonedHermit.explode();
// NB SpicyHermits occasionally adds a q-mine death action!
delete this.abandonedHermit;
};
this.$timed_hermitAction_resurrect = function() {
if (this.debug) {
this.$msg_dbg("timed_hermitAction_resurrect.");
}
this.$timer_delete_hermitAction_resurrect();
if (!this.abandonedHermit) {
return;
}
if (!this.abandonedHermit.isValid) {
delete this.abandonedHermit;
return;
}
// We have to *replace* the hermit (otherwise it cannot be a station).
// If the hermit is close enough to the player to notice the change, abort.
if (!player.ship || !player.ship.position) {
delete this.abandonedHermit;
return;
}
var ps = player.ship; // for speed, but changes won't affect the original variable
if (this.abandonedHermit.position.distanceTo(ps.position) < 50000) {
if (this.debug) {
this.$msg_dbg("Hermit too close to player for resurrection.");
}
delete this.abandonedHermit;
return;
}
// Get data for the replacement.
var orientation = this.abandonedHermit.orientation;
var position = this.abandonedHermit.position;
if (this.abandonedHermit) {
this.abandonedHermit.remove(true);
delete this.abandonedHermit;
}
// Do the replacement.
// Note that Spicy Hermits overrides Oolite's rockhermit shipdata, so what we'll get here is 'spicy' stuff.
var replacement;
replacement = system.addShips("harderHermits_resurrected", 1, position);
// this.replacement = this.abandonedHermit.spawnOne( "harderHermits_resurrected" );
if (replacement[0] && replacement[0].isValid) {
if (this.debug) {
this.$msg_dbg("Created replacement.");
}
// this.replacement.orientation = this.abandonedHermit.orientation;
// this.replacement.position = this.abandonedHermit.position;
replacement[0].orientation = orientation;
replacement[0].lightsActive = false;
replacement[0].desiredRange = 13000; // Tested?
if (this.debug) {
replacement[0].displayName = "Abandoned rock hermit (RESURRECTED)";
}
// Energy
var r = Math.random();
replacement[0].maxEnergy *= (r + 1.5);
} else if (this.debug) {
this.$msg_dbg("Replacement failed to exist.");
}
};
/*
==============
EVENT HANDLERS
==============
*/
this.startUp = function() {
if (this.debug) {
this.$msg_dbg("DEBUGGING is ON.");
if (this.debug_testResurrection) {
this.$msg_dbg("Testing resurrection.");
}
}
if (worldScripts["Hermitage_Main"]) {
// Hermitage_Main is the name the script itself declares.
// Yet, that script's *filename* is hermitage_main.js.
this.installed_spicyHermits = true;
this.$msg_info("Detected hermitage OXP");
}
if (worldScripts["spicy_hermits_abandoned"]) {
this.installed_spicyHermits = true;
this.$msg_info("Detected SpicyHermits OXP");
}
if (worldScripts["Pirate_Coves"]) {
this.installed_pirateCove = true;
this.$msg_info("Detected pirateCove OXP.");
}
};
this.shipDockedWithStation = function(station) {
if (!player.ship.docked || player.ship.dockedStation.name !== "Abandoned Rock Hermit") {
return;
}
// Unmodified abandoned hermits from SpicyHermits do not allow the player to dock (at all), so this routine won't fire for that.
this.showScreen = "rejectPage";
mission.runScreen({
title: "Abandoned Rock Hermit (well, not really abandoned)",
color: "redColor",
message: "You have docked at a disguised pirate cove.\n\nNine out of ten for style, but minus several thousand for good thinking.",
model: "rockhermit",
choicesKey: "harderHermits_docked"
},
function(choice) {
if (choice === "1_RETURN") {
var r = Math.random();
// r = 0.1; // TESTING
if (r < 0.2) {
player.commsMessage("The pirates attack your launching ship!");
player.ship.launch();
if (!this.timer_die) {
this.timer_die = new Timer(this, this.$die_timed, 1.7);
}
this.mySound_hullBang.play();
} else if (r < 0.8) {
var d = 40 + ~~((Math.random() * 500) + 1);
player.commsMessage("The pirates attack your launching ship!");
player.ship.launch();
player.ship.energy = player.ship.energy - d;
if (player.ship.energy < 0) {
if (!this.timer_die) {
this.timer_die = new Timer(this, this.$die_timed, 1.7);
}
} else {
this.mySound_hullBang.play();
}
}
station.reactToAIMessage("ATTACKED");
}
}
);
};
this.playerWillEnterWitchspace = function() {
this.$timer_delete_all();
};
this.shipExitedWitchspace = function() {
if (system.isInterstellarSpace) {
return;
}
if (this.debug) {
this.$msg_dbg("shipExitedWitchspace");
}
this.$treatHermits_normalAndSpicy();
if (this.installed_spicyHermits) {
this.$treatHermits_spicy_abandoned();
}
if (this.installed_pirateCove) {
// PirateCoves adds hermits upon shipExitedWitchspace
this.timer_$treatHermits_coves = new Timer(this, this.$treatHermits_coves, 1);
if (this.debug) {
this.$msg_dbg("Set timer to seek coves.");
}
}
};
/*
=======================
OTHER
=======================
*/
this.$treatHermits_core = function(s) {
var i;
var debugStr;
var energyToAdd;
/*
Adjust energy of all hermits detected. Those hermits comprise:
- all hermits added by the core game;
- hermits added by the SpicyHermits OXP (er, I think);
- hermits added by the PirateCove OXP (which get added on Witchspace exit and so are detected within this function only when it is run on a timer.
SpicyHermits gives pirate rock-hermits a maxEnergy of 2500.
SpicyHermits leaves the maxEnergy of other types alone, i.e. at Oolite default, which is 1,000.
(SpicyHermits saves the position of its hermits but anything else - including their maxEnergy - about them.
We will not try to save that, either.)
*/
i = s.length;
if (this.debug) {
// * Debugging version *
debugStr = "Hermits: iterating through <" + i + "> found ..";
this.$msg_dbg(debugStr);
while (i--) {
if (!s[i] || !s[i].isValid) {
continue;
}
debugStr = ".. Rock hermit <" + s[i].displayName + "> HAD energy " + s[i].maxEnergy;
this.$msg_dbg(debugStr);
if (s[i].maxEnergy === 1000) {
energyToAdd = Math.ceil(Math.random() * 1499);
} else if (s[i].maxEnergy === 2500) {
energyToAdd = Math.ceil(Math.random() * 180);
}
s[i].maxEnergy += energyToAdd;
debugStr = ".. Rock hermit <" + s[i].displayName + ">: added <" + energyToAdd + ">; NOW HAS energy " + s[i].maxEnergy;
this.$msg_dbg(debugStr);
}
} else {
// * NON-debugging version *
while (i--) {
if (!s[i] || !s[i].isValid) {
continue;
}
if (s[i].maxEnergy === 1000) {
energyToAdd = Math.ceil(Math.random() * 1499);
} else if (s[i].maxEnergy === 2500) {
energyToAdd = Math.ceil(Math.random() * 180);
}
s[i].maxEnergy += energyToAdd;
}
}
};
this.$treatHermits_spicy_abandoned = function() {
if (!this.debug && !this.debug_testResurrection) {
if (Math.random() > this.abandoned_chanceAct) {
if (this.debug) {
this.$msg_dbg("Abandoned hermits: decided to ignore.");
}
return;
}
}
var action, debugStr, i, r, s, seconds;
if (this.debug) {
// DEBUGGING version
this.$msg_dbg("Abandoned hermits: seeking ..");
s = system.filteredEntities(this, this.$isAbandonedHermit);
if (s.length < 1) {
this.$msg_dbg(".. found no abandoned hermits.");
return;
}
this.$msg_dbg(".. found at least one abandoned hermit.");
// Pick one of them.
i = ~~(Math.random() * s.length);
// Check there is nothing fundamentally wrong with it.
if (!(s[i] && s[i].isValid)) {
this.$msg_dbg("Invalid abandoned hermit selected.");
return;
}
this.abandonedHermit = s[i];
if (this.debug_testResurrection) {
action = "resurrect";
seconds = 5;
this.timer_hermitAction_resurrect = new Timer(this, this.$timed_hermitAction_resurrect, seconds);
} else {
seconds = ~~((Math.random() * 10800) + 1) + 5; // * 10800 + 5
r = Math.random();
if (r < 0.7) {
action = "warn-then-explode";
this.timer_hermitAction_warnThenExplode = new Timer(this, this.$timed_hermitAction_warnThenExplode, seconds);
} else if (r < 0.75) {
action = "warn";
this.timer_warn = new Timer(this, this.$timed_hermitAction_warn, seconds);
} else if (r < 0.8) {
action = "explode";
this.timer_hermitAction_explode = new Timer(this, this.$timed_hermitAction_explode, seconds);
} else {
action = "resurrect";
this.timer_hermitAction_resurrect = new Timer(this, this.$timed_hermitAction_resurrect, seconds);
}
}
s[i].displayName = "Abandoned Rock Hermit (TWEAKED)";
debugStr = ".. Primed abandoned hermit <" + this.abandonedHermit.displayName + "> to <" + action + "> in " + seconds + " seconds time.";
this.$msg_dbg(debugStr);
} else {
// NON-DEBUGGING version
s = system.filteredEntities(this, this.$isAbandonedHermit);
if (s.length < 1) {
return;
}
i = ~~(Math.random() * s.length);
if (!(s[i] && s[i].isValid)) {
return;
}
this.abandonedHermit = s[i];
seconds = ~~((Math.random() * 10800) + 1) + 5; // * 10800 + 5
r = Math.random();
if (r < 0.7) {
this.timer_hermitAction_warnThenExplode = new Timer(this, this.$timed_hermitAction_warnThenExplode, seconds);
} else if (r < 0.75) {
this.timer_warn = new Timer(this, this.$timed_hermitAction_warn, seconds);
} else if (r < 0.8) {
this.timer_hermitAction_explode = new Timer(this, this.$timed_hermitAction_explode, seconds);
} else {
this.timer_hermitAction_resurrect = new Timer(this, this.$timed_hermitAction_resurrect, seconds);
}
}
};
this.$treatHermits_normalAndSpicy = function() {
var s;
if (this.installed_hermitage) {
s = system.filteredEntities(this, this.$isHermitButNotHermitage);
} else {
s = system.filteredEntities(this, this.$isHermit);
}
if (this.debug) {
// DEBUGGING version
if (s.length === 0) {
this.$msg_dbg("Seeking normal and spicy hermits: none found.");
return;
}
this.$msg_dbg("Seeking normal and spicy hermits ..");
this.$treatHermits_core(s);
return;
}
// NON-DEBUGGING VERSION
if (s.length > 0) {
this.$treatHermits_core(s);
}
};
/*
=======================
JSHINT: end of wrapper
=======================
*/
}).call(this);
// EOF |