Scripts/bountysystem_mostwanted.js |
"use strict";
this.name = "BountySystem_MostWanted";
this.author = "phkb";
this.copyright = "2017 phkb";
this.description = "Routines for controlling the creation and movement of GalCop's most wanted.";
this.licence = "CC BY-NC-SA 4.0";
/*
There will probably be a lot of edge cases (where timing would indicate ship should be present but it isn't, or it is present but it shouldn't be)
There's a lot of fuzzy logic in determining when to add a ship, to make it actually possible to lie in wait for a ship
More info/options may be required on bounty screen to assist in waiting
Idea:
Snoopers news items about whereabouts of wanted pilots (News flash - Bill Smells was spotted in the Lave system on date...etc)
Have a random message be sent from ships arriving at WP along the lines of ("Did you see that ship in X? That's Y'd ship!")
Add additional methods of tracking bounties (bribing officials, planting tracking devices)
Have ships heading off on search for specialty items, then have notice that "X is searching for Y."
TODO:
if ship has been created (jumped in), and time jump occurs (eg player ejects) - remove them
!! what happens if mark jumps in, then player docks and saves game? mark needs to be insta-docked on reload
!! add a script to reset escape pod occupants bounty to normal levels (otherwise player could get paid twice)
!! test process of waiting outside station for bounty if SDC is not installed
need to make sure all bounties will fight rather than just run away (paricularly for traders)
make tipsters move around chart, and only let them tip if a bounty is within 15LY
If no SDC, what happens to escorts that aren't able to dock before the mother ship relaunches?
need to check for undocked escorts when mother is relaunched. if found, cancel docking instructions and offer to escort mother
If a target is attacked by the player and manages to escape, plot a random path for escape, then return them to the closest
system in a normal plot (ie spacelane, milkrun etc)
-- this should be handled by standard AI routines
How easy/hard is it to track a target?
Work out what happens if target goes through worm hole
investigate what would happen if target is docked in sdc, player jumps out and back again, before target has launched.
ship won't be pending, so need to update record to reflect it
add player to most wanted list if bounty is over 250
need better AI for target ships, to make them flee if they're scanned, or if there are a lot of police/hunters around
This might be OK, because AI is already getting tweaked by the accuracy setting
might be worth investigating how to add hiddenBountyFlee methods to the AI
Wanted list item definition:
index record index
system their current system
dockTime the time they docked at "system"
currentVisible indicates their current "system" value is visible (ie they docked at the main station)
shipName the name of their ship
shipType the type of their ship
shipDataKey the datakey of their ship
personality the personality of their ship
primaryRole their primary role
bounty their interstellar bounty
escorts the number of escorts following the pilot
escortData
escortShipKey the ship keys for each of the escorts
escortShipName the ship names for each of the escorts
escortPersonality the entityPersonalities for each of the escorts
escortPilotName the names of each of the pilots
escortBounty the amount of bounty for each escort
escortHiddenBounty
destinationSystem their next destination system
pilotDescription pilot info
pilotName ..
pilotHomeSystem ..
pilotLegalStatus ..
pilotInsurance ..
pilotSpecies ..
equipment
departureTime
lastChange
updateChance
movement code to describe how the ship will move (eg, along spacelane, on milk run, etc)
1 = milk run
2 = spacelane
3 = safe/dangerous
4 = custom path - used to move ships from one location to another, and for couriers
*/
this._disabled = false;
this._debug = false; // controls output of debug messages
this._milkRuns = []; // list of milk runs in the current sector
this._spacelanes = []; // list of spacelanes in the current sector
this._safeDangerous = []; // list of safe/dangerous systems (array of dictionarys, having "id"-int and "dangerous"-array of ints)
this._courierRoutes = []; // list of cross-chart systems couriers are likely to be on
// array has two elements (0, 1) 0 = top left to bottom right, 1 = bottom left to top right
// each element has a dictionary with two keys (point1 and point2)
// the value of these keys is an array of system ID's.
this._customPath = []; // list of custom paths currently in play
this._wanted = []; // full list of wanted pilots (accurate, updated every day)
this._pending = []; // array of ship records that may or may not be created/launched in the current system
this._displayList = []; // list of pilots for display (subset, only updated every 5 days)
this._missionList = []; // array of indexes of most wanted records to show on the manifest screen
this._completed = []; // list of criminals destroyed by player for whom they can claim a receipt for
this._lastUpdate = 0; // time of last update of the displaylist
this._refreshDays = 3; // how often to update the list (default 3)
this._constantUpdates = true;
this._randomShips = []; // array of ship roles, types and data keys
this._licencePurchaseDate = 0; // date hunter licence was purchased
this._menuColor = "orangeColor";
this._exitColor = "yellowColor";
this._holdConcealment = [];
this._unconcealmentActive = false;
this._rsnInstalled = false; // indicates whether randomshipnames OXP is installed
this._sdcInstalled = false; // indicates whether Station Dock Control OXP is installed
this._populateCounter = 30; // counter used to control when the updateMovementData routine is called
// set to 30 so that the routine is called on the first repopulate event (about 20 seconds after startup)
this._timeRange = 7200; // time differential (in seconds) for which ship will be considered for adding to a system (3600 = 1 hour)
this._checkOnArrival = []; // array of ships to check for on arrival in a new system
// this is to cater for the times when a target jumps out, their wormhole closes, then the player
// jumps to the same system and the core game retains the original ship
this._doLicenceRemoval = false; // indicates when the player's bounty hunter licence will be removed
this._renewalDockMessage = false; // indicates when a licence renewal message has been added to dock reports
this._hunterTips = []; // array of current hunter tips
this._hunterTipSources = []; // array of tip sources (name, reliability)
this._controlledRoles = [
"trader", "trader-courier", "trader-smuggler",
"pirate", "pirate-light-freighter", "pirate-medium-freighter", "pirate-heavy-freighter",
"pirate-light-fighter", "pirate-medium-fighter", "pirate-heavy-fighter",
"hunter", "hunter-medium", "hunter-heavy", "assassin-light", "assassin-medium", "assassin-heavy",
"escort", "escort-medium", "escort-heavy"
];
// ships with these keys will not be used for any MW ship
this._bountyShipKeyExclusions = ["convoys-adder","convoys-anaconda","convoys-anaconda2","convoys-anaconda3","convoys-anaconda-admiral",
"convoys-anaconda-pirate","convoys-asp","convoys-asp-pirate","convoys-boa","convoys-boa-pirate","convoys-boa-mk2","convoys-boa-mk2-pirate",
"convoys-cobra3","convoys-cobra3-pirate","convoys-ferdelance","convoys-ferdelance-pirate","convoys-gecko-pirate","convoys-krait",
"convoys-krait-pirate","convoys-mamba","convoys-moray","convoys-moray-pirate","convoys-moray-morayMED","convoys-python","convoys-python-team",
"convoys-python-pirate","convoys-python-blackdog","convoys-shuttle","convoys-transporter","convoys-transporter-miner","convoys-worm",
"convoys-worm-miner","freighterconvoys-anaconda","freighterconvoys-anaconda2","freighterconvoys-anaconda3","freighterconvoys-anaconda4",
"freighterconvoys-boa","freighterconvoys-boa-mk2","freighterconvoys-cobra3","freighterconvoys-moray","freighterconvoys-morayMED",
"freighterconvoys-python","freighterconvoys-python-team","freighterconvoys-python-trader","freighterconvoys-shuttle","freighterconvoys-shuttle2",
"freighterconvoys-transporter","freighterconvoys-transporter-miner","freighterconvoys-worm","freighterconvoys-worm-miner","freighterconvoys-miner"
];
//-------------------------------------------------------------------------------------------------------------
this.startUp = function() {
if (this._disabled === true) {
if (missionVariables.BountySystem_Wanted) delete missionVariables.BountySystem_Wanted;
if (missionVariables.BountySystem_LastUpdate) delete missionVariables.BountySystem_LastUpdate;
if (missionVariables.BountySystem_Pending) delete missionVariables.BountySystem_Pending;
if (missionVariables.BountySystem_DisplayList) delete missionVariables.BountySystem_DisplayList;
if (missionVariables.BountySystem_Completed) delete missionVariables.BountySystem_Completed;
if (missionVariables.BountySystem_Tips) delete missionVariables.BountySystem_Tips;
if (missionVariables.BountySystem_MissionList) delete missionVariables.BountySystem_MissionList;
delete this.startUpComplete;
delete this.systemWillPopulate;
delete this.systemWillRepopulate;
delete this.playerWillSaveGame;
delete this.playerEnteredNewGalaxy;
delete this.playerBoughtEquipment;
delete this.playerBoughtNewShip;
delete this.shipLaunchedFromStation;
delete this.shipWillDockWithStation;
delete this.shipDockedWithStation;
delete this.shipExitedWitchspace;
delete this.dayChanged;
delete this.missionScreenEnded;
delete this.missionScreenOpportunity;
delete this.guiScreenWillChange;
delete this.reportScreenEnded;
delete this.startUp;
return;
}
if (this._debug) this._refreshDays = 0;
// load up list of wanted people
if (missionVariables.BountySystem_Wanted) {
this._wanted = JSON.parse(missionVariables.BountySystem_Wanted);
delete missionVariables.BountySystem_Wanted;
for (var i = 0; i < this._wanted.length; i++) {
var wanted = this._wanted[i];
if (wanted.routeMode === "OPTIMIZED_FOR_JUMPS") wanted.routeMode = "OPTIMIZED_BY_JUMPS";
if (wanted.routeMode === "OPTIMIZED_FOR_TIME") wanted.routeMode = "OPTIMIZED_BY_TIME";
// add any missing shipname data
if (wanted.shipName === "") wanted.shipName = this.$getRandomShipName(wanted.primaryRole);
for (var j = 0; j < wanted.escortData.length; j++) {
if (wanted.escortData[j].shipName === "") wanted.escortData[j].shipName = this.$getRandomShipName(wanted.escortsRole);
}
}
}
if (missionVariables.BountySystem_DisplayList) {
this._displayList = JSON.parse(missionVariables.BountySystem_DisplayList);
delete missionVariables.BountySystem_DisplayList;
}
if (missionVariables.BountySystem_LastUpdate) this._lastUpdate = missionVariables.BountySystem_LastUpdate;
if (missionVariables.BountySystem_Pending) {
this._pending = JSON.parse(missionVariables.BountySystem_Pending);
delete missionVariables.BountySystem_Pending;
// add time property if missing
if (this._pending.length > 0) {
for (var i = 0; i < this._pending.length; i++) {
if (this._pending[i].hasOwnProperty("time") === false) {
var dta = JSON.parse(this._pending[i].data);
this._pending[i].time = dta.departureTime;
}
}
}
}
if (missionVariables.BountySystem_CustomPath) {
this._customPath = JSON.parse(missionVariables.BountySystem_CustomPath);
delete missionVariables.BountySystem_CustomPath;
}
if (missionVariables.BountySystem_MissionList) {
this._missionList = JSON.parse(missionVariables.BountySystem_MissionList);
delete missionVariables.BountySystem_MissionList;
}
if (missionVariables.BountySystem_Completed) {
this._completed = JSON.parse(missionVariables.BountySystem_Completed);
delete missionVariables.BountySystem_Completed;
}
if (missionVariables.BountySystem_LicencePurchased) {
this._licencePurchaseDate = missionVariables.BountySystem_LicencePurchased;
}
if (this._licencePurchaseDate === 0 && player.ship.equipmentStatus("EQ_HUNTER_LICENCE") === "EQUIPMENT_OK") {
this._licencePurchaseDate = clock.adjustedSeconds;
}
if (missionVariables.BountySystem_TipSources) {
this._hunterTipSources = JSON.parse(missionVariables.BountySystem_TipSources);
delete missionVariables.BountySystem_Wanted;
}
}
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function() {
if (worldScripts["randomshipnames"]) this._rsnInstalled = true;
if (worldScripts.StationDockControl) {
this._sdcInstalled = true;
worldScripts.StationDockControl._propertiesToKeep.push("_mostWanted");
}
this.$loadShipNames();
this.$getSpacelanes();
this.$getMilkRuns();
this.$calculateSafeDangerousSystems();
this.$calculateCourierRoutes();
this.$lookForPendingRecords();
if (this._hunterTipSources.length === 0) this.$createTipSources();
if (missionVariables.BountySystem_Tips) {
this._hunterTips = JSON.parse(missionVariables.BountySystem_Tips);
delete missionVariables.BountySystem_Tips;
}
// if we don't have any records yet, create some data
if (this._wanted.length === 0) this.$initialiseData();
if (this._hunterTips.length === 0) this.$createTips(false);
//if (this._debug) this.$testData();
// if we have data but no display list, update that as well.
if (this._displayList.length === 0) {
this.$updateDisplayList();
}
this.$customPathCleanup();
}
//-------------------------------------------------------------------------------------------------------------
this.systemWillPopulate = function() {
this._loadShipData = true;
}
//-------------------------------------------------------------------------------------------------------------
this.systemWillRepopulate = function() {
if (this._loadShipData === true) {
this._loadShipData = false;
this.$loadShipNames();
}
// if we have pending ships in the queue, try processing them
if (this._pending.length > 0) this.$processPendingShips();
// count the number of times we hit the repopulate function (every 20 seconds or so)
// after 10 minutes update movement data
this._populateCounter += 1;
if (this._populateCounter >= 30) { // every ten minutes
this._populateCounter = 0;
this.$updateMovementData();
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function() {
missionVariables.BountySystem_Wanted = JSON.stringify(this._wanted);
missionVariables.BountySystem_LastUpdate = this._lastUpdate;
missionVariables.BountySystem_LicencePurchased = this._licencePurchaseDate;
delete missionVariables.BountySystem_Pending;
delete missionVariables.BountySystem_DisplayList;
delete missionVariables.BountySystem_CustomPath;
delete missionVariables.BountySystem_MissionList;
delete missionVariables.BountySystem_Completed;
delete missionVariables.BountySystem_TipSources;
delete missionVariables.BountySystem_Tips;
if (this._pending.length > 0) missionVariables.BountySystem_Pending = JSON.stringify(this._pending);
if (this._displayList.length > 0) missionVariables.BountySystem_DisplayList = JSON.stringify(this._displayList);
if (this._customPath.length > 0) missionVariables.BountySystem_CustomPath = JSON.stringify(this._customPath);
if (this._missionList.length > 0) missionVariables.BountySystem_MissionList = JSON.stringify(this._missionList);
if (this._completed.length > 0) missionVariables.BountySystem_Completed = JSON.stringify(this._completed);
if (this._hunterTipSources.length > 0) missionVariables.BountySystem_TipSources = JSON.stringify(this._hunterTipSources);
if (this._hunterTips.length > 0) missionVariables.BountySystem_Tips = JSON.stringify(this._hunterTips);
}
//-------------------------------------------------------------------------------------------------------------
// large time jumps can occur here...
this.shipWillDockWithStation = function(station) {
this.$updateMovementData();
}
//-------------------------------------------------------------------------------------------------------------
// ...and here
this.playerBoughtEquipment = function(equipment) {
this.$updateMovementData();
if (equipment === "EQ_HUNTER_LICENCE_RENEWAL") {
player.ship.removeEquipment(equipment);
player.ship.awardEquipment("EQ_HUNTER_LICENCE");
this._licencePurchaseDate = clock.adjustedSeconds;
}
if (equipment === "EQ_HUNTER_LICENCE") {
this._licencePurchaseDate = clock.adjustedSeconds;
}
}
//-------------------------------------------------------------------------------------------------------------
// ...and here
this.playerBoughtNewShip = function(ship) {
this.$updateMovementData();
}
//-------------------------------------------------------------------------------------------------------------
// ...and here
this.reportScreenEnded = this.missionScreenEnded = function() {
this.$updateMovementData();
}
//-------------------------------------------------------------------------------------------------------------
this.playerEnteredNewGalaxy = function(galaxyNumber) {
this.$getSpacelanes();
this.$getMilkRuns();
this.$calculateSafeDangerousSystems();
// at the moment the only realistic thing to do is to reset our data array when entering a new galaxy
this._wanted.length = 0;
this._displayList.length = 0;
this._hunterTips.length = 0;
this._hunterTipSources.length = 0;
this._customPath.length = 0;
this.$createTipSources();
this._lastUpdate = 0;
this.$initialiseData();
this.$updateDisplayList();
}
//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation = function(station) {
if (missionVariables.BountySystem_Wanted) delete missionVariables.BountySystem_Wanted;
if (missionVariables.BountySystem_Pending) delete missionVariables.BountySystem_Pending;
if (missionVariables.BountySystem_DisplayList) delete missionVariables.BountySystem_DisplayList;
}
//-------------------------------------------------------------------------------------------------------------
this.shipDockedWithStation = function(station) {
// if the player has a bounty, and this is a galcop station, and the government/techlevel is reasonably high, and the player has a BH licence
if (player.bounty > 0 && station.allegiance === "galcop" && system.government > 4 && system.techLevel > 9 && player.ship.equipmentStatus("EQ_HUNTER_LICENCE") === "EQUIPMENT_OK") {
// remove it
this._doLicenceRemoval = true;
}
this._renewalDockMessage = false;
}
//-------------------------------------------------------------------------------------------------------------
this.shipExitedWitchspace = function() {
// reset the pending flag
for (var i = 0; i < this._wanted.length; i++) {
if (this._wanted[i].pending === true) this._wanted[i].pending = false;
}
this._pending.length = 0;
// check for any ships that might have been jumping into this system which we've created already
// any that are already here we'll set to "pending" so they will be ignored by the updateMovementData routine
this.$checkArrivalList();
// check for any updated ship movements
this.$updateMovementData();
}
//-------------------------------------------------------------------------------------------------------------
this.dayChanged = function(newday) {
this.$updateMovementData();
// possibly add a new item
if (Math.random() > 0.9 && this._wanted.length < 30) this.$initialiseData(1);
// possibly remove one (simulating a criminal being caught by someone else in the galaxy)
if (Math.random() > 0.96 && this._wanted.length > 10) this.$removeItem();
// will we be doing an update of the display list?
if (this._constantUpdates === false && (clock.adjustedSeconds - this._lastUpdate) / 86400 >= this._refreshDays) this.$updateDisplayList();
var lic_exp = (clock.adjustedSeconds - this._licencePurchaseDate) / 86400;
if (lic_exp >= 25 && lic_exp < 30 && player.ship.equipmentStatus("EQ_HUNTER_LICENCE") === "EQUIPMENT_OK") {
if (player.ship.docked === false && this._renewalDockMessage === false) {
// add docking message (if in space)
player.addMessageToArrivalReport(expandDescription("[licence-renewal-docknotice]"));
this._renewalDockMessage = true;
} else {
// add console message (if docked)
player.consoleMessage(expandDescription("[licence-renewal-docknotice]"));
}
}
if (lic_exp >= 30 && player.ship.equipmentStatus("EQ_HUNTER_LICENCE") === "EQUIPMENT_OK") {
player.ship.removeEquipment("EQ_HUNTER_LICENCE");
// send email (if installed)
var w = worldScripts.EmailSystem;
if (w) {
var ga = worldScripts.GalCopAdminServices;
w.$createEmail({sender:"GalCop Security Office",
subject:"Bounty Hunter Licence Expiration Notice",
date:global.clock.adjustedSeconds,
message:expandDescription("[licence-expired]"),
expiryDays:ga._defaultExpiryDays
});
}
if (player.ship.docked === false) {
// add docking message (if in space)
player.addMessageToArrivalReport(expandDescription("[licence-expiry-docknotice]"));
} else {
// add console message (if docked)
player.consoleMessage(expandDescription("[licence-expiry-docknotice]"));
}
}
this.$createTips();
}
//-------------------------------------------------------------------------------------------------------------
this.missionScreenOpportunity = function() {
if (this._doLicenceRemoval === true) {
this._doLicenceRemoval = false;
player.ship.removeEquipment("EQ_HUNTER_LICENCE");
this._licencePurchaseDate = 0;
mission.runScreen({
screenID:"oolite-bountysystem-licence-map",
title: "Licence Revoked",
overlay: {name:"mw-warning.png", height:546},
message: expandDescription("[licence-revoked]"),
exitScreen: "GUI_SCREEN_STATUS"
});
}
}
//-------------------------------------------------------------------------------------------------------------
this.guiScreenWillChange = function(to, from) {
// force the manifest entries to update
// this keeps the "number of hours remaining" value up to date.
if (to === "GUI_SCREEN_MANIFEST") {
this.$updateManifest();
}
}
//-------------------------------------------------------------------------------------------------------------
this.$updateMovementData = function $updateMovementData() {
// note: do not execute this function from the startUpComplete or startUp events.
// some station naming occurs during these events, meaning that the displayName of stations could change,
// rendering any newly created pending records unusable.
this.$revealMap();
var type99found = false;
// run a check on everyone in the list
for (var i = 0; i < this._wanted.length; i++) {
var wanted = this._wanted[i];
// sometimes increase their bounty
if (Math.random() > 0.96) {
wanted.realBounty += (Math.floor(Math.random() * 30)) + (Math.random() > 0.7 ? (Math.floor(Math.random() * 30)) + (Math.random() > 0.95 ? (Math.floor(Math.random() * 30)) : 0): 0);
}
if (wanted.pending === false) {
if (this._debug) log(this.name, "checking " + wanted.pilotName + " for movement");
var active = false;
var nova = false;
var info = System.infoForSystem(galaxyNumber, wanted.system);
var info2 = System.infoForSystem(galaxyNumber, wanted.destinationSystem);
var rt = info.routeToSystem(info2, wanted.routeMode);
if (!rt) {
log(this.name, "!ERROR: No route calculated for wanted character movement: G" + (galaxyNumber + 1) + " - " + wanted.system + " to " + wanted.destinationSystem);
}
// make a note if either the source or destination are nova systems
// we'll prevent any display of ships going to or coming from these systems
if (info.sun_gone_nova || info2.sun_gone_nova) nova = true;
// check if any are noted as being in system
if (nova === false && wanted.system === system.ID) {
// if so, is their departure time still in the future?
if (this._debug) log(this.name, "dock checking: check 1 " + (clock.adjustedSeconds < wanted.departureTime) + ", check 2 " + (clock.adjustedSeconds >= wanted.dockTime));
if (clock.adjustedSeconds < wanted.departureTime && clock.adjustedSeconds >= wanted.dockTime) {
// if so, they are docked somewhere in the system - the player can lie in wait outside stations
active = true;
var stn = this.$getDockedStation(wanted);
// sdc - check for existing record
this._pending.push({type:"docked", chance:0, station:stn.displayName, index:wanted.index, shipKey:wanted.shipDataKey, time:wanted.departureTime, data:JSON.stringify(wanted)});
if (stn.isMainStation) {
if (wanted.lastVisibleSystem != -1) this.$cycleHistory(wanted);
wanted.updated = (wanted.departureTime > clock.adjustedSeconds ? clock.adjustedSeconds : wanted.departureTime);
wanted.lastVisibleSystem = wanted.system;
wanted.lastVisibleDestination = wanted.destinationSystem;
}
if (this._debug) {
log(this.name, "!!NOTE: Setting " + wanted.pilotName + " to be docked at a station " + stn.displayName);
log(this.name, "current time " + clock.clockStringForTime(clock.adjustedSeconds));
log(this.name, "departure " + clock.clockStringForTime(wanted.departureTime));
log(this.name, "docked " + clock.clockStringForTime(wanted.dockTime));
}
wanted.pending = true;
} else {
// if their departure time is in the past, the player missed them.
// continue with normal update process
}
}
// check if any are noted as coming to this system
if (nova === false && wanted.destinationSystem === system.ID) {
var arrival = wanted.departureTime + (rt.time * 3600);
var diff = (arrival - clock.adjustedSeconds);
if (this._debug) log(this.name, "arrival checking: arrival " + arrival + ", diff " + diff + ", rt.time " + rt.time + ", rt.route.length " + rt.route.length);
// if so, is their arrival within -1.5/+1.5 hours of current time?
if (diff >= (-3600 * 1.5) && diff < (3600 * 1.5)) {
// if so, they are due to arrive soon - set up for their arrival
active = true;
this._pending.push({type:"witchpoint", chance:0, station:"", index:wanted.index, shipKey:wanted.shipDataKey, time:arrival + (this._timeRange * 4), data:JSON.stringify(wanted)});
if (this._debug) {
log(this.name, "!!NOTE: Setting " + wanted.pilotName + " to be created at the witchpoint");
log(this.name, "current time " + clock.clockStringForTime(clock.adjustedSeconds));
log(this.name, "departure " + clock.clockStringForTime(wanted.departureTime));
log(this.name, "route time " + rt.time + " hrs");
log(this.name, "arrival " + clock.clockStringForTime(arrival));
}
wanted.pending = true;
} else if (diff < (-3600 * 4)) {
// if not, they got there ahead of the player, and they're ahead by at least 4 hours, then dock them somewhere in system
active = true;
var stn = this.$getDockedStation(wanted);
this._pending.push({type:"docked", chance:0, station:stn.displayName, index:wanted.index, shipKey:wanted.shipDataKey, time:arrival + (this._timeRange * 4), data:JSON.stringify(wanted)});
if (stn.isMainStation) {
if (wanted.lastVisibleSystem != -1) this.$cycleHistory(wanted);
wanted.updated = (wanted.departureTime > clock.adjustedSeconds ? clock.adjustedSeconds : wanted.departureTime);
wanted.lastVisibleSystem = wanted.system;
wanted.lastVisibleDestination = wanted.destinationSystem;
}
if (this._debug) {
log(this.name, "!!NOTE: Setting " + wanted.pilotName + " to be docked at a station " + stn.displayName);
log(this.name, "current time " + clock.adjustedSeconds);
log(this.name, "departure " + wanted.departureTime);
log(this.name, "route time " + rt.time + " hrs");
log(this.name, "arrival " + clock.clockStringForTime(arrival));
}
wanted.dockTime = arrival;
wanted.departureTime = arrival + (this._timeRange * 4);
wanted.pending = true;
}
}
// for all others, run a process of updating records where the departure time is now in the past
if (active === false && rt && (wanted.departureTime + (rt.time * 3600)) < clock.adjustedSeconds) {
// i've wrapped the movement code in a do/while loop, because there is a chance the movement type will change
// during the process, and we want to ensure all ships have been moved along their new courses correctly
do {
switch (wanted.movement) {
case 1: // milk run
// keep swapping the ship between the destinations until their departure time is in the future
do {
// TODO: chance that ship will either (a) switch to a new milk run, or (b) switch to a spacelane
if (this._debug) log(this.name, "Moving " + wanted.pilotName + " from " + wanted.system + " to " + wanted.destinationSystem);
wanted.dockTime = wanted.departureTime + (rt.time * 3600) + Math.floor(Math.random() * 1800) + 1800;
wanted.departureTime = wanted.dockTime + (Math.random() * 21600 + 21600);
var hold = wanted.destinationSystem;
wanted.destinationSystem = wanted.system;
if (nova === false && Math.random() > wanted.updateChance && wanted.dockTime < clock.adjustedSeconds) {
if (this._debug) log(this.name, "updating last visible system to " + wanted.system);
if (wanted.lastVisibleSystem != -1) this.$cycleHistory(wanted);
wanted.lastVisibleSystem = wanted.system;
wanted.lastVisibleDestination = wanted.destinationSystem;
wanted.updated = (wanted.departureTime < clock.adjustedSeconds ? wanted.departureTime : wanted.dockTime);
}
} while (wanted.departureTime < clock.adjustedSeconds);
break;
case 2: // spacelane
// TODO: chance that ship will either (a) switch to a new lane, or (b) switch to a milk run
var sl = this._spacelanes[wanted.arrayIndex];
do {
if (this._debug) log(this.name, "Moving " + wanted.pilotName + " from " + wanted.system + " to " + wanted.destinationSystem);
var idx1 = sl.indexOf(wanted.system);
var idx2 = sl.indexOf(wanted.destinationSystem);
// some planets are in lanes twice.
if (Math.abs(idx1 - idx2) !== 1) {
// this must be a lane with multiple entries of the same system.
if (idx1 !== sl.lastIndexOf(wanted.system)) idx1 = sl.lastIndexOf(wanted.system);
if (idx2 !== sl.lastIndexOf(wanted.destinationSystem)) idx2 = sl.lastIndexOf(wanted.destinationSystem);
// note: this won't handle the scenario where a system is in the list 3 times, but there aren't any atm
}
wanted.system = wanted.destinationSystem;
if (idx1 > idx2) {
var idx3 = idx2 - 1;
if (idx2 === 0) idx3 = 1;
}
if (idx1 < idx2) {
var idx3 = idx2 + 1;
if (idx2 === (sl.length - 1)) idx3 = idx2 - 1;
}
// theoretically idx1 should never equal idx2
wanted.destinationSystem = sl[idx3];
wanted.dockTime = wanted.departureTime + (rt.time * 3600) + Math.floor(Math.random() * 1800) + 1800;
wanted.departureTime = wanted.dockTime + (Math.random() * 21600 + 21600);
// recalculate the route for the next interation
info = System.infoForSystem(galaxyNumber, wanted.system);
info2 = System.infoForSystem(galaxyNumber, wanted.destinationSystem);
rt = info.routeToSystem(info2, wanted.routeMode);
if (nova === false && Math.random() > wanted.updateChance && wanted.dockTime < clock.adjustedSeconds) {
if (this._debug) log(this.name, "updating last visible system to " + wanted.system);
if (wanted.lastVisibleSystem != -1) this.$cycleHistory(wanted);
wanted.lastVisibleSystem = wanted.system;
wanted.lastVisibleDestination = wanted.destinationSystem;
wanted.updated = (wanted.departureTime < clock.adjustedSeconds ? wanted.departureTime : wanted.dockTime);
}
} while (wanted.departureTime < clock.adjustedSeconds);
break;
case 3: // safe/dangerous pair
var sd = this._safeDangerous[wanted.arrayIndex];
// only do something if we found a pair
if (sd) {
do {
if (this._debug) log(this.name, "Moving " + wanted.pilotName + " from " + wanted.system + " to " + wanted.destinationSystem);
wanted.system = wanted.destinationSystem;
if (wanted.destinationSystem === sd.id) {
//pick a dangerous system from list
wanted.destinationSystem = sd.dangerous[Math.floor(Math.random() * sd.dangerous.length)];
} else {
if (Math.random() > 0.98) {
// plot a path to another safe/dangerous combination
var check = 0;
var dest = null;
do {
dest = this._safeDangerous[Math.floor(Math.random() * this._safeDangerous.length)];
// make sure this is a new destination, not our current one
if (dest.id !== sd.id) {
// how far is this
var newrt = System.infoForSystem(galaxyNumber, wanted.destinationSystem).routeToSystem(System.infoForSystem(galaxyNumber, dest.id));
if (!newrt || newrt.distance > 30) {
dest = null;
}
} else {
dest = null;
}
check += 1;
} while (dest == null || check < 5);
if (dest) {
if (this._debug) log(this.name, "Moving to new destination at system " + dest.id);
// lock this in as the new custom path
var check = this.$createCustomPath(wanted.destinationSystem, dest.id, wanted.routeMode);
if (check !== -1) {
// select the first destination on the list
wanted.arrayIndex = check;
wanted.destinationSystem = this._customPath[wanted.arrayIndex][1];
wanted.movement = 4;
} else {
// invalid route, so revert back to original
wanted.destinationSystem = sd.id;
}
}
} else {
wanted.destinationSystem = sd.id;
}
}
wanted.dockTime = wanted.departureTime + (rt.time * 3600) + Math.floor(Math.random() * 1800) + 1800;
wanted.departureTime = wanted.dockTime + (Math.random() * 21600 + 21600);
if (nova === false && Math.random() > wanted.updateChance && wanted.dockTime < clock.adjustedSeconds) {
if (this._debug) log(this.name, "updating last visible system to " + wanted.system);
if (wanted.lastVisibleSystem != -1) this.$cycleHistory(wanted);
wanted.lastVisibleSystem = wanted.system;
wanted.lastVisibleDestination = wanted.destinationSystem;
wanted.updated = (wanted.departureTime < clock.adjustedSeconds ? wanted.departureTime : wanted.dockTime);
}
// recalculate the route for the next iteration
info = System.infoForSystem(galaxyNumber, wanted.system);
info2 = System.infoForSystem(galaxyNumber, wanted.destinationSystem);
rt = info.routeToSystem(info2, wanted.routeMode);
} while (wanted.departureTime < clock.adjustedSeconds && wanted.movement === 3);
} else {
// stop this ship from moving and flag it for deletion
wanted.movement = 99;
}
break;
case 4: // custom path, point to point, one way
var sl = this._customPath[wanted.arrayIndex];
do {
if (this._debug) log(this.name, "Moving " + wanted.pilotName + " from " + wanted.system + " to " + wanted.destinationSystem);
var idx = sl.indexOf(wanted.destinationSystem);
wanted.system = wanted.destinationSystem;
if (idx === sl.length - 1) {
// this is the end of the line!
if (wanted.primaryRole === "trader-courier") {
// pick another route from this point
// work out which segment we're on
var segment = -1;
var side = "";
var dest = 0;
var chk1 = this._courierRoutes[0]["point1"].indexOf(wanted.destinationSystem);
var chk2 = this._courierRoutes[0]["point2"].indexOf(wanted.destinationSystem);
var chk3 = this._courierRoutes[1]["point1"].indexOf(wanted.destinationSystem);
var chk4 = this._courierRoutes[1]["point2"].indexOf(wanted.destinationSystem);
if (chk1 >= 0) {segment = 0; side = "point2";}
if (chk2 >= 0) {segment = 0; side = "point1";}
if (chk3 >= 0) {segment = 1; side = "point2";}
if (chk4 >= 0) {segment = 1; side = "point1";}
var found = false;
var tries = 0;
// an edge case is resulting in the dest system not being found on any of the courier routes
// so check we have one before doing the loop
if (segment === -1) {
// create a custom path to the start of a new courier run
segment = (Math.random() > 0.5 ? 1 : 0);
side = (Math.random() > 0.5 ? "point1" : "point2");
}
do {
var dest = this._courierRoutes[segment][side][Math.floor(Math.random() * this._courierRoutes[segment][side].length)];
// create a new custom path
var check = -1;
if (dest != wanted.system)
check = this.$createCustomPath(wanted.system, dest, wanted.routeMode);
if (check !== -1) {
// select the first destination on the list
wanted.arrayIndex = check;
wanted.destinationSystem = this._customPath[wanted.arrayIndex][1];
wanted.movement = 4;
found = true;
} else {
tries += 1;
}
} while (found === false && tries < 5);
if (found === false) {
// shouldn't really happen
log(this.name, "!!ERROR: Courier route could not be found from system " + wanted.system + " (" + segment + ", " + side + ")");
wanted.movement = 99;
}
} else {
// switch to type 3 again
for (var j = 0; j < this._safeDangerous.length; j++) {
var sd = this._safeDangerous[j];
if (sd.id === sl[idx]) {
// clear out the custom path so it can be reused
this._customPath[wanted.arrayIndex] = null;
if (this._debug) log(this.name, ("Final destination reached - moving back to safe/dangerous around system " + sl[idx]));
wanted.arrayIndex = j;
wanted.movement = 3;
// set a new destination
wanted.destinationSystem = sd.dangerous[Math.floor(Math.random() * sd.dangerous.length)];
break;
}
}
// this shouldn't ever happen...
if (wanted.movement === 4) {
log(this.name, "!!ERROR: Safe/dangerous system combo not found for system " + wanted.system);
// stop this ship from moving and flag it for deletion
wanted.movement = 99;
}
}
} else {
// otherwise, just move the ship along the path
wanted.destinationSystem = sl[idx + 1];
}
wanted.dockTime = wanted.departureTime + (rt.time * 3600) + Math.floor(Math.random() * 1800) + 1800;
wanted.departureTime = wanted.dockTime + (Math.random() * 21600 + 21600);
if (nova === false && Math.random() > wanted.updateChance && wanted.dockTime < clock.adjustedSeconds) {
if (this._debug) log(this.name, "updating last visible system to " + wanted.system);
if (wanted.lastVisibleSystem != -1) this.$cycleHistory(wanted);
wanted.lastVisibleSystem = wanted.system;
wanted.lastVisibleDestination = wanted.destinationSystem;
wanted.updated = (wanted.departureTime < clock.adjustedSeconds ? wanted.departureTime : wanted.dockTime);
}
// recalculate the route for the next iteration
info = System.infoForSystem(galaxyNumber, wanted.system);
info2 = System.infoForSystem(galaxyNumber, wanted.destinationSystem);
rt = info.routeToSystem(info2, wanted.routeMode);
} while (wanted.departureTime < clock.adjustedSeconds && wanted.movement === 4);
break;
}
} while (wanted.departureTime < clock.adjustedSeconds && wanted.movement < 99);
if (wanted.movement === 99) type99found = true;
if (this._debug) this.$writeDataToLog(wanted, "Updating record");
}
}
}
this.$restoreMap();
if (type99found === true) {
// clean up any type 99 movements (which shouldn't ever happen)
for (var i = this._wanted.length - 1; i >= 0; i--) {
if (this._wanted[i].movement === 99) {
this._wanted.splice(i, 1);
}
}
}
if (this._pending.length > 0) this.$createTips(true);
}
//-------------------------------------------------------------------------------------------------------------
this.$checkArrivalList = function $checkArrivalList() {
for (var i = 0; i < this._checkOnArrival.length; i++) {
var check = this._checkOnArrival[i];
if (check.isValid) {
for (var j = 0; j < this._wanted.length; j++) {
var wanted = this._wanted[j];
if (check.script._mostWanted === wanted.index) wanted.pending = true;
}
}
}
// clear out the array - we won't need it again until the player next jumps
this._checkOnArrival.length = 0;
}
//-------------------------------------------------------------------------------------------------------------
// removes a random entry from the list
this.$removeItem = function $removeItem(itmIndx) {
var idx = -1;
var force = false;
if (itmIndx && isNaN(itmIndx) === false) {
force = true;
for (var i = 0; i < this._wanted.length; i++) {
if (this._wanted[i].index === itmIndx) {idx = i; break;}
}
} else {
idx = Math.floor(Math.random() * this._wanted.length);
itmIndx = this._wanted[idx].index;
}
if (idx === -1) return;
// only remove them if they're not pending (still just data)
if (force === true || this._wanted[idx].pending === false) {
if (this._debug) this.$writeDataToLog(this._wanted[idx], "Deleting record");
// remove ship from the display list
for (var i = 0; i < this._displayList.length; i++) {
if (this._displayList[i].index === itmIndx) {
this._displayList.splice(i, 1);
break;
}
}
// remove any tips
for (var i = this._hunterTips.length - 1; i >= 0; i--) {
if (this._hunterTips[i].index === itmIndx) {
this._hunterTips.splice(i, 1);
}
}
var ml = this._missionList.indexOf(itmIndx);
if (ml >= 0) {
this._missionList.splice(ml, 1);
this.$updateManifest();
}
this._wanted.splice(idx, 1);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$removePendingItem = function $removePendingItem(idx) {
for (var i = 0; i < this._pending.length; i++) {
if (this._pending[i].index === idx) {
this._pending.splice(i, 1);
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------
// creates new records of ship and pilot data
this.$initialiseData = function $initialiseData(max) {
// work out how many criminals we will be creating
var total = parseInt(Math.random() * 30) + 10;
if (max && isNaN(max) === false) total = max;
var role = "";
var s_type = 0;
for (var i = 0; i < total; i++) {
s_type = 0;
var d_type = Math.random();
// work out the type and level of the criminal. higher levels should be rarer but stronger
// trader type
if (d_type <= 0.3) {
s_type = 1;
if (Math.random() > 0.5) {
s_type = 2;
if (Math.random() > 0.8) s_type = 3;
} else if(Math.random() > 0.7) {
// courier
s_type = 11;
}
}
// pirate type
if (d_type > 0.3 && d_type <= 0.7) {
s_type = 4;
if (Math.random() > 0.5) {
s_type = 5;
if (Math.random() >= 0.7) {
s_type = 6;
if (Math.random() > 0.9) s_type = 7;
}
}
}
// assassin type
if (d_type > 0.7 && d_type <= 0.95) {
s_type = 8;
if (Math.random() > 0.7) s_type = 9;
}
// hunter type
if (d_type > 0.95) {
// this is pretty rare
if (Math.random() <= 0.05) s_type = 10;
}
if (s_type === 0) continue;
// start setting up our data
var dta = {};
dta.index = this.$newItemIndex();
dta.routeMode = "OPTIMIZED_BY_JUMPS";
dta.pending = false;
dta.bounty = 0;
// note: while weapons are being included in the definition, if "autoWeapons" is set on the shipdata,
// the weapon definitions in the original data will be used instead of anything set here.
switch (s_type) {
case 1: // trader
case 2: // trader
case 3: // trader
case 11: // courier
// build a ship
if (s_type <= 3) {
// bounty between 200 and 7100
dta.realBounty = parseInt(Math.random() * 150 + 200) + ((parseInt(Math.random() * 250) + 200) * Math.pow(3, s_type - 0.5));
// vary rarely add some really juicy numbers
if (Math.random() > 0.97) dta.realBounty += parseInt(Math.random() * 2000 + 2000);
role = "trader";
if (Math.random() > 0.5) dta.routeMode = "OPTIMIZED_BY_TIME";
if (Math.random() > (0.7 - (s_type / 10))) role = "trader-smuggler";
var found = false;
do {
dta.shipDataKey = this.$getRandomShipKey(role);
var shipPlist = Ship.shipDataForKey(dta.shipDataKey);
dta.shipType = shipPlist.name;
// make sure this is a serious trader (not a bug or hognose)
if (shipPlist.max_cargo >= 20 + (s_type - 1) * 20) found = true;
} while (found === false);
} else {
// bounty between 200 and 9350
dta.realBounty = parseInt(Math.random() * 150 + 200) + ((parseInt(Math.random() * 250) + 200) * 20);
// vary rarely add some really juicy numbers
if (Math.random() > 0.97) dta.realBounty += parseInt(Math.random() * 3000 + 3000);
role = "trader-courier";
dta.shipDataKey = this.$getRandomShipKey(role);
var shipPlist = Ship.shipDataForKey(dta.shipDataKey);
dta.shipType = shipPlist.name;
dta.routeMode = "OPTIMIZED_BY_TIME";
}
dta.shipAI = "oolite-traderAI.js";
dta.shipName = this.$getRandomShipName(role);
dta.personality = Math.floor(Math.random() * 32767);
dta.primaryRole = role;
dta.accuracy = (s_type <= 3 ? (5 + s_type) : 8);
dta.heatInsulation = 2;
switch (s_type) {
case 1:
dta.equipment = "FORE:EQ_WEAPON_BEAM_LASER,AFT:EQ_WEAPON_BEAM_LASER";
dta.escortsRole = "escort";
break;
case 2:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_BEAM_LASER,EQ_CLOAKING_DEVICE";
dta.escortsRole = "escort-medium";
break;
case 3:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_MILITARY_LASER,EQ_CLOAKING_DEVICE";
dta.escortsRole = "escort-heavy";
break;
case 11:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_MILITARY_LASER,EQ_CLOAKING_DEVICE";
dta.escortsRole = "escort";
break;
}
dta.equipment += ",EQ_ESCAPE_POD";
if (s_type <= 3) {
dta.escorts = (s_type * 2); // 2, 4 or 6
this.$addEscortsToData(dta);
} else {
// no escorts for couriers
dta.escorts = 0;
dta.escortData = [];
}
// create a pilot, picking a random system as home
var pilot = this.$createPilot(Math.floor(Math.random() * 256));
dta.pilotDescription = pilot.description;
dta.pilotName = pilot.name;
dta.pilotHomeSystem = pilot.homeSystem;
dta.pilotSpecies = pilot.species;
if (s_type <= 3) {
// pick a starting point
// milk run or spacelane
if (Math.random() > 0.5) {
// milkrun it is
// pick a random milkrun
dta.arrayIndex = Math.floor(Math.random() * this._milkRuns.length);
dta.movement = 1; // milkrun
var mr = this._milkRuns[dta.arrayIndex];
dta.system = mr.id1;
dta.destinationSystem = mr.id2
} else {
// spacelane it is
// pick a random spacelane
dta.arrayIndex = Math.floor(Math.random() * this._spacelanes.length);
dta.movement = 2; // spacelane
var sl = this._spacelanes[dta.arrayIndex];
// pick a starting point
var idx = Math.floor(Math.random() * sl.length);
dta.system = sl[idx];
// which way are we going, l-to-r or r-to-l
if (idx < (sl.length - 1) && idx > 0) {
if (Math.random() > 0.5) {
// right to left
dta.destinationSystem = sl[idx - 1];
} else {
// left to right
dta.destinationSystem = sl[idx + 1];
}
} else {
// edge cases
if (idx === 0) {
dta.destinationSystem = sl[idx + 1];
} else {
dta.destinationSystem = sl[idx - 1];
}
}
}
} else {
// pick a start/end point from the available courier routes, and make sure it's connected
var side = (Math.random() > 0.5 ? 1 : 0);
var start = (Math.random() > 0.5 ? "point1" : "point2");
var end = (start === "point1" ? "point2" : "point1");
// try to find a connecting route
var found = false;
var tries = 0;
do {
var sys1 = this._courierRoutes[side][start][Math.floor(Math.random() * this._courierRoutes[side][start].length)];
var sys2 = this._courierRoutes[side][end][Math.floor(Math.random() * this._courierRoutes[side][end].length)];
var rt = System.infoForSystem(galaxyNumber, sys1).routeToSystem(System.infoForSystem(galaxyNumber, sys2));
if (!rt) {
tries += 1;
} else {
// create a custom route for this run
var check = this.$createCustomPath(sys1, sys2, dta.routeMode);
if (check !== -1) {
// select the first destination on the list
dta.arrayIndex = check;
dta.system = this._customPath[dta.arrayIndex][0];
dta.destinationSystem = this._customPath[dta.arrayIndex][1];
dta.movement = 4;
found = true;
} else {
tries += 1;
}
}
} while (found === false && tries < 5);
// we weren't able to create a patch, so give up on this entry
if (found === false) continue;
}
// when did they dock?
dta.dockTime = clock.adjustedSeconds - (Math.random() * 21600 + 3600);
// when will they leave dock?
dta.departureTime = clock.adjustedSeconds + (Math.random() * 21600 + 3600);
// arrival time in new system will be departureTime + travelTime(time between systems) + extraTime(random flight time)
// is their current position visible to GalCop?
dta.updateChance = (s_type <= 3 ? (s_type / 6) : 0.5);
break;
case 4: // pirate
case 5:
case 6:
case 7:
// bounty between 250 and 15200
dta.realBounty = parseInt(Math.random() * 100 + 250) + ((parseInt(Math.random() * 250) + 200) * Math.pow(3, s_type - 4));
// vary rarely add some really juicy numbers
if (Math.random() > 0.97) dta.realBounty += parseInt(Math.random() * 5000 + 5000);
dta.bounty = 60 + (Math.floor(Math.random() * 8)) + Math.floor(Math.random() * 8);
if (Math.random() > 0.5) dta.routeMode = "OPTIMIZED_BY_TIME";
// build a ship
var def_role = "pirate";
switch (s_type) {
case 4:
role = "pirate";
dta.escortsRole = "pirate-light-fighter";
break;
case 5:
role = "pirate-light-freighter";
dta.escortsRole = "pirate-light-fighter";
break;
case 6:
role = "pirate-medium-freighter";
dta.escortsRole = "pirate-medium-fighter";
break;
case 7:
role = "pirate-heavy-freighter";
dta.escortsRole = "pirate-heavy-fighter";
break;
}
if (this.$roleExists(role) === false) role = def_role;
dta.shipAI = "oolite-pirateFreighterAI.js";
var found = false;
do {
dta.shipDataKey = this.$getRandomShipKey(role);
var shipPlist = Ship.shipDataForKey(dta.shipDataKey);
dta.shipType = shipPlist.name;
// make sure this is a serious pirate (not a bug or hognose)
if (shipPlist.max_cargo >= 20 + (s_type - 4) * 20) found = true;
} while (found === false);
dta.shipName = this.$getRandomShipName(role);
dta.personality = Math.floor(Math.random() * 32767);
dta.primaryRole = role;
dta.accuracy = s_type;
dta.heatInsulation = 2;
switch (s_type) {
case 4:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER";
break;
case 5:
dta.equipment = "FORE:EQ_WEAPON_BEAM_LASER,AFT:EQ_WEAPON_BEAM_LASER,EQ_CLOAKING_DEVICE";
break;
case 6:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_BEAM_LASER,EQ_CLOAKING_DEVICE";
break;
case 7:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_MILITARY_LASER,EQ_CLOAKING_DEVICE";
break;
}
// assassins don't have escaspe pods
dta.equipment += ",EQ_ESCAPE_POD";
if (Math.random() < (s_type / 5)) {
dta.escorts = ((s_type - 3) * 2); // 2, 4, 6 or 8
this.$addEscortsToData(dta);
} else {
dta.escorts = 0;
dta.escortData = [];
}
// create a pilot, picking a random system as home
var pilot = this.$createPilot(Math.floor(Math.random() * 256));
dta.pilotDescription = pilot.description;
dta.pilotName = pilot.name;
dta.pilotHomeSystem = pilot.homeSystem;
dta.pilotSpecies = pilot.species;
// where are they now, and where are they headed?
// pick a safe/dangerous element, start them in the safe one
dta.arrayIndex = Math.floor(Math.random() * this._safeDangerous.length);
dta.movement = 3; // star-type movement (if there is more than 1 dangerous system against the safe one, otherwise same as a milkrun)
var sd = this._safeDangerous[dta.arrayIndex];
dta.system = sd.id;
dta.destinationSystem = sd.dangerous[0];
// when did they dock?
dta.dockTime = clock.adjustedSeconds - (Math.random() * 21600 + 3600);
// when will they leave dock?
dta.departureTime = clock.adjustedSeconds + (Math.random() * 21600 + 3600);
// arrival time in new system will be departureTime + travelTime(time between systems) + extraTime(random flight time)
// is their current position visible to GalCop?
dta.updateChance = (s_type - 3) / 6;
break;
case 8: // assassin
case 9:
// bounty between 250 and 11600
dta.realBounty = parseInt(Math.random() * 100 + 250) + ((parseInt(Math.random() * 250) + 200) * Math.pow(5, s_type - 7));
// vary rarely add some really juicy numbers
if (Math.random() > 0.97) dta.realBounty += parseInt(Math.random() * 5000 + 5000);
dta.routeMode = "OPTIMIZED_BY_TIME";
// build a ship
switch (s_type) {
case 8:
role = "assassin-medium";
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_BEAM_LASER";
dta.escortsRole = "assassin-light";
break;
case 9:
role = "assassin-heavy";
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_MILITARY_LASER";
dta.escortsRole = "assassin-medium";
break;
}
dta.equipment += ",X:EQ_ESCAPE_POD";
if (this.$roleExists(role) === false) continue;
dta.shipAI = "oolite-assassinAI.js";
dta.shipDataKey = this.$getRandomShipKey(role);
var shipPlist = Ship.shipDataForKey(dta.shipDataKey);
dta.shipType = shipPlist.name;
dta.shipName = this.$getRandomShipName(role);
dta.personality = Math.floor(Math.random() * 32767);
dta.primaryRole = role;
dta.accuracy = s_type - 1;
dta.heatInsulation = 2;
dta.equipment += ",EQ_ESCAPE_POD,EQ_CLOAKING_DEVICE";
dta.escorts = ((s_type - 6) * 2); // 4, or 6
this.$addEscortsToData(dta);
// create a pilot, picking a random system as home
var pilot = this.$createPilot(Math.floor(Math.random() * 256));
dta.pilotDescription = pilot.description;
dta.pilotName = pilot.name;
dta.pilotHomeSystem = pilot.homeSystem;
dta.pilotSpecies = pilot.species;
// where are they now, and where are they headed?
// pick a safe/dangerous element, start them in the safe one
dta.arrayIndex = Math.floor(Math.random() * this._safeDangerous.length);
dta.movement = 3; // star-type movement (if there is more than 1 dangerous system against the safe one, otherwise same as a milkrun)
var sd = this._safeDangerous[dta.arrayIndex];
dta.system = sd.dangerous[0];
dta.destinationSystem = sd.id;
// when did they dock?
dta.dockTime = clock.adjustedSeconds - (Math.random() * 21600 + 3600);
// when will they leave dock?
dta.departureTime = clock.adjustedSeconds + (Math.random() * 21600 + 3600);
// arrival time in new system will be departureTime + travelTime(time between systems) + extraTime(random flight time)
// is their current position visible to GalCop?
dta.updateChance = (s_type / 15);
break;
case 10: // hunter
// bounty between 500 and 7350
dta.realBounty = parseInt(Math.random() * 100 + 500) + ((parseInt(Math.random() * 250) + 200) * 15);
// vary rarely add some really juicy numbers
if (Math.random() > 0.97) dta.realBounty += parseInt(Math.random() * 5000 + 5000);
if (Math.random() > 0.3) dta.routeMode = "OPTIMIZED_BY_TIME";
// build a ship
role = "hunter-heavy";
if (this.$roleExists(role) === false) continue;
dta.shipAI = "oolite-bountyHunterLeaderAI.js";
dta.shipDataKey = this.$getRandomShipKey(role);
var shipPlist = Ship.shipDataForKey(dta.shipDataKey);
dta.shipType = shipPlist.name;
dta.shipName = this.$getRandomShipName(role);
dta.personality = Math.floor(Math.random() * 32767);
dta.primaryRole = role;
dta.accuracy = s_type - 1;
dta.heatInsulation = 2;
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_MILITARY_LASER";
dta.equipment += ",EQ_ESCAPE_POD,EQ_CLOAKING_DEVICE";
dta.escorts = Math.floor(Math.random() * 4) + 5;
dta.escortsRole = "hunter-medium";
this.$addEscortsToData(dta);
// create a pilot, picking a random system as home
var pilot = this.$createPilot(Math.floor(Math.random() * 256));
dta.pilotDescription = pilot.description;
dta.pilotName = pilot.name;
dta.pilotHomeSystem = pilot.homeSystem;
dta.pilotSpecies = pilot.species;
// where are they now, and where are they headed?
// pick a safe/dangerous element, start them in the safe one
dta.arrayIndex = Math.floor(Math.random() * this._safeDangerous.length);
dta.movement = 3; // star-type movement (if there is more than 1 dangerous system against the safe one, otherwise same as a milkrun)
var sd = this._safeDangerous[dta.arrayIndex];
dta.system = sd.dangerous[0];
dta.destinationSystem = sd.id;
// when did they dock?
dta.dockTime = clock.adjustedSeconds - (Math.random() * 21600 + 3600);
// when will they leave dock?
dta.departureTime = clock.adjustedSeconds + (Math.random() * 21600 + 3600);
// arrival time in new system will be departureTime + travelTime(time between systems) + extraTime(random flight time)
// is their current position visible to GalCop?
dta.updateChance = 0.6
break;
}
// finalise settings
if (Math.random() > dta.updateChance) {
dta.lastVisibleSystem = dta.system;
dta.lastVisibleDestination = dta.destinationSystem;
dta.updated = clock.adjustedSeconds - ((Math.random() * 14) * 86400) + (Math.random() * 86400);
} else {
dta.lastVisibleSystem = -1;
}
dta.lastVisibleHistory = [2];
// add this record to the array
if (this._debug) this.$writeDataToLog(dta, "Creating record");
this._wanted.push(dta);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$addEscortsToData = function $addEscortsToData(dta) {
dta.escortData = [];
for (var j = 0; j < dta.escorts; j++) {
var esc = {};
esc["escortShipKey"] = this.$getRandomShipKey(dta.escortsRole);
esc["escortShipName"] = this.$getRandomShipName(dta.escortsRole);
esc["escortPersonality"] = Math.floor(Math.random() * 32768);
esc["escortPilotName"] = this.$generateName(); //randomName() + " " + randomName();
if (dta.primaryRole.indexOf("pirate") >= 0) {
esc["escortBounty"] = Math.floor(Math.random() * (dta.accuracy * 5) + 5);
} else {
esc["escortBounty"] = 0;
}
esc["escortHiddenBounty"] = Math.floor(Math.random() * 30 + 5);
dta.escortData.push(esc);
}
}
//-------------------------------------------------------------------------------------------------------------
// looks for any ships that need to be added to the local system in some way, either witchpoint or station
this.$processPendingShips = function $processPendingShips() {
var sdcInst = this._sdcInstalled;
var doUpdate = false;
for (var i = this._pending.length - 1; i >= 0; i--) {
var pend = this._pending[i];
var r_type = pend.type;
var chance = pend.chance;
var dta = JSON.parse(pend.data);
// check for a big time difference (eg caused by ejecting)
// if difference is too large, revert this record to be not pending
var diff = (pend.time - clock.adjustedSeconds);
// if the departure time less than the current time, switch this back to not-pending
if (diff < 0) {
doUpdate = true;
for (var j = 0; j < this._wanted.length; j++) {
if (this._wanted[j].index === pend.index) {
this._wanted[j].pending = false;
break;
}
}
this._pending.splice(i, 1);
continue;
}
// work out if this ship is docked somewhere, or if it will be jumping in
// if docked, and SDC is installed, add it to a dock
// otherwise, we can choose a random time to add the ship
switch (r_type) {
case "witchpoint":
// how far is the player from the wp? If they're too far away, don't spawn anything yet
var wp = new Vector3D(0, 0, 0); //system.shipsWithRole("buoy-witchpoint")[0];
if (player.ship.position.distanceTo(wp) < (player.ship.scannerRange * 3)) {
// what's the actual time differential for this ship?
var info = System.infoForSystem(galaxyNumber, dta.system);
var rt = system.info.routeToSystem(info, dta.routeMode);
var diff = Math.abs((dta.departureTime + (rt.time * 3600)) - clock.adjustedSeconds);
if (Math.random() < (diff / 3600) && Math.random() < chance) {
// OK, here we go!
this.$createShips("wp", dta, this.$wormholePos(), rt);
this._pending.splice(i, 1);
} else {
// increase the chance for next time around.
pend.chance += 0.05;
}
}
break;
case "docked":
// we're only going to switch between rock hermits and the main station, so we know SDC will be handling the launch
var stn = this.$translateStationName(pend.station);
// this shouldn't happen, but still...
if (stn == null) continue;
// is SDC installed?
if (sdcInst === true) {
var sdc = worldScripts.StationDockControl; // link to the main SDC pack
var found = false;
// make sure the station is not in the process of being updated
if (sdc._populateStation.length > 0) {
for (var j = 0; j < sdc._populateStation.length; j++) {
if (sdc._populateStation.stn === stn) {
found = true;
break;
}
}
// station is about to be populated, so hold off on this one for the moment
// catch it next time round
if (found === true) continue;
}
var pilot = {name:dta.pilotName, insurance:0, description:dta.pilotDescription, homeSystem:dta.pilotHomeSystem, species:dta.pilotSpecies};
var dt = parseInt((dta.departureTime - clock.adjustedSeconds) / 60)
// we can now add the ship definition to the array
sdc.$addShipToArray({
station:stn, // the station object the ship will be docked at
role:dta.primaryRole,
shipName:dta.shipName,
shipType:dta.shipType,
shipDataKey:dta.shipDataKey,
personality:dta.personality,
aiName:dta.shipAI,
accuracy:dta.accuracy,
equipment:dta.equipment,
heatInsulation:dta.heatInsulation,
homeSystem:pilot.homeSystem,
fuel:7,
bounty:dta.bounty,
escortName:"",
escortLeader:false,
groupName:(dta.escorts > 0 ? "bh_group_" + dta.index : ""),
groupLeader:(dta.escorts > 0 ? true : false),
destinationSystem:dta.destinationSystem,
destinationHidden:true,
goods:"PLENTIFUL_GOODS",
pilot:pilot,
dockTime:dta.dockTime,
departureTime:dt,
departureSeconds:0,
lastChance:clock.adjustedSeconds,
//lastChange:clock.adjustedSeconds + (3600 * 4), // so the ship doesn't get an updated departure slot too quickly
launchCallback:"$bounty_launchCallback",
worldScript:this.name,
properties:{
_mostWanted:dta.index,
_hiddenBounty:dta.realBounty,
_storedHiddenBounty:dta.realBounty
}
});
if (worldScripts.Smugglers_DockMaster) {
var sdci = worldScripts.StationDockControl_Interface;
if (sdci.$externalInterfaceExists({
pilotName:dta.pilotName,
menuText:"Flag ship for Dock Master notification",
worldScript:this.name,
callback:"$bounty_dockMaster_flag"}) === false) {
sdci.$externalInterface({
pilotName:dta.pilotName,
menuText:"Flag ship for Dock Master notification",
station:system.mainStation, // this menu will only be available at the main station (where there's a dock master)
worldScript:this.name,
callback:"$bounty_dockMaster_flag",
parameter:dta.index
});
}
}
if (this._debug) log(this.name, "adding BH ship to station - " + dta.shipName + ", " + stn.displayName);
if (this._debug) log(this.name, "dock time " + clock.clockStringForTime(dta.dockTime));
if (dta.escorts > 0 && dta.escortData.length > 0) {
// add all the escorts to SDC as well
for (var j = 0; j < dta.escortData.length; j++) {
var item = dta.escortData[j];
var st = this.$getShipType(item.escortShipKey);
if (st != "") {
var e_pilot = {name:item.escortPilotName, insurance:0, homeSystem:dta.pilotHomeSystem, species:dta.pilotSpecies};
sdc.$addShipToArray({
station:stn, // the station object the ship will be docked at
role:dta.escortsRole,
shipName:item.escortShipName,
shipType:st,
shipDataKey:item.escortShipKey,
personality:item.escortPersonality,
aiName:"oolite-escortAI.js",
accuracy:dta.accuracy,
equipment:"",
heatInsulation:1,
homeSystem:e_pilot.homeSystem,
fuel:7,
bounty:item.escortBounty,
escortName:"",
escortLeader:false,
groupName:"bh_group_" + dta.index,
groupLeader:false,
destinationSystem:dta.destinationSystem,
destinationHidden:true,
goods:"PLENTIFUL_GOODS",
pilot:e_pilot,
dockTime:dta.dockTime + (j + 1),
departureTime:dt,
departureSeconds:5,
lastChange:clock.adjustedSeconds, // + (3600 * 4), // so the ship doesn't get an updated departure slot too quickly
launchCallback:"$bounty_escortLaunchCallback",
worldScript:this.name,
properties:{
_mostWanted:dta.index,
_hiddenBounty:item.escortHiddenBounty,
_storedHiddenBounty:item.escortHiddenBounty
}
});
}
}
}
// remove the item so it doesn't get created again.
this._pending.splice(i, 1);
continue; // just continue here, because with SDC there is no further work to do on this ship
} else {
//this._launching.push({station:pend.station, data:JSON.stringify(dta), })
var diff = dta.departureTime - clock.adjustedSeconds;
if (Math.random() < (diff / 3600) && Math.random() < chance) {
// without SDC we just launch the ships
// is there any space in the launch queue for this group of ships
// so, if there's only 1 slot, and there's 5 ships in this group, don't launch any of them
if (this.$launchAvailable(stn, dta.escorts + 1) === true) {
this.$createShips("stn", dta, stn);
this._pending.splice(i, 1);
}
continue;
}
pend.chance += 0.05;
}
break;
}
}
// if an item was switched back to non-pending, we should do a refresh of the movement data
// in case something needs to be switched from arriving to docked
if (doUpdate === true) this.$updateMovementData();
}
//-------------------------------------------------------------------------------------------------------------
this.$createShips = function $createShips(posType, dta, pos, rt) {
var wpop = worldScripts["oolite-populator"];
var shpKey = dta.shipDataKey;
// make sure a single ship is launched/added (ie without escorts), because we'll be doing the escorts manually
if (this.$bountyVersionExists(shpKey)) shpKey = "dock_" + shpKey;
var lead = null;
if (posType === "wp") {
var shps = system.addShips("[" + shpKey + "]", 1, pos, 0);
if (shps && shps.length > 0) lead = shps[0];
}
if (posType === "stn") {
lead = pos.launchShipWithRole("[" + shpKey + "]");
}
if (lead) {
// attach scripts
this.$bounty_launchCallback("launched", lead);
lead.shipUniqueName = dta.shipName;
dta.fuel = 7 - (rt ? rt.distance : 0);
dta.goods = "";
if (dta.primaryRole.indexOf("trader") >= 0) dta.goods = "SCARCE_GOODS";
if (dta.primaryRole.indexOf("pirate") >= 0) dta.goods = "PIRATE_GOODS";
this.$updateShip(lead, dta);
if (Math.random() * 8 > system.info.government) {
// may have used some missiles already
wpop._setMissiles(lead, -1);
}
if (this._debug) log(this.name, "adding BH ship to " + posType + " - " + lead.shipUniqueName + ", " + lead);
if (this._sdcInstalled) {
var sdc = worldScripts.StationDockControl;
sdc.$awaitShipDocking({shipName:dta.shipName, pilotName:dta.pilotName, worldScript:this.name, callback:"$sdc_shipDockedWithStation", parameter:dta.index, launchCallback:"$bounty_launchCallback"});
}
if (dta.escorts > 0 && dta.escortData.length > 0) {
// set up a ship group
var grp = new ShipGroup("bh_group_" + dta.index, lead);
lead.group = grp;
for (var j = 0; j < dta.escortData.length; j++) {
var item = dta.escortData[j];
var esc = null;
if (posType === "wp") {
var shps = system.addShips("[" + item.escortShipKey + "]", 1, pos, 1E3);
if (shps && shps.length > 0) esc = shps[0];
}
if (posType === "stn") {
var escShpKey = item.escortShipKey;
// make sure a single ship is launched (ie without escorts)
if (this.$bountyVersionExists(shpKey)) escShpKey = "bounty_" + escShpKey;
esc = pos.launchShipWithRole("[" + escShpKey + "]");
}
if (esc) {
esc.shipUniqueName = item.escortShipName;
esc.entityPersonality = item.escortPersonality;
esc.fuel = 7;
esc.homeSystem = dta.pilotHomeSystem;
esc.destinationSystem = lead.destinationSystem;
// set the seed values so that the pilot's species can be defined by their home system
var seed = "0 0 0 0 " + dta.pilotHomeSystem.toString() + " 2";
esc.setCrew({name:item.escortPilotName, origin:dta.pilotHomeSystem,
bounty:item.escortBounty, random_seed:seed});
// attach a shipDied handler so we can update the master record when escorts are killed
// that way, if the player shoots 2 out of 5 escorts, and the rest manage to escape, if the player finds them again
// those killed escorts won't have magically regenerated
this.$bounty_escortLaunchCallback("launched", esc);
esc.script._mostWanted = dta.index;
esc.script._hiddenBounty = item.escortHiddenBounty;
wpop._setWeapons(esc, 2.5);
esc.group = grp;
grp.addShip(esc);
// try to do an escort offer
esc.performEscort();
if (this._debug) log(this.name, "add BH escort ship to " + posType + " - " + esc.shipUniqueName + ", " + esc);
//log(this.name, "escort offer to lead = " + ret);
} else {
log(this.name, "!!ERROR: Escort (shipkey " + item.escortShipKey + ") not created for ship " + lead.shipUniqueName + ", " + lead);
}
}
}
// make sure the leader has hardhead missiles
this.$switchMissiles(lead);
// remove the item so it doesn't get created again.
//this._pending.splice(i, 1);
} else {
log(this.name, "!!ERROR: Lead ship not created at " + posType + ": " + (posType === "stn" ? "(" + pos.shipUniqueName + ") " : "") + dta.shipUniqueName + ", " + dta.pilotName);
}
}
//-------------------------------------------------------------------------------------------------------------
// looks for any ships that have been created and are registered as docked in SDC
// when not found, reset pending flag back to false so ships will be regenerated
this.$lookForPendingRecords = function $lookForPendingRecords() {
if (this._sdcInstalled === true) {
// get the data for this system
var sdcData = worldScripts.StationDockControl._systemDockingData;
if (sdcData[system.ID]) var sdc = sdcData[system.ID];
// get the list of object keys for this (basically a station index list)
if (sdc) var keys = Object.keys(sdc);
// we're doing all this here so we only do it once, rather than each time a pending flag is found
}
for (var i = 0; i < this._wanted.length; i++) {
var wanted = this._wanted[i];
if (wanted.pending === true) {
if (this._sdcInstalled === false) {
// without sdc, we can just reset the record - no saved data to mess with
this.$removePendingItem(wanted.index);
wanted.pending = false;
} else {
var found = false;
if (keys) {
// loop through the stations
for (var j = 0; j < keys.length; j++) {
// get the ships docked at the station
var stndata = sdc[keys[j]];
for (var k = 0; k < stndata.length; k++) {
// investigate each ship entry, looking for additionalProperties._mostWanted
var shipd = stndata[k];
if (shipd.hasOwnProperty("additionalProperties") && shipd.additionalProperties.hasOwnProperty("_mostWanted")) {
if (wanted.index == shipd.additionalProperties._mostWanted) {
// found! so we don't want to attempt to recreate this one
found = true;
break;
}
}
}
if (found === true) break;
}
}
// not found, so set the flag back to false so it can be regenerated
if (found === false) {
this.$removePendingItem(wanted.index);
wanted.pending = false;
}
}
}
}
// look for any remain pending records that are no longer valid
for (var i = this._pending.length - 1; i >= 0; i--) {
var pend = this._pending[i];
if (pend.system !== system.ID && pend.destinationSystem !== system.ID) {
this._pending.splice(i, 1);
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$getDockedStation = function $getDockedStation(data) {
// pick between main station and rock hermit
// default is main station
var main = true;
// work out if a rh should be used
switch (data.primaryRole) {
case "trader":
case "trader-courier":
case "trader-smuggler":
// more likely in dangerous systems
if (Math.random() > (0.5 - ((7 - system.info.government) / 7))) main = false;
break;
case "pirate":
case "pirate-light-freighter":
case "pirate-medium-freighter":
case "pirate-heavy-freighter":
// pirates will always prefer a non-main station
if (Math.random() > 0.2) main = false;
break;
case "hunter":
case "hunter-medium":
case "hunter-heavy":
if (Math.random() > (0.5 - ((7 - system.info.government) / 7))) main = false;
break;
case "assassin-light":
case "assassin-medium":
case "assassin-heavy":
break;
}
if (main) {
return system.mainStation;
} else {
var stns = system.stations;
var found = -1;
for (var i = 0; i < stns.length; i++) {
if (stns[i].hasRole("rockhermit")) {found = i; break;}
}
if (found >= 0) {
return stns[found];
} else {
// just in case there are no rock hermits here
return system.mainStation;
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$sdc_shipDockedWithStation = function $sdc_shipDockedWithStation(station, param) {
var mw = worldScripts.BountySystem_MostWanted;
for (var i = 0; i < mw._wanted.length; i++) {
var wanted = mw._wanted[i];
if (wanted.index === param) {
if (wanted.lastVisibleSystem != -1) mw.$cycleHistory(wanted);
wanted.dockTime = clock.adjustedSeconds;
wanted.lastVisibleSystem = system.ID;
wanted.lastVisibleDestination = wanted.destinationSystem;
wanted.updated = clock.adjustedSeconds;
if (worldScripts.Smugglers_DockMaster) {
var sdci = worldScripts.StationDockControl_Interface;
// make sure it's not already there
sdci.$removeExternalInterface({
pilotName:wanted.pilotName,
menuText:"Flag ship for Dock Master notification",
worldScript:"BountySystem_MostWanted",
callback:"$bounty_dockMaster_flag"
});
if (station.isMainStation) {
// add the external interface
sdci.$externalInterface({
pilotName:wanted.pilotName,
menuText:"Flag ship for Dock Master notification",
worldScript:"BountySystem_MostWanted",
callback:"$bounty_dockMaster_flag",
parameter:wanted.index
});
}
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_shipDied = function $bounty_shipWillEnterWormhole(whom, why) {
if (this.ship.script.$bh_shipDied) this.ship.script.$bh_shipDied(whom, why);
// remove ship from all wanted arrays
var mw = worldScripts.BountySystem_MostWanted;
mw.$removeItem(this.ship.script._mostWanted);
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_shipWillEnterWormhole = function $bounty_shipWillEnterWormhole() {
if (this.ship.script.$bh_shipWillEnterWormhole) this.ship.script.$bh_shipWillEnterWormhole();
// logic: no shipDied/shipRemoved/entityDestroyed events on entering a wormhole
// status changes to "STATUS_ENTERING_WITCHSPACE" and stays valid until the player jumps out
// if wormhole collapses and player then jumps to same system...ship will be "STATUS_IN_FLIGHT" at destination
// entityDestroyed only fires if player jumps to a different system, or after 6 minutes
// not sure how long the game will wait before clearing out these ships - check
var mw = worldScripts.BountySystem_MostWanted;
for (var i = 0; i < mw._wanted.length; i++) {
var wanted = mw._wanted[i];
if (wanted.index === this.ship.script._mostWanted) {
// update the destination and departure time
wanted.destinationSystem = this.ship.destinationSystem;
wanted.departureTime = clock.adjustedSeconds;
}
}
mw._checkOnArrival.push(this.ship);
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_shipDockedWithStation = function $bounty_shipDockedWithStation(station) {
if (this.ship.script.$bh_shipDockedWithStation) this.ship.script.$bh_shipDockedWithStation(station);
var mw = worldScripts.BountySystem_MostWanted;
// if SDC is installed don't do anything - SDC handles the everything
if (mw._sdcInstalled === true) return;
// put ship back onto the pending array, but with a negative chance value, so that it will be some minutes before they are launched again
// hopefully this will give their escorts time to dock as well.
var itm = null;
for (var i = 0; i < mw._wanted.length; i++) {
var wanted = mw._wanted[i];
if (wanted.index === this.ship.script._mostWanted) itm = wanted;
}
if (itm) {
var waitperiod = (0.05 * 3) * Math.floor(Math.random() * 10 + 7) * -1; // somewhere between 7 and 17 minutes
mw._pending.push({type:"docked", chance:waitperiod, station:station.displayName, index:itm.index, shipKey:itm.shipDataKey, time:clock.adjustedSeconds + Math.abs(chance * 60), data:JSON.stringify(itm)});
}
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_shipLaunchedEscapePod = function $bounty_shipLaunchedEscapePod(escapepod, passengers) {
if (this.ship.script.$bh_shipLaunchedEscapePod) this.ship.script.$bh_shipLaunchedEscapePod(escapepod, passengers);
// remove ship from all wanted arrays
var mw = worldScripts.BountySystem_MostWanted;
mw.$removeItem(this.ship.script._mostWanted);
// if the player hasn't done a warrant scan, leave everything alone
// if the player has done a warrant scan, make the remaining bounty in the range of (20-60) so the player doesn't get paid the big bounty twice
if (this.ship.script._hiddenBounty === 0) {
// the big bounty will move over to the escape pod with the pilot
// reset the bounty on the ship so the player doesn't get paid twice
var b = parseInt(Math.random() * 40 + 20);
this.ship.bounty = b;
//escapepod.crew[0].bounty = b;
//escapepod.bounty = b;
}
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_launchCallback = function $bounty_launchCallback(launchType, ship) {
if (this._debug) log(this.name, "launchCallback " + launchType + ", " + ship);
switch (launchType) {
case "launching":
case "launched":
// "ship" will be an actual ship
if (ship) {
var mw = worldScripts.BountySystem_MostWanted;
// attach our scripts to the new ship
if (ship.script.shipDied) ship.script.$bh_shipDied = ship.script.shipDied;
ship.script.shipDied = mw.$bounty_shipDied;
if (ship.script.shipWillEnterWormhole) ship.script.$bh_shipWillEnterWormhole = ship.script.shipWillEnterWormhole;
ship.script.shipWillEnterWormhole = mw.$bounty_shipWillEnterWormhole;
if (ship.script.shipDockedWithStation) ship.script.$bh_shipDockedWithStation = ship.script.shipDockedWithStation;
ship.script.shipDockedWithStation = mw.$bounty_shipDockedWithStation;
if (ship.script.shipLaunchedEscapePod) ship.script.$bh_shipLaunchedEscapePod = ship.script.shipLaunchedEscapePod;
ship.script.shipLaunchedEscapePod = mw.$bounty_shipLaunchedEscapePod;
// remove any external menu added to SDC
if (worldScripts.StationDockControl_Interface) {
var sdci = worldScripts.StationDockControl_Interface;
sdci.$removeExternalInterface({
pilotName:ship.crew[0].name,
menuText:"Flag ship for Dock Master notification",
worldScript:"BountySystem_MostWanted",
callback:"$bounty_dockMaster_flag"
});
}
}
break;
case "cleared":
// "ship"" will be the SDC ship data record
// reset the pending flag on any ships cleared by SDC so they go back into the movement process
var idx = ship.additionalProperties["_mostWanted"];
var mw = worldScripts.BountySystem_MostWanted;
for (var i = 0; i < mw._wanted.length; i++) {
var item = mw._wanted[i];
if (item.index === idx) item.pending = false;
}
break;
}
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_escortLaunchCallback = function $bounty_escortLaunchCallback(launchType, ship) {
switch (launchType) {
case "launching":
case "launched":
if (ship) {
var mw = worldScripts.BountySystem_MostWanted;
if (ship.script.shipDied) ship.script.$bh_shipDied = ship.script.shipDied;
ship.script.shipDied = mw.$bounty_escort_shipDied;
}
break;
}
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_escort_shipDied = function $bounty_escort_shipDied(whom, why) {
if (this.ship.script.$bh_shipDied) this.ship.script.$bh_shipDied(whom, why);
// find the record for this escort
var mw = worldScripts.BountySystem_MostWanted;
for (var i = 0; i < mw._wanted.length; i++) {
if (mw._wanted[i].index === this.ship.script._mostWanted) {
var dta = mw._wanted[i];
// look for the escort details for this wanted pilot
for (var j = 0; j < dta.escortData.length; j++) {
if (dta.escortData[j].escortShipKey === this.ship.dataKey && dta.escortData[j].escortPersonality === this.ship.entityPersonality) {
// bingo - time to remove it
dta.escorts -= 1;
dta.escortData.splice(j, 1);
break;
}
}
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$bounty_dockMaster_flag = function $bounty_dockMaster_flag(shipIndex, param) {
var dm = worldScripts.Smugglers_DockMaster;
if (dm._flagged.length >= 3) {
player.consoleMessage("Unable to flag more than 3 ships");
return;
}
var mw = worldScripts.BountySystem_MostWanted;
for (var i = 0; i < mw._wanted.length; i++) {
if (mw._wanted[i].index == param) {
var fee = parseInt(mw._wanted[i].realBounty * 0.1);
player.consoleMessage("Ship has been flagged with the Dock Master");
dm._flagged.push({
text:this.$padTextRight(mw._wanted[i].pilotName + " (" + mw._wanted[i].shipType + (mw._rsnInstalled ? " \"" + mw._wanted[i].shipName + "\"" : "") + ")", 25) + this.$padTextLeft(formatCredits(fee, false, true), 6),
index:param,
shipIndex:shipIndex,
cost:fee
});
// remove the menu from SDC
var sdci = worldScripts.StationDockControl_Interface;
sdci.$removeExternalInterface({
pilotName:mw._wanted[i].name,
menuText:"Flag ship for Dock Master notification",
worldScript:"BountySystem_MostWanted",
callback:"$bounty_dockMaster_flag"
});
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$cycleHistory = function $cycleHistory(dta) {
dta.lastVisibleHistory[2] = dta.lastVisibleHistory[1];
dta.lastVisibleHistory[1] = dta.lastVisibleHistory[0];
dta.lastVisibleHistory[0] = {updated:dta.updated, system:dta.lastVisibleSystem, destination:dta.lastVisibleDestination};
}
//-------------------------------------------------------------------------------------------------------------
this.$updateDisplayList = function $updateDisplayList() {
this._lastUpdate = clock.adjustedSeconds;
// update or add records
this._displayList.length = 0;
for (var i = 0; i < this._wanted.length; i++) {
var itm = this._wanted[i];
this._displayList.push({
lastVisibleSystem:itm.lastVisibleSystem,
lastVisibleDestination:itm.lastVisibleDestination,
updated:itm.updated,
departureTime:itm.departureTime,
lastVisibleHistory:itm.lastVisibleHistory,
pilotName:itm.pilotName,
pilotDescription:itm.pilotDescription,
shipName:itm.shipName,
shipType:itm.shipType,
bounty:itm.realBounty,
index:itm.index});
}
}
//-------------------------------------------------------------------------------------------------------------
this.$translateStationName = function $translateStationName(name) {
var stns = system.stations;
for (var i = 0; i < stns.length; i++) {
if (stns[i].displayName === name) return stns[i];
}
return null;
}
//-------------------------------------------------------------------------------------------------------------
// returns the amount of time it will take to travel between two systems
this.$timeBetweenTwoPoints = function $timeBetweenTwoPoints(sys1, sys2, rtType) {
if (sys1 === sys2) return -1;
if (!rtType) {
var rtType = "OPTIMIZED_BY_JUMPS";
}
var info1 = System.infoForSystem(galaxyNumber, sys1);
var info2 = System.infoForSystem(galaxyNumber, sys2);
var rt = info1.routeToSystem(info2, rtType);
var result = rt.time * 3600
return result;
}
//-------------------------------------------------------------------------------------------------------------
this.$customPathCleanup = function $customPathCleanup() {
for (var j = 0; j < this._customPath.length; j++) {
var found = false;
for (var i = 0; i < this._wanted.length; i++) {
var wanted = this._wanted[i];
if (wanted.movement == 4 && wanted.arrayIndex == j) {
found = true;
}
}
if (found === false && this._customPath[j] != null) {
if (this._debug) log(this.name, "cleaning up index " + j);
this._customPath[j] = null;
}
}
}
//-------------------------------------------------------------------------------------------------------------
// creates a custom path between two systems, returns custom path index if successful, otherwise -1
this.$createCustomPath = function $createCustomPath(startID, endID, rtType) {
if (startID === endID) return -1;
if (!rtType) {
var rtType = "OPTIMIZED_BY_JUMPS";
}
var sys1 = System.infoForSystem(galaxyNumber, startID);
var sys2 = System.infoForSystem(galaxyNumber, endID);
var rt = sys1.routeToSystem(sys2, rtType);
if (rt && rt.route.length > 1) {
if (this._debug) log(this.name, "custom path route is valid " + startID + ", " + endID);
var list = [];
for (var i = 0; i < rt.route.length; i++) {
list.push(rt.route[i]);
}
var idx = -1;
for (var i = 0 ; i < this._customPath.length; i++) {
// look for any empty slots
if (this._customPath[i] == null) {
idx = i;
if (this._debug) log(this.name, "reusing custom path index " + idx + ", " + list);
this._customPath[i] = list;
break;
}
}
if (idx === -1) {
// no empty slots found, so add a new one
this._customPath.push(list);
idx = this._customPath.length - 1;
if (this._debug) log(this.name, "creating custom path index " + idx + ", " + list);
}
// return the index of the custom path
return idx;
} else {
if (this._debug) log(this.name, "custom path route is invalid " + startID + ", " + endID);
return -1;
}
}
//-------------------------------------------------------------------------------------------------------------
// loads the spacelane array with data for the current galaxy
this.$getSpacelanes = function $getSpacelanes() {
this._spacelanes.length = 0;
switch (galaxyNumber) {
case 0:
this._spacelanes.push([141,250,111,186,50,73,35,188,250]);
this._spacelanes.push([7,129,227,73,89,222,29,93,42,131]);
this._spacelanes.push([131,62,150,198,36,28,16,221,99]);
this._spacelanes.push([99,241,86,126,18,246]);
break;
case 1:
this._spacelanes.push([82,23,188,23,54,74,122,57,115,178,45]);
this._spacelanes.push([45,144,189,140,65,48,204,193,221,236,66,58,88,127]);
this._spacelanes.push([127,109,42,114,202]);
this._spacelanes.push([127,207,136,6,24,53,78,48]);
this._spacelanes.push([205,59,100,9,156,92,61,41,179,189]);
this._spacelanes.push([113,115,57,94,29]);
break;
case 2:
this._spacelanes.push([38,182,246,91,22,140,5,56,177,150,26,75,144,209,17,218]);
this._spacelanes.push([50,65,79,154,38,139,189,135,42]);
this._spacelanes.push([205,241,101,132,6,180,164,70,10,85,81,225,81,85,10,70,202,53]);
this._spacelanes.push([140,58,152,76,77,97,168]);
this._spacelanes.push([106,250,245,160,245,22]);
this._spacelanes.push([118,161,54,165,129,186]);
break;
case 3:
this._spacelanes.push([116,230,167,48,210,36,150,84,240,193,223,118,197,135,85,154,213,162,166,213]);
this._spacelanes.push([16,42,172,40,80,65,144,105,119,208,189,1,174,146,100,233]);
this._spacelanes.push([50,239,103,108,103,177,17,177,103,45,105,137,95,54,77,76,21,2,249,113,141,113,97]);
this._spacelanes.push([209,33,62,25,134,58,138,191,78,57,242,234,245,181,82,117,53,74,38]);
this._spacelanes.push([71,79,68,110,220,158,215,63,44,66,146,174,1,4,121,145,142,6,142,11,7,161,140]);
this._spacelanes.push([7,32,232,216,60]);
break;
case 4:
this._spacelanes.push([41,216,112,230,28,102,181,35,180,24,19,156,1,45,79,172,169]);
this._spacelanes.push([140,137,173,70,7,253,243,135,193,225,184,150,115,201,189,227,226,221,57,202,135,202,57,221,226,227,189,115,11,54,158,175,85,178,204,12,215,212,158]);
this._spacelanes.push([194,8,210,41,222,183,254,149,130,108,82,92,29,121,34,183]);
this._spacelanes.push([114,118,2,116,244,248,65,146,153,10,99,91,200,244]);
this._spacelanes.push([120,9,233,104,136,129,139,163,61]);
this._spacelanes.push([249,16,20,39,93,207,131,74,182,252,188,40,146,153,146,40,188,252,182,166,53,221,220,225]);
this._spacelanes.push([30,89,87,89,152,170,88,194,77,246,106,190,208,167]);
break;
case 5:
this._spacelanes.push([84,3,8,88,206,136,144,13,92,99,85,133,40,215,115,83,246,39,35,114]);
this._spacelanes.push([169,51,80,103,243,98,102,16,109,101,67,142,60,209,233,112,225,131,210,12,150,91]);
this._spacelanes.push([104,54,162,148,211,6,181,17,108,28]);
this._spacelanes.push([156,113,14,216,82,177,116,154,120,50,232,124,215]);
this._spacelanes.push([10,77,159,226,31,203,30,234,240,234,140,159]);
break;
case 6:
this._spacelanes.push([103,58,253,65,39,44,236,150,247,193,179,133,215,95,109]);
this._spacelanes.push([194,73,146,239,86,74,199,23,138,18,234,244,166,152,162,242,184]);
this._spacelanes.push([218,130,125,205,79,191,17,178]);
this._spacelanes.push([211,7,163,67,209,250,19,239]);
this._spacelanes.push([46,36,212,187,53,107,174]);
break;
case 7:
this._spacelanes.push([114,12,241,39,23,38,123,130,167,63,136,8,44,91,56,62,186,93,32,61,244,243,116,46,157,230,151,213,198,148,49,76,203,255,161,98,53,1,145,33]);
this._spacelanes.push([215,2,211,9,13,147,216,225,21,218,71,206,236,190,18,26,152,51,209,24,174,82,179,173,30,251,233,125,45,41,104,110,73,135,117,55]);
this._spacelanes.push([126,6,81,65,169,232,252]);
this._spacelanes.push([75,219,248,117]);
this._spacelanes.push([10,72,219,248,117]);
}
}
//-------------------------------------------------------------------------------------------------------------
// loads the mulk run array with data for the current galaxy
this.$getMilkRuns = function $getMilkRuns() {
this._milkRuns.length = 0;
switch (galaxyNumber) {
case 0:
this._milkRuns.push({id1:99,id2:84,rating:70});
this._milkRuns.push({id1:99,id2:191,rating:72});
this._milkRuns.push({id1:12,id2:116,rating:73});
this._milkRuns.push({id1:163,id2:192,rating:73});
this._milkRuns.push({id1:131,id2:42,rating:73});
this._milkRuns.push({id1:254,id2:187,rating:74});
this._milkRuns.push({id1:158,id2:116,rating:75});
this._milkRuns.push({id1:98,id2:84,rating:75});
this._milkRuns.push({id1:98,id2:191,rating:75});
this._milkRuns.push({id1:195,id2:63,rating:76});
this._milkRuns.push({id1:254,id2:251,rating:76});
this._milkRuns.push({id1:79,id2:174,rating:76});
this._milkRuns.push({id1:49,id2:116,rating:76});
this._milkRuns.push({id1:254,id2:74,rating:77});
this._milkRuns.push({id1:100,id2:42,rating:77});
this._milkRuns.push({id1:207,id2:116,rating:77});
this._milkRuns.push({id1:131,id2:167,rating:78});
this._milkRuns.push({id1:240,id2:187,rating:78});
this._milkRuns.push({id1:79,id2:191,rating:79});
this._milkRuns.push({id1:33,id2:123,rating:81});
this._milkRuns.push({id1:99,id2:185,rating:81});
this._milkRuns.push({id1:82,id2:244,rating:83});
this._milkRuns.push({id1:227,id2:154,rating:83});
this._milkRuns.push({id1:35,id2:186,rating:84});
this._milkRuns.push({id1:221,id2:185,rating:84});
this._milkRuns.push({id1:163,id2:252,rating:86});
this._milkRuns.push({id1:141,id2:101,rating:89});
this._milkRuns.push({id1:250,id2:101,rating:89});
this._milkRuns.push({id1:218,id2:18,rating:90});
this._milkRuns.push({id1:82,id2:154,rating:90});
this._milkRuns.push({id1:246,id2:18,rating:93});
break;
case 1:
this._milkRuns.push({id1:255,id2:37,rating:72});
this._milkRuns.push({id1:191,id2:37,rating:74});
this._milkRuns.push({id1:128,id2:165,rating:74});
this._milkRuns.push({id1:57,id2:94,rating:76});
this._milkRuns.push({id1:24,id2:20,rating:78});
this._milkRuns.push({id1:237,id2:174,rating:79});
this._milkRuns.push({id1:16,id2:157,rating:80});
this._milkRuns.push({id1:81,id2:20,rating:80});
this._milkRuns.push({id1:167,id2:94,rating:81});
this._milkRuns.push({id1:82,id2:174,rating:82});
this._milkRuns.push({id1:40,id2:68,rating:82});
this._milkRuns.push({id1:106,id2:211,rating:83});
this._milkRuns.push({id1:57,id2:19,rating:83});
this._milkRuns.push({id1:57,id2:115,rating:84});
this._milkRuns.push({id1:185,id2:38,rating:84});
this._milkRuns.push({id1:92,id2:211,rating:85});
this._milkRuns.push({id1:191,id2:83,rating:85});
this._milkRuns.push({id1:16,id2:34,rating:87});
this._milkRuns.push({id1:40,id2:179,rating:88});
this._milkRuns.push({id1:209,id2:115,rating:88});
this._milkRuns.push({id1:81,id2:97,rating:90});
this._milkRuns.push({id1:82,id2:86,rating:92});
this._milkRuns.push({id1:167,id2:115,rating:92});
this._milkRuns.push({id1:231,id2:147,rating:94});
break;
case 2:
this._milkRuns.push({id1:205,id2:168,rating:71});
this._milkRuns.push({id1:144,id2:147,rating:73});
this._milkRuns.push({id1:34,id2:57,rating:73});
this._milkRuns.push({id1:64,id2:168,rating:73});
this._milkRuns.push({id1:76,id2:152,rating:76});
this._milkRuns.push({id1:76,id2:66,rating:76});
this._milkRuns.push({id1:205,id2:82,rating:77});
this._milkRuns.push({id1:155,id2:57,rating:77});
this._milkRuns.push({id1:116,id2:152,rating:77});
this._milkRuns.push({id1:17,id2:24,rating:77});
this._milkRuns.push({id1:205,id2:114,rating:79});
this._milkRuns.push({id1:17,id2:41,rating:79});
this._milkRuns.push({id1:17,id2:147,rating:79});
this._milkRuns.push({id1:22,id2:140,rating:79});
this._milkRuns.push({id1:64,id2:215,rating:79});
this._milkRuns.push({id1:58,id2:152,rating:80});
this._milkRuns.push({id1:50,id2:65,rating:82});
this._milkRuns.push({id1:42,id2:163,rating:83});
this._milkRuns.push({id1:58,id2:140,rating:84});
this._milkRuns.push({id1:205,id2:241,rating:84});
this._milkRuns.push({id1:43,id2:98,rating:84});
this._milkRuns.push({id1:22,id2:91,rating:84});
this._milkRuns.push({id1:42,id2:135,rating:85});
this._milkRuns.push({id1:54,id2:118,rating:86});
this._milkRuns.push({id1:18,id2:100,rating:87});
this._milkRuns.push({id1:5,id2:66,rating:87});
this._milkRuns.push({id1:79,id2:65,rating:89});
this._milkRuns.push({id1:10,id2:141,rating:89});
this._milkRuns.push({id1:6,id2:180,rating:89});
this._milkRuns.push({id1:58,id2:66,rating:89});
this._milkRuns.push({id1:10,id2:70,rating:90});
this._milkRuns.push({id1:5,id2:140,rating:90});
this._milkRuns.push({id1:116,id2:122,rating:92});
this._milkRuns.push({id1:10,id2:85,rating:94});
break;
case 3:
this._milkRuns.push({id1:38,id2:160,rating:70});
this._milkRuns.push({id1:25,id2:24,rating:72});
this._milkRuns.push({id1:25,id2:62,rating:74});
this._milkRuns.push({id1:220,id2:171,rating:75});
this._milkRuns.push({id1:137,id2:105,rating:76});
this._milkRuns.push({id1:209,id2:33,rating:77});
this._milkRuns.push({id1:29,id2:168,rating:78});
this._milkRuns.push({id1:58,id2:24,rating:78});
this._milkRuns.push({id1:103,id2:107,rating:78});
this._milkRuns.push({id1:65,id2:239,rating:78});
this._milkRuns.push({id1:103,id2:105,rating:79});
this._milkRuns.push({id1:103,id2:177,rating:79});
this._milkRuns.push({id1:38,id2:53,rating:82});
this._milkRuns.push({id1:42,id2:16,rating:83});
this._milkRuns.push({id1:38,id2:74,rating:84});
this._milkRuns.push({id1:103,id2:108,rating:84});
this._milkRuns.push({id1:103,id2:239,rating:84});
this._milkRuns.push({id1:220,id2:68,rating:84});
this._milkRuns.push({id1:58,id2:109,rating:89});
this._milkRuns.push({id1:220,id2:90,rating:90});
break;
case 4:
this._milkRuns.push({id1:34,id2:186,rating:70});
this._milkRuns.push({id1:34,id2:250,rating:70});
this._milkRuns.push({id1:66,id2:58,rating:70});
this._milkRuns.push({id1:2,id2:63,rating:71});
this._milkRuns.push({id1:226,id2:31,rating:71});
this._milkRuns.push({id1:130,id2:250,rating:72});
this._milkRuns.push({id1:162,id2:250,rating:73});
this._milkRuns.push({id1:34,id2:183,rating:74});
this._milkRuns.push({id1:162,id2:183,rating:74});
this._milkRuns.push({id1:137,id2:191,rating:75});
this._milkRuns.push({id1:98,id2:123,rating:75});
this._milkRuns.push({id1:130,id2:108,rating:76});
this._milkRuns.push({id1:12,id2:81,rating:76});
this._milkRuns.push({id1:213,id2:81,rating:77});
this._milkRuns.push({id1:115,id2:150,rating:78});
this._milkRuns.push({id1:162,id2:149,rating:78});
this._milkRuns.push({id1:254,id2:183,rating:79});
this._milkRuns.push({id1:212,id2:46,rating:80});
this._milkRuns.push({id1:198,id2:31,rating:80});
this._milkRuns.push({id1:254,id2:250,rating:82});
this._milkRuns.push({id1:130,id2:149,rating:82});
this._milkRuns.push({id1:194,id2:88,rating:83});
this._milkRuns.push({id1:198,id2:63,rating:84});
this._milkRuns.push({id1:99,id2:91,rating:84});
this._milkRuns.push({id1:254,id2:149,rating:85});
this._milkRuns.push({id1:99,id2:200,rating:85});
this._milkRuns.push({id1:184,id2:150,rating:86});
this._milkRuns.push({id1:89,id2:87,rating:88});
this._milkRuns.push({id1:249,id2:16,rating:90});
break;
case 5:
this._milkRuns.push({id1:243,id2:57,rating:70});
this._milkRuns.push({id1:243,id2:228,rating:71});
this._milkRuns.push({id1:182,id2:160,rating:71});
this._milkRuns.push({id1:14,id2:249,rating:73});
this._milkRuns.push({id1:240,id2:30,rating:75});
this._milkRuns.push({id1:20,id2:57,rating:75});
this._milkRuns.push({id1:243,id2:231,rating:75});
this._milkRuns.push({id1:243,id2:101,rating:75});
this._milkRuns.push({id1:243,id2:98,rating:76});
this._milkRuns.push({id1:109,id2:57,rating:76});
this._milkRuns.push({id1:243,id2:103,rating:77});
this._milkRuns.push({id1:34,id2:24,rating:78});
this._milkRuns.push({id1:69,id2:167,rating:78});
this._milkRuns.push({id1:144,id2:61,rating:79});
this._milkRuns.push({id1:109,id2:228,rating:79});
this._milkRuns.push({id1:182,id2:167,rating:79});
this._milkRuns.push({id1:240,id2:234,rating:80});
this._milkRuns.push({id1:144,id2:253,rating:81});
this._milkRuns.push({id1:144,id2:97,rating:81});
this._milkRuns.push({id1:109,id2:98,rating:81});
this._milkRuns.push({id1:20,id2:244,rating:81});
this._milkRuns.push({id1:86,id2:131,rating:81});
this._milkRuns.push({id1:109,id2:101,rating:82});
this._milkRuns.push({id1:28,id2:108,rating:82});
this._milkRuns.push({id1:1,id2:108,rating:82});
this._milkRuns.push({id1:115,id2:215,rating:83});
this._milkRuns.push({id1:109,id2:231,rating:83});
this._milkRuns.push({id1:20,id2:103,rating:84});
this._milkRuns.push({id1:1,id2:181,rating:86});
this._milkRuns.push({id1:240,id2:140,rating:88});
this._milkRuns.push({id1:14,id2:113,rating:88});
this._milkRuns.push({id1:144,id2:13,rating:88});
this._milkRuns.push({id1:102,id2:98,rating:88});
this._milkRuns.push({id1:17,id2:108,rating:91});
this._milkRuns.push({id1:6,id2:181,rating:92});
this._milkRuns.push({id1:40,id2:215,rating:94});
this._milkRuns.push({id1:17,id2:181,rating:96});
this._milkRuns.push({id1:50,id2:232,rating:98});
break;
case 6:
this._milkRuns.push({id1:170,id2:105,rating:75});
this._milkRuns.push({id1:170,id2:190,rating:75});
this._milkRuns.push({id1:64,id2:160,rating:75});
this._milkRuns.push({id1:13,id2:160,rating:76});
this._milkRuns.push({id1:6,id2:174,rating:77});
this._milkRuns.push({id1:183,id2:164,rating:79});
this._milkRuns.push({id1:28,id2:223,rating:79});
this._milkRuns.push({id1:119,id2:190,rating:79});
this._milkRuns.push({id1:151,id2:180,rating:80});
this._milkRuns.push({id1:64,id2:81,rating:80});
this._milkRuns.push({id1:55,id2:105,rating:80});
this._milkRuns.push({id1:195,id2:159,rating:80});
this._milkRuns.push({id1:55,id2:190,rating:80});
this._milkRuns.push({id1:86,id2:127,rating:80});
this._milkRuns.push({id1:172,id2:160,rating:81});
this._milkRuns.push({id1:199,id2:233,rating:82});
this._milkRuns.push({id1:151,id2:73,rating:82});
this._milkRuns.push({id1:181,id2:95,rating:83});
this._milkRuns.push({id1:103,id2:58,rating:83});
this._milkRuns.push({id1:71,id2:160,rating:83});
this._milkRuns.push({id1:66,id2:190,rating:84});
this._milkRuns.push({id1:135,id2:80,rating:84});
this._milkRuns.push({id1:23,id2:233,rating:84});
this._milkRuns.push({id1:66,id2:105,rating:84});
this._milkRuns.push({id1:215,id2:95,rating:86});
this._milkRuns.push({id1:247,id2:202,rating:86});
this._milkRuns.push({id1:82,id2:105,rating:87});
this._milkRuns.push({id1:82,id2:190,rating:87});
this._milkRuns.push({id1:172,id2:81,rating:88});
this._milkRuns.push({id1:71,id2:81,rating:88});
this._milkRuns.push({id1:67,id2:209,rating:88});
this._milkRuns.push({id1:23,id2:246,rating:89});
this._milkRuns.push({id1:7,id2:209,rating:89});
this._milkRuns.push({id1:215,id2:133,rating:91});
this._milkRuns.push({id1:183,id2:133,rating:92});
this._milkRuns.push({id1:247,id2:133,rating:93});
this._milkRuns.push({id1:151,id2:5,rating:95});
break;
case 7:
this._milkRuns.push({id1:56,id2:240,rating:70});
this._milkRuns.push({id1:56,id2:170,rating:72});
this._milkRuns.push({id1:82,id2:100,rating:75});
this._milkRuns.push({id1:31,id2:25,rating:77});
this._milkRuns.push({id1:147,id2:121,rating:77});
this._milkRuns.push({id1:41,id2:35,rating:78});
this._milkRuns.push({id1:244,id2:138,rating:78});
this._milkRuns.push({id1:192,id2:133,rating:78});
this._milkRuns.push({id1:151,id2:230,rating:78});
this._milkRuns.push({id1:137,id2:121,rating:80});
this._milkRuns.push({id1:206,id2:25,rating:80});
this._milkRuns.push({id1:232,id2:86,rating:81});
this._milkRuns.push({id1:93,id2:185,rating:81});
this._milkRuns.push({id1:93,id2:196,rating:81});
this._milkRuns.push({id1:192,id2:35,rating:81});
this._milkRuns.push({id1:161,id2:255,rating:82});
this._milkRuns.push({id1:14,id2:25,rating:83});
this._milkRuns.push({id1:110,id2:172,rating:84});
this._milkRuns.push({id1:82,id2:179,rating:84});
this._milkRuns.push({id1:41,id2:233,rating:85});
this._milkRuns.push({id1:251,id2:30,rating:85});
this._milkRuns.push({id1:218,id2:71,rating:89});
this._milkRuns.push({id1:93,id2:186,rating:90});
this._milkRuns.push({id1:206,id2:71,rating:90});
this._milkRuns.push({id1:251,id2:233,rating:90});
this._milkRuns.push({id1:93,id2:92,rating:92});
this._milkRuns.push({id1:232,id2:81,rating:92});
this._milkRuns.push({id1:110,id2:177,rating:93});
this._milkRuns.push({id1:232,id2:252,rating:93});
break
}
// make sure we don't end up with nova systems!
for (var i = this._milkRuns.length - 1; i >= 0; i--) {
var sys1 = System.infoForSystem(galaxyNumber, this._milkRuns[i].id1);
var sys2 = System.infoForSystem(galaxyNumber, this._milkRuns[i].id2);
if (sys1.sun_gone_nova || sys2.sun_gone_nova) {
this._milkRuns.splice(i, 1);
}
}
}
//-------------------------------------------------------------------------------------------------------------
// calculates an array of safe systems with close by dangerous systems
this.$calculateSafeDangerousSystems = function $calculateSafeDangerousSystems() {
this._safeDangerous.length = 0;
for (var i = 0; i < 256; i++) {
var data = {id:i, dangerous:[]};
var sys = System.infoForSystem(galaxyNumber, i);
// is this one of our safe systems (gov >= 5)
if (!sys.sun_gone_nova) {
if (sys.government >= 5) {
var locals = sys.systemsInRange(7);
// any dangerous systems in range?
for (var j = 0; j < locals.length; j++) {
var lcl = locals[j];
if (!lcl.sun_gone_nova && lcl.government <= 2) {
data.dangerous.push(lcl.systemID);
}
}
}
if (data.dangerous.length > 0) {
this._safeDangerous.push(data);
//if (this._debug) log(this.name, "SafeDangerous " + data.id + ", " + data.dangerous);
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
// calculates a series of cross-chart possibilities for couriers
// note: the chart 7 data will probably only have workable data in the [0] element (top left to lower right),
// because the large section of map in the lower left is cut off from the rest of the map
this.$calculateCourierRoutes = function $calculateCourierRoutes() {
this._courierRoutes = [
{point1:[], point2:[]},
{point1:[], point2:[]}
];
for (var i = 0; i <= 255; i++) {
var sys = System.infoForSystem(galaxyNumber, i);
if (sys.coordinates.x < 31 && sys.coordinates.y < 16) this._courierRoutes[0].point1.push(i);
if (sys.coordinates.x > 71 && sys.coordinates.y > 36) this._courierRoutes[0].point2.push(i);
if (sys.coordinates.x < 31 && sys.coordinates.y > 36) this._courierRoutes[1].point1.push(i);
if (sys.coordinates.x > 71 && sys.coordinates.y < 16) this._courierRoutes[1].point2.push(i);
}
/*if (this._debug) {
log(this.name, "route 1 point1:" + this._courierRoutes[0].point1);
log(this.name, "route 1 point2:" + this._courierRoutes[0].point2);
log(this.name, "route 2 point1:" + this._courierRoutes[1].point1);
log(this.name, "route 2 point2:" + this._courierRoutes[1].point2);
}*/
}
//-------------------------------------------------------------------------------------------------------------
// populates the randomShips array with ship names (eg "Cobra Mark III", "Asp Mark II" etc) and their associated role (eg "trader")
// because most of the time we will be working with a data array, and not an actual ship object, we need a way to link
// roles to ship types and ship keys. this routine re-compiles the list of possibilties which we can then use throughout the code.
// the result will be: each role and ship type will have one entry in the list, and the shipKeys element will have a list of
// possible versions of that ship.
this.$loadShipNames = function $loadShipNames() {
//-------------------------------------------------------------------------------------------------------------
// returns the role frequency out of a data string
function getRoleFrequency(roleName, roleData) {
var point1 = roleData.indexOf(roleName) + roleName.length;
var freq = "1"; // default of 1 (ie there is no bracket value)
if (roleData.charAt(point1) === "(") {
// extract the percentage
var point2 = roleData.indexOf(")", point1);
freq = roleData.substring(point1 + 1, point2);
}
return freq;
}
// compile a list of ships/roles
this._randomShips.length = 0;
var cr = this._controlledRoles;
var excl = this._bountyShipKeyExclusions;
for (var i = 0; i < cr.length; i++) {
var shipKeys = Ship.keysForRole(cr[i]);
var freq = "";
if (shipKeys) {
for (var j = 0; j < shipKeys.length; j++) {
var key = shipKeys[j];
// don't include any of these keys
if (excl.indexOf(key) >= 0) continue;
var include = false;
var shipdata = Ship.shipDataForKey(key);
// only alllow ships that don't have any spawning restrictions
// as we could be anywhere when we need to spawn them
if (shipdata.conditions) {
include = false;
} else if (shipdata.condition_script) {
include = false;
} else {
// otherwise we're free to play
include = true;
}
if (include) {
freq = getRoleFrequency(cr[i], shipdata.roles);
// make sure we don't load our "dock" versions of ships
if (key.indexOf("dock_") === -1 && key.indexOf("bounty_") === -1) {
if (this.$objIsInArray(cr[i], this._randomShips) === false) {
this._randomShips.push({role:cr[i], shipKeys:key, frequency:freq});
} else {
this.$addShipKeyToShipType(cr[i], key, freq);
}
}
}
}
} else {
log(this.name, "!!NOTE: No ship keys found for role " + cr[i]);
}
}
}
//-------------------------------------------------------------------------------------------------------------
// adds a key/frequency to a particular role. The key will be used for generating ships on launch
this.$addShipKeyToShipType = function $addShipKeyToShipType(role, shipKey, freq) {
for (var i = 0; i < this._randomShips.length; i++) {
if (this._randomShips[i].role === role) {
this._randomShips[i].shipKeys += "," + shipKey;
this._randomShips[i].frequency += "," + freq;
}
}
}
//-------------------------------------------------------------------------------------------------------------
// returns a pilot object
this.$createPilot = function $createPilot(home) {
var pilot = {};
// create the pilot
pilot["name"] = this.$generateName(); //expandDescription("%N [nom]");
pilot["description"] = "a " + System.infoForSystem(galaxyNumber, home).inhabitant.toLowerCase() + " from " + System.systemNameForID(home); // check
pilot["homeSystem"] = home;
pilot["species"] = System.infoForSystem(galaxyNumber, home).inhabitant.toLowerCase();
return pilot;
}
//-------------------------------------------------------------------------------------------------------------
// select a random ship type key (eg "noshaders_z_groovy_cobra1_india_npc") for a particular the role (eg "trader")
this.$getRandomShipKey = function $getRandomShipKey(role) {
var keylist = "";
var freqlist = "";
for (var i = 0; i < this._randomShips.length; i++) {
if (this._randomShips[i].role === role) {
keylist = this._randomShips[i].shipKeys;
freqlist = this._randomShips[i].frequency;
break;
}
}
if (keylist === "") {
// should never happen...
return "";
}
// the number of elements in these two arrays should match
var items = keylist.split(",");
var freq = freqlist.split(",");
var choice = -1;
do {
choice = Math.floor(Math.random() * items.length);
// will we keep this choice or reset it?
if (Math.random() > parseFloat(freq[choice])) choice = -1;
} while (choice === -1);
var bountyVer = false;
var prefix = "bounty_";
// use SDC's versions if installed
if (this._sdcInstalled) {
if (worldScripts.StationDockControl.$dockVersionExists(items[choice])) {
prefix = "dock_";
bountyVer = true;
}
} else {
if (this.$bountyVersionExists(items[choice])) bountyVer = true;
}
return (bountyVer === true ? prefix : "") + items[choice];
}
//-------------------------------------------------------------------------------------------------------------
// use randomshipnames OXP to generate ship names (if installed) - otherwise just return a blank string (no name)
this.$getRandomShipName = function $getRandomShipName(role) {
var randomShipName = "";
if (this._rsnInstalled) {
if (player.ship) {
try {
if (Ship.roleIsInCategory(role, "oolite-bounty-hunter") || Ship.roleIsInCategory(role, "oolite-assassin") )
randomShipName = worldScripts["randomshipnames"].$randomHunterName(player.ship);
else if (Ship.roleIsInCategory(role, "oolite-pirate"))
randomShipName = worldScripts["randomshipnames"].$randomPirateName(player.ship);
// catch everything else as a trader
if (randomShipName === "")
randomShipName = worldScripts["randomshipnames"].$randomTraderName(player.ship);
}
catch (err) {
log(this.name, "!!ERROR: Unable to get ship name from RSN: " + err);
}
}
if (randomShipName === "" || randomShipName == null) randomShipName = this.$phraseGenShipName();
}
return randomShipName;
}
//-------------------------------------------------------------------------------------------------------------
// if getRandomShipName fails to generate a name, create one using phrasegen
this.$phraseGenShipName = function $phraseGenShipName() {
var mwpg = worldScripts.GNN_PhraseGen; //mw_Cabal_Common_PhraseGen;
var text = mwpg._makePhrase(mwpg.$pool["GNN_NamesShips"]);
return text;
}
//-------------------------------------------------------------------------------------------------------------
// returns the ship type (eg Cobra MkIII) for a given data key
this.$getShipType = function $getShipType(dataKey) {
var info = Ship.shipDataForKey(dataKey);
if (info) {
return info.name;
} else {
return "";
}
}
//-------------------------------------------------------------------------------------------------------------
// checks if the role exists in our array of ships
this.$roleExists = function $roleExists(role) {
var found = false;
for (var i = 0; i < this._randomShips.length; i++) {
if (this._randomShips[i].role === role) {
found = true;
break;
}
}
return found;
}
//-------------------------------------------------------------------------------------------------------------
// checks if the role/ship combinations exists in the array
this.$objIsInArray = function $objIsInArray(role, array) {
if (array != null && array.length > 0) {
for (var i = 0; i < array.length; i++) {
if (array[i].role === role) return true;
}
}
return false;
}
//-------------------------------------------------------------------------------------------------------------
// writes the details of the selected record to the log
this.$writeDataToLog = function $writeDataToLog(record, reason) {
log(this.name, "=========================================================");
log(this.name, reason + ":");
log(this.name, "---------------------------------------------------------");
log(this.name, "Pilot name: " + record.pilotName);
log(this.name, "Pilot description: " + record.pilotDescription);
log(this.name, "Pilot home system: " + record.pilotHomeSystem);
log(this.name, "Pilot species: " + record.pilotSpecies);
log(this.name, "Current system: " + record.system);
log(this.name, "Destination: " + record.destinationSystem);
log(this.name, "Dock time: " + clock.clockStringForTime(record.dockTime));
log(this.name, "Departure time: " + clock.clockStringForTime(record.departureTime));
log(this.name, "Ship name: " + record.shipName);
log(this.name, "Ship type: " + record.shipType);
log(this.name, "Ship dataKey: " + record.shipDataKey);
log(this.name, "Ship personality: " + record.personality);
log(this.name, "Primary role: " + record.primaryRole);
log(this.name, "AI name: " + record.shipAI);
log(this.name, "Accuracy: " + record.accuracy);
//log(this.name, "Equipment: " + record.equipment);
log(this.name, "Bounty: " + record.realBounty);
log(this.name, "Escorts: " + record.escorts);
log(this.name, "Escort role: " + record.escortsRole);
log(this.name, "Array index: " + record.arrayIndex);
log(this.name, "Movement: " + record.movement);
log(this.name, "Last visible system:" + record.lastVisibleSystem);
log(this.name, "Last visible dest: " + record.lastVisibleDestination);
log(this.name, "Updated: " + clock.clockStringForTime(record.updated));
log(this.name, "Update chance: " + record.updateChance);
log(this.name, "---------------------------------------------------------");
if (record.system === system.ID || record.destinationSystem === system.ID) {
if (this._debug) log(this.name, "!!NOTE: Ship is in or coming to current system!");
}
}
//-------------------------------------------------------------------------------------------------------------
this.$wormholePos = function $wormholePos() {
var v = Vector3D.randomDirection().multiply(2000 + Math.random() * 3000);
if (v.z < 0 && Math.abs(v.x) + Math.abs(v.y) < 1000) {
v.z = -v.z; // avoid collision risk with witchbuoy
}
return v;
}
//-------------------------------------------------------------------------------------------------------------
// pushes details from the data array onto a launched ship
this.$updateShip = function $updateShip(ship, shipData) {
var scn = worldScripts.BountySystem_WarrantScanner;
scn.$setBounty(ship, shipData.realBounty);
// push all the stored data onto the ship;
if (oolite.compareVersion("1.80") < 0) {
ship.entityPersonality = shipData.personality; // can only do this in Oolite 1.81 or greater
}
ship.primaryRole = shipData.primaryRole;
ship.accuracy = shipData.accuracy;
ship.heatInsulation = shipData.heatInsulation;
ship.setBounty(shipData.bounty, "setup actions");
ship.shipUniqueName = shipData.shipName;
ship.homeSystem = shipData.pilotHomeSystem;
ship.destinationSystem = shipData.destinationSystem;
ship.fuel = shipData.fuel;
// set the seed values so that the pilot's species can be defined by their home system
var seed = "0 0 0 0 " + shipData.pilotHomeSystem.toString() + " 2";
// todo: check what happens to "species"
if (shipData.pilotDescription != "") {
ship.setCrew({name:shipData.pilotName, origin:shipData.pilotHomeSystem,
bounty:0, short_description:shipData.pilotDescription, random_seed:seed});
} else {
ship.setCrew({name:shipData.pilotName, origin:shipData.pilotHomeSystem,
bounty:0, random_seed:seed});
}
// if we have goods defined (but not 'cargo')
if (shipData.goods != "" && (!shipData.cargo || shipData.cargo === "")) {
// put some cargo in the hold
ship.setCargoType(shipData.goods);
}
if (shipData.equipment != "") {
// process all the equipment additions
var items = shipData.equipment.split(",");
for (var j = 0; j < items.length; j++) {
var itm = items[j];
if (itm.indexOf(":") >= 0) {
var subitems = itm.split(":");
switch (subitems[0]) {
case "X":
ship.removeEquipment(subitems[1]);
break;
case "FORE":
if (ship.autoWeapons === true) ship.forwardWeapon = subitems[1];
break;
case "AFT":
if (ship.autoWeapons === true) ship.aftWeapon = subitems[1];
break;
case "PORT":
if (ship.autoWeapons === true) ship.portWeapon = subitems[1];
break;
case "STARBOARD":
if (ship.autoWeapons === true) ship.starboardWeapon = subitems[1];
break;
}
} else {
if (itm != "") {
ship.awardEquipment(itm);
}
}
}
}
// set the ai of the ship (if required)
if (shipData.shipAI != "") ship.switchAI(shipData.shipAI);
ship.script._mostWanted = shipData.index;
}
//-------------------------------------------------------------------------------------------------------------
// return the display list entry for a particular index
this.$getDisplayData = function $getDisplayData(idx) {
for (var i = 0; i < this._displayList.length; i++) {
if (this._displayList[i].index === idx) return this._displayList[i];
}
return null;
}
//-------------------------------------------------------------------------------------------------------------
this.$isPending = function $isPending(idx) {
for (var i = 0; i < this._wanted.length; i++) {
if (this._wanted[i].index === idx) return this._wanted[i].pending;
}
return false;
}
//-------------------------------------------------------------------------------------------------------------
this.$newItemIndex = function $newItemIndex() {
var idx = 1;
for (var i = 0; i < this._wanted.length; i++) {
if (this._wanted[i].index >= idx) idx = this._wanted[i].index + 1;
}
return idx;
}
//-------------------------------------------------------------------------------------------------------------
// returns true if a "bounty_shipkey" entry exists in the shipdata.plist file. Otherwise false
// used when launching/adding ships to the system to ensure that only 1 ship is created, without escorts
// escorts are created manually
this.$bountyVersionExists = function $bountyVersionExists(shipKey) {
var shipdata = Ship.shipDataForKey("bounty_" + shipKey);
if (shipdata) {
return true;
} else {
return false;
}
}
this.$testData = function $testData() {
// set up a dummy type 3
var syslist = system.info.systemsInRange(4);
var list = [];
for (var i = 0; i < syslist.length; i++) {
list.push(syslist[i].systemID);
}
this._safeDangerous.push({id:system.ID, dangerous:list});
// create a record
var s_type = 4;
var dta = {};
dta.index = this.$newItemIndex();
// bounty between 250 and 15200
dta.realBounty = parseInt(Math.random() * 100 + 250) + ((parseInt(Math.random() * 250) + 200) * Math.pow(3, s_type - 4));
dta.bounty = 60 + (Math.floor(Math.random() * 8)) + Math.floor(Math.random() * 8);
dta.pending = false;
// build a ship
var def_role = "pirate";
var role = "";
switch (s_type) {
case 4:
role = "pirate";
dta.escortsRole = "pirate";
break;
case 5:
role = "pirate-light-freighter";
dta.escortsRole = "pirate-light-fighter";
break;
case 6:
role = "pirate-medium-freighter";
dta.escortsRole = "pirate-medium-fighter";
break;
case 7:
role = "pirate-heavy-freighter";
dta.escortsRole = "pirate-heavy-fighter";
break;
}
if (this.$roleExists(role) === false) role = def_role;
dta.shipAI = "oolite-pirateFreighterAI.js";
var found = false;
do {
dta.shipDataKey = this.$getRandomShipKey(role);
var shipPlist = Ship.shipDataForKey(dta.shipDataKey);
dta.shipType = shipPlist.name;
// make sure this is a serious pirate (not a bug or hognose)
if (shipPlist.max_cargo >= 20 + (s_type - 4) * 20) found = true;
} while (found === false);
dta.shipName = this.$getRandomShipName(role);
dta.personality = Math.floor(Math.random() * 32767);
dta.primaryRole = role;
dta.accuracy = s_type;
dta.heatInsulation = 2;
switch (s_type) {
case 4:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER";
break;
case 5:
dta.equipment = "FORE:EQ_WEAPON_BEAM_LASER,AFT:EQ_WEAPON_BEAM_LASER,EQ_CLOAKING_DEVICE";
break;
case 6:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_BEAM_LASER,EQ_CLOAKING_DEVICE";
break;
case 7:
dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_MILITARY_LASER,EQ_CLOAKING_DEVICE";
break;
}
dta.equipment += ",EQ_ESCAPE_POD";
dta.escorts = ((s_type - 3) * 2); // 2, 4, 6 or 8
this.$addEscortsToData(dta);
// create a pilot, picking a random system as home
var pilot = this.$createPilot(Math.floor(Math.random() * 256));
dta.pilotDescription = pilot.description;
dta.pilotName = pilot.name;
dta.pilotHomeSystem = pilot.homeSystem;
dta.pilotSpecies = pilot.species;
// where are they now, and where are they headed?
// pick a safe/dangerous element, start them in the safe one
dta.arrayIndex = this._safeDangerous.length - 1;
dta.movement = 3; // star-type movement (if there is more than 1 dangerous system against the safe one, otherwise same as a milkrun)
var sd = this._safeDangerous[dta.arrayIndex];
dta.system = sd.id; //sd.dangerous[0];
dta.destinationSystem = sd.dangerous[0]; //sd.id;
// when did they dock?
dta.dockTime = clock.adjustedSeconds - 3600; // (3600 * 10.5);
// when will they leave dock?
dta.departureTime = clock.adjustedSeconds + (3600 * 4.5); //(3600 * 8.5);
// arrival time in new system will be departureTime + travelTime(time between systems) + extraTime(random flight time)
// is their current position visible to GalCop?
dta.updateChance = (s_type - 3) / 5;
if (Math.random() > 0) {
dta.lastVisibleSystem = dta.system;
dta.lastVisibleDestination = dta.destinationSystem;
dta.updated = dta.dockTime;
} else {
dta.lastVisibleSystem = -1;
}
dta.lastVisibleHistory = [2];
if (this._debug) this.$writeDataToLog(dta, "Creating special record");
this._wanted.push(dta);
}
//-------------------------------------------------------------------------------------------------------------
// determines whether there is room to launch a certain number of ships
this.$launchAvailable = function $launchAvailable(station, ships) {
if (station) {
var subent = station.subEntities;
var space = 0;
var queued = 0;
if (subent) {
for (var i = 0; i < subent.length; i++) {
if (subent[i].isDock) {
space += 16 - subent[i].launchingQueueLength;
queued += subent[i].launchingQueueLength;
}
}
} else {
if (this._debug) log(this.name, "!NOTE: $launchAvailable -- subent is null (no subentities on station), could not find dock, returning false");
}
if (queued === 0 && space === 0 && this._debug) log(this.name, "!NOTE: $launchAvailable -- no queued ships but space is 0 - no docks found?");
return (space >= ships);
} else {
if (this._debug) log(this.name, "!ERROR: $launchAvailable -- station is null, defaulting to false");
return false;
}
}
//-------------------------------------------------------------------------------------------------------------
this.$updateManifest = function $updateManifest() {
var b = worldScripts.BountySystem_Core;
var markDeleted = [];
var textData = [];
if (this._constantUpdates === true) this.$updateDisplayList();
textData.push("Most Wanted:");
for (var i = 0; i < this._missionList.length; i++) {
var dta = this.$getDisplayData(this._missionList[i]);
if (dta) {
var sys = System.infoForSystem(galaxyNumber, dta.lastVisibleSystem);
var rt = system.info.routeToSystem(sys, player.ship.routeMode);
var rt2 = sys.routeToSystem(System.infoForSystem(galaxyNumber, dta.lastVisibleDestination), dta.routeMode);
var rt3 = system.info.routeToSystem(System.infoForSystem(galaxyNumber, dta.lastVisibleDestination), player.ship.routeMode);
var dist = 0;
var jmps = 0;
if (rt) {
if (player.ship.equipmentStatus("EQ_HUNTER_LICENCE") === "EQUIPMENT_OK" && dta.departureTime < clock.adjustedSeconds && rt3) {
dist = rt3.distance;
jmps = rt3.route.length - 1;
} else {
dist = rt.distance;
jmps = rt.route.length - 1;
}
} else {
dist = system.info.distanceToSystem(sys);
}
//(this.$isPending(dta.index) ? "• " : "") +
var text = dta.pilotName + ", bounty of " + formatCredits(dta.bounty, false, true) + ", flying a " + dta.shipType +
(this._rsnInstalled === true ? " called \"" + dta.shipName + "\"" : "") + ", ";
if (player.ship.equipmentStatus("EQ_HUNTER_LICENCE") === "EQUIPMENT_OK" && dta.departureTime < clock.adjustedSeconds && rt3) {
var arr = -1;
// if there is a route to the target, calc their arrival time
if (rt2) {
arr = dta.departureTime + (rt2.time * 3600);
}
text += "due in " + System.systemNameForID(dta.lastVisibleDestination) + " " +
"(" + dist.toFixed(1) + "ly" + (jmps > 0 ? ", " + jmps + " jump" + (jmps > 1 ? "s" : "") : "") + ") ";
// if there is a route to the target, add some additional info to the manifest
if (arr >= 0) {
if (arr > clock.adjustedSeconds) {
text += "in " + b.$getTimeSince(clock.adjustedSeconds - (arr - clock.adjustedSeconds), false) + ".";
} else {
text += b.$getTimeSince(arr, false) + " ago.";
}
}
} else {
text += "last seen in " + System.systemNameForID(dta.lastVisibleSystem) + " " +
"(" + dist.toFixed(1) + "ly" + (jmps > 0 ? ", " + jmps + " jump" + (jmps > 1 ? "s" : "") : "") + ") " +
b.$getTimeSince(dta.updated, false) + " ago.";
}
// make sure the mission text will fit on the display by breaking up the text into screen-width columns
var coltext = b.$columnText(text, 30);
for (var j = 0; j < coltext.length; j++) {
textData.push((j === 0 ? "" : " ") + coltext[j]);
}
} else {
// if we don't get any data back, mark this record for deletion
markDeleted.push(i);
}
}
// update the manifest
if (textData.length === 1) {
mission.setInstructions(null, this.name);
} else {
mission.setInstructions(textData, this.name);
}
// clean up any deleted records
for (var i = 0; i < markDeleted.length; i++) {
this._missionList.splice(markDeleted[i], 1);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$generateName = function $generateName() {
var mwpg = worldScripts.GNN_PhraseGen; //mw_Cabal_Common_PhraseGen;
var text = mwpg._makePhrase(mwpg.$pool["GNN_Names"]);
return text;
}
//-------------------------------------------------------------------------------------------------------------
this.$askWaitTime = function $askWaitTime() {
var text = expandDescription("[mw_waittime_question]");
var curChoices = {};
for (var i = 1; i <= 12; i++) {
curChoices["02_WAIT_" + (i < 10 ? "0" : "") + i + "~" + i] = {text:"Wait " + i + " hour" + (i === 1 ? "" : "s"), color:this._menuColor}
}
var def = "99_CLOSE";
curChoices["99_CLOSE"] = {text:"[galcop-exit]", color:this._exitColor};
var opts = {
screenID: "oolite-galcopsecoffice-wait-map",
title: "Most Wanted - Details",
overlay: {name:"mw-clock.png", height:546},
allowInterrupt: false,
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
mission.runScreen(opts, this.$askWaitHandler, this);
}
//-------------------------------------------------------------------------------------------------------------
this.$askWaitHandler = function $askWaitHandler(choice) {
if (!choice) return;
if (choice.indexOf("02_WAIT") >= 0) {
var wait = parseInt(choice.substring(choice.indexOf("~") + 1));
clock.addSeconds(wait * 3600);
// if the station dock control is installed, tell it to check for launched ships
if (worldScripts.StationDockControl) {
var w = worldScripts.StationDockControl;
if (w._disable === false) {
w.$checkForLaunchedShips();
}
}
this.dayChanged();
player.consoleMessage(wait + " hour" + (wait === 1 ? " has" : "s have") + " elapsed.");
}
worldScripts.BountySystem_Core.$showSecOffice();
}
//-------------------------------------------------------------------------------------------------------------
// by cag for speed improvements instead of using "indexOf"
this.$indexInList = function $indexInList(item, list) { // for arrays only
var k = list.length;
while( k-- ) {
if( list[k] === item ) return k;
}
return -1;
}
//-------------------------------------------------------------------------------------------------------------
// appends space to currentText to the specified length in 'em'
this.$padTextRight = function $padTextRight(currentText, desiredLength, leftSwitch) {
if (currentText == null) currentText = "";
var hairSpace = String.fromCharCode(31);
var ellip = "…";
var currentLength = defaultFont.measureString(currentText);
var hairSpaceLength = defaultFont.measureString(hairSpace);
// calculate number needed to fill remaining length
var padsNeeded = Math.floor((desiredLength - currentLength) / hairSpaceLength);
if (padsNeeded < 1) {
// text is too long for column, so start pulling characters off
var tmp = currentText;
do {
tmp = tmp.substring(0, tmp.length - 2) + ellip;
if (tmp === ellip) break;
} while (defaultFont.measureString(tmp) > desiredLength);
currentLength = defaultFont.measureString(tmp);
padsNeeded = Math.floor((desiredLength - currentLength) / hairSpaceLength);
currentText = tmp;
}
// quick way of generating a repeated string of that number
if (!leftSwitch || leftSwitch === false) {
return currentText + new Array(padsNeeded).join(hairSpace);
} else {
return new Array(padsNeeded).join(hairSpace) + currentText;
}
}
//-------------------------------------------------------------------------------------------------------------
// appends space to currentText to the specified length in 'em'
this.$padTextLeft = function $padTextLeft(currentText, desiredLength) {
return this.$padTextRight(currentText, desiredLength, true);
}
//-------------------------------------------------------------------------------------------------------------
// creates/updates hunter tips array
this.$createTips = function $createTips(pendingOnly) {
for (var i = 0; i < this._wanted.length; i++) {
var item = this._wanted[i];
if ((item.pending === true && (pendingOnly === true || Math.random() > (Math.random() * 0.3))) || (pendingOnly === false && Math.random() > (Math.random() * 0.5 + 0.5))) {
var tipster = this._hunterTipSources[Math.floor(Math.random() * this._hunterTipSources.length)];
// will this be an accurate tip?
var accurate = (Math.random() <= tipster.reliability ? true : false);
if (item.pending === true) {
// find the pending record
for (var j = 0; j < this._pending.length; j++) {
var pend = this._pending[j];
if (pend.index === item.index) {
var txt = "";
var tiptyp = 0;
var sysName = system.name;
if (accurate) {
switch (pend.type) {
case "docked":
tiptyp = 2;
txt = this.$generateTip(2, item.pilotName, item.shipType, sysName, (pend.station.indexOf("Rock") === -1 ? "the main station" : "a Rock Hermit"));
break;
case "witchpoint":
tiptyp = 1;
txt = this.$generateTip(1, item.pilotName, item.shipType, sysName, "");
break;
}
} else {
// create an inaccurate wp or docked message (it might still end up being accurate, but we won't know for sure)
var stn = "";
if (Math.random() > tipster.reliability) {
var sysList = System.infoForSystem(galaxyNumber, item.system).systemsInRange(7);
sysName = sysList[Math.floor(Math.random() * sysList.length)].name;
}
if (Math.random() > 0.5) {
// docked
stn = (Math.random() > 0.5 ? "the main station" : "a Rock Hermit");
tiptyp = 2;
} else {
// wp
tiptyp = 1;
}
txt = this.$generateTip(tiptyp, item.pilotName, item.shipType, sysName, stn);
}
if (this.$tipCountForBounty(item.index, tiptyp) > 2) continue;
if (this._debug) log(this.name, "checking pending " + tiptyp + " " + pend.type + " - " + txt);
// create message
this._hunterTips.push({
createdDate:clock.adjustedSeconds - (Math.floor(Math.random() * 21600)),
text:txt,
bountyName:item.pilotName,
index:item.index,
source:tipster.name,
system:system.ID,
expireDate:clock.adjustedSeconds + (86400 * 5),
type:tiptyp
});
break;
}
}
} else {
var id = -1;
if (accurate) {
// create an accurate ship spotted message
id = item.system;
} else {
// create an inaccurate ship spotted message
var sysList = System.infoForSystem(galaxyNumber, item.system).systemsInRange(7);
id = sysList[Math.floor(Math.random() * sysList.length)].ID;
}
var txt = this.$generateTip(0, item.pilotName, item.shipType, System.systemNameForID(id), "")
if (this._debug) log(this.name, "checking non pending " + txt);
// create message
this._hunterTips.push({
createdDate:item.dockTime + (Math.floor(Math.random() * 21600)),
text:txt,
bountyName:item.pilotName,
index:item.index,
source:tipster.name,
system:id,
expireDate:item.dockTime + (86400 * 5),
type:0,
});
}
}
}
// Finally, delete any tips older than 5 days
for (var i = this._hunterTips.length - 1; i >= 0; i--) {
if ((clock.adjustedSeconds - this._hunterTips[i].createdDate) / 86400 > 5) {
this._hunterTips.splice(i, 1);
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$tipCountForBounty = function $tipCountForBounty(idx, type) {
var count = 0;
for (var i = 0; i < this._hunterTips.length; i++) {
if (this._hunterTips[i].index === idx && this._hunterTips[i].type === type) count += 1;
}
return count;
}
//-------------------------------------------------------------------------------------------------------------
this.$removeTipForBounty = function $removeTipForBounty(idx, type) {
for (var i = this._hunterTips.length -1; i >= 0; i--) {
if (this._hunterTips[i].index === idx && this._hunterTips[i].type === type) {
this._hunterTips.splice(i, 1);
return;
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$createTipSources = function $createTipSources() {
var tot = Math.floor(Math.random() * 20 + 10);
for (var i = 0; i < tot; i++) {
this._hunterTipSources.push({name:this.$generateName(), reliability:Math.random() * 30 + 70});
}
}
//-------------------------------------------------------------------------------------------------------------
this.$generateTip = function $generateTip(tipType, bountyName, shipType, systemName, stationName) {
switch (tipType) {
case 0: // seen in location
var def = {
fieldA: ["I have it on good authority that","There are rumours that","Information has come to light indicating","My sources are telling me that","News from the underground says that","According to my best sources,","FYI,","News flash:","A word to the wise:","For those who are interested,","It's come to my attention that","Be aware that","It's probably worth noting that"],
fieldB: ["bandit","brigand","criminal","crook","desperado","fugitive","gangster","hijacker","hooligan","lawbreaker","marauder","mobster","murderer","psychopath","sinner","sociopath","outlaw","pirate","plunderer","racketeer","raider","ravager","renegade","robber","vagabond","villain"],
fieldC: ["seen","spotted","identified","noticed","recognised","observed","glimpsed","spied"],
fieldD: [" recently"],
fieldE: ["flying around in a","cruising around in a","flying a","flying in a"],
fieldF: [" tricked out"," shiny","n upgraded"," renovated","n above-spec","n over-clocked","n illegally modified"," fully kitted out","n iron-ass"," heavily modified"," seriously upgraded"," ferocious"],
fieldG: [", according to [8]",", based on [8]"],
fieldH: ["recent information","the latest information","data from reliable sources",],
fieldI: ["the \\[system\\] system","\\[system\\]"],
fieldJ: ["During a recent [7]","On a recent [7]","While I was on a recent [7]"],
fieldK: ["bandit","brigand","criminal","crook","desperado","fugitive","gangster","hijacker","hooligan","lawbreaker","marauder","mobster","murderer","psychopath","sinner","sociopath","outlaw","pirate","plunderer","racketeer","raider","ravager","renegade","robber","vagabond","villain"],
fieldL: ["through","in"],
fieldM: ["see","spot","notice","identify","recognise","observe","glimpse","spy"],
fieldN: ["happened to [4]","[6]"],
fieldO: ["saw","spotted","identified","noticed","recognised","observed","glimpsed","spied"],
fieldP: ["trip","journey","voyage"],
fieldQ: ["on my way","passing","going","travelling","heading"],
fieldR: [],
sentences: [
"1 (D50=the [2] |)\\[name\\] was4 3 in 9, 56 \\[shiptype\\].",
"1 (D50=the [2] |)\\[name\\], 56 \\[shiptype\\], was4 3 in 9.",
"1 (D50=the [2] |)\\[name\\] was4 3 in 9.",
"1 (D50=the [2] |)\\[name\\] was 34 in 9, 56 \\[shiptype\\].",
"1 (D50=the [2] |)\\[name\\], 56 \\[shiptype\\], was 34 in 9.",
"1 (D50=the [2] |)\\[name\\] was 34 in 9.",
"(D60=the [2] |)\\[name\\] has been4 3 in 9, 56 \\[shiptype\\].",
"(D60=the [2] |)\\[name\\], 56 \\[shiptype\\], has been4 3 in 9.",
"(D60=the [2] |)\\[name\\] has been4 3 in 9.",
"(D60=the [2] |)\\[name\\] has been 34 in 9, 56 \\[shiptype\\].",
"(D60=the [2] |)\\[name\\], 56 \\[shiptype\\], has been 34 in 9.",
"(D60=the [2] |)\\[name\\] has been 34 in 9.",
"(D60=the [2] |)\\[name\\] has been4 3 in 97, 56 \\[shiptype\\].",
"(D60=the [2] |)\\[name\\], 56 \\[shiptype\\], has been4 3 in 97.",
"(D60=the [2] |)\\[name\\] has been4 3 in 97.",
"(D60=the [2] |)\\[name\\] has been 34 in 97, 56 \\[shiptype\\].",
"(D60=the [2] |)\\[name\\], 56 \\[shiptype\\], has been 34 in 97.",
"(D60=the [2] |)\\[name\\] has been 34 in 97.",
"{1 3 }9, I {5 (D50=the [2] |)\\[name\\], }56 \\[shiptype\\].",
"I was {8 through }94, and {5 (D50=the [2] |)\\[name\\], }56 \\[shiptype\\]."
]
};
break;
case 1: // witchpoint
var def = {
fieldA: ["I have it on good authority that","There are rumours that","Information has come to light indicating","My sources are telling me that","News from the underground says that","According to my best sources","FYI,","News flash:","A word to the wise:","For those who are interested,","It's come to my attention that","Be aware that","It's probably worth noting that"],
fieldB: ["is due to [3]","is expected to [3]","will be [4]","is due in","is on their way to","is expected in","is heading for"],
fieldC: ["jump into","jet into","witchjump into","head into","arrive in"],
fieldD: ["jumping into","jetting into","witchjumping into","heading for","arriving in"],
fieldE: ["bandit","brigand","criminal","crook","desperado","fugitive","gangster","hijacker","hooligan","lawbreaker","marauder","mobster","murderer","psychopath","sinner","sociopath","outlaw","pirate","plunderer","racketeer","raider","ravager","renegade","robber","vagabond","villain"],
fieldF: [" tricked out"," shiny","n upgraded"," renovated","n above-spec","n over-clocked","n illegally modified"," fully kitted out","n iron-ass"," heavily modified"," seriously upgraded"," ferocious"],
fieldG: [", according to [8]"],
fieldH: ["recent information","the latest information","reliable sources"],
fieldI: ["the \\[system\\] system","\\[system\\]"],
fieldJ: ["real soon","any time now","really soon","at any moment","in next to no time","faster than you can say \"[2]\""],
fieldK: ["Braben lied","It's a trap","That's one doomed space marine","It's not my fault","Use the force, Luke","Punch it","We're going in full throttle","I thought they smelled bad on the outside","Geronimo","Phasers on stun","Kobayashi Maru"],
fieldL: ["in a","flying a","piloting a"],
fieldM: [],
fieldN: [],
fieldO: [],
fieldP: [],
fieldQ: [],
fieldR: [],
sentences: [
"1 (D50=the [5] |)\\[name\\] 2 9 {1, 3}6 \\[shiptype\\].",
"1 (D50=the [5] |)\\[name\\] 2 9 {1, 3 \\[shiptype\\].",
"1 (D50=the [5] |)\\[name\\], {3}6 \\[shiptype\\], 2 9 {1.",
"1 (D50=the [5] |)\\[name\\], {3 \\[shiptype\\], }2 9 {1.",
"1 (D50=the [5] |)\\[name\\] 2 9 {1.",
"(D60=the [5] |)\\[name\\] 2 97, {3}6 \\[shiptype\\].",
"(D60=the [5] |)\\[name\\] 2 97, {3 \\[shiptype\\].",
"(D60=the [5] |)\\[name\\], {3}6 \\[shiptype\\], 2 97.",
"(D60=the [5] |)\\[name\\], {3 \\[shiptype\\], }2 97.",
"(D60=the [5] |)\\[name\\] 2 97.",
"(D60=the [5] |)\\[name\\] 2 9 {1, 3}6 \\[shiptype\\].",
"(D60=the [5] |)\\[name\\] 2 9 {1, 3 \\[shiptype\\].",
"(D60=the [5] |)\\[name\\], {3}6 \\[shiptype\\], 2 9 {1.",
"(D60=the [5] |)\\[name\\], {3 \\[shiptype\\], }2 9 {1.",
"(D60=the [5] |)\\[name\\] 2 9 {1."
],
};
break;
case 2: // docked at station
var def = {
fieldA: ["I have it on good authority that","There are rumours that","Information has come to light indicating","My sources are telling me that","News from the underground says that","According to my best sources","FYI,","News flash:","A word to the wise:","For those who are interested,","It's come to my attention that","Be aware that","It's probably worth noting that"],
fieldB: ["bandit","brigand","criminal","crook","desperado","fugitive","gangster","hijacker","hooligan","lawbreaker","marauder","mobster","murderer","psychopath","sinner","sociopath","outlaw","pirate","plunderer","racketeer","raider","ravager","renegade","robber","vagabond","villain"],
fieldC: ["heading for","flying to","on their way to"],
fieldD: [],
fieldE: ["in a","flying a","piloting a"],
fieldF: [" tricked out"," shiny","n upgraded"," renovated","n above-spec","n over-clocked","n illegally modified"," fully kitted out","n iron-ass"," heavily modified"," seriously upgraded"," ferocious"],
fieldG: [", according to [8]"],
fieldH: ["recent information","the latest information","reliable sources"],
fieldI: ["the \\[system\\] system","\\[system\\]"],
fieldJ: [],
fieldK: [],
fieldL: [],
fieldM: [],
fieldN: [],
fieldO: [],
fieldP: [],
fieldQ: [],
fieldR: [],
sentences: [
"1 (D50=the [2] |)\\[name\\] is 3 \\[stationtype\\] in 9, 5 \\[shiptype\\].",
"1 (D50=the [2] |)\\[name\\] is 3 \\[stationtype\\] in 9, 56 \\[shiptype\\].",
"1 (D50=the [2] |)\\[name\\], 5 \\[shiptype\\], is 3 \\[stationtype\\] in 9.",
"1 (D50=the [2] |)\\[name\\], 56 \\[shiptype\\], is 3 \\[stationtype\\] in 9.",
"1 (D50=the [2] |)\\[name\\] is 3 \\[stationtype\\] in 9.",
"(D50=the [2] |)\\[name\\] is 3 \\[stationtype\\] 56 \\[shiptype\\]7.",
"(D50=the [2] |)\\[name\\] is 3 \\[stationtype\\] 5 \\[shiptype\\]7.",
"(D50=the [2] |)\\[name\\], 5 \\[shiptype\\], is 3 \\[stationtype\\]7.",
"(D50=the [2] |)\\[name\\], 56 \\[shiptype\\], is 3 \\[stationtype\\]7.",
"(D50=the [2] |)\\[name\\] is 3 \\[stationtype\\]7."
],
};
break;
}
var text = worldScripts.GNN_PhraseGen._makePhrase(def);
return expandDescription(this.$cleanUp(text), {name:bountyName, shiptype:shipType, system:systemName, stationtype:stationName});
}
//-------------------------------------------------------------------------------------------------------------
this.$cleanUp = function $cleanUp(text) {
// remove any of the \ chars that prefix any [ and ] chars
text = text.replace(/\\\[/g, "[");
text = text.replace(/\\\]/g, "]");
// look for any \n operatives, and replace them with an actual new line
text = text.replace(/\\n/g, String.fromCharCode(13) + String.fromCharCode(10));
text = text.replace(/\[mission/g, "[mission_");
return text;
}
//-------------------------------------------------------------------------------------------------------------
this.$switchMissiles = function $switchMissiles(ship) {
var done = false;
do {
if (ship.equipmentStatus("EQ_MISSILE") === "EQUIPMENT_OK" && Math.random() > 0.5) {
ship.removeEquipment("EQ_MISSILE");
ship.awardEquipment("EQ_HARDENED_MISSILE");
} else {
done = true;
}
} while (done === false);
}
//-------------------------------------------------------------------------------------------------------------
this.$revealMap = function $revealMap() {
this._holdConcealment = [];
this._unconcealmentActive = true;
if (this._debug) log(this.name, "system map uncovered");
for (var i = 0; i < 256; i++) {
var sys = System.infoForSystem(galaxyNumber, i);
var c = 0;
if (sys.concealment) c = sys.concealment;
this._holdConcealment.push(c);
if (c != 0) sys.setProperty(2, "concealment", 0);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$restoreMap = function $restoreMap() {
if (this._holdConcealment.length === 0) return;
for (var i = 0; i < this._holdConcealment.length; i++) {
var sys = System.infoForSystem(galaxyNumber, i);
if (this._holdConcealment[i] != 0) sys.setProperty(2, "concealment", this._holdConcealment[i]);
}
if (this._debug) log(this.name, "system map restored");
this._unconcealmentActive = false;
} |