| Config/script.js | "use strict";
this.name = "PrimeableEquipmentMFD";
this.author = "Nicholas Menchise";
this.copyright = "(C) 2019 Nicholas Menchise";
this.licence = "CC BY-NC-SA 4.0";
//
// This world script includes the instructions for an MFD that lists the primeable equipment
// on the player ship and indicates the current selection.
//
// Whether or not the MFD requires calibration.
this.$calibrateMe = false;
// Whether or not there is any functional primeable equipment on the player ship.
this.$primeAnything = false;
// Stores the array of equipment keys for primed equipment on the player ship in the order that it's primed.
// The first value should always be an empty string for the None setting.
this.$primeQueue = [""];
// Stores the index value for the current selection in the prime queue.
this.$primeIndex = 0;
// Stores the timer that checks the calibration and current selection at regular intervals. Set by shipLaunchedFromStation event handler.
this.$detectSelection = null;
// Stores the MFD key.
this.$mfdKey = "nm_primeable-mfd";
// Stores the MFD strings.
// 0 is the MFD title.
// 1 informs the player that no primeable equipment is available.
// 2 informs the player that calibration is required.
// 3 informs the player that calibration is restarting due to error.
// 4 informs the player that calibration was successful.
// 5 is the instruction to initiate the calibration sequence.
// 6 is the instruction to continue the calibration sequence.
//
this.$mfdStrings = [
    "Primeable Equipment",
    "\n\n\n  None available.",
    "\n\n\n  Calibration Required\n\n",
    "\n\n\n  Error found. Restarting...",
    "\n\n\n  Calibration Done\n\n    Press prime button to\n    display list.",
    "    Set prime to None. If already\n    None, set to None again.",
    "    Press prime button until\n    done.  "
];
//
// Updates the MFD.
//
// This function is called by $detectSelection timer.
//
this._updateSelection = function() {
    var thisPrimeEquip = player.ship.primedEquipment;
    var arrayPrimeEquip = this.$primeQueue;
    var mfdText = this.$mfdStrings;
    var mfdTitle = mfdText[0];
    // Checks calibration and requests calibration, if required. See the function below.
    this._checkCalibration(thisPrimeEquip, arrayPrimeEquip, mfdTitle, mfdText[1], mfdText[2], mfdText[5]);
    if (this.$calibrateMe) {
        return;
    } else {
        // Compares the primed equipment to the current selection indicated in the MFD. Updates the MFD if they don't match.
        var thatPrimeEquip = "May or may not match.";
        var indexPrimeEquip = this.$primeIndex;
        if (indexPrimeEquip >= 0) thatPrimeEquip = arrayPrimeEquip[indexPrimeEquip];    // see shipWillDockWithStation event handler below
        if (thisPrimeEquip !== thatPrimeEquip) this._regularMfdString(thisPrimeEquip, arrayPrimeEquip, arrayPrimeEquip.length, mfdTitle);
    }
}
//
// Returns the number of functional primeable equipment items on the player ship.
//
// This function is called by _checkCalibration and _calibrateMeUpdate functions.
//
// yourShip argument stores a reference to the object representing the player ship.
//
this._getTotalPrime = function(yourShip) {
    var playerEquip = yourShip.equipment;
    var totalPrime = 0;
    var multi = [];
    for (var n = 0; n < playerEquip.length; n++) {
        if (playerEquip[n].scriptName.length > 0 && multi.indexOf(playerEquip[n].equipmentKey) == -1) {
            var eq = EquipmentInfo.infoForKey(playerEquip[n].equipmentKey);
            if (yourShip.equipmentStatus(playerEquip[n]) === "EQUIPMENT_OK") totalPrime++;
            // if this equipment item can carry multiple, add it to the multi list so we don't add it to the count more than once
            if (eq.canCarryMultiple) multi.push(eq.equipmentKey)
        }
    }
    return totalPrime;
}
//
// Checks if calibration is required and requests calibration, if necessary.
//
// This function is called by _updateSelection function.
//
// thisPrimeEquip argument stores the equipment key for the equipment that is currently primed.
// arrayPrimeEquip argument stores the array of equipment keys for primed equipment on the player ship in the order that it's primed.
// mfdTitle argument stores the title string for the MFD.
// mfdNone argument stores the string informing the player that no primeable equipment is available.
// mfdNeed argument stores the string informing the player that calibration is required.
// mfdDo argument stores the string instructing the player to prime the None setting.
//
this._checkCalibration = function(thisPrimeEquip, arrayPrimeEquip, mfdTitle, mfdNone, mfdNeed, mfdDo) {
    var yourShip = player.ship;
    var primeTotal = this._getTotalPrime(yourShip);
    // Calibration not required if there is no functional primeable equipment on the ship. Informs the player that none is available.
    if (primeTotal == 0) {
        this.$detectSelection.stop();    // the timer should be stopped if there's no primeable equipment
        yourShip.setMultiFunctionText(this.$mfdKey, mfdTitle + mfdNone);
        this.$primeAnything = false;
        this.$calibrateMe = false;
        return;
    } else {
        this.$primeAnything = true;
        primeTotal++;    // incremented to account for the None option in the prime queue
    }
    // Calibration required if equipmentRepaired event handler set calibrateMe to true.
    var needCalibration = false;
    if (this.$calibrateMe) needCalibration = true;
    // Calibration required if total number of functional primeable equipment items does not match the total in the prime queue.
    if (primeTotal != arrayPrimeEquip.length) needCalibration = true;
    // Calibration required if primed equipment is not found in the prime queue.
    var foundPrimeEquip = arrayPrimeEquip.indexOf(thisPrimeEquip);
    if (foundPrimeEquip < 0) needCalibration = true;
    // Prepares MFD for calibration and instructs player to calibrate.
    if (needCalibration) {
        this.$calibrateMe = true;
        this.$detectSelection.stop();
        this.$primeQueue.length = 0;    // the array should be empty until the player primes the None setting
        yourShip.setMultiFunctionText(this.$mfdKey, mfdTitle + mfdNeed + mfdDo);
    }
}
//
// Assigns calibration update to MFD.
//
// This function is called by playerChangedPrimedEquipment event handler.
//
// newPrimeEquip argument stores the next equipment key for calibration.
// countPrimeEquip argument is the total number of items in the prime queue.
// mfdTitle argument stores the title string for the MFD.
// mfdNeed argument stores the string informing the player that calibration is required.
// mfdError argument stores the string informing the player that calibration is restarting due to error.
// mfdDone argument stores the string informing the player that calibration was successful.
// mfdDo argument stores the string instructing the player to press the prime button until done.
//
this._calibrateMeUpdate = function(newPrimeEquip, countPrimeEquip, mfdTitle, mfdNeed, mfdError, mfdDone, mfdDo) {
    var updateText;
    var yourShip = player.ship;
    var donePresses = this._getTotalPrime(yourShip) + 1;
    var duplicateError = false;
    if (newPrimeEquip === "" && countPrimeEquip == 1) {
        // Calibration sequence begins.
        updateText = mfdTitle + mfdNeed + mfdDo + "0/" + donePresses;
    } else if (newPrimeEquip !== "" && countPrimeEquip < donePresses) {
        // Calibration sequence continues.
        var alreadyThere = this.$primeQueue.indexOf(newPrimeEquip);
        if (alreadyThere >= 0) duplicateError = true;    // calibration will fail if the equipment is already in the prime queue
        var x = this.$primeQueue.push(newPrimeEquip);
        updateText = mfdTitle + mfdNeed + mfdDo + countPrimeEquip + "/" + donePresses;
    } else if (newPrimeEquip === "" && countPrimeEquip == donePresses) {
        // Calibration sequence finishes.
        this.$calibrateMe = false;
        updateText = mfdTitle + mfdDone;
        this.$detectSelection.start();
    } else {
        duplicateError = true;    // calibration failing, using duplicateError boolean for convenience
    }
    if (duplicateError) {
        // Restarts calibration, if error found. Informs player on the MFD.
        yourShip.setMultiFunctionText(this.$mfdKey, mfdTitle + mfdError);
        this.$primeQueue.length = 0;    // array is emptied to prevent false positive if player keeps pressing prime button
        this.$detectSelection.nextTime = clock.absoluteSeconds + 2;    // timer should not be running when this happens
        this.$detectSelection.start();
    } else {
        // Passes calibration update to the MFD.
        yourShip.setMultiFunctionText(this.$mfdKey, updateText);
    }
}
//
// Updates primeable equipment list on MFD.
//
// This function is called by _updateSelection function and playerChangedPrimedEquipment event handler.
//
// nextPrimeEquip argument is the equipment key of the newly primed equipment.
// arrayPrimeEquip argument stores the array of equipment keys for primed equipment on the player ship in the order that it's primed.
// countPrimeEquip argument is the total number of items in the prime queue.
// mfdTitle argument stores the title string for the MFD.
//
this._regularMfdString = function(nextPrimeEquip, arrayPrimeEquip, countPrimeEquip, mfdTitle) {
    // Defines the strings that indicate whether or not the equipment is currently primed.
    var gapUnselected = "      ";
    var gapSelected = ">>  ";
    // Sets the first line of the MFD, which includes title, current selection position and total items in prime queue.
    var sayThisMfd = mfdTitle;
    this.$primeIndex = arrayPrimeEquip.indexOf(nextPrimeEquip);
    var nextPrimeIndex = this.$primeIndex;
    var lastOne = countPrimeEquip - 1;
    sayThisMfd = sayThisMfd + "                  " + nextPrimeIndex + "/" + lastOne + "\n";
    // Sets the second line of the MFD, which is either blank or equipment item prior to the current selection.
    if (countPrimeEquip > 2 && nextPrimeIndex == 0) {
        sayThisMfd += gapUnselected;
        sayThisMfd += this._getEquipName(arrayPrimeEquip[lastOne]);
        sayThisMfd += "\n";
    } else if (countPrimeEquip > 2 && nextPrimeIndex > 1) {
        sayThisMfd += gapUnselected;
        sayThisMfd += this._getEquipName(arrayPrimeEquip[nextPrimeIndex - 1]);
        sayThisMfd += "\n";
    } else {
        sayThisMfd += "\n";
    }
    // Sets the third line of the MFD, which is the current selection.
    sayThisMfd += gapSelected;
    sayThisMfd += this._getEquipName(arrayPrimeEquip[nextPrimeIndex]);
    sayThisMfd += "\n";
    // Sets the rest of the lines of the MFD, which are the items following the current selection in the prime queue.
    var alreadyShowed = 0;
    if (countPrimeEquip > 2) alreadyShowed = 2;
    if (countPrimeEquip <= 2) alreadyShowed = 1;
    var showLimit = countPrimeEquip - alreadyShowed;
    var x = nextPrimeIndex + 1;
    for (var n = 1; n <= showLimit; n++) {
        if (n == 8) break;    // there are seven lines available in the MFD for this loop
        if (x == countPrimeEquip) x = 0;
        sayThisMfd += gapUnselected;
        sayThisMfd += this._getEquipName(arrayPrimeEquip[x]);
        x++;
        if (n < 7) sayThisMfd += "\n";
    }
    player.ship.setMultiFunctionText(this.$mfdKey, sayThisMfd);
}
//
// Returns the display name of a primeable equipment item. The name is truncated if it's more than 32 characters.
// The None setting is displayed as an empty string.
//
// This function is called by _regularMfdString function.
//
// thisEquipPlease argument is the equipment key of the item to be named.
//
this._getEquipName = function(thisEquipPlease) {
    var thisEquipName = "";
    if (thisEquipPlease.length > 0) thisEquipName = EquipmentInfo.infoForKey(thisEquipPlease).name;
    if (thisEquipName.length > 32) thisEquipName = thisEquipName.substring(0, 30) + "...";
    return thisEquipName;
}
//
// Event handlers.
//
this.shipWillDockWithStation = function(station) {
    // Nullifies the timer. Timer documentation states that timer should be stopped before nullifying.
    // Condition statement is due to the possibility of a shipLaunchedEscapePod event beforehand.
    if (this.$detectSelection != null) this.$detectSelection.stop();
    this.$detectSelection = null;
    // Clears the MFD text and sets negative index value to force MFD update when ship launches, otherwise
    // the MFD will not list anything until the player presses the prime key or calibration is done.
    player.ship.setMultiFunctionText(this.$mfdKey, this.$mfdStrings[0]);
    this.$primeIndex = -1;
}
this.shipLaunchedFromStation = function(station) {
    // Sets the timer.
    this.$detectSelection = new Timer(this, this._updateSelection, 0, 1);
}
this.shipDied = function(whom, why) {
    // Nullifies the timer. Timer documentation states that timer should be stopped before nullifying.
    this.$detectSelection.stop();
    this.$detectSelection = null;
}
this.equipmentDamaged = function(equipment) {
    // Removes the equipment from the prime queue, if it's primeable.
    if (!this.$calibrateMe && EquipmentInfo.infoForKey(equipment).scriptName.length > 0) {
        var x = this.$primeQueue.indexOf(equipment);
        var y = this.$primeQueue.splice(x, 1);
        if (this.$primeIndex > x) this.$primeIndex--;
    }
}
this.equipmentRemoved = function(equipmentKey) {
    // Removes the equipment from the prime queue, if it's there. The condition statement is different from the one in
    // equipmentDamaged event handler due to the possibility of damaged primeable equipment in the argument.
    var x = this.$primeQueue.indexOf(equipmentKey);
    if (!this.$calibrateMe && x >= 0) {
        var y = this.$primeQueue.splice(x, 1);
        if (this.$primeIndex > x) this.$primeIndex--;
    }
}
this.equipmentRepaired = function(equipment) {
    // This code is only intended for in-flight repairs, which is possible with some expansion packs.
    if (!player.ship.docked && EquipmentInfo.infoForKey(equipment).scriptName.length > 0) {
        // Calibration is required, if equipment is primeable. Prepares MFD for calibration and informs the player.
        this.$detectSelection.stop();
        var mfdText = this.$mfdStrings;
        player.ship.setMultiFunctionText(this.$mfdKey, mfdText[0] + mfdText[3]);
        this.$primeQueue.length = 0;    // array is emptied to prevent false positive if calibration already in progress
        if (this.$calibrateMe) this.$detectSelection.nextTime = clock.absoluteSeconds + 2;    // delay if calibration already in progress
        this.$calibrateMe = true;
        this.$detectSelection.start();
    }
}
this.playerChangedPrimedEquipment = function(equipmentKey) {
    var arrayPrimeEquip = this.$primeQueue;
    var howManyPrime = arrayPrimeEquip.length;
    var mfdText = this.$mfdStrings;
    if (equipmentKey === "" && this.$calibrateMe && howManyPrime < 1) {
        // Start calibration sequence.
        var x = this.$primeQueue.push("");
        howManyPrime++;
        this._calibrateMeUpdate(equipmentKey, howManyPrime, mfdText[0], mfdText[2], mfdText[3], mfdText[4], mfdText[6]);
    } else if (this.$calibrateMe && howManyPrime > 0) {
        // Continue calibration sequence.
        this._calibrateMeUpdate(equipmentKey, howManyPrime, mfdText[0], mfdText[2], mfdText[3], mfdText[4], mfdText[6]);
    } else if (!this.$calibrateMe && this.$primeAnything) {
        // List the primeable equipment.
        this._regularMfdString(equipmentKey, arrayPrimeEquip, howManyPrime, mfdText[0]);
    } 
}
this.shipLaunchedEscapePod = function(escapepod) {
    // Nullifies the timer. Timer documentation states that timer should be stopped before nullifying.
    this.$detectSelection.stop();
    this.$detectSelection = null;
}
 |