Scripts/equipstorage.js |
"use strict";
this.name = "EquipmentStorage";
this.author = "phkb";
this.copyright = "2019 phkb";
this.description = "Handles the process of storing equipment items for reuse later";
this.licence = "CC BY-NC-SA 4.0";
// TODO: Allow storage of missiles
this._noStore = ["EQ_BREAKABLE_TORUSDRIVE", "EQ_BREAKABLE_HUD_IFF_SCANNER", "EQ_IRONHIDE"];
this._allowedIgnored = ["EQ_SCANNER_SHOW_MISSILE_TARGET", "EQ_MULTI_TARGET", "EQ_ADVANCED_NAVIGATIONAL_ARRAY", "EQ_INTEGRATED_TARGETING_SYSTEM",
"EQ_TARGET_MEMORY", "EQ_SMUGGLING_PHASE_ADJUSTMENT", "EQ_SDC_HACK_CHIP", "EQ_IG_INSURANCE", "EQ_IG_LEGAL_HACK", "EQ_LMSS_ACTUATOR",
"EQ_ESCORTCONTRACTS", "EQ_TEA_MAKER", "EQ_TEAPOT", "EQ_COMMSLOGMFD", "EQ_COMMSLOGMFD_PASSIVE", "EQ_BROADCASTCOMMSMFD", "EQ_DAMAGE_REPORT_MFD",
"EQ_DAMAGE_REPORT_MFD_PASSIVE", "EQ_COMBATMFD", "EQ_NAVIGATION_MFD", "EQ_APRIL_INVENTORY", "EQ_APRIL_TRANSFER", "EQ_APRIL_UNLOAD",
"EQ_AMS_1", "EQ_AMS_2", "EQ_AMS_3", "EQ_AMS_4", "EQ_GLARE_FILTER", "EQ_AMS_5", "EQ_AMS_6", "EQ_AUTO_EJECT", "EQ_BOUNTY_INFORMER", "EQ_CARGOSPOTTER",
"EQ_ELITE_RANK", "EQ_RESERVE_TANK_EMPTY", "EQ_AUX_TANK_EMPTY", "EQ_WEAPON_GATLING_LASER_COOLER", "EQ_HUDSELECTOR", "EQ_MARKET_INQUIRER_MFD",
"EQ_TROPHY_MFD", "EQ_UPS_IDCLEANER", "EQ_MULTIPASS", "EQ_MULTIPASSED_ID", "EQ_HARDWIRE_ORE_PROCESSOR", "EQ_TARGETSELECTOR",
"EQ_TARGETSELECTOR_MODECHANGER", "EQ_SHIPS_CAT_1", "EQ_SHIPS_CAT_2", "EQ_SHIPS_CAT_3", "EQ_SHIPS_CAT_4", "EQ_SHIPS_CAT_5", "EQ_SHIPS_CAT_6",
"EQ_SHIPS_CAT_7", "EQ_SHIPS_CAT_8", "EQ_SHIPS_CAT_9", "EQ_CTE_TRADERNET", "EQ_CAMERA_DRONES", "EQ_WPH_ASC_UPGRADE", "EQ_POLICE_SCANNER_UPGRADE",
"EQ_Q-CHARGER_MESS", "EQ_REPAIRBOTS_RECHARGE", "EQ_SAFETYCATCH", "EQ_SAFETY_MINE", "EQ_SCANNER_ALERTING_ENHANCEMENT", "EQ_HYPER_RADIO",
"EQ_HYPER_RADIO_ADD", "EQ_HYPER_RADIO_PIRATE", "EQ_ILS", "EQ_WEAPON_LASER_COOLER", "EQ_MANIFEST_MFD", "EQ_SC_MANUAL_CONFIGURATOR_BASIC",
"EQ_SC_MANUAL_CONFIGURATOR_STANDARD", "EQ_SC_MANUAL_CONFIGURATOR_ADVANCED", "EQ_TARGET_AUTOLOCK", "EQ_ENEMY_TARGETER_UPGRADE",
"EQ_TELESCOPEEXT", "EQ_TORUSTOSUN", "EQ_TRACKER", "EQ_TRACKERCAM_LINK", "EQ_TWS_GALACTICSATNAV", "EQ_WELCOME_MAT", "EQ_GAL_DRIVE_MOD",
"EQ_SALON_CONTROL", "EQ_SNIPER_SCOPE", "EQ_SYSTEM_MARKET_WATCH", "EQ_AUTOECM", "EQ_GALAXY_INFO", "EQ_LONG_RANGE_SCANNER_JUMP",
"EQ_RETICLE_TARGET_SENSITIVE", "EQ_MANIF_SCANNERX", "EQ_MC_DESCRAMBLER", "EQ_MURPH_THARGOID_DRIVE_TOFIT", "EQ_ENEMY_TARGETER_UPGRADE",
"EQ_SNIPERLOCK", "EQ_MFD_FAST_CONFIG", "EQ_GCM_COMMS_RELAY_SWITCH", "EQ_GCM_CARGO_STOPPER", "EQ_GCM_EJECTION_DAMPER", "EQ_GCM_UNPROCESSED_SCAN_DATA",
"EQ_GCM_SOFTWARE", "EQ_GCM_STOLEN_SCHEMATICS", "EQ_GCM_STOLEN_CODES", "EQ_GCM_STOLEN_DOCUMENTS", "EQ_GCM_STOLEN_WEAPONDESIGNS",
"EQ_RRS_FLIGHTFORM", "EQ_RRS_ESCORT_TARGETING_SYSTEM", "EQ_RRS_ESCORT_TARGETING_SYSTEM_WAYSTATION",
"EQ_NS_MINING_SCANNER_UPGRADE", "EQ_NS_SCANNER_SCAVENGER_HACK", "EQ_TRAIL_DETECTOR"
];
this._storage = []; // main array holding storage information
this._sc_core = null; // link to shipconfig core functions
this._compNames = ["KennOords Storage", "BulkStor", "RentaSpace", "Storage King", "HOowards Storage World",
"%H Self Storage", "Galactic Storage", "StoreIt Self Storage", "Systemwide Storage", "Safe-n-Sound",
"Premier Storage Solutions", "TopShelf Storage", "HandiStor", "SpaceWays Self Storage", "B&B Stor-More", "OO-Haul Storage"
];
this._salesRep = ""; // holds a string containing the name of the local sales rep
this._page = 0; // controls which page of information will be displayed
this._lastChargeDate = 0; // date player was last charged for storage
this._display = 0; // controls which display will be shown on the interface screen
this._displayType = 0; // 0 = current location only, 1 = all locations
this._selectedItem = ""; // currently selected item
this._lastChoice = ["", "", "", "", "", "", "", "", ""]; // players last choice on each of the displays
this._lastChoiceStore = "";
this._lastSource = -1; // used to establish the start point for destination system calculations
this._commodities = []; // stores a list of installed commodity keys
this._storedPrices = []; // stores a copy of any sample prices so the player always gets the same answer
this._establishmentFee = 100;
this._disabled = false;
this._menuColor = "orangeColor"; // color of general menu items
this._itemColor = "yellowColor"; // color of special menu items (eg exit menu items)
this._damagedColor = "redColor"; // color of damaged equipment items
this._installedColor = "greenColor"; // color of installed equipment items
this._riskColor = "0.8 0.8 0.8 1"; // color of risky transit items
this._refundPct = 0.85; // value between 0 and 1 that indicates how much refund you get on equipment sold. 0 = no refund, 1 = refund full original price
this._NCInstalled = false;
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
if (worldScripts.ShipConfiguration_Core) this._sc_core = worldScripts.ShipConfiguration_Core;
if (this._disabled) {
delete this.playerWillSaveGame;
delete this.shipWillDockWithStation;
delete this.playerEnteredNewGalaxy;
delete this.dayChanged;
delete this.playerBoughtEquipment;
delete this.playerBoughtNewShip;
delete this.reportScreenEnded;
delete this.missionScreenEnded;
delete this.startUpComplete;
return;
}
// add a mission screen exception to Xenon UI
if (worldScripts.XenonUI) {
var wx = worldScripts.XenonUI;
wx.$addMissionScreenException("oolite-storage-shortrangechart-map");
wx.$addMissionScreenException("oolite-storage-longrangechart-map");
}
// add a mission screen exception to Xenon Redux UI
if (worldScripts.XenonReduxUI) {
var wxr = worldScripts.XenonReduxUI;
wxr.$addMissionScreenException("oolite-storage-shortrangechart-map");
wxr.$addMissionScreenException("oolite-storage-longrangechart-map");
}
if (worldScripts.DisplayCurrentCourse) {
var dcc = worldScripts.DisplayCurrentCourse;
dcc._screenIDList.push("oolite-storage-shortrangechart-map");
dcc._screenIDList.push("oolite-storage-longrangechart-map");
}
if (worldScripts.CargoTypeExtension) this._NCInstalled = true;
// pull in the values from ShipConfig vars, if loading for the first time after the split
if (missionVariables.ShipConfig_EquipStorage) {
this._storage = JSON.parse(missionVariables.ShipConfig_EquipStorage);
this.$addExtraField();
delete missionVariables.ShipConfig_EquipStorage;
}
if (missionVariables.ShipConfig_LastChargeDate) {
this._lastChargeDate = missionVariables.ShipConfig_LastChargeDate;
delete missionVariables.ShipConfig_LastChargeDate;
}
// otherwise, we'll get our own versions
if (missionVariables.EquipmentStorage_Data) {
this._storage = JSON.parse(missionVariables.EquipmentStorage_Data);
delete missionVariables.EquipmentStorage_Data;
}
if (missionVariables.EquipmentStorage_LastChargeDate) {
this._lastChargeDate = missionVariables.EquipmentStorage_LastChargeDate;
}
this.$initInterface(player.ship.dockedStation);
this._lastSource = system.ID;
var keys = Object.keys(system.mainStation.market);
for (var i = 0; i < keys.length; i++) {
this._commodities.push(keys[i]);
}
this.$compileSamplePrices();
// if shipconfig is present, point our nostore list at shipconfig's nosell list
if (this._sc_core) this._noStore = this._noStore.concat(this._sc_core._noSell);
// include shipversions placeholder equipment items
if (worldScripts.shipversion) {
for (var i = 75; i <= 100; i++) {
this._noStore.push("EQ_SERVICE_LEVEL_" + i.toString());
}
for (var i = 10; i <= 100; i++) {
this._noStore.push("EQ_SHIP_VERSION_" + i.toString());
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function () {
if (this._storage.length > 0) {
missionVariables.EquipmentStorage_Data = JSON.stringify(this._storage);
} else {
delete missionVariables.EquipmentStorage_Data;
}
missionVariables.EquipmentStorage_LastChargeDate = this._lastChargeDate;
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation = function (station) {
this.$initInterface(station);
this.$checkForArrivals();
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillLaunchFromStation = function (station) {
this._lastSource = system.ID;
}
//-------------------------------------------------------------------------------------------------------------
this.shipExitedWitchspace = function () {
// update the lastSource ID
if (system.ID != -1) this._lastSource = system.ID;
this.$compileSamplePrices();
}
//-------------------------------------------------------------------------------------------------------------
this.playerEnteredNewGalaxy = function (galaxyNumber) {
// any in transit items will be transported to their destinations - a galjump freebee
for (var i = 0; i < this._storage.length; i++) {
if (this._storage[i].inTransit === true) {
this._storage[i].system = this._storage[i].transitDestination;
this._storage[i].systemName = this._storage[i].transitDestinationName;
this._storage[i].inTransit = false;
this._storage[i].transitSystem = -1;
this._storage[i].transitDestination = -1;
this._storage[i].transitETA = 0;
this._storage[i].transitStart = 0;
}
}
this._lastSource = system.ID;
}
//-------------------------------------------------------------------------------------------------------------
this.dayChanged = function () {
// charge the player for storage
if ((clock.seconds - this._lastChargeDate) > 86400) {
this._lastChargeDate = clock.seconds;
var data = this.$storageSystemList();
var abort = false;
var compList = "";
var dropList = {};
var totalRefund = 0;
var totalCost = 0;
var keys = Object.keys(data);
for (var i = 0; i < keys.length; i++) {
var gal = parseInt(keys[i].split("_")[0]);
var sys = parseInt(keys[i].split("_")[1]);
var cost = this.$calculateSystemCost(gal, sys);
var count = this.$storageSystemCount(gal, sys);
if (player.credits > cost) {
player.credits -= cost;
totalCost += cost;
compList += (compList === "" ? "" : "\n") + "- " + formatCredits(cost, false, true) + " for storage of " + count + (count === 1 ? " item" : " items") + " in the " + data[keys[i]] + " system" +
(galaxyNumber != gal ? " (G" + (gal + 1) + ")" : "");
} else {
// refund half the cost of the items in storage, then remove them
abort = true;
var refund = 0;
for (var j = this._storage.length - 1; j >= 0; j--) {
var item = this._storage[j];
if (item.galaxy === gal && item.system === sys) {
if (item.equipmentKey != "") {
var info = EquipmentInfo.infoForKey(item.equipmentKey);
if (info.effectiveTechLevel > 14) {
refund += 1000;
} else {
refund += (info.price / 10) * 0.5;
}
}
if (item.commodity != "") {
refund += ((system.mainStation.market[item.commodity].price / 10) * item.weight) * 0.5;
}
}
this._storage.splice(j, 1);
}
totalRefund += refund
dropList[keys[i]] = {
galaxy: gal,
system: sys,
systemName: data[keys[i]],
refund: refund,
count: count
};
}
}
// send a refund email, if required
if (abort === true && totalRefund > 0) {
player.credits += totalRefund;
// give the player an email, if installed
var ga = worldScripts.GalCopAdminServices;
if (ga) {
var email = worldScripts.EmailSystem;
var keys = Object.keys(dropList);
for (var i = 0; i < keys.length; i++) {
var item = dropList[keys[i]];
var msg = expandDescription("[storeequip-cancelled]", {
systemname: item.systemName,
galaxy: (parseInt(item.galaxy) === galaxyNumber ? "" : " (G" + item.galaxy + ")"),
count: item.count,
refund: formatCredits(item.refund, true, true)
});
if (item.galaxy != galaxyNumber) {
email.$createEmail({
sender: expandDescription(this._compNames[item.system % 16]),
subject: "Storage Cancelled",
date: global.clock.seconds,
message: msg,
expiryDays: ga._defaultExpiryDays
});
} else {
email.$createEmail({
sender: expandDescription(this._compNames[item.system % 16]),
subject: "Storage Cancelled",
date: global.clock.seconds,
sentFrom: item.system,
message: msg,
expiryDays: ga._defaultExpiryDays
});
}
}
}
}
// send a confirmation email, if required
if (compList.length > 0 && totalCost > 0) {
// give the player an email, if installed
var ga = worldScripts.GalCopAdminServices;
if (ga) {
var email = worldScripts.EmailSystem;
var msg = expandDescription("[storeequip-dailycost]", {
cost: formatCredits(totalCost, true, true),
costdetails: compList
});
email.$createEmail({
sender: "Storage Facility",
subject: "Storage payment",
date: global.clock.seconds,
message: msg,
expiryDays: ga._defaultExpiryDays
});
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerBoughtEquipment = function (equipment) {
this.$checkForArrivals();
}
//-------------------------------------------------------------------------------------------------------------
this.playerBoughtNewShip = function (ship) {
this.$checkForArrivals();
}
//-------------------------------------------------------------------------------------------------------------
this.reportScreenEnded = this.missionScreenEnded = function () {
this.$checkForArrivals();
}
//-------------------------------------------------------------------------------------------------------------
this.$addExtraField = function() {
if (this._storage.length == 0) return;
for (var i = 0; i < this._storage.length; i++) {
if (!this._storage[i].hasOwnProperty("extra")) this._storage[i].extra = "";
}
}
//-------------------------------------------------------------------------------------------------------------
// mission screen for displaying list of equipment that can be stored
this.$storeEquipment = function $storeEquipment() {
function compare(a, b) {
return b.space - a.space;
}
var p = player.ship;
var stn = p.dockedStation;
var used = 0;
var maxspace = 0;
if (this._sc_core) {
used = this._sc_core.$calcEquipmentSpace(p);
maxspace = Math.ceil(this._sc_core.$equipmentSpaceTotal(p) + this._sc_core.$cargoSpaceAvailable(p));
}
var interrupt = true;
var spc = String.fromCharCode(31) + String.fromCharCode(31) + String.fromCharCode(31);
var text = "";
var curChoices = {};
var itemcount = 0;
var pagesize = 15;
if (!this._sc_core) pagesize += 5;
this._hudHidden = p.hudHidden;
if (this.$isBigGuiActive() === false) p.hudHidden = true;
if (this._sc_core) this._sc_core._configScreen = true;
var enabled = true;
if (this.$storageSystemCount(galaxyNumber, system.ID) === 0 && player.credits < this._establishmentFee) enabled = false;
// display the list of options
if (used > maxspace) {
// make sure we don't lock the player in during flight
if (p.alertCondition === 0) {
interrupt = false; // set to false to force the player to sell equipment before continuing
}
if (this._sc_core) {
curChoices["98_SWITCH"] = {
text: "[sc-change-config]",
color: this._itemColor
};
pagesize -= 1;
}
curChoices["99_EXIT"] = {
text: "[storage-return]",
color: this._disabledColor,
unselectable: true
};
} else {
curChoices["99_EXIT"] = {
text: "[storage-return]",
color: this._itemColor
};
if (this._sc_core) this._sc_core._initialSetup = false;
}
text += this.$pageHeader();
if (this._sc_core) {
text += this.$padTextRight(expandDescription("[storage-equipment-title]"), 16) +
this.$padTextLeft((this._sc_core ? "Equip" : " "), 4) +
this.$padTextLeft(" ", 4) +
this.$padTextLeft("Storage", 8) + "\n";
} else {
var addText = " ";
if (stn.isMainStation === true && this.$storageSystemCount(galaxyNumber, system.ID) === 0) {
addText += expandDescription("[storage-deposit-required]", {
fee: formatCredits(this._establishmentFee, false, true)
});
}
text += this.$padTextRight(addText, 24) +
this.$padTextLeft("Storage", 8) + "\n";
}
text += this.$padTextRight("Equipment Item", 16) +
this.$padTextLeft((this._sc_core ? "space" : " "), 4) +
this.$padTextLeft((this._sc_core ? "Weight" : " "), 4) +
this.$padTextLeft("Cost", 8) + "\n\n";
var eq = p.equipment;
var list = [];
for (var i = 0; i < eq.length; i++) {
var item = eq[i];
// exclusions
// don't include "no store" items
if (this._noStore.indexOf(item.equipmentKey) >= 0) continue;
if (this._sc_core) {
// boosters can't be included either
if (this._sc_core._boosters.indexOf(item.equipmentKey) >= 0) continue;
// nor can armour
if (this._sc_core._armour.indexOf(item.equipmentKey) >= 0) continue;
// nor can extensions
if (this._sc_core._extensions.indexOf(item.equipmentKey) >= 0) continue;
}
// we can't store smuggling compartments, because we can't reliably reinstall them later
// storage facilities only exist at main stations, but smuggling compartments can only be installed at non-main stations
if (item.equipmentKey.indexOf("EQ_SMUGGLING_COMPARTMENT") >= 0) continue;
// don't include any items in the ignore equipment list that aren't specially allowed
if (this._sc_core && this._sc_core._ignoreEquip.indexOf(item.equipmentKey) >= 0 && this._allowedIgnored.indexOf(item.equipmentKey) === -1) continue;
var space = 0;
var weight = 0;
var zeroSpace = 0;
var lookup = null;
if (this._sc_core) lookup = this._sc_core._equipmentMatrix[item.equipmentKey];
if (lookup) {
space = parseFloat(lookup[0]);
weight = parseFloat(lookup[1]);
if (space === 0 && weight === 0) zeroSpace = 1;
} else {
if (item.requiredCargoSpace === 0) {
if (this._allowedIgnored.indexOf(item.equipmentKey) >= 0) {
zeroSpace = 1;
} else {
space = 1;
weight = 1;
}
} else {
weight = item.requiredCargoSpace;
space = weight;
}
}
var colr = this._menuColor;
if (p.equipmentStatus(item.equipmentKey) === "EQUIPMENT_DAMAGED") colr = this._damagedColor;
// special case for armour
if (this._sc_core && this._sc_core._armour.indexOf(item.equipmentKey) >= 0) {
if (p.script._armourFront < 100 || p.script._armourAft < 100) colr = this._damagedColor;
}
if (enabled === false) colr = this._disabledColor;
if (item.isVisible && item.requiresEmptyPylon === false && this.$equipmentIsRequired(item.equipmentKey) === false && (!this._sc_core || (space > 0 || weight > 0 || zeroSpace === 1))) {
// any items in the negotiate list will show as "???" in the cost column
// if the player chooses to sell this item he will have to negotiate a price
var loop = 1;
// special case for passenger berths - only 1 item is in the equipment list, but you could have multiple installed
if (item.equipmentKey === "EQ_PASSENGER_BERTH") loop = p.passengerCapacity;
for (var j = 1; j <= loop; j++) {
list.push({
eq: item.equipmentKey,
space: space,
weight: weight,
cost: this.$calculateStorageCost(space, weight),
color: colr,
name: (item.equipmentKey === "EQ_PASSENGER_BERTH" ? "Passenger Berth" : item.name),
section: ""
});
}
}
}
// laser weapons
var lmss = worldScripts.LMSS_Core;
var section = ["Forward", "Aft", "Port", "Starboard", "Forward - Secondary", "Aft - Secondary", "Port - Secondary", "Starboard - Secondary"];
for (var i = 0; i < 7; i++) {
var key = "";
var damage = false;
switch (i) {
case 0:
key = p.forwardWeapon.equipmentKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["FORWARD"].primary;
damage = true;
}
break;
case 1:
key = p.aftWeapon.equipmentKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["AFT"].primary;
damage = true;
}
break;
case 2:
key = p.portWeapon.equipmentKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["PORT"].primary;
damage = true;
}
break;
case 3:
key = p.starboardWeapon.equipmentKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["STARBOARD"].primary;
damage = true;
}
break;
case 4:
if (lmss) {
key = lmss._forwardAltKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["FORWARD"].secondary;
damage = true;
}
}
break;
case 5:
if (lmss) {
key = lmss._aftAltKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["AFT"].secondary;
damage = true;
}
}
break;
case 6:
if (lmss) {
key = lmss._portAltKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["PORT"].secondary;
damage = true;
}
}
break;
case 7:
if (lmss) {
key = lmss._starboardAltKey;
if (key == "EQ_WEAPON_DAMAGED_LASER") {
key = worldScripts.BreakableLasers_Main._holdDamage["STARBOARD"].secondary;
damage = true;
}
}
break;
}
if (key !== "" && key !== "EQ_WEAPON_NONE") {
var item = EquipmentInfo.infoForKey(key);
var space = 1; // for storage purposes, it's always 1t
var weight = 0;
var zeroSpace = 0;
if (this._sc_core) {
var lookup = this._sc_core._equipmentMatrix[item.equipmentKey];
if (lookup) {
space = parseFloat(lookup[0]);
if (space === 0) space = 1;
weight = parseFloat(lookup[1]);
} else {
weight = 1;
}
} else {
weight = 1;
}
colr = this._menuColor;
if (damage) colr = this._damagedColor;
list.push({
eq: item.equipmentKey,
space: space,
weight: weight,
cost: this.$calculateStorageCost(space, weight),
color: colr,
name: item.name + " (" + section[i] + ")",
section: i
});
}
}
if (list.length > 0) {
list.sort(compare);
var maxpage = Math.ceil(list.length / pagesize);
if (maxpage < (this._page + 1)) this._page -= 1;
var end = ((this._page * pagesize) + pagesize);
if (end > list.length) end = list.length;
// note: then station equipmentPriceFactor has been removed to prevent exploitation of equipment sales at different stations (galcop => rock hermit)
for (var i = (this._page * pagesize); i < end; i++) {
curChoices["01_EQUIP-" + (i < 10 ? "0" : "") + i + "~" + list[i].eq + (list[i].section !== "" ? "|" + list[i].section : "")] = {
text: this.$padTextRight(list[i].name, 16) +
this.$padTextLeft((this._sc_core ? list[i].space.toFixed(1) + spc + "t" : " "), 4) +
this.$padTextLeft((this._sc_core ? list[i].weight.toFixed(1) + spc + "t" : " "), 4) +
(list[i].cost === "???" ? this.$padTextLeft("???", 8) :
this.$padTextLeft(formatCredits((list[i].cost), true, true) + "/d", 8)), //* stn.equipmentPriceFactor
alignment: "LEFT",
unselectable: !enabled,
color: list[i].color
};
itemcount += 1;
}
for (var i = 0; i < ((pagesize + 1) - itemcount); i++) {
curChoices["90_SPACER_" + i] = "";
}
} else {
text += expandDescription("[storage-none-to-store]");
}
if (maxpage > 1 && this._page < (maxpage - 1)) {
curChoices["95_NEXT"] = {
text: "[storage-nextpage]",
color: this._itemColor
};
} else {
curChoices["95_NEXT"] = {
text: "[storage-nextpage]",
color: this._disabledColor,
unselectable: true
};
}
if (this._page > 0) {
curChoices["96_PREV"] = {
text: "[storage-prevpage]",
color: this._itemColor
};
} else {
curChoices["96_PREV"] = {
text: "[storage-prevpage]",
color: this._disabledColor,
unselectable: true
};
}
var def = "99_EXIT";
if (this._lastChoiceStore != "") def = this._lastChoiceStore;
var opts = {
screenID: "oolite-storage-equipment-map",
title: "Store Equipment",
allowInterrupt: interrupt,
exitScreen: (this._sc_core ? this._sc_core._sellEquipExitScreen : "GUI_SCREEN_INTERFACES"),
choices: curChoices,
initialChoicesKey: def,
message: text
};
if (this._sc_core) this._sc_core.$addShipModelToScreen(opts);
mission.runScreen(opts, this.$storeEquipmentScreenHandler, this);
if (this._sc_core) this._sc_core.$finaliseShipModel();
}
//-------------------------------------------------------------------------------------------------------------
// handles menu selection on store equipment screen
this.$storeEquipmentScreenHandler = function $storeEquipmentScreenHandler(choice) {
if (!choice) return;
var p = player.ship;
var stn = p.dockedStation;
this._lastChoiceStore = choice;
if (choice.indexOf("01_EQUIP") >= 0) {
var item = choice.substring(choice.indexOf("~") + 1);
var section = ""
// check for a laser position
if (item.indexOf("|") >= 0) {
section = item.split("|")[1];
item = item.split("|")[0];
}
var info = EquipmentInfo.infoForKey(item);
var space = 0;
var weight = 0;
if (section === "") {
var dam = p.equipmentStatus(item);
var lookup = null;
if (this._sc_core) lookup = this._sc_core._equipmentMatrix[info.equipmentKey];
if (lookup) {
space = parseFloat(lookup[0]);
weight = parseFloat(lookup[1]);
if (space === 0 && info.requiredCargoSpace > 0) space = info.requiredCargoSpace;
} else {
if (info.requiredCargoSpace === 0) {
if (this._allowedIgnored.indexOf(info.equipmentKey) === -1) {
space = 1;
weight = 1;
}
} else {
weight = info.requiredCargoSpace;
space = weight;
}
}
// special case for passenger berths
if (item === "EQ_PASSENGER_BERTH") {
var creds = player.credits;
p.awardEquipment("EQ_PASSENGER_BERTH_REMOVAL");
p.credits = creds;
} else {
p.removeEquipment(item);
}
if (item.indexOf("EQ_LMSS") >= 0) {
// if we've removed all the positions, then remove the activator as well
if (p.equipmentStatus("EQ_LMSS_FRONT") != "EQUIPMENT_OK" && p.equipmentStatus("EQ_LMSS_AFT") != "EQUIPMENT_OK" &&
p.equipmentStatus("EQ_LMSS_PORT") != "EQUIPMENT_OK" && p.equipmentStatus("EQ_LMSS_STARBOARD") != "EQUIPMENT_OK") {
p.removeEquipment("EQ_LMSS_ACTIVATOR");
}
worldScripts.LMSS_Core.$resetInterface();
}
if (this._sc_core) this._sc_core._current = {};
var idx = this.$countItemAtStation(item);
// for some reason passenger berths report as unavailable
if (item === "EQ_PASSENGER_BERTH" && dam === "EQUIPMENT_UNAVAILABLE") dam = "EQUIPMENT_OK";
} else {
// weapons are removed from specific locations
var lookup = null;
if (this._sc_core) lookup = this._sc_core._equipmentMatrix[item];
if (lookup) {
space = parseFloat(lookup[0]);
if (space === 0) space = 1;
weight = parseFloat(lookup[1]);
} else {
space = 1;
weight = 1;
}
var dam = "EQUIPMENT_OK"; // lasers can't be damaged
var lmss = worldScripts.LMSS_Core;
var bl = worldScripts.BreakableLasers_Main;
switch (section) {
case "0":
if (p.forwardWeapon.equipmentKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["FORWARD"].primary = "";
dam = "EQUIPMENT_DAMAGED";
}
p.forwardWeapon = "EQ_WEAPON_NONE";
break;
case "1":
if (p.aftWeapon.equipmentKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["AFT"].primary = "";
dam = "EQUIPMENT_DAMAGED";
}
p.aftWeapon = "EQ_WEAPON_NONE";
break;
case "2":
if (p.portWeapon.equipmentKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["PORT"].primary = "";
dam = "EQUIPMENT_DAMAGED";
}
p.portWeapon = "EQ_WEAPON_NONE";
break;
case "3":
if (p.starboardWeapon.equipmentKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["STARBOARD"].primary = "";
dam = "EQUIPMENT_DAMAGED";
}
p.starboardWeapon = "EQ_WEAPON_NONE"
break;
case "4":
if (lmss._forwardAltKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["FORWARD"].secondary = "";
dam = "EQUIPMENT_DAMAGED";
}
lmss._forwardAltKey = "EQ_WEAPON_NONE";
p.removeEquipment("EQ_LMSS_FRONT_WEAPON");
break;
case "5":
if (lmss._aftAltKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["AFT"].secondary = "";
dam = "EQUIPMENT_DAMAGED";
}
lmss._aftAltKey = "EQ_WEAPON_NONE";
p.removeEquipment("EQ_LMSS_AFT_WEAPON");
break;
case "6":
if (lmss._portAltKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["PORT"].primary = "";
dam = "EQUIPMENT_DAMAGED";
}
lmss._portAltKey = "EQ_WEAPON_NONE";
p.removeEquipment("EQ_LMSS_PORT_WEAPON");
break;
case "7":
if (lmss._starboardAltKey == "EQ_WEAPON_DAMAGED_LASER") {
bl._holdDamage["STARBOARD"].primary = "";
dam = "EQUIPMENT_DAMAGED";
}
lmss._starboardAltKey = "EQ_WEAPON_NONE";
p.removeEquipment("EQ_LMSS_STARBOARD_WEAPON");
break;
}
if (lmss) lmss.$updateManifest();
if (bl) bl.$updateManifest();
var idx = this.$countItemAtStation(item);
// once stored, they will become just standard lasers, not allocated to any specific position on the ship
// positions will be confirmed when lasers are re-installed
}
// charge player deposit
if (this.$storageSystemCount(galaxyNumber, system.ID) === 0) {
player.credits -= this._establishmentFee;
player.consoleMessage(formatCredits(this._establishmentFee, false, true) + " deducted to open storage facility account", 5);
}
this._storage.push({
galaxy: galaxyNumber,
system: system.ID,
systemName: system.name,
equipmentKey: item,
commodity: "",
space: space,
weight: weight,
status: dam,
index: idx,
inTransit: false,
transitETA: 0,
transitDestination: -1,
transitSystem: -1,
transitStart: 0
});
// give the player an email, if installed
var ga = worldScripts.GalCopAdminServices;
if (ga) {
var email = worldScripts.EmailSystem;
var storeName = expandDescription(this._compNames[system.ID % 16]);
if (this.$storageSystemCount(galaxyNumber, system.ID) === 0) {
// email T&C's
}
// were we charged something, or did we get a refund?
var cost = "This item will be stored here at a rate of " + formatCredits(this.$calculateStorageCost(space, weight), true, true) + " per day.";
var msg = expandDescription("[storeequip-email]", {
storagename: storeName,
equipname: info.name,
equipcost: cost,
sender: this.$salesRep()
});
email.$createEmail({
sender: storeName,
subject: "Storing equipment",
date: global.clock.adjustedSeconds,
message: msg,
expiryDays: ga._defaultExpiryDays
});
}
if (this._sc_core) this._sc_core.$addEquipmentSpaceItem(p);
}
if (choice === "95_NEXT") this._page += 1;
if (choice === "96_PREV") this._page -= 1;
if (choice === "98_SWITCH") {
this._sc_core._source = "";
this._sc_core.$shipConfig();
return;
}
if (this._sc_core && this._sc_core._source === "REMOVEITEM") return;
if (choice != "99_EXIT") {
this.$storeEquipment();
return;
}
if (choice === "99_EXIT") {
if (this._sc_core) {
if (this._sc_core._source === "CONFIGSCREEN") {
this._sc_core._source = "";
this._sc_core.$shipConfig();
}
return;
}
this.$viewStoredItems();
}
}
//-------------------------------------------------------------------------------------------------------------
// initialise the equipment specification list
this.$initInterface = function $initInterface(station) {
// no access in interstellar space
if (system.ID === -1) {
station.setInterface(this.name, null);
return;
}
if (this.$stationHasStorageFacilities(station) === true) {
station.setInterface(this.name, {
title: "Storage facility management",
category: "Station Interfaces",
summary: "Lists any equipment or cargo you have stored at this station or in other systems.",
callback: this.$openStorageListing.bind(this)
});
} else {
station.setInterface(this.name, {
title: "Storage facility information",
category: "Station Interfaces",
summary: "Lists any equipment or cargo you have stored at the main station or in other systems.",
callback: this.$openStorageListing.bind(this)
});
}
}
//-------------------------------------------------------------------------------------------------------------
this.$openStorageListing = function $openStorageListing() {
this._page = 0;
this._display = 0;
this._displayType = 0;
this.$viewStoredItems();
}
//-------------------------------------------------------------------------------------------------------------
// views mission screen showing currently stored equipment
this.$viewStoredItems = function $viewStoredItems() {
function compare(a, b) {
return (b.sort > a.sort ? -1 : 1);
}
var p = player.ship;
var stn = p.dockedStation;
var text = "";
var curChoices = {};
var itemcount = 0;
var list = [];
var pagesize = 20;
this._hudHidden = p.hudHidden;
if (this.$isBigGuiActive() === false) p.hudHidden = true;
if (this._sc_core) this._sc_core._configScreen = true;
// main list
if (this._display === 0) {
pagesize = 19;
text += expandDescription(this._compNames[system.ID % 16]) + " Facility Management" + (p.dockedStation.isMainStation === true ? "" : " (at Main Station)") + "\n\n";
text += this.$padTextRight(expandDescription("Item"), 16) +
this.$padTextRight("Location", 10) +
this.$padTextLeft("Cost", 6) + "\n";
for (var i = 0; i < this._storage.length; i++) {
if (this._displayType === 1 || (this._storage[i].galaxy === galaxyNumber && this._storage[i].system === system.ID) || this._storage[i].inTransit === true) {
if (this._storage[i].equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(this._storage[i].equipmentKey);
if (equip) { // only display equipment items that are currently installed (in case an OXP is removed)
var colr = this._menuColor;
if (this._storage[i].galaxy === galaxyNumber && this._storage[i].system === system.ID) colr = this._installedColor;
if (this._storage[i].status === "EQUIPMENT_DAMAGED") colr = this._damagedColor;
if (this._storage[i].galaxy != galaxyNumber) colr = "blueColor";
if (this._storage[i].inTransit === true) colr = this._riskColor;
var info = null;
var dist = 0;
if (this._storage[i].galaxy === galaxyNumber && this._storage[i].system != system.ID && this._storage[i].system >= 0) {
info = System.infoForSystem(galaxyNumber, this._storage[i].system);
var route = system.info.routeToSystem(info);
if (route && route.route.length > 0) dist = route.distance;
}
list.push({
equipmentName: "Equipment: " + (equip.equipmentKey === "EQ_PASSENGER_BERTH" ? "Passenger Berth" : equip.name),
location: (this._storage[i].inTransit === false ? this._storage[i].systemName + " " + (info != null ? "(dist: " + dist.toFixed(1) + "ly)" : (this._storage[i].galaxy != galaxyNumber ? "(G" + (this._storage[i].galaxy + 1) + ")" : "")) : "In transit"),
cost: formatCredits(this.$calculateStorageCost(this._storage[i].space, this._storage[i].weight), true, true) + " / day",
equipmentKey: this._storage[i].equipmentKey,
commodity: "",
galaxy: this._storage[i].galaxy,
system: this._storage[i].system,
color: colr,
sort: this._storage[i].galaxy + "_" + this._storage[i].systemName + "_" + equip.name,
id: this._storage[i].galaxy + "|" + this._storage[i].system + "|" + this._storage[i].equipmentKey + "|" + this._storage[i].index
});
}
}
if (this._storage[i].commodity != "" && this._commodities.indexOf(this._storage[i].commodity) >= 0) {
var colr = this._menuColor;
if (this._storage[i].galaxy === galaxyNumber && this._storage[i].system === system.ID) colr = this._installedColor;
if (this._storage[i].galaxy != galaxyNumber) colr = "blueColor";
if (this._storage[i].inTransit === true) colr = this._riskColor;
var info = null;
var dist = 0;
if (this._storage[i].galaxy === galaxyNumber && this._storage[i].system != system.ID && this._storage[i].system >= 0) {
info = System.infoForSystem(galaxyNumber, this._storage[i].system);
var route = system.info.routeToSystem(info);
if (route && route.route.length > 0) dist = route.distance;
}
list.push({
equipmentName: "Cargo: " + this._storage[i].weight + this.$getCommodityUnit(this._storage[i].commodity) + " × " + displayNameForCommodity(this._storage[i].commodity) + (this._storage[i].extra != "" ? "*" : ""),
location: (this._storage[i].inTransit === false ? this._storage[i].systemName + " " + (info != null ? "(dist: " + dist.toFixed(1) + "ly)" : (this._storage[i].galaxy != galaxyNumber ? "(G" + (this._storage[i].galaxy + 1) + ")" : "")) : "In transit"),
cost: formatCredits(this.$calculateStorageCost(this._storage[i].space, this._storage[i].weight, this.$getCommodityUnit(this._storage[i].commodity)), true, true) + " / day",
equipmentKey: "",
commodity: this._storage[i].commodity,
galaxy: this._storage[i].galaxy,
system: this._storage[i].system,
color: colr,
sort: this._storage[i].galaxy + "_" + this._storage[i].systemName + "_zz" + displayNameForCommodity(this._storage[i].commodity), // ensure cargo items come after equipment
id: this._storage[i].galaxy + "|" + this._storage[i].system + "|" + this._storage[i].commodity + "|" + this._storage[i].index
});
}
}
}
if (list.length > 0) {
list.sort(compare);
var maxpage = Math.ceil(list.length / pagesize);
if (maxpage < (this._page + 1)) this._page -= 1;
var end = ((this._page * pagesize) + pagesize);
if (end > list.length) end = list.length;
// note: the station equipmentPriceFactor has been removed to prevent exploitation of equipment sales at different stations (galcop => rock hermit)
for (var i = (this._page * pagesize); i < end; i++) {
curChoices["01_EQUIP-" + (i < 10 ? "0" : "") + i + "~" + list[i].id] = {
text: this.$padTextRight(list[i].equipmentName, 16) +
this.$padTextRight(list[i].location, 10) +
this.$padTextLeft(list[i].cost, 6),
alignment: "LEFT",
color: list[i].color
};
itemcount += 1;
}
for (var i = 0; i < (pagesize - itemcount) + (p.dockedStation.isMainStation === false ? 1 : 0); i++) {
curChoices["90_SPACER_" + i] = "";
}
} else {
text += expandDescription("[storage-equip-none]");
}
if (p.dockedStation.isMainStation === true) {
if (this.$storageSystemCount(galaxyNumber, system.ID) === 0 && player.credits < this._establishmentFee) {
if (!this._sc_core) {
curChoices["96_Z_STOREEQUIP"] = {
text: expandDescription("[storage-store-equipment]") + " (insufficient credits to open account)",
color: this._disabledColor,
unselectable: true
};
}
curChoices["98_MOVECARGO"] = {
text: expandDescription("[storage-move-cargo]") + " (insufficient credits to open account)",
color: this._disabledColor,
unselectable: true
};
} else {
if (!this._sc_core) {
curChoices["96_Z_STOREEQUIP"] = {
text: expandDescription("[storage-store-equipment]"),
color: this._itemColor,
};
}
curChoices["98_MOVECARGO"] = {
text: "[storage-move-cargo]",
color: this._itemColor
};
}
}
if (maxpage > 1 && this._page < (maxpage - 1)) {
curChoices["95_NEXT"] = {
text: "[storage-nextpage]",
color: this._itemColor
};
} else {
curChoices["95_NEXT"] = {
text: "[storage-nextpage]",
color: this._disabledColor,
unselectable: true
};
}
if (this._page > 0) {
curChoices["96_PREV"] = {
text: "[storage-prevpage]",
color: this._itemColor
};
} else {
curChoices["96_PREV"] = {
text: "[storage-prevpage]",
color: this._disabledColor,
unselectable: true
};
}
if (this._displayType === 1) {
curChoices["97_SHOWLOCAL"] = {
text: "[storage-showlocal]",
color: this._itemColor
};
} else {
curChoices["97_SHOWALL"] = {
text: "[storage-showall]",
color: this._itemColor
};
}
curChoices["99_EXIT"] = {
text: "Exit",
color: this._itemColor
};
var def = "99_EXIT";
if (this._lastChoice[this._display] != "") def = this._lastChoice[this._display];
var opts = {
screenID: "oolite-storage-main-map",
title: "Storage - " + (this._displayType === 0 ? "Local" : "All Systems"),
allowInterrupt: true,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
// equipment details
if (this._display === 1) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
}
var info = null;
var dist = 0;
var jumps = 0;
var danger = 0;
var illegal = 0;
var time = 0;
if (item.galaxy === galaxyNumber && item.system != system.ID && item.system >= 0) {
this.$revealMap();
info = System.infoForSystem(galaxyNumber, item.system);
var route = system.info.routeToSystem(info);
jumps = route.route.length;
dist = route.distance;
danger = this.$checkRouteDangerLevel(route);
if (item.commodity != "") illegal = this.$checkRouteIllegalLevel(route, item.commodity);
time = route.time;
this.$restoreMap();
}
if (item.equipmentKey != "") {
text = this.$padTextRight("Equipment item:", 10) + (item.equipmentKey === "EQ_PASSENGER_BERTH" ? "Passenger Berth" : equip.name) + "\n";
text += this.$padTextRight("Equipment status:", 10) + (item.status === "EQUIPMENT_OK" ? "OK" : "Damaged") + "\n";
if (this._sc_core) {
if (parseFloat(item.space) === 0 && parseFloat(item.weight) === 0) {
text += this.$padTextRight("Space/weight:", 10) + "Negligible\n";
} else {
text += this.$padTextRight("Space/weight:", 10) + (parseFloat(item.space) === 0 ? item.weight : item.space) + "t/" + item.weight + "t\n";
}
}
text += this.$padTextRight("Storage cost:", 10) + formatCredits(this.$calculateStorageCost(item.space, item.weight), true, true) + " per day\n";
}
if (item.commodity != "") {
text = this.$padTextRight("Cargo type:", 10) + displayNameForCommodity(item.commodity) + "\n";
if (this._sc_core) {
var spcwt = this.$cargoSpaceRequired(this.$getCommodityUnit(item.commodity), item.weight);
text += this.$padTextRight("Space/weight:", 10) + spcwt + "t/" + item.weight + this.$getCommodityUnit(item.commodity) + "\n";
}
text += this.$padTextRight("Storage cost:", 10) + formatCredits(this.$calculateStorageCost(item.space, item.weight, this.$getCommodityUnit(item.commodity)), true, true) + " per day\n";
if (item.extra != "") {
text += this.$padTextRight("Note:", 10) + item.extra.split(";").length.toString() + this.$getCommodityUnit(item.commodity) + " is from specialty market.\n";
}
}
if (item.system != -1) {
text += this.$padTextRight("Location:", 10) +
item.systemName + " " + (info != null ? "(dist: " + dist.toFixed(1) + "ly)" : (item.galaxy != galaxyNumber ? "(G" + (item.galaxy + 1) + ")" : "")) + "\n";
} else {
text += this.$padTextRight("Location:", 10) + "In transit\n";
var eta = this.$getTimeRemaining(item.transitETA);
text += this.$padTextRight("ETA:", 10) + System.systemNameForID(item.transitDestination) + (eta === "Overdue" ? " - delivery overdue" : " in " + eta) + "\n";
}
var tfrcost = 0;
if (dist > 0) {
tfrcost = this.$calculateTransferCost(dist, jumps, danger, illegal);
text += this.$padTextRight("Transfer cost:", 10) + formatCredits(tfrcost, true, true) + "\n";
text += this.$padTextRight("Transfer time:", 10) + time.toFixed(1) + " hrs\n";
text += this.$padTextRight("Transfer risk:", 10) + expandDescription("[transfer-danger-" + danger + "]") + "\n";
}
if (dist > 7.5) {
curChoices["25_SHOWMAP_LONG"] = {
text: "[storage-showmap]",
color: this._itemColor
};
} else if (dist > 0 && dist <= 7.5) {
curChoices["25_SHOWMAP_SHORT"] = {
text: "[storage-showmap]",
color: this._itemColor
};
}
if (dist > 0 && player.credits >= tfrcost) {
if (item.equipmentKey != "") {
curChoices["26_TRANSFER"] = {
text: "[storage-transfer]",
color: this._itemColor
};
} else if (item.commodity != "") {
curChoices["26_TRANSFER"] = {
text: "[storage-transfer-cargo]",
color: this._itemColor
};
}
}
if (item.inTransit === true) {
curChoices["35_WAIT"] = {
text: "[storage-wait]",
color: this._itemColor
};
}
// can only install items if we're in the same system and at the main station
if (item.galaxy === galaxyNumber && item.system === system.ID && p.dockedStation.isMainStation === true) {
if (item.equipmentKey != "") {
// can we install this item?
var inst = true;
var reason = "";
var curr = p.equipmentStatus(item.equipmentKey);
if (p.canAwardEquipment(item.equipmentKey) === false) {
inst = false;
reason = " (required equipment item not installed or item not permitted)";
}
// special case for shield boosters
//if (item.equipmentKey === "EQ_NAVAL_SHIELD_BOOSTER" && p.equipmentStatus("EQ_SHIELD_BOOSTER") != "EQUIPMENT_OK") {inst = false; reason = " (required equipment item not installed)";}
// if we can't carry multiple versions of it, and we already have one, then no
if (curr === "EQUIPMENT_OK" && equip.canCarryMultiple === false) {
inst = false;
reason = " (already installed)";
}
// reset for laser items
if (item.equipmentKey.indexOf("EQ_WEAPON") >= 0) {
inst = true;
reason = "";
}
// if the current item of the same time is damaged, and so's the one in storage, then nodeName
// (otherwise it can be used to fix the broken one)
if (curr === "EQUIPMENT_DAMAGED" && item.status === "EQUIPMENT_DAMAGED") {
inst = false;
reason = " (both items damaged)";
}
// do we have room for it, or will it put the ship into overload?
var eq = EquipmentInfo.infoForKey(item.equipmentKey);
if (eq.requiredCargoSpace > 0 && p.cargoSpaceAvailable < eq.requiredCargoSpace) {
inst = false;
reason = " (insufficient cargo space)";
}
var lookup = null;
if (this._sc_core) lookup = this._sc_core._equipmentMatrix[item.equipmentKey];
if (lookup) {
var equipSpace = this._sc_core.$availableEquipmentSpace(p);
// subtract the space the existing item is taking up
if (curr === "EQUIPMENT_OK" || curr === "EQUIPMENT_DAMAGED") equipSpace += lookup[0];
if (lookup[0] > equipSpace) {
inst = false;
reason = " (insufficient equipment space)";
}
}
if (inst === true) {
curChoices["30_INSTALL"] = {
text: "[storage-install]",
color: this._itemColor
};
} else {
curChoices["30_INSTALL"] = {
text: expandDescription("[storage-install]" + reason),
color: this._disabledColor,
unselectable: true
};
}
}
if (item.commodity != "") {
// can we transfer any of this cargo into our hold
var inst = true;
var reason = "";
if (p.cargoSpaceAvailable === 0) {
inst = false;
reason = " (insufficient cargo space)";
}
if (inst === true) {
curChoices["31_LOAD"] = {
text: "[storage-load-cargo]",
color: this._itemColor
};
} else {
curChoices["31_LOAD"] = {
text: expandDescription("[storage-load-cargo]" + reason),
color: this._disabledColor,
unselectable: true
};
}
}
}
// work out item cost
if (item.equipmentKey != "") {
if (item.inTransit === false && equip.techLevel <= 14 && item.galaxy === galaxyNumber) {
var sellcost = equip.price / 10 * (item.status === "EQUIPMENT_DAMAGED" ? 0.5 : (item.equipmentKey.indexOf("EQ_WEAPON") >= 0 ? 1 : this._refundPct)); // * factor;
curChoices["70_SELL"] = {
text: expandDescription("[storage-sell]", {
cost: formatCredits(sellcost, true, true)
}),
color: this._itemColor
};
}
}
if (item.commodity != "") {
// can only sell stored cargo when you're in the same system
if (item.inTransit === false && item.galaxy === galaxyNumber) {
var pcsfee = 1;
var maxqty = item.weight;
var sellcost = 0;
var price = 0;
if (item.system === system.ID) {
if ((item.weight + system.mainStation.market[item.commodity].quantity) > 127) {
maxqty = 127 - system.mainStation.market[item.commodity].quantity;
}
// 10% price penalty for selling remotely
if (p.dockedStation.isMainStation === false) pcsfee = 0.9;
price = (system.mainStation.market[item.commodity].price / 10) * pcsfee;
} else {
if (item.weight + Math.floor(system.scrambledPseudoRandomNumber(77) * 127) > 127) {
maxqty = 127 - Math.floor(system.scrambledPseudoRandomNumber(77) * 127);
}
// price will be 20% less than the sample price
pcsfee = 0.8;
price = this.$getSamplePrice(item.system, item.commodity) * pcsfee;
}
// only show the sell option if we can sell something
if (maxqty > 0) {
sellcost = price * maxqty;
curChoices["71_SELL"] = {
text: expandDescription("[storage-sell]", {
cost: maxqty + this.$getCommodityUnit(item.commodity) + (item.extra != "" ? "*" : "") + " @ " + price.toFixed(1) +
", total " + formatCredits(sellcost, true, true) +
(pcsfee < 1 ? " incl " + ((1 - pcsfee) * 100).toFixed(0) + "% process fee" : "")
}),
color: this._itemColor
};
} else {
curChoices["71_SELL"] = {
text: "[storage-nosell]",
color: this._disabledColor,
unselectable: true
};
}
}
}
// give player the option of dumping stuff in other galaxies (you're unable to do business transactions from different sectors)
if (item.galaxy != galaxyNumber) {
curChoices["80_DUMP"] = {
text: "[storage-dump]",
color: this._itemColor
};
}
curChoices["98_EXIT"] = {
text: "[storage-return]",
color: this._itemColor
};
var def = "98_EXIT";
if (this._lastChoice[this._display] != "") def = this._lastChoice[this._display];
var opts = {
screenID: "oolite-storage-item-map",
title: "Storage - " + (item.inTransit === true ? "In Transit" : item.systemName),
allowInterrupt: true,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
// show short range map to location
if (this._display === 2) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
// hold the player's destination
this._suspendedDestination = p.targetSystem;
// override it for the display
p.targetSystem = item.system;
var bg = "SHORT_RANGE_CHART";
curChoices["20_RETURN"] = {
text: "[storage-return]",
color: this._itemColor
};
if (item.system != system.ID && item.system >= 0 && this.$playerTargetSystem() != item.system && p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY")) {
curChoices["96_SETCOURSE~" + item.system] = {
text: "Set course for " + item.systemName,
color: this._itemColor
};
}
curChoices["98_EXIT"] = {
text: "[storage-return]",
color: this._itemColor
};
def = "20_RETURN";
if (this._lastChoice[this._display] != "") def = this._lastChoice[this._display];
var opts = {
screenID: "oolite-storage-shortrangechart-map",
title: "Storage - Chart",
backgroundSpecial: bg,
allowInterrupt: true,
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
// show long range map to location
if (this._display === 3) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
// hold the player's destination
this._suspendedDestination = p.targetSystem;
// override it for the display
p.targetSystem = item.system;
var bg = "LONG_RANGE_CHART";
if (p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY")) bg = "LONG_RANGE_CHART_SHORTEST";
curChoices["20_RETURN"] = {
text: "[storage-return]",
color: this._itemColor
};
if (item.system != system.ID && item.system >= 0 && this.$playerTargetSystem() != item.system && p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY")) {
curChoices["96_SETCOURSE~" + item.system] = {
text: "Set course for " + item.systemName,
color: this._itemColor
};
}
curChoices["98_EXIT"] = {
text: "[storage-return]",
color: this._itemColor
};
def = "20_RETURN";
if (this._lastChoice[this._display] != "") def = this._lastChoice[this._display];
var opts = {
screenID: "oolite-storage-longrangechart-map",
title: "Storage - Chart",
backgroundSpecial: bg,
allowInterrupt: true,
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
// request transfer
if (this._display === 4) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
}
var info = null;
var dist = 0;
var jumps = 0;
var danger = 0;
var illegal = 0;
var time = 0;
if (item.galaxy === galaxyNumber && item.system != system.ID && item.system >= 0) {
this.$revealMap();
info = System.infoForSystem(galaxyNumber, item.system);
var route = system.info.routeToSystem(info);
jumps = route.route.length;
dist = route.distance;
danger = this.$checkRouteDangerLevel(route);
if (item.commodity != "") illegal = this.$checkRouteIllegalLevel(route, item.commodity);
time = route.time;
this.$restoreMap();
}
if (item.equipmentKey != "") {
text = this.$padTextRight("Equipment item:", 10) + (item.equipmentKey === "EQ_PASSENGER_BERTH" ? "Passenger Berth" : equip.name) + "\n";
text += this.$padTextRight("Equipment status:", 10) + (item.status === "EQUIPMENT_OK" ? "OK" : "Damaged") + "\n";
text += this.$padTextRight("Space/weight:", 10) + (item.space === 0 ? item.weight : item.space) + "t/" + item.weight + "t\n";
text += this.$padTextRight("Storage cost:", 10) + formatCredits(this.$calculateStorageCost(item.space, item.weight), true, true) + " per day\n";
}
if (item.commodity != "") {
text = this.$padTextRight("Cargo type:", 10) + displayNameForCommodity(item.commodity) + "\n";
var spcwt = this.$cargoSpaceRequired(this.$getCommodityUnit(item.commodity), item.weight);
text += this.$padTextRight("Space/weight:", 10) + spcwt + "t/" + item.weight + this.$getCommodityUnit(item.commodity) + "\n";
text += this.$padTextRight("Storage cost:", 10) + formatCredits(this.$calculateStorageCost(item.space, item.weight, this.$getCommodityUnit(item.commodity)), true, true) + " per day\n";
}
if (item.system != -1) {
text += this.$padTextRight("Location:", 10) +
item.systemName + " " + (info != null ? "(dist: " + dist.toFixed(1) + "ly)" : (item.galaxy != galaxyNumber ? "(G" + (item.galaxy + 1) + ")" : "")) + "\n";
} else {
text += this.$padTextRight("Location:", 10) + "In transit\n";
var eta = this.$getTimeRemaining(item.transitETA);
text += this.$padTextRight("ETA:", 10) + System.systemNameForID(item.transitDestination) + (eta === "Overdue" ? " - delivery overdue" : " in " + eta) + "\n";
}
if (dist > 0) {
var tfrcost = this.$calculateTransferCost(dist, jumps, danger, illegal);
text += this.$padTextRight("Transfer cost:", 10) + formatCredits(tfrcost, true, true) + "\n";
text += this.$padTextRight("Transfer time:", 10) + time.toFixed(1) + " hrs\n";
text += this.$padTextRight("Transfer risk:", 10) + expandDescription("[transfer-danger-" + danger + "]") + "\n";
}
if (item.commodity != "" && illegal > 0) {
text += "\n\nNote: The transfer cost includes premiums for bribing officials.";
}
text += "\n\nDo you want to wait here for this item to arrive?";
curChoices["40_YES"] = {
text: "Yes",
color: this._itemColor
};
curChoices["41_NO"] = {
text: "No",
color: this._itemColor
};
curChoices["42_CANCEL"] = {
text: "Cancel transfer",
color: this._itemColor
};
def = "42_CANCEL";
var opts = {
screenID: "oolite-storage-item-map",
title: "Storage - " + item.systemName,
allowInterrupt: true,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
// transfer cargo to storage - select commodity
if (this._display === 5) {
var cargo = p.manifest.list;
var itemcount = 1;
var sdm = worldScripts.Smugglers_DockMaster;
var gcm = worldScripts.GalCopBB_Missions;
var notAllowed = ["slaves", "firearms", "narcotics"];
text = "Select the cargo you want to transfer into storage:\n";
if (this.$storageSystemCount(galaxyNumber, system.ID) === 0) {
text += "(Note: " + formatCredits(this._establishmentFee, false, true) + " will be charged to establish account)\n";
itemcount += 1;
}
for (var i = 0; i < cargo.length; i++) {
// make sure we don't store relabelled cargo
var q = cargo[i].quantity;
if (sdm && sdm._cargoLabelled.length > 0) {
for (var j = 0; j < sdm._cargoLabelled.length; j++) {
if (sdm._cargoLabelled[j].newCommodity === cargo[i].commodity) q -= sdm._cargoLabelled[j].quantity;
}
}
// make sure we're not storing something required for a mission that would stop that mission from working.
if (gcm) {
var restr = gcm.$cargoRestricted(cargo[i].commodity);
q -= restr;
}
if (q > 0) {
var unselect = false;
if (notAllowed.indexOf(cargo[i].commodity) >= 0) unselect = true
curChoices["50_" + (i < 10 ? "0" : "") + i + "_CARGO~" + cargo[i].commodity] = {
text: cargo[i].displayName + " (" + q + cargo[i].unit + ")" + (this.$calcCTEcargo(cargo[i].commodity) > 0 ? "*" : "") +
(unselect === true ? " - Not permitted" : ""),
color: (unselect === false ? this._menuColor : this._disabledColor),
unselectable: unselect
};
itemcount += 1;
}
}
for (var i = 0; i < (25 - itemcount); i++) {
curChoices["97_SPACER_" + i] = "";
}
curChoices["98_EXIT"] = {
text: "[storage-return]",
color: this._itemColor
};
var def = "98_EXIT";
if (this._lastChoice[this._display] != "") def = this._lastChoice[this._display];
var opts = {
screenID: "oolite-storage-cargo-map",
title: "Storage - Cargo",
allowInterrupt: true,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
// how much of the cargo should be transferred
if (this._display === 6) {
// either from storage (tfrType = 1) or ships hold (tfrType = 0)
this.$getTransferAmount();
return;
}
// confirm dumping
if (this._display === 7) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
var itmText = "";
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
itmText = " - " + (item.equipmentKey === "EQ_PASSENGER_BERTH" ? "Passenger Berth" : equip.name);
}
if (item.commodity != "") {
itmText = " - " + item.weight + this.$getCommodityUnit(item.commodity) + " × " + displayNameForCommodity(item.commodity);
}
text = expandDescription("[storage-dump-confirm]", {
item: itmText
});
curChoices["81_YES"] = {
text: "Yes",
color: this._itemColor
};
curChoices["82_NO"] = {
text: "No",
color: this._itemColor
};
var def = "82_NO";
if (this._lastChoice[this._display] != "") def = this._lastChoice[this._display];
var opts = {
screenID: "oolite-storage-cargo-map",
title: "Storage - Dump Item",
allowInterrupt: true,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
// install laser
if (this._display === 8) {
var itemcount = 3;
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
}
text = "Install: " + equip.name + "\n\nSelect the position into which you want to install this weapon:\n";
var lmss = worldScripts.LMSS_Core;
var section = ["Forward", "Aft", "Port", "Starboard", "Forward - Secondary", "Aft - Secondary", "Port - Secondary", "Starboard - Secondary"];
for (var i = 0; i < 7; i++) {
var curr = "X";
switch (i) {
case 0:
if (" 1 3 5 7 9 11 13 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
curr = p.forwardWeapon.equipmentKey;
break;
case 1:
if (" 2 3 6 7 10 11 14 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
curr = p.aftWeapon.equipmentKey;
break;
case 2:
if (" 4 5 6 7 12 13 14 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
curr = p.portWeapon.equipmentKey;
break;
case 3:
if (" 8 9 10 11 12 13 14 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
curr = p.starboardWeapon.equipmentKey;
break;
case 4:
if (" 1 3 5 7 9 11 13 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
if (lmss && p.equipmentStatus("EQ_LMSS_FRONT") === "EQUIPMENT_OK") curr = lmss._forwardAltKey;
break;
case 5:
if (" 2 3 6 7 10 11 14 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
if (lmss && p.equipmentStatus("EQ_LMSS_AFT") === "EQUIPMENT_OK") curr = lmss._aftAltKey;
break;
case 6:
if (" 4 5 6 7 12 13 14 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
if (lmss && p.equipmentStatus("EQ_LMSS_PORT") === "EQUIPMENT_OK") curr = lmss._portAltKey;
break;
case 7:
if (" 8 9 10 11 12 13 14 15 ".indexOf(" " + p.weaponFacings.toString() + " ") >= 0)
if (lmss && p.equipmentStatus("EQ_LMSS_STARBOARD") === "EQUIPMENT_OK") curr = lmss._starboardAltKey;
break;
}
if (curr !== "X") {
itemcount += 1;
if (curr === "" || curr === "EQ_WEAPON_NONE") {
curChoices[(60 + i) + "_WEAPON~" + item.equipmentKey] = {
text: this.$padTextRight(section[i], 31),
color: this._menuColor,
unselectable: false
};
} else {
curChoices[(60 + i) + "_WEAPON~" + item.equipmentKey] = {
text: this.$padTextRight(section[i], 10) + this.$padTextLeft("Current: " + EquipmentInfo.infoForKey(curr).name, 21),
color: this._disabledColor,
unselectable: true
};
}
}
}
for (var i = 0; i < (25 - itemcount); i++) {
curChoices["97_SPACER_" + i] = "";
}
curChoices["98_EXIT"] = {
text: "[storage-return]",
color: this._itemColor
};
var def = "98_EXIT";
if (this._lastChoice[this._display] != "") def = this._lastChoice[this._display];
var opts = {
screenID: "oolite-storage-item-map",
title: "Storage - Weapon Installation",
allowInterrupt: true,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: def,
message: text
};
}
mission.runScreen(opts, this.$itemStorageScreenHandler, this);
}
//-------------------------------------------------------------------------------------------------------------
this.$itemStorageScreenHandler = function $itemStorageScreenHandler(choice) {
if (this._suspendedDestination) player.ship.targetSystem = this._suspendedDestination;
this._suspendedDestination = null;
if (choice == null) return;
var p = player.ship;
var stn = p.dockedStation;
this._lastChoice[this._display] = choice;
if (choice.indexOf("01_EQUIP") >= 0) {
this._selectedItem = choice.substring(choice.indexOf("~") + 1);
this._display = 1;
}
if (choice === "20_RETURN") this._display = 1;
if (choice === "25_SHOWMAP_SHORT") this._display = 2;
if (choice === "25_SHOWMAP_LONG") this._display = 3;
if (choice === "26_TRANSFER") this._display = 4;
if (choice === "35_WAIT") {
// switch over to the wait option
choice = "40_YES";
}
if (choice === "30_INSTALL") {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
// for laser weapons, we need to check what position it will be loaded into
if (item.equipmentKey.indexOf("EQ_WEAPON") >= 0) {
this._display = 8;
} else {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
this._display = 0;
// we should only get here if it's possible to install the equipment, so we shouldn't need to do any extra checks
if (p.equipmentStatus(item.equipmentKey) === "EQUIPMENT_DAMAGED") {
if (equip.techLevel <= 14) {
// ask the player if they want to keep the damaged item?
var curChoices = {};
var sellcost = equip.price / 10 * 0.5 * this._refundPct;
curChoices["01_SELL"] = "Sell item (" + formatCredits(sellcost, true, true) + ")";
curChoices["02_STORE"] = "Store item";
var opts = {
screenID: "oolite-storage-swapout-map",
title: "Storage - " + item.systemName,
allowInterrupt: false,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
message: expandDescription("[storage-sellorstore]"),
};
mission.runScreen(opts, this.$sellOrStoreDamaged, this);
return;
} else {
// no choice but to store the item, so swap it out
p.setEquipmentStatus(item.equipmentKey, "EQUIPMENT_OK");
item.status = "EQUIPMENT_DAMAGED";
player.consoleMessage("Damaged item replaced with working item, damaged item stored.");
}
} else {
if (p.awardEquipment(item.equipmentKey) === true) {
if (item.status === "EQUIPMENT_DAMAGED") p.setEquipmentStatus(item.equipmentKey, "EQUIPMENT_DAMAGED");
player.consoleMessage("Item installed from storage.");
if (item.equipmentKey.indexOf("EQ_LMSS") >= 0) {
worldScripts.LMSS_Core.playerBoughtEquipment(item.equipmentKey);
}
this._storage.splice(itemIndex, 1);
} else {
player.consoleMessage("!ALERT! Unable to install equipment.");
this._display = 1;
}
}
}
}
if (choice === "31_LOAD") {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
this._tfrCargo = item.commodity;
this._maxCargo = item.weight;
this._tfrExtra = item.extra.split(";").length.toString();
// how much of this can the player ship handle?
var orig = p.manifest[this._tfrCargo];
p.manifest[this._tfrCargo] += this._maxCargo;
// check that the hold actually took all the amount
if (p.manifest[this._tfrCargo] != (orig + this._maxCargo)) {
// if not, adjust the amount of transfer
this._maxCargo = p.manifest[this._tfrCargo] - orig;
}
p.manifest[this._tfrCargo] = orig;
this._tfrType = 1; // transfer to cargo hold
this._display = 6; // ask player how much cargo to transfer
}
if (choice === "42_CANCEL") this._display = 1;
if (choice === "40_YES") {
// we're waiting, so more the equipment directly into local storage and add the required time
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
this.$revealMap();
var danger = 0;
var time = 0;
var info = System.infoForSystem(galaxyNumber, (item.inTransit === true ? item.transitSystem : item.system));
var route = system.info.routeToSystem(info);
var jumps = route.route.length;
var dist = route.distance;
var danger = this.$checkRouteDangerLevel(route);
var illegal = (item.commodity != "" ? this.$checkRouteIllegalLevel(route, item.commodity) : 0);
var time = route.time * 3600 + (Math.floor(Math.random() * 4) * 3600);
var tfrcost = this.$calculateTransferCost(dist, jumps, danger, illegal);
player.credits -= parseInt(tfrcost * 10) / 10;
player.consoleMessage("Transfer request initiated. Your account has been debited " + formatCredits(tfrcost, true, true));
var destroyed = false;
// work out if the item arrives safely
for (var i = 0; i < route.route.length; i++) {
var sys = System.infoForSystem(galaxyNumber, route.route[i]);
if (Math.random() > ((sys.government + 1) / 9) && Math.random() > ((sys.government + 1) / 9) && Math.random() > ((sys.government + 1) / 9)) {
destroyed = true;
break;
}
}
if (destroyed === false && item.commodity != "") {
// chance of item being confiscated
var chance = 0;
for (var i = 0; i < illegal; i++) {
chance += Math.random();
}
var caught = (chance < (illegal * 0.2) ? false : true);
}
this.$restoreMap();
// add the transit time to the current time
clock.addSeconds(time);
this._display = 0;
var info = null;
var route = null;
if (destroyed === true) {
// bad luck, pal
var sellcost = 0;
var extra = "";
if (equip) {
if (equip.techLevel <= 14) {
sellcost = (equip.price / 10 * (item.status === "EQUIPMENT_DAMAGED" ? 0.5 : 1) * 0.1);
extra = ", and we hope this insurance payment (of approximately 10% of the equipment value) will go some way towards alleviating the pain";
}
} else if (item.commodity != "") {
// 10% of cargo value
sellcost = Math.floor(((system.mainStation.manifest[item.commodity].price / 10) * item.weight) * 0.1);
extra = ", and we hope this insurance payment (of approximately 10% of the cargo value) will go some towards alleviating the pain";
}
var storeName = expandDescription(this._compNames[item.system % 16]);
mission.runScreen({
screenID: "oolite-storage-destroyed-map",
title: "Storage - Transfer",
overlay: {
name: "equipstorage.png",
height: 546
},
allowInterrupt: false,
message: (equip ? expandDescription("[storage-transfer-destroyed]", {
extra: extra,
storagename: storeName
}) : expandDescription("[storage-transfer-destroyed-cargo]", {
extra: extra,
storagename: storeName
})),
exitScreen: "GUI_SCREEN_INTERFACES"
}, this.$transferFailed, this);
// give player a consolation refund of 10% of item cost
if (sellcost > 0) {
player.credits += sellcost;
player.consoleMessage("You have been refunded " + formatCredits(sellcost, true, true));
}
// remove the item from the storage array
this._storage.splice(itemIndex, 1);
return;
} else if (caught === true) {
var storeName = expandDescription(this._compNames[item.system % 16]);
mission.runScreen({
screenID: "oolite-storage-caught-map",
title: "Storage - Transfer",
overlay: {
name: "equipstorage.png",
height: 546
},
allowInterrupt: false,
message: expandDescription("[storage-transfer-caught]", {
storagename: storeName
}),
exitScreen: "GUI_SCREEN_INTERFACES"
}, this.$transferFailed, this);
this._storage.splice(itemIndex, 1);
return;
} else {
// otherwise just move the item to be local
item.system = system.ID;
item.systemName = system.name;
}
}
if (choice === "41_NO") {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
var info = System.infoForSystem(galaxyNumber, item.system);
var route = system.info.routeToSystem(info);
var jumps = route.route.length;
var dist = route.distance;
var danger = this.$checkRouteDangerLevel(route);
var illegal = (item.commodity != "" ? this.$checkRouteIllegalLevel(route, item.commodity) : 0);
var tfrcost = this.$calculateTransferCost(dist, jumps, danger, illegal);
player.credits -= parseInt(tfrcost * 10) / 10;
player.consoleMessage("Transfer request initiated. Your account has been debited " + formatCredits(tfrcost, true, true) + ".");
item.inTransit = true;
item.transitDestination = system.ID;
item.transitDestinationName = system.name;
item.transitSystem = item.system;
item.transitStart = clock.adjustedSeconds;
item.system = -1;
item.transitETA = clock.adjustedSeconds + (route.time * 3600) + 7200;
this._display = 0;
}
if (choice.indexOf("50_") >= 0) {
this._tfrCargo = choice.substring(choice.indexOf("~") + 1);
this._maxCargo = p.manifest[this._tfrCargo];
this._tfrType = 0; // transfer to storage
this._tfrExtra = this.$calcCTEcargo(this._tfrCargo).toString();
this._display = 6;
}
if (choice.match(/6\d\_WEAPON/g)) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
var equip = choice.substring(choice.indexOf("~") + 1);
var section = choice.substring(1, 2);
// note: because of the way I interfaced LMSS with redspear's "NewLasers" OXP, you will need to have the LMSS OXP in order to install most New Lasers
var lmss = worldScripts.LMSS_Core;
if (lmss) lmss._switching = true;
var bl = worldScripts.BrakableLasers_Main;
// we will only allow installation into an empty position, so there is no need to do a remove/re-store
switch (section) {
case "0":
if (item.status == "EQUIPMENT_DAMAGED") {
p.forwardWeapon = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["FORWARD"].primary = equip;
bl.$updateManifest();
} else {
p.forwardWeapon = equip;
}
break;
case "1":
if (item.status == "EQUIPMENT_DAMAGED") {
p.forwardWeapon = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["AFT"].primary = equip;
bl.$updateManifest();
} else {
p.aftWeapon = equip;
}
break;
case "2":
if (item.status == "EQUIPMENT_DAMAGED") {
p.forwardWeapon = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["PORT"].primary = equip;
bl.$updateManifest();
} else {
p.portWeapon = equip;
}
break;
case "3":
if (item.status == "EQUIPMENT_DAMAGED") {
p.forwardWeapon = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["STARBOARD"].primary = equip;
bl.$updateManifest();
} else {
p.starboardWeapon = equip;
}
break;
case "4":
if (lmss) {
if (item.status == "EQUIPMENT_DAMAGED") {
lmss._forwardAltKey = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["FORWARD"].secondary = equip;
bl.$updateManifest();
} else {
lmss._forwardAltKey = equip;
}
p.awardEquipment("EQ_LMSS_FRONT_WEAPON");
}
break;
case "5":
if (lmss) {
if (item.status == "EQUIPMENT_DAMAGED") {
lmss._aftAltKey = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["AFT"].secondary = equip;
bl.$updateManifest();
} else {
lmss._aftAltKey = equip;
}
p.awardEquipment("EQ_LMSS_AFT_WEAPON");
}
break;
case "6":
if (lmss) {
if (item.status == "EQUIPMENT_DAMAGED") {
lmss._portAltKey = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["PORT"].secondary = equip;
bl.$updateManifest();
} else {
lmss._portAltKey = equip;
}
p.awardEquipment("EQ_LMSS_PORT_WEAPON");
}
break;
case "7":
if (lmss) {
if (item.status == "EQUIPMENT_DAMAGED") {
lmss._starboardAltKey = "EQ_WEAPON_DAMAGED_LASER";
bl._holdDamage["STARBOARD"].secondary = equip;
bl.$updateManifest();
} else {
lmss._starboardAltKey = equip;
}
p.awardEquipment("EQ_LMSS_STARBOARD_WEAPON");
}
break;
}
if (lmss) {
lmss._switching = false;
lmss.$updateManifest();
}
this._storage.splice(itemIndex, 1);
this._display = 0;
}
if (choice === "70_SELL") {
var itemIndex = this.$getStorageIndex(this._selectedItem);
this.$sellEquipment(itemIndex);
this._display = 0;
}
if (choice === "71_SELL") {
var itemIndex = this.$getStorageIndex(this._selectedItem);
// ask how much to sell
this._tfrCargo = this._storage[itemIndex].commodity;
this._maxCargo = this._storage[itemIndex].weight;
this._tfrExtra = this._storage[itemIndex].extra.split(";").length.toString();
if (this._storage[itemIndex].system != system.ID) {
if (this._maxCargo + (system.scrambledPseudoRandomNumber(77) * 127) > 127) {
this._maxCargo = 127 - (system.scrambledPseudoRandomNumber(77) * 127);
}
} else {
if ((this._maxCargo + system.mainStation.market[this._tfrCargo].quantity) > 127) {
this._maxCargo = 127 - system.mainStation.market[this._tfrCargo].quantity;
}
}
this._tfrType = 2;
this._display = 6;
}
if (choice === "80_DUMP") this._display = 7;
if (choice === "81_YES") {
var itemIndex = this.$getStorageIndex(this._selectedItem);
this._storage.splice(itemIndex, 1);
player.consoleMessage("Item was successfully dumped.");
this._display = 0;
}
if (choice === "82_NO") this._display = 1;
if (choice.indexOf("96_SETCOURSE") >= 0) {
var dest = parseInt(choice.substring(choice.indexOf("~") + 1));
if (dest >= 0 && dest <= 255) {
player.ship.targetSystem = dest;
player.ship.infoSystem = player.ship.targetSystem;
player.consoleMessage("Course set for " + System.systemNameForID(dest));
}
}
if (choice === "96_Z_STOREEQUIP") {
this.$storeEquipment();
return;
}
if (choice === "95_NEXT") this._page += 1;
if (choice === "96_PREV") this._page -= 1;
if (choice === "97_SHOWLOCAL") {
this._displayType = 0;
this._lastChoice[this._display] = "97_SHOWALL";
}
if (choice === "97_SHOWALL") {
this._displayType = 1;
this._lastChoice[this._display] = "97_SHOWLOCAL";
}
if (choice === "98_MOVECARGO") this._display = 5;
if (choice === "98_EXIT") this._display = 0;
if (choice != "99_EXIT") {
this.$viewStoredItems();
return;
}
}
//-------------------------------------------------------------------------------------------------------------
// prompts the user for the transfer amount
this.$getTransferAmount = function $getTransferAmount(type) {
var text = "";
// don't show a screen when only 1 unit is possible
if (this._maxCargo === 1) {
switch (this._tfrType) {
case 0:
this.$getCargoTransferIn(1);
return;
case 1:
this.$getCargoTransferOut(1);
return;
case 2:
this.$getCargoToSell(1);
return;
}
}
switch (this._tfrType) {
case 0:
text = expandDescription("[enter-quantity-storage]", {
commodity: displayNameForCommodity(this._tfrCargo),
quantity: this._maxCargo,
cte_note: (this._tfrExtra != "" ? "\n\nNote: " + this._tfrExtra + " units of this cargo is from the specialty market." : "")
});
break;
case 1:
text = expandDescription("[enter-quantity-hold]", {
commodity: displayNameForCommodity(this._tfrCargo),
quantity: this._maxCargo,
cte_note: (this._tfrExtra != "" ? "\n\nNote: " + this._tfrExtra + " units of this cargo is from the specialty market." : "")
});
break;
case 2:
text = expandDescription("[enter-quantity-sell]", {
commodity: displayNameForCommodity(this._tfrCargo),
quantity: this._maxCargo,
cte_note: (this._tfrExtra != "" ? "\n\nNote: " + this._tfrExtra + " units of this cargo is from the specialty market." : "")
});
break;
}
var opts = {
screenID: "oolite-storage-transfer-map",
title: "Storage - " + displayNameForCommodity(this._tfrCargo),
allowInterrupt: false,
overlay: {
name: "equipstorage.png",
height: 546
},
exitScreen: "GUI_SCREEN_INTERFACES",
message: text,
textEntry: true
};
switch (this._tfrType) {
case 0:
mission.runScreen(opts, this.$getCargoTransferIn, true);
break;
case 1:
mission.runScreen(opts, this.$getCargoTransferOut, true);
break;
case 2:
mission.runScreen(opts, this.$getCargoToSell, true);
break;
}
}
//-------------------------------------------------------------------------------------------------------------
// parses the input from the getTransferAmount screen - for transferring cargo to storage
this.$getCargoTransferIn = function $getCargoTransferIn(param) {
if (!param) {
this._display = 0;
this.$viewStoredItems();
return;
}
if (parseInt(param) >= 1 && parseInt(param) <= this._maxCargo) {
var amount = parseInt(param);
var cte = worldScripts.CargoTypeExtension;
var extra = "";
if (cte) {
extra = this.$extractCargoFromCTE(this._tfrCargo, amount, this._maxCargo);
}
var idx = this.$countItemAtStation(this._tfrCargo);
if (idx === 0) {
// charge establishment fee (if required)
if (this.$storageSystemCount(galaxyNumber, system.ID) === 0) {
player.credits -= this._establishmentFee;
player.consoleMessage(formatCredits(this._establishmentFee, false, true) + " deducted to open storage facility account", 5);
}
var spcwt = this.$cargoSpaceRequired(this.$getCommodityUnit(this._tfrCargo), amount);
this._storage.push({
galaxy: galaxyNumber,
system: system.ID,
systemName: system.name,
equipmentKey: "",
commodity: this._tfrCargo,
space: spcwt,
weight: amount,
status: "",
index: 0,
inTransit: false,
transitETA: 0,
transitDestination: -1,
transitSystem: -1,
transitStart: 0,
extra: extra
});
} else {
idx = this.$getStorageIndex(galaxyNumber + "|" + system.ID + "|" + this._tfrCargo + "|0");
this._storage[idx].weight += amount;
var spcwt = this.$cargoSpaceRequired(this.$getCommodityUnit(this._tfrCargo), this._storage[idx].weight);
this._storage[idx].space = spcwt;
this._storage[idx].extra += (this._storage[idx].extra == "" ? "" : ";") + extra;
}
// take the cargo out of the hold
var p = player.ship;
p.manifest[this._tfrCargo] -= amount;
}
this._display = 0;
this.$viewStoredItems();
}
//-------------------------------------------------------------------------------------------------------------
this.$calcCTEcargo = function (generic) {
var cte = worldScripts.CargoTypeExtension;
if (!cte) return 0;
// if there isn't enough generic cargo of a particular type
// throw out special cargo entries of that type until there is
var totalspecial = 0;
for (var j = 0; j < cte.specialCargoCarried[generic].length; j++) {
if (cte.specialCargoRegister[cte.specialCargoCarried[generic][j].type]) {
totalspecial += cte.specialCargoCarried[generic][j].quantity;
}
}
return totalspecial;
}
//-------------------------------------------------------------------------------------------------------------
// parses the input from the getTransferAmount screen - for transferring cargo to hold
this.$getCargoTransferOut = function $getCargoTransferOut(param) {
if (!param) {
this._display = 1;
this.$viewStoredItems();
return;
}
if (parseInt(param) >= 1 && parseInt(param) <= this._maxCargo) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var p = player.ship;
var amount = parseInt(param);
var starting = p.manifest[this._tfrCargo];
// put the cargo into the main hold
p.manifest[this._tfrCargo] += amount;
// check that the hold actually took all the amount
if (p.manifest[this._tfrCargo] != (starting + amount)) {
// if not, adjust the amount of transfer
amount = p.manifest[this._tfrCargo] - starting;
}
// interface with hermitage cargo
//if (worldScripts.Hermitage_Cargo) {
// worldScripts.Hermitage_Cargo.$addCargoToData(this._tfrCargo, amount, p.dockedStation.equivalentTechLevel, system.info.economy);
//}
var count = 0;
var ncmanifest = this.$checkForAndRemoveCTECargo(this._tfrCargo, amount);
if (ncmanifest && this._NCInstalled) {
var cte = worldScripts.CargoTypeExtension;
cte.mergePlayerManifest(ncmanifest);
}
this._storage[itemIndex].weight -= amount;
if (this._storage[itemIndex].weight === 0) {
this._storage.splice(itemIndex, 1);
this._display = 0;
this.$viewStoredItems();
return;
}
this._storage[itemIndex].space = this.$cargoSpaceRequired(this.$getCommodityUnit(this._tfrCargo), this._storage[itemIndex].weight);
}
this._display = 1;
this.$viewStoredItems();
}
//-------------------------------------------------------------------------------------------------------------
// parses the input from the getTransferAmount screen - for selling cargo
this.$getCargoToSell = function $getCargoToSell(param) {
if (!param) {
this._display = 1;
this.$viewStoredItems();
return;
}
if (parseInt(param) >= 1 && parseInt(param) <= this._maxCargo) {
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
var amount = parseInt(param);
var price = 0;
// give player credits
if (item.system === system.ID) {
// 10% price penalty for selling remotely in the same system
price = (system.mainStation.market[item.commodity].price / 10) * (player.ship.dockedStation.isMainStation ? 1 : 0.9);
// add cargo to market
var current = system.mainStation.market[item.commodity].quantity;
// make sure we don't go over capacity
var diff = 0;
if (current + amount > system.mainStation.market[item.commodity].capacity) {
diff = (current + amount) - system.mainStation.market[item.commodity].capacity;
amount -= diff;
}
system.mainStation.setMarketQuantity(item.commodity, current + amount);
} else {
// use the sample price as the means to calc the sale price at a distant system
// includes a 20% price penalty for selling remotely
price = this.$getSamplePrice(item.system, item.commodity) * 0.8;
}
player.credits += price * amount;
player.consoleMessage("You have been credited " + formatCredits(price * amount, true, true)) + ".";
this.$playSound("sell");
// remove qty from storage
this._storage[itemIndex].weight -= amount;
// if we have nothing left, remove the item from the array
if (this._storage[itemIndex].weight === 0) {
this._storage.splice(itemIndex, 1);
this._display = 0;
this.$viewStoredItems();
return;
}
this._storage[itemIndex].space = this.$cargoSpaceRequired(this.$getCommodityUnit(this._tfrCargo), this._storage[itemIndex].weight);
}
this._display = 1;
this.$viewStoredItems();
}
//-------------------------------------------------------------------------------------------------------------
// extracts an certain amount of a particular commodity from new cargoes
this.$extractCargoFromCTE = function(commodity, amount, max) {
var cte = worldScripts.CargoTypeExtension;
var special = this.$calcCTEcargo(commodity);
var normal = max - special;
if (amount - normal > 0) {
// we're transferring some special cargo
var storage = [];
var ncmanifest = cte.suspendPlayerManifest(commodity);
var nc = ncmanifest.split("|");
var lst = nc[1].split("/");
var counter = 0;
for (var i = 0; i < lst.length; i++) {
if (lst[i] != "") {
var itms = lst[i].split(";");
for (var j = 0; j < itms.length; j++) {
if (itms[j] != "") {
// reduce the original
var sub = itms[j].split("=");
var removed = 0;
while (sub[1] > 0) {
sub[1]--;
counter++;
removed++;
if ((amount - normal) - counter == 0) break;
}
itms[j] = sub.join("=");
//storage.push(sub[0] + "=" + removed + "=" + sub[2]);
// make a copy of what we're taking out
// we'll store them a 1 unit items to make the return process easier
for (var k = 0; k < removed; k++) {
var st = "";
for (var m = 0; m < sub.length; m++) {
st += (st == "" ? "" : "=") + (m == 1 ? 1 : sub[m]);
}
storage.push(st);
}
}
}
lst[i] = itms.join(";");
}
if ((amount - normal) - counter == 0) break;
}
nc[1] = lst.join("/");
ncmanifest = nc.join("|");
// tell NC about what we've done
cte.mergePlayerManifest(ncmanifest);
// pull our storage data together
extra = storage.join(";");
}
return extra;
}
//-------------------------------------------------------------------------------------------------------------
this.$checkForAndRemoveCTECargo = function(commodity, quantity) {
var extra = "";
for (var i = 0; i < this._sc_Cargo.length; i++) {
if (this._storage[i].commodity == commodity) {
if (this._storage[i].extra != "") {
var dta = [];
dta = this._storage[i].extra.split(";");
var normal = this._storage[i].weight - dta.length;
if (quantity - normal > 0) {
var diff = quantity - normal;
// compile a list of the cargo items to re-merge with nc
while (diff > 0) {
extra += (extra == "" ? "" : ";") + dta.shift();
diff--;
}
this._storage[i].extra = dta.join(";");
}
}
}
}
// because we store everything as 1 unit items, we need to compile it back into totals so NC has good data
var hold = this.$compileCTEValues(extra);
var ncmanifest = "2|" + this.$buildMergeManifest(commodity, hold);
return ncmanifest;
}
//-------------------------------------------------------------------------------------------------------------
// compile multiple 1 unit items down to one entry with a 1+ unit count
this.$compileCTEValues = function(extra) {
var items = extra.split(";");
var list = {};
for (var i = 0; i < items.length; i++) {
if (!list[items[i]]) {
list[items[i]] = 1;
} else {
list[items[i]] = list[items[i]] + 1;
}
}
var keys = Object.keys(list);
var final = "";
for (var i = 0; i < keys.length; i++) {
var subs = keys[i].split("=");
final = (final == "" ? "" : ";") + subs[0] + "=" + list[keys[i]] + "=" + subs[2];
}
return final;
}
//-------------------------------------------------------------------------------------------------------------
// put the manifest string together
// blank entries in all but the item we are processing the commodity for
this.$buildMergeManifest = function(commodity, extra) {
var cte = worldScripts.CargoTypeExtension;
var goodsList = cte.cargoTypes;
var serial = "";
for (var i = 0; i < goodsList.length; i++) {
if (goodsList[i] == commodity) {
serial += extra;
}
if (i + 1 < goodsList.length) {
serial += "/";
}
}
return serial;
}
//-------------------------------------------------------------------------------------------------------------
// used to sell a particular item out of the storage array
this.$sellEquipment = function $sellEquipment(itemIndex) {
var item = this._storage[itemIndex];
var info = EquipmentInfo.infoForKey(item.equipmentKey);
var stn = player.ship.dockedStation;
var sellcost = info.price / 10 * (item.status === "EQUIPMENT_DAMAGED" ? 0.5 : 1) * (item.equipmentKey.indexOf("EQ_WEAPON") >= 0 ? 1 : this._refundPct);
player.credits += sellcost;
// give the player an email, if installed
var ga = worldScripts.GalCopAdminServices;
if (ga) {
var email = worldScripts.EmailSystem;
var cost = "In total you were refunded " + formatCredits(sellcost, true, true) + ".";
var msg = expandDescription("[storage-sell-email]", {
storename: expandDescription(this._compNames[item.system % 16]),
systemname: item.systemName,
equipname: (item.equipmentKey === "EQ_PASSENGER_BERTH" ? "Passenger Berth" : info.name),
equipcost: cost
});
email.$createEmail({
sender: expandDescription(this._compNames[item.system % 16]),
subject: "Removing equipment",
date: global.clock.adjustedSeconds,
sentFrom: item.system,
message: msg,
expiryDays: ga._defaultExpiryDays
});
}
player.consoleMessage("You have been refunded " + formatCredits(sellcost, true, true));
this._storage.splice(itemIndex, 1);
}
//-------------------------------------------------------------------------------------------------------------
this.$transferFailed = function $transferFailed(choice) {
this.$viewStoredItems();
}
//-------------------------------------------------------------------------------------------------------------
this.$sellOrStoreDamaged = function $sellOrStoreDamaged(choice) {
if (choice == null) return;
var p = player.ship;
var itemIndex = this.$getStorageIndex(this._selectedItem);
var item = this._storage[itemIndex];
if (choice === "01_SELL") {
// this is a swap out replacement to a damaged item, and sell the damaged one
p.setEquipmentStatus(item.equipmentKey, "EQUIPMENT_OK");
item.status = "EQUIPMENT_DAMAGED";
player.consoleMessage("Damaged item replaced with working item, damaged item sold.");
this.$sellEquipment(itemIndex);
}
if (choice === "02_STORE") {
// just change the status of each equipment item
p.setEquipmentStatus(item.equipmentKey, "EQUIPMENT_OK");
item.status = "EQUIPMENT_DAMAGED";
player.consoleMessage("Damaged item replaced with working item, damaged item stored.");
}
this.$viewStoredItems();
return;
}
//-------------------------------------------------------------------------------------------------------------
// calculates the storage cost for a single item of equipment, based on its size/weight profile
this.$calculateStorageCost = function $calculateStorageCost(space, weight, commodityType) {
var calc = 0;
if (commodityType != null) {
space = this.$cargoSpaceRequired(commodityType, weight);
switch (commodityType) {
case "kg":
weight /= 1000;
break;
case "g":
weight /= 1000000;
break;
}
}
calc = space + (weight > space ? weight - space : 0);
if (calc <= 0) calc = 0.1;
return calc;
}
//-------------------------------------------------------------------------------------------------------------
this.$salesRep = function $salesRep() {
if (this._salesRep === "") {
this._salesRep = randomName() + " " + randomName();
}
return this._salesRep;
}
//-------------------------------------------------------------------------------------------------------------
// calculates the total daily cost of all equipment currently stored throughout the galaxy
this.$calculateTotalDailyCost = function $calculateTotalDailyCost() {
var cost = 0;
for (var i = 0; i < this._storage.length; i++) {
var item = this._storage[i];
var add = true;
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
if (!equip) add = false;
}
if (add === true) cost += this.$calculateStorageCost(item.space, item.weight);
}
return cost;
}
//-------------------------------------------------------------------------------------------------------------
// returns the current daily cost for the gal/sys ID combination
this.$calculateSystemCost = function $calculateSystemCost(galaxyNum, systemID) {
var cost = 0;
for (var i = 0; i < this._storage.length; i++) {
var item = this._storage[i];
if (item.system === systemID && item.galaxy === galaxyNum) {
var add = true;
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
if (!equip) add = false;
}
if (add === true) cost += this.$calculateStorageCost(item.space, item.weight);
}
}
return cost;
}
//-------------------------------------------------------------------------------------------------------------
// returns a dictionary of gal/sys id's with the corresponding name of the system where the player currently has equipment stored
this.$storageSystemList = function $storageSystemList() {
var data = {};
for (var i = 0; i < this._storage.length; i++) {
var item = this._storage[i];
var add = true;
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
if (!equip) add = false;
}
if (add === true) data[item.galaxy + "_" + item.system] = item.systemName;
}
return data;
}
//-------------------------------------------------------------------------------------------------------------
// counts the number of equipment items stored at the selected gal/sys
this.$storageSystemCount = function $storageSystemCount(galaxyNum, systemID) {
var count = 0;
for (var i = 0; i < this._storage.length; i++) {
var item = this._storage[i];
if (item.system === systemID && item.galaxy === galaxyNum) {
if (item.equipmentKey != "") {
var equip = EquipmentInfo.infoForKey(item.equipmentKey);
if (equip) count += 1;
}
if (item.commodity != "") {
count += item.weight;
}
}
}
return count;
}
//-------------------------------------------------------------------------------------------------------------
// returns true if the station has equipment storage facilities, otherwise false
this.$stationHasStorageFacilities = function $stationHasStorageFacilities(station) {
if (station.isMainStation) return true;
return false;
}
//-------------------------------------------------------------------------------------------------------------
// returns the count of the specific equipment key stored at a station (in case the player decides to store multiples of the same item)
this.$countItemAtStation = function $countItemAtStation(itemKey) {
var count = 0;
for (var i = 0; i < this._storage.length; i++) {
if (this._storage[i].galaxy === galaxyNumber && this._storage[i].system === system.ID) {
if (this._storage[i].equipmentKey === itemKey) {
var equip = EquipmentInfo.infoForKey(this._storage[i].equipmentKey);
if (equip) count += 1;
}
if (this._storage[i].commodity === itemKey) {
count += this._storage[i].weight;
}
}
}
return count;
}
//-------------------------------------------------------------------------------------------------------------
this.$getStorageIndex = function $getStorageIndex(datakey) {
var data = datakey.split("|");
var gal = parseInt(data[0]);
var sys = parseInt(data[1]);
var eq = data[2];
var idx = parseInt(data[3]);
for (var i = 0; i < this._storage.length; i++) {
if (this._storage[i].galaxy === gal && this._storage[i].system === sys && (this._storage[i].equipmentKey === eq || this._storage[i].commodity === eq) && this._storage[i].index === idx) return i;
}
return -1;
}
//-------------------------------------------------------------------------------------------------------------
// returns a weighted average danger level for a particular route
this.$checkRouteDangerLevel = function $checkRouteDangerLevel(route) {
var danger = 0;
var count = 0;
for (var i = 0; i < route.route.length; i++) {
var sys = System.infoForSystem(galaxyNumber, route.route[i]);
danger += (7 - sys.government);
count += 1;
if (sys.government === 0) {
danger += (7 - sys.government);
count += 1;
}
if (sys.government <= 1) {
danger += (7 - sys.government);
count += 1;
}
if (sys.government <= 2) {
danger += (7 - sys.government);
count += 1;
}
if (sys.government <= 3) {
danger += (7 - sys.government);
count += 1;
}
if (sys.government <= 4) {
danger += (7 - sys.government);
count += 1;
}
if (sys.government <= 5) {
danger += (7 - sys.government);
count += 1;
}
}
danger = parseInt(danger / count);
return danger;
}
//-------------------------------------------------------------------------------------------------------------
// returns a count of the number of systems where this good is illegal
this.$checkRouteIllegalLevel = function $checkRouteIllegalLevel(rt, commodity) {
var si = worldScripts.Smugglers_Illegal;
if (!si) return 0;
var illegal = 0;
for (var i = 0; i < rt.route.length; i++) {
if (si.$isGoodIllegal(rt.route[i], commodity) === true) illegal += 1;
}
return illegal;
}
//-------------------------------------------------------------------------------------------------------------
// returns the player's target system (1.80) or the next jump to their target system (1.82)
this.$playerTargetSystem = function $playerTargetSystem() {
if (player.ship.hasOwnProperty("nextSystem")) return player.ship.nextSystem;
var target = player.ship.targetSystem;
if (oolite.compareVersion("1.81") < 0 && player.ship.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY") === true) {
// in 1.81 or greater, the target system could be more than 7 ly away. It becomes, essentially, the final destination.
// there could be multiple interim stop points between the current system and the target system.
// the only way to get this info is to recreate a route using the same logic as entered on the ANA, and pick item 1
// from the list. That should be the next destination in the list.
if (system.ID === -1) {
var myRoute = System.infoForSystem(galaxyNumber, this._lastSource).routeToSystem(System.infoForSystem(galaxyNumber, target), player.ship.routeMode);
} else {
var myRoute = System.infoForSystem(galaxyNumber, global.system.ID).routeToSystem(System.infoForSystem(galaxyNumber, target), player.ship.routeMode);
}
if (myRoute && myRoute.route.length >= 1) {
target = myRoute.route[1];
}
}
return target;
}
//-------------------------------------------------------------------------------------------------------------
// returns a string containing the hours, minutes (and possibly seconds) remaining until the expiry time is reached
this.$getTimeRemaining = function $getTimeRemaining(expiry, hoursOnly) {
var diff = expiry - clock.adjustedSeconds;
var result = "";
if (diff > 0) {
var hours = Math.floor(diff / 3600);
var mins = Math.floor((diff - (hours * 3600)) / 60);
var secs = Math.floor(diff - (hours * 3600) - (mins * 60));
// special case - reduce 1 hour down to mins
if (hours === 1 && mins < 40) {
hours = 0;
mins += 60;
}
// special case - reduce 1 min down to secs
if (hours === 0 && mins === 1 && secs < 40) {
mins = 0;
secs += 60;
}
if (hoursOnly && hoursOnly === true && mins > 30 && hours > 1) hours += 1;
if (hours > 0) result += hours + " hours";
if ((hoursOnly == null || hoursOnly === false) || (hours === 0 && mins > 0)) {
if (mins > 0) result += (result === "" ? "" : " ") + mins + " mins";
}
if ((hoursOnly == null || hoursOnly === false) || (hours === 0 && mins === 0 && secs > 0)) {
if (hours === 0 && secs > 0) result += (result === "" ? "" : " ") + secs + " secs";
}
} else {
result = "Overdue";
}
return result;
}
//-------------------------------------------------------------------------------------------------------------
// check for any in transit arrivals
this.$checkForArrivals = function $checkForArrivals() {
var si = worldScripts.Smugglers_Illegal;
var mapOn = false;
// any in transit arrivals?
for (var i = this._storage.length - 1; i >= 0; i--) {
if (this._storage[i].inTransit === true) {
var item = this._storage[i];
var equip = null;
var cargo = "";
if (item.equipmentKey != "") equip = EquipmentInfo.infoForKey(item.equipmentKey);
if (item.commodity != "" && this._commodities.indexOf(item.commodity) >= 0) cargo = item.commodity;
// only move valid equipment items
if (equip || cargo != "") {
if (mapOn === false) {
this.$revealMap();
mapOn = true;
}
// our starting system
var info1 = System.infoForSystem(galaxyNumber, item.transitSystem);
// our ultimate destination
var info2 = System.infoForSystem(galaxyNumber, item.transitDestination);
// route between the two
var route1 = info1.routeToSystem(info2);
// now work out the first step of this complete route
var info3 = System.infoForSystem(galaxyNumber, route1.route[1]);
// get the route between info1 (start) and this new point
var route2 = info1.routeToSystem(info3);
if (item.transitStart + (route2.time * 3600) < clock.adjustedSeconds) {
if (Math.random() > ((info3.government + 1) / 9) && Math.random() > ((info3.government + 1) / 9) && Math.random() > ((info3.government + 1) / 9)) {
var sellcost = 0;
var extra = "";
var text = "";
extra = " Insurance pays you " + formatCredits(sellcost, true, true) + ".";
if (equip && equip.techLevel <= 14) {
sellcost = (equip.price / 10 * (item.status === "EQUIPMENT_DAMAGED" ? 0.5 : 1) * 0.1);
text = "Storage Transfer Shipping reports that the ship carrying your " + (item.equipmentKey === "EQ_PASSENGER_BERTH" ? "passenger berth" : equip.name.toLowerCase()) +
" has been destroyed by pirates while on route to " + info2.name + "." + extra;
}
if (cargo != "") {
sellcost = ((system.mainStation.market[cargo].price / 10) * 0.1) * item.weight;
text = "Storage Transfer Shipping reports that the ship carrying your cargo of " + item.weight + this.$getCommodityUnit(item.commodity) + " × " + displayNameForCommodity(item.commodity) +
" has been destroyed by pirates while on route to " + info2.name + "." + extra;
}
// tell the player via an arrival report messages
player.addMessageToArrivalReport(text);
this._storage.splice(i, 1);
} else {
// move the ship along the plot
item.transitSystem = info3.systemID;
// add some time
item.transitStart += (route2.time * 3600) + 3600;
// check for illegal goods
if (si && cargo != "") {
// player may have paid a premium to allow for the shipping commander to bribe official's, but that doesn't mean it's going to work!
if (si.$isGoodIllegal(item.transitSystem, item.commodity) === true) {
// attempt a bribe on player's behalf - change player amount. if they can't afford it, remove cargo
// 2 tries
var chance = worldScripts.Smugglers_DockMaster._bribeChance[system.ID];
var result = false;
for (var tries = 1; tries <= 2; tries++) {
var bribe_attempt = Math.random();
if (bribe_attempt >= chance) {
result = true;
break;
}
}
if (result === false) {
// tell the player via an arrival report messages
var text = "Storage Transfer Shipping reports that your cargo of " + item.weight + this.$getCommodityUnit(item.commodity) + " × " + displayNameForCommodity(item.commodity) +
" has been discovered and confiscated by GalCop Customs officials in " + info3.name + "." + extra;
player.addMessageToArrivalReport(text);
this._storage.splice(i, 1);
continue;
}
}
}
if (item.transitSystem === item.transitDestination) {
// arrived! reset transit data
item.system = item.transitDestination;
item.systemName = info2.name;
item.inTransit = false;
item.transitSystem = -1;
item.transitDestination = -1;
item.transitETA = 0;
item.transitStart = 0;
}
}
}
}
}
}
if (mapOn === true) {
this.$restoreMap();
}
}
//-------------------------------------------------------------------------------------------------------------
// returns the cost of transferring an item to local storage, based on the total distance, number of jumps, the danger level and the number of illegal systems
this.$calculateTransferCost = function $calculateTransferCost(dist, jumps, danger, illegal) {
// cargo only: we add a premium for bribes if there are any systems that consider the cargo illegal
// for equipment, illegal should always be zero
return (((dist / jumps) * 3) * (danger + 1)) * 10 + (illegal * (system.scrambledPseudoRandomNumber(illegal) * 500 + 500));
}
//-------------------------------------------------------------------------------------------------------------
// gets the commodity type for a particular commodity (t, kg or g)
this.$getCommodityUnit = function $getCommodityUnit(generic) {
if (system.isInterstellarSpace) {
var m = player.ship.manifest;
if (m[generic] > 0) {
for (var i = 0; i < m.list.length; i++) {
if (m.list[i].commodity == generic) return m.list[i].unit;
}
} else {
return "t";
}
}
var types = ["t", "kg", "g"];
return types[system.mainStation.market[generic].quantity_unit];
}
//-------------------------------------------------------------------------------------------------------------
// returns the minimum amount of space required for a particular cargo type (kg, g or t) and weight
this.$cargoSpaceRequired = function $cargoSpaceRequired(cargoType, weight) {
var spcwt = 0;
switch (cargoType) {
case "kg":
spcwt = parseInt(weight / 1000);
break;
case "g":
spcwt = parseInt(weight / 1000000);
break;
default:
spcwt = weight;
break;
}
if (spcwt === 0) spcwt = 1;
return spcwt;
}
//-------------------------------------------------------------------------------------------------------------
// compiles a list of sample prices for all the cargo/system combinations we have in storage
this.$compileSamplePrices = function $compileSamplePrices() {
this._storedPrices.length = 0;
var sc = worldScripts.Smugglers_Contracts;
if (system.ID === -1) return;
for (var i = 0; i < this._storage.length; i++) {
if (this._storage[i].commodity != "" && this._storage[i].galaxy === galaxyNumber && this._storage[i].system != system.ID) {
var sys = System.infoForSystem(galaxyNumber, this._storage[i].system);
var prc = 0;
if (sc) {
prc = sc.$priceForCommodity(this._storage[i].commodity, sys);
} else {
prc = (sys.samplePrice(this._storage[i].commodity) / 10);
}
this._storedPrices.push({
system: this._storage[i].system,
commodity: this._storage[i].commodity,
price: prc
});
}
}
sc = null
}
//-------------------------------------------------------------------------------------------------------------
// returns the price for a particular system/commoodity combo
this.$getSamplePrice = function $getSamplePrice(sysID, commodity) {
for (var i = 0; i < this._storedPrices.length; i++) {
if (this._storedPrices[i].system === sysID && this._storedPrices[i].commodity === commodity) return this._storedPrices[i].price;
}
// if we get here, the specific system/commodity pair wan't matched, so add a new one to the array and return the new price
var sc = worldScripts.Smugglers_Contracts;
var sys = System.infoForSystem(galaxyNumber, sysID);
var prc = 0;
if (sc) {
prc = sc.$priceForCommodity(commodity, sys);
} else {
prc = (sys.samplePrice(commodity) / 10);
}
// add it to the array so we don't have to keep looking it up
this._storedPrices.push({
system: sysID,
commodity: commodity,
price: prc
});
return prc;
}
//-------------------------------------------------------------------------------------------------------------
// returns true if a HUD with allowBigGUI is enabled, otherwise false
this.$isBigGuiActive = function $isBigGuiActive() {
if (oolite.compareVersion("1.83") <= 0) {
return player.ship.hudAllowsBigGui;
} else {
var bigGuiHUD = ["XenonHUD.plist", "coluber_hud_ch01-dock.plist"]; // until there is a property we can check, I'll be listing HUD's that have the allow_big_gui property set here
if (bigGuiHUD.indexOf(player.ship.hud) >= 0) {
return true;
} else {
return false;
}
}
}
//-------------------------------------------------------------------------------------------------------------
// 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.replace(/%%/g, "%"));
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.replace(/%%/g, "%")) > desiredLength);
currentLength = defaultFont.measureString(tmp.replace(/%%/g, "%"));
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);
}
//-------------------------------------------------------------------------------------------------------------
this.$pageHeader = function $pageHeader() {
if (this._sc_core) {
return this._sc_core.$pageHeader("store");
} else {
return "";
}
}
//-------------------------------------------------------------------------------------------------------------
// player the buy/sell sound effects
this.$playSound = function $playSound(soundtype) {
var mySound = new SoundSource;
switch (soundtype) {
case "buy":
mySound.sound = "[buy-commodity]";
break;
case "sell":
mySound.sound = "[sell-commodity]";
break;
}
mySound.loop = false;
mySound.play();
}
//-------------------------------------------------------------------------------------------------------------
// routine to completely reveal the system map (if parts have been concealed) to ensure route calculations work
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);
}
}
//-------------------------------------------------------------------------------------------------------------
// routine to restore system map (if parts had been concealed) after route calculations have completed
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;
}
//-------------------------------------------------------------------------------------------------------------
// returns true if the passed equipment key is required by another piece of installed equipment, otherwise false
this.$equipmentIsRequired = function $equipmentIsRequired(equipmentKey) {
// todo: look at requiresAnyEquipment as well
var p = player.ship;
var eq = p.equipment;
var result = false;
// special case for passengers: make sure we always have enough berths for the number of passengers currently on board.
if (equipmentKey === "EQ_PASSENGER_BERTH") {
if (p.passengerCount > 0 && p.passengerCapacity <= p.passengerCount) {
result = true;
}
} else {
for (var i = 0; i < eq.length; i++) {
// special case that isn't listed in equipment config
//if (equipmentKey === "EQ_SHIELD_BOOSTER" && eq[i].equipmentKey === "EQ_NAVAL_SHIELD_BOOSTER") {
// result = true;
// break;
// }
var info = EquipmentInfo.infoForKey(eq[i].equipmentKey);
if (info.requiresEquipment) {
if (info.requiresEquipment.indexOf(equipmentKey) >= 0 ||
// some special cases for ShipConfig items
(this._sc_core &&
((equipmentKey.indexOf("EQ_FUEL_SCOOPS") >= 0 && info.requiresEquipment.indexOf("EQ_FUEL_SCOOPS") >= 0) ||
(equipmentKey.indexOf("EQ_FUEL_INJECTION") >= 0 && info.requiresEquipment.indexOf("EQ_FUEL_INJECTION") >= 0) ||
(equipmentKey.indexOf("EQ_HEAT_SHIELD") >= 0 && info.requiresEquipment.indexOf("EQ_HEAT_SHIELD") >= 0))
)) {
result = true;
break;
}
}
}
}
return result;
} |