Back to Index Page generated: May 8, 2024, 6:16:03 AM

Expansion Fuel Tweaks

Content

Warnings

  1. Required Expansions mismatch between OXP Manifest and Expansion Manager at character position 0071 (DIGIT ZERO vs LATIN SMALL LETTER N)
  2. No version in dependency reference to oolite.oxp.phkb.MarketScriptInterface:null

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Changes how fuel works, to make sun skimming more useful and profitable. Changes how fuel works, to make sun skimming more useful and profitable.
Identifier oolite.oxp.phkb.FuelTweaks oolite.oxp.phkb.FuelTweaks
Title Fuel Tweaks Fuel Tweaks
Category Mechanics Mechanics
Author phkb and Thargoid phkb and Thargoid
Version 1.14.5 1.14.5
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
  • oolite.oxp.phkb.MarketScriptInterface:0
  • oolite.oxp.phkb.MarketScriptInterface:
  • Optional Expansions
    Conflict Expansions
    Information URL https://wiki.alioth.net/index.php/Fuel_Tweaks n/a
    Download URL https://wiki.alioth.net/img_auth.php/3/35/FuelTweaks.oxz n/a
    License Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme file Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme file
    File Size n/a
    Upload date 1697074383

    Documentation

    Also read http://wiki.alioth.net/index.php/Fuel%20Tweaks

    readme.txt

    Fuel Tweaks
    By Nick Rogers
    
    Overview
    ========
    This OXP came out of a BB discussion where the idea was to make fuel scooping both (a) more desirable, and (b) more likely to happen. This OXP seeks to meet these goals in the following ways:
        1. The fuel system can be tweaked in a number of ways. It can operate as normal, or fuel rationing could be in effect, limiting the amount of fuel that can be bought at stations. Refuelling stations can also be installed, which effectively moves the purchase of fuel to be outside the main station. All of these scenarios can be altered by Javascript functions (see below).
        2. Scooped fuel can be collected in fuel storage containers and sold for profit.
    
    This is a concept OXP, designed to feed discussion and experimentation.
    
    Commodities
    ===========
    A new trade good has been added to the system: Quirium Fuel. This trade good gets its best price at mainly agricultural systems.
    
        Item            Description                         Average Price/cr    Units 
        Quirium Fuel    Fuel scooped from a star's corona               30.0    TC
    
    Equipment
    =========
    The following equipment items have been added to the game:
    
    Quirium Fuel Processor
    ----------------------
    This device replicates some of the fuel scooping system except, rather than putting the fuel into the main tank, processed fuel is stored in specialised fuel storage containers. The Fuel Processor is automatically activated during the fuel scoop process when the ship's main tank is full. 
    
    The Fuel Processor comes equipped with 1 fuel container, so simply by purchasing this item pilots will be able to scoop 1t of quirium fuel.
    
        Cost:           450.0 Cr
        Availability:   TL4
    
    Quirium Fuel Storage Unit
    -------------------------
    Fuel storage units can store 1t of Quirium fuel. Until used they will not consume any cargo space. When fuel is scooped and processed the units will expand to hold the fuel. If Quirium Fuel is dumped, a fuel storage unit will be dumped with it. When it is scooped, the fuel storage unit will be scooped as well.
    
        Cost:           50.0 Cr
        Availability:   TL3
    
    Quirium Fuel Transfer
    ---------------------
    This device is a slightly unstable method of moving fuel from storage and into the main ship tank. Quirium fuel is highly volatile, and the connection between the fuel processor and all storage units is designed to be one-way during flight. The Fuel transfer device is a third party add-on which breaches some of the containment protocols of the storage units in order to extract fuel and dump it in the main engine fuel tank. There is a chance that cargo loss or equipment damage could result from the transfer process. There have been reports of complete ship destruction in extreme cases, but these reports are rare.
    
    To transfer fuel during flight, prime the "Quirium Fuel Transfer" equipment, then press the "n" (activate) key twice to start transferring fuel. Press the "n" key a third time (or use the "b" (mode) key) to stop the process.
    
    A minimum 1t of Quirium fuel will be used regardless of how much is actually transferred to the main tank. Excess fuel is dumped to prevent any additional damage. For example, transferring 0.4LY of fuel will use 1t of Quirium. Transferring 6.4LY of fuel will also use 1t. Stopping the transfer process will dump the excess fuel from the container, meaning that each time you start the transfer you will use 1t of Quirium fuel.
    
        Cost:           1380.0 Cr
        Availability:   TL7
    
    Options
    =======
    The "fuelTweaks_fuelEconomy.js" file contains a variety of functions and settings to control where fuel is sold, how much can be sold, and the presence of refuelling stations. While this file can be manually adjusted to taste, the preferred way is by using the following JavaScript interfaces described below.
    
    Fuel stations
    -------------
    If fuel stations are enabled for a particular system, they will appear towards the edge of scanner range behind the main station. To get refuelled, simply fly into the station and come to a halt when directed. Fuel will then be transferred. WHen finished, exit the station and your account will be charged.
    
    Fuel rations
    ------------
    Some systems may have introduced a ration system, where a limited amount of fuel is available for purchase at the main station. Once you have purchased your ration, you will be unable to purchase any more fuel in that system until you jump out and come back.
    
    Fuel Collector OXP
    ------------------
    If Frame's Fuel Collector OXP is installed, the Fuel Collector will collect fuel into the Fuel Processor once the ship's tank is full.
    
    JavaScript interfaces
    =====================
    Note: Changes made to the fuel system via these JavaScript methods will persist across save games.
    
    Fuel
    ----
    The following Javascript methods control access to the sale of fuel through the F3 interface:
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$addFuelAvailability(ecos : array, govs : array, tl : int[, useRations : boolean]);
    
        Adds a economy/government/min techlevel fuel availability setting. "ecos" and "govs" are arrays containing integers between 0 and 7.
        To ignore the economy or government, pass an empty array.
        tl is an integer, being the minimum techlevel required, between -1 and 15 (-1 means no techlevel check is performed)
        useRations is an optional flag indicating that fuel rations will be used at these systems, rather than the standard fuel.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$setMaxFuelRation(maxVal : int);
    
        Sets the maximum amount of fuel that can be purchased through a non-refuelling stations
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$setFuelAllegiance(alleg: array);
    
        Sets an array of allegiance types to control what stations can sell fuel.
        An empty array means all stations can sell fuel.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$addFuelSystemOverride(sysID : int, avail : boolean [, useRations : boolean [, maxRation : int]]);
    
        Adds a system specific override to the fuel system.
        avail determines whether fuel will be available for sale.
        useRations determines whether fuel rationing is in effect
        maxRation sets the maximum amount of fuel ration that can be sold.
    
    Refuelling stations
    -------------------
    The following methods control the presence of refueling stations:
    Note: Refuel stations will not be present if no fuel is available in the system.
    Note: If a refueling station is present in a system, fuel will not be for sale in other stations.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$addRefuelStationAvailability(ecos : array, govs : array, tl : int);
    
        Adds a economy/government/min techlevel fuel availability setting. "ecos" and "govs" are arrays containing integers between 0 and 7.
        To ignore the economy or government, pass an empty array.
        tl is an integer, being the minimum techlevel required, between -1 and 15 (-1 means no techlevel check is performed)
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$setRefuelStationCostFactor(cf : decimal);
    
        Sets the default cost factor applied to fuel sales at refuelling stations. default 0.15
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$addRefuelStationSystemOverride(sysID : int, avail : boolean, costFactor : decimal);
    
        Adds an refuel station override item for the speficied system ID.
        avail = true means a refuel station will always be present, false means it will never be present
        costFactor is the cost factor applied to fuel sales through the refuel station.
        Note: Fuel must be available in the system before a refuelling station can be added.
    
    General methods
    ---------------
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$isFuelAvailable([sysID : int]);
    
        Returns true if the passed system ID (or the current system if no value passed) will have fuel available (either at the station itself or via a refuelling station). Otherwise false.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$fuelRationsInUse([sysID : int]);
    
        Returns true if fuel rationing is in use in the passed system ID.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$getMaxFuelRation([sysID: int]);
    
        Returns the maximum fuel ration permitted in the passed system ID.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$isRefuelStationAvailable([sysID : int]);
    
        Returns true if the passed system ID (or the current system if no value passed) will have refuelling stations present. Otherwise false.
        Note: Fuel must be available in the system before a refuelling station can be added.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$reset();
    
        Resets all fuel settings back to their default.
    
    Or you can change the data elements directly in fuelTweaks_fuelEconomy.js. ;)
    
    License
    =======
    This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 4.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
    
    With thanks to Thargoid for his fly-through Fuel Station (from the Fuel Station OXP), and to gsagostinho for his amazing textures.
    
    Discussion
    ==========
    This OXP is discussed at this forum link: http://aegidian.org/bb/viewtopic.php?f=4&t=18947
    
    Version History
    ===============
    1.14.5
    - Made compatible with MarketScriptInterface.oxz.
    
    1.14.4
    - The current state of the Quirium Fuel Processor (ie. how full it is) is now shown on the F5F5 Manifest screen.
    
    1.14.3
    - A Quirium Fuel Storage Unit will now automatically be awarded whenever a quirium fuel cargo container is scooped.
    
    1.14.2
    - Bug fixes.
    
    1.14.1
    - Fixed invalid character in shipdata.plist file.
    
    1.14
    - Fixed issue with repairing damaged fuel storage units.
    
    1.13.1
    - Removed debug log messages.
    
    1.13
    - Fixed issue with Fuel Collector taking too long to fill up accumulator when scooping fuel in free space.
    - Fixed issue with Fuel Collector turning off the Quirium Fuel Processor when scooping fuel from the sun.
    
    1.12
    - Bug fixes and tweaks to the fuel transfer process.
    - Added link to Fuel Collector OXP to enable the fuel collector to collect fuel into the fuel processor.
    - Added variable pricing for pirate fuel, based on the amount of fuel required.
    
    1.11
    - Excluded fuel items from getting purchase notifications via the Email System.
    - Scooping ejected quirium fuel containers will now award the player a Quirium Fuel Storage unit, so they can safely keep the cargo, rather than requiring the cargo be auto-ejected.
    - Dumping quirium fuel will now dump a fuel storage unit along with it.
    - Adjusted the prices of the Quirium Fuel Storage unit and it's associated removal item.
    - Adjusted fuel storage equipment item configuration to handle case where player might have scooped some Quirium fuel and received fuel storage units, but without having a fuel processor.
    - Better logic for determining if an escape pod is installed.
    - Fixed missing variable definition errors during self-destruct sequence.
    - Fixed output messages including a "0" during the self-destruct sequence.
    - Corrected readme and wiki page regarding the Quirium Fuel Transfer equipment item and process.
    
    1.10
    - Bug fixes.
    
    1.9
    - NPC AI not being set to correct file to use fuel stations.
    - Updated texture on fuel station, turned off the "smooth" setting.
    
    1.8
    - Better handling of interstellar space.
    - Fuel can now be purchased at some chaotic and pirate stations in systems where there is some sort of fuel restrictions in place, but at a price.
    
    1.7
    - Fixed invalid reference bug after exiting witchspace.
    
    1.6
    - Added missing cost factor to refuel station availability code.
    
    1.5
    - Message about fuel not being for sale incorrectly being broadcast even when rations are available.
    - Added information about fuel availability to the F7 System Data screen.
    - Fixed incorrect TL variable reference in various lookup functions.
    - Tweaks to checking functions to make them more logical.
    
    1.4
    - Bug fixes.
    
    1.3
    - Tweaks to the equipment.plist file.
    - Added 5 and 6 ly fuel rations.
    - Tweaks to the logic of the various properties to make system clearer.
    - Added textures from gsagostinho's updated version of Fuel Stations.
    - Added reset function to remove any fuel-related settings currently in use.
    - Bug fixes.
    
    1.2
    - Set the default quantity of Quirium fuel available for purchase at all stations to be zero, to encourage scooping.
    - Added the "Quirium Fuel Transfer" equipment item, to allow for fuel to be transferred from cargo to the main tank, but with a risk of cargo and/or equipment damage (and even entire ship destruction!).
    - Scooping of Quirium Fuel cargo pods when there is insufficient fuel storage units to hold it will now result in the cargo being auto-ejected.
    - Corrected logic for determining when fuel or fuel stations are available.
    - Added logic to allow for players without fuel scoops to always have the ability to purchase 4ly fuel rations, even if all other logic says no fuel or rations or fuel stations are allowed in this system.
    
    1.1
    - Added options and JS methods to control how and where fuel is sold.
    
    1.0
    - Initial release.
    

    Equipment

    Name Visible Cost [deci-credits] Tech-Level
    Fuel yes 2 1+
    Fuel (1.0ly only) yes 100 1+
    Fuel (2.0ly only) yes 250 1+
    Fuel (3.0ly only) yes 400 1+
    Fuel (4.0ly only) yes 800 1+
    Fuel (5.0ly only) yes 1200 1+
    Fuel (6.0ly only) yes 1600 1+
    Quirium Fuel Processor yes 4500 4+
    Remove Quirium Fuel Processor no 500 1+
    Quirium Fuel Storage Unit yes 500 3+
    Remove Quirium Fuel Storage Unit no 100 1+
    Quirium Fuel Transfer yes 13800 7+
    Remove Quirium Fuel Internal Transfer no 2000 1+
    Fuel yes 10 1+

    Ships

    Name
    Burning quirium fuel
    Refuelling Station

    Models

    This expansion declares no models. This may be related to warnings.

    Scripts

    Path
    Scripts/fuelTweaks_burningFuel.js
    "use strict";
    this.name					= "FuelTweaks_BurningFuel";
    this.author					= "Thargoid";
    this.copyright				= "Creative Commons: attribution, non-commercial, sharealike with clauses - see readme.txt";
    this.description			= "Script for fuel station";
    
    this._timer = null;
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipSpawned = function() {
        var delay = 0.25;
        var chance = parseInt(Math.random() * 8 + 1);
        switch (chance) {
            case 1: 
                delay += 0.25;
                break;
            case 3:
                delay += 0.50;
                break;
            case 5:
                delay += 0.75;
                break;
            case 7:
                delay += 1;
                break;
        }
        this._timer = new Timer(this, this.$sequence, delay, 0);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$sequence = function $sequence() {
        this.ship.dealEnergyDamage(200, 50);
        this.ship.explode();
    }
    Scripts/fuelTweaks_conditions.js
    "use strict";
    this.name					= "FuelTweaks_Conditions";
    this.author					= "phkb";
    this.copyright              = "2017 phkb";
    this.description			= "Condition script for fuel equipment";
    this.licence                = "CC BY-NC-SA 4.0";
    
    //-------------------------------------------------------------------------------------------------------------
    this.allowAwardEquipment = function(equipment, ship, context) {
        if (context === "scripted") return true;
        if (equipment === "EQ_FUEL") {
            if (system.ID === -1) return true;
            var fe = worldScripts.FuelTweaks_FuelEconomy;
            if (fe._fuelNormal === true) return true;
            if (fe.$isFuelAvailable() === true && fe.$fuelRationsInUse() === false && fe.$isRefuelStationAvailable() === false) return true;
            return false;
        }
    
        if (equipment === "EQ_FUEL_STORAGE") {
            var sts = ship.equipmentStatus("EQ_FUEL_PROCESSOR");
            if (sts === "EQUIPMENT_OK" || sts === "EQUIPMENT_DAMAGED") return true;
            return false;
        }
    
        if (equipment === "EQ_PIRATE_FUEL") {
            var fe = worldScripts.FuelTweaks_FuelEconomy;
            if (fe._fuelNormal === true) return false;
            if (fe.$isFuelAvailable() === true && fe.$fuelRationsInUse() === false && fe.$isRefuelStationAvailable() === false) return false;
            if (system.economy < 4) return false;
            if (ship.dockedStation.allegiance === "pirate" || ship.dockedStation.allegiance === "chaotic") return true;
            return false;
        }
    
        var list = ["EQ_FUEL_ALT1","EQ_FUEL_ALT2","EQ_FUEL_ALT3","EQ_FUEL_ALT4","EQ_FUEL_ALT5","EQ_FUEL_ALT6"]    
        if (list.indexOf(equipment) >= 0) {
            if (system.ID === -1) return false;
            var fe = worldScripts.FuelTweaks_FuelEconomy;
            if (fe._fuelNormal === true) return false;
            if (fe.$fuelRationsInUse() === false) return false;
            var info = EquipmentInfo.infoForKey(equipment);
            var max = parseInt(info.scriptInfo["fuel_amount"]);
            if (max > fe.$getMaxFuelRation()) return false;
    
            var req = parseInt(7 - player.ship.fuel);
            if (max > req) return false;
            //if ((max - 1) < req) return false; // this would only allow the highest ration amount to be shown
    
            // check the station allegiance
            var alleg = ship.dockedStation.allegiance;
            if (alleg == null) alleg = "neutral";
            if (fe._fuelAllegiance.length > 0 && fe._fuelAllegiance.indexOf(alleg) === -1) return false;
            // not available if we've already got our ration from this station.
            if (ship.dockedStation && fe._emergencyFuel.indexOf(ship.dockedStation.displayName) >= 0) return false;
            // might add further conditions here.
        }
        return true;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.updateEquipmentPrice = function(equipment, price) {
        var newprice = price;
        var p = player.ship;
        if (equipment === "EQ_PIRATE_FUEL") {
            newprice = ((7 - p.fuel) * 10) * price;
        }
        return newprice;
    }
    Scripts/fuelTweaks_fuelEconomy.js
    "use strict";
    this.name					= "FuelTweaks_FuelEconomy";
    this.author					= "phkb";
    this.copyright              = "2017 phkb";
    this.description			= "Controls where fuel is available";
    this.licence                = "CC BY-NC-SA 4.0";
    
    this._fuelNormal = true;                    // switch to true to enable normal fuel operations galaxywide
    this._fuelUseRations = false;               // default setting to indicate whether fuel rationing is in place (true) or standard fuel purchasing (false)
                                                // even if false, availability of fuel will still be controlled by settings below
    this._fuelAvailability = [];                // an array of dictionaries
                                                // dict:    eco         array of economies. empty array means no economy check
                                                //          gov         array of government types. empty array means no gov checks
                                                //          tl          min tech level. -1 means no tl check
                                                //          rations     boolean to indicate fuel rations are in use. default = this._fuelUseRations
                                                //          max         integer between 0 and 4 being the maximum ration that can be sold
    this._maxFuelRation = 1;                    // default maximum amount of ration that can be sold (between 0 and 6)
    this._fuelAllegiance = ["galcop"];          // allegiance of stations where fuel rations will be available. empty means any station allegiance
                                                // can include galcop,neutral,pirate,chaotic,,military,private,restricted,hunter,thargoid
    this._fuelSystemOverride = [];              // array of dictionaries
                                                // dict:    systemID    id of the system having the override
                                                //          available   boolean indicating whether any fuel is for sale
                                                //          rations     boolean indicating whether rations are in use
                                                //          max         integer between 0 and 4 indicating the maximum ration that can be sold
    this._refuelStationAvailability = [];       // an array of dictionaries
                                                // dict:    eco         array of economies. empty array means no economy check
                                                //          gov         array of government types. empty array means no gov checks
                                                //          tl          min tech level. -1 means no tl check
                                                //          factor      price factor for these systems
    this._refuelStationSystemOverride = [];     // array of dictionaries 
                                                // dict:    systemID    system id of system in question
                                                //          available   boolean indicating whether refuel station is available
                                                //          factor      price factor to apply to fuel here
    this._refuelStationCostFactor = 0.15;       // default price factor applied to fuel sold through refuelling stations
    
    this._emergencyFuel = [];                   // array of stations names where player has purchased a fuel ration
    this._saveSettings = false;                 // set to true to save all settings in save game file (which means values set above will be overridden)
                                                // this would probably only enabled if the OXP reached release stage and was linked into other OXP's
                                                // eg Diplomacy
    
    this._trueValues = ["yes", "1", 1, "true", true];
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function() {
        /*
        // sample settings
        this._fuelNormal = false; // turn off normal fuel operations
        this._fuelUseRations = true; // turn on rationing
        // add some controls over fuel availability
        this.$addFuelAvailability([4,5,6,7], [0], 5);
        this.$addFuelAvailability([4,5,6,7], [1], 3);
        this.$addFuelAvailability([3,4,5,6,7], [2,3,4,5,6,7], 0, false);
        
        // add some controls over where refulling stations are present
        this.$addRefuelStationAvailability([4,5], [0], 8);
        this.$addRefuelStationAvailability([4,5], [1], 6);
        this.$addRefuelStationAvailability([4,5,6], [2], 3);
        this.$addRefuelStationAvailability([3,4,5,6], [2,3,4,5,6,7], 2);
        */
    
        if (missionVariables.FuelTweaks_EmergencyFuel) {
            this._emergencyFuel = JSON.parse(missionVariables.FuelTweaks_EmergencyFuel);
            delete missionVariables.FuelTweaks_EmergencyFuel;
        }
        // only try to load settings if we're actually saving them
        if (this._saveSettings === true) {
            if (missionVariables.FuelTweaks_FuelAvailability) {
                this._fuelAvailability = JSON.parse(missionVariables.FuelTweaks_FuelAvailability);
                delete missionVariables.FuelTweaks_FuelAvailability;
            }
            if (missionVariables.FuelTweaks_Allegiance) {
                this._fuelAllegiance = JSON.parse(missionVariables.FuelTweaks_Allegiance);
                delete missionVariables.FuelTweaks_Allegiance;
            }
            if (missionVariables.FuelTweaks_FuelSystemOverride) {
                this._fuelSystemOverride = JSON.parse(missionVariables.FuelTweaks_FuelSystemOverride);
                delete missionVariables.FuelTweaks_FuelSystemOverride;
            }
            if (missionVariables.FuelTweaks_RefuelStationAvailability) {
                this._refuelStationAvailability = JSON.parse(missionVariables.FuelTweaks_RefuelStationAvailability);
                delete missionVariables.FuelTweaks_RefuelEconomy;
            }
            if (missionVariables.FuelTweaks_RefuelStationSystemOverride) {
                this._refuelStationSystemOverride = JSON.parse(missionVariables.FuelTweaks_RefuelStationSystemOverride);
                delete missionVariables.FuelTweaks_RefuelStationSystemOverride;
            }
            if (missionVariables.FuelTweaks_RefuelStationCostFactor) {
                this._refuelStationCostFactor = parseFloat(missionVariables.FuelTweaks_RefuelStationCostFactor);
            }
            if (missionVariables.FuelTweaks_Normal) {
                this._fuelNormal = (this._trueValues.indexOf(missionVariables.FuelTweaks_Normal) >= 0 ? true : false);
            }
        }
        delete this.startUp;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function() {
        if (worldScripts["oolite-system-data-config"] && worldScripts["CommpressedF7Layout"]) {
            worldScripts["oolite-system-data-config"].addChangeCallback(this.name, "$addInfoToSystemDataScreen");
            delete this.guiScreenWillChange;
            delete this.infoSystemWillChange;
        }
        if (worldScripts.GalCopAdminServices) {
            var ga = worldScripts.GalCopAdminServices;
            ga._purchase_ignore_equip.push("EQ_PIRATE_FUEL");
            ga._purchase_ignore_equip.push("EQ_FUEL_ALT1");
            ga._purchase_ignore_equip.push("EQ_FUEL_ALT2");
            ga._purchase_ignore_equip.push("EQ_FUEL_ALT3");
            ga._purchase_ignore_equip.push("EQ_FUEL_ALT4");
            ga._purchase_ignore_equip.push("EQ_FUEL_ALT5");
            ga._purchase_ignore_equip.push("EQ_FUEL_ALT6");
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function() {
        if (this._emergencyFuel.length > 0) {
            missionVariables.FuelTweaks_EmergencyFuel = JSON.stringify(this._emergencyFuel);
        } else {
            delete missionVariables.FuelTweaks_EmergencyFuel;
        }
        // only save settings if we're allowed
        if (this._saveSettings === true) {
            missionVariables.FuelTweaks_FuelAvailability = JSON.stringify(this._fuelAvailability);
            missionVariables.FuelTweaks_Allegiance = JSON.stringify(this._fuelAllegiance);
            missionVariables.FuelTweaks_FuelSystemOverride = JSON.stringify(this._fuelSystemOverride);
            missionVariables.FuelTweaks_RefuelStationAvailability = JSON.stringify(this._refuelStationAvailability);
            missionVariables.FuelTweaks_RefuelStationSystemOverride = JSON.stringify(this._refuelStationSystemOverride);
            missionVariables.FuelTweaks_RefuelStationCostFactor = this._refuelStationCostFactor;
            missionVariables.FuelTweaks_Normal = this._fuelNormal;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerBoughtEquipment = function(equipmentKey) {
        var list = ["EQ_FUEL_ALT1","EQ_FUEL_ALT2","EQ_FUEL_ALT3","EQ_FUEL_ALT4"]    
    	if (list.indexOf(equipmentKey) >= 0) {
            var info = EquipmentInfo.infoForKey(equipmentKey);
            var amt = parseInt(info.scriptInfo["fuel_amount"]);
    		player.ship.fuel += amt;
            player.ship.removeEquipment(equipmentKey);
            this._emergencyFuel.push(player.ship.dockedStation.displayName); 
        }
        if (equipmentKey === "EQ_PIRATE_FUEL") {
            player.ship.fuel = 7;
            player.ship.removeEquipment(equipmentKey);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillEnterWitchspace = function(cause, destination) {
        this._emergencyFuel = [];
        if (cause === "galactic jump") {
            // reset fuel system parameters
            this._fuelAvailability = [];
            this._fuelSystemOverride = [];
            this._refuelStationAvailability = [];
            this._refuelStationSystemOverride = [];
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipExitedWitchspace = function() {
        if (this._fuelNormal === false && system.ID >= 0) {
            var msg = "";
            var avail = this.$isFuelAvailable(system.ID);
            var stn = (avail === true ? this.$isRefuelStationAvailable(system.ID) : false);
            var rations = (avail === true ? this.$fuelRationsInUse(system.ID) : false);
            if (avail === false) msg = expandDescription("[fuelTweaks_notAvailable]");
            if (avail === true) {
                if (rations === true && stn === false) msg = expandDescription("[fuelTweaks_fuelRationsAvailable]");
            }
            if (msg !== "") {
                var targets = system.shipsWithRole("buoy-witchpoint");
                if (targets.length > 0) {
                    for (var i = 0; i < targets.length; i++) {
                        targets[i].commsMessage(msg, player.ship);
                    }
                }
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.guiScreenWillChange = function(to, from) {
        if (to === "GUI_SCREEN_SYSTEM_DATA") {
    		this.$addInfoToSystemDataScreen();
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.infoSystemWillChange = function(to, from) {
    	if (guiScreen === "GUI_SCREEN_SYSTEM_DATA") {
    		this.$addInfoToSystemDataScreen();
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // adds an availability register to the list
    this.$addFuelAvailability = function(ecoList, govList, tl, useRations, maxRation) {
        if (Array.isArray(ecoList) === false) {
            throw "Invalid settings - ecoList must be an array";
        }
        for (var i = 0; i < ecoList.length; i++) {
            if (ecoList[i] < 0 || ecoList[i] > 7) {
                throw "Invalid settings - ecoList data elements must be between 0 and 7";
            }
        }
        if (Array.isArray(govList) === false) {
            throw "Invalid settigns - govList must be an array";
        }
        for (var i = 0; i < govList.length; i++) {
            if (govList[i] < 0 || govList[i] > 7) {
                throw "Invalid settings - govList data elements must be between 0 and 7";
            }
        }
        if (tl < -1 || tl > 15) {
            throw "Invalid settings - tl must be between -1 and 15";
        }
        // default if not passed
        if (useRations == undefined) useRations = this._fuelUseRations;
        if (maxRation == undefined) {
            maxRation = this._maxFuelRation;
        } else {
            if (isNaN(maxRation) || maxRation < 0 || maxRation > 6) {
                throw "Invalid settings - maxRation must be an integer between 0 and 6";
            }
        }
    
        var test = JSON.stringify({eco:ecoList, gov:govList, tl:tl, rations:useRations, max:maxRation});
        var found = false;
        for (var i = 0; i < this._fuelAvailability.length; i++) {
            if (JSON.stringify(this._fuelAvailability[i]) === test) {found = true; break;}
        }
        if (found === false) this._fuelAvailability.push({eco:ecoList, gov:govList, tl:tl, rations:useRations, max:maxRation});
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // removes a fuel availability register from the list
    this.$removeFuelAvailability = function(ecoList, govList, tl, useRations, maxRation) {
        if (Array.isArray(ecoList) === false) {
            throw "Invalid settings - ecoList must be an array";
        }
        for (var i = 0; i < ecoList.length; i++) {
            if (ecoList[i] < 0 || ecoList[i] > 7) {
                throw "Invalid settings - ecoList data elements must be between 0 and 7";
            }
        }
        if (Array.isArray(govList) === false) {
            throw "Invalid settigns - govList must be an array";
        }
        for (var i = 0; i < govList.length; i++) {
            if (govList[i] < 0 || govList[i] > 7) {
                throw "Invalid settings - govList data elements must be between 0 and 7";
            }
        }
        if (tl < -1 || tl > 15) {
            throw "Invalid settings - tl must be between -1 and 15";
        }
        // default if not passed
        if (useRations == undefined) useRations = this._fuelUseRations;
        if (maxRation == undefined) {
            maxRation = this._maxFuelRation;
        } else {
            if (isNaN(maxRation) || maxRation < 0 || maxRation > 6) {
                throw "Invalid settings - maxRation must be an integer between 0 and 6";
            }
        }
    
        var test = JSON.stringify({eco:ecoList, gov:govList, tl:tl, rations:useRations, max:maxRation});
        for (var i = 0; i < this._fuelAvailability.length; i++) {
            if (JSON.stringify(this._fuelAvailability[i]) === test) {
                this._fuelAvailability.splice(i, 1);
                break;
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$addInfoToSystemDataScreen = function() {
    	var sysID = player.ship.targetSystem;
    	if (player.ship.hasOwnProperty("infoSystem")) sysID = player.ship.infoSystem;
        // build message
        var msg = "";
        var avail = this.$isFuelAvailable(sysID);
        var stn = (avail === true ? this.$isRefuelStationAvailable(sysID) : false);
        var rations = (avail === true ? this.$fuelRationsInUse(sysID) : false);
        if (avail === false) msg = expandDescription("[fuelTweaks_notAvailable]");
        if (avail === true) {
            if (rations === true && stn === false) msg = expandDescription("[fuelTweaks_fuelRationsAvailable]");
            if (stn === true) msg = expandDescription("[fuelTweaks_fuelStationAvailable]");
        }
        // add message to top part of screen, if possible
        var added = false;
        if (worldScripts["oolite-system-data-config"] && worldScripts["CompressedF7Layout"]) {
            var ln = 0;
            var dc = worldScripts["oolite-system-data-config"];
            for (var i = 16; i >= 1; i--) {
                if (ln === 0 && dc.systemDataLineText(i) != "") {
                    ln = i + 1;
                }
                if (dc.systemDataLineOwner(i) === this.name) {
                    ln = i;
                    break;
                }
            }
            if (ln <= 16 && ln > 0) {
                added = true;
                dc.setSystemDataLine(ln, msg, (msg != "" ? this.name : ""));
            }
        } 
        // if none of the above worked, then just add the message to the bottom part of the screen
        if (added === false) mission.addMessageText(msg);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // adds a fuel override to a specific system
    this.$addFuelSystemOverride = function(sysID, avail, useRations, maxRation) {
        // default if not passed
        if (!useRations) useRations = this._fuelUseRations;
        if (!maxRation) {
            maxRation = this._maxFuelRation;
        } else {
            if (isNaN(maxRation) || maxRation < 0 || maxRation > 6) {
                throw "Invalid settings - maxRation must be an integer between 0 and 6";
            }
        }
        
        var found = false;
        for (var i = 0; i < this._fuelSystemOverride.length; i++) {
            if (this._fuelSystemOverride[i].systemID === sysID) {
                this._fuelSystemOverride[i] = {systemID:sysID, available:avail, rations:useRations, max:maxRation};
                found = true;
                break;
            }
        }
        if (found === false) {
            this._fuelSystemOverride.push({systemID:sysID, available:avail, rations:useRations, max:maxRation});
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // removes a system specific fuel override
    this.$removeFuelSystemOverride = function(sysID) {
        if (isNaN(sysID) || sysID < 0 || sysID > 255) {
            throw "Invalid setting - system ID must be an integer between 0 and 255";
        }
        for (var i = 0; i < this._fuelSystemOverride.length; i++) {
            if (this._fuelSystemOverride[i].systemID === sysID) {
                this._fuelSystemOverride.splice(i, 1)
                break;
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // Sets the default maximum amount of fuel that can be purchased through a non-refuelling stations
    // Zero (0) means no ration available.
    this.$setMaxFuelRation = function(maxFuel) {
    	if (isNaN(maxFuel) === true || maxFuel < 0 || maxFuel > 6) {
    		throw "Invalid setting - max fuel ration must be an integer between 0 and 6";
    	}
        this._maxFuelRation = maxFuel;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // Sets an array of allegiance types to control what stations can sell fuel.
    // empty array means all stations.
    this.$setFuelAllegiance = function(alleg) {
    	if (Array.isArray(alleg) === false) {
    		throw "Invalid setting - parameter must be an array of strings";
    	}
        var poss = ["galcop","neutral","pirate","chaotic","military","private","restricted","hunter","thargoid"];
    	for (var i = 0; i < alleg.length; i++) {
    		if (poss.indexOf(alleg[i]) === -1) {
    			throw "Invalid allegiance value - " + alleg[i] + " must be one of these: galcop,neutral,pirate,chaotic,,military,private,restricted,hunter,thargoid";
    		}
    	}
    	this._fuelAllegiance = alleg;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // adds a refuel station availability register to the list
    this.$addRefuelStationAvailability = function(ecoList, govList, tl, factor) {
            if (Array.isArray(ecoList) === false) {
            throw "Invalid settings - ecoList must be an array";
        }
        for (var i = 0; i < ecoList.length; i++) {
            if (ecoList[i] < 0 || ecoList[i] > 7) {
                throw "Invalid settings - ecoList data elements must be between 0 and 7";
            }
        }
        if (Array.isArray(govList) === false) {
            throw "Invalid settigns - govList must be an array";
        }
        for (var i = 0; i < govList.length; i++) {
            if (govList[i] < 0 || govList[i] > 7) {
                throw "Invalid settings - govList data elements must be between 0 and 7";
            }
        }
        if (tl < -1 || tl > 15) {
            throw "Invalid settings - tl must be between -1 and 15";
        }
        if (factor && isNaN(factor) === true) {
            throw "Invalid settings - factor must be a valid number greater than 0";
        }
        var test = JSON.stringify({eco:ecoList, gov:govList, tl:tl});
        var found = false;
        for (var i = 0; i < this._refuelStationAvailability.length; i++) {
            if (JSON.stringify(this._refuelStationAvailability[i]) === test) {found = true; break;}
        }
        if (!factor) factor = this._refuelStationCostFactor;
        if (found === false) this._refuelStationAvailability.push({eco:ecoList, gov:govList, tl:tl, factor:factor});
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // removes a refuel station availability register from the list
    this.$removeRefuelStationAvailability = function(ecoList, govList, tl) {
            if (Array.isArray(ecoList) === false) {
            throw "Invalid settings - ecoList must be an array";
        }
        for (var i = 0; i < ecoList.length; i++) {
            if (ecoList[i] < 0 || ecoList[i] > 7) {
                throw "Invalid settings - ecoList data elements must be between 0 and 7";
            }
        }
        if (Array.isArray(govList) === false) {
            throw "Invalid settigns - govList must be an array";
        }
        for (var i = 0; i < govList.length; i++) {
            if (govList[i] < 0 || govList[i] > 7) {
                throw "Invalid settings - govList data elements must be between 0 and 7";
            }
        }
        if (tl < -1 || tl > 15) {
            throw "Invalid settings - tl must be between -1 and 15";
        }
        var test = JSON.stringify({eco:ecoList, gov:govList, tl:tl});
        for (var i = 0; i < this._refuelStationAvailability.length; i++) {
            if (JSON.stringify(this._refuelStationAvailability[i]) === test) {
                this._refuelStationAvailability.splice(i, 1); 
                break;
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // Adds a system ID to a list of systems that will be forced to have a refuelling station.
    this.$addRefuelStationSystemOverride = function(sysID, avail, costFactor) {
        if (isNaN(sysID) || sysID < 0 || sysID > 255) {
            throw "Invalid setting - system ID must be an integer between 0 and 255";
        }
        if (isNaN(costFactor) || costFactor <= 0) {
            throw "Invalid setting - cost factor must be greater than 0"
        }
        var found = false;
        for (var i = 0; i < this._refuelStationSystemOverride.length; i++) {
            if (this._refuelStationSystemOverride[i].systemID === sysID) {
                found = true;
                this._refuelStationSystemOverride[i] = {systemID:sysID, available:avail, factor:costFactor};
                break;
            }
        }
        if (found === false) {
            this._refuelStationSystemOverride.push({systemID:sysID, available:avail, factor:costFactor});
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // Removes a systemID from the list of systems that will always have a refuelling station.
    this.$removeRefuelStationSystemOverride = function(sysID) {
        if (isNaN(sysID) || sysID < 0 || sysID > 255) {
            throw "Invalid setting - system ID must be an integer between 0 and 255";
        }
        for (var i = 0; i < this._refuelStationSystemOverride.length; i++) {
            if (this._refuelStationSystemOverride[i].systemID === sysID) {
                this._refuelStationSystemOverride.splice(i, 1);
                break;
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // sets the default refuelling station cost factor 
    this.$setRefuelStationCostFactor = function(cf) {
        if (isNaN(cf) || cf <= 0) {
            throw "Invalid setting - cost factor must be greater than 0";
        }
        this._refuelStationCostFactor = cf;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns true if fuel rations will be available in a particular system. otherwise false.
    this.$isFuelAvailable = function(sysID) {
        if (this._fuelNormal === true) return true;
    	if (!sysID) sysID = system.ID;
    	var sys = System.infoForSystem(galaxyNumber, sysID);
        // check if we have an override
        var ovr = this.$checkFuelSystemOverride(sysID);
        if (ovr) return ovr.available;
        return this.$checkFuelAvailability(sys.economy, sys.government, sys.techlevel);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns true if fuel rationing is in use in a system, otherwise false
    this.$fuelRationsInUse = function(sysID) {
        if (this._fuelNormal === true) return false;
    	if (!sysID) sysID = system.ID;
    	var sys = System.infoForSystem(galaxyNumber, sysID);
        // look for an override first
        var ovr = this.$checkFuelSystemOverride(sysID);
        if (ovr) return ovr.rations;
        // check if a refuel station is available here
        if (this.$isRefuelStationAvailable(sysID) === true) return false;
        var inuse = this.$checkFuelRationsInUse(sys.economy, sys.government, sys.techlevel);
        // make sure players who can't scoop fuel can still get a fuel ration
        if (player.ship.hasEquipmentProviding("EQ_FUEL_SCOOPS") === false) {
            if (inuse === false && this.$isFuelAvailable(sysID) === false && this.$isRefuelStationAvailable(sysID) === false) {
                inuse = true;
            }
        }
        return inuse;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks all fuel availability settings to see if we hit a true condition
    this.$checkFuelAvailability = function(ecoID, govID, tl) {
        for (var i = 0; i < this._fuelAvailability.length; i++) {
            var checkCount = 0;
            var itm = this._fuelAvailability[i];
            if (itm.eco.length === 0 || itm.eco.indexOf(ecoID) >= 0) checkCount += 1;
            if (itm.gov.length === 0 || itm.gov.indexOf(govID) >= 0) checkCount += 1;
            if (itm.tl === -1 || tl >= itm.tl) checkCount += 1;
     
            if (checkCount === 3) {
                return true;
            }
        }
        return false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks all fuel availability settings to see whether fuel rations are in use
    this.$checkFuelRationsInUse = function(ecoID, govID, tl) {
        var inuse = this._fuelUseRations;
        var itm = this.$getAvailabilityItem(ecoID, govID, tl);
        if (itm != null) inuse = itm.rations;
        return inuse;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns the maximum possible fuel ration available for this system
    this.$getMaxFuelRation = function(sysID) {
        var max = this._maxFuelRation;
    	if (!sysID) sysID = system.ID;
    	var sys = System.infoForSystem(galaxyNumber, sysID);
        // look for an override
        var ovr = this.$checkFuelSystemOverride(sysID);
        if (ovr) return ovr.max;
        // look for a general item
        var itm = this.$getAvailabilityItem(sys.economy, sys.government, sys.techlevel);
        if (itm != null) max = itm.max;
        // make sure players who can't scoop fuel can still get a decent fuel ration
        if (player.ship.hasEquipmentProviding("EQ_FUEL_SCOOPS") === false) {
            if (this.$isFuelAvailable(sysID) === false && this.$isRefuelStationAvailable(sysID) === false) {
                max = 4;
            }
        }
        return max;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks the availability register for a match on eco, gov and tl
    this.$getAvailabilityItem = function(ecoID, govID, tl) {
        var item = null;
        for (var i = 0; i < this._fuelAvailability.length; i++) {
            var itm = this._fuelAvailability[i];
            if (((itm.eco.length > 0 && itm.eco.indexOf(ecoID) >= 0) || itm.eco.length === 0) &&
                ((itm.gov.length > 0 && itm.gov.indexOf(govID) >= 0) || itm.gov.length === 0) &&
                (itm.tl === -1 || tl >= itm.tl)) {item = itm; break;}
        }
        return item;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks for a fuel ration system override, returns item or null
    this.$checkFuelSystemOverride = function(sysID) {
        if (this._fuelSystemOverride.length > 0) {
            for (var i = 0; i < this._fuelSystemOverride.length; i++) {
                if (this._fuelSystemOverride[i].systemID === sysID) return this._fuelSystemOverride[i];
            }
        }
        return null;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns true if fuel rations will be available from stations in a particular system. otherwise false
    this.$isRefuelStationAvailable = function(sysID) {
        // if the fuel is set to normal operations, don't spawn any refuelling stations - but maybe some discussion is worthwhile here.
        if (this._fuelNormal === true) return false;
    	if (!sysID) sysID = system.ID;
    	var sys = System.infoForSystem(galaxyNumber, sysID);
        // is fuel allowed to be sold in this system? run relevant fuel availability checks first
        var fuelAvail = true;
        var ovr = this.$checkFuelSystemOverride(sysID);
        // check if we have a "deny" override
        if (ovr) {
            fuelAvail = ovr.available;
        } else {
            // otherwise check for general availability
            fuelAvail = this.$checkFuelAvailability(sys.economy, sys.government, sys.techlevel);
        }
        // check the economy of the current system
        var avail = true;
        // if fuel is available we can now check for refuel stations
        if (fuelAvail === true) {
            // check if we have an override for this system
            ovr = this.$checkRefuelStationSystemOverride(sysID);
            if (ovr) return ovr.available;
            avail = this.$checkRefuelStationAvailability(sys.economy, sys.government, sys.techlevel);
        } else {
            // if no fuel is available, no refuelling stations are available either
            avail = false;
        }
        return avail;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks all reful station availability settings to see if we hit a true condition
    this.$checkRefuelStationAvailability = function(ecoID, govID, tl) {
        for (var i = 0; i < this._refuelStationAvailability.length; i++) {
            var checkCount = 0;
            var itm = this._refuelStationAvailability[i];
            if (itm.eco.length === 0 || itm.eco.indexOf(ecoID) >= 0) checkCount += 1;
            if (itm.gov.length === 0 || itm.gov.indexOf(govID) >= 0) checkCount += 1;
            if (itm.tl === -1 || tl >= itm.tl) checkCount += 1;
    
            // if we completely matched on this item, we're good to go
            if (checkCount === 3) {
                return true;
            }
        }
        return false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks the fuel station availability register for a match on eco, gov and tl
    this.$getRefuelStationAvailabilityItem = function(ecoID, govID, tl) {
        var item = null;
        for (var i = 0; i < this._refuelStationAvailability.length; i++) {
            var itm = this._refuelStationAvailability[i];
            if (((itm.eco.length > 0 && itm.eco.indexOf(ecoID) >= 0) || itm.eco.length === 0) &&
                ((itm.gov.length > 0 && itm.gov.indexOf(govID) >= 0) || itm.gov.length === 0) &&
                ((itm.tl >= 0 && tl >= itm.tl) || itm.tl === -1)) {item = itm; break;}
        }
        return item;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks for a fuel ration system override, returns item or null
    this.$checkRefuelStationSystemOverride = function(sysID) {
        if (this._refuelStationSystemOverride.length > 0) {
            for (var i = 0; i < this._refuelStationSystemOverride.length; i++) {
                if (this._refuelStationSystemOverride[i].systemID === sysID) return this._refuelStationSystemOverride[i];
            }
        }
        return null;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns the refuel station cost factor for this system
    this.$getRefuelStationCostFactor = function(sysID) {
    	if (!sysID) sysID = system.ID;
    	var sys = System.infoForSystem(galaxyNumber, sysID);
        // check for an override
        var ovr = this.$checkRefuelStationSystemOverride(sysID);
        if (ovr) return ovr.factor;
        // start with the default
        var result = this._refuelStationCostFactor;
        // see if there's something in the register
        var item = this.$getRefuelStationAvailabilityItem(sys.economy, sys.government, sys.techlevel);
        if (item != null) {
            result = parseFloat(item.factor);
        }
        return result;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // resets all fuel-related data
    this.$reset = function() {
        this._fuelNormal = true;
        this._fuelAvailability = [];
        this._maxFuelRation = 1;
        this._fuelAllegiance = "galcop";
        this._fuelSystemOverride = [];
        this._refuelStationAvailability = [];
        this._refuelStationSystemOverride = [];
        this._refuelStationCostFactor = 0.15
        this._emergencyFuel = [];
        delete missionVariables.FuelTweaks_FuelAvailability;
        delete missionVariables.FuelTweaks_Allegiance;
        delete missionVariables.FuelTweaks_FuelSystemOverride;;
        delete missionVariables.FuelTweaks_RefuelStationAvailability;
        delete missionVariables.FuelTweaks_RefuelStationSystemOverride;
        delete missionVariables.FuelTweaks_RefuelStationCostFactor;
        delete missionVariables.FuelTweaks_Normal;
    }
    Scripts/fuelTweaks_quirium.js
    "use strict";
    this.name                   = "FuelTweaks_Quirium";
    this.author                 = "phkb";
    this.copyright              = "2017 phkb";
    this.description            = "Routines for controlling the collection, sale and transport of scooped Quirium fuel";
    this.licence                = "CC BY-NC-SA 4.0";
    
    /*
        TODO:
            firing on, or using ecm near, to a cargo pod with Quirium inside will result in a cascade explosion
    */
    
    this._scoopDistanceTimer = null;
    this._damagedStorage = 0;
    this._preProcessAmount = 0;
    this._scoopProcess = 0;
    this._fuelScoopStorage = false;
    this._chs = false;
    this._mo_timer = null;
    this._purchase = {};
    this._minAmount = 0.1;
    this._shipConfig = false;
    this._scEquip = [];
    this._itemColor = "yellowColor";								
    this._menuColor = "orangeColor";
    this._exitColor = "yellowColor";
    this._disabledColor = "darkGrayColor";
    this._startCount = 0;
    this._secondTimer = null;
    this._transferTimer = null;
    this._destructTimer = null;
    this._damageChance = 0.05; // 0.1;
    this._destructCounter = 0;
    this._destructPhase = 0;
    this._oneTAmount = 7;                       /// amount of scooped fuel that will be considered "1t"
    //this._dumpQuirium = null;
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function() {
        if (missionVariables.FuelTweaks_PreProcessAmount) this._preProcessAmount = missionVariables.FuelTweaks_PreProcessAmount;
        if (missionVariables.FuelTweaks_ScoopProcess) this._scoopProcess = missionVariables.FuelTweaks_ScoopProcess;
        if (worldScripts["Coronal Harvester Script"]) this._chs = true;
        if (worldScripts.ShipConfiguration_Core) {
            this._shipConfig = true;
        }
        if (worldScripts["Fuel Collector"]) {
            worldScripts["Fuel Collector"].$CruiseCheck = this.$fuelCollector_CruiseCheck;
            worldScripts["Fuel Collector"].$checkifover01 = this.$fuelCollector_checkifover01;
        }
        this.$initInterface(player.ship.dockedStation);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLaunchedFromStation = function(station) {
        if (player.ship.equipmentStatus("EQ_FUEL_PROCESSOR") === "EQUIPMENT_OK") {
            this._scoopDistanceTimer = new Timer(this, this.$monitorPlayer, 5, 5);
        }
        if (this._shipConfig === true) {
            var sc = worldScripts.ShipConfiguration_Core;
            var eq = EquipmentInfo.infoForKey(sc.$equipmentItemInUse("fuelscoops", player.ship));
            if (eq) this._minAmount = parseFloat(eq.scriptInfo.accumulator_size) + 0.1;
            // grab a copy of sc equipment that will report itself as damaged, so we don't double up during a self-destruct
            this._scEquip = [].concat(sc._engines).concat(sc._boosters).concat(sc._hyperdrive).concat(sc._thrusters)
                .concat(sc._energy).concat(sc._frontshields).concat(sc._aftshields).concat(sc._fuelinjectors)
                .concat(sc._fuelscoops).concat(sc._heatshields);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function() {
        missionVariables.FuelTweaks_PreProcessAmount = this._preProcessAmount;
        missionVariables.FuelTweaks_ScoopProcess = this._scoopProcess;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDied = function(whom, why) {
        if (this._scoopDistanceTimer && this._scoopDistanceTimer.isRunning) this._scoopDistanceTimer.stop();
        this._scoopDistanceTimer = null;
        this.$stopTimers();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDockedWithStation = function(station) {
        if (this._scoopDistanceTimer && this._scoopDistanceTimer.isRunning) this._scoopDistanceTimer.stop();
        this._scoopDistanceTimer = null;
        this.$initInterface(station);
        this.$stopTimers();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.equipmentDamaged = function(equipmentKey) {
        // if a full storage container gets damaged, remove a fuel commodity from the player
        if (equipmentKey === "EQ_FUEL_PROCESSOR" || equipmentKey === "EQ_FUEL_STORAGE") {
            var curr = player.ship.manifest["quirium_fuel"];
            var cntr = this.$countOKContainers();
            if (curr > cntr) {
                player.ship.manifest["quirium_fuel"] -= (curr - cntr);
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerBoughtEquipment = function(equipmentKey) {
        var p = player.ship;
        var refundEq = "";
        if (equipmentKey === "EQ_FUEL_STORAGE_REMOVAL") {
            p.removeEquipment("EQ_FUEL_STORAGE_REMOVAL");
            refundEq = "EQ_FUEL_STORAGE";
        }
        if (equipmentKey === "EQ_FUEL_PROCESSOR_REMOVAL") {
            p.removeEquipment("EQ_FUEL_PROCESSOR_REMOVAL");
            refundEq = "EQ_FUEL_PROCESSOR";
            mission.setInstructions("", this.name);
        }
        if (equipmentKey === "EQ_FUEL_TRANSFER_REMOVAL") {
            p.removeEquipment("EQ_FUEL_TRANSFER_REMOVAL");
            refundEq = "EQ_FUEL_TRANSFER";
        }
        if (equipmentKey === "EQ_FUEL_STORAGE") {
            if (p.equipmentStatus("EQ_FUEL_STORAGE", true)["EQUIPMENT_DAMAGED"] > 0) {
                p.setEquipmentStatus("EQ_FUEL_STORAGE", "EQUIPMENT_OK");
                p.removeEquipment("EQ_FUEL_STORAGE");
            }
        }
        if (equipmentKey === "EQ_FUEL_PROCESSOR") {
            this._preProcessAmount = 0;
            this.$updateManifest();
        }
        if (refundEq !== "") {
        	var stn = p.dockedStation;
    		var eqSts = p.equipmentStatus(refundEq);
            p.removeEquipment(refundEq);
    		// refund the cost of the equipment
            if (eqSts === "EQUIPMENT_OK") player.credits += (eq.price / 10) * stn.equipmentPriceFactor;
            if (eqSts === "EQUIPMENT_DAMAGED") player.credits += ((eq.price/ 10) * stn.equipmentPriceFactor) / 2;
        }
        if (equipmentKey === "EQ_FUEL_TRANSFER" || equipmentKey === "EQ_FUEL_TRANSFER_REMOVAL") {
            this.$initInterface(player.ship.dockedStation);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerBoughtCargo = function(commodity, units, price) {
        if (commodity === "quirium_fuel") {
            var spare = this.$countOKContainers() - player.ship.manifest["quirium_fuel"];
            if (spare < 0) {
                player.consoleMessage("Unable to purchase Quirium fuel - insufficient fuel storage.", 5);
                player.ship.manifest["quirium_fuel"] -= Math.abs(spare);
                player.ship.dockedStation.setMarketQuantity(commodity, player.ship.dockedStation.market[commodity].quantity + Math.abs(spare));
                player.credits += (Math.abs(spare) * (price / 10));
                if (worldScripts.market_observer3) {
                    this._mo_timer = new Timer(this, this.$reverseMOPurchase, 0.5, 0);
                    this._purchase = {commodity:commodity, units:units, price:price};
                }
                return;
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLaunchedEscapePod = function(escapepod) {
        this.$stopTimers();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipScoopedFuel = function() {
        if (this._fuelScoopStorage === true) {
            // send this fuel to storage
            this._preProcessAmount += this._minAmount;
            this.$updateManifest();
            // display some status info ... somewhere ...
            var checkCalc = parseInt(Math.abs(parseFloat(this._preProcessAmount) - parseFloat(this._oneTAmount) * ((this._scoopProcess + 1) * 0.25)) * 100);
            var p = player.ship;
            if (this._scoopProcess === 2 && checkCalc <= 5) {
                player.consoleMessage("75% complete\n", 5);
                this._scoopProcess += 1;
            }
            if (this._scoopProcess === 1 && checkCalc <= 5) {
                player.consoleMessage("50% complete\n", 5);
                this._scoopProcess += 1;
            }
            if (this._scoopProcess === 0 && checkCalc <= 5) {
                player.consoleMessage("25% complete\n", 5);
                this._scoopProcess += 1;
            }
            if (this._preProcessAmount >= this._oneTAmount) {
                p.manifest["quirium_fuel"] += 1;
                this._preProcessAmount = 0;
                this._scoopProcess = 0;
                this.$updateManifest();
                player.consoleMessage("Processed 1t Quirium fuel\n", 5);
                // add an extra blank line otherwise the "Fuel scoop active" message will overwrite it
                var curr = p.manifest["quirium_fuel"];
                var cntr = this.$countOKContainers();
                if (curr === cntr) {
                    this._fuelScoopStorage = false;
                    player.consoleMessage("All fuel storage units are full - processing halted.\n", 5);
                    return;
                }
                if (p.cargoSpaceAvailable === 0) {
                    this._fuelScoopStorage = false;
                    player.consoleMessage("Cargo capacity reached - processing halted.\n", 5);
                    return;
                }
            }
            // subtract the amount from the player's fuel so 
            p.fuel -= this._minAmount;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipScoopedOther = function(whom) {
        if (whom.isCargo && whom.commodity === "quirium_fuel") {
            // we automatically gain an qfsu whenever we scoop quirium fuel
            var p = player.ship;
            p.awardEquipment("EQ_FUEL_STORAGE");
            /*var curr = p.manifest["quirium_fuel"];
            var cntr = this.$countOKContainers();
            if (curr > cntr) {
                // if we don't have any quirium on board, but we do have a processor, we don't need to add a separate fuel storage unit
                if (curr === 0 && player.ship.equipmentStatus("EQ_FUEL_PROCESSOR") === "EQUIPMENT_OK") return;
                var diff = curr - cntr;
                //this._dumpQuirium = new Timer(this, this.$dumpQuirium, 1, 0);
                // player picks up fuel storage unit with the fuel if they don't have enough of them 
                for (var i = 0; i < diff; i++) {
                    p.awardEquipment("EQ_FUEL_STORAGE");
                }
            }*/
        }    
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDumpedCargo = function(cargo) {
        if (cargo.commodity === "quirium_fuel") {
            // if we just dumped quirium, we dumped the storage unit with it.
            var result = player.ship.removeEquipment("EQ_FUEL_STORAGE");
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // not used any more, but kept just in case
    /*this.$dumpQuirium = function $dumpQuirium() {
        player.consoleMessage("Unable to store Quirium Fuel safely - auto-ejecting cargo!", 5);
        // hopefully this will dump the just-scooped entity
        player.ship.dumpCargo(1, "quirium_fuel");
    }*/
    
    //-------------------------------------------------------------------------------------------------------------
    // start the process (after second press)
    this.activated = function() {
        if (player.ship.fuel === 7) {
            player.consoleMessage("Fuel tanks are full. Unable to start fuel transfer.");
            return;
        }
        if (player.ship.manifest["quirium_fuel"] === 0) {
            player.consoleMessage("No Quirium fuel in storage. Unable to start fuel transfer.");
            return;
        }
        var ft = worldScripts.FuelTweaks_Quirium;
        // stop the process, if it's running
        if (ft._transferTimer && ft._transferTimer.isRunning) {ft.mode(); return;}
        // ask the player again before starting
        if (this._startCount === 0) {
            this._startCount = 1;
            ft._secondTimer = new Timer(ft, ft.$cancelStart, 20, 0);
            player.consoleMessage("Activate again to begin fuel transfer.");
            return;
        }
        // ok we're really starting now
        if (this._startCount === 1) {
            this._startCount = 0;
            if (ft._secondTimer.isRunning) ft._secondTimer.stop();
            ft._transferTimer = new Timer(ft, ft.$doFuelTransfer, 2, 2);
            player.consoleMessage("Fuel transfer started.", 2);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // stop process
    this.mode = function() {
        var ft = worldScripts.FuelTweaks_Quirium;
        if (ft._transferTimer && ft._transferTimer.isRunning) {
            player.ship.manifest["quirium_fuel"] -= 1;
            ft._damageChance = 0.05;
            ft._transferTimer.stop();
            player.consoleMessage("Fuel transfer stopped. 1t Quirium fuel consumed.");
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$cancelStart = function $cancelStart() {
        this._startCount = 0;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$doFuelTransfer = function $doFuelTransfer() {
        var p = player.ship;
        if (p.equipmentStatus("EQ_FUEL_TRANSFER") === "EQUIPMENT_DAMAGED") {
            this.mode();
            return;
        }
        p.fuel += 0.1;
        if (p.fuel >= 7) {
            p.fuel = 7;
            player.consoleMessage("Fuel tanks full. Transfer completed.");
            this.mode();
            return;
        }
        player.consoleMessage("Fuel transfer in progress", 1.5);
        // will there be damage?
        if (Math.random() < this._damageChance) {
            // yes there is
            // but what type?
            var type = Math.random();
            if (type >= 0 && type < 0.76) {
                // cargo - grab a copy of the array
                var c = p.manifest.list.splice(0);
                // sort it randomly
                c.sort(function(a, b) { return Math.random() - 0.5; });
                var amt = 0;
                var cmdty = "";
                var unit = "t";
                for (var i = 0; i < c.length; i++) {
                    if (c[i].quantity > 0 && c[i].unit === "t") {
                        amt = 1;
                        cmdty = c[i].commodity;
                        p.manifest[c[i].commodity] -= 1;
                        break;
                    }
                    if (c[i].quantity > 0 && c[i].unit !== "t") {
                        amt = Math.floor(Math.random() * c[i].quantity) + 1;
                        cmdty = c[i].commodity;
                        unit = c[i].unit;
                        p.manifest[c[i].commodity] -= amt;
                        break;
                    }
                }
                if (cmdty != "") {
                    player.consoleMessage("Warning! " + amt + unit + " of " + displayNameForCommodity(cmdty) + " destroyed!");
                    var mySound = new SoundSource;
                    mySound.sound = "[player-scrape-damage]";
                    mySound.loop = false;
                    mySound.play();
                    // check to see if we've destroyed all the stored quirium fuel 
                    if (cmdty === "quirium_fuel" && p.manifest[cmdty] === 0) {
                        this._damageChance = 0.05;
                        this._transferTimer.stop();
                        player.consoleMessage("Fuel transfer stopped. Insufficient Quirium fuel available.");
                    }
                } else {
                    // theoretically this can never happen - if there's no cargo to destroy, then there's
                    // no quirium fuel left, so the process should have been stopped in the clause above
                    type = 0.6; // switch to equipment damage if no cargo available
                }
            }
            if (type >= 0.76 && type < 0.995) {
                // equipment
    			this.$performEquipmentDamage();
            }
            if (type >= 0.995) {
                this._transferTimer.stop();
                p.script._findMe = true;
                // oh dear - the ship!
                player.consoleMessage("ALERT! Catastrophic internal fuel leak!");
                // start the self-destruct sequence
                this._destructPhase = 0;
                this._destructTimer = new Timer(this, this.$destructSequence, 2, 2);
                // slowly damage every equipment item
                // turn off hud and replace with custom one that only has console at top left corner
                // show a brief series of error messages then either (a) eject the player or (b) destroy their ship.
            }
        }
        this._damageChance += 0.01;
    }
    
    this.$testDestruct = function () {
        // oh dear - the ship!
        player.consoleMessage("ALERT! Catastrophic internal fuel leak!");
        // start the self-destruct sequence
        this._destructPhase = 0;
        this._destructTimer = new Timer(this, this.$destructSequence, 2, 2);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$destructSequence = function $destructSequence() {
        this.$performEquipmentDamage();
        this._destructCounter += 1;
        if (this._destructCounter > 8) {
            // switch off hud
            this._storeHUD = player.ship.hud;
            player.ship.hud = "destruct_hud.plist";
            // unbreak the breakable IFF scanner (if present and damaged) so the final sequence display is shown clearly
            if (player.ship.equipmentStatus("EQ_BREAKABLE_HUD_IFF_SCANNER") === "EQUIPMENT_DAMAGED") player.ship.setEquipmentStatus("EQ_BREAKABLE_HUD_IFF_SCANNER", "EQUIPMENT_OK");
            this._destructPhase = 1;
            this._destructTimer.stop();
            this._destructCounter = 0;
            this._destructTimer = new Timer(this, $destructFinalSequence, 1, 1);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // we're doing this manually, rather than using takeInternalDamage, so we can (a) exclude some items, and (b) only damage equipment
    this.$performEquipmentDamage = function() {
        // list of equipment items we don't want to damage (either because they're critical to gameplay, or it just doesn't make sense)
        var noDamage = ["EQ_HULL_REPAIR"];
        var p = player.ship;
    
        // grab a copy of the equipment list
        var eq = p.equipment.slice(0);
        // randomly sort the list
        eq.sort(function(a, b) { return Math.random() - 0.5; });
        for (var i = 0; i < eq.length; i++) {
            var eqItem = eq[i];
            // find an item to damage (but not the escape pod)
            if (noDamage.indexOf(eqItem.equipmentKey) === -1 && eqItem.provides.indexOf("EQ_ESCAPE_POD") === -1 && p.equipmentStatus(eqItem.equipmentKey) == "EQUIPMENT_OK" && eqItem.damageProbability != 0 && eqItem.isVisible == true && Math.random() <= eqItem.damageProbability) {
                p.setEquipmentStatus(eqItem.equipmentKey, "EQUIPMENT_DAMAGED");
                if (this._scEquip.indexOf(eqItem.equipmentKey) === -1) {
                    player.consoleMessage("Warning! Fuel leak! " + eqItem.name + " damaged!");
                }
                var mySound = new SoundSource;
                mySound.sound = "[player-scrape-damage]";
                mySound.loop = false;
                mySound.play();
                break;
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$destructFinalSequence = function $destructFinalSequence() {
        var msg = [
            "",
            "Life support system failure!",
            "Environmental control failure!",
            "Hull breach!",
            "Structure integrity failing!",
            "Oxygen venting detected!",
            "Complete atmosphere loss in 1 sec"
        ];
        this._destructCounter += 1;
        if (this._destructCounter < msg.length) {
            player.consoleMessage(msg[this._destructCounter]);
            return;
        }
        if (this._destructCounter >= msg.length) {
            if (this._destructPhase === 1) this._destructPhase = 2;
            if (this._destructPhase === 2 && player.ship.hasEquipmentProviding("EQ_ESCAPE_POD") === "EQUIPMENT_OK") {
                player.consoleMessage("Auto-eject sequence initiated");
                player.ship.throwSpark();
                this._destructPhase = 3;
                player.ship.abandonShip();
                return;
            }
            this._destructTimer.stop();
            this._explodeTimer = new Timer(this, this.$explodeShip, 0.25, 0);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$explodeShip = function $explodeShip() {
        this.$stopTimers();
        player.ship.explode();
        player.ship.hud = this._storeHUD;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$stopTimers = function() {
        if (this._secondTimer && this._secondTimer.isRunning) this._secondTimer.stop();
        if (this._transferTimer && this._transferTimer.isRunning) this.mode();
        if (this._scoopDistanceTimer && this._scoopDistanceTimer.isRunning) this._scoopDistanceTimer.stop();
        if (this._destructTimer && this._destructTimer.isRunning) this._destructTimer.stop();
        //if (this._dumpQuirium && this._dumpQuirium.isRunning) this._dumpQuirium.stop();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // initialise the F4 screen entries
    this.$initInterface = function(station) {
        if (player.ship.equipmentStatus("EQ_FUEL_TRANSFER") === "EQUIPMENT_OK") {
            station.setInterface(this.name,{
                title:"Quirium fuel transfer",
                category:"Ship Systems",
                summary:"Allows scooped Quirium fuel in fuel containers to be transferred safely to your ship's fuel tank.",
                callback:this.$showScreen.bind(this)
            });
        } else {
            station.setInterface(this.name, null);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$showScreen = function() {
        var text = "";
        if (player.ship.manifest["quirium_fuel"] === 0 || player.ship.fuel === 7) {
            text = "No Quirium fuel in your hold. No transfer available.";
            if (player.ship.fuel === 7) text = "Fuel tanks are full. No transfer required.";
    		mission.runScreen({
    			screenID:"oolite-quirium-fuel-map",
    			title: "Quirium Fuel Transfer",
    			overlay: {name:"fuelTweaks_pump.png", height:546},
    			message: text,
    			exitScreen: "GUI_SCREEN_INTERFACES"
    		});
        } else {
            text = "Confirm you wish to transfer " + (7 - player.ship.fuel) + "ly of fuel from your cargo hold to your ship's fuel tank."
                + "\n\nNote: 1t of Quirium will be consumed in this transfer.";
            var curChoices = {};
    		curChoices["01_YES"] = {text:"Process with transfer", color:this._menuColor};
    		curChoices["02_NO"] = {text:"Return", color:this._menuColor};
    
    		var opts = {
    			screenID: "oolite-quirium-transfer-map",
    			title: "Confirm Quirium Fuel Transfer",
    			overlay: {name:"fuelTweaks_pump.png", height:546},
    			allowInterrupt: true,
    			exitScreen: "GUI_SCREEN_INTERFACES",
    			choices: curChoices,
    			initialChoicesKey: "02_NO",
    			message: text
    		};
        	mission.runScreen(opts, this.$screenHandler, this);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$screenHandler = function(choice) {
        if (!choice) return;
        if (choice === "01_YES") {
            var amt = 7 - player.ship.fuel;
            player.ship.fuel = 7;
            player.ship.manifest["quirium_fuel"] -= 1;
            player.consoleMessage(amt + "ly fuel transferred to main tank.\n1t Quirium Fuel used.");
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$reverseMOPurchase = function() {
        var mo = worldScripts.market_observer3;
        mo.playerSoldCargo(this._purchase.commodity, this._purchase.units, this._purchase.price);
        this._purchase = {};
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$monitorPlayer = function $monitorPlayer() {
        var p = player.ship;
        if (this.$playerWithinFuelScoopRange() === true) {
            // if it's already on, don't start it again
            if (this._fuelScoopStorage === true) return;
            // stay out of the way of the coronal harvester
            if (this._chs) {
                var chs = worldScripts["Coronal Harvester Script"];
                if (chs._vicinitySunTimer && chs._vicinitySunTimer.isRunning) return;
            }
            // do we have a processor?
            if (p.equipmentStatus("EQ_FUEL_PROCESSOR") === "EQUIPMENT_OK") {
                // how much space do we have?
                var curr = p.manifest["quirium_fuel"];
                var cntr = this.$countOKContainers();
                // if we have spare containers, and our fuel tanks are full, we can turn on the storage process
                if (curr < cntr && p.fuel >= 7 && p.cargoSpaceAvailable > 0) {
                    // we have free space
                    // enable some scooping action
                    this._fuelScoopStorage = true;
                    p.fuel -= this._minAmount;
                }
            }
        } else {
            // if the fuel process was active, and we're about to turn it off, make sure we give the player their fuel back.
            if (this._fuelScoopStorage === true) player.ship.fuel = 7;
            this._fuelScoopStorage = false;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$playerWithinFuelScoopRange = function() {
        if (!system.sun) return false;
        if (((system.sun.collisionRadius * system.sun.collisionRadius) / system.sun.position.squaredDistanceTo(player.ship.position)) > 0.75) return true;
        return false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns the number of fuel containers
    this.$countFuelContainers = function() {
    	var fc = 0;
    	var eq = player.ship.equipment;
    	for (var i = 0; i < eq.length; i++) {
    		if (eq[i].equipmentKey === "EQ_FUEL_STORAGE") fc += 1;
    	}
    	return fc;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$countOKContainers = function() {
        if (player.ship && player.ship.equipmentStatus("EQ_FUEL_STORAGE", true) != undefined) {
            return player.ship.equipmentStatus("EQ_FUEL_STORAGE", true)["EQUIPMENT_OK"] + (player.ship.equipmentStatus("EQ_FUEL_PROCESSOR") === "EQUIPMENT_OK" ? 1 : 0);
        } else {
            return 0;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // fuel collector function overrides to enable fuel collection interface
    this.$fuelCollector_checkifover01 = function(fuel_award) {
        this.fuel_below01 += fuel_award;
        var ftq = worldScripts.FuelTweaks_Quirium;
        if (this.fuel_below01 > 1000) {
            // only do something if we're /not/ in fuel scoop range of the sun
            // when we're in scoop range of the sun, the fuel scoop itself will take over
            if (ftq.$playerWithinFuelScoopRange() === false) {
                // if we have full fuel, pass the quirium over to the quirium fuel accumulator
                if (player.ship.fuel === 7) {
                    var curr = player.ship.manifest["quirium_fuel"];
                    var cntr = ftq.$countOKContainers();
                    // are we in fuel scooping range?
                    if (ftq._fuelScoopStorage === false && curr < cntr) {
                        ftq._fuelScoopStorage = true;
                        player.consoleMessage("Fuel Collector >> Quirium Fuel Storage", 10);
                        player.consoleMessage("Gathered fuel: 0.1 ly", 10);
                        ftq.shipScoopedFuel();
                        player.ship.fuel = 7;
                        ftq._fuelScoopStorage = false;
                    }
                } else if (player.ship.fuel < 7) {
                    // otherwise, it's just the normal fuel collector process here.
                    player.ship.fuel += 0.1;
                    player.consoleMessage("Fuel Collector", 10);
                    player.consoleMessage("Gathered fuel: 0.1 ly", 10);
                }
            }
            this.fuel_below01 -= 1000;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$fuelCollector_CruiseCheck = function() {
    	if (player.ship.docked) {
    		this.CruiseCheckTimer.stop()
    		return // return because we really dont need more checking from here
    			//return also saves a few cycles, instead of having the CPU do 3 extra Compares it just jumps to an address in memory
    	}
    	
    	//if(this.tonearplanet) //if it is zero, then return
    	//return
    	
    	// we never got here if the fuel collector was not started in the first place which is why
            // we can use explicit OR	
    	if (player.ship.equipmentStatus("EQ_FRAME_FUEL_COLLECTOR") != "EQUIPMENT_OK" || player.ship.equipmentStatus("EQ_FUEL_SCOOPS") != "EQUIPMENT_OK") { //is EQ damaged ?
    		this.CruiseCheckTimer.stop() // should we stop or keep it running, in order for it to be repaired..
    		//i'd say performance is of the essense here, therefore we kill it until next witchspace / station launch
    		return // return because we really dont need more checking from here
    	}
        	
    	//player.ship.consoleMessage("entering cruisecheck", 3) // for testing
    	
    		
    	//if(system.isInterstellarSpace) //some person in the future might add a sun in interstellar space
    	if(!system.sun) {
    			//so if there is a sun present, it will activate the crusing mode collector	
    		if(this.ispaceswitch && this.firstrun) {
    			this.ispaceswitch = false
    			this.firstrun = false
    			player.consoleMessage("Fuel Collector",3)
    			player.consoleMessage("Interstellar space: Fly at max speed to extract fuel",3)
    		}
    		
    		//if there is not a sun there it will extract whatever it can from its surroundings..
    		//however only as long as the player is at max speed.
    		if(player.ship.speed == player.ship.maxSpeed)		
    		this.$checkifover01(this.fuel_level_1*Math.random())
    		return  
    	} else {		
    		//what distance are we at to the star
    		// to close and it will shutdown, to far away it will collect very little
    		
    		/* a notice on why it shuts down, when to close
    		
    		due to the fine filter of the fuel collector, it will shut down when it
    		gets to close to the star so that the filter is having a chance of getting
    		cleaned by the subsequent cleaning, which in effect harvest the fuel from
    		the filter
    		
    		The fuel scoop will then take over shortly after..
    		*/
    		
    		
    		let sun_distance = player.ship.position.distanceTo(system.sun)+system.sun.radius	
    		/* This is the old shut off if to close to sun..
    		// this however didnt take into consideration, the proximity to the planet
    		*/
    		
    		if ((player.ship.speed > player.ship.maxSpeed) || ( 7 == player.ship.fuel && !worldScripts.FuelTweaks_Quirium)) {//|| means explicit or // injector or warp speed
                return // return because we really dont need more checking from here
    		}
    		
    		let distancemodifier =10
    				
    		if(sun_distance< this.averagesun)
    		distancemodifier = 30
    		if(sun_distance< this.nearsun)
    		distancemodifier = 50 //this is near the filters saturation limit,..
    				
    		let speedp = 100/player.ship.maxSpeed*player.ship.speed
    		
    		if (speedp>89) {
    			this.$checkifover01(this.fuel_level_4+distancemodifier)			
    			//player.consoleMessage("speed over 89 %", 3) // for testing
    			return			
    		}
    		
    		if(speedp>49) {
    			this.$checkifover01(this.fuel_level_3+distancemodifier)
    			//player.consoleMessage("speed over 49 %",3) // for testing
    			return			
    		}
    		
    		if(speedp>19) {
    			this.$checkifover01(this.fuel_level_2+distancemodifier)
    			//player.consoleMessage("speed over 19 %",3) // for testing
    			return			
    		}		
    	}
    }
    
    this.$updateManifest = function $updateManifest() {
        mission.setInstructions("Quirium Fuel Processor status: " + (parseFloat(this._preProcessAmount / this._oneTAmount) * 100).toFixed(1) + "%% full",this.name);
    }
    Scripts/fuelTweaks_station.js
    "use strict";
    this.name					= "FuelTweaks_Station";
    this.author					= "Thargoid";
    this.copyright				= "Creative Commons: attribution, non-commercial, sharealike with clauses - see readme.txt";
    this.description			= "Script for fuel station";
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipSpawned = function() { 
    	this.ship.scannerDisplayColor1 = "greenColor";
    	this.ship.scannerDisplayColor2 = "lightGrayColor";
    
    	var traders = system.shipsWithPrimaryRole("trader", this.ship, 50E3)	
    	if (traders.length > 0 && traders[0].AIState == "HEAD_FOR_PLANET") {
    		traders[0].script.checkFuelStationDistance = this.checkFuelStationDistance; // attach function to script.
    		traders[0].script.checkUsage = this.checkUsage; // attach function to script.
    		traders[0].setAI("fuelTweaks_gotoFuelStationAI.plist");
    	}
    
    	//  line the station up with the route one. Code borrowed from Anarchies for convenience.
    	if (system.isInterstellarSpace || !system.mainPlanet) return;
    	var targetVector = system.mainPlanet.position.subtract(this.ship.position).direction();
    	var angle = this.ship.heading.angleTo(targetVector);
    	var cross = this.ship.heading.cross(targetVector).direction();
    	this.ship.orientation = this.ship.orientation.rotate(cross, -angle);	
    	this.setColour();
    	this.setPrice();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.setColour = function() {
    	this.colRand = system.scrambledPseudoRandomNumber(45.32);
    	var colName = "yellowColor";
    	if (this.colRand < 0.25) colName = "blueColor";
    	if (this.colRand < 0.75) colName = "redColor";
    	if (this.colRand > 0.25 && this.colRand < 0.5) colName = "magentaColor";
    	this.ship.setMaterials({"fuelTweaks_station.png": { diffuse: colName }});
    }
    	
    //-------------------------------------------------------------------------------------------------------------
    this.setPrice = function() {
    	var fe = worldScripts.FuelTweaks_FuelEconomy;
    	var cf = fe.$getRefuelStationCostFactor();
    	this.fuelPrice = cf * EquipmentInfo.infoForKey("EQ_FUEL").price * player.ship.fuelChargeRate; // price per 0.1LY of fuel
    	if (system.economy === 0 || system.economy === 5) this.fuelPrice *= 1.2; //  rich industrial or agricultural
    	if (system.techLevel > 4 && system.techLevel < 11) this.fuelPrice *= 1.1; //  mid-tech level
    	this.fuelPrice = this.decPlaces(this.fuelPrice,2);
    }	
    
    //-------------------------------------------------------------------------------------------------------------
    this.decPlaces = function(number, places) {
    	if (!places || places < 0) places = 0;
    	if (!number) return 0;
    	return ((Math.round(number * Math.pow(10, places))) / Math.pow(10, places));
    }
    	
    //-------------------------------------------------------------------------------------------------------------
    this.playerDetected = function() {
    	this.firstMessage = true;
    	this.fuelTransferred = 0; // how many 0.1LY units are transferred
    	this.fuelBill = 0;
    	this.ship.commsMessage("Greetings Commander " + player.name + ". Refuel here for only " + this.decPlaces((10 * this.fuelPrice),1) + " credits per ly");
    	if (this.scanTimer) {
    		this.scanTimer.start();
    	} else {
    		this.scanTimer = new Timer(this, this.locatePlayer, 0, 0.50);
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.locatePlayer = function locatePlayer() {
    	if (!this.ship ||!this.ship.isValid || !this.ship.position || !player.ship.isValid) { 
    		// if the ship no longer exists but timer is running, e.g. if player has jumped whilst near a satellite into a system without one
    		this.playerGone();
    		return;
    	}
    
    	if (this.ship.position.distanceTo(player.ship) < 150) {
    		// player ship within 150m of the centre of the fuel station
    		if (player.ship.fuel < 7) {
    			if (player.credits > this.fuelBill) {
    				// player in place, fuel tank not full and credit balance not empty
    				player.ship.fuel += 0.1;
    				this.fuelBill += this.fuelPrice;
    				this.fuelTransferred++;
    
    				if (this.firstMessage) {
    					player.consoleMessage("Fuel transfer is underway, please come to a halt.", 6);
    					this.firstMessage = false;
    				}
    				return;
    			} else { // not enough funds left
    				player.consoleMessage("Insufficient credits remaining, transfer terminated.", 6);
    				this.scanTimer.stop();
    				return;
    			}
    		} else { // Fuel tank full
    			player.consoleMessage("Fuel tanks are full.", 6);
    			this.scanTimer.stop();
    			return;
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipTraversePositiveZ = this.shipTraverseNegativeZ = function(ship) {
    	if (ship.isPlayer) this.playerLeaving()
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerLeaving = function() {
    	this.fuelBill = this.decPlaces(this.fuelPrice * this.fuelTransferred,1);
    	player.consoleMessage("Summary - " + (this.fuelTransferred / 10) + " ly transferred, " + this.fuelBill + " credits charged.", 6);
    	player.credits -= this.fuelBill;
    	this.fuelTransferred = 0;
    	this.fuelBill = 0;
    	this.firstMessage = true;
    }
        
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillEnterWitchspace = this.playerGone = function() {
    	if(this.scanTimer) {
    		this.scanTimer.stop();
    		delete this.scanTimer;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDied = function(whom, why) {
    	this.playerGone();
    	this.fuelCount = (Math.ceil(Math.random() * 30) + 30);
    	this.ship.spawn("fuelStation_burningFuel", this.fuelCount); // lets make this go with a bang!
    
    	if (whom && whom.isPlayer) {
    		player.consoleMessage("CCTV beam towards the main station detected.", 6);
    		player.score -=1; // don't condone vandalism!
    		player.ship.setBounty(player.bounty + 20, "damaged property");
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // below not used by stationscript but is attached to traderscript.
    this.checkFuelStationDistance = function() {	
    	if (this.ship.position.distanceTo(this.ship.target) > 50E3) {
    		this.ship.reactToAIMessage("NEXT_FUELSTATION")
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.checkUsage = function() {
    	if (this.ship.target.position.distanceTo(player.ship) < 1000) {
    		this.ship.reactToAIMessage("NEXT_FUELSTATION")
    	} else {
    		this.ship.reactToAIMessage("STATION_CLEAR")
    	}
    }
    	
    //-------------------------------------------------------------------------------------------------------------
    this.attackedMessage = function() {
    	this.ship.commsMessage("ALERT - fuel station under attack, explosion danger!");
    }	
    	
    //-------------------------------------------------------------------------------------------------------------
    this.collisionMessage = function() {
    	this.ship.commsMessage("ALERT - proximity detection, please take evasive action");
    }
    Scripts/fuelTweaks_stationSetup.js
    "use strict";
    this.name					= "FuelTweaks_StationSetup";
    this.author					= "Thargoid";
    this.copyright				= "Creative Commons: attribution, non-commercial, sharealike with clauses - see readme.txt";
    this.description			= "Script to add fuel station to certain systems";
    
    this._notify = false;
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function() {
    	if (missionVariables.FuelTweaks_Notice) this._notify = missionVariables.FuelTweaks_Notice;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function() {
    	if (worldScripts.BountySystem_Core) {
    		worldScripts.BountySystem_Core._offenceTypes["damaged property"] = {description:"Willful damage of GalCop property.", severity:2};
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.missionScreenOpportunity = function() {
    	if (this._notify == false) {
    		this._notify = true;
    		/*mission.runScreen({
    			screenID:"oolite-fueltweaks-notice-map",
    			title: "Change to refuelling process",
    			model:"fuelTweaks_station",
    			spinModel:true,
    			message: this.$duplicate("=", 32) + "\nOfficial GalCop Notice:\n" + this.$duplicate("-", 32) + "\n\nDue to a spate of accidents involving refuelling at GalCop stations, all pilots need to be aware of new rules and processes governing the refuelling of ships.\n\nYou will no longer be able to fully refuel your ship at GalCop stations. Instead, GalCop have installed a specialised refuelling station near the main station of many systems. Pilots can enter these facilities to refuel.\n\nThere are a few places where these refuelling stations are not yet able to be installed, and so you will be able to purchase an emergency fuel ration from those stations.\n\nWe thank you for your support and help in making our stations safer.\n\nGalCop Port Authority",
    			exitScreen: "GUI_SCREEN_STATUS"
    		});*/
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function() {
    	missionVariables.FuelTweaks_Notice = this._notify;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.systemWillPopulate = function() {
    	if (system.isInterstellarSpace || system.sun.isGoingNova || system.sun.hasGoneNova || system.countShipsWithRole("fuelTweaks_location") > 0) return;
    
    	// no anarchy system, and no really low-tech systems
    	var fe = worldScripts.FuelTweaks_FuelEconomy;
    	if (fe.$isRefuelStationAvailable() === false) return;
    
    	var posFS = system.mainStation.position.add(system.mainStation.vectorForward.multiply(system.mainStation.scannerRange * -0.8));
    
    	system.setPopulator("fuel_station", {
    		location: "COORDINATES",
    		coordinates: posFS,
    		callback: function(pos) {
    			var fs = system.addShips("fuelTweaks_station", 1, pos, 0);
    		}}
    	);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // 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;
    }