Scripts/emailsystem_base.js |
"use strict";
this.name = "EmailSystem";
this.author = "phkb";
this.copyright = "2017 phkb";
this.description = "Implements a simple email system via the interfaces screen.";
this.licence = "CC BY-NC-SA 4.0";
// specific settings for this oxp
this._maxpage = 0; // total number of pages of inbox to display
this._curpage = 1; // the current page of the inbox being displayed
this._msRows = 18; //15 // rows to display on the mission screen
this._msCols = 32; // columns to display on the mission screen
this._itemsOnPage = 0; // number of emails being displayed on a page
this._displayType = 0; // controls the view. 0 = inbox, 1 = email, 2 = trace
this._emailPage = 0; // which page of the email are we viewing.
this._emailMaxPages = 0; // total number of pages in the email we are viewing
this._emails = []; // main array of emails
this._emailID = 0; // id of the email we are viewing
this._disableEmailNotification = false; // disables unread email notification when docking
this._notifyMainStationOnly = false; // unread email notification at main stations only
this._archiveLimit = 100; // number of emails to keep before they start getting deleted automatically
this._updateRequired = true; // flag to indicate the interface screen needs updating because a new email was added
this._newMailAlert = null // timer for future dated new emails arriving
this._pageItems = [];
this._lastChoice = ["", "", ""];
this._emailOpen = false;
this._itemColor = "yellowColor";
this._menuColor = "orangeColor";
this._exitColor = "yellowColor";
this._disabledColor = "darkGrayColor";
this._readColumn = 0.4;
//=============================================================================================================
// set up initial variables
//-------------------------------------------------------------------------------------------------------------
this.startUp = function() {
this._hudHidden = false;
this._emailOpen = false;
}
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function() {
// add the welcome email here. If this is the first time we've used the system, there won't be any data to load from mission variables
// so it will not be overwritten by restoring saved values
// once there are saved emails to restore, this email will disappear
this.$createEmail({sender:"Xenon Industries",
subject:"Welcome to your inbox!",
date:clock.seconds - 100,
message:"Xenon Industries is proud to welcome you to your new inbox. We hope you enjoy the facilities this system provides.\n\n"
+ "Xenon Industries have been working behind the scenes for many years providing message facilities to spacers from "
+ "all walks of life. However, it was only after GalCop regulation 3827B (Sub-section A) was passed that we "
+ "have been allowed to provide a fully functional email system to any space going vessel. Even with this "
+ "regulation, email facilities are only operational while dockside, as GalCop regulations make it clear than "
+ "emailing while flying is a serious offence.\n\nDespite this, we know you will love all the benefits a good email "
+ "client can provide, and we believe we have all of this and more.\n\n"
+ "Thank you for using Xenon Industries's email system, and we trust it will perform flawlessly for you for years to come."}, false);
if (defaultFont.measureString("!") > 0.4) this._readColumn = defaultFont.measureString("!") + 0.1;
// restore saved data if any exists
if (missionVariables.EmailSystem_Emails) {
this._emails = JSON.parse(missionVariables.EmailSystem_Emails);
delete missionVariables.EmailSystem_Emails;
}
this.$checkForFutureDatedEmails();
var p = player.ship;
if(p.docked) this.$initInterface(p.dockedStation);
}
//=============================================================================================================
//public interfaces
//-------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------
// Create a new email
// REQUIRED
// emailObj.sender (text) Name of person sending email
// emailObj.subject (text) Subject line of email
// emailObj.date time in seconds
// OPTIONAL
// emailObj.message (text) Body text of email
// emailObj.sentFrom (int) ID of Planet that is the source of the email. Defaults to the current planet.
// If the optional stopTrace flag is set, this ID will be the last planet in the trace.
// emailObj.isRead (boolean) setting this to true will add the email to the inbox as if it's been read by the player.
// this might be useful if you have displayed the message to the player using "addMessageToArrivalReport",
// and want to add a corresponding email, which, because the player has seen it, should be flagged as read. Default false
// emailObj.stopTrace (boolean) Indicates that the routing ticket is corrupt and a trace is only partial. The trace will terminate at the "sentFrom" planet. Default false.
// emailObj.traceRoute (csv text) Allows the trace route information to be fully specified. If not specified, the route will be all planets between sentFrom and the current planet
// using the fastest route.
// emailObj.expiryDate time in seconds when email will expire
// emailObj.expiryDays Number of days added to current date
// emailObj.expiryHours Number of hours added to current date
// emailObj.expiryMinutes Number of minutes added to current date
// emailObj.expirySeconds Number of seconds added to current date
// emailObj.expiryText Text to display in header when email expires
// emailObj.allowExpiryCancel (boolean) indicates whether the expiry date of the email can be cancelled. (default true)
// emailObj.expiryOptions (csv text) csv list of which options to display after expiry (possible values in list are 1,2,3 or 4) eg "3,4"
// emailObj.forceResponse (boolean) Indicates that the player must select a response before the email can be closed. Default false
// emailObj.option1 (ResponseOption) Response option 1
// emailObj.option2 (ResponseOption) Response option 2
// emailObj.option3 (ResponseOption) Response option 3
// emailObj.option4 (ResponseOption) Response option 4
//
// Response options are an object:
// response.display (text) Text to display on email. Will be slotted into "Send 'xxx' response"
// response.reply (text) Text to be appended to the email as a reply.
// response.script (text) the name of the worldScript where the callback function is located
// response.callback (text) the name of the function to call when the reply is selected
// response.parameter (object) object to pass to the function when it is called
this.$createEmail = function(emailObj) {
// using parameters
if (emailObj.hasOwnProperty("sender") === false || emailObj.sender === "") {
throw "Invalid settings: sender must be supplied.";
}
if (emailObj.hasOwnProperty("subject") === false || emailObj.subject === "") {
throw "Invalid settings: subject must be supplied.";
}
if (emailObj.hasOwnProperty("date") === false || emailObj.date === 0) {
throw "Invalid settings: date must be supplied.";
}
if (emailObj.hasOwnProperty("sentFrom") === true) {
if (emailObj.sentFrom < 0 || emailObj.sentFrom > 255) {
throw "Invalid settings: sentFrom (planet ID) must be supplied and be in range 0-255.";
}
}
var id = this.$nextID();
var ebody = "";
if (emailObj.hasOwnProperty("message") === true) ebody = emailObj.message;
var planet = system.ID;
if (emailObj.hasOwnProperty("sentFrom") === true) planet = emailObj.sentFrom;
var stoptr = false;
if (emailObj.hasOwnProperty("stopTrace") === true) stoptr = emailObj.stopTrace;
var read = false;
if (emailObj.hasOwnProperty("isRead") === true) read = emailObj.isRead;
var trc = "";
if (emailObj.hasOwnProperty("traceRoute") === true) {
trc = emailObj.traceRoute;
} else {
trc = this.$populateTrace(planet); // text: CSV list of planets in the trace
}
var forcersp = false;
if (emailObj.hasOwnProperty("forceResponse") === true) forcersp = emailObj.forceResponse;
var expDate = 0;
if (emailObj.hasOwnProperty("expiryDate") === true) expDate = emailObj.expiryDate;
if (emailObj.hasOwnProperty("expiryDays") === true || emailObj.hasOwnProperty("expiryHours") === true || emailObj.hasOwnProperty("expiryMinutes") === true || emailObj.hasOwnProperty("expirySeconds") === true) {
var addsec = 0;
// convert all values to seconds
if (emailObj.hasOwnProperty("expiryDays") === true) addsec += emailObj.expiryDays * 24 * 60 * 60;
if (emailObj.hasOwnProperty("expiryHours") === true) addsec += emailObj.expiryHours * 60 * 60;
if (emailObj.hasOwnProperty("expiryMinutes") === true) addsec += emailObj.expiryMinutes * 60;
if (emailObj.hasOwnProperty("expirySeconds") === true) addsec += emailObj.expirySeconds; // don't know why you'd want to, but just in case
// add the expiry amount to the transmit date, so a future dated email with expiry will not expire before it's visible
if (addsec > 0) expDate = emailObj.date + addsec;
}
var expText = "";
if (emailObj.hasOwnProperty("expiryText") === true) expText = emailObj.expiryText;
var expOptions = "";
if (emailObj.hasOwnProperty("expiryOptions") === true) expOptions = emailObj.expiryOptions;
if (expOptions != "" && expText === "") {
throw "Invalid settings: expiryOptions have been defined but no expiryText has been set. Options will never be available to player.";
}
var expCancel = true;
if (emailObj.hasOwnProperty("allowExpiryCancel") === true) expCancel = emailObj.allowExpiryCancel;
var opt1 = {DisplayText:"", ReplyText:"", WorldScriptsName:"", CallbackFunction:"", FunctionParam:{}};
if (emailObj.hasOwnProperty("option1") === true) {
opt1.DisplayText = emailObj.option1.display;
opt1.ReplyText = emailObj.option1.reply;
opt1.WorldScriptsName = emailObj.option1.script;
opt1.CallbackFunction = emailObj.option1.callback;
if (emailObj.option1.hasOwnProperty("parameter") === true) opt1.FunctionParam = emailObj.option1.parameter;
}
var opt2 = {DisplayText:"", ReplyText:"", WorldScriptsName:"", CallbackFunction:"", FunctionParam:{}};
if (emailObj.hasOwnProperty("option2") === true) {
opt2.DisplayText = emailObj.option2.display;
opt2.ReplyText = emailObj.option2.reply;
opt2.WorldScriptsName = emailObj.option2.script;
opt2.CallbackFunction = emailObj.option2.callback;
if (emailObj.option2.hasOwnProperty("parameter") === true) opt2.FunctionParam = emailObj.option2.parameter;
}
var opt3 = {DisplayText:"", ReplyText:"", WorldScriptsName:"", CallbackFunction:"", FunctionParam:{}};
if (emailObj.hasOwnProperty("option3") === true) {
opt3.DisplayText = emailObj.option3.display;
opt3.ReplyText = emailObj.option3.reply;
opt3.WorldScriptsName = emailObj.option3.script;
opt3.CallbackFunction = emailObj.option3.callback;
if (emailObj.option3.hasOwnProperty("parameter") === true) opt3.FunctionParam = emailObj.option3.parameter;
}
var opt4 = {DisplayText:"", ReplyText:"", WorldScriptsName:"", CallbackFunction:"", FunctionParam:{}};
if (emailObj.hasOwnProperty("option4") === true) {
opt4.DisplayText = emailObj.option4.display;
opt4.ReplyText = emailObj.option4.reply;
opt4.WorldScriptsName = emailObj.option4.script;
opt4.CallbackFunction = emailObj.option4.callback;
if (emailObj.option4.hasOwnProperty("parameter") === true) opt4.FunctionParam = emailObj.option4.parameter;
}
if (expOptions != "" &&
((expOptions.indexOf("1") >=0 && opt1.DisplayText === "") ||
(expOptions.indexOf("2") >=0 && opt2.DisplayText === "") ||
(expOptions.indexOf("3") >=0 && opt3.DisplayText === "") ||
(expOptions.indexOf("4") >=0 && opt4.DisplayText === ""))) {
throw "Invalid settings: expiryOptions have been defined but the response option has not been set.";
}
var msg = {ID:id,
Sender:emailObj.sender,
Subject:emailObj.subject,
TransmitDate:emailObj.date,
EmailBody:ebody,
OriginatingPlanet:System.systemNameForID(planet),
ReceivedPlanet:System.systemNameForID(system.ID),
Read:read,
CorruptTrace:stoptr,
Trace:trc,
ExpiryDate:expDate,
ExpiryText:expText,
ExpiryOptions:expOptions,
AllowExpiryCancel:expCancel,
ChosenOption:0,
Marked:false,
GalaxyNum:galaxyNumber,
ForceResponse:forcersp,
ResponseOption1:opt1,
ResponseOption2:opt2,
ResponseOption3:opt3,
ResponseOption4:opt4};
this._emails.push(msg);
if (emailObj.date > clock.seconds && player.ship.docked === true) {
// set a timer to ding when the email "appears" in the inbox - only while docked
if (!this._newMailAlert || this._newMailAlert.isRunning === false) {
this._newMailAlert = new Timer(this, this.$newMailArrived, (emailObj.date - clock.seconds), 0);
}
}
// make sure we keep our array inside the bounds of the archive limit
this.$deleteOldest();
this._updateRequired = true;
// return the msg id back to the caller, just in case they need it.
return id;
}
//=============================================================================================================
// ship interfaces
//-------------------------------------------------------------------------------------------------------------
this.shipDockedWithStation = function(station) {
if (this._disableEmailNotification === false && ((this._notifyMainStationOnly === true && station.isMainStation) || this._notifyMainStationOnly === false)) {
var unread = this.$totalUnreadItemsRequiringResponse();
if(unread != 0) {
var addText = "emails";
var respText = "require";
if (unread === 1) { addText = "email"; respText = "requires"; }
player.addMessageToArrivalReport("You have " + unread + " unread " + addText + " that " + respText + " a response.");
}
}
this.$checkForFutureDatedEmails();
this.$initInterface(station);
}
//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation = function(station) {
delete missionVariables.EmailSystem_Emails;
if (this._newMailAlert && this._newMailAlert.isRunning) this._newMailAlert.stop();
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function() {
// save email array
missionVariables.EmailSystem_Emails = JSON.stringify(this._emails);
}
//-------------------------------------------------------------------------------------------------------------
this.guiScreenChanged = function(to, from) {
if (guiScreen === "GUI_SCREEN_INTERFACES" || this._updateRequired === true) {
// update the interfaces screen
this._updateRequired = false;
var p = player.ship;
if (p.dockedStation) this.$initInterface(p.dockedStation);
}
if (from === "GUI_SCREEN_MISSION" && this._emailOpen) {
this._emailOpen = false;
if (this._hudHidden === false && player.ship.hudHidden === true) player.ship.hudHidden = false;
}
}
//=============================================================================================================
// general functions
//-------------------------------------------------------------------------------------------------------------
// check for any future dated emails, and start a timer to play a ding noise
this.$checkForFutureDatedEmails = function() {
// when will the next ding happen?
if (player.ship.docked) {
var next = 0;
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].TransmitDate > clock.seconds && (this._emails[i].TransmitDate - clock.seconds) > next) {
next = (this._emails[i].TransmitDate - clock.seconds);
// update the receipt planet and the trace of all future dated emails, so when they arrive
// they have the correct values
if (this._emails[i].GalaxyNum === galaxyNumber) {
this._emails[i].ReceivedPlanet = System.systemNameForID(system.ID);
this._emails[i].Trace = this.$populateTrace(System.systemIDForName(this._emails[i].OriginatingPlanet));
}
}
}
if (next > 0) {
if (!this._newMailAlert || this._newMailAlert.isRunning === false)
this._newMailAlert = new Timer(this, this.$newMailArrived, next, 0);
}
}
}
//-------------------------------------------------------------------------------------------------------------
// play the new mail message noise
this.$newMailArrived = function $newMailArrived() {
this._updateRequired = true;
var mySound = new SoundSource;
mySound.sound = "ding.ogg";
mySound.loop = false;
mySound.play();
player.consoleMessage(expandDescription("[emailnewitem]"));
// check for any more emails
this.$checkForFutureDatedEmails();
}
//-------------------------------------------------------------------------------------------------------------
// returns the next ID number for new emails
this.$nextID = function() {
var iMax = 0;
if (this._emails != null && this._emails.length > 0) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].ID > iMax) iMax = this._emails[i].ID;
}
}
return (iMax + 1);
}
//-------------------------------------------------------------------------------------------------------------
// this function should only be called when an email is created. Once created, it will be populated from the missionvariables store
this.$populateTrace = function(startPoint) {
// get list of planets between start and end points
var sysID = system.ID;
if (system.ID === -1) sysID = player.ship.targetSystem;
var myRoute = System.infoForSystem(galaxyNumber, sysID).routeToSystem(System.infoForSystem(galaxyNumber, startPoint), "OPTIMIZED_BY_TIME");
// expand and reverse list for storage
var ret = "";
if (myRoute != null) {
for (var i = 0; i < myRoute.route.length; i++) {
if (i > 0) {
ret += ",";
}
ret = ret + System.systemNameForID(myRoute.route[i]);
}
} else {
ret = "<< Error: Trace unavailable >>";
}
return ret;
}
//-------------------------------------------------------------------------------------------------------------
// deletes oldest emails from array until the count is less than archive total
this.$deleteOldest = function() {
function compare(a,b) {
return a.TransmitDate - b.TransmitDate;
}
// look for and delete any expired emails first
for (var i = this._emails.length - 1; i >= 0; i--) {
if (this._emails[i].ExpiryDate != 0 && clock.seconds > this._emails[i].ExpiryDate && this._emails[i].ExpiryText === "") {
this._emails.splice(i, 1);
}
}
if (this._emails.length > this._archiveLimit) {
// sort emails oldest to newest
this._emails.sort(compare);
var idx = 0;
do {
// only delete if there isn't a response required
if (this.$requiresResponse(this._emails[idx]) === false) this._emails.splice(idx, 1);
idx += 1;
// if the player has 100 emails that require a response, we might still end up with an array greater than 100
// so watch for that case here
if (idx >= this._emails.length) break;
} while (this._emails.length > this._archiveLimit);
}
}
//-------------------------------------------------------------------------------------------------------------
// returns the email based on ID number
this.$getEmailByID = function(id) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].ID === id) return this._emails[i];
}
return null;
}
//-------------------------------------------------------------------------------------------------------------
// returns the email based on ID number
this.$getEmailIndexByID = function(id) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].ID === id) return i;
}
return -1;
}
//-------------------------------------------------------------------------------------------------------------
this.$findNextEmailID = function(id) {
var ret = -1;
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].ID === id && i < (this._emails.length - 1)) ret = this._emails[i + 1].ID;
}
return ret;
}
//-------------------------------------------------------------------------------------------------------------
// executes the callback function of the selected response
this.$executeCallback = function(id, optionNumber) {
var email = this.$getEmailByID(id);
switch (optionNumber) {
case 1:
if (email.ResponseOption1.CallbackFunction != "") {
var w = worldScripts[email.ResponseOption1.WorldScriptsName];
if (w) w[email.ResponseOption1.CallbackFunction](email.ResponseOption1.FunctionParam);
}
break;
case 2:
if (email.ResponseOption2.CallbackFunction != "") {
var w = worldScripts[email.ResponseOption2.WorldScriptsName];
if (w) w[email.ResponseOption2.CallbackFunction](email.ResponseOption2.FunctionParam);
}
break;
case 3:
if (email.ResponseOption3.CallbackFunction != null) {
var w = worldScripts[email.ResponseOption3.WorldScriptsName];
if (w) w[email.ResponseOption3.CallbackFunction](email.ResponseOption3.FunctionParam);
}
break;
case 4:
if (email.ResponseOption4.CallbackFunction != null) {
var w = worldScripts[email.ResponseOption4.WorldScriptsName];
if (w) w[email.ResponseOption4.CallbackFunction](email.ResponseOption4.FunctionParam);
}
break;
}
}
//-------------------------------------------------------------------------------------------------------------
// counts the total number of emails viewable in the inbox
this.$totalItems = function() {
var itms = 0;
if (this._emails.length > 0) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].TransmitDate <= clock.seconds) itms += 1;
}
}
return itms;
}
//-------------------------------------------------------------------------------------------------------------
// counts the total number of marked emails
this.$totalItemsMarked = function() {
var itms = 0;
if (this._emails.length > 0) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].Marked === true) itms += 1;
}
}
return itms;
}
//-------------------------------------------------------------------------------------------------------------
// counts how many read items are in the inbox
this.$totalReadItems = function() {
var itms = 0;
if (this._emails != null && this._emails.length > 0) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].Read === true && this._emails[i].TransmitDate <= clock.seconds) itms += 1;
}
}
return itms;
}
//-------------------------------------------------------------------------------------------------------------
// counts how many unread items are in the inbox
this.$totalUnreadItems = function() {
var itms = 0;
if (this._emails != null && this._emails.length > 0) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].Read === false && this._emails[i].TransmitDate <= clock.seconds) itms += 1;
}
}
return itms;
}
//-------------------------------------------------------------------------------------------------------------
// counts how many unread items requiring a response are in the inbox
this.$totalUnreadItemsRequiringResponse = function() {
var itms = 0;
if (this._emails != null && this._emails.length > 0) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].Read === false && this._emails[i].TransmitDate <= clock.seconds && this._emails[i].ExpiryDate > clock.adjustedSeconds && this.$requiresResponse(this._emails[i]) === true) itms += 1;
}
}
return itms;
}
//-------------------------------------------------------------------------------------------------------------
// marks all items read
this.$markAllItemsRead = function() {
if (this._emails != null && this._emails.length > 0) {
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].Read === false && this._emails[i].TransmitDate <= clock.seconds) this._emails[i].Read = true;
}
}
}
//-------------------------------------------------------------------------------------------------------------
// checks whether the current item is marked
this.$isItemMarked = function(id) {
var email = this.$getEmailByID(id);
if (email.Marked === true) {
return true;
} else {
return false;
}
}
//-------------------------------------------------------------------------------------------------------------
// marks the currently selected item
this.$markItem = function(id) {
var email = this.$getEmailByID(id);
email.Marked = true;
}
//-------------------------------------------------------------------------------------------------------------
// unmarks the currently selected item
this.$unmarkItem = function(id) {
var email = this.$getEmailByID(id);
email.Marked = false;
}
//-------------------------------------------------------------------------------------------------------------
// deletes the currently selected item
this.$deleteSelectedItem = function(id) {
if (this._emails.length > 0 && id > 0) {
var idx = this.$getEmailIndexByID(id);
if (this.$requiresResponse(this._emails[idx]) === false || this._emails[idx].ExpiryDate < clock.adjustedSeconds) {
this._emails.splice(idx, 1);
this._maxpage = Math.ceil(this.$totalItems() / this._msRows);
}
}
}
//-------------------------------------------------------------------------------------------------------------
// deletes all marked emails that don't have a pending response
this.$deleteMarkedItems = function() {
if (this._emails.length > 0 && this.$totalItemsMarked() > 0) {
for (var i = this._emails.length - 1; i >= 0; i--) {
if (this._emails[i].Marked === true && this.$requiresResponse(this._emails[i]) === false) {
this._emails.splice(i, 1);
}
}
this._curpage = 0;
this._maxpage = Math.ceil(this.$totalItems() / this._msRows);
}
}
//-------------------------------------------------------------------------------------------------------------
// deletes all marked emails that don't have a pending response
this.$deleteReadItems = function() {
if (this._emails.length > 0 && this.$totalReadItems() > 0) {
for (var i = this._emails.length - 1; i >= 0; i--) {
if (this._emails[i].Read === true && this.$requiresResponse(this._emails[i]) === false) {
this._emails.splice(i, 1);
}
}
this._curpage = 0;
this._maxpage = Math.ceil(this.$totalItems() / this._msRows);
}
}
//-------------------------------------------------------------------------------------------------------------
// deletes all emails that don't have a pending response.
this.$deleteAllItems = function() {
for (var i = this._emails.length - 1; i >= 0; i--) {
// only delete emails that are in the past
if (this.$requiresResponse(this._emails[i]) === false && this._emails[i].TransmitDate <= clock.seconds) {
this._emails.splice(i, 1);
}
}
this._curpage = 0;
this._maxpage = 1;
}
//-------------------------------------------------------------------------------------------------------------
// records the index of the response against the selected email
this.$recordResponse = function(id, option) {
var email = this.$getEmailByID(id);
email.ChosenOption = option;
email.ResponseDate = clock.seconds;
}
//-------------------------------------------------------------------------------------------------------------
// Returns the header details of the email formatted for display
this.$header = function(email) {
var text = "";
text += this.$padTextRight("From:", 5) + email.Sender + "\n";
text += this.$padTextRight("Sent:", 5) + clock.clockStringForTime(email.TransmitDate)
// add the galaxy number if the email was received in a different galaxy to the one the player is in now.
if (galaxyNumber != email.GalaxyNum) text += " (G" + (email.GalaxyNum + 1) + ")";
text += "\n";
// expiry date
if (email.ExpiryDate != 0) {
text += this.$padTextRight("Expires:", 5);
if (email.ExpiryDate > clock.seconds) {
text += clock.clockStringForTime(email.ExpiryDate) + "\n";
} else {
text += email.ExpiryText + "\n";
}
}
text += this.$padTextRight("Subject:", 5) + email.Subject + "\n";
text += this.$duplicate("-", 32) + "\n";
return text;
}
//-------------------------------------------------------------------------------------------------------------
// checks whether a response is required for this email.
// Returns true if there is a response and none has been selected, otherwise false.
this.$requiresResponse = function(email) {
var ret = false;
if ((email.ResponseOption1.DisplayText != "" || email.ResponseOption2.DisplayText != "" || email.ResponseOption3.DisplayText != "" || email.ResponseOption4.DisplayText != "") && email.ChosenOption === 0) {
ret = true;
}
return ret;
}
//-------------------------------------------------------------------------------------------------------------
// returns the inbox line for this email
this.$inboxDisplay = function(email) {
var ret = "";
if (email.Read === false) {
ret += this.$padTextRight("!", this._readColumn);
} else {
ret += this.$padTextRight("", this._readColumn);
}
ret += this.$padTextRight(email.Sender, 10);
ret += this.$padTextRight(this.$inboxTime(clock.clockStringForTime(email.TransmitDate)), 7.6);
ret += this.$padTextRight(email.Subject, 14);
return ret;
}
//-------------------------------------------------------------------------------------------------------------
// appends space to currentText to the specified length in 'em'
this.$padTextRight = function(currentText, desiredLength) {
if (currentText == null) currentText = "";
var hairSpace = String.fromCharCode(31);
var currentLength = defaultFont.measureString(currentText);
var hairSpaceLength = defaultFont.measureString(hairSpace);
var ellip = "…";
// calculate number needed to fill remaining length
var padsNeeded = Math.floor((desiredLength - currentLength) / hairSpaceLength);
if (padsNeeded < 1) {
// text is too long for column, so start pulling characters off
var tmp = currentText;
do {
tmp = tmp.substring(0, tmp.length - 2) + ellip;
if (tmp === ellip) break;
} while (defaultFont.measureString(tmp) > desiredLength);
currentLength = defaultFont.measureString(tmp);
padsNeeded = Math.floor((desiredLength - currentLength) / hairSpaceLength);
currentText = tmp;
}
if (padsNeeded < 0) padsNeeded = 0;
// quick way of generating a repeated string of that number
return currentText + new Array(padsNeeded).join(hairSpace);
}
//-------------------------------------------------------------------------------------------------------------
// works out whether a particular option should be displayed or not
this.$displayResponseOption = function(email, itemNumber) {
var bShow = false;
switch (itemNumber) {
case 1:
if (email.ResponseOption1 != null && email.ResponseOption1.DisplayText != "") bShow = true;
// if the expiry is turned off but this option was included as an expiry option, don't show it
if (email.ExpiryDate === 0 && email.ExpiryOptions.indexOf("1") >= 0) bShow = false;
if (email.ExpiryDate != 0) {
// don't show this option if it's an expiry option
if (email.ExpiryDate > clock.seconds && email.ExpiryOptions.indexOf("1") >= 0) bShow = false;
// don't show this option if the email has expired and it's not included in the expiry options
if (email.ExpiryDate <= clock.seconds && email.ExpiryOptions.indexOf("1") < 0) bShow = false;
}
break;
case 2:
if (email.ResponseOption2 != null && email.ResponseOption2.DisplayText != "") bShow = true;
// if the expiry is turned off but this option was included as an expiry option, don't show it
if (email.ExpiryDate === 0 && email.ExpiryOptions.indexOf("2") >= 0) bShow = false;
if (email.ExpiryDate != 0) {
// don't show this option if it's an expiry option
if (email.ExpiryDate > clock.seconds && email.ExpiryOptions.indexOf("2") >= 0) bShow = false;
// don't show this option if the email has expired and it's not included in the expiry options
if (email.ExpiryDate <= clock.seconds && email.ExpiryOptions.indexOf("2") < 0) bShow = false;
}
break;
case 3:
if (email.ResponseOption3 != null && email.ResponseOption3.DisplayText != "") bShow = true;
// if the expiry is turned off but this option was included as an expiry option, don't show it
if (email.ExpiryDate === 0 && email.ExpiryOptions.indexOf("3") >= 0) bShow = false;
if (email.ExpiryDate != 0) {
// don't show this option if it's an expiry option
if (email.ExpiryDate > clock.seconds && email.ExpiryOptions.indexOf("3") >= 0) bShow = false;
// don't show this option if the email has expired and it's not included in the expiry options
if (email.ExpiryDate <= clock.seconds && email.ExpiryOptions.indexOf("3") < 0) bShow = false;
}
break;
case 4:
if (email.ResponseOption4 != null && email.ResponseOption4.DisplayText != "") bShow = true;
// if the expiry is turned off but this option was included as an expiry option, don't show it
if (email.ExpiryDate === 0 && email.ExpiryOptions.indexOf("4") >= 0) bShow = false;
if (email.ExpiryDate != 0) {
// don't show this option if it's an expiry option
if (email.ExpiryDate > clock.seconds && email.ExpiryOptions.indexOf("4") >= 0) bShow = false;
// don't show this option if the email has expired and it's not included in the expiry options
if (email.ExpiryDate <= clock.seconds && email.ExpiryOptions.indexOf("4") < 0) bShow = false;
}
break;
}
return bShow;
}
//-------------------------------------------------------------------------------------------------------------
// duplicates text until it is just less than the desired length;
this.$duplicate = function(text, desiredLength) {
var res = "";
do {
res += text;
} while (defaultFont.measureString(res) < desiredLength);
res = res.substring(1, res.length);
return res;
}
//-------------------------------------------------------------------------------------------------------------
// adds a message to an array, splitting the lines based on a line width
this.$addMsgToArray = function(msg, ary, linewidth) {
var prt = " ";
if (msg.substring(0,1) === "~" || msg.substring(0,1) === "-") {
// don't indent this one
prt = "";
// remove the "~" char
if (msg.substring(0,1) === "~") msg = msg.substring(1, msg.length);
}
if (defaultFont.measureString(msg) > linewidth) {
var words = msg.split(" ");
var iPoint = 0
var nextWord = "";
do {
// add the space in (after the first word)
if (prt != "") prt += " ";
// add the word on
prt = prt + words[iPoint];
// get the next word in the array
if (iPoint < words.length - 1) {
nextWord = " " + words[iPoint + 1];
} else {
nextWord = ""
}
// check the width of the next with the nextword added on
if (defaultFont.measureString(prt + nextWord) > linewidth) {
// hit the max width - add the line and start again
ary.push(prt);
prt = "";
}
iPoint += 1;
// check for the end of the array, and output remaining text
if ((iPoint >= words.length) && (prt.trim() != "")) ary.push(prt);
} while (iPoint < words.length);
} else {
ary.push(prt + msg);
}
}
//=============================================================================================================
// screen interfaces
this.$initInterface = function(station) {
var unread = "";
var itms = this.$totalUnreadItems();
if (itms > 0) unread = " (" + itms.toString() + " unread" + (this.$totalUnreadItemsRequiringResponse() > 0 ? " •" : "") + ")"
station.setInterface(this.name,{
title:"Email system" + unread,
category:expandDescription("[interfaces-category-logs]"),
summary:"Opens your email inbox",
callback:this.$showInbox.bind(this)
});
}
//=============================================================================================================
// inbox
this.$showInbox = function() {
this._emailID = 0;
this._emailIndex = 0;
this._maxpage = Math.ceil(this.$totalItems() / this._msRows);
this._curpage = 0;
this._displayType = 0;
this.$showPage();
}
//-------------------------------------------------------------------------------------------------------------
this.$showPage = function() {
function compare(a,b) {
return b.TransmitDate - a.TransmitDate;
}
this._hudHidden = player.ship.hudHidden;
if (this.$isBigGuiActive() === false) player.ship.hudHidden = true;
this._emailOpen = true;
var text = "";
var opts;
var curChoices = {};
var def = "";
//=============================================================================================================
// inbox view
if (this._displayType === 0) {
// sort the inbox by date, newest to oldest
this._emails.sort(compare);
this._emailPage = 0;
var expired = false;
// look for and delete any expired emails
for (var i = this._emails.length - 1; i >= 0; i--) {
if (this._emails[i].ExpiryDate != 0 && clock.seconds > this._emails[i].ExpiryDate && this._emails[i].ExpiryText === "") {
this._emails.splice(i, 1);
expired = true;
}
}
// adjust the max page if we remove any expired emails
if (expired) this._maxpage = Math.ceil(this.$totalItems() / this._msRows);
curChoices = this.$inboxPageChoices(this._curpage, this._msRows);
// make sure the selected email stays selected, in case new emails arrived while we were viewing another email
if (this._emailID != 0 && this._emailIndex != this.$getChoiceItemIndex(this._emailID)) {
var old = this._emailIndex;
this._emailIndex = this.$getChoiceItemIndex(this._emailID);
if (this._emailIndex === 0 && old === this._msRows) {
// we've been bumped to a new page, so switch to it
this._curpage += 1;
curChoices = this.$inboxPageChoices(this._curpage, this._msRows);
this._emailIndex = this.$getChoiceItemIndex(this._emailID);
}
this._lastChoice[this._displayType] = "01_email-" + (this._emailIndex < 10 ? "0" : "") + this._emailIndex + "+" + this._emailID;
}
this._emailID = 0;
text = this.$padTextRight("", this._readColumn + 0.15);
text += this.$padTextRight("From", 10);
text += this.$padTextRight("Date", 7.6);
text += "Subject";
if (this._itemsOnPage === 0) text += "\n\n(no items to display)";
for (var i = 0; i < (this._msRows + 1) - this._itemsOnPage; i++) {
curChoices["02_SPACER_" + i] = "";
}
var def = "99_EXIT";
if (this._emails != null && this._emails.length != 0) {
if (this._curpage < this._maxpage - 1) {
curChoices["10_GOTONEXT"] = {text:"[emailopt_nextpage]", color:this._menuColor};
} else {
curChoices["10_GOTONEXT"] = {text:"[emailopt_nextpage]", color:this._disabledColor, unselectable:true};
}
if (this._curpage > 0) {
curChoices["11_GOTOPREV"] = {text:"[emailopt_prevpage]", color:this._menuColor};
} else {
curChoices["11_GOTOPREV"] = {text:"[emailopt_prevpage]", color:this._disabledColor, unselectable:true};
}
if (this.$totalReadItems() > 0) {
curChoices["42_MARKALLREAD"] = {text:"[emailopt_markallread]", color:this._menuColor};
curChoices["45_DELREAD"] = {text:"[emailopt_deleteread]", color:this._menuColor};
} else {
curChoices["42_MARKALLREAD"] = {text:"[emailopt_markallread]", color:this._disabledColor, unselectable:true};
curChoices["45_DELREAD"] = {text:"[emailopt_deleteread]", color:this._disabledColor, unselectable:true};
}
curChoices["50_DELALL"] = {text:"[emailopt_deleteall]", color:this._menuColor};
} else {
curChoices["10_GOTONEXT"] = {text:"[emailopt_nextpage]", color:this._disabledColor, unselectable:true};
curChoices["11_GOTOPREV"] = {text:"[emailopt_prevpage]", color:this._disabledColor, unselectable:true};
curChoices["42_MARKALLREAD"] = {text:"[emailopt_markallread]", color:this._disabledColor, unselectable:true};
curChoices["45_DELREAD"] = {text:"[emailopt_deleteread]", color:this._disabledColor, unselectable:true};
curChoices["50_DELALL"] = {text:"[emailopt_deleteall]", color:this._disabledColor, unselectable:true};
}
curChoices["99_EXIT"] = {text:"[emailopt_exit]", color:this._exitColor};
var opts = {
screenID: "oolite-emailsystem-main-map",
title: "Inbox - page " + (this._curpage + 1).toString() + " of " + this._maxpage.toString(),
allowInterrupt: true,
exitScreen: "GUI_SCREEN_INTERFACES",
overlay: {name:"email-message.png", height:546},
choices: curChoices,
initialChoicesKey: (this._lastChoice[this._displayType] ? this._lastChoice[this._displayType] : def),
message: text
};
}
//=============================================================================================================
// email item
if (this._displayType === 1) {
var email = this.$getEmailByID(this._emailID);
var headerlen = 4;
if (email.ExpiryDate !=0 && email.ExpiryDate > clock.seconds) {
headerlen += 1; // extra line if expiry date is still current
if (email.allowExpiryCancel) headerlen +=1; // another line for the "Cancel expiry" option
}
email.Read = true;
text += this.$header(email);
var lines = email.EmailBody.split("\n");
var dest = [];
for (var i = 0; i < lines.length; i++) {
this.$addMsgToArray(lines[i], dest, this._msCols);
}
// append any response to the body of the email
if (email.ChosenOption > 0) {
var resp = "";
resp += "\n";
resp += "~" + this.$duplicate("-", 32) + "\n";
resp += "~" + this.$padTextRight("Reply sent:", 5) + clock.clockStringForTime(email.ResponseDate) + "\n";
resp += "~Reply:\n\n";
switch (email.ChosenOption) {
case 1:
resp += email.ResponseOption1.ReplyText;
break;
case 2:
resp += email.ResponseOption2.ReplyText;
break;
case 3:
resp += email.ResponseOption3.ReplyText;
break;
case 4:
resp += email.ResponseOption4.ReplyText;
break;
}
var respLines = resp.split("\n");
for (var i = 0; i < respLines.length; i++) {
this.$addMsgToArray(respLines[i], dest, this._msCols);
}
}
var addText = "";
var iPageHeight = 16 + (4 - headerlen);
this._emailMaxPages = 0;
// check if
if (dest.length > iPageHeight && this.$requiresResponse(email) === true) {
// how many options are there?
var iRespCount = 0;
if ($displayResponseOption(email, 1)) iRespCount += 1;
if ($displayResponseOption(email, 2)) iRespCount += 1;
if ($displayResponseOption(email, 3)) iRespCount += 1;
if ($displayResponseOption(email, 4)) iRespCount += 1;
// reduce the page height by the number of responses
iPageHeight -= iRespCount;
}
if (dest.length > iPageHeight) {
this._emailMaxPages = Math.ceil(dest.length / iPageHeight);
addText = " (Page " + (this._emailPage + 1).toString() + " of " + this._emailMaxPages.toString() + ")";
}
var iStart = this._emailPage * iPageHeight; // when 0 then 0, when 1 then 16
var iEnd = this._emailPage * iPageHeight + iPageHeight; // when 0 then 16, when 1 then 32 etc
if (iEnd > dest.length) {
iEnd = dest.length;
}
for (var i = iStart; i <= iEnd - 1; i++) {
text += dest[i] + "\n";
}
def = "23_CLOSE";
if (this._emailMaxPages != 0) {
if (this._emailPage + 1 < this._emailMaxPages) {
curChoices["21_NEXTPAGE"] = {text:"[emailitem_nextpage]", color:this._menuColor};
def = "21_NEXTPAGE";
} else {
curChoices["21_NEXTPAGE"] = {text:"[emailitem_nextpage]", color:this._disabledColor, unselectable:true};
}
if (this._emailPage > 0) {
curChoices["22_PREVPAGE"] = {text:"[emailitem_prevpage]", color:this._menuColor};
} else {
curChoices["22_PREVPAGE"] = {text:"[emailitem_prevpage]", color:this._disabledColor, unselectable:true};
}
}
// if the force response option is turned on, disable all the close email options, so the player has to make a choice
if (email.ForceResponse === true && email.ChosenOption === 0) {
curChoices["23_CLOSE"] = {text:"[emailitem_close]", color:this._disabledColor, unselectable:true};
curChoices["23A_CLOSEOPEN"] = {text:"[emailitem_closeopen]", color:this._disabledColor, unselectable:true};
curChoices["24_CLOSEDEL"] = {text:"[emailitem_closedelete]", color:this._disabledColor, unselectable:true};
} else {
curChoices["23_CLOSE"] = {text:"[emailitem_close]", color:this._menuColor};
if (this.$findNextEmailID(this._emailID) >= 0) {
curChoices["23A_CLOSEOPEN"] = {text:"[emailitem_closeopen]", color:this._menuColor};
} else {
curChoices["23A_CLOSEOPEN"] = {text:"[emailitem_closeopen]", color:this._disabledColor, unselectable:true};
}
if (this.$requiresResponse(email) === true && email.ExpiryDate > clock.seconds && email.ChosenOption === 0) {
curChoices["24_CLOSEDEL"] = {text:"[emailitem_closedelete]", color:this._disabledColor, unselectable:true};
} else {
curChoices["24_CLOSEDEL"] = {text:"[emailitem_closedelete]", color:this._menuColor};
}
}
curChoices["25_TRACE"] = {text:"[emailitem_trace]", color:this._menuColor};
if (email.ExpiryDate != 0 && email.ExpiryDate > clock.seconds && email.AllowExpiryCancel === true) {
curChoices["25A_CANCELEXPIRY"] = {text:"[emailitem_cancelexpiry]", color:this._menuColor};
}
if (email.ChosenOption === 0) {
if (this.$displayResponseOption(email, 1)) curChoices["26_OPT1"] = {text:"Send '" + email.ResponseOption1.DisplayText + "' response", color:this._menuColor};
if (this.$displayResponseOption(email, 2)) curChoices["26_OPT2"] = {text:"Send '" + email.ResponseOption2.DisplayText + "' response", color:this._menuColor};
if (this.$displayResponseOption(email, 3)) curChoices["26_OPT3"] = {text:"Send '" + email.ResponseOption3.DisplayText + "' response", color:this._menuColor};
if (this.$displayResponseOption(email, 4)) curChoices["26_OPT4"] = {text:"Send '" + email.ResponseOption4.DisplayText + "' response", color:this._menuColor};
}
var opts = {
screenID: "oolite-emailsystem-item-map",
title: "Message" + addText,
allowInterrupt: false,
exitScreen: "GUI_SCREEN_INTERFACES",
overlay: {name:"email-message_open.png", height:546},
choices: curChoices,
initialChoicesKey: (this._lastChoice[this._displayType] != "" ? this._lastChoice[this._displayType] : def),
message: text
};
}
//=============================================================================================================
// trace
if (this._displayType === 2) {
var email = this.$getEmailByID(this._emailID);
var initText = "- Received: ";
text += this.$header(email);
text += "Trace:\n\n";
var planets = email.Trace.split(",");
var bEnd = false;
var bCrpt = false;
var colHeight = 16;
if (planets.length < colHeight) {
for (var i = 0; i < planets.length; i++) {
if (planets[i] != "") {
text += initText + planets[i] + "\n";
initText = "- Sent from: ";
}
}
} else {
for (var i = 0; i < colHeight; i++) {
if (planets[i] != "") {
text += this.$padTextRight(initText + planets[i], 10);
initText = "- Sent from: ";
if (i + colHeight < planets.length) {
if (planets[i + colHeight] != "") {
text += this.$padTextRight("- Sent from: " + planets[i + colHeight], 10);
}
}
if (i + colHeight === planets.length) {
if (email.CorruptTrace === true) {
text += "- Routing ticket corrupt";
bCrpt = true;
}
}
if (i + (colHeight * 2) < planets.length) {
if (planets[i + (colHeight * 2)] != "") {
text += this.$padTextRight("- Sent from: " + planets[i + (colHeight * 2)], 10);
}
}
if (i + (colHeight * 2) === planets.length) {
if (email.CorruptTrace === true) {
text += "- Routing ticket corrupt";
bCrpt = true;
}
}
text += "\n";
}
}
}
if (email.CorruptTrace === true) {
if (bCrpt === false) {
text += "- Routing ticket corrupt\n";
}
text += "\nTrace incomplete.";
} else if (bEnd === false){
text += "\nTrace complete.";
}
def = "27_CLOSE";
curChoices["27_CLOSE"] = {text:"[emailtrace_close]", color:this._exitColor};
var opts = {
screenID: "oolite-emailsystem-trace-summary",
title: expandDescription("[emailtrace_title]"),
allowInterrupt: false,
overlay: {name:"email-message_open.png", height:546},
exitScreen: "GUI_SCREEN_INTERFACES",
choices: curChoices,
initialChoicesKey: (this._lastChoice[this._displayType] != "" ? this._lastChoice[this._displayType] : def),
message: text
};
planets = [];
}
mission.runScreen(opts, this.$inboxHandler, this);
}
//-------------------------------------------------------------------------------------------------------------
this.$inboxHandler = function(choice) {
var curdisplay = this._displayType;
var newChoice = "";
var newChoicePage = 0;
this._lastChoice[this._displayType] = choice;
if (!choice) {
return; // launched while reading?
} else if (choice.indexOf("01_email") >= 0) {
this._emailID = parseInt(choice.substring(choice.indexOf("+") + 1));
this._emailIndex = parseInt(choice.substring(choice.indexOf("-") + 1, choice.indexOf("+")));
this._emailPage = 0;
this._displayType = 1;
} else if (choice === "11_GOTOPREV") {
this._curpage -= 1;
if (this._curpage === 0) {
newChoice = "10_GOTONEXT";
newChoicePage = this._displayType;
}
} else if (choice === "10_GOTONEXT") {
this._curpage += 1;
if (this._curpage === this._maxpage - 1) {
newChoice = "11_GOTOPREV";
newChoicePage = this._displayType;
}
} else if (choice === "42_MARKALLREAD") {
this.$markAllItemsRead();
} else if (choice === "45_DELREAD") {
this.$deleteReadItems();
} else if (choice === "50_DELALL") {
this.$deleteAllItems();
} else if (choice === "21_NEXTPAGE") {
this._emailPage += 1;
if ((this._emailPage - 1) === this._emailMaxPages) {
newChoice = "22_PREVPAGE";
newChoicePage = this._displayType;
}
} else if (choice === "22_PREVPAGE") {
this._emailPage -= 1;
if (this._emailPage === 0) {
newChoice = "21_NEXTPAGE";
newChoicePage = this._displayType;
}
} else if (choice === "23_CLOSE") {
this._displayType = 0;
} else if (choice === "23A_CLOSEOPEN") {
this._emailPage = 0;
// get next email id
this._emailID = this.$findNextEmailID(this._emailID);
// if this the last item on the page?
if (this._emailIndex === this._msRows && (this._curpage + 1) < this._maxpage) {
// we've flipped over to the next page
this._curpage += 1;
this.$inboxPageChoices(this._curpage, this._msRows);
}
this._emailIndex = this.$getChoiceItemIndex(this._emailID)
newChoice = "01_email-" + (this._emailIndex < 10 ? "0" : "") + this._emailIndex + "+" + this._emailID;
newChoicePage = 0;
} else if (choice === "24_CLOSEDEL") {
this._displayType = 0;
this.$deleteSelectedItem(this._emailID);
} else if (choice === "25_TRACE") {
this._displayType = 2;
} else if (choice === "25A_CANCELEXPIRY") {
this._emails[this.$getEmailIndexByID(this._emailID)].ExpiryDate = 0;
} else if (choice === "26_OPT1") {
// make sure the email hasn't expired while being viewed
if (this.$displayResponseOption(this.$getEmailByID(this._emailID), 1)) {
this.$recordResponse(this._emailID, 1);
this.$executeCallback(this._emailID, 1);
}
} else if (choice === "26_OPT2") {
// make sure the email hasn't expired while being viewed
if (this.$displayResponseOption(this.$getEmailByID(this._emailID), 2)) {
this.$recordResponse(this._emailID, 2);
this.$executeCallback(this._emailID, 2);
}
} else if (choice === "26_OPT3") {
// make sure the email hasn't expired while being viewed
if (this.$displayResponseOption(this.$getEmailByID(this._emailID), 3)) {
this.$recordResponse(this._emailID, 3);
this.$executeCallback(this._emailID, 3);
}
} else if (choice === "26_OPT4") {
// make sure the email hasn't expired while being viewed
if (this.$displayResponseOption(this.$getEmailByID(this._emailID), 4)) {
this.$recordResponse(this._emailID, 4);
this.$executeCallback(this._emailID, 4);
}
} else if (choice === "27_CLOSE") {
this._displayType = 1;
}
if (newChoice != "") this._lastChoice[newChoicePage] = newChoice;
if (choice != "99_EXIT") {
this.$showPage();
}
}
//-------------------------------------------------------------------------------------------------------------
this.$inboxPageChoices = function(cpage, lines) {
//var output = "";
var iStart = 0;
var iEnd = 0;
var offset = 0;
var choices = {};
// work out start point - start after any future dated emails
for (var i = 0; i < this._emails.length; i++) {
if (this._emails[i].TransmitDate <= clock.seconds) {
offset = i;
break;
}
}
// set out initial end point
iStart = offset;
iEnd = iStart + lines;
if (cpage != 0) {
iStart = (cpage * lines) + offset;
iEnd = iStart + lines;
}
if (iEnd > this._emails.length) {
iEnd = this._emails.length;
}
this._itemsOnPage = 0;
this._pageItems.length = 0;
if (this.$totalItems() != 0) {
for (var i = iStart; i < iEnd; i++) {
// put an index in the key for sorting, and add the id for selecting
this._itemsOnPage += 1;
choices["01_email-" + (this._itemsOnPage < 10 ? "0" : "") + this._itemsOnPage + "+" + this._emails[i].ID] = {text:this.$inboxDisplay(this._emails[i]), alignment:"LEFT", color:this._itemColor};
this._pageItems.push({ID:this._emails[i].ID, index:this._itemsOnPage});
}
}
return choices;
}
//-------------------------------------------------------------------------------------------------------------
this.$getChoiceItemIndex = function(id) {
var result = 0;
if (this._pageItems && this._pageItems.length > 0) {
for (var i = 0; i < this._pageItems.length; i++) {
if (this._pageItems[i].ID === id) result = this._pageItems[i].index;
}
}
return result;
}
//-------------------------------------------------------------------------------------------------------------
this.$inboxTime = function(emailTime) {
return emailTime.substring(0, emailTime.length - 3);
}
//-------------------------------------------------------------------------------------------------------------
// returns true if a HUD with allowBigGUI is enabled, otherwise false
this.$isBigGuiActive = function() {
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;
}
}
}
|
Scripts/galcopadmin.js |
"use strict";
this.name = "GalCopAdminServices";
this.author = "phkb";
this.copyright = "2017 phkb";
this.description = "Transmits emails to player from GalCop admin relating to bounty notifications and other admin processes.";
this.licence = "CC BY-NC-SA 4.0";
/*
Todo:
Check for docking fines on other station types (UPS Courier, Jaguar company, The collector, Aquatics, Resistance Commander, Lave Acedemy, FTZ, Planetfall);
Check for purchase equip on Black Monks Monestary (need different voice for email).
Ideas:
Welcome to new galaxy emails
- Tech Level 15 planets -- G1 Ceesxe, G2 Tezaeded, G3 none (14: LEZAER,BIRERA,LEORENDI,ORZAEDVE,TEEDUS,TIERA,CEDILE), G4 none (14: GEBIISSO,DICEBE),
G5 Xevera, G6 Diesanen, G7 Quandixe and Maraus, G8 none (14: ESUSALE).
- List of galactic regions
- List of galactic routes
- GalCop HQ's
- RRS station HQ locations
- Superhub locations
- Gal Navy sector commands
Constore emails about special deals
Space bar emails
Emails from revolutionists, saying "Here's the details of the conspiracy"
Emails from Hognose Evangelists telling player about their religion
Emails containing bargains for trade (ie "trade in Furs between X and Y for a super bargain. Offer won't last!" X will be system within 7 LY of player, Y will be within 10 LY of X.)
maybe two different emails: 1 saying nnn commodity is really cheap at X, 1 saying demand for nnn commodity is high at Y
have an opt in/opt out functionality
-- seems to be similar to function in NewCargoes OXP, but might be useful as an alternative (ie. if you don't want NewCargos, you can still get market bargins)
-- also similar to functionality in BlOomberg markets
*/
this._debug = true;
this._bountyEmailBody = ""; // holds details of next bounty email
this._bountyEmailTime = 0; // the time of the last kill
this._bountyEmailTotalCR = 0; // total amount of bounty
this._boughtEquipTimer = null;
this._killCount = 0; // total number of kills
this._killAssortedCount = 0; // total number of non-ship kills (eg missiles)
this._holdBountyEmail = []; // holds bounty emails across hyperspace jumps
this._disableBounty = false; // controls whether bounty emails are sent
this._disableDocking = false; // controls whether docking violation emails are sent
this._disableEscapePods = false; // controls whether escape pod rescue emails are sent
this._disableContracts = false; // controls whether contract emails are sent
this._disableFines = false; // controls whether fine processing emails are sent
this._disableEquipPurchase = false; // controls whether equipment purchase emails are sent
this._disableMaintenance = false; // controls whether repair and overhaul emails are sent
this._disableNewShip = false; // controls whether new ship emails are sent
this._disableEliteFederation = false; // controls whether changes to player rank are sent
this._defaultExpiryDays = 5; // default expiry period for emails that expire
this._repairHullDamage = false; // keeps track of hull damage email (Battle Damage OXP)
this._repairIronHide = false; // keeps track of iron hide repair emails (IronHide OXP)
this._sendMaintEmail = false; // keeps track of when we are sending maintenance emails (relates to IronHide OXP)
this._sendRepairEmail = false; // keeps track of when we are sending repair emails (relates to IronHide OXP)
this._maintCost = 0;
this._maintCostInit = 0;
this._equipItems = []; // list of equipment items, held in order to determine diff between purchase and repair
this._equipSalesRep = ""; // name of sales assistant for equipment
this._shipSalesRep = ""; // name of sales assistant for ships
this._maintRep = ""; // name of maintenance rep for repair or overhaul emails
this._dutyOfficer = ""; // station duty officer/flight controller (for docking fines)
this._galCopBountyOfficer = ""; // name of galcop bounty processor
this._insuranceOfficer = ""; // name of claims administrator (for escape pod insurance claims)
this._namesLocation = ""; // keeps track of the system/dock the names are associated with
this._galCopHQ = [7, 33, 26, 49, 102, 85, 202, 184]; // galcop hq locations in each sector
this._fedHQ = [131, 167, 58, 65, 230, 35, 181, 130]; // location of elite federation hq in each sector
this._playerEnteringShipyard = false; // keeps track of when the player enters the shipyard at a station, so we can check for buying a new ship
this._licenceNumber = ""; // holds the pilot licence number, in case it's ever needed
this._maintItemNameReplacements = ""; // holds list of maint item replacement name keys
this._trueValues = ["yes", "1", 1, "true", true];
this._playerEjected = false;
this._maint_ignore_equip = []; // no longer used, but kept for backwards compatibility.
this._oldPassengerCount = 0;
/* equipment known to have description items for an overhaul email */
this._maint_known_equip = ["EQ_CARGO_BAY", "EQ_ECM", "EQ_FUEL_SCOOPS", "EQ_ESCAPE_POD", "EQ_ENERGY_UNIT", "EQ_NAVAL_ENERGY_UNIT", "EQ_DOCK_COMP", "EQ_GAL_DRIVE",
"EQ_WEAPON_PULSE_LASER", "EQ_WEAPON_BEAM_LASER", "EQ_WEAPON_MINING_LASER", "EQ_WEAPON_MILITARY_LASER", "EQ_CLOAKING_DEVICE", "EQ_PASSENGER_BERTH", "EQ_FUEL_INJECTION",
"EQ_SCANNER_SHOW_MISSILE_TARGET", "EQ_MULTI_TARGET", "EQ_ADVANCED_COMPASS", "EQ_ADVANCED_NAVIGATIONAL_ARRAY", "EQ_TARGET_MEMORY", "EQ_INTEGRATED_TARGETING_SYSTEM",
"EQ_SHIELD_BOOSTER", "EQ_NAVAL_SHIELD_BOOSTER", "EQ_HEAT_SHIELD", "EQ_WORMHOLE_SCANNER", "EQ_WEAPON_TWIN_PLASMA_CANNON",
"EQ_LMSS_FRONT", "EQ_LMSS_AFT", "EQ_LMSS_PORT", "EQ_LMSS_STARBOARD", "EQ_LMSS_ACTUATOR"];
/* equipment items devoted to repair (not equipment in themselves) */
this._maint_repair_equip = ["EQ_HULL_REPAIR", "EQ_IRONHIDE_REPAIR", "EQ_TURRET_RECOVER", "EQ_SHIP_VERSION_REPAIR", "EQ_SERVICE_LEVEL_SMALL_FIX_1",
"EQ_SERVICE_LEVEL_SMALL_FIX_2", "EQ_SERVICE_LEVEL_SMALL_FIX_3", "EQ_SERVICE_LEVEL_SMALL_FIX_4"];
/* equipment items devoted to removal of equipment */
this._maint_remove_equip = ["EQ_PASSENGER_BERTH_REMOVAL", "EQ_MISSILE_REMOVAL", "EQ_WEAPON_NONE"];
/* equipment items to be ignored by the email system */
this._purchase_ignore_equip = ["EQ_FUEL", "EQ_MISSILE", "EQ_TRUMBLE", "EQ_RRS_FUEL", "EQ_SHIP_RESPRAY", "EQ_SHIP_RESPRAY_180", "EQ_SMUGGLING_COMPARTMENT", "EQ_IMPORT_PERMIT"];
// equipment items that will be immediately removed after purchase
this._purchase_removed = ["EQ_IRONHIDE_MIL", "EQ_REPAIRBOTS_RECHARGE_10", "EQ_REPAIRBOTS_RECHARGE_5"];
//======================================================================================================================
// Library config
this._galCopAdminConfig = {Name:this.name, Alias:"GalCop Admin Services", Display:"Config", Alive:"_galCopAdminConfig",
Bool:{
B0:{Name:"_disableBounty", Def:false, Desc:"Bounty emails"},
B1:{Name:"_disableDocking", Def:false, Desc:"Docking fine emails"},
B2:{Name:"_disableEscapePods", Def:false, Desc:"Escape pod emails"},
B3:{Name:"_disableContracts", Def:false, Desc:"Contract emails"},
B4:{Name:"_disableFines", Def:false, Desc:"Fine penalty emails"},
B5:{Name:"_disableEquipPurchase", Def:false, Desc:"Equip purchase emails"},
B6:{Name:"_disableNewShip", Def:false, Desc:"New ship emails"},
B7:{Name:"_disableMaintenance", Def:false, Desc:"Maintenance emails"},
B8:{Name:"_disableEliteFederation", Def:false, Desc:"Elite Fed emails"},
Info:"Set item to true to disable those emails from being transmitted."},
};
//=============================================================================================================
// ship interfaces
//-------------------------------------------------------------------------------------------------------------
this.startUp = function() {
// delete the missionScreenEnded routine if IronHide OXP is not installed
if (!worldScripts["IronHide Armour Script"]) delete this.missionScreenEnded;
}
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function() {
// register our settings, if Lib_Config is present
if (worldScripts.Lib_Config) worldScripts.Lib_Config._registerSet(this._galCopAdminConfig);
// load in the licence number if it's been saved
if (missionVariables.GalCopAdmin_licenceNumber) this._licenceNumber = missionVariables.GalCopAdmin_licenceNumber;
if (missionVariables.GalCopAdmin_DisableBounty) this._disableBounty = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableBounty) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableEscapePods) this._disableEscapePods = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableEscapePods) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableContracts) this._disableContracts = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableContracts) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableFines) this._disableFines = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableFines) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableEquipPurchase) this._disableEquipPurchase = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableEquipPurchase) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableNewShip) this._disableNewShip = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableNewShip) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableMaintenance) this._disableMaintenance = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableMaintenance) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableEliteFed) this._disableEliteFederation = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableEliteFed) >= 0 ? true : false);
if (missionVariables.GalCopAdmin_DisableDocking) this._disableDocking = (this._trueValues.indexOf(missionVariables.GalCopAdmin_DisableDocking) >= 0 ? true : false);
this._maintItemNameReplacements = expandDescription("[maint_itemname_list]");
// send a late notice pilot licence email
if (global.clock.clockStringForTime(global.clock.seconds).indexOf("2084004:20") === -1 && this._licenceNumber === "") {
this._licenceNumber = this.$generateLicenceNumber();
// pilot licence notification arrives shortly after the start
var lgl = expandDescription("[legalstatuswarnings_" + expandDescription("[commander_legal_status]") + "]");
var w = worldScripts.EmailSystem;
w.$createEmail({sender:expandDescription("[new-licence-sender]"),
subject:expandDescription("Re: New Pilot Registration"),
date:global.clock.adjustedSeconds,
message:expandDescription("[latenotice-licence]", {licenceno:this._licenceNumber, insertlegalstatus:lgl}),
sentFrom:this._galCopHQ[galaxyNumber]
});
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function() {
// save the licence number in worldscripts
//if (this._licenceNumber === "") this._licenceNumber = this.$generateLicenceNumber();
missionVariables.GalCopAdmin_licenceNumber = this._licenceNumber;
missionVariables.GalCopAdmin_DisableBounty = this._disableBounty;
missionVariables.GalCopAdmin_DisableEscapePods = this._disableEscapePods;
missionVariables.GalCopAdmin_DisableContracts = this._disableContracts;
missionVariables.GalCopAdmin_DisableFines = this._disableFines;
missionVariables.GalCopAdmin_DisableEquipPurchase = this._disableEquipPurchase;
missionVariables.GalCopAdmin_DisableNewShip = this._disableNewShip;
missionVariables.GalCopAdmin_DisableMaintenance = this._disableMaintenance;
missionVariables.GalCopAdmin_DisableEliteFed = this._disableEliteFederation;
missionVariables.GalCopAdmin_DisableDocking = this._disableDocking;
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation = function(station) {
var w = worldScripts.EmailSystem;
this.$setupRepNames(station);
// have we changed ranking?
var newrank = expandDescription("[commander_rank]");
if (this._oldrank != newrank && newrank != "Harmless" && this._disableEliteFederation === false) {
// send an email from the Elite Federation
// get clean version of rank
if (newrank.indexOf("Deadly") >=0) newrank = "Deadly";
if (newrank.indexOf("E L I T E") >=0 || newrank.indexOf("ELITE") >= 0) newrank = "Elite";
var pre = "a";
if ("AEIOU".indexOf(player.ship.shipClassName.substring(0,1)) >= 0) {
pre = "an";
}
w.$createEmail({sender:expandDescription("[elite-fed-sender]"),
subject:expandDescription("[elite-fed-subject-" + newrank + "]"),
date:global.clock.adjustedSeconds,
message:expandDescription("[elite-fed-body-" + newrank + "]", {shipnamepre:pre, realshipname:player.ship.shipUniqueName, galnum:(galaxyNumber + 1)}),
sentFrom:this._fedHQ[galaxyNumber]
});
}
// do we have any pending bounty notifications?
if (this._disableBounty === false && (this._bountyEmailBody != "" || (this._holdBountyEmail && this._holdBountyEmail.length > 0))) {
var include = "";
// have we got any bounty reports in the hold queue
if (this._holdBountyEmail && this._holdBountyEmail.length > 0) {
for (var i = 0; i < this._holdBountyEmail.length; i++) {
if (this._holdBountyEmail[i].bountySystem === "Interstellar space") {
include += "~In " + this._holdBountyEmail[i].bountySystem + ":\n" + this._holdBountyEmail[i].bountyEmail + "\n";
} else {
include += "~In the " + this._holdBountyEmail[i].bountySystem + " system:\n" + this._holdBountyEmail[i].bountyEmail + "\n";
}
}
// any stuff left to add? add another system marker
if (this._bountyEmailBody != "") {
if (this._bountySystem === "Interstellar space") {
include += "~In " + this._bountySystem + ":\n";
} else {
include += "~In the " + this._bountySystem + " system:\n";
}
}
// clean up
while(this._holdBountyEmail.length > 0) {
this._holdBountyEmail.pop();
}
}
// any emailbody holding info? add it to the include var
if (this._bountyEmailBody != "") include += this._bountyEmailBody;
// add warning for no-bounty kills
if (this._bountyEmailTotalCR > 0 && this._bountyEmailBody.indexOf("(no bounty)") >= 0) include += "\nPlease note that GalCop does not condone the killing of innocent pilots.\n";
// number of kills
var kills = "A total of " + this._killCount + " ships were destroyed";
if (this._killCount === 1) kills = "A single ship was destroyed";
var killasrt = "";
if (this._killAssortedCount > 0) {
killasrt = " (plus " + this._killAssortedCount + " other items)";
if (this._killAssortedCount === 1) killasrt = " (plus 1 other item)";
}
kills += killasrt;
var emailType = "[galcop-bounty-admin-body]";
// if we didn't have any bounty, switch to the no-bounty email type
if (this._bountyEmailTotalCR === 0) emailType = "[galcop-nobounty-admin-body]";
w.$createEmail({sender:expandDescription("[galcop-bounty-sender]"),
subject:"Bounty confirmation",
date:this._bountyEmailTime,
message:expandDescription(emailType, {bounty:formatCredits(this._bountyEmailTotalCR, false, true), bountybody:include, totalkills:kills, sender:this._galCopBountyOfficer}),
sentFrom:this._galCopHQ[galaxyNumber],
expiryDays:this._defaultExpiryDays}
);
this._bountyEmailBody = "";
this._bountyEmailTotalCR = 0;
this._bountyEmailTime = 0;
this._killCount = 0;
this._killAssortedCount = 0;
}
// player ejected
if (this._disableEscapePods === false && this._playerEjected === true) {
var msg = expandDescription("[escapepod-rescue-body]", {sender:randomName() + " " + randomName()});
w.$createEmail({sender:expandDescription("[escapepod-insurance-sender]"),
subject:"Rescue",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
// docking fine
if (this._disableDocking === false && station.requiresDockingClearance === true &&
player.dockingClearanceStatus != "DOCKING_CLEARANCE_STATUS_GRANTED" && player.dockingClearanceStatus != "DOCKING_CLEARANCE_STATUS_TIMING_OUT" &&
this._playerEjected === false && system.sun.isGoingNova === false) {
// what type of station is this?
var bSent = false;
// calculate fine
var fine = player.credits * 0.05;
if (fine > 5000) fine = 5000;
// main station
if (station.isMainStation === true) {
var msg = expandDescription("[galcop-docking-fine-body]", {fine:formatCredits(fine, true, true), stationname:station.displayName, sender:this._dutyOfficer});
w.$createEmail({sender:expandDescription("[galcop-docking-fine-sender]"),
subject:"Docking Penalty",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
bSent = true;
}
// seedy space bar
if (bSent === false && station.hasRole("random_hits_any_spacebar")) {
var msg = expandDescription("[ssb-docking-fine-body]", {fine:formatCredits(fine, true, true), stationname:station.displayName, sender:this._dutyOfficer});
w.$createEmail({sender:expandDescription("[ssb-docking-fine-sender]"),
subject:"Docking Penalty",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
bSent = true;
}
// blackmonk monestary
if (bSent === false && station.hasRole("blackmonk_monastery")) {
var msg = expandDescription("[bmm-docking-fine-body]", {fine:formatCredits(fine, true, true), stationname:station.displayName, sender:this._dutyOfficer});
w.$createEmail({sender:expandDescription("[bmm-docking-fine-sender]"),
subject:"Docking Penalty",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
bSent = true;
}
// constore
if (bSent === false && station.hasRole("constore")) {
var msg = expandDescription("[constore-docking-fine-body]", {fine:formatCredits(fine, true, true), stationname:station.displayName, sender:this._dutyOfficer});
w.$createEmail({sender:expandDescription("[constore-docking-fine-sender]"),
subject:"Docking Penalty",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
bSent = true;
}
// rescue station
if (bSent === false && station.hasRole("rescue_station")) {
var msg = expandDescription("[rs-docking-fine-body]", {fine:formatCredits(fine, true, true), stationname:station.displayName, sender:this._dutyOfficer});
w.$createEmail({sender:expandDescription("[rs-docking-fine-sender]"),
subject:"Docking Penalty",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
bSent = true;
}
// other?
if (bSent === false) {
var msg = expandDescription("[generic-docking-fine-body]", {fine:formatCredits(fine, true, true), stationname:station.name, sender:this._dutyOfficer});
w.$createEmail({sender:expandDescription("[generic-docking-fine-sender]"),
subject:"Docking Penalty",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
// general fine notification/payment
if (this._disableFines === false && player.ship.markedForFines === true && station.isMainStation && station.suppressArrivalReports === false && system.sun.isGoingNova === false && player.bounty < (50 - (system.info.government * 6))) {
// calculate what the fine is
var gov = 0;
var calc_fine = 0;
if (global.system.ID === -1) {
gov = 1;
} else {
gov = system.government;
}
calc_fine = 50 + ((gov < 2 || gov > 5) ? 50 : 0);
calc_fine *= player.bounty;
if (calc_fine > player.credits) {
calc_fine = player.credits;
}
if (calc_fine > 0) {
var msg = expandDescription("[marked-for-fines-intro]", {fine:formatCredits(calc_fine, true, true)});
if (player.bounty >= 50) {
msg += expandDescription("[marked-for-fines-fugitive]");
}
msg += expandDescription("[marked-for-fines-end]");
w.$createEmail({sender:expandDescription("[marked-for-fines-sender]"),
subject:"Fine payment",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
this._playerEjected = false;
}
//-------------------------------------------------------------------------------------------------------------
this.guiScreenChanged = function(to, from) {
// make a note of when we reach the shipyafrds screen
if (guiScreen === "GUI_SCREEN_SHIPYARD" && this._disableNewShip === false) {
var p = player.ship;
this._playerEnteringShipyard = true;
this._oldcredits = player.credits;
// calculate price of current ship
// reproduction of core code
this._storedShipCost = this.$cunningFee((((p.price - (p.price * 0.006 * this.$missingSubEntitiesAdjustment())) * 75 * p.serviceLevel) + 5000) / 10000 , 0.005);
// calculate price of stock in hold
this._storedManifestCost = 0;
for (var i = 0; i < manifest.list.length; i++) {
this._storedManifestCost += Math.round(manifest.list[i].quantity * (p.dockedStation.market[manifest.list[i].commodity].price / 10) * 100) / 100;
}
}
if (guiScreen != "GUI_SCREEN_SHIPYARD" && guiScreen != "GUI_SCREEN_STATUS" && this._playerEnteringShipyard === true) {
this._playerEnteringShipyard = false;
}
// sending an email at the start of a new game, welcome player to their just-purchased ship
// note, because of the way Hardships works, it's hard to know when the player has finished looking at ships and testing them
// so, if you have hardships installed, you won't get a welcome to your new ship email. Standard purchasing will still give an email
if (guiScreen === "GUI_SCREEN_STATUS" && player.name === "Jameson" && !worldScripts.hardships) {
if (global.clock.clockStringForTime(global.clock.seconds).indexOf("2084004:20") === 0 && !missionVariables.EmailSystem_newGame) {
// this is a new game, send new ship email
missionVariables.EmailSystem_newGame = 1;
this.$sendNewShipEmail(player.ship);
}
if (global.clock.clockStringForTime(global.clock.seconds).indexOf("2084004:20") === -1) {
// clean up
delete missionVariables.EmailSystem_newGame;
}
}
// send a pilot licence email
if (guiScreen === "GUI_SCREEN_STATUS" && player.name === "Jameson") {
if (global.clock.clockStringForTime(global.clock.seconds).indexOf("2084004:20") === 0 && this._licenceNumber === "") {
this._licenceNumber = this.$generateLicenceNumber();
// pilot licence notification arrives shortly after the start
var w = worldScripts.EmailSystem;
w.$createEmail({sender:expandDescription("[new-licence-sender]"),
subject:expandDescription("New Pilot Registration"),
date:global.clock.seconds + 40,
message:expandDescription("[new-licence]", {licenceno:this._licenceNumber}),
sentFrom:this._galCopHQ[galaxyNumber]
});
}
}
// make a note of the credit balance
if(to && to === "GUI_SCREEN_EQUIP_SHIP") {
this._oldcredits = player.credits;
this._oldPassengerCount = player.ship.passengerCapacity;
// if the Battle damage OXP is present, check for the HULL REPAIR item. If it's not on the player ship, there is hull damage to repair
var w = worldScripts["Battle Damage"];
if (w && missionVariables.BattleDamage_status === "DAMAGED") {
// there is hull damage to repair
this._repairHullDamage = true;
}
// if the Iron Hide OXP is present, check for damage so we can include an item in the email
w = worldScripts["IronHide Armour Script"];
if(w) {
if ((player.ship.equipmentStatus("EQ_IRONHIDE") === "EQUIPMENT_OK" || player.ship.equipmentStatus("EQ_IRONHIDE_MIL") === "EQUIPMENT_OK") && missionVariables.ironHide_percentage < 100) {
this._repairIronHide = true;
}
}
// store equipment status of all items so we can tell when it's a repair job
var p = player.ship;
var eq = p.equipment;
for (var i = 0; i < eq.length; i++) {
var q = eq[i];
this._equipItems.push({key:q.equipmentKey, status:p.equipmentStatus(q.equipmentKey)});
}
}
}
//-------------------------------------------------------------------------------------------------------------
// special case for IronHide
this.missionScreenEnded = function() {
// if the ironhide armour gets repairs during the maintenance overhaul, it calls a mission screen
// this will run when the mission screen ends
if (this._sendMaintEmail === true) {
this._sendMaintEmail = false;
this._maintCost = this._maintCostInit - player.credits;
this.$sendMaintenanceEmail()
}
// if the ironhide armour is repaired on its own, it still calls a mission screen
// this will run when that screen ends
if (this._sendRepairEmail === true) {
this._sendRepairEmail = false;
var msg = expandDescription("[purchase-maintenance]",
{shipname:player.ship.shipClassName,
maintenanceitems:"\n\n- Repair of IronHide armour",
servicecost:formatCredits(this._maintCostInit - player.credits, true, true),
costnote:"",
sender:this._maintRep
});
var w = worldScripts.EmailSystem;
w.$createEmail({sender:expandDescription("[purchase-maintenance-sender]"),
subject:"Repair (Invoice #" + (this.$rand(500000) + 100000).toString() + ")",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedEscapePod = function(pod, pass) {
this._playerEjected = true;
}
//-------------------------------------------------------------------------------------------------------------
this.playerBoughtEquipment = function(equipment) {
if (this._debug) log(this.name, "equipment " + equipment);
// start a timer to do all the bought equipment work
// this is to ensure any OXP processes have completed (like refunding) before we do out calculations
this._boughtKey = equipment
this._boughtStn = player.ship.dockedStation;
// make sure the timer isn't already running
if (this._boughtEquipTimer && this._boughtEquipTimer.isRunning) this._boughtEquipTimer.stop();
this._boughtEquipTimer = new Timer(this, this.$playerBoughtEquip, 1, 0);
}
//-------------------------------------------------------------------------------------------------------------
this.$playerBoughtEquip = function $playerBoughtEquip() {
var equipment = this._boughtKey;
if (this._debug) log(this.name, "bought key = " + equipment);
// work out where the purchase occurred
var stn = null;
if (this._boughtStn) {
stn = this._boughtStn;
} else {
if (player.ship.dockedStation) {
stn = player.ship.dockedStation;
} else {
stn = system.mainStation;
}
}
this._boughtStn = null;
// don't do anything for these items
if (this._purchase_ignore_equip.indexOf(equipment) >= 0) return;
var w = worldScripts.EmailSystem;
if (this._shipSalesRep === "") {
this.$setupRepNames(stn);
}
if (equipment !== "EQ_RENOVATION") {
// purchasing items
var etype = "purchase";
var subtype = 0;
var eq = EquipmentInfo.infoForKey(equipment);
// work out what sort of purchase this was: standard purchase, repair or removal
// we could be repairing something so check the statuses we saved when we switched to the equip ship screen
if (this._equipItems && this._equipItems.length > 0) {
for (var i = 0; i < this._equipItems.length; i++) {
if (this._equipItems[i].key === equipment && this._equipItems[i].status === "EQUIPMENT_DAMAGED") etype = "repair";
}
}
// if the equipment key itself has "REPAIR" in it, switch to repair mode
if (this._maint_repair_equip.indexOf(equipment) >= 0 || (equipment.indexOf("REPAIR") >= 0 && equipment.indexOf("REPAIRBOTS") === 0)) etype = "repair";
// if the equipment key itself has "REMOVAL" in it, switch to removal mode
var desc = eq.description.toLowerCase();
if (this._maint_remove_equip.indexOf(equipment) >= 0 ||
(desc.indexOf("remove") >= 0 ||
(desc.indexOf("sell ") >= 0 && desc.indexOf("buy ") === -1) ||
desc.indexOf("unmount") >= 0 ||
desc.indexOf("undo ") >= 0 ||
equipment.indexOf("REFUND") >= 0))
{etype = "remove"; subtype = 1;}
// if the player doesn't have the equipment anymore, it must be a removal
// this should really only be triggered by an external pack calling the playerBoughtEquipment routine manually (see Ship Configuration for an example)
if (etype === "purchase") {
if (equipment != "EQ_PASSENGER_BERTH" && player.ship.equipmentStatus(equipment) !== "EQUIPMENT_OK" && this._purchase_removed.indexOf(equipment) === -1) etype = "remove";
}
var extra = "";
var msg = "";
var itemname = "";
// see if there is a replacement description for this piece of equipment
if (this._maintItemNameReplacements.indexOf(equipment) >= 0) {
itemname = expandDescription("[maint_itemname_" + equipment + "]");
if (!itemname || itemname === "" || itemname.indexOf("[maint_") >= 0) {
itemname = eq.name;
}
} else {
itemname = eq.name;
}
if (this._debug) {
log(this.name, "etype = " + etype);
log(this.name, "subtype = " + subtype);
log(this.name, "old creds = " + this._oldcredits);
log(this.name, "curr creds = " + player.credits);
}
switch (etype) {
case "remove":
if (this._disableEquipPurchase === false) {
var cost = "";
// were we charged something, or did we get a refund?
if (eq.price != 0) {
if ((this._oldcredits - player.credits) < 0) {
if (subtype === 1) {
cost = "The cost of this service was " + formatCredits(eq.price / 10, true, true) + ", but all together you were refunded " + formatCredits(player.credits - this._oldcredits, true, true) + ".";
} else {
cost = "In total you were refunded " + formatCredits(player.credits - this._oldcredits, true, true) + ".";
}
} else {
cost = "You were charged " + formatCredits(this._oldcredits - player.credits, true, true) + ".";
}
} else {
if ((this._oldcredits - player.credits) < 0) {
cost = "In total you were refunded " + formatCredits(player.credits - this._oldcredits, true, true) + ".";
} else {
cost = "There was no charge for this service.";
}
}
msg = expandDescription("[remove-equip]",
{stationname:stn.displayName,
equipname:itemname,
equipcost:cost,
sender:this._equipSalesRep
});
w.$createEmail({sender:expandDescription("[purchase-equip-sender]"),
subject:"Removing equipment",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
// special case for escape pod
if (equipment === "EQ_ESCAPE_POD") {
msg = expandDescription("[escapepod-sold-body]",
{sender:randomName() + " " + randomName()
});
w.$createEmail({sender:expandDescription("[escapepod-insurance-sender]"),
subject:"Contract termination",
date:global.clock.adjustedSeconds + 150,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
break;
case "purchase":
if (this._disableEquipPurchase === false) {
var paid = ((eq.price / 10) * stn.equipmentPriceFactor);
if (this._oldcredits != player.credits + ((eq.price / 10) * stn.equipmentPriceFactor)) {
paid = (this._oldcredits - player.credits);
// did we get a refund for an existing weapon?
if (equipment.indexOf("EQ_WEAPON") >= 0) {
extra = "(Note: You were refunded the cost of any laser that was removed in order to install your new one.)";
// switch back to the direct equipment price, otherwise the email text gets confusing
paid = ((eq.price / 10) * stn.equipmentPriceFactor);
}
}
if (this._debug) log(this.name, "paid = " + paid);
msg = expandDescription("[purchase-equip]",
{stationname:stn.displayName,
extranote:extra,
equipname:itemname + ": " + eq.description,
equipcost:"The cost of this item was " + formatCredits(paid, true, true),
sender:this._equipSalesRep
});
// make the missle purchase email more reasonable.
if (equipment.indexOf("MISSILE") >= 0) {
msg = msg.replace("We hope you will enjoy many years of trouble-free use of this item.", "We hope this item performs flawlessly for you when you need it.");
}
w.$createEmail({sender:expandDescription("[purchase-equip-sender]"),
subject:"Purchasing equipment",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
// special case for escapepods - send insurance application notification
if (equipment === "EQ_ESCAPE_POD") {
msg = expandDescription("[escapepod-purchase-body]",
{sender:randomName() + " " + randomName()
});
w.$createEmail({sender:expandDescription("[escapepod-insurance-sender]"),
subject:"Insurance Application",
date:global.clock.adjustedSeconds + 300,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
break;
case "repair":
if (this._disableMaintenance === false) {
if (equipment === "EQ_IRONHIDE_REPAIR") {
this._sendRepairEmail = true;
this._maintCostInit = this._oldcredits;
} else {
if ((this._oldcredits - player.credits) > 0) {
var maint = "";
if (eq.name.toLowerCase().indexOf("repair") >= 0) {
maint = "\n\n- " + eq.name;
} else {
maint = "\n\n- Repair of " + eq.name;
}
// special cases - ShipVersion OXP
if (equipment === "EQ_TURRET_RECOVER") maint = "\n\n- Recovery of destroyed turrets";
if (equipment === "EQ_SHIP_VERSION_REPAIR") maint = "\n\n- Restoring the recharge bonuses provided by Ship Version equipment.";
msg = expandDescription("[purchase-maintenance]",
{shipname:player.ship.shipClassName,
maintenanceitems:maint,
servicecost:formatCredits(this._oldcredits - player.credits, true, true),
costnote:"",
sender:this._maintRep
});
var w = worldScripts.EmailSystem;
w.$createEmail({sender:expandDescription("[purchase-maintenance-sender]"),
subject:"Repair (Invoice #" + (this.$rand(500000) + 100000).toString() + ")",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
}
break;
}
if (equipment === "EQ_IRONHIDE_REPAIR") this._repairIronHide = false;
if (equipment === "EQ_HULL_REPAIR") this._repairHullDamage = false;
} else {
if (this._disableMaintenance === false) {
if (this._repairIronHide === false) {
// if there's no ironhide armour repair, send the email immediately
this._maintCost = this._oldcredits - player.credits;
this.$sendMaintenanceEmail();
} else {
// otherwise set up params for sending email later
this._sendMaintEmail = true;
this._maintCostInit = this._oldcredits;
}
}
}
this._oldcredits = player.credits;
}
//-------------------------------------------------------------------------------------------------------------
this.playerBoughtNewShip = function(ship, price) {
if (this._playerEnteringShipyard === true && this._disableNewShip === false) {
this._newShipCost = (this._oldcredits + this._storedShipCost + this._storedManifestCost) - player.credits;
this._playerEnteringShipyard = false;
this.$sendNewShipEmail(ship);
}
this._oldcredits = player.credits;
}
//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation = function(station) {
// make a note of the rank we have on launch
this._oldrank = expandDescription("[commander_rank]");
// make a note of the system we launch in
this._bountySystem = system.name;
}
//-------------------------------------------------------------------------------------------------------------
this.shipKilledOther = function(whom, damageType) {
// don't record anything if this is a siumulator run
if (this.$simulatorRunning()) return;
if (whom.isMissile) {
this._killAssortedCount += 1;
this._bountyEmailTime = global.clock.seconds;
}
if (!whom.hasRole("escape-capsule") && (whom.isPiloted || whom.isDerelict || whom.hasRole("tharglet") || whom.hasRole("thargon"))) {
// increment the kill counter
this._killCount += 1;
this._bountyEmailTime = global.clock.seconds;
// but was their a bounty?
if (whom.bounty > 0) {
// add a new item to the bounty email body
var true_bounty = whom.bounty;
if (whom.isCargo || whom.scanClass == "CLASS_BUOY" || whom.scanClass == "CLASS_ROCK") true_bounty = whom.bounty / 10;
this._bountyEmailBody += "~- Destruction of " + whom.displayName + " for " + formatCredits(true_bounty, false, true) + ".\n";
this._bountyEmailTotalCR += true_bounty;
} else {
// add a no bounty item to the email body
this._bountyEmailBody += "~- Destruction of " + whom.displayName + " (no bounty).\n";
}
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipExitedWitchspace = function() {
// if we enter a system while there is some bounty email body hanging around, put it into an array so we can itemise it later
if (this._bountyEmailBody != "") {
if (!this._holdBountyEmail) {
this._holdBountyEmail = [];
}
this._holdBountyEmail.push({bountyEmail:this._bountyEmailBody, bountySystem:this._bountySystem});
this._bountyEmailBody = "";
}
this._bountySystem = system.name;
}
//-------------------------------------------------------------------------------------------------------------
// bounty on scooped escape capsule (1.81 only)
this.playerRescuedEscapePod = function(fee, reason, occupant) {
var w = worldScripts.EmailSystem;
var msg = "";
var subj = "";
var sndr = "";
switch (reason) {
case "insurance":
sndr = expandDescription("[escapepod-insurance-sender]");
subj = "Salvage fee for escape pod recovery";
msg = expandDescription("[escapepod-insurance-body]",
{occupant:occupant.name,
description:occupant.description,
fee:formatCredits(fee / 10, true, true),
sender:this._insuranceOfficer
});
break;
case "bounty":
sndr = expandDescription("[galcop-bounty-sender]");
subj = "Bounty for escape pod recovery";
msg = expandDescription("[escapepod-bounty-body]",
{occupant:occupant.name,
description:occupant.description,
fee:formatCredits(fee / 10, true, true),
sentFrom:this._galCopHQ[galaxyNumber],
sender:this._galCopBountyOfficer
});
break;
//case "slave":
}
if (sndr != "" && this._disableEscapePods === false) {
w.$createEmail({sender:sndr,
subject:subj,
date:global.clock.seconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
//-------------------------------------------------------------------------------------------------------------
// send email to player when a contract is started. (1.81 only)
this.playerEnteredContract = function(type, contract) {
var w = worldScripts.EmailSystem;
var msg = "";
var subj = "";
var sndr = "";
switch (type) {
case "cargo":
sndr = expandDescription("[cargo-contract-sender]");
subj = "Accepted contract: " + contract.cargo_description;
msg = expandDescription("[cargo-contract-start]",
{description:contract.cargo_description,
systemname:System.systemNameForID(contract.destination),
time:global.clock.clockStringForTime(contract.arrival_time),
fee:formatCredits(contract.fee, true, true)
});
break;
case "passenger":
sndr = expandDescription("[passenger-contract-sender]");
subj = "Accepted contract: " + contract.name;
msg = expandDescription("[passenger-contract-start]",
{contractname:contract.name,
systemname:System.systemNameForID(contract.destination),
time:global.clock.clockStringForTime(contract.arrival_time),
fee:formatCredits(contract.fee, true, true)
});
break;
case "parcel":
sndr = expandDescription("[parcel-contract-sender]");
subj = "Accepted contract: " + contract.name;
msg = expandDescription("[parcel-contract-start]",
{contractname:contract.name,
systemname:System.systemNameForID(contract.destination),
time:global.clock.clockStringForTime(contract.arrival_time),
fee:formatCredits(contract.fee, true, true)
});
break;
}
if (sndr != "" && this._disableContracts === false) {
w.$createEmail({sender:sndr,
subject:subj,
date:global.clock.adjustedSeconds,
message:msg
});
}
}
//-------------------------------------------------------------------------------------------------------------
// result of parcel/passenger/cargo contract (1.81 only)
this.playerCompletedContract = function(type, result, fee, contract) {
var w = worldScripts.EmailSystem;
if (this._disableContracts === false) {
var msg = "";
var subj = "";
var sndr = "";
sndr = expandDescription("[" + type + "-contract-sender]");
msg = expandDescription("[" + type + "-contract-" + result + "]",
{description:contract.cargo_description,
contractname:contract.name,
systemname:System.systemNameForID(contract.destination),
time:global.clock.clockStringForTime(contract.arrival_time),
fee:formatCredits(fee / 10, true, true)
});
subj = expandDescription("[" + type + "-contract-" + result + "-subject]");
w.$createEmail({sender:sndr,
subject:subj,
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
}
//-------------------------------------------------------------------------------------------------------------
// sends the maintenance email
this.$sendMaintenanceEmail = function() {
var maint = "";
var item = "";
var count = 0;
var hasLCB = false;
var extra = "";
if (this._repairIronHide === true) extra = " (includes cost of IronHide armour repair)";
// add common items
maint += "\n\n~General ship maintenance tasks\n";
maint += expandDescription("[maintitem_all]");
// add general items
do {
item = expandDescription("[maintitem_general]");
if (item.trim() != "") {
// because the first word of the item can be random, check if everything after the first word exists in our maintenance list yet
// only add it if it doesn't exist
if (maint.indexOf(item.substring(item.indexOf(" ")).trim()) === -1) {
maint += "\n- " + item;
count += 1;
}
}
} while (count < system.info.techlevel);
var p = player.ship;
var itemname = "";
var diagtype = expandDescription("[maintperform]");
maint += "\n\n~Equipment specific maintenance tasks"
// if the player ship hyperspace capable?
if (p.hasHyperspaceMotor) {
maint += "\n- " + diagtype + " diagnostics on Witchspace Drive";
maint += "\n- " + expandDescription("[maint_Hyperspace]");
}
// get list of equipment keys to ignore (hull damage equipment item from the Battle Damage OXP, IronHide item, and any cats/dogs from Ships Cat OXP)
// add equipment specific items;
for (var i = 0; i < p.equipment.length; i++) {
var e_item = p.equipment[i];
if (this._maint_known_equip.indexOf(e_item.equipmentKey) >= 0) {
// can this item be repaired in this system?
if ((e_item.techLevel - 1) <= system.info.techlevel && e_item.isVisible) {
// is this piece of equipment OK (don't do maintenance on damaged equipment)
if (p.equipmentStatus(e_item.equipmentKey) === "EQUIPMENT_OK") {
// add a diagnostic entry for all items
itemname = e_item.name;
// check if we have a large cargo bay - we'll use this later on
if (e_item.equipmentKey === "EQ_CARGO_BAY") hasLCB = true;
// special case for passenger berth, as its name has extraneous text in it
if (e_item.equipmentKey === "EQ_PASSENGER_BERTH") itemname = "Passenger Berth";
maint += "\n- " + diagtype + " diagnostics on " + itemname;
// get a maintenance item for this equipment
item = expandDescription("[maint_" + e_item.equipmentKey + "]");
// do we have a real value? if so, add it to the list
if (item.indexOf("[") === -1 && item.trim() != "") maint += "\n- " + item;
} else if (p.equipmentStatus(e_item.equipmentKey) === "EQUIPMENT_DAMAGED") {
// this item is damaged - just note it in the message
// add a diagnostic entry for all items
itemname = e_item.name;
// special case for passenger berth, as its name has extraneous text in it
if (e_item.equipmentKey === "EQ_PASSENGER_BERTH") itemname = "Passenger Berth";
item = "Identified repairs required for " + itemname;
maint += "\n- " + item;
}
}
}
}
// did the player repair the ironhide armour?
if ((p.equipmentStatus("EQ_IRONHIDE") === "EQUIPMENT_OK" || p.equipmentStatus("EQ_IRONHIDE_MIL") === "EQUIPMENT_OK") && missionVariables.ironHide_percentage === 100 && this._repairIronHide === true) {
// player repaired ironhide armour
maint += "\n- Repair IronHide armour";
this._repairIronHide = false;
}
// for battle damage OXP, add an item to show that the damage has been repaired
if (this._repairHullDamage === true) {
maint += "\n- Repair hull damage";
this._repairHullDamage = false;
}
// do we have any cargo space but no LCB?
if (p.cargoSpaceCapacity > 0 && hasLCB === false) {
maint += "\n- " + expandDescription("[maint_CargoBay]");
}
// do we have any missiles?
if (p.missileCapacity > 0) {
maint += "\n- " + diagtype + " diagnostics on missile system";
maint += "\n- " + expandDescription("[maint_MissileSystem]");
}
// weapon equipment items don't appear in the ship.equipment array, so we need to do an individual check for each one
if (p.forwardWeapon && p.forwardWeapon.equipmentKey != "EQ_WEAPON_NONE" && this._maint_known_equip.indexOf(p.forwardWeapon.equipmentKey) >= 0) {
if (p.forwardWeapon.techLevel <= (system.info.techlevel - 1)) {
maint += "\n- " + diagtype + " diagnostics on front " + p.forwardWeapon.name;
item = expandDescription("[maint_" + p.forwardWeapon.equipmentKey + "]", {pos:"front"});
maint += "\n- " + item;
}
}
if (p.aftWeapon && p.aftWeapon.equipmentKey != "EQ_WEAPON_NONE" && this._maint_known_equip.indexOf(p.aftWeapon.equipmentKey) >= 0) {
if (p.aftWeapon.techLevel <= (system.info.techlevel - 1)) {
maint += "\n- " + diagtype + " diagnostics on aft " + p.aftWeapon.name;
item = expandDescription("[maint_" + p.aftWeapon.equipmentKey + "]", {pos:"aft"});
maint += "\n- " + item;
}
}
if (p.portWeapon && p.portWeapon.equipmentKey != "EQ_WEAPON_NONE" && this._maint_known_equip.indexOf(p.portWeapon.equipmentKey) >= 0) {
if (p.portWeapon.techLevel <= (system.info.techlevel - 1)) {
maint += "\n- " + diagtype + " diagnostics on port " + p.portWeapon.name;
item = expandDescription("[maint_" + p.portWeapon.equipmentKey + "]", {pos:"port"});
maint += "\n- " + item;
}
}
if (p.starboardWeapon && p.starboardWeapon.equipmentKey != "EQ_WEAPON_NONE" && this._maint_known_equip.indexOf(p.starboardWeapon.equipmentKey) >= 0) {
if (p.starboardWeapon.techLevel <= (system.info.techlevel - 1)) {
maint += "\n- " + diagtype + " diagnostics on starboard " + p.starboardWeapon.name;
item = expandDescription("[maint_" + p.starboardWeapon.equipmentKey + "]", {pos:"starboard"});
maint += "\n- " + item;
}
}
maint += "\n- Ship detailing and valet service\n- Parts and labour";
var msg = expandDescription("[purchase-maintenance]",
{shipname:p.shipClassName,
maintenanceitems:maint,
servicecost:formatCredits(this._maintCost, true, true),
costnote:extra,
sender:this._maintRep
});
var w = worldScripts.EmailSystem;
w.$createEmail({sender:expandDescription("[purchase-maintenance-sender]"),
subject:"Overhaul (Invoice #" + (this.$rand(500000) + 100000).toString() + ")",
date:global.clock.adjustedSeconds,
message:msg,
expiryDays:this._defaultExpiryDays
});
}
//-------------------------------------------------------------------------------------------------------------
// sends new ship email
this.$sendNewShipEmail = function(ship) {
// make sure we have created the rep names
if (this._shipSalesRep === "") this.$setupRepNames();
var equip = "";
var specs = "";
var inj = 7;
if (0 >= oolite.compareVersion("1.81")) inj = ship.injectorSpeedFactor;
var wpn = "\n Front - ";
if (ship.forwardWeapon && ship.forwardWeapon.equipmentKey != "EQ_WEAPON_NONE") {
wpn += ship.forwardWeapon.name;
} else {
wpn += "None";
}
if (" 3 7 11 15 ".indexOf(" " + ship.weaponFacings.toString() + " ") >= 0) {
wpn += "\n Aft - ";
if (ship.aftWeapon && ship.aftWeapon.equipmentKey != "EQ_WEAPON_NONE") {
wpn += ship.aftWeapon.name;
} else {
wpn += "None";
}
}
if (" 5 7 13 15 ".indexOf(" " + ship.weaponFacings.toString() + " ") >= 0) {
wpn += "\n Port - ";
if (ship.portWeapon && ship.portWeapon.equipmentKey != "EQ_WEAPON_NONE") {
wpn += ship.portWeapon.name;
} else {
wpn += "None";
}
}
if (" 9 11 13 15 ".indexOf(" " + ship.weaponFacings.toString() + " ") >= 0) {
wpn += "\n Starboard - ";
if (ship.starboardWeapon && ship.starboardWeapon.equipmentKey != "EQ_WEAPON_NONE") {
wpn += ship.starboardWeapon.name;
} else {
wpn += "None";
}
}
specs = "- Max speed/thrust: " + (ship.maxSpeed / 1000).toFixed(3) + "/" + (ship.maxThrust / 1000).toFixed(3) + " LS\n" +
"- Injector speed: " + ((ship.maxSpeed * inj) / 1000).toFixed(3) + " LS\n" +
"- Max pitch/roll/yaw: " + ship.maxPitch.toFixed(2) + "/" + ship.maxRoll.toFixed(2) + "/" + ship.maxYaw.toFixed(2) + "\n" +
"- Laser mounts: " + wpn + "\n" +
"- Missile pylons: " + ship.missileCapacity + "\n" +
"- Cargo capacity: " + ship.cargoSpaceCapacity + " tons\n" +
"- Max energy: " + (ship.maxEnergy) + " units\n" +
"- Energy recharge rate: " + ship.energyRechargeRate.toFixed(2) + " units/sec\n" +
"- Hyperspace capable: " + ship.hasHyperspaceMotor + "\n";
if (ship.equipment.length > 0) {
equip = "Your ship also came equipped with the following items:\n";
var added = false;
var e = ship.equipment;
for (var i = 0; i < e.length; i++) {
var q = e[i];
if ("EQ_HULL_REPAIR".indexOf(q.equipmentKey) === -1) {
if (q.isPortableBetweenShips === false && q.isVisible === true) {
equip += "- " + q.name + "\n";
added = true
}
}
}
if (added === false) {
equip = "";
} else {
equip += "\n";
}
}
var cost = ship.price;
var extra = "";
if (this._newShipCost) {
cost = this._newShipCost;
extra = " As part of this transaction your old ship was traded for " + formatCredits(this._storedShipCost, false, true);
if (this._storedManifestCost > 0) extra += ", and the content of your hold was traded for " + formatCredits(this._storedManifestCost, true, true);
extra += ".";
}
var msg = expandDescription("[purchase-ship]",
{stationname:player.ship.dockedStation.displayName,
shipclass:ship.shipClassName,
shipspecs:specs,
shipequip:equip,
shipcost:formatCredits(cost, false, true),
extracost:extra,
rndsystem:System.systemNameForID(this.$rand(256)-1),
sender:this._shipSalesRep
});
var w = worldScripts.EmailSystem;
w.$createEmail({sender:expandDescription("[purchase-ship-sender]"),
subject:"Purchase of new ship",
date:global.clock.adjustedSeconds,
message:msg
});
// transfer of ownership email arrives shortly after the first one.
w.$createEmail({sender:"GalCop Ship Registry",
subject:"Transfer of ownership",
date:global.clock.adjustedSeconds + 25,
message:expandDescription("[new-ship-transfer]")
});
}
//-------------------------------------------------------------------------------------------------------------
// return a random number between 1 and max
this.$rand = function(max) {
return Math.floor((Math.random() * max) + 1)
}
//-------------------------------------------------------------------------------------------------------------
// generates a random licence number in the format "GPL000000-XX000-XX0000"
this.$generateLicenceNumber = function() {
var ln = "GPL";
ln += (this.$rand(800000) + 100000);
ln += "-" + expandDescription("[licencecodes]");
ln += (this.$rand(500) + 200);
ln += "-" + expandDescription("[licencecodes]");
ln += (this.$rand(8000) + 1000);
return ln;
}
//-------------------------------------------------------------------------------------------------------------
// set up and store various names for inclusion in emails
this.$setupRepNames = function(station) {
if (!station && !player.ship.dockedStation) station = system.mainStation;
if (!station && player.ship.dockedStation) station = player.ship.dockedStation;
// if we just redocked at the same station, don't change anything
if (this._namesLocation === system.name + "-" + station.displayName) return;
this._namesLocation = system.name + "-" + station.displayName;
this._shipSalesRep = randomName() + " " + randomName();
this._equipSalesRep = randomName() + " " + randomName();
this._maintRep = randomName() + " " + randomName();
this._dutyOfficer = randomName() + " " + randomName();
this._insuranceOfficer = randomName() + " " + randomName();
// bounty processing occurs in a central location, so only update the officer occasionally
if (this._galCopBountyOfficer === "") {
this._galCopBountyOfficer = randomName() + " " + randomName();
} else {
if (this.$rand(20) > 15) this._galCopBountyOfficer = randomName() + " " + randomName();
}
}
//-------------------------------------------------------------------------------------------------------------
// reproductions of core code to try and work out an accurate trade in value for the player's ship
this.$cunningFee = function(value, precision) {
var fee = value;
var superfee = 100000.0;
var max = 1 + precision;
var min = 1 - precision;
var rounded_fee = superfee * Math.floor(0.5 + fee / superfee);
if (rounded_fee === 0) rounded_fee = 1;
var ratio = fee / parseFloat(rounded_fee);
while ((ratio < min || ratio > max) && superfee > 1)
{
rounded_fee = superfee * Math.floor(0.5 + fee / superfee);
if (rounded_fee === 0) rounded_fee = 1;
ratio = fee / parseFloat(rounded_fee);
superfee /= 10.0;
}
if (ratio > min && ratio < max) fee = rounded_fee;
return fee;
}
//-------------------------------------------------------------------------------------------------------------
this.$missingSubEntitiesAdjustment = function() {
// each missing subentity depreciates the ship by 5%, up to a maximum of 35% depreciation.
var percent = 5 * (player.ship.subEntityCapacity - player.ship.subEntities.length);
return (percent > 35 ? 35 : percent);
}
//-------------------------------------------------------------------------------------------------------------
this.$simulatorRunning = function() {
var w = worldScripts["Combat Simulator"];
if (w && w.$checkFight && w.$checkFight.isRunning) return true;
return false;
}
|