Scripts/epc_passenger_contracts.js |
"use strict";
this.name = "EnhancedPassengerContracts";
this.author = "phkb";
this.copyright = "2018 phkb";
this.description = "Expands the passenger contracts system";
this.licence = "CC BY-NC-SA 4.0";
/*
todo:
passengers who get injured during battles and need medical treatment at the next station
passengers who steal cargo and disappear
passengers who steal parcels and disappear
*/
//
this._flags = [1,1,1,1,1,1,1,1,1];
this._settings = 511;
this._simulator = false;
this._internal = false;
this._loading = true;
this._emailDisable = false;
this._sendEmailType = 0;
this._informPlayerOfSystem = false;
this._avoidGovTypeLoading = 1.2; // 20% increase
this._avoidSpeciesLoading = 1.3; // 30% increase
this._avoidSystemLoading = 1.05; // 5% for each system
this._smoothFlightLoading = 2.0; // 100% increase
this._bountyLoading = 1.6; // 60% increase
this._noScanLoading = 1.6; // 60% increase
this._bonusSystemLoading = 0.1; // 10%
this._changeTimer = null;
this._monitorWildMovementTimer = null;
this._chatTimer = null;
this._complimentTimer = null;
this._damageTimer = null;
this._impatientTimer = null;
this._interstellarSpaceTimer = null;
this._transmissions = [];
this._govTypeNames = ["Anarchy","Feudal","Multi-Government","Dictatorship","Communist","Confederate","Democratic","Corporate State"];
this._inhabitantTypes = ["Lobsters","Felines","Humanoids","Insects","Frogs","Lizards","Rodents","Birds","Colonials"];
this._config = {
Name:this.name,
Display:"Config",
Alias:"Enh. Passenger Contracts",
Alive:"_config",
Notify:"$onChange",
EInt:{
E0:{
Name:"_settings",
Def:511,
Min:0,
Max:511,
Desc:[
"A:Gov type restr.",
"B:Species type restr.",
"C:System restr.",
"D:Bonus systems",
"E:Passenger bounties",
"F:No bounty scan restr.",
"G:Smooth flight restr.",
"H:Mid-flight changes",
"I:Passenger comms"
]
},
Info:"Options A-H control what type of enhanced contracts will be generated. Option I controls whether passengers will send the player any comms messages."
},
};
//-------------------------------------------------------------------------------------------------------------
this.$onChange = function() {
var set = 1;
for (var i = 0; i < this._flags.length; i++) {
if (this._settings & set) {
this._flags[i] = 1;
} else {
this._flags[i] = 0;
}
set *= 2;
}
}
//-------------------------------------------------------------------------------------------------------------
this.startUp = function() {
// turn off standard passenger contract system
// disable script and empty its dataset
this.$disableCorePassengerContracts();
}
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function() {
if (worldScripts.BountySystem_Core) {
// tell the bounty system about the new offense type
var b = worldScripts.BountySystem_Core;
b.$uncoverBounties_endpoint = b.$uncoverBounties;
b.$uncoverBounties = this.$ovr_bountySystem_uncoverBounties;
b._offenceTypes["transporting offenders"] = {description:"Transporting and associating with known offenders.", severity:1};
}
if (worldScripts.AutoPrimeEquipment) {
// sync up autoprime equip so selecting our MFD automatically primes broadcast comms
worldScripts.AutoPrimeEquipment.$addConfig("EnhancedPassengerMFD", "EQ_BROADCASTCOMMSMFD");
}
if (missionVariables.EnhancedPassengers_Settings) {
// pull out the stored value
this._settings = parseInt(missionVariables.EnhancedPassengers_Settings);
} else {
// build settings from flags array (in case a user has manually changed the defaults)
var set = 1;
this._settings = 0;
for (var i = 0; i < this._flags.length; i++) {
if (this._flags[i] === 1) {
this._settings += set;
}
set *= 2;
}
}
// register our settings, if Lib_Config is present
if (worldScripts.Lib_Config) worldScripts.Lib_Config._registerSet(this._config);
}
//-------------------------------------------------------------------------------------------------------------
this.systemWillPopulate = function() {
// add our station key to the main station, so the contracts are only offered there
if (system.mainStation) {
worldScripts.BulletinBoardSystem.$addStationKey(this.name, system.mainStation, "mainStation");
}
}
//-------------------------------------------------------------------------------------------------------------
this.missionScreenOpportunity = function() {
if (this._loading === true) {
this._loading = false;
this.$removeExistingContracts();
if (this.$countAvailableContracts() === 0) this.$createPassengerContracts();
// force the interface entry to update
worldScripts.BulletinBoardSystem.$initInterface(player.ship.dockedStation);
delete this.missionScreenOpportunity;
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerEnteredContract = function(type, contract) {
if (this._internal === true) {
if (this._sendEmailType > 0) {
switch (this._sendEmailType) {
case 1:
this.$customPassengerContractEmail(contract);
break;
default:
this.$contractAdjustmentEmail(contract);
break;
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerCompletedContract = function(type, result, fee, contract) {
if (type === "passenger") {
var bb = worldScripts.BulletinBoardSystem;
for (var i = 0; i < bb._data.length; i++) {
var itm = bb._data[i];
if (itm != null && itm.accepted === true) {
// is this item the one we're dealing with?
if (itm.destination === contract.destination && itm.payment === contract.fee && itm.source === contract.start) {
bb.$removeBBMission(itm.ID);
break;
}
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$epc_shipBeingAttacked = function(whom) {
player.ship.script._epc_attacked += 1;
}
//-------------------------------------------------------------------------------------------------------------
this.$epc_shipTargetDestroyed = function(target) {
if (Math.random() < 0.4) {
if (!this._complimentTimer || this._complimentTimer.isRunning === false) {
this._complimentTimer = new Timer(this, this.$niceShotMessage, 2, 0);
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$epc_shipTakingDamage = function(amount, whom, type) {
if (amount > 0 && (player.ship.energy - amount) > 0 && Math.random() < 0.6) {
if (!this._damageTimer || this._damageTimer.isRunning === false) {
this._damageTimer = new Timer(this, this.$damageMessage, 2, 0);
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipDied = function(whom, why) {
if (this._simulator === true) return;
this.$stopTimers();
}
//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation = function(station) {
if (this.$simulatorRunning() === true) {
this._simulator = true;
return;
}
this.$startTimers();
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation = function(station) {
if (this._simulator === true) return;
this.$stopTimers();
// check if we have any contracts to terminate
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
for (var i = data.length - 1; i >= 0; i--) {
if (data[i].accepted === true && data[i].worldScript === this.name) {
var contract = data[i].data.details;
var terminate = false;
if (station.allegiance === "galcop") {
if (this._flags[0] === 1 && contract.avoidGovType >= 0 && contract.avoidGovType === system.government) {
player.addMessageToArrivalReport(expandDescription("[epc_avoid-government-fail]", {name:contract.name, govType:system.governmentDescription}));
terminate = true;
}
if (this._flags[1] === 1 && contract.avoidSpecies != "" && system.info.inhabitants.indexOf(contract.avoidSpecies) >= 0) {
player.addMessageToArrivalReport(expandDescription("[epc_avoid-species-fail]", {name:contract.name, species:contract.avoidSpecies}));
terminate = true;
}
if (this._flags[2] === 1 && contract.avoidSysList && contract.avoidSysList.length > 0) {
if (contract.avoidSysList.indexOf(system.ID) >= 0) {
player.addMessageToArrivalReport(expandDescription("[epc_avoid-system-fail]", {name:contract.name, system:system.name}));
terminate = true;
}
}
if (this._flags[3] === 1 && contract.bonusSysList && contract.bonusSysList.length > 0) {
var idx = contract.bonusSysList.indexOf(system.ID);
if (idx >= 0) {
// remove the system now, so the player can't get the bonus twice
contract.bonusSysList.splice(idx, 1);
// remove this system from the map
for (var j = 0; j < data[i].additionalMarkers.length; j++) {
if (data[i].additionalMarkers[j].destination === system.ID) {
data[i].additionalMarkers.splice(j, 1);
break;
}
}
// because we are still mid-mission at this point, the BB system will not automatically remove
// any chart markers (it will wait until the mission is finished to do this).
/// So we'll do it now manually.
mission.unmarkSystem({system:system.ID, name:this.name + "_" + data[i].ID});
// add an arrival report
player.addMessageToArrivalReport(expandDescription("[epc_bonus-system-success]", {name:contract.name, bonus:formatCredits(data[i].payment * this._bonusSystemLoading, true, true)}));
// pay the player
player.credits += Math.floor((data[i].payment * this._bonusSystemLoading) * 10) / 10;
}
}
}
if (terminate === true) {
// send an email message for our special case
var w = worldScripts.EmailSystem;
if (w && this._emailDisable === false) {
var sndr = expandDescription("[passenger-contract-sender]");
var msg = expandDescription("[passenger-contract-terminated]",
{contractname:contract.name,
systemname:System.systemNameForID(contract.destination),
time:global.clock.clockStringForTime(data[i].expiry)
});
var subj = expandDescription("[passenger-contract-terminated-subject]");
w.$createEmail({sender:sndr,
subject:subj,
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:worldScripts.GalCopAdminServices._defaultExpiryDays
});
}
player.ship.removePassenger(contract.name);
player.decreasePassengerReputation();
bb.$removeBBMission(data[i].ID);
break;
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillExitWitchspace = function() {
if (!system.isInterstellarSpace && !system.sun.hasGoneNova && system.mainStation) {
// must be a regular system with a main station
this.$createPassengerContracts();
}
var p = player.ship;
p.script._epc_wildMovement = 0;
p.script._epc_attacked = 0;
// only try and do a change if broadcast comms is installed
if (p.passengerCount > 0 && p.equipmentStatus("EQ_BROADCASTCOMMSMFD") === "EQUIPMENT_OK") {
if (system.isInterstellarSpace) {
if (this._flags[8] === 1) this._interstellarSpaceTimer = new Timer(this, this.$interstellarSpaceMessage.bind(this), 7, 0);
} else {
if (this._flags[8] === 1) {
if (this._impatientTimer && this._impatientTimer.isRunning) this._impatientTimer.stop();
this._impatientTimer = new Timer(this, this.$impatientMessage.bind(this), (60 * 10), (60 * 5)); // after 10 minutes, then every 5 mins after that
}
if (this._flags[7] === 1) {
if (this._changeTimer && this._changeTimer.isRunning) this._changeTimer.stop();
this._changeTimer = new Timer(this, this.$doContractChange.bind(this), Math.random() * 60 + 30, 0);
}
}
}
this.$resetFoundFlag();
}
//-------------------------------------------------------------------------------------------------------------
this.guiScreenChanged = function(to, from) {
if (this._informPlayerOfSystem === true) {
player.consoleMessage("New destination marked with white 'X'", 6);
this._informPlayerOfSystem = false;
}
}
//-------------------------------------------------------------------------------------------------------------
this.$createPassengerContracts = function() {
var bountySys = false;
if (worldScripts.BountySystem_Core) bountySys = true;
// no point in generating too many, but generally want 5 or more
// some of them will be discarded later
var numContracts = Math.floor(5 * Math.random() + 5 * Math.random() + 5 * Math.random() + (player.passengerReputationPrecise * Math.random()));
if (player.passengerReputationPrecise >= 0 && numContracts < 5) {
numContracts += 5;
}
if (numContracts > 16) {
numContracts = 16;
} else if (numContracts < 0) {
numContracts = 0;
}
// some of these possible contracts may be discarded later on
for (var i = 0; i < numContracts; i++) {
// pick a random system to take the passenger to
var destination = Math.floor(Math.random() * 256);
// discard if chose the current system
if (destination === system.ID) continue;
// get the SystemInfo object for the destination
var destinationInfo = System.infoForSystem(galaxyNumber, destination);
// skip nova systems
if (destinationInfo.sun_gone_nova) continue;
// create a passenger contract record
this.$createRecord(destinationInfo, bountySys);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$createRecord = function(sys, bountySystem) {
// this part is the same as core
var passenger = {};
var daysUntilDeparture = 1 + (Math.random() * (7 + player.passengerReputationPrecise - sys.government));
if (daysUntilDeparture <= 0) {
// loses some more contracts if reputation negative
return;
}
var route = system.info.routeToSystem(sys);
if (!route || route.route.length === 0) return;
passenger.payment = 0;
passenger.destination = sys.systemID;
passenger.route = route;
if (Math.random() < 0.5) {// 50% local inhabitant
passenger.species = system.info.inhabitant;
} else { // 50% random species (which will be 50%ish human)
passenger.species = System.infoForSystem(galaxyNumber, Math.floor(Math.random() * 256)).inhabitant;
}
if (passenger.species.match(new RegExp(expandDescription("[human-word]"), "i"))) {
passenger.name = expandDescription("%N ") + expandDescription("[nom]");
} else {
passenger.name = randomName() + " " + randomName();
}
/* Because passengers with duplicate names won't be accepted,
* check for name duplication with either other passengers
* here or other passengers carried by the player, and adjust
* this passenger's name a little if there's a match */
do {
var okay = true;
for (var j = 0; j < player.ship.passengers.length; j++) {
if (player.ship.passengers[j].name == passenger.name) {
okay = false;
break;
}
}
if (okay) {
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
for (var j = 0; j < data.length; j++) {
var item = data[j];
if (item.data && item.data.hasOwnProperty("type") && item.data.type === "enhanced_passenger" && item.data.details.name == passenger.name) {
okay = false;
break;
}
}
}
if (!okay) passenger.name += "a";
} while (!okay);
// risk
passenger.risk = Math.floor(Math.random()*3);
passenger.species = expandDescription("[passenger-description-risk" + passenger.risk + "]") + " " + passenger.species;
// time allowed for delivery is time taken by "fewest jumps"
// route, plus timer above. Higher reputation makes longer
// times available.
var d_time = Math.floor(daysUntilDeparture * 86400) + (passenger.route.time * 3600);
passenger.deadline = clock.adjustedSeconds + d_time;
if (passenger.risk < 2 && sys.government <= 1 && Math.random() < 0.5) {
passenger.risk++;
}
// ok, we have a valid target - what sort of destination is this?
// total payment is:
passenger.payment = Math.floor(
// payment per hop (higher at rep > 5)
5 * Math.pow(route.route.length - 1, (passenger.risk * 0.2) + (player.passengerReputationPrecise > 5 ? 2.45 : 2.3)) +
// payment by route length
route.distance * (8 + (Math.random() * 8)) +
// premium for delivery to more dangerous systems
(5 * (7 - sys.government) * (7 - sys.government))
);
passenger.payment *= (Math.random() + Math.random() + Math.random() + Math.random()) / 2;
var prudence = (2 * Math.random()) - 1;
var desperation = (Math.random() * (0.5 + passenger.risk)) * (1 + 1 / (Math.max(0.5, d_time - (route.time * 3600))));
var competency = Math.max(50, (route.route.length - 1) * (0.5 + (passenger.risk * 2)));
if (passenger.risk == 0) competency -= 30;
passenger.payment = Math.floor(passenger.payment * (1 + (0.4 * prudence)));
passenger.payment += (passenger.risk * 200);
passenger.skill = Math.min(60, competency + 20 * (prudence - desperation));
// this is the enhanced stuff
passenger.changed = false;
var typeCheck = Math.random() * (10 + (7 - sys.economy));
var avoidGov = 0.2;
var avoidSpecies = 0.2;
var avoidSystem = 0.2;
var bonusSystem = 0.2;
var smooth = 0.1;
var noScan = 0.2;
if (typeCheck >= 9) {
smooth = 0.5;
noScan = 0.6;
} else if (typeCheck >= 7) {
smooth = 0.2;
noScan = 0.4;
}
//log(this.name, "Passenger " + passenger.name);
passenger.smooth = false;
// only low-risk passengers want smooth flights, on shorter trips only
if (this._flags[6] === 1 && passenger.risk === 0 && route.route.length < 10 && Math.random() < smooth) {
// this passenger wants a smooth flight
passenger.smooth = true;
// make the payment a bit larger
//log(this.name, "pre smooth loading = " + passenger.payment);
passenger.payment = Math.floor(passenger.payment * this._smoothFlightLoading);
//log(this.name, "post smooth loading = " + passenger.payment);
//passenger.changed = true; // we'll prevent these passengers from making mid-route changes, though
}
passenger.avoidGovType = -1;
if (this._flags[0] === 1 && Math.random() < avoidGov) {
do {
passenger.avoidGovType = Math.floor(Math.random() * 8);
} while (passenger.avoidGovType === sys.government || passenger.avoidGovType === system.government);
//log(this.name, "pre avoidGov loading = " + passenger.payment);
passenger.payment = Math.floor(passenger.payment * this._avoidGovTypeLoading);
//log(this.name, "post avoidGov loading = " + passenger.payment);
}
passenger.avoidSpecies = "";
if (this._flags[1] === 1 && passenger.avoidGovType === -1 && Math.random() < avoidSpecies) {
do {
passenger.avoidSpecies = this._inhabitantTypes[Math.floor(Math.random() * this._inhabitantTypes.length)];
} while (sys.inhabitants.indexOf(passenger.avoidSpecies) >= 0 || passenger.species.indexOf(passenger.avoidSpecies) >= 0);
//log(this.name, "pre avoidSpecies loading = " + passenger.payment);
passenger.payment = Math.floor(passenger.payment * this._avoidSpeciesLoading);
//log(this.name, "post avoidSpecies loading = " + passenger.payment);
}
var rt = system.info.routeToSystem(sys, "OPTIMIZED_BY_TIME");
passenger.avoidSysList = [];
if (this._flags[2] === 1 && Math.random() < avoidSystem) {
// how many will we have to avoid?
var num = Math.floor(route.route.length * 0.2);
if (num > 3) num = 3;
if (num < 1) num = 1;
//log(this.name, "number to avoid " + num + ", routeLen = " + route.route.length);
for (var i = 0; i < num; i++) {
// sometime pick a system on the quick route
if (Math.random() > 0.6) {
var tgt = System.infoForSystem(galaxyNumber, rt.route[Math.floor(Math.random() * (rt.route.length - 1))]);
} else {
var tgt = System.infoForSystem(galaxyNumber, route.route[Math.floor(Math.random() * (route.route.length - 1))]);
}
// make sure we avoid any conflicts with other clauses
if ((passenger.avoidGovType === -1 || passenger.avoidGovType != tgt.government) &&
(passenger.avoidSpecies === "" || tgt.inhabitants.indexOf(passenger.avoidSpecies) === -1) &&
tgt.systemID != system.ID &&
passenger.avoidSysList.indexOf(tgt.systemID) === -1) {
passenger.avoidSysList.push(tgt.systemID);
passenger.payment = Math.floor(passenger.payment * this._avoidSystemLoading);
}
}
//log(this.name, "avoid sysList = " + passenger.avoidSysList.length);
}
passenger.bonusSysList = [];
if (this._flags[3] === 1 && Math.random() < bonusSystem) {
// how many extra will we have?
var num = Math.floor(route.route.length * 0.2);
if (num > 3) num = 3;
if (num < 1) num = 1;
// get the fast route as well
//log(this.name, "potential bonus systems " + num + ", routeLen = " + route.route.length);
for (var i = 0; i < num; i++) {
// make sure the point we pick along the route is not the start or end point
var point = Math.floor(Math.random() * (route.route.length - 2)) + 1;
var tgtList = System.infoForSystem(galaxyNumber, route.route[point]).systemsInRange(6);
var tgt = tgtList[Math.floor(Math.random() * tgtList.length)];
// make sure we avoid any conflicts with other clauses
if ((passenger.avoidGovType === -1 || passenger.avoidGovType != tgt.government) &&
(passenger.avoidSpecies === "" || tgt.inhabitants.indexOf(passenger.avoidSpecies) === -1) &&
route.route.indexOf(tgt.systemID) === -1 &&
rt.route.indexOf(tgt.systemID) === -1 &&
passenger.avoidSysList.indexOf(tgt.systemID) === -1 &&
passenger.bonusSysList.indexOf(tgt.systemID) === -1)
passenger.bonusSysList.push(tgt.systemID);
}
//log(this.name, "bonus sysList = " + passenger.bonusSysList.length);
}
passenger.noScan = false;
passenger.bounty = 0;
passenger.hiddenBounty = 0;
passenger.found = false;
var custMenu = null;
if (bountySystem) {
// warrant check only available if player is clean
if (player.bounty === 0 && this._flags[4] === 1) {
custMenu = [];
custMenu.push({text:"Request GalCop Warrant Information", worldScript:this.name, callback:"$doWarrantCheck", condition:"$warrantCheckAvailable", autoRemove:true});
}
if (this._flags[4] === 1 && Math.random() < ((8 - system.government) / 8)) {
if (Math.random() > 0.8) {
// this passenger has a bounty
passenger.bounty += Math.floor(Math.random() * (10 - system.government) + 5);
// make the payment a bit larger - this passenger knows it's riskier
//log(this.name, "pre bounty loading = " + passenger.payment);
passenger.payment = Math.floor(passenger.payment * this._bountyLoading);
//log(this.name, "post bounty loading = " + passenger.payment);
} else {
// this passenger has a hidden bounty
passenger.hiddenBounty += Math.floor(Math.random() * (10 - system.government) + 5);
//log(this.name, passenger.name + " - " + passenger.hiddenBounty);
}
}
if (this._flags[5] === 1 && Math.random() > 0.8) {
// but only some will care, even those who don't have a bounty
if (passenger.smooth === false && Math.random() < noScan) {
passenger.noScan = true;
// make the payment a bit larger
//log(this.name, "pre noscan loading = " + passenger.payment);
passenger.payment = Math.floor(passenger.payment * this._noScanLoading);
//log(this.name, "post noscan loading = " + passenger.payment);
}
}
}
passenger.advance = Math.min(passenger.payment * 0.9, Math.max(0, Math.floor(passenger.payment * (0.05 + (0.1 * desperation) + (0.02 * player.passengerReputationPrecise))))); // some% up front
passenger.payment -= passenger.advance;
this.$ovr_addPassengerToSystem(passenger, custMenu);
}
//-------------------------------------------------------------------------------------------------------------
this.$disableCorePassengerContracts = function() {
var psngr = worldScripts["oolite-contracts-passengers"];
// remove the event hooks
delete psngr.shipWillExitWitchspace;
delete psngr.playerWillSaveGame;
delete psngr.shipWillLaunchFromStation;
delete psngr.guiScreenWillChange;
delete psngr.guiScreenChanged;
// intercept the _addPassengerToSystem function
psngr._addPassengerToSystem = this.$ovr_addPassengerToSystem;
// if contracts on BB is installed, we don't need this function
if (worldScripts.ContractsOnBB) {
delete this.playerCompletedContract;
}
}
//-------------------------------------------------------------------------------------------------------------
this.$removeExistingContracts = function() {
// clear the array
var psngr = worldScripts["oolite-contracts-passengers"];
if (psngr.$passengers && psngr.length > 0) psngr.$passengers.length = 0;
system.mainStation.setInterface("oolite-contracts-passengers", null);
// remove any pre-existing BB passenger contracts
if (worldScripts.ContractsOnBB) {
var cobb = worldScripts.ContractsOnBB;
var bb = worldScripts.BulletinBoardSystem;
// remove anything already there
var curr = cobb.$countContracts(32000);
//log(this.name, "current " + curr);
if (curr > 0) {
for (var i = 0; i < curr; i++) {
bb.$removeBBMission(32000 + i);
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$ovr_addPassengerToSystem = function(passenger, custMenu) {
var xui = false;
var ovr = "";
if (worldScripts.XenonReduxUI) {
xui = true;
ovr = {name:"xrui-boardingpass.png", height:546};
}
if (worldScripts.XenonUI) {
xui = true;
ovr = {name:"xui-boardingpass.png", height:546};
}
// we won't attempt to change any other passenger - just the ones we create
// so we'll flag any contract that arrives here as having been changed
if (passenger.hasOwnProperty("changed") === false) {
passenger.changed = true;
}
var cust = [];
if (passenger.advance > 0) cust.push({heading:expandDescription("[epc_contract-advance]"), value:formatCredits(passenger.advance, true, true)});
cust.push({heading:expandDescription("[epc_contract-clientname]"), value:passenger.name + ", a " + passenger.species});
if (passenger.hasOwnProperty("bounty") && passenger.bounty > 0) {
cust.push({heading:expandDescription("[epc_contract-bounty]"), value:(passenger.bounty >= 50 ? "Fugitive" : "Offender") + " (" + passenger.bounty + ")"});
}
var additional = ".";
var addCount = 0;
var smooth_text = "";
if (passenger.hasOwnProperty("smooth") === true && passenger.smooth === true) {
smooth_text = expandDescription("[epc_contract-no-wildness]");
addCount += 1;
} else {
passenger.smooth = false;
}
var scan_text = "";
if (passenger.hasOwnProperty("noScan") === true && passenger.noScan === true) {
scan_text = expandDescription("[epc_contract-no-scan]");
addCount += 1;
} else {
passenger.noScan = false;
}
var avoidGov_text = "";
if (passenger.hasOwnProperty("avoidGovType") === true && passenger.avoidGovType >= 0) {
avoidGov_text = expandDescription("[epc_contract-avoid-gov]", {govType:this._govTypeNames[passenger.avoidGovType]});
addCount += 1;
} else {
passenger.avoidGovType = -1;
}
var avoidSpecies_text = "";
if (passenger.hasOwnProperty("avoidSpecies") === true && passenger.avoidSpecies != "") {
avoidSpecies_text = expandDescription("[epc_contract-avoid-species]", {species:passenger.avoidSpecies});
addCount += 1;
} else {
passenger.avoidSpecies = ""
}
var addMarkers = [];
var avoidSysList_text = "";
var govs = new Array();
for (var i = 0; i < 8 ; i++) govs.push(String.fromCharCode(i));
if (passenger.hasOwnProperty("avoidSysList") === true && Array.isArray(passenger.avoidSysList) === true && passenger.avoidSysList.length > 0) {
var listText = "";
for (var i = 0; i < passenger.avoidSysList.length; i++) {
var sys = System.infoForSystem(galaxyNumber, passenger.avoidSysList[i]);
listText += "\n -- " + sys.name + " (" + govs[sys.government] + " TL" + (sys.techlevel + 1) + ")";
addMarkers.push({destination:sys.systemID, markerColor:"yellowColor", markerShape:"MARKER_X"});
}
avoidSysList_text = expandDescription("[epc_contract-avoid-systems]", {syslist:listText});
addCount += 1;
}
var bonusSysList_text = "";
if (passenger.hasOwnProperty("bonusSysList") === true && Array.isArray(passenger.bonusSysList) === true && passenger.bonusSysList.length > 0) {
var listText = "";
for (var i = 0; i < passenger.bonusSysList.length; i++) {
var sys = System.infoForSystem(galaxyNumber, passenger.bonusSysList[i]);
listText += "\n -- " + sys.name + " (" + govs[sys.government] + " TL" + (sys.techlevel + 1) + ")";
addMarkers.push({destination:sys.systemID, markerColor:"greenColor", markerShape:"MARKER_X"});
}
bonusSysList_text = expandDescription("[epc_contract-bonus-systems]", {bonus:formatInteger(this._bonusSystemLoading * 100) + "% of payment", syslist:listText});
addCount += 1;
}
if (addCount > 0) additional = expandDescription("[epc_additional-clauses]", {multiChange:(addCount === 1 ? "" : "s")});
var customMenu = "";
if (custMenu != undefined) customMenu = custMenu;
var bb = worldScripts.BulletinBoardSystem;
bb.$addBBMission({
source:system.ID,
destination:passenger.destination,
stationKey:"mainStation",
description:expandDescription("[epc_contract-passenger-title]"),
details:expandDescription("[epc_contract-passenger-description]", {client:passenger.name, destination:System.systemNameForID(passenger.destination), extra:(additional + smooth_text + avoidGov_text + avoidSpecies_text + avoidSysList_text + bonusSysList_text + scan_text)}),
payment:passenger.payment,
allowTerminate:false,
completionType:"IMMEDIATE",
stopTimeAtComplete:true,
allowPartialComplete:false,
expiry:passenger.deadline,
disablePercentDisplay:true,
noEmails:true,
playAcceptedSound:false,
markerShape:"NONE", // marker control will be handled by contracts system
overlay:(xui === true ? ovr : ""),
customDisplayItems:cust,
customMenuItems:customMenu,
additionalMarkers:addMarkers,
initiateCallback:"$acceptPassengerContract",
availableCallback:"$passengerContractAvailable",
worldScript:this.name,
data:{type:"enhanced_passenger", details:passenger}
});
}
//-------------------------------------------------------------------------------------------------------------
this.$acceptPassengerContract = function(missID) {
//log(this.name, "accepted contract " + missID);
var bb = worldScripts.BulletinBoardSystem;
var item = bb.$getItem(missID);
this.$acceptContract(item.data.details);
}
//-------------------------------------------------------------------------------------------------------------
// perform checks to see if the passenger contract can be accepted by the player
this.$passengerContractAvailable = function(missID) {
var pc = worldScripts["oolite-contracts-passengers"];
var item = worldScripts.BulletinBoardSystem.$getItem(missID);
// temp variable to simplify code
var passenger = item.data.details;
if (passenger) {
var playerrep = worldScripts["oolite-contracts-helpers"]._playerSkill(player.passengerReputationPrecise);
if (player.ship.passengerCapacity <= player.ship.passengerCount) {
return expandMissionText("oolite-contracts-passengers-command-unavailable").replace("(", "").replace(")", "");
}
else if (playerrep < passenger.skill) {
var utype = "both";
if (player.passengerReputationPrecise*10 >= passenger.skill) {
utype = "kills";
} else if (Math.sqrt(player.score) >= passenger.skill) {
utype = "rep";
}
return expandMissionText("oolite-contracts-passengers-command-unavailable-"+utype).replace("(", "").replace(")", "");
}
}
return "";
}
//-------------------------------------------------------------------------------------------------------------
this.$acceptContract = function(passenger) {
// give the passenger to the player
this._internal = true;
this.$disableEmails();
this._sendEmailType = 1;
var result = player.ship.addPassenger(passenger.name, system.ID, passenger.destination, passenger.deadline, passenger.payment, passenger.advance, passenger.risk);
this.$enableEmails();
this._sendEmailType = 0;
this._internal = false;
var helpers = worldScripts["oolite-contracts-helpers"];
if (result) {
// pay the advance
player.credits += passenger.advance;
helpers._soundSuccess();
if (passenger.risk > 0) {
// once for medium risk
helpers._setClientName(passenger.name);
if (passenger.risk > 1) {
// three times for high risk
helpers._setClientName(passenger.name);
helpers._setClientName(passenger.name);
}
}
} else {
// else must have had another passenger board recently
// (unlikely, but another OXP could have done it)
helpers._soundFailure();
}
}
//-------------------------------------------------------------------------------------------------------------
this.$countAvailableContracts = function() {
var count = 0;
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.accepted === false && item.data && item.data.hasOwnProperty("type") && item.data.type === "enhanced_passenger") count += 1;
}
//log(this.name, "count contracts " + count);
return count;
}
//-------------------------------------------------------------------------------------------------------------
this.$doContractChange = function $doContractChange() {
// go through all the accepted passenger contracts and see if any of them want to change their destination
var p = player.ship;
if (player.alertCondition === 3) {
if (Math.random() > 0.0) {
this._changeTimer = new Timer(this, this.$doContractChange.bind(this), Math.random() * 60 + 30, 0);
}
return; // maybe try again shortly
}
// make sure we still have broadcast comms (might have been damaged)
if (p.equipmentStatus("EQ_BROADCASTCOMMSMFD") !== "EQUIPMENT_OK") return;
for (var i = 0; i < p.passengers.length; i++) {
var passenger = p.passengers[i];
if (Math.random() > 0.0 && passenger.destination != system.ID) { // 0.8
// how far away is the destination
var sys = System.infoForSystem(galaxyNumber, passenger.destination);
var rt = system.info.routeToSystem(sys, "OPTIMIZED_BY_TIME");
// if there's no route to the system, or there's more than 2 jumps left, we're good to go
if (!rt || rt.route.length > 2) {
var sysList = system.info.systemsInRange(30);
var newsys = sysList[Math.floor(Math.random() * sysList.length)];
var newrt = system.info.routeToSystem(newsys, "OPTIMIZED_BY_TIME");
if (newrt && newrt.route.length > 1 && newrt.route.length > rt.route.length) {
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
var bbitem = null;
for (var j = 0; j < data.length; j++) {
var item = data[j];
if (item.accepted === true && item.worldScript === this.name) {
if (item.data.details.name === passenger.name && item.data.details.destination === passenger.destination) {
bbitem = item;
break;
}
}
}
// if this passenger has already done a mid-flight change, don't do another one
if (!bbitem) continue;
var dtls = bbitem.data.details;
if (dtls.changed === true) continue;
// make sure we dont conflict with other types
if (dtls.avoidGovType >= 0 && newsys.government === dtls.avoidGovType) continue;
if (dtls.avoidSpecies != "" && newsys.inhabitants.indexOf(dtls.avoidSpecies) >= 0) continue;
if (dtls.avoidSysList.length > 0 && dtls.avoidSysList.indexOf(newsys.systemID) >= 0) continue;
if (dtls.bonusSysList.length > 0 && dtls.bonusSysList.indexOf(newsys.systemID) >= 0) continue;
// found a target!
// time to power up the MFD
var diff = Math.abs(newrt.route.length - rt.route.length);
//log(this.name, "diff " + diff + ", risk " + passenger.risk + ", gov " + newsys.government);
var extra = Math.pow(diff, (passenger.risk + 1) * 1.5) * (14 - newsys.government);
if (extra < 50) extra = 50;
var txt = expandDescription("[epc_new-destination]", {client:passenger.name, original_system:sys.name, new_system:newsys.name, extra:formatCredits(extra, false, true)});
// store some data for quick pickup later
this._newDest = {
name:passenger.name,
original:sys.systemID,
source:item.source,
newDest:newsys.systemID,
deadline:clock.adjustedSeconds + (newrt.time * 3600),
species:passenger.species,
risk:passenger.risk,
skill:dtls.skill,
advance:passenger.premium,
payment:passenger.fee,
newRoute:newrt,
smooth:dtls.smooth,
noScan:dtls.noScan,
bounty:dtls.bounty,
avoidGovType:dtls.avoidGovType,
avoidSpecies:dtls.avoidSpecies,
// next two should always be empty (because we are preventing those types from changing their minds)
// but in case /we/ ever change our minds...
avoidSysList:(dtls.hasOwnProperty("avoidSysList") ? dtls.avoidSysList : []),
bonusSysList:(dtls.hasOwnProperty("bonusSysList") ? dtls.bonusSysList : []),
hiddenBounty:dtls.hiddenBounty,
found:dtls.found,
bbID:bbitem.ID,
extra:extra
};
mission.markSystem({system:newsys.systemID, name:"epc_newDest", markerColor:"whiteColor", markerShape:"MARKER_X"});
this._informPlayerOfSystem = true;
// set this value so if the player declines, we won't keep asking on this passenger
bbitem.data.details.changed = true;
// communicate with player about the new mission
worldScripts.EnhancedPassengerMFD.$updateMFD(txt);
break;
}
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
// routine to check the combat simulator worldscript, to see if it's running or not
this.$simulatorRunning = function() {
var w = worldScripts["Combat Simulator"];
if (w && w.$checkFight && w.$checkFight.isRunning) return true;
return false;
}
//-------------------------------------------------------------------------------------------------------------
this.$acceptPendingChange = function() {
if (!this._newDest || this._newDest == null) return;
// get a copy of the passenger details
var p = player.ship;
// remove the system mark
mission.unmarkSystem({system:this._newDest.newDest, name:"epc_newDest"});
this._informPlayerOfSystem = false;
// remove the old passenger
p.removePassenger(this._newDest.name)
// add them back in with the new details
this._internal = true;
this.$disableEmails();
this._sendEmailType = 2;
var result = p.addPassenger(this._newDest.name, this._newDest.source, this._newDest.newDest, this._newDest.deadline, parseInt(this._newDest.payment) + parseInt(this._newDest.extra), this._newDest.advance, this._newDest.risk);
this._sendEmailType = 0;
this.$enableEmails();
this._internal = false;
// update the bb
var bb = worldScripts.BulletinBoardSystem;
var item = bb.$getItem(this._newDest.bbID);
item.destination = this._newDest.newDest;
item.destinationName = System.systemNameForID(this._newDest.newDest);
item.expiry = this._newDest.deadline;
item.payment = this._newDest.payment + this._newDest.extra;
item.data.details = {
payment: this._newDest.payment + this._newDest.extra,
destination: this._newDest.newDest,
route: this._newDest.newRoute,
species: this._newDest.species,
name: this._newDest.name,
risk: this._newDest.risk,
deadline: this._newDest.deadline,
skill: this._newDest.skill,
advance: this._newDest.advance,
smooth: this._newDest.smooth,
noScan: this._newDest.noScan,
bounty: this._newDest.bounty,
avoidGovType: this._newDest.avoidGovType,
avoidSpecies: this._newDest.avoidSpecies,
avoidSysList: this._newDest.avoidSysList,
bonusSysList: this._newDest.bonusSysList,
hiddenBounty: this._newDest.hiddenBounty,
found: this._newDest.found,
changed: true
};
delete this._newDest;
}
//-------------------------------------------------------------------------------------------------------------
this.$declinePendingChange = function() {
// remove the system mark
mission.unmarkSystem({system:this._newDest.newDest, name:"epc_newDest"});
this._informPlayerOfSystem = false;
// just delete the details
delete this._newDest;
}
//-------------------------------------------------------------------------------------------------------------
this.$startTimers = function() {
// check if we have any need to monitor for movement/attacks
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
var start = false;
var found = false;
// look for any passengers, and if we need to monitor for wild movement
for (var i = 0; i < data.length; i++) {
if (data[i].accepted === true && data[i].worldScript === this.name) {
found = true;
if (data[i].data.details.smooth === true) {start = true; break;}
}
}
// set up the chat timer
if (found === true && this._flags[8] === 1) {
this._transmissions.length = 0;
this._chatTimer = new Timer(this, this.$sendChatMessage, Math.floor(Math.random() * 120 + 60), Math.floor(Math.random() * 120) + 60);
this.shipTargetDestroyed = this.$epc_shipTargetDestroyed;
this.shipTakingDamage = this.$epc_shipTakingDamage;
}
// if we don't have a need for a wild movement monitor, exit here.
if (start === false) return;
// otherwise, set up the properties, events, fcb and monitor timer
var p = player.ship;
p.script._epc_wildMovement = 0;
p.script._epc_wildMovementWarning = false;
p.script._epc_attacked = 0;
p.script._epc_stable = 0.0;
// some ships will be sluggish, so "wild movement" isn't really possible for them
// so max sure than wild movement will only be calculated for ships that have the possibility of it
// for those with pitch/roll stats lower than these values, it won't trigger
p.script._maxPitch = Math.max(0.75, p.maxPitch);
p.script._maxRoll = Math.max(1, p.maxRoll);
this.shipBeingAttacked = this.$epc_shipBeingAttacked;
this._frameCallbackID = addFrameCallback(this.$checkForWildMovement.bind(this));
this._monitorWildMovementTimer = new Timer(this, this.$monitorWildMovement.bind(this), 5, 5);
}
//-------------------------------------------------------------------------------------------------------------
this.$stopTimers = function() {
if (this._chatTimer && this._chatTimer.isRunning) {
this._chatTimer.stop();
this._chatTimer = null;
}
if (this._changeTimer && this._changeTimer.isRunning) {
this._changeTimer.stop();
this._changeTimer = null;
}
if (this._monitorWildMovementTimer && this._monitorWildMovementTimer.isRunning) {
this._monitorWildMovementTimer.stop();
this._monitorWildMovementTimer = null;
}
if (this._complimentTimer && this._complimentTimer.isRunning) {
this._complimentTimer.stop();
this._complimentTimer = null;
}
if (this._damageTimer && this._damageTimer.isRunning) {
this._damageTimer.stop();
this._damageTimer = null;
}
if (this._impatientTimer && this._impatientTimer.isRunning) {
this._impatientTimer.stop();
this._impatientTimer = null;
}
delete this.shipTargetDestroyed;
delete this.shipTakingDamage;
this.$stopFrameCallback();
}
//-------------------------------------------------------------------------------------------------------------
this.$stopFrameCallback = function() {
if (this._frameCallbackID && isValidFrameCallback(this._frameCallbackID)) {
removeFrameCallback(this._frameCallbackID);
}
delete this._frameCallbackID;
delete this.shipBeingAttacked;
}
//-------------------------------------------------------------------------------------------------------------
this.$checkForWildMovement = function $checkForWildMovement(delta) {
var p = player.ship;
var ps = p.script;
if (!p || p.isValid === false || !ps) return;
// are we moving around a lot?
if (ps._maxPitch - Math.abs(p.pitch) < 0.0001) {ps._epc_wildMovement += delta; ps._epc_stable = 0; return;}
if (ps._maxRoll - Math.abs(p.roll) < 0.0001) {ps._epc_wildMovement += delta; ps._epc_stable = 0; return;}
// monitor how long we've been flying in a stable way
ps._epc_stable += delta;
// every 30 seconds or so, bring down our wild movement amount
if (ps._epc_stable > 15) {
ps._epc_stable = 0;
if (ps._epc_wildMovement > 0) {
ps._epc_wildMovement -= 1;
}
if (ps._epc_attacked > 0) {
ps._epc_attacked -= 1;
}
// reset the warning flag if we get back to 0 again
if (ps._epc_wildMovement <= 0 || ps._epc_attacked <= 0) {
ps._epc_wildMovementWarning = false;
ps._epc_wildMovement = 0;
ps._epc_attacked = 0;
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$monitorWildMovement = function $monitorWildMovement() {
var p = player.ship;
var ps = p.script;
var ding = false;
if (!p || p.isValid === false || !ps) {
this._monitorWildMovementTimer.stop();
return;
}
//log(this.name, "wm = " + ps._epc_wildMovement + ", lh " + ps._epc_attacked);
// send warning after 15 seconds of wild movement or 20 laser hits
if ((ps._epc_wildMovement > 15 || ps._epc_attacked > 20) && ps._epc_wildMovementWarning === false) {
// find a contract who can act as spokesperson for anyone else.
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.accepted === true && item.worldScript === this.name) {
var passenger = item.data.details;
if (passenger.smooth === true) {
//log(this.name, "sending wild movement warning for " + passenger.name);
this.$transmitMessageFromPassenger(passenger, "[passenger-response-not-comfortable-warning]");
break;
}
}
}
ps._epc_wildMovementWarning = true;
player.consoleMessage("");
return;
}
// 30 seconds of wild movement or 40 hits
if (ps._epc_wildMovement > 30 || ps._epc_attacked > 40) {
ding = true;
// reset the values so we don't keep sending the same message
ps._epc_wildMovement = 0;
ps._epc_attacked = 0;
}
if (ding === true) {
// stop the frame callback - we're done
this.$stopFrameCallback();
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.accepted === true && item.worldScript === this.name) {
var passenger = item.data.details;
if (passenger.smooth === true) {
// oh dear
this.$transmitMessageFromPassenger(passenger, "[passenger-response-not-comfortable]");
item.payment = item.payment * 0.5; // 50% reduction
passenger.payment = item.payment;
passenger.smooth = false; // turn this off now, so it can't happen twice
item.data.details = passenger;
// find and update the actual passenger record
for (var j = 0; j < p.passengers.length; j++) {
var psngr = p.passengers[j];
if (psngr.name === passenger.name && psngr.destination === item.destination) {
//log(this.name, "failed for " + psngr.name);
// remove the old passenger
p.removePassenger(passenger.name)
// add them back in with the new details
this._internal = true;
this.$disableEmails();
this._sendEmailType = 3;
var result = p.addPassenger(passenger.name, item.source, item.destination, passenger.deadline, passenger.payment, passenger.advance, passenger.risk);
this._sendEmailType = 0;
this.$enableEmails();
this._internal = false;
break;
}
}
}
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$ovr_bountySystem_uncoverBounties = function(source) {
var p = player.ship;
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
var done = false;
// only do the check if the source of the scan is a police vessel, and we're in a high-level government system
// (never in an anarchy, but more and more likely the higher the government level)
if ((Math.random() * 7) < system.government) {
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.accepted === true && item.worldScript === "EnhancedPassengerContracts") {
var passenger = item.data.details;
// check for any passengers carrying a bounty - and potentially add a bounty to the player
if (passenger.hiddenBounty > 0 || passenger.bounty > 0) {
// found one!
// ding the player and inform them
if (done === false && passenger.found === false && source.isPolice) {
done = true;
player.ship.setBounty(player.bounty + Math.floor(Math.random() * 5 + 2), "transporting offenders");
source.commsMessage(expandDescription("[police-comms-offender-passenger]"), player.ship);
}
passenger.found = true;
// add a custom display item to display the passenger bounty
if (passenger.bounty === 0) {
passenger.bounty = passenger.hiddenBounty;
passenger.hiddenBounty = 0;
item.customDisplayItems.push({heading:expandDescription("[epc_contract-bounty]"), value:passenger.bounty});
item.data.details = passenger;
}
}
// check for any passengers who don't want to be scanned
if (passenger.noScan === true) {
// oh dear
var epc = worldScripts.EnhancedPassengerContracts;
epc.$transmitMessageFromPassenger(passenger, "[passenger-response-got-scanned]");
item.payment = item.payment * 0.25; // 75% reduction
passenger.payment = item.payment;
passenger.noScan = false; // turn this off now, so it can't happen twice
for (var j = 0; j < p.passengers.length; j++) {
var psngr = p.passengers[j];
if (psngr.name === passenger.name && psngr.destination === item.destination) {
// remove the old passenger
p.removePassenger(passenger.name)
// add them back in with the new details
epc._internal = true;
epc.$disableEmails();
epc._sendEmailType = 3;
var result = p.addPassenger(passenger.name, item.source, item.destination, passenger.deadline, passenger.payment, passenger.advance, passenger.risk);
epc._sendEmailType = 0;
epc.$enableEmails();
epc._internal = false;
break;
}
}
item.data.details = passenger;
}
}
}
}
// do the standard uncover bounties
this.$uncoverBounties_endpoint(source);
}
//-------------------------------------------------------------------------------------------------------------
this.$doWarrantCheck = function(missID) {
var p = player.ship;
var bb = worldScripts.BulletinBoardSystem;
var item = bb.$getItem(missID);
var found = false;
var passenger = item.data.details;
if (passenger.hiddenBounty > 0) {
passenger.bounty = passenger.hiddenBounty;
passenger.hiddenBounty = 0;
item.customDisplayItems.push({heading:expandDescription("[epc_contract-bounty]"), value:passenger.bounty});
player.consoleMessage(expandDescription("[epc_reveal-bounty]", {name:passenger.name, bounty:passenger.bounty}), 5);
found = true;
} else {
player.consoleMessage(expandDescription("[epc_reveal-no-bounty]", {name:passenger.name}), 5);
}
item.payment = item.payment * 0.8; // 20% reduction
passenger.payment = item.payment;
item.data.details = passenger;
for (var j = 0; j < p.passengers.length; j++) {
var psngr = p.passengers[j];
if (psngr.name === passenger.name && psngr.destination === item.destination) {
// remove the old passenger
p.removePassenger(passenger.name)
// add them back in with the new details
this._internal = true;
this.$disableEmails();
if (found === false) this._sendEmailType = 4;
var result = p.addPassenger(passenger.name, item.source, item.destination, passenger.deadline, passenger.payment, passenger.advance, passenger.risk);
this._sendEmailType = 0;
this.$enableEmails();
this._internal = false;
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$warrantCheckAvailable = function(missID) {
var bb = worldScripts.BulletinBoardSystem;
var item = bb.$getItem(missID);
if (item.accepted === false) return "only when contract accepted";
if (item.data.details.bounty > 0) return "bounty already visible";
return "";
}
//-------------------------------------------------------------------------------------------------------------
this.$resetFoundFlag = function() {
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.accepted === true && item.worldScript === this.name) {
item.data.details.found = false;
}
}
}
//-------------------------------------------------------------------------------------------------------------
// turns off contract emails, if they aren't already
this.$disableEmails = function() {
if (worldScripts.GalCopAdminServices) {
var ga = worldScripts.GalCopAdminServices;
this._emailDisable = ga._disableContracts;
ga._disableContracts = true;
}
}
//-------------------------------------------------------------------------------------------------------------
// turns on contracts emails, if it was previously
this.$enableEmails = function() {
if (worldScripts.GalCopAdminServices) {
var ga = worldScripts.GalCopAdminServices;
ga._disableContracts = this._emailDisable;
}
}
//-------------------------------------------------------------------------------------------------------------
this.$customPassengerContractEmail = function(contract) {
var w = worldScripts.EmailSystem;
if (!w || this._emailDisable === true) return;
// look up the BB item
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
var item = null;
for (var i = 0; i < data.length; i++) {
if (data[i].accepted === true &&
data[i].worldScript === this.name &&
data[i].destination === contract.destination &&
data[i].payment === contract.fee &&
data[i].source === contract.start) {
item = data[i].data.details;
}
}
if (item === null) return;
var extras = this.$buildExtrasText(item);
var sndr = expandDescription("[passenger-contract-sender]");
var subj = "Accepted contract: " + contract.name;
var msg = expandDescription("[epc_email-passenger-contract-start]",
{contractname:contract.name,
systemname:System.systemNameForID(contract.destination),
time:global.clock.clockStringForTime(contract.arrival_time),
fee:formatCredits(contract.fee, true, true),
extras:extras
});
if (sndr != "") {
w.$createEmail({sender:sndr,
subject:subj,
date:global.clock.adjustedSeconds,
message:msg
});
}
}
//-------------------------------------------------------------------------------------------------------------
this.$contractAdjustmentEmail = function(contract) {
var w = worldScripts.EmailSystem;
if (!w || this._emailDisable === true) return;
// look up the BB item
var bb = worldScripts.BulletinBoardSystem;
var data = bb._data;
var item = null;
for (var i = 0; i < data.length; i++) {
if (data[i].accepted === true &&
data[i].worldScript === this.name &&
data[i].destination === contract.destination &&
data[i].payment === contract.fee &&
data[i].source === contract.start) {
item = data[i].data.details;
}
}
if (item === null) return;
var adjType = "";
switch (this._sendEmailType) {
case 2:
adjType = "[epc_email-contract-amend-destination]";
break;
case 3:
adjType = "[epc_email-contract-amend-payment]";
break;
case 4:
adjType = "[epc_email-contract-amend-privacy]";
break;
}
var extras = this.$buildExtrasText(item);
var sndr = expandDescription("[passenger-contract-sender]");
var subj = "Amended contract: " + contract.name;
var msg = expandDescription(adjType,
{contractname:contract.name,
systemname:System.systemNameForID(contract.destination),
time:global.clock.clockStringForTime(contract.arrival_time),
fee:formatCredits(contract.fee, true, true),
extras:extras
});
if (sndr != "") {
w.$createEmail({sender:sndr,
subject:subj,
date:global.clock.adjustedSeconds,
message:msg
});
}
}
//-------------------------------------------------------------------------------------------------------------
this.$buildExtrasText = function(item) {
var govs = new Array();
for (var i = 0; i < 8 ; i++) govs.push(String.fromCharCode(i));
var extras = "";
if (item.hasOwnProperty("smooth") && item.smooth === true) {
extras += expandDescription("[epc_contract-no-wildness]");
}
if (item.hasOwnProperty("noScan") && item.noScan === true) {
extras += expandDescription("[epc_contract-no-scan]");
}
if (item.hasOwnProperty("avoidGovType") && item.avoidGovType >= 0) {
extras += expandDescription("[epc_contract-avoid-gov]", {govType:this._govTypeNames[item.avoidGovType]});
}
if (item.hasOwnProperty("avoidSpecies") && item.avoidSpecies != "") {
extras += expandDescription("[epc_contract-avoid-species]", {species:item.avoidSpecies});
}
if (item.hasOwnProperty("avoidSysList") && item.avoidSysList.length > 0) {
var listText = "";
for (var i = 0; i < item.avoidSysList.length; i++) {
var sys = System.infoForSystem(galaxyNumber, item.avoidSysList[i]);
listText += "\n -- " + sys.name + " (" + govs[sys.government] + " TL" + (sys.techlevel + 1) + ")";
}
extras += expandDescription("[epc_contract-avoid-systems]", {syslist:listText});
}
if (item.hasOwnProperty("bonusSysList") && item.bonusSysList.length > 0) {
var listText = "";
for (var i = 0; i < item.bonusSysList.length; i++) {
var sys = System.infoForSystem(galaxyNumber, item.bonusSysList[i]);
listText += "\n -- " + sys.name + " (" + govs[sys.government] + " TL" + (sys.techlevel + 1) + ")";
}
extras += expandDescription("[epc_contract-bonus-systems]", {bonus:formatInteger(this._bonusSystemLoading * 100) + "% of payment", syslist:listText});
}
return extras;
}
//-------------------------------------------------------------------------------------------------------------
this.$sendChatMessage = function $sendChatMessage() {
// don't send any messages if there is a pending contract change
if (this._newDest) return;
// don't sent chat messages in Interstellar space
if (system.isInterstellarSpace) return;
// overheating
if (player.ship.temperature >= 0.65) {
if (Math.random() < 0.5) {
this.$transmitMessageFromPassenger(this.$pickRandomPassenger(), "[passenger-overheating]");
}
// if the ship is overheating, don't continue and potentially send a small talk message
return;
}
// low energy
if (player.ship.energy < 32) {
if (Math.random() < 0.5) {
this.$transmitMessageFromPassenger(this.$pickRandomPassenger(), "[passenger-low-energy-concern]");
}
return;
}
// low altitude
if (player.alertAltitude) {
// altitude could be low near the sun, too, but hopefully the temperature message above will prevent conflicts
if (Math.random() < 0.5) {
this.$transmitMessageFromPassenger(this.$pickRandomPassenger(), "[passenger-low-altitude-concern]");
}
return;
}
// don't send small talk during read alert
if (player.alertCondition === 3) return;
// small talk
if (Math.random() < 0.2) {
// pick a passenger
var passenger = this.$pickRandomPassenger();
if (passenger) {
// set up any mission variables that might be used by the chat text
var ds = this.$getSystemsByDescription("disease");
missionVariables.diseaseSystem = ds[Math.floor(Math.random() * ds.length)].name;
var es = this.$getSystemsByDescription("earthquake");
missionVariables.earthquakeSystem = es[Math.floor(Math.random() * es.length)].name;
missionVariables.finalDestination = System.systemNameForID(passenger.destination);
var shipTypes = ["Cobra Mark III","Boa","Boa Class Cruiser","Anaconda","Fer-de-Lance"];
for (var i = 0; i < shipTypes.length; i++) {
if (player.ship.name !== shipTypes[i]) {
missionVariables.altShipName = shipTypes[i];
break;
}
}
var data = expandDescription("[passenger-chat]");
var idx = parseInt(data.split("|")[0]);
var msg = data.split("|")[1];
// clean up the mission variables we added
delete missionVariables.altShipName;
delete missionVariables.finalDestination;
delete missionVariables.diseaseSystem;
delete missionVariables.earthquakeSystem;
if (this._transmissions.indexOf(idx) === -1) {
this.$transmitMessageFromPassenger(passenger, msg);
this._transmissions.push(idx);
}
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.$niceShotMessage = function $niceShotMessage() {
// pick a passenger
this.$transmitMessageFromPassenger(this.$pickRandomPassenger(), "[passenger-nice-shooting]");
}
//-------------------------------------------------------------------------------------------------------------
this.$damageMessage = function $damageMessage() {
this.$transmitMessageFromPassenger(this.$pickRandomPassenger(), "[passenger-damage-concern]");
}
//-------------------------------------------------------------------------------------------------------------
this.$impatientMessage = function $impatientMessage() {
this.$transmitMessageFromPassenger(this.$pickRandomPassenger(), "[passenger-impatient]");
}
//-------------------------------------------------------------------------------------------------------------
this.$interstellarSpaceMessage = function $interstellarSpaceMessage() {
this.$transmitMessageFromPassenger(this.$pickRandomPassenger(), "[passenger-interstellar]");
}
//-------------------------------------------------------------------------------------------------------------
this.$pickRandomPassenger = function() {
var p = player.ship;
return p.passengers[Math.floor(Math.random() * p.passengers.length)];
}
//-------------------------------------------------------------------------------------------------------------
this.$transmitMessageFromPassenger = function(passenger, message) {
if (!passenger) return;
if (message.indexOf("[") === 0) message = expandDescription(message);
var notifySound = new SoundSource;
notifySound.sound = "[@beep]";
notifySound.play();
player.commsMessage("Message from passenger " + passenger.name + ": " + message, 5);
// add to comms log (if installed) so that it doesn't disappear with other messages
if (worldScripts.CommsLogMFD) {
worldScripts.CommsLogMFD.commsMessageReceived(message, null, "Passenger " + passenger.name);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$getSystemsByDescription = function(options) {
var planets = SystemInfo.filteredSystems(this, function(other) {
return (other.description.indexOf(options) >= 0 && other.systemID != system.ID);
});
return planets;
}
|