Scripts/broadcastcomms_mfd.js |
"use strict";
this.name = "BroadcastCommsMFD";
this.author = "phkb and Zireael";
this.copyright = "2015 phkb and Zireael";
this.description = "Displays available broadcast messages in a MFD.";
this.licence = "CC BY-NC-SA 4.0";
//TODO:
//Investigate the possibility of making all internal functions into a separate JS, and loading them using the external access functions
// specific settings for this oxp
this._debug = false; // change to false for less logging
this._MFDMaxLines = 9; // maximum number of lines visible in the MFD (10, minus 1 for the header line)
this._bribeInitial = 1; // initial bribe offering (credits)
this._demandCargo = 5; // amount of cargo to demand (tons)
this._tauntAccuracyLength = 10; // how long the accuracy adjustment will last (in seconds)
this._surrenderWait = 15; // time to wait (in seconds) after a surrender before checking player has complied
this._surrenderWait_Police = 5; // time to wait (in seconds) after surrendering to police before checking if the player has complied (repeats until player reaches main station, jumps out of system, or is declared non-compliant)
this._surrenderAccuracyLength = 20; // how long (in seconds) the extra accuracy lasts (given when player renegs surrender with lasers)
this._outputToConsole = true; // indicates the selected comms message will be displayed as a console message
// for cases where the MFD is not visible
this._defaultResponseWait = 2; // default amount of time to wait between sending comms and reply
this._internalMessages = 13; // number of internal messages
this._lastSource = -1; // used to establish the start point for destination system calculations
this._msgAlt = ""; // use to switch to a 3rd party OXP supplying new message responses
this._idSource = 0;
//=============================================================================================================
// set up initial variables
this.startUp = function () {
this._killedNames = []; // array containing list of ship names killed by the player in this outing
// used to determine how an escape pod will respond
this._escapepodShipNames = []; // array of links between escape pods and ships
this._scoopOffer = []; // keeps track of escape pods we've communicated with
this._selectedMsg = -1; // currently selected message (defaults to no message)
this._holdTarget = -1; // keeps track of the players hyperspace destination
this._lines = []; // available messages as lines on the MFD
this._greeted = []; // keeps track of ships we've greeted
this._bribed = []; // keeps track of ships we're bribed
this._demanded = []; // keeps track of ships we've demanded cargo from
this._alertCond = 1; // keeps track of the current alert condition
this._targetType = ""; // keeps track of the type of target (either npc, police, thargoid)
this._closestAttackerType = ""; // keeps track of the type of closest attacker
this._accuracyChanged = []; // keeps track of ships whose accuracy we've adjusted
this._bribeCurrent = []; // keeps track of the current bribe offered to different targets
this._bribeAmount = this._bribeInitial; // current bribe offering
this._piracyWorked = false; // flag to indicate that the players demand for cargo (piracy) worked
this._checkTimer = null; // timer to check for when the player target disappears (ie through a wormhole)
this._piracyNPCTimer = null; // timer for an NPC telling police about players act of piracy
this._piracyPoliceTimer = null; // timer for a police response to NPC telling them about players act of piracy
this._waitingForPiracyResponse = false; // flag to indicate the player is waiting for a target to respond to a demand for cargo
this._externalMessages = []; // any external messages
this._surrenderCurrent_Pirate = []; // keeps track of the current list of ships surrendered to
this._surrenderedTo = []; // keeps track of who we've surrendered to
this._surrenderTimer_Pirate = null; // timer that will wait for cargo being dumped after surrender
this._surrenderCheck_Pirate = false; // indicates that player has surrendered and that cargo should be getting dumped
this._surrenderCheck_Police = false; // indicates that player has sent a surrender request to police and has been told to disable weapons
this._surrenderTimer_Police = null; // timer to monitor player compliance after surrendering to police (will run until player docks or leaves system)
this._surrenderPoliceChances = 0; // if player is not complying with police instructions, they have this many timer updates remaining to comply
this._surrenderMainStationDist = 0; // keeps track of how close the player has come to the main station after surrender, in case they go somewhere else
this._surrenderBounty = 0; // "hidden" bounty after surrendering to police, will be restored when leaving system or docking at any station
this._dockingRequest = false;
this._targetStation = null;
this._targetLastComms = null; // holds reference to last transmission source
this._disableInternal = []; // array of flags to keep track of which internal messages have been disabled
for (var i = 0; i <= this._internalMessages; i++) {
this._disableInternal.push(false);
}
this.$updateView(false);
this._lastSource = system.ID;
}
// ideas: have a "sorry" message for when you accidentally fire on police or stations, which could then limit retaliation
// need to work out when the player has fired on GalCop's or system stations.
//=============================================================================================================
// external access
//-------------------------------------------------------------------------------------------------------------
// function used to create a custom message
this.$createMessage = function (msgobj) {
var truetypes = ["yes", "1", "true", true, 1, -1];
var falsetypes = ["no", "0", "false", false, 0];
var transtypes = ["broadcast", "target"];
// check for some invalid conditions
if (msgobj.hasOwnProperty("messageName") === false || msgobj.messageName === "") {
throw "Invalid settings: messageName must not be null or blank.";
}
if (msgobj.hasOwnProperty("transmissionType") === true && transtypes.indexOf(msgobj.transmissionType) === -1) {
throw "Invalid settings: transmissiontype must be either 'broadcast' or 'target'.";
}
if (msgobj.hasOwnProperty("displayText") === false || msgobj.displayText === "") {
throw "Invalid settings: displayText must not be null or blank.";
}
if (msgobj.hasOwnProperty("callbackFunction") === false || msgobj.callbackFunction === "") {
throw "Invalid settings: callbackFunction not set.";
}
// if these params are null, default them
if (msgobj.hasOwnProperty("deleteOnTransmit") === false || falsetypes.indexOf(msgobj.deleteOnTransmit) === -1) msgobj.deleteOnTransmit = true;
if (msgobj.hasOwnProperty("delayCallback") === false) msgobj.delayCallback = this._defaultResponseWait;
if (msgobj.hasOwnProperty("messageText") === false || msgobj.messageText === "") msgobj.messageText = msgobj.displayText;
if (msgobj.hasOwnProperty("shipDisplayName") === false) msgobj.shipDisplayName = "";
if (msgobj.hasOwnProperty("hideOnConditionRed") === false || truetypes.indexOf(msgobj.hideOnConditionRed) === -1) msgobj.hideOnConditionRed = false;
// check that this message isn't already in the list
var found = false;
// check the external messages
if (!this._externalMessages) this._externalMessages = [];
if (this._externalMessages) {
for (var i = 0; i < this._externalMessages.length; i++) {
if (this._externalMessages[i] && this._externalMessages[i].messageName === msgobj.messageName) {
throw "Invalid settings: message already exists.";
}
}
}
var chkShip = null;
var disable_defaults = [];
if (msgobj.hasOwnProperty("ship")) chkShip = msgobj.ship;
if (chkShip && chkShip.scriptInfo.hasOwnProperty("bcc_disable_defaults") && Array.isArray(chkShip.scriptInfo.bcc_disable_defaults)) disable_defaults = chkShip.scriptInfo.bcc_disable_defaults
if (chkShip && chkShip.script.hasOwnProperty("bcc_disable_defaults") && Array.isArray(chkShip.script.bcc_disable_defaults)) disable_defaults = chkShip.script.bcc_disable_defaults
// then check the built in messages
if ((msgobj.displayText.indexOf("Is anyone heading") >= 0 && (!this._disableInternal[1] && disable_defaults.indexOf("1") == -1)) ||
(msgobj.displayText === "Send distress message" && (!this._disableInternal[2] && disable_defaults.indexOf("2") == -1)) ||
(msgobj.displayText === "Send greeting to target" && (!this._disableInternal[3] && disable_defaults.indexOf("3") == -1)) ||
(msgobj.displayText === "Send taunt to target" && (!this._disableInternal[4] && disable_defaults.indexOf("4") == -1)) ||
(msgobj.displayText === "Issue threat to target" && (!this._disableInternal[5] && disable_defaults.indexOf("5") == -1)) ||
(msgobj.displayText === "Surrender to target" && (!this._disableInternal[8] && disable_defaults.indexOf("8") == -1)) ||
(msgobj.displayText === "Offer to rescue escape pod" && (!this._disableInternal[9] && disable_defaults.indexOf("9") == -1)) ||
(msgobj.displayText === "(Target last comms message)" && (!this._disableInternal[10] && disable_defaults.indexOf("10") == -1)) ||
(msgobj.displayText === "Keep away from my target" && (!this._disableInternal[11] && disable_defaults.indexOf("11") == -1)) ||
(msgobj.displayText === "Request docking clearance" && (!this._disableInternal[12] && disable_defaults.indexOf("12") == -1)) ||
(msgobj.displayText === "Withdraw docking request" && (!this._disableInternal[13] && disable_defaults.indexOf("13") == -1)) ||
(msgobj.displayText === "Demand " + this._demandCargo.toString() + " ton" + ((this._demandCargo === 1) ? "" : "s") + " of cargo from target" && (!this._disableInternal[7] && disable_defaults.indexOf("7") == -1)) ||
(msgobj.displayText.indexOf("Offer bribe") >= 0 && (!this._disableInternal[6]) && disable_defaults.indexOf("6") == -1)) {
throw "Invalid settings: Cannot use comm system message types.";
}
// if we didn't find it, add it now
this._externalMessages.push({
messageName: msgobj.messageName,
callbackFunction: msgobj.callbackFunction,
displayText: msgobj.displayText,
messageText: msgobj.messageText,
ship: msgobj.ship,
shipDisplayName: msgobj.shipDisplayName,
transmissionType: msgobj.transmissionType,
deleteOnTransmit: msgobj.deleteOnTransmit,
delayCallback: msgobj.delayCallback,
hideOnConditionRed: msgobj.hideOnConditionRed
});
/*var keys = Object.keys(msgobj);
for (var i = 0; i < keys.length; i++) {
log(this.name, keys[i] + " - " + msgobj[keys[i]]);
}*/
this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
// checks for the existence of a message in the current list. Returns true if found, otherwise false.
this.$checkMessageExists = function (messagename) {
var found = false;
if (this._externalMessages != null && this._externalMessages.length > 0) {
for (var i = 0; i < this._externalMessages.length; i++) {
if (this._externalMessages[i] && this._externalMessages[i].messageName === messagename) {
found = true;
break;
}
}
}
return found;
}
//-------------------------------------------------------------------------------------------------------------
// function used to update the message display text and transmission text of an existing message
this.$updateMessage = function (msgobj) {
if (msgobj.hasOwnProperty("messageName") === false || msgobj.messageName === "") {
throw "Invalid setting: messageName must not be null or blank.";
}
if (msgobj.hasOwnProperty("displayText") === true && msgobj.displayText === "") {
throw "Invalid settings: displayText must not be blank.";
}
var found = false;
if (this._externalMessages) {
for (var i = 0; i < this._externalMessages.length; i++) {
if (this._externalMessages[i] && this._externalMessages[i].messageName != msgobj.messageName && this._externalMessages[i].displayText === msgobj.displayText) {
found = true;
}
}
}
if (found === true) {
throw "Invalid settings: displayText is already used in another another message.";
}
var rebuild = false;
// look through the list
if (this._externalMessages) {
for (var i = 0; i < this._externalMessages.length; i++) {
if (this._externalMessages[i] && this._externalMessages[i].messageName === msgobj.messageName) {
if (msgobj.hasOwnProperty("displayText") === true && this._externalMessages[i].displayText != msgobj.displayText) {
this._externalMessages[i].displayText = msgobj.displayText;
rebuild = true;
}
if (msgobj.hasOwnProperty("messageText") === true && msgobj.messageText != "") this._externalMessages[i].messageText = msgobj.messageText;
if (msgobj.hasOwnProperty("callbackFunction") === true) this._externalMessages[i].callbackFunction = msgobj.callbackFunction;
if (msgobj.hasOwnProperty("deleteOnTransmit") === true) this._externalMessages[i].deleteOnTransmit = msgobj.deleteOnTransmit;
if (msgobj.hasOwnProperty("delayCallback") === true) this._externalMessages[i].delayCallback = msgobj.delayCallback;
break;
}
}
}
// if we found a match, rebuild the message list
if (rebuild === true) this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
// function to disable internal messages
// disable options
// 0 - all
// 1 - request for wormhole
// 2 - send distress message
// 3 - send greeting
// 4 - send taunt
// 5 - send threat
// 6 - offer bribe
// 7 - demand cargo
// 8 - surrender to target
// 9 - escape pod offer to rescue
// 10 - target last comms message
// 11 - keep away from my target
// 12 - request docking clearance
// 13 - withdraw docking request
this.$disableMessage = function (msgid) {
if (msgid > this._disableInternal.length - 1) {
throw "Invalid settings: msgid must be less than " + (this._disableInternal.length - 1).toString() + ".";
}
if (msgid === 0) {
for (var i = 0; i < this._disableInternal.length; i++) {
this._disableInternal[i] = true;
}
} else {
this._disableInternal[msgid] = true;
}
this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
// function to enable internal messages
// enable options
// 0 - all
// 1 - request for wormhole
// 2 - send distress message
// 3 - send greeting
// 4 - send taunt
// 5 - send threat
// 6 - offer bribe
// 7 - demand cargo
// 8 - surrender to target
// 9 - escape pod offer to rescue
// 10 - target last comms message
// 11 - keep away from my target
this.$enableMessage = function (msgid) {
if (msgid > this._disableInternal.length - 1) {
throw "Invalid settings: msgid must be less than " + (this._disableInternal.length - 1).toString() + ".";
}
if (msgid === 0) {
for (var i = 0; i < this._disableInternal.length; i++) {
this._disableInternal[i] = false;
}
} else {
this._disableInternal[msgid] = false;
}
this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
// function to determine if an internal message is enabled or not
// msgid = id of internal message.
// returns true if message is enabled, otherwise false
// passing msgid value of 0 will check if all messages are enabled. Only returns true if all messages are enabled. Otherwise false.
this.$isMessageEnabled = function (msgid) {
if (msgid > this._disableInternal.length - 1) {
throw "Invalid settings: msgid must be less than " + (this._disableInternal.length - 1).toString() + ".";
}
if (msgid === 0) {
var count = 0;
for (var i = 0; i < this._disableInternal.length; i++) {
if (this._disableInternal[i] === false) count += 1;
}
if (count === this._disableInternal.length) {
return true;
} else {
return false;
}
} else {
return !this._disableInternal[msgid]
}
}
//-------------------------------------------------------------------------------------------------------------
// function used to remove a message from the external messages list
this.$removeMessage = function (messagename) {
if (messagename == null || messagename === "") {
throw "Invalid setting: messagename must not be null or blank.";
}
var rebuild = false;
// look through the list
if (this._externalMessages) {
for (var i = 0; i < this._externalMessages.length; i++) {
if (this._externalMessages[i] && this._externalMessages[i].messageName === messagename) {
// found it, so set the array entry to null to remove it
this._externalMessages[i] = null;
rebuild = true;
}
}
}
// if we found a match, rebuild the message list
if (rebuild === true) this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
// the number of lines (messages) in our message box
this.$maxMessages = function () {
return this._lines.length;
}
//=============================================================================================================
// ship interfaces
//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation = function _shipWillDockWithStation(station) {
this.$stopAllTimers();
this._dockingRequest = false;
var that = _shipWillDockWithStation; // pointer to this function
var bountysystem = (that.bountysystem = that.bountysystem || worldScripts.BountySystem_Core); // cache worldScript reference in a local property on this function
if (this._surrenderBounty > 0) { // hidden bounty from surrendering to police will be restored when docking with any station (not only the main station!)
if (bountysystem) bountysystem._changing = true; // tell Bounty System OXP to ignore the bounty change we are about to do (so it doesn't get recorded as a new offence)
player.bounty += this._surrenderBounty; // make hidden bounty visible again (add it to current bounty in case the player gained additional bounty meanwhile)
if (bountysystem) bountysystem._changing = false; // tell Bounty System OXP to pay attention to bounty changes again
this._surrenderBounty = 0; // clear our hidden bounty variable (need to do this regardless of whether Bounty System is installed)
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation = function (station) {
this.$fullResetVariables();
this._holdTarget = this.$playerTargetSystem();
this.$buildMessageList();
this._lastSource = system.ID;
}
//-------------------------------------------------------------------------------------------------------------
this.playerBoughtEquipment = function (equipment) {
if (equipment === "EQ_BROADCASTCOMMSMFD_REMOVAL") {
var p = player.ship;
p.removeEquipment("EQ_BROADCASTCOMMSMFD_REMOVAL");
p.removeEquipment("EQ_BROADCASTCOMMSMFD");
}
}
//-------------------------------------------------------------------------------------------------------------
this.equipmentDamaged = function(equipment) {
if (equipment == "EQ_BROADCASTCOMMSMFD") {
this.$buildMessageList();
}
}
//-------------------------------------------------------------------------------------------------------------
this.equipmentRepaired = function(equipment) {
if (equipment == "EQ_BROADCASTCOMMSMFD") {
this.$buildMessageList();
}
}
//-------------------------------------------------------------------------------------------------------------
this.guiScreenChanged = function (to, from) {
if (!player.ship.isInSpace) return;
if (from === "GUI_SCREEN_SHORT_RANGE_CHART" || from === "GUI_SCREEN_LONG_RANGE_CHART") {
if (this._holdTarget != this.$playerTargetSystem()) {
this._holdTarget = this.$playerTargetSystem();
this.$buildMessageList();
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.alertConditionChanged = function (newCondition, oldCondition) {
if (!player.ship.isInSpace) return;
if (player.ship.isInSpace === true && this._alertCond != player.alertCondition) {
if (player.alertCondition != 3 || (player.alertCondition === 3 && player.alertHostiles === true)) this._alertCond = player.alertCondition;
this.$buildMessageList();
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipTargetLost = function (target) {
this.$resetVariables();
this.$startTargetTimer();
if (target === this._targetLastComms) this._targetLastComms = null;
this._bribeAmount = this._bribeInitial;
this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillEnterWitchspace = function _shipWillEnterWitchspace(station) {
var that = _shipWillEnterWitchspace; // pointer to this function
var bountysystem = (that.bountysystem = that.bountysystem || worldScripts.BountySystem_Core); // cache worldScript reference in a local property on this function
if (this._surrenderBounty > 0) { // hidden bounty from surrendering to police will be restored when jumping out of the system
if (!bountysystem) { // but do not do this if Bounty System is installed; it will take care of setting the player's bounty including the hidden amount
player.bounty += this._surrenderBounty; // make hidden bounty visible again (add it to current bounty in case the player gained additional bounty meanwhile)
}
this._surrenderBounty = 0; // clear our hidden bounty variable (need to do this regardless of whether Bounty System is installed)
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillExitWitchspace = function () {
this.$stopAllTimers();
this.$fullResetVariables();
this._holdTarget = this.$playerTargetSystem();
this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
this.shipExitedWitchspace = function () {
// update the lastSource ID
if (system.ID != -1) this._lastSource = system.ID;
}
//-------------------------------------------------------------------------------------------------------------
this.playerEnteredNewGalaxy = function (galaxyNumber) {
this.$stopAllTimers();
this.$fullResetVariables();
this._holdTarget = -1;
this.$buildMessageList();
this._lastSource = system.ID;
}
//-------------------------------------------------------------------------------------------------------------
this.shipTargetAcquired = function (target) {
this._targetType = "";
this._closestAttackerType = "";
this._bribeAmount = this._bribeInitial;
if (target.isShip === true && target.isPiloted) {
if (target.scanClass != "CLASS_CARGO") {
this._targetType = "npc";
// not sure about OXP ships, whether analysis of all roles (not just the primary role) will be required
if (Ship.roleIsInCategory(target.primaryRole, "oolite-police") === true) this._targetType = "police";
if (target.scanClass === "CLASS_THARGOID") this._targetType = "thargoid";
if (Ship.roleIsInCategory(target.primaryRole, "oolite-bounty-hunter") === true) {
this._targetType = "hunter";
// work out what the bribe amount should be
this.$workOutCurrentBribeAmount(target);
}
if (Ship.roleIsInCategory(target.primaryRole, "oolite-pirate") === true) {
this._targetType = "pirate";
// work out what the bribe amount should be
this.$workOutCurrentBribeAmount(target);
}
if (target.isStation) this._targetType = "station";
}
if (target.scanClass === "CLASS_CARGO" && target.hasRole("escape-capsule") === true) this._targetType = "escapepod";
}
this.$buildMessageList();
this.$startTargetTimer();
}
//-------------------------------------------------------------------------------------------------------------
this.shipDied = function (whom, why) {
if (this._debug === true) log(this.name, "shipDied whom = " + whom.displayName + " why = " + why);
this.$stopAllTimers();
}
//-------------------------------------------------------------------------------------------------------------
this.shipTargetDestroyed = function (target) {
this.$resetVariables();
this.$startTargetTimer();
this._bribeAmount = this._bribeInitial;
if (target === this._targetLastComms) this._targetLastComms = null;
this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
this.commsMessageReceived = function (message, sender) {
if (sender && sender != player.ship && sender.isStation === false && sender != player.ship.target) {
if (this._debug) log(this.name, "last comms: " + sender.displayName);
this._targetLastComms = sender;
this.$buildMessageList();
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipKilledOther = function (whom, damageType) {
if (whom === this._targetLastComms) this._targetLastComms = null;
// keep track of the names of ship's crew we've killed, so if they end up in an escape pod, we can adjust the message responses
if (!whom.hasRole("escape-capsule") && (whom.isPiloted || whom.isDerelict || whom.hasRole("tharglet") || whom.hasRole("thargon"))) {
this._killedNames.push(whom.displayName);
// did the ship launch an escape pod? look for one within 1km of destroyed ship
var podsinRange = system.shipsWithRole("escape-capsule", whom, 1000);
if (podsinRange && podsinRange.length > 0) {
// we only get here if we've found at least 1 escape pod
podsinRange.forEach(function (pod) {
var bAdd = true;
// have we already added this pod to our array?
if (this._escapepodShipNames.length != 0) {
for (var i = 0; i < this._escapepodShipNames.length; i++) {
if (this._escapepodShipNames[i].escapepod === pod) bAdd = false;
}
}
if (bAdd === true) this._escapepodShipNames.push({
escapepod: pod,
shipname: whom.displayName
});
}, this);
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipBeingAttacked = function (whom) {
// add this ship to the greeting list - we don't want to send a greeting to someone who's fired at us
this.$addShipToArray(whom, this._greeted);
}
//-------------------------------------------------------------------------------------------------------------
this.shipAttackedOther = function (other) {
if (this._debug === true) log(this.name, "shipAttackedOther - " + other.displayName);
// check if player is attacking a ship they surrendered to
if (this._surrenderCheck_Pirate === true) {
var scp = this._surrenderCurrent_Pirate;
if (scp != null && scp.length > 0) {
var found = false;
var group = "";
for (var i = 0; i < scp.length; i++) {
if (scp[i] === other) {
// we have a match - surrender is void
found = true;
group = scp[i].group;
break;
}
}
if (found === true) {
// increase their accuracy
for (var i = 0; i < scp.length; i++) {
scp[i].target = player.ship;
this.$addShipToAccuracyList(scp[i], 4, this._surrenderAccuracyLength);
if (scp[i].isVisible === true && ((group == null || group === "") || this.$rand(20) > 10)) {
// send a message from the group
this.$sendMessageToPlayer(scp[0], this.$getRandomItemDescription("response-break-surrender-pirate"));
}
}
// reset the surrender current values
this._surrenderCheck_Pirate = false;
this._surrenderCurrent_Pirate = [];
this._surrenderTimer_Pirate.stop();
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.cargoDumpedNearby = function (cargo, ship) {
// target dumped cargo after we asked
if (this._source === ship && this._waitingForPiracyResponse) {
if (this._debug === true) log(this.name, "cargo dumped from players piracy victim - piracy worked");
// is ship in range of a police vessel or station
if (this.$countLawVessels(ship) > 0 && this.$rand(50) > 40) {
if (this._debug === true) log(this.name, "police vessel was notified of act of piracy - player bounty increased");
this._piracyVictim = ship;
// start a timer to send a notification from npc to police
this._piracyNPCTimer = new Timer(this, this.$sendPiracyNPCResponse, 4, 0);
}
this._piracyWorked = true;
this._waitingForPiracyResponse = false;
}
// player dumped cargo after surrender
if (this._surrenderCheck_Pirate === true && ship === player.ship) {
// player has complied with surrender demands - turn off retaliation
this._surrenderTimer_Pirate.stop();
this._surrenderCheck_Pirate = false;
// set one of the pirates in the group to scoop cargo
if (this._surrenderCurrent_Pirate.length > 0) {
for (var i = 0; i < this._surrenderCurrent_Pirate.length; i++) {
if (this._surrenderCurrent_Pirate[i].cargoSpaceCapacity > 0) {
this._surrenderCurrent_Pirate[i] = cargo;
break;
}
}
}
this._surrenderCurrent_Pirate = [];
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerDockingClearanceExpired = function () {
this._dockingRequest = false;
if (oolite.compareVersion("1.85") <= 0) this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
this.playerDockingClearanceGranted = function () {
this._dockingRequest = true;
if (oolite.compareVersion("1.85") <= 0) this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
this.playerDockingClearanceCancelled = function () {
this._dockingRequest = false;
if (oolite.compareVersion("1.85") <= 0) this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
this.playerRequestedDockingClearance = function (message) {
//log(this.name, "bcc " + message);
switch (message) {
case "DOCKING_CLEARANCE_EXTENDED":
case "DOCKING_CLEARANCE_DENIED_TRAFFIC_OUTBOUND":
case "DOCKING_CLEARANCE_DENIED_TRAFFIC_INBOUND":
case "DOCKING_CLEARANCE_GRANTED":
this._dockingRequest = true;
break;
case "DOCKING_CLEARANCE_DENIED_SHIP_FUGITIVE":
case "DOCKING_CLEARANCE_DENIED_NO_DOCKS":
case "DOCKING_CLEARANCE_NOT_REQUIRED":
case "DOCKING_CLEARANCE_CANCELLED":
this._dockingRequest = false;
break;
}
if (oolite.compareVersion("1.85") <= 0) this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
this.shipSpawned = function(ship) {
var msgs = {};
if (ship.scriptInfo.hasOwnProperty("bcc_custom_messages")) msgs = ship.scriptInfo.bcc_custom_messages;
if (ship.script.hasOwnProperty("bcc_custom_messages")) msgs = ship.script.bcc_custom_messages;
if (Object.keys(msgs).length > 0) {
ship.script.bcc_id_source = this._idSource;
this._idSource += 1;
// put the dictionary on the ship script so we can track state (scriptInfo is readonly otherwise)
ship.script.bcc_current_messages = JSON.parse(JSON.stringify(msgs));
this.$setupCurrentCustomMessages(ship);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$setupCurrentCustomMessages = function(ship) {
var msgs = ship.script.bcc_current_messages;
if (Object.keys(msgs).length == 0) return;
var keys = Object.keys(msgs);
for (var i = 0; i < keys.length; i++) {
var msg = msgs[keys[i]];
if (msg.state == "visible") {
if (this.$checkMessageExists(this.name + "_" + ship.script.bcc_id_source + "_" + keys[i]) == false) {
this.$createMessage({
messageName: this.name + "_" + ship.script.bcc_id_source + "_" + keys[i],
transmissionType: "target",
ship: ship,
displayText: msg.display,
messageText: expandDescription(msg.transmit),
deleteOnTransmit: msg.delete_on_transmit,
delayCallback: msg.delay,
callbackFunction: this.$customMessageCallback.bind(this, ship, keys[i])
});
}
} else {
if (this.$checkMessageExists(this.name + "_" + ship.script.bcc_id_source + "_" + keys[i])) {
this.$removeMessage(this.name + "_" + ship.script.bcc_id_source + "_" + keys[i]);
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$customMessageCallback = function(ship, msg_key) {
var msgs = ship.script.bcc_current_messages;
var msg = msgs[msg_key];
msg.state = "hidden";
this.$sendMessageToPlayer(ship, expandDescription(msg.reply));
if (msg.hasOwnProperty("post_reply_hide_messages") && Array.isArray(msg.post_reply_hide_messages)) {
var replies = msg.post_reply_hide_messages;
for (var i = 0; i < replies.length; i++) {
msgs[replies[i]].state = "hidden";
}
}
if (msg.hasOwnProperty("post_reply_show_messages") && Array.isArray(msg.post_reply_show_messages)) {
var replies = msg.post_reply_show_messages;
for (var i = 0; i < replies.length; i++) {
msgs[replies[i]].state = "visible";
}
}
if (msg.hasOwnProperty("post_reply_function") && msg.post_reply_function != "" && msg.hasOwnProperty("post_reply_worldscript") && msg.post_reply_worldscript != "") {
worldScripts[msg.post_reply_worldscript][msg.post_reply_function](ship, msg_key);
}
// force the messages to be updated
this.$setupCurrentCustomMessages(ship);
}
//=============================================================================================================
// starts the target watcher timer if it's appropriate to do so, otherwise stops the timer
this.$startTargetTimer = function () {
// start/stop the check target timer
if (this._targetType != "" && this._targetType != "station" && (this._checkTimer == null || this._checkTimer.isRunning === false)) {
// if we have a non-station target, then start our check timer
this._checkTimer = new Timer(this, this.$checkForTargetInvalid, 1, 1);
} else if ((this._targetType === "" || this._targetType === "station") && this._checkTimer != null && this._checkTimer.isRunning === true) {
// stop our timer - we don't have a target to watch anymore
this._checkTimer.stop();
}
}
//=============================================================================================================
// rebuilds the list of available messages, based on current state of play
this.$buildMessageList = function () {
// store the currently selected message, so we can reselect it after the list is rebuilt
var stored = "";
if (this._selectedMsg >= 0 && this._selectedMsg < this._lines.length && this._lines[this._selectedMsg] != null) {
stored = this._lines[this._selectedMsg].id;
}
// reset comms log settings
this._lines = [];
// p = player ship, t = player target, tt = player's targets target
var p = player.ship,
t = p && p.target,
tt = t && t.target;
var disable_defaults = [];
if (t) {
if (t.scriptInfo && t.scriptInfo.hasOwnProperty("bcc_disable_defaults") && Array.isArray(t.scriptInfo.bcc_disable_defaults)) disable_defaults = t.scriptInfo.bcc_disable_defaults;
if (t.script && t.script.hasOwnProperty("bcc_disable_defaults") && Array.isArray(t.script.bcc_disable_defaults)) disable_defaults = t.script.bcc_disable_defaults;
}
if (p.equipmentStatus("EQ_BROADCASTCOMMSMFD") === "EQUIPMENT_OK") {
if (this._targetLastComms && this._disableInternal[10] === false && disable_defaults.indexOf("10") == -1) this._lines.push({
id: "core_10",
text: "(Target last comms message)"
});
// add default messages (ie "broadcast" messages)
// if there are hostiles present
if (this._alertCond === 3 && this._disableInternal[2] === false && disable_defaults.indexOf("2") == -1) this._lines.push({
id: "core_2",
text: "Send distress message"
});
// load up any external messages
if (this._externalMessages !== null && this._externalMessages.length > 0) {
var cMsg = {};
var bAdd = false;
for (var i = 0; i < this._externalMessages.length; i++) {
bAdd = false;
cMsg = this._externalMessages[i];
if (cMsg) {
// are we going to display this message?
if (cMsg.transmissionType === "broadcast" ||
(cMsg.transmissionType === "target" && cMsg.ship === null && cMsg.shipDisplayName === "" && t !== null) ||
(cMsg.transmissionType === "target" && cMsg.ship && t === cMsg.ship) ||
(cMsg.transmissionType === "target" && cMsg.shipDisplayName && t.displayName === cMsg.shipDisplayName)) {
bAdd = true;
}
if (this._alertCond === 3 && cMsg.hideOnConditionRed === true) bAdd = false;
if (bAdd === true) this._lines.push({
id: cMsg.messageName,
text: cMsg.displayText
});
}
}
}
// do we have a non-hostile target? add general target messages
// greeting, taunt, drop your cargo,
if (this._alertCond !== 3 && t && t.isPiloted && this._targetType !== "station" && this._targetType !== "escapepod") {
// check who we've greeted before
// only allow greeting to non-greeted ships
if (this.$itemIsInArray(t, this._greeted) === false && this._disableInternal[3] === false && disable_defaults.indexOf("3") == -1) {
this._lines.push({
id: "core_3",
text: "Send greeting to target"
});
}
if (this._disableInternal[4] === false && disable_defaults.indexOf("4") == -1) this._lines.push({
id: "core_4",
text: "Send taunt to target"
});
// only add add a demand for cargo if the ship has cargo capacity
if (t.cargoSpaceCapacity > 0 && this._disableInternal[7] === false && disable_defaults.indexOf("7") == -1) {
// check who we've demanded cargo from before
// only allow demands to ships once
if (this.$itemIsInArray(t, this._demanded) === false) {
this._lines.push({
id: "core_7",
text: "Demand " + this._demandCargo.toString() + " ton" + ((this._demandCargo === 1) ? "" : "s") + " of cargo from target"
});
}
}
}
if (t && t.isPiloted && this._targetType === "escapepod") {
if (this.$itemIsInArray(t, this._scoopOffer) === false && this._disableInternal[9] === false && disable_defaults.indexOf("9") == -1 && p.equipmentStatus("EQ_FUEL_SCOOPS") === "EQUIPMENT_OK") {
this._lines.push({
id: "core_9",
text: "Offer to rescue escape pod"
});
}
}
// no target set (or target is not attacking player), but red alert condition
if (this._alertCond === 3 && (!t || tt !== p)) {
if (this._disableInternal[8] === false && disable_defaults.indexOf("8") == -1) this._lines.push({
id: "core_8",
text: "Surrender to nearest attacker"
});
if (this._disableInternal[6] === false && disable_defaults.indexOf("6") == -1) this._lines.push({
id: "core_6",
text: "Offer bribe to nearest attacker"
});
}
// do we have a hostile target? add hostile target messages
// i surrender, taunt, threat, bribe
if (this._alertCond === 3 && t && t.isPiloted && this._targetType !== "station" && this._targetType !== "escapepod") {
// only allow surrender to ships we haven't surrendered to before ... unless they are police attacking us!
if ((t.isPolice && t.hasHostileTarget && tt == p) || (this._disableInternal[8] === false && disable_defaults.indexOf("8") == -1 && this.$itemIsInArray(t, this._surrenderedTo) === false)) {
this._lines.push({
id: "core_8",
text: "Surrender to target"
});
}
// only offer bribe option to ship targeting the player
if (tt === p && player.credits >= this._bribeAmount && (this._targetType === "npc" || this._targetType === "pirate" || this._targetType === "hunter" || this._targetType === "police")) {
// check who we've bribed before
// only allow bribing to non-bribed ships
if (this.$itemIsInArray(t, this._bribed) === false && this._disableInternal[6] === false && disable_defaults.indexOf("6") == -1) {
this._lines.push({
id: "core_6",
text: "Offer bribe of " + this._bribeAmount.toString() + "cr to target"
});
}
}
if (this._disableInternal[4] === false && disable_defaults.indexOf("4") == -1) this._lines.push({
id: "core_4",
text: "Send taunt to target"
});
if (this._disableInternal[5] === false && disable_defaults.indexOf("5") == -1) this._lines.push({
id: "core_5",
text: "Issue threat to target"
});
if (this._disableInternal[11] === false && disable_defaults.indexOf("11") == -1) this._lines.push({
id: "core_11",
text: "Keep away from my target"
});
}
// if a target system is set
if (this._alertCond !== 3 && this._holdTarget !== global.system.ID && this._holdTarget >= 0 && this._disableInternal[1] === false && disable_defaults.indexOf("1") == -1) {
this._lines.push({
id: "core_1",
text: "Is anyone heading to " + System.systemNameForID(this._holdTarget) + "?"
});
}
// docking clearance
if (typeof p.requestDockingClearance === "function") {
if (t && t.isValid && t.isStation && t.canDockShip(p) && this._dockingRequest === false && this._disableInternal[12] === false && disable_defaults.indexOf("12") == -1) {
this._lines.push({
id: "core_12",
text: "Request docking clearance"
});
}
if (t && t.isValid && t.isStation && t.canDockShip(p) && this._dockingRequest === true && this._disableInternal[13] === false && disable_defaults.indexOf("13") == -1) {
this._lines.push({
id: "core_13",
text: "Withdraw docking request"
});
}
}
}
if (stored !== null && stored !== "") {
// in our new array, check to see that our stored message still exists
var found = false;
for (var i = 0; i < this._lines.length; i++) {
if (this._lines[i].id === stored) {
// if it does, set the selected message pointer to it
this._selectedMsg = i;
found = true;
}
}
if (found === false) {
// if the selected message isn't there anymore, reset the selected message pointer
this._selectedMsg = -1;
}
}
this.$updateView(false);
}
//=============================================================================================================
// displays the available messages in the MFD
this.$updateView = function (sendConsole) {
var p = player.ship;
if (p.equipmentStatus("EQ_BROADCASTCOMMSMFD") === "EQUIPMENT_OK") {
var output = "";
var glyph = ">";
// if we have lines, work out what to display, based on the current scroll position
if (this._lines != null && (this._lines.length != 1 || this._lines[0].text != "")) {
var start = 0;
if (this._selectedMsg > this._MFDMaxLines - 1) start = this._selectedMsg - 8;
// build the header
output = "BROADCAST MESSAGE:";
if (start > 0) output += " << ";
if (this._lines.length > this._MFDMaxLines) {
if (this._selectedMsg < this._lines.length - 1) {
output += " >>";
}
}
output += "\n";
for (var i = start; i < this._lines.length; i++) {
if (this._selectedMsg === i) {
output += glyph + " ";
// only send an update to the console if the option is on and the request came from user input
if (this._outputToConsole === true && sendConsole === true) {
player.consoleMessage("Selected: " + this._lines[i].text);
}
}
output += this._lines[i].text + "\n";
}
} else {
output = "BROADCAST MESSAGE:";
}
// send output to MFD
p.setMultiFunctionText("BroadcastCommsMFD", output, false);
} else {
if (p.equipmentStatus("EQ_BROADCASTCOMMSMFD") == "EQUIPMENT_DAMAGED") {
p.setMultiFunctionText("BroadcastCommsMFD", "BROADCAST MESSAGE:\n\nDamaged!\nTransmission system offline", false);
}
}
}
//=============================================================================================================
// transmit selected message
this.$transmit = function () {
var p = player.ship;
var msg = "";
var id = "";
var transmission = "";
var params = {};
// only allow a transmit if we're not currently waiting for a response to another message
if (this._delay == null || this._delay.isRunning === false) {
// do we have a selected message?
if (this._selectedMsg >= 0 && this._selectedMsg < this._lines.length && this._lines[this._selectedMsg] != null) {
id = this._lines[this._selectedMsg].id;
msg = this._lines[this._selectedMsg].text;
// perform tranmission
switch (id) {
case "core_1": //"Is anyone heading to somewhere?"
this.$sendBroadcastMessage("Is anyone heading to " + System.systemNameForID(this._holdTarget) + "?");
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToRequestForWormhole, this._defaultResponseWait, 0);
break;
case "core_2": //"Send distress message":
this.$sendBroadcastMessage(this.$getRandomItemDescription("transmit-help"));
p.broadcastDistressMessage();
break;
case "core_3": //"Send greeting to target":
if (this.$checkTarget() === false) return;
this._source = p.target;
transmission = this.$getCustomTransmission(this._source, 3);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-greeting-" + this._targetType);
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToGreeting.bind(this, this._source, this._targetType), this._defaultResponseWait, 0);
break;
case "core_4": //"Send taunt to target":
if (this.$checkTarget() === false) return;
this._source = p.target;
transmission = this.$getCustomTransmission(this._source, 4);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-taunt-" + this._targetType);
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToTaunt.bind(this, this._source, this._targetType), this._defaultResponseWait, 0);
// add this target to the greeted array - illogical to say Hi after a taunt
this.$addShipToArray(this._source, this._greeted);
// update the MFD straight away, because we might do this in yellow alert status
this.$buildMessageList();
break;
case "core_5": //"Issue threat to target":
if (this.$checkTarget() === false) return;
this._source = p.target;
transmission = this.$getCustomTransmission(this._source, 5);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-threat-" + this._targetType);
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToThreat, this._defaultResponseWait, 0);
// add this target to the greeted array - illogical to say Hi after a threat
this.$addShipToArray(this._source, this._greeted);
break;
case "core_6": //"Offer bribe to target":
if (msg.indexOf("nearest") === -1) {
if (this.$checkTarget() === false) return;
this._source = p.target;
var crType = "credits";
if (this._bribeAmount === 1) crType = "credit";
params = {amount: this._bribeAmount.toString(), credittype: crType};
transmission = this.$getCustomTransmission(this._source, 6, params);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-bribe", params);
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToBribe, this._defaultResponseWait, 0);
// add this target to the greeted array - illogical to say Hi after a bribe
this.$addShipToArray(this._source, this._greeted);
} else {
this._source = this.$findNearestAttacker();
if (this.$itemIsInArray(this._source, this._bribed) === false) {
// add this target to the greeted array - illogical to say Hi after a bribe
this.$addShipToArray(this._source, this._greeted);
this.$workOutCurrentBribeAmount(this._source);
if (this._bribeAmount < player.credits) {
params = {amount: this._bribeAmount.toString(), credittype: crType};
transmission = this.$getCustomTransmission(this._source, 6, params);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-bribe", params);
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToBribe, this._defaultResponseWait, 0);
} else {
// we shouldn't ever get here, because once you reach beyond your credit balance you are automatically
// added to the bribed array, but still. Just in case.
player.consoleMessage("Insufficient credits to offer");
}
} else {
player.consoleMessage("Closest ship has already been bribed");
}
}
break;
case "core_7": //"Demand cargo":
if (this.$checkTarget() === false) return;
this._source = p.target;
var tons = this._demandCargo.toString() + ((this._demandCargo === 1) ? " ton" : " tons");
params = {"tons": tons};
transmission = this.$getCustomTransmission(this._source, 7, params);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-piracy", params);
this.$sendMessageToTarget(transmission);
this._waitingForPiracyResponse = true;
if (this._targetType === "npc" || this._targetType === "pirate") {
if (this._debug === true) log(this.name, "ship '" + this._source.displayName + "' might be responding");
if (this._source.AIScript.oolite_priorityai) {
if (this._debug === true) log(this.name, "ai found!");
var hold = this._source.target;
this._source.AIScript.oolite_intership.cargodemand = this._demandCargo;
this._source.target = p;
this._source.performAttack();
this._source.AIScript.oolite_priorityai.reconsiderNow();
// de-target the player so any red-alert is removed
this._source.target = hold;
} else {
if (this._debug === true) log(this.name, "no priority AI found!");
}
}
// we can only demand once - after that, if you want cargo, use your lasers!
this.$addShipToArray(this._source, this._demanded);
this.$addShipToArray(this._source, this._greeted);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToDemandForCargo, this._defaultResponseWait, 0);
this.$buildMessageList();
break;
case "core_8": //"Surrender to target":
if (msg.indexOf("nearest") === -1) {
if (this.$checkTarget() === false) return;
this._source = p.target;
transmission = this.$getCustomTransmission(this._source, 8);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-surrender");
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToSurrender, this._defaultResponseWait, 0);
// add this target to the greeted array - illogical to say Hi after a surrender
this.$addShipToArray(this._source, this._greeted);
} else {
this._source = this.$findNearestAttacker();
if ((this._source && this._source.isPolice) || this.$itemIsInArray(this._source, this._surrenderedTo) === false) {
transmission = this.$getCustomTransmission(this._source, 8);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-surrender");
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToSurrender, this._defaultResponseWait, 0);
// add this target to the greeted array - illogical to say Hi after a surrender
this.$addShipToArray(this._source, this._greeted);
} else {
player.consoleMessage("Closest ship has already been surrendered to");
}
}
break;
case "core_9": //"Offer to rescue escape pod":
if (this.$checkTarget() === false) return;
this._source = p.target;
transmission = this.$getCustomTransmission(this._source, 9);
if (transmission == "") transmission = this.$getRandomItemDescription("transmit-escapepod");
this.$sendMessageToTarget(transmission);
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToEscapePodOffer, this._defaultResponseWait, 0);
break;
case "core_10": //"(Target last comms message)":
if (this._targetLastComms) {
// still in range?
var found = false;
var tlc = p.checkScanner(true);
for (var i = 0; i < tlc.length; i++) {
if (tlc[i] === this._targetLastComms) found = true;
}
if (found === false) {
player.consoleMessage("Unable to locate target");
} else {
p.target = this._targetLastComms;
}
}
this._targetLastComms = null;
this.$buildMessageList();
break;
case "core_11": //"Keep away from my target":
if (this.$checkTarget() === false) return;
this._source = p.target;
this.$sendBroadcastMessage(this.$getRandomItemDescription("transmit-keep-away-from-target"));
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToKeepAwayFromTarget, this._defaultResponseWait, 0);
break;
case "core_12": // request docking clearance
case "core_13": // withdraw docking request
if (this.$checkTarget() === false) return;
if (p.target.isStation && p.target.canDockShip(p)) {
if (this._dockingRequest === false) {
this._dockingRequest = true;
this.$sendBroadcastMessage(this.$getRandomItemDescription("request-docking-clearance"));
} else {
this.$sendBroadcastMessage(this.$getRandomItemDescription("withdraw-docking-request"));
this._dockingRequest = false;
}
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, this.$respondToDockingRequest, this._defaultResponseWait, 0);
this._targetStation = p.target;
} else {
player.consoleMessage("Current target is not station or cannot dock ship");
}
break;
default:
// this should be any external messages
var cMsg = {};
// find the message to call
for (var i = 0; i < this._externalMessages.length; i++) {
cMsg = this._externalMessages[i];
if (cMsg) {
if (cMsg.messageName === id) {
// we have a hit
// but only transmit the message if it doesn't start with bracket characters
if (msg.substring(0, 1) != "{" && msg.substring(0, 1) != "(" && msg.substring(0, 1) != "[" && msg.substring(0, 1) != "<") {
this.$sendMessageToTarget(expandDescription(cMsg.messageText));
}
if (this._delay && this._delay.isRunning) this._delay.stop();
this._delay = new Timer(this, cMsg.callbackFunction, cMsg.delayCallback, 0);
if (cMsg.deleteOnTransmit === true) {
this._externalMessages[i] = null;
this.$buildMessageList();
}
// break out of the loop once we've found a hit.
break;
}
}
}
break;
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$getCustomTransmission = function(ship, typeID, params) {
var msg = "";
var custom_defaults = {};
if (ship.scriptInfo.hasOwnProperty("bcc_custom_defaults")) {
custom_defaults = ship.scriptInfo.bcc_custom_defaults;
}
if (ship.script.hasOwnProperty("bcc_custom_defaults")) {
custom_defaults = ship.script.bcc_custom_defaults;
}
if (Object.keys(custom_defaults).length > 0) {
if (custom_defaults.hasOwnProperty(typeID) && custom_defaults[typeID].hasOwnProperty("transmit")) {
if (params) {
msg = expandDescription(custom_defaults[typeID].transmit, params);
} else {
msg = expandDescription(custom_defaults[typeID].transmit);
}
}
}
return msg;
}
//-------------------------------------------------------------------------------------------------------------
this.$getCustomReply = function(ship, typeID, customProperty, params) {
var msg = "";
var property = "reply";
if (customProperty && customProperty != "") property = customProperty;
var custom_defaults = {};
if (ship.scriptInfo.hasOwnProperty("bcc_custom_defaults")) {
custom_defaults = ship.scriptInfo.bcc_custom_defaults;
}
if (ship.script.hasOwnProperty("bcc_custom_defaults")) {
custom_defaults = ship.script.bcc_custom_defaults;
}
if (Object.keys(custom_defaults).length > 0) {
if (custom_defaults.hasOwnProperty(typeID) && custom_defaults[typeID].hasOwnProperty(property)) {
if (params) {
msg = expandDescription(custom_defaults[typeID][property], params);
} else {
msg = expandDescription(custom_defaults[typeID][property]);
}
}
}
return msg;
}
//-------------------------------------------------------------------------------------------------------------
// send message out to target
this.$sendMessageToTarget = function (msg) {
// second parameter causes function to either fail or happen invisibly
player.ship.commsMessage(msg); //player.ship.target
}
//-------------------------------------------------------------------------------------------------------------
// send message out to everyone
this.$sendBroadcastMessage = function (msg) {
player.ship.commsMessage(msg);
}
//-------------------------------------------------------------------------------------------------------------
// send message to player
this.$sendMessageToPlayer = function (source, msg) {
if (source.isValid === true) source.commsMessage(msg, player.ship);
}
//-------------------------------------------------------------------------------------------------------------
// checks that the player has a valid target
this.$checkTarget = function () {
if (player.ship.target == null) {
player.consoleMessage("Unable to locate target");
this.$buildMessageList();
return false;
} else {
return true;
}
}
//=============================================================================================================
// response routines
//=============================================================================================================
// wormhole request - 1
this.$respondToRequestForWormhole = function $respondToRequestForWormhole() {
// find all NPC ships in range who are about to go to destination
var npc = this.$findNPCShips();
var rsp = false;
npc.forEach(function (ship) {
// if the ships destination system is the same as the players, and a random chance passes, display a "come along" message
if (ship.destinationSystem === this._holdTarget && this.$rand(10) > 1) {
var respType = "std";
// there is a 70% chance a pirate will give an unfriendly response, and a 30% chance a trader will do it as well
if (((ship.hasRole("pirate") || ship.hasRole("assassin-light") || ship.hasRole("assassin-medium") || ship.hasRole("assassin-heavy")) && Math.random() > 0.3) || Math.random() > 0.7) {
respType = "unfriendly";
}
var reply = "";
reply = this.$getCustomReply(ship, 1, "reply_confirm");
if (reply == "") reply = this.$getRandomItemDescription("response-wormhole-" + respType);
this.$sendMessageToPlayer(ship, reply);
}
// if the ships destination system is not the players destination, but the ships destination is outbound, and a random chance passes, display a "I'm going somewhere else" message
if (ship.destinationSystem != this._holdTarget && ship.destinationSystem != global.system.ID && ship.hasRole("generationship") === false && this.$rand(10) > 2) {
if (ship.hasRole("pirate") || ship.hasRole("assassin-light") || ship.hasRole("assassin-medium") || ship.hasRole("assassin-heavy")) {
// unfriendly ships won't respond
return;
}
var reply = "";
var params = {systemname: System.systemNameForID(ship.destinationSystem)};
reply = this.$getCustomReply(ship, 1, "reply_decline", params);
if (reply == "") reply = this.$getRandomItemDescription("response-wormhole-decline", params);
this.$sendMessageToPlayer(ship, reply);
}
}, this);
}
//=============================================================================================================
// respond to comms message -- ???
this.$respondToCommsMessage = function $respondToCommsMessage () {
// is target hostile?
if (this._source.hasRole("generationship")) return;
if (this._source.hasRole("thargoid")) {
this.$sendMessageToPlayer(this._source, expandDescription("[thargoid_curses]"));
} else {
if (this._alertCond === 3) {
// is target actually targeting the player, or is the target part of a group that is targeting the player?
var friend = true;
if (this._source.target === player.ship) {
friend = false
} else {
if (this._source.group.ships && this._source.group.ships.length > 0) {
var ships = this._source.group.ships;
ships.forEach(function (ship) {
if (ship.target === player.ship) friend = false;
}, this);
}
}
if (friend === false) {
this.$sendMessageToPlayer(this._source, this.$getRandomItemDescription("response-comms-unfriendly"));
} else {
this.$sendMessageToPlayer(this._source, this.$getRandomItemDescription("response-comms-friendly"));
}
} else {
// is this ship under attack?
if (this.$countShipsTargetingNPC(this._source) > 0) {
this.$sendMessageToPlayer(this._source, this.$getRandomItemDescription("response-comms-friendly"));
} else {
this.$sendMessageToPlayer(this._source, this.$getRandomItemDescription("response-comms-nobattle"));
}
}
}
}
//=============================================================================================================
// escape pod - 9
this.$respondToEscapePodOffer = function $respondToEscapePodOffer() {
// did we shoot his ship down?
var podshipname = "";
if (this._escapepodShipNames.length > 0) {
for (var i = 0; i < this._escapepodShipNames.length; i++) {
if (this._escapepodShipNames[i].escapepod === this._source) podshipname = this._escapepodShipNames[i].shipname;
}
}
var reply = "";
if (podshipname != "" && this.$itemIsInArray(podshipname, this._killedNames) === true) {
reply = this.$getCustomReply(this._source, 9, "reply_unfriendly");
if (reply == "") reply = this.$getRandomItemDescription("response-escapepod-unfriendly");
this.$sendMessageToPlayer(this._source, reply);
} else {
reply = this.$getCustomReply(this._source, 9, "reply_friendly");
if (reply == "") reply = this.$getRandomItemDescription("response-escapepod-friendly");
this.$sendMessageToPlayer(this._source, reply);
}
this.$addShipToArray(this._source, this._scoopOffer);
// rebuild the messagelist (so that offer to scoop is removed)
this.$buildMessageList();
}
//=============================================================================================================
// keep away from target - 11
this.$respondToKeepAwayFromTarget = function $respondToKeepAwayFromTarget() {
var ships = checkScanner(true);
// look for any ships that are currently targeting the players target
ships.forEach(function (ship) {
if (ship.target === this._source) {
// is this ship friendly towards player
var friend = true;
if (ship.group.ships && ship.group.ships.length > 0) {
var shipgroup = ship.group.ships;
shipgroup.forEach(function (g_ship) {
if (g_ship.target === player.ship) friend = false;
}, this);
}
// only respond if ship is friendly
if (friend) {
ship.target = null;
ship.removeDefenseTarget(this._source);
var reply = this.$getCustomReply(this._source, 11);
if (reply == "") reply = this.$getRandomItemDescription("response-keep-away-from-target");
this.$sendMessageToPlayer(this._source, reply);
}
}
}, this);
}
//=============================================================================================================
// respond to "request docking clearance" - 12
this.$respondToDockingRequest = function $respondToDockingRequest() {
if (this._targetStation.isValid && this._targetStation.isStation && this._targetStation.canDockShip(player.ship)) {
if (this._dockingRequest === true) {
player.ship.requestDockingClearance(this._targetStation);
} else {
player.ship.cancelDockingRequest(this._targetStation);
}
this.$buildMessageList();
}
}
//=============================================================================================================
// greeting - 3
this.$respondToGreeting = function $respondToGreeting(ship, targetType) {
if (ship != null && ship.hasRole("generationship")) return;
// get one of predefined list of greetings and transmit
var rsp = 0; // 0 = no response, 1 = pick a response
if (this.$rand(10) > 2) rsp = 1;
// always give a response for thargoids
if (targetType === "thargoid") rsp = 1;
// todo: could this make the target friendlier towards the player?
// any changes to NPC behaviour will happen regardless of whether they have decided to send a response or not
if (rsp === 1 && ship != null && targetType != "" && ship.isPiloted) {
var reply = "";
reply = this.$getCustomReply(ship, 3);
if (reply == "") reply = this.$getRandomItemDescription("response-greeting-" + this._targetType);
this.$sendMessageToPlayer(ship, reply);
// add the target to the greeted list
this.$addShipToArray(ship, this._greeted);
// rebuild the messagelist (so that greeting is removed)
this.$buildMessageList();
}
}
//=============================================================================================================
// bribe - 6
this.$respondToBribe = function $respondToBribe() {
// there will always be a response to this message
// based on the amount of bribe, the chances of accepting grow steadily greater
// i.e. low chance of accepting with low amounts, greater chance with higher amounts
// initial chance of 2.5% of accepting (slightly higher chance of 12.5% when player is in the early game), increases as digits are added to bribe amount
var shiptype = "";
var chance = 0.025 + ((player.score < 100) ? 0.1 : 0.0) + (0.1 * (this._bribeAmount.toString().length - this._bribeInitial.toString().length))
// set the shiptype - initially the targeted shiptype
shiptype = this._targetType;
// however, if the closestAttacker is set, use that
if (this._closestAttackerType != "") shiptype = this._closestAttackerType;
if (shiptype === "police") {
// no chance of bribing a police vessel in the aegis
if (this._source.position.distanceTo(system.mainStation) < 51200) chance = 0;
// chance decreases based on system government level
if (chance > 0) {
chance -= system.info.government;
if (chance < 0) chance = 0;
}
}
if (this._debug === true) log(this.name, "chance of accepting bribe = " + chance.toString());
if (this._source != null && shiptype != "") {
var reply = "";
// if the pirates are demanding cargo, they might be susceptible to a bribe.
// if they're a bounty hunter, they probably want to kill the player, so they won't be
if (((shiptype === "police" || shiptype === "pirate") && this.$rand(50) > (50 * chance)) || shiptype === "hunter") {
// decline
if (this._debug === true) log(this.name, shiptype + " '" + this._source.displayName + "' rejected bribe of " + this._bribeAmount.toString());
// after a few bribes, the police will eventually fine the player
if (shiptype === "police") {
if (this._bribeAmount > 5 && Math.random() < 0.5) {
player.ship.setBounty(player.ship.bounty + this.$rand(20), "attempted bribe");
this.$addShipToBribedArray(this._source);
this._bribeAmount = this._bribeInitial;
reply = this.$getCustomReply(this._source, 6, "reply_fine");
if (reply == "") reply = this.$getRandomItemDescription("response-bribe-police-fine");
this.$sendMessageToPlayer(this._source, reply);
this.$buildMessageList();
return;
}
}
reply = this.$getCustomReply(this._source, 6, "reply_decline");
if (reply == "") reply = this.$getRandomItemDescription("response-bribe-decline-" + shiptype);
this.$sendMessageToPlayer(this._source, reply);
if (this._bribeAmount.toString().substring(0, 1) === "2") {
// use 2.5 when then current amount starts with "2", so from 200 we end up on 500, from 2000 to 5000, 20000 to 50000 etc
this._bribeAmount *= 2.5;
} else {
// otherwise use the default multiple of 2, so we go from 100 to 200, 500 to 1000 etc
this._bribeAmount *= 2;
}
if (this._bribeAmount > player.credits) {
// can't be bribed
// add them to the bribed list so they can't be offered a bribe and reset bribe amount
this.$addShipToBribedArray(this._source);
this._bribeAmount = this._bribeInitial;
} else {
// update the current bribe array with the new bribe amount
// if the player detargets the ship and retargets them, the same amount will then be shown
this.$updateShipInCurrentBribeArray(this._source, true);
}
this.$buildMessageList();
} else {
// accept
if (this._debug === true) log(this.name, shiptype + " '" + this._source.displayName + "' accepted bribe of " + this._bribeAmount.toString());
reply = this.$getCustomReply(this._source, 6, "reply_accept");
if (reply == "") reply = this.$getRandomItemDescription("response-bribe-accept-" + (shiptype === "police" ? "police" : "npc"));
this.$sendMessageToPlayer(this._source, reply);
player.credits -= this._bribeAmount;
// detarget the player from the group
if (this._source.group != "") {
this.$removePlayerTargetFromPirateGroup(this._source);
} else {
if (this._debug === true) log(this.name, "player de-targeted from ship " + this._source.displayName);
this._source.target = null;
}
// add the ship(s) to the bribed array so we don't offer that option again
this.$addShipToBribedArray(this._source);
this._bribeAmount = this._bribeInitial;
this.$buildMessageList();
}
}
}
//-------------------------------------------------------------------------------------------------------------
// add a ship (or a group of ships) to the bribeCurrent array
this.$updateShipInCurrentBribeArray = function (ship, recursive) {
// keep track of what we've offered different ships
if (this._bribeCurrent != null && this._bribeCurrent.length > 0) {
var found = false;
for (var i = 0; i < this._bribeCurrent.length; i++) {
if (this._bribeCurrent[i].ship === ship) {
this._bribeCurrent[i].amount = this._bribeAmount;
found = true;
}
}
if (found === false) {
this._bribeCurrent.push({
ship: ship,
amount: this._bribeAmount
});
}
} else {
this._bribeCurrent.push({
ship: ship,
amount: this._bribeAmount
});
}
// add in all the pirates in the group, so we can't keep trying to bribe individual members
if (recursive === true) {
if (ship.group == null || ship.group === "") {
// single
// do nothing
} else {
// group
var shipGroup = ship.group.ships;
shipGroup.forEach(function (groupship) {
this.$updateShipInCurrentBribeArray(groupship, false);
}, this);
}
}
}
//-------------------------------------------------------------------------------------------------------------
// adds a ship (or a group of ships) to the bribed array
this.$addShipToBribedArray = function (ship) {
if (ship.group == null || ship.group === "") {
// single
this.$addShipToArray(ship, this._bribed);
} else {
// group
var shipgroup = ship.group.ships;
shipgroup.forEach(function (groupship) {
this.$addShipToArray(groupship, this._bribed);
}, this);
}
}
//=============================================================================================================
// taunt - 4
this.$respondToTaunt = function $respondToTaunt(ship, targetType) {
if (ship != null && ship.hasRole("generationship")) return;
var reply = "";
// get one of predefined list of taunts and transmit
var rsp = 0; // 0 = no response, 1 = pick a response
// hight chance of a response
if (this.$rand(10) > 2) rsp = 1;
// always give a response for thargoids
if (targetType === "thargoid") rsp = 1;
var p = player;
// any changes to NPC behaviour will happen regardless of whether they have decided to send a response or not
// todo: could this make the target angrier towards the player?
// possibilities: for enemy: briefly makes their accuracy drop
// briefly makes their accuracy increase
if (ship != null && ship.target === p.ship && this._alertCond === 3 && targetType != "" && targetType != "thargoid") {
if (this._debug === true) log(this.name, "we'll probably be changing the accuracy now...");
// settings to configure randomness
var chanceOfChange = 0.5; // likelihood of change as decimal, where 0.5 = 50%, .75 = 75%, etc
var maxChange = 3; // maximum amount of change to accuracy
// this npc is targeting the player
// decide if this taunt is going to have an impact
if (this.$rand(50) >= (50 * chanceOfChange)) {
if (this._debug === true) log(this.name, "yep - changing");
// decide how much better/worse their accuracy will be, either 1, 2 or 3 points
var diff = this.$rand(maxChange);
// decide if the npc will get become more or less accurate, although more likely it will be less accurate
// 33% chance of more accurate, 66% chance of less accurate
if (this.$rand(3) > 1) diff *= -1; // less accurate
// add the ship to the accuracyChanged array
this.$addShipToAccuracyList(ship, diff, this._tauntAccuracyLength);
}
}
// if the players target is not targeting the player, then potentially switch their target to the player
// this could be used to draw someone's fire away from another ship
if (ship != null && ship.target != p.ship && targetType != "") {
var chance = 45;
// adjust the chance by player score - the higher the score the less likely they will attack
// elite ranking
if (p.score >= 32 && p.score < 64) chance -= 5; // average
if (p.score >= 64 && p.score < 128) chance -= 10; // above average
if (p.score >= 128 && p.score < 512) chance -= 15; // competant
if (p.score >= 512 && p.score < 2560) chance -= 20; // dangerous
if (p.score >= 2560 && p.score < 6400) chance -= 25; // deadly
if (p.score >= 6400) chance -= 30; // elite
this.$willPlayerTargetTurnOnPlayer(chance);
}
// for nonenemy: make them more likely to start firing at you
// send out the response
if (rsp === 1 && ship != null && ship.isPiloted) {
reply = this.$getCustomReply(ship, 4);
if (reply == "") reply = this.$getRandomItemDescription("response-taunt-" + targetType);
this.$sendMessageToPlayer(ship, reply);
}
}
//=============================================================================================================
// piracy (demand for cargo) - 7
this.$respondToDemandForCargo = function $respondToDemandForCargo() {
if (this._source != null && this._source.hasRole("generationship")) return;
// only need to send a response if the ships refuses to comply
if (this._source != null && this._targetType != "" && this._piracyWorked === false) {
var reply = this.$getCustomReply(this._source, 7, "reply_refuse");
if (reply == "") reply = this.$getRandomItemDescription("response-piracy-" + this._targetType);
this.$sendMessageToPlayer(this._source, reply);
// rebuild the messagelist (so that greeting is removed)
this._waitingForPiracyResponse = false;
this.$buildMessageList();
}
this._piracyWorked === false;
}
//=============================================================================================================
// surrender - 8
this.$respondToSurrender = function $respondToSurrender() {
// todo: has pirate asked for cargo?
//note: real check will be 48
if (this._debug === true) log(this.name, "responding to surrender");
var reply = "";
// pirate have a chance of accepting the surrender, police will always accept it
if (this._source != null && (this._source.isPolice || this.$rand(50) > 45)) {
// remove the player as the primary target from any NPC's targeting the player
if (this._source.isPolice === false) {
this._surrenderCurrent_Pirate = [];
var isGroup = false;
if (this._source.group && this._source.group != "") {
isGroup = true;
var group = this._source.group.ships;
group.forEach(function (ship) {
this.$addShipToArray(ship, this._surrenderedTo);
this.$addShipToArray(ship, this._surrenderCurrent_Pirate);
}, this);
} else {
this.$addShipToArray(this._source, this._surrenderedTo);
this.$addShipToArray(this._source, this._surrenderCurrent_Pirate);
}
this.$buildMessageList();
if (this._debug === true) log(this.name, "pirates accepted surrender");
if (this._source.group != "") {
this.$removePlayerTargetFromPirateGroup(this._source);
} else {
this._source.target = null;
}
if (!this._surrenderTimer_Pirate || this._surrenderTimer_Pirate.isRunning === false) {
this._surrenderTimer_Pirate = new Timer(this, this.$surrenderCheckState_Pirate, this._surrenderWait, 0);
}
this._surrenderCheck_Pirate = true;
// reply should be "Hurry up and dump some cargo, scum"
var pnCap = "We";
var pnLw = "we";
if (isGroup === false) {
pnCap = "I";
pnLw = "I";
}
reply = this.$getCustomReply(this._source, 8, "reply_impatient");
if (reply == "") reply = this.$getRandomItemDescription("response-surrender-pirate", {pronouncap: pnCap, pronoun: pnLw});
this.$sendMessageToPlayer(this._source, reply);
} else {
// police surrender
// only if bounty is less than 50 ie offender status only. Fugitive will not be allowed to surrender
if (player.bounty < 50) {
if (player.bounty > 30 && Math.random() < 0.5) {
if (this._debug === true) log(this.name, "police ignored surrender request from player with high bounty (50% chance)");
return; // no response - player can try sending another surrender
}
reply = this.$getCustomReply(this._source, 8, "reply_police_accept");
if (reply == "") reply = this.$getRandomItemDescription("response-surrender-police");
this.$sendMessageToPlayer(this._source, reply);
this.$addShipToArray(this._source, this._surrenderedTo); // add the police ship that responded to list that player can't surrender to again (we also use this to identify who should send rejection if the player doesn't comply)
this._surrenderCheck_Police = true; // a separate variable is needed because the timer keeps running and we want to know if the player surrenders again to new police after gaining additional bounty
if (this._surrenderPoliceChances === 0) this._surrenderPoliceChances = 5; // number of timer updates to tolerate non-compliance (but no extra chances if they send multiple surrender messages)
// start a timer, if it's not already started
if (!this._surrenderTimer_Police || this._surrenderTimer_Police.isRunning === false) {
this._surrenderTimer_Police = new Timer(this, this.$surrenderCheckState_Police, this._surrenderWait_Police, this._surrenderWait_Police); // repeats until stopped
}
} else {
reply = this.$getCustomReply(this._source, 8, "reply_police_reject");
if (reply == "") reply = this.$getRandomItemDescription("response-deny-surrender-police");
this.$sendMessageToPlayer(this._source, reply); // fugitive rejection
}
}
} else {
if (this._debug === true) log(this.name, "declined");
if (this._source.isThargoid) {
this.$sendMessageToPlayer(this._source, expandDescription("[thargoid_curses]"));
}
}
}
//-------------------------------------------------------------------------------------------------------------
// check that the player has surrendered to the pirate
// if we get here, it means the player hasn't dumped cargo (which would stop the timer)
this.$surrenderCheckState_Pirate = function $surrenderCheckState_Pirate() {
this._surrenderCheck_Pirate = false;
var scp = this._surrenderCurrent_Pirate;
if (scp != null && scp.length > 0) {
for (var i = 0; i < scp.length; i++) {
// retarget the player
if (scp[i] && scp[i].isValid === true) {
scp[i].target = player.ship;
if (this._debug === true) log(this.name, "player re-targeted on ship " + scp[i].displayName + " in group " + scp[i].group);
// send message, from random members of the group, or from the single pirate otherwise
if (scp[i].isVisible === true && ((scp[i].group == null || scp[i].group === "") || this.$rand(20) > 10)) {
// send a message from the group
this.$sendMessageToPlayer(scp[0], this.$getRandomItemDescription("response-break-surrender-pirate"));
}
scp[i].performAttack();
}
}
}
// clear the array
this._surrenderCurrent_Pirate = [];
}
//-------------------------------------------------------------------------------------------------------------
// check that the player has surrendered to the police
// player has to disable their weapons system ("_" key)
/*this.$surrenderCheckState_Police = function $surrenderCheckState_Police() {
var law = this.$findLawVessels(player.ship);
var sent = false;
// if the player hasn't turned their weapons off transmit message
if (player.ship.weaponsOnline) {
if (this._debug === true) log(this.name, "Police rejected surrender");
// send a message from the group
if (law.length > 0) {
for (var i = 0; i < law.length; i++) {
if (law[i].isStation === false && law[i].target != player.ship) {
if (sent === false) {
this.$sendMessageToPlayer(law[i], this.$getRandomItemDescription("response-break-surrender-police"));
sent = true;
}
}
}
}
} else {
if (this._debug === true) log(this.name, "Police accepted surrender");
for (var i = 0; i < law.length; i++) {
if (law[i].isStation === false && law[i].target === player.ship) {
this.$addShipToArray(law[i], this._surrenderedTo);
if (sent === false) {
this.$sendMessageToPlayer(law[i], this.$getRandomItemDescription("response-accept-surrender-police"));
sent = true;
// mark the player for fines
if (player.bounty > 0) {
law[i].markTargetForFines();
}
}
law[i].target = null;
if (this._debug === true) log(this.name, law[i].displayName + " de-targeting player");
}
}
}
}*/
//-------------------------------------------------------------------------------------------------------------
// check if the player is complying with instructions after surrendering to police, and make police stop hostilities if they do
// player has to disable their weapons system ("_" key) initially but can switch them on again after surrender is accepted
// player has to approach the main station without deviating more than 50km (player can take all day to travel the distance, but must not go somewhere else)
// this timer will continue running until the player is declared non-compliant, or docks and pays their fine, or jumps out of the system
this.$surrenderCheckState_Police = function $surrenderCheckState_Police() {
var that = $surrenderCheckState_Police; // pointer to this function
var bountysystem = (that.bountysystem = that.bountysystem || worldScripts.BountySystem_Core); // cache worldScript reference in a local property on this function
var p = player.ship,
ms = system.mainStation;
var dist = (ms && ms.isValid) ? p.position.distanceTo(ms) : 0; // player current distance to main station
var hasSurrendered = this._surrenderMainStationDist !== 0, // this._surrenderMainStationDist > 0 implies surrender was accepted and we are tracking their progress
isThreat = p.weaponsOnline && this._surrenderCheck_Police, // we require weapons off when a surrender request is pending, after surrender is accepted they can be re-enabled
isFar = dist > this._surrenderMainStationDist + 50000, // after surrendering, did distance from main station increase by more than 50km since the last time seen by police?
isFugitive = player.bounty > 50; // gained after surrender, otherwise the surrender would be rejected immediately
// begin nearby police/main-station loop
var law = this.$findLawVessels(p);
for (var i = 0; i < law.length; i++) {
// is the player seen?
if (law[i].hasHostileTarget && law[i].target !== p) {
continue; // skip any police that are occupied with fights against someone other than the player
} else if (dist < this._surrenderMainStationDist) { // for players that have surrendered, if they are near any police that aren't too busy to notice, update distance tracking
this._surrenderMainStationDist = dist; // this is the closest the player has been to the main station since they surrendered (to be used in the next timer update)
}
// check compliance
if (isFugitive) { // player became a fugitive after surrendering earlier and police nearby aren't too busy to notice
hasSurrendered = false; // police AI will handle comms to fugitives...
break; // fall through to restore hidden bounty and stop timer
} else if (!isThreat && !isFar) { // player is compliant (handle this case first so later checks can assume non-compliance)
// check if player has a pending surrender request
if (this._surrenderCheck_Police) {
if (hasSurrendered === false && law[i].target == p) { // must be targeting the player because markTargetForFines uses the ship's target
law[i].markTargetForFines(); // flag player to be fined when they dock at the main station
this._surrenderMainStationDist = dist; // begin tracking player distance to station (and make hasSurrendered true for the next timer update)
hasSurrendered = true; // make it true for the current timer update to skip bounty restoration code after the loop
}
if (hasSurrendered) { // things to do once each time the player surrenders (not just the first time)
this.$sendMessageToPlayer(law[i], this.$getRandomItemDescription("response-accept-surrender-police")); // police ships or main station can send this message
if (this._debug === true) log(this.name, "Police accepted surrender");
// hide most of the player's current bounty (police attack offenders with bounty above a threshold, which is lower in higher-government systems)
if (player.bounty > 0) {
this._surrenderBounty += player.bounty - 1; // add current bounty to hidden bounty (player may gain additional bounty after surrender and surrender to a different group of police)
if (bountysystem) bountysystem._changing = true; // tell Bounty System OXP to ignore the bounty change we are about to do (so it doesn't clear local offences)
player.bounty = 1; // leave a token 1 cr visible bounty so player is offender but police won't attack (bounty hunters probably won't either, but who knows?)
if (bountysystem) bountysystem._changing = false; // tell Bounty System OXP to pay attention to bounty changes again
}
// so if the player gets a new bounty on the way to the station, they can try to surrender again to police they encounter, stopping hostilities
// but if they go off course and are seen by police, their hidden bounty will be restored (code below) and the police probably will attack them
var nearbyShips = p.checkScanner(true); // poweredOnly : true (includes stations) - note this only returns up to 32 results even if more are in scanner range
for (var k = 0; k < nearbyShips.length; k++) // inner loop to record surrender and stop hostilities with all nearby clean-legal-status ships/stations that are hostile to the player
{
if (nearbyShips[k].bounty === 0 && nearbyShips[k].target === p && nearbyShips[k].hasHostileTarget) { // nearby ship or station that is hostile and targeting player (stations also have bounty === 0 usually)
this.$addShipToArray(nearbyShips[k], this._surrenderedTo); // make sure player can't surrender to them again
nearbyShips[k].target = null; // de-target the player so they stop attacking and their AI can find something else to do
nearbyShips[k].removeDefenseTarget(p); // reduce likelihood of re-acquiring the player as a target if ships are in combat with someone else
if (nearbyShips[k].AIScript && nearbyShips[k].AIScript.oolite_priorityai.getParameter("oolite_distressAggressor") === p)
nearbyShips[k].AIScript.oolite_priorityai.setParameter("oolite_distressAggressor",null); // clear a recent distress call made against the player
if (this._debug === true) log(this.name, nearbyShips[k].displayName + " de-targeting player");
}
}
break; // fall through to clear this._surrenderCheck_Police (using break as a do-once, but we have to do it inside the hasSurrendered check in case the first surrender needs to keep looking for police targeting the player)
}
} else { // this._surrenderCheck_Police === false
return; // the player hasn't sent another surrender again, and is compliant, so we don't need to do anything else until the next timer update
}
continue; // if execution reaches this line, this._surrenderCheck_Police === true but hasSurrendered === false && law[i].target !== p so we are still looking for a law[i].target === p
} else if (law[i].isStation === false) { // player is non-compliant (implied by previous check), and stations don't interact with non-compliant players, so we are a nearby police ship
if (isThreat && this._surrenderPoliceChances--) { // player has not yet disabled weapons (pre-surrender) and we haven't exhausted our patience yet
this.$sendMessageToPlayer(law[i], this.$getRandomItemDescription("response-surrender-police")); // one police sends another instructions message
return; // take no further action until the next timer update (using return as a do-once and to skip the code that clears this._surrenderCheck_Police after the loop)
} else { // either isThreat with no chances left, or isFar (going off course doesn't receive any tolerance (or warning), but the player may be able to surrender to a new group of police)
hasSurrendered = false; // make sure this is set before the break in the block below so we restore their hidden bounty even if we don't send a message
if (this.$itemIsInArray(law[i], this._surrenderedTo)) { // only police that witnessed the original surrender can send a message
this.$sendMessageToPlayer(law[i], this.$getRandomItemDescription("response-break-surrender-police"));
if (this._debug === true) log(this.name, "Police rejected surrender");
break; // only send one message
}
// fall through to restore hidden bounty and stop timer
// the police AI probably will attack them and send its own messages, since they were attacked by police before (why else did the player surrender?)
}
}
}
// end nearby police/main-station loop
if (hasSurrendered === false) { // surrender was rejected because the player didn't disable weapons in time, or has been broken because player went off course or became a fugitive after surrender was accepted
this._surrenderMainStationDist = 0; // reset distance tracking for future surrender attempts (would have to be addressed to other police than the ones to which the player originally surrendered)
if (this._surrenderBounty > 0) { // player has a hidden bounty
if (bountysystem) bountysystem._changing = true; // tell Bounty System OXP to ignore the bounty change we are about to do (so it doesn't get recorded as a new offence)
player.bounty += this._surrenderBounty; // make hidden bounty visible again (add it to current bounty in case the player gained additional bounty meanwhile)
if (bountysystem) bountysystem._changing = false; // tell Bounty System OXP to pay attention to bounty changes again
this._surrenderBounty = 0; // clear hidden bounty
}
this._surrenderTimer_Police.stop();
} else { // hasSurrendered is true
this._surrenderCheck_Police = false; // any pending request has been handled (we use return to bypass this when needed)
}
}
//=============================================================================================================
// threat - 5
this.$respondToThreat = function $respondToThreat() {
if (this._source != null && this._source.hasRole("generationship")) return;
// get one of a predefined list of threats and transmit
var rsp = 0; // 0 = no response, 1 = pick a response
if (this.$rand(10) > 2) rsp = 1;
// always give a response for thargoids
if (this._targetType === "thargoid") rsp = 1;
var p = player;
var altResponse = 0; // whether we're using the alternate responses because the npc is fleeing (0 = normal, 1 = fleeing)
// for thargoid - no change in behaviour
// any changes to NPC behaviour will happen regardless of whether they have decided to send a response or not
// for police -- make it an offence
if (this._source != null && this._targetType != "" && this._targetType === "police") {
// threatening police results in a fine
player.bounty += 1;
this._source.target = player.ship;
this._source.markTargetForFines();
}
// for npc/pirate/hunter - small chance of enemy giving up if player kill count is high and/or player status is offender or greater
// if npc decides to flee, get different message
// check: target is still there, they're not thargoids or police, and they are targeting the ship
if (this._source != null && this._targetType != "" && this._targetType != "thargoid" && this._targetType != "police" && this._source.target === p.ship) {
var chance = 0.0; // starting chance is 0% ie. no chance the target will flee
// weight up the chances of this enemy fleeing
// 1. how many ships are targeting the player? If lots, then less likely to flee
// if >= 5, no change
var shipcount = this.$countShipsTargetingPlayer();
// if there are lots of ships targeting the player this function could make our value go negative, which we'll check for later
if (shipcount < 5) chance += (0.3 - (shipcount * 0.05));
// 2. how strong is the player
// based on status (fugitive = higher chance, offender = not so high, clean = not high at all)
if (p.bounty > 0 && p.bounty <= 50) chance += 0.1; // offender status
if (p.bounty > 50) chance += 0.2; // fugitive status
// elite ranking
if (p.score >= 32 && p.score < 64) chance += 0.05; // average
if (p.score >= 64 && p.score < 128) chance += 0.1; // above average
if (p.score >= 128 && p.score < 512) chance += 0.15; // competant
if (p.score >= 512 && p.score < 2560) chance += 0.2; // dangerous
if (p.score >= 2560 && p.score < 6400) chance += 0.25; // deadly
if (p.score >= 6400) chance += 0.3; // elite
// threat assessment levels
if (this._source.threatAssessment() < p.ship.threatAssessment()) chance += 0.1;
// 3. how many other ships are targeting it
var shipcount = this.$countShipsTargetingPlayerTarget();
if (shipcount > 2) chance += (shipcount * 0.05);
// make sure we're positive
if (chance < 0) chance = 0.0;
// not greater than a 50% chance
if (chance > 0.5) chance = 0.5
if (this._debug === true) log(this.name, "final chance percentage = " + chance.toString());
// will the ship flee?
if (this.$rand(70) < (50 * chance)) {
if (this._debug === true) log(this.name, "ship '" + this._source.displayName + "' is fleeing");
// force a response for a fleeing ship
rsp = 1;
// change response type to fleeing
altResponse = 1;
// remove the player as a target
this._source.target = null;
// make ship flee
this._source.performFlee();
}
} else if (this._source != null && this._targetType != "" && this._targetType != "police" && this._source.target != p.ship) {
// check: target is still there, they're not thargoids or police, and they are *not* targeting the ship
// basically, if the other ship is not targeting the player, make them do so now
var chance = 35;
// adjust the chance by player score - the higher the score the less likely they will attack
// elite ranking
if (p.score >= 32 && p.score < 64) chance -= 5; // average
if (p.score >= 64 && p.score < 128) chance -= 10; // above average
if (p.score >= 128 && p.score < 512) chance -= 15; // competant
if (p.score >= 512 && p.score < 2560) chance -= 20; // dangerous
if (p.score >= 2560 && p.score < 6400) chance -= 25; // deadly
if (p.score >= 6400) chance -= 30; // elite
this.$willPlayerTargetTurnOnPlayer(chance);
// force a response
rsp = 1;
}
if (rsp === 1 && this._source != null && this._targetType != "" && this._source.isPiloted) {
// get a standard "I'm not scared of you" threat response
var reply = this.$getCustomReply(this._source, 5, (altResponse == 0 ? "reply_normal" : "reply_fleeing"));
if (reply == "") reply = this.$getRandomItemDescription("response-threat-" + this._targetType + "-" + altResponse.toString());
this.$sendMessageToPlayer(this._source, reply);
// rebuild the messagelist (so that greeting is removed)
this.$buildMessageList();
}
}
//-------------------------------------------------------------------------------------------------------------
// handles the response of an NPC to piracy, where they have decided to dob the player in
this.$sendPiracyNPCResponse = function $sendPiracyNPCResponse() {
// only send the response if the victim is still valid and is visible to player
if (this._piracyVictim.isValid === true && this._piracyVictim.isVisible === true) {
var listtype = "response-piracy-npc-police";
if (this._piracyPolice.isPolice === false) listtype = "response-piracy-npc-station";
this.$sendMessageToPlayer(this._piracyVictim, this.$getRandomItemDescription(listtype));
}
// if the victim has died before they get a chance to tell, don't send a response
if (this._piracyVictim.isValid === true) this._piracyPoliceTimer = new Timer(this, this.$sendPiracyPoliceResponse, 4, 0);
}
//-------------------------------------------------------------------------------------------------------------
// handles the response of a police vessel to an NPC's notification of the players piracy
this.$sendPiracyPoliceResponse = function $sendPiracyPoliceResponse() {
if (this._piracyPolice.isValid === true && this._piracyPolice.isVisible === true) {
this.$sendMessageToPlayer(this._piracyPolice, this.$getRandomItemDescription("response-piracy-police-npc"));
}
// if the police vessel has died before they get a chance to set the players bounty, don't change it.
if (this._piracyPolice.isValid === true) {
player.ship.setBounty(player.ship.bounty + this.$rand(10), "act of piracy");
if (this._debug === true) log(this.name, "player bounty now " + player.bounty.toString());
}
}
//=============================================================================================================
// helper functions
//-------------------------------------------------------------------------------------------------------------
this.$resetVariables = function () {
this._alertCond = player.alertCondition;
this._targetType = "";
this._closestAttackerType = "";
}
//-------------------------------------------------------------------------------------------------------------
this.$fullResetVariables = function () {
this._escapepodShipNames = [];
this._scoopOffer = [];
this._greeted = [];
this._bribed = [];
this._demanded = [];
this._bribeCurrent = [];
this._surrenderCurrent_Pirate = [];
this._surrenderedTo = [];
this._surrenderCheck_Pirate = false;
this._surrenderCheck_Police = false;
this._surrenderPoliceChances = 0;
this._surrenderMainStationDist = 0;
this._surrenderBounty = 0;
this._bribeAmount = this._bribeInitial;
this._piracyWorked = false;
this._waitingForPiracyResponse = false;
this._killedNames = [];
this._targetLastComms = null;
this.$resetVariables();
}
//-------------------------------------------------------------------------------------------------------------
// stop any timers we have running
this.$stopAllTimers = function () {
// stop the check timer
if (this._checkTimer && this._checkTimer.isRunning === true) this._checkTimer.stop();
if (this._piracyNPCTimer && this._piracyNPCTimer.isRunning === true) this._piracyNPCTimer.stop();
if (this._piracyPoliceTimer && this._piracyPoliceTimer.isRunning === true) this._piracyPoliceTimer.stop();
// stop the response message delay timer
if (this._delay && this._delay.isRunning === true) this._delay.stop();
// stop the surrender timer
if (this._surrenderTimer_Pirate && this._surrenderTimer_Pirate.isRunning === true) this._surrenderTimer_Pirate.stop();
if (this._surrenderTimer_Police && this._surrenderTimer_Police.isRunning === true) this._surrenderTimer_Police.stop();
// stop any accuracy changes
if (this._accuracyChanged && this._accuracyChanged.length > 0) {
for (var i = 0; i < this._accuracyChanged.length; i++) {
if (this._accuracyChanged[i].IsActive === true) this._accuracyChanged[i].StopChange();
}
}
// reset the arrays
this._accuracyChanged = [];
}
//-------------------------------------------------------------------------------------------------------------
// return a random number between 1 and max
this.$rand = function (max) {
return Math.floor((Math.random() * max) + 1)
}
//-------------------------------------------------------------------------------------------------------------
// adds a ship to an array, but only once
this.$addShipToArray = function (ship, array) {
var found = false;
if (array != null && array.length > 0) {
for (var i = 0; i < array.length; i++) {
if (array[i] === ship) {
found = true;
break;
}
}
}
if (found === false) array.push(ship);
}
//-------------------------------------------------------------------------------------------------------------
// returns a description item
this.$getRandomItemDescription = function (listitem, dict) {
// we need to distinguish hunters from pirates in the above code, but in the transmissions and responses they're the same thing
var listname = "[" + listitem.replace("-hunter", "-pirate") + this._msgAlt + "]";
// fail safe, incase there's a
if (listname.indexOf("-]") >= 0) {
listname = listname.replace("-" + this._msgAlt + "]", "-npc" + this._msgAlt + "]");
}
if (dict) {
var item = expandDescription(listname, dict);
} else {
var item = expandDescription(listname);
}
return item;
}
//-------------------------------------------------------------------------------------------------------------
// find all npc ships in range
this.$findNPCShips = function () {
function _isNPC(entity) {
return entity.isShip && !(entity.isPlayer) && !(entity.isMissile) && !(entity.isBeacon) && !(entity.isBoulder) && !(entity.isCargo) && !(entity.isRock) && !(entity.isWeapon) && !(entity.isTurret);
}
return system.filteredEntities(this, _isNPC, player.ship, player.ship.scannerRange);
}
//-------------------------------------------------------------------------------------------------------------
// find all police or main stations in range of ship
this.$findLawVessels = function (npc) {
function _ships(entity) {
return entity.isShip && !(entity.isPlayer) && (entity.isPolice || (entity.isStation && entity.isMainStation));
}
return system.filteredEntities(this, _ships, npc, npc.scannerRange);
}
//-------------------------------------------------------------------------------------------------------------
// return the count of law vesses in range of ship
this.$countLawVessels = function (npc) {
var ships = this.$findLawVessels(npc);
this._piracyPolice = null;
ships.forEach(function (ship) {
// find the first police vessel in the list and set our piracy police variable to that one
if (ship.isPolice === true && this._piracyPolice == null) this._piracyPolice = ship;
}, this);
// if there was no police vessel in the list, it must be a main station, so set it instead
if (this._piracyPolice == null && ships.length > 0) this._piracyPolice = ships[0];
return ships.length;
}
//-------------------------------------------------------------------------------------------------------------
// find all npc ships in range that are targeting the player
this.$countShipsTargetingPlayer = function () {
function _isShipTargetingPlayer(entity) {
return entity.isShip && !(entity.isPlayer) && !(entity.isMissile) && !(entity.isBeacon) && !(entity.isBoulder) && !(entity.isCargo) && !(entity.isRock) && !(entity.isWeapon) && !(entity.isTurret) && entity.target === player.ship;
}
var ships = system.filteredEntities(this, _isShipTargetingPlayer, player.ship, player.ship.scannerRange);
return ships.length;
}
//-------------------------------------------------------------------------------------------------------------
// find all npc ships in range that are targeting the player
this.$countShipsTargetingNPC = function (npc) {
function _isShipTargetingNPC(entity) {
return entity.isShip && !(entity.isPlayer) && !(entity.isMissile) && !(entity.isBeacon) && !(entity.isBoulder) && !(entity.isCargo) && !(entity.isRock) && !(entity.isWeapon) && !(entity.isTurret) && entity.target === npc;
}
var ships = system.filteredEntities(this, _isShipTargetingNPC, npc, npc.scannerRange);
return ships.length;
}
//-------------------------------------------------------------------------------------------------------------
// find all npc ships in range that are targeting the player
this.$countShipsTargetingPlayerTarget = function () {
function _isShipTargetingTarget(entity) {
return entity.isShip && !(entity.isPlayer) && !(entity.isMissile) && !(entity.isBeacon) && !(entity.isBoulder) && !(entity.isCargo) && !(entity.isRock) && !(entity.isWeapon) && !(entity.isTurret) && entity.target === this._source;
}
var ships = system.filteredEntities(this, _isShipTargetingTarget, player.ship, player.ship.scannerRange);
return ships.length;
}
//-------------------------------------------------------------------------------------------------------------
// remove the player as the target of a pirate group
this.$removePlayerTargetFromPirateGroup = function (pirateship) {
if (pirateship.group) {
var ships = pirateship.group.ships;
ships.forEach(function (ship) {
if (this._debug === true) log(this.name, "player de-targeted from ship " + ship.displayName + " in group " + pirateship.group);
ship.target = null;
}, this);
} else {
pirateship.target = null;
}
}
//-------------------------------------------------------------------------------------------------------------
// adds a ship to the accuracy changes array and starts the process
this.$addShipToAccuracyList = function (ship, addvalue, seconds) {
//-------------------------------------------------------------------------------------------------------------
// internal class used for adjusting the accuracy of a ship for a given number of seconds
function AccuracyAdj(ship, addvalue, seconds) {
this.ship = ship;
this.oldvalue = ship.accuracy;
this.addvalue = CheckNewAccuracyLevel(this.oldvalue, addvalue);
this.seconds = seconds;
this.delay = null;
this.DoChange = function () {
if (this.addvalue != 0) {
if (worldScripts.BroadcastCommsMFD._debug === true)
log(this.name, "changing " + this.ship.displayName + " accuracy from " + this.oldvalue.toString() + " to " + (this.oldvalue + this.addvalue).toString());
this.ship.accuracy += this.addvalue;
this.delay = new Timer(this, this.RevertChange.bind(this), this.seconds, 0);
}
}
this.IsActive = function () {
if (this.delay && this.delay.isRunning) {
return true;
} else {
return false;
}
}
this.StopChange = function () {
this.delay.stop();
// reset the accuracy of the ship
if (this.ship && this.ship.isValid) {
this.ship.accuracy = this.oldvalue;
if (worldScripts.BroadcastCommsMFD._debug === true)
log(this.name, "reverting " + this.ship.displayName + " accuracy back to " + this.oldvalue.toString() + " from " + (this.oldvalue + this.addvalue).toString());
}
}
this.RevertChange = function RevertChange() {
if (this.ship && this.ship.isValid) {
this.ship.accuracy = this.oldvalue;
if (worldScripts.BroadcastCommsMFD._debug === true)
log(this.name, "reverting " + this.ship.displayName + " accuracy back to " + this.oldvalue.toString() + " from " + (this.oldvalue + this.addvalue).toString());
}
}
function CheckNewAccuracyLevel(curr, diff) {
var newvalue = diff;
if ((curr + diff) > 10 || (curr + diff) < -5) {
if (diff < 0) {
newvalue = -5 - curr;
} else {
newvalue = 10 - curr;
}
}
return newvalue;
}
}
var item = -1;
// first, make sure we aren't already adjusting a ship's accuracy
if (this._accuracyChanged != null && this._accuracyChanged.length > 0) {
for (var i = 0; i < this._accuracyChanged.length; i++) {
if (this._accuracyChanged[i] && this._accuracyChanged[i].ship === ship) {
item = i;
break;
}
}
}
// if we found an item, check to see if it's running.
if (item != -1) {
if (this._accuracyChanged[item].IsActive === false) {
// not running, so remove it and add it as a new item
this._accuracyChanged[item] = null;
item = -1;
}
// if it is running, don't make any changes.
}
if (item === -1) {
// not found, so add the ship
var newItem = new AccuracyAdj(ship, addvalue, seconds);
newItem.DoChange();
this._accuracyChanged.push(newItem);
}
}
//-------------------------------------------------------------------------------------------------------------
// check timer essentially looks to see if our target tas become invalid (by going through a wormhole)
// for some reason the "shipTargetLost" is not firing in this scenario
this.$checkForTargetInvalid = function $checkForTargetInvalid() {
var p = player.ship;
var found = false;
if (this._targetType != "" && (!(p.target) || p.isValid === false)) {
this._targetType = "";
found = true;
this.$startTargetTimer();
}
if (found === true) this.$buildMessageList();
}
//-------------------------------------------------------------------------------------------------------------
// determines if the players target will turn on the player
// used by the taunt and threat functions
this.$willPlayerTargetTurnOnPlayer = function (checkAmount) {
if (this._debug === true) log(this.name, "Chance target will turn on player = " + checkAmount.toString());
if (player.ship.target && player.ship.target.target != player.ship && this.$rand(50) > checkAmount) {
player.ship.target.target = player.ship;
if (this._debug === true) log(this.name, "target " + player.ship.target + " is now targeting player");
}
}
//-------------------------------------------------------------------------------------------------------------
// sets the current bribe amount to the amount set for a particular ship
this.$workOutCurrentBribeAmount = function (ship) {
if (this._bribeCurrent != null && this._bribeCurrent.length > 0) {
for (var i = 0; i < this._bribeCurrent.length; i++) {
if (this._bribeCurrent[i].ship === ship) this._bribeAmount = this._bribeCurrent[i].amount;
}
}
}
//-------------------------------------------------------------------------------------------------------------
// finds and returns the nearest ship targeting the player. If none found, returns null
this.$findNearestAttacker = function () {
var ships = player.ship.checkScanner(true);
var min = player.ship.scannerRange;
var calc = 0;
var selected = null;
for (var i = 0; i < ships.length; i++) {
if (ships[i].target === player.ship) {
calc = player.ship.position.distanceTo(ships[i]);
if (calc < min) {
min = calc;
selected = ships[i];
}
}
}
if (selected != null) {
this._closestAttackerType = "npc";
if (selected.hasRole("police") === true) this._closestAttackerType = "police";
if (selected.hasRole("thargoid") === true) this._closestAttackerType = "thargoid";
if (selected.hasRole("hunter") === true) this._closestAttackerType = "hunter";
if (selected.hasRole("pirate") === true) this._closestAttackerType = "pirate";
}
return selected;
}
//-------------------------------------------------------------------------------------------------------------
// returns the player's target system (1.80) or the next jump to their target system (1.82)
this.$playerTargetSystem = function () {
if (player.ship.hasOwnProperty("nextSystem")) return player.ship.nextSystem;
var target = player.ship.targetSystem;
if (oolite.compareVersion("1.81") < 0 && player.ship.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY") === true) {
// in 1.81 or greater, the target system could be more than 7 ly away. It becomes, essentially, the final destination.
// there could be multiple interim stop points between the current system and the target system.
// the only way to get this info is to recreate a route using the same logic as entered on the ANA, and pick item 1
// from the list. That should be the next destination in the list.
if (system.ID === -1) {
var myRoute = System.infoForSystem(galaxyNumber, this._lastSource).routeToSystem(System.infoForSystem(galaxyNumber, target), player.ship.routeMode);
} else {
var myRoute = System.infoForSystem(galaxyNumber, system.ID).routeToSystem(System.infoForSystem(galaxyNumber, target), player.ship.routeMode);
}
if (myRoute && myRoute.route.length >= 1) {
target = myRoute.route[1];
}
} else {
if (target >= 0 && system.info.distanceToSystem(System.infoForSystem(galaxyNumber, target)) > 7) target = -1;
}
return target;
}
//-------------------------------------------------------------------------------------------------------------
this.$itemIsInArray = function (element, array) {
var found = false;
if (array != null && array.length > 0) {
for (var i = 0; i < array.length; i++) {
if (array[i] === element) found = true;
}
}
return found;
}
|