Back to Index Page generated: May 17, 2025, 5:47:49 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.16 1.16
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 1746613058

    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 settings in Library Config or 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 prime-able 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. For safety reasons, the process will stop automatically if you dock, begin a hyperspace jump or enter a wormhole.
    
    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.
    
    Library Config
    ==============
    Many of the settings can be customised via Library Config.
    
    Fuel Availability: Allegiance
    -----------------------------
    This setting allows you to control which stations will have fuel, based on their allegiance. Select all the allegiances you want fuel to be available at by changing the "0" to a "1" in front of each allegiance type. Selecting no allegiances will effectively mean fuel will be available at any stations, regardless of allegiance (ie. this would be the same as the base game, where all stations that have an F3 screen will offer fuel for sale).
    
    Fuel Availability: Economies
    ----------------------------
    This settings allows you to control which systems will have fuel, based on their economy. Select all the economies you want fuel to be available at by changing the "0" to a "1" in front of each economy type.
    
    Fuel Availability: Governments
    ------------------------------
    This settings allows you to control which systems will have fuel, based on their government. Select all the governments you want fuel to be available at by changing the "0" to a "1" in front of each government type.
    
    Fuel Stations: Economies
    ------------------------
    This settings allows you to control which systems will have fuel stations, based on their economy. Select all the economies you want fuel stations to be available at by changing the "0" to a "1" in front of each economy type.
    
    Fuel Stations: Governments
    --------------------------
    This settings allows you to control which systems will have fuel stations, based on their government. Select all the governments you want fuel stations to be available at by changing the "0" to a "1" in front of each government type.
    
    General Settings
    ----------------
    Switches:
        Apply changes: True means changes made to the fuel availability settings will be saved with the game and will apply when the game is reloaded. False means the settings will only apply in the current game until it is reloaded.
        Normal fuel operation: True means all settings are ignored, and the default fuel system will be in place. False means all settings are applied, and by default, this will create refuelling stations near each main station. Use this to quickly turn the system on or off.
        Fuel rationing: True means there will be limits to the amount of fuel you can purchase. False means no rationing will be in effect.
    
    Values:
        Max fuel ration: When rationing is in effect, set the maximum amount that can be purchased. Integer between 0 and 6.
        Default min TL: The minimum TL of a system where fuel can be purchased. 0 means everywhere.
        Refuel stn cost factor: The cost factor applied to fuel purchases from fuel stations. If 7LY of fuel would normally cost 15cr, a factor 0.15 would mean the actual cost would be (15 x 0.15) 2.25cr.
        Refuel stn min TL: The minimum TL of a system where fuel stations will be present. 0 means everywhere.
    
    Examples
    ========
    1. Using Refuelling Stations for fuel.
    In order to move all refuelling functions to refuelling stations, do the following:
        a. Set "General Settings", "Switches", "Apply changes" to true.
        b. Set "General Settings", "Switches", "Normal fuel operation" to false.
    
    2. Only having Refuelling Stations in certain government types.
    To limit where refuelling stations will appear by the government type, do the following:
        a. Open "Fuel Stations: Governments", "Flags", and change the flag from 1 to 0 on all government types where you do not want refuelling stations to appear.
    
    3. Allowing normal refuelling at some government types.
    In order to allow some governments to have normal fuel operations (ie fuel can be purchased via the F3 Equip Ship screen), do the following:
        a. Open "Fuel Availability: Governments", "Flags", and change the flag from 1 to 0 on all government types where you do not want normal fuel operations.
        b. Open "Fuel Stations: Governments", "Flags", and ensure the opposite value is set for the government. That is, if you turned on fuel availability at Democracies, turn off fuel stations at Democracies.
    
    4. Implementing fuel rationing.
    In order to allow fuel rationing, do the following:
        a. Set "General Settings", "Switches", "Fuel rationing" to true.
        b. Set "General Settings", "Values", "Max fuel ration" to the maximum number you want available. The default is 1 (ie only 1 LY of fuel can be purchased at the station per system visit).
    Once fuel rationing is in place, any fuel availability settings will apply to rations. That is, if fuel is available in a system, it will be rationed.
    
    JavaScript interfaces
    =====================
    Note: Changes made to the fuel system via these JavaScript methods will only persist across save games if the "Save settings" option is true.
    
    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[, maxRations : 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 a null value.
        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.
        maxRations is an optional integer indicating the maximum amount of rationed fuel that can be purchased, between 0 and 6.
    
        ---------------------------------------------------------------------------------------------------------------------
        worldScripts.FuelTweaks_FuelEconomy.$setMaxFuelRation(maxVal : int);
    
        Sets the default maximum amount of fuel that can be purchased through 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 refuelling stations:
    Note: Refuel stations will not be present if no fuel is available in the system.
    Note: If a refuelling 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[, factor: float]);
    
        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 a null value.
        tl is an integer, being the minimum techlevel required, between -1 and 15 (-1 means no techlevel check is performed)
        factor is an optional decimal value that indicates the default fuel cost factor applied to these fuel stations.
    
        ---------------------------------------------------------------------------------------------------------------------
        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 specified 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 WildShips docking port. 
    
    Fuel flow and shutdown sounds from Machine-Shutdown-021.wav by Astounded -- https://freesound.org/s/520810/ -- License: Attribution 4.0
    
    Discussion
    ==========
    This OXP is discussed at this forum link: http://bb.oolite.space/viewtopic.php?f=4&t=18947
    
    Version History
    ===============
    1.16
    - Tweaks to the refuelling station texture.
    
    1.15
    - Switched logic for checking economy and government to be more logical. An empty array means everything is turned off, rather than ignored.
    - Added Library Config options so player can easily change fuel settings for their game.
    - A galactic jump will now not remove default settings, just any settings added via JS.
    - Witchspace jumps will now stop any transfer of Quirium fuel from storage.
    - Reduced the chance of damage when transferring fuel. Reduced the chance of a catastrophic failure.
    - New fuel station model added, to replace old one.
    - Added sound effects while fuel transfer in progress.
    
    1.14.6
    - Fixed JS error when removing items via the F3 Equip Ship screen.
    
    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 (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_alertFX.js
    "use strict";
    this.name = "fuelTweaks_alertFX";
    this.author = "Svengali & Thargoid, phkb";
    this.copyright = "CC-by";
    this.description = "FX script";
    this.version = "1.0";
    
    this.effectSpawned = function () {
    	var scr = worldScripts.FuelTweaks_StationSetup;
    	this.getRid = 0;
    	// size and align ve
    	this.visualEffect.scale(scr._fxScale);
    	var p = player.ship;
        this.visualEffect.position = p.position.add(p.vectorForward.multiply(scr._fxForward)).add(p.vectorUp.multiply(scr._fxUp));
    	this.visualEffect.orientation = p.orientation;
    	// start the frame callback
    	this.ovFCBID = addFrameCallback(this.repos.bind(this));
    }
    
    this.effectRemoved = function () {
    	removeFrameCallback(this.ovFCBID);
    }
    
    this.repos = function (delta) {
    	var p = player.ship;
    	if (!p.isValid || this.getRid > 6) {
    		this.visualEffect.remove();
    		return;
    	}
    	var scr = worldScripts.FuelTweaks_StationSetup;
    
        this.visualEffect.position = p.position.add(p.vectorForward.multiply(scr._fxForward)).add(p.vectorUp.multiply(scr._fxUp));
        this.visualEffect.orientation = p.orientation;
    
    	this.getRid += delta;
    	return;
    }
    
    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(300, 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.indexOf(alleg) === -1) return false; // fe._fuelAllegiance.length > 0 && 
            // 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;
        }
        // in case our condition script has won the install race via equipment-overrides
        if (equipment == "EQ_FUEL" && player.ship.dockedStation.dataKey == "KW_II") {
            newprice = worldScripts["oolite-II"].updateEquipmentPrice(equipment, 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";
    
    /* 
    check: fuel available at corp state, but rations were shown instead. plus, rations up to 6 were shown, even though limit was 4
    also, buying the 5 and 6 rations did nothing (ie no fuel)
    */
    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._npcUseStations = false;
    this._defaultMinTL = 0;
    this._fuelGovs = 0;
    this._fuelEcos = 0;
    this._fuelAvailability = [{eco:[0,1,2,3,4,5,6,7],gov:[0,1,2,3,4,5,6,7],tl:0,rations:false,max:1}];
                                                // 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 6 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._fuelAllegiances = 1;
    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._defaultRSMinTL = 0;
    this._refuelGovs = 0;
    this._refuelEcos = 0;
    this._refuelStationAvailability = [{eco:[0,1,2,3,4,5,6,7],gov:[0,1,2,3,4,5,6,7],tl:0,factor:0.15}];
                                               // 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._allegiances = ["galcop", "neutral", "pirate", "chaotic", "military", "private", "restricted", "hunter", "thargoid"];
    this._ecos = [];
    this._govs = [];
    
    // configuration settings for use in Lib_Config
    this._feConfig = {
    	Name: this.name,
    	Alias: "Fuel Tweaks",
    	Display: "General Settings",
    	Alive: "_feConfig",
    	Notify: "$update",
    	Bool: {
    		B0: { Name: "_saveSettings", Def: false, Desc: "Apply changes" },
    		B1: { Name: "_fuelNormal", Def: true, Desc: "Normal fuel operation" },
            B2: { Name: "_fuelUseRations", Def: false, Desc: "Fuel rationing" },
            B3: { Name: "_npcUseStations", Def: false, Desc: "NPCs use stations" },
    		Info: "0: Apply any fuel availability changes when saving the game; 1: Apply normal (ie standard) fuel operations in all systems - all settings will be ignored; 2: Use fuel rationing when custom options are in operation; 3: NPC's will be allowed to use refuelling stations."
    	},
    	SInt: {
    		S0: { Name: "_maxFuelRation", Def: 1, Min: 0, Max: 6, Desc: "Max fuel ration" },
    		S1: { Name: "_defaultMinTL", Def: 0, Min: 0, Max: 15, Desc: "Default min TL" },
    		S2: { Name: "_refuelStationCostFactor", Def: 0.15, Min: 0.01, Max: 50, Float:true, Desc: "Refuel stn cost factor" },
    		S3: { Name: "_defaultRSMinTL", Def: 0, Min: 0, Max: 15, Desc: "Refuel stn min TL" },
    		Info: "0: Maximum fuel ration available (when rationing in place); 1: Minimum TL for purchasing fuel, where 0 means everywhere; 2: Default cost factor applied to any fuel stations; 3: Minimum TL where Refuel Stations are available, where 0 means everywhere."
    	},
    };
    
    this._faAllegianceConfig = {
        Name: this.name,
        Display: "Fuel Availability: Allegiance",
        Alias: "Fuel Tweaks",
        Alive: "_faAllegianceConfig",
        Notify: "$update",
        EInt: {
            E0: {
                Name: "_fuelAllegiances",
                Def: 0,
                Min: 0,
                Max: 511,
                Desc: this._allegiances
            },
            Info: "Station allegiances where fuel will be available."
        },
    };
    
    this._faGovernmentConfig = {
        Name: this.name,
        Display: "Fuel Availability: Governments",
        Alias: "Fuel Tweaks",
        Alive: "_faGovernmentConfig",
        Notify: "$update",
        EInt: {
            E0: {
                Name: "_fuelGovs",
                Def: 0,
                Min: 0,
                Max: 255,
                Desc: this._govs
            },
            Info: "Default Governments where fuel will be available."
        },
    };
    
    this._faEconomyConfig = {
        Name: this.name,
        Display: "Fuel Availability: Economies",
        Alias: "Fuel Tweaks",
        Alive: "_faEconomyConfig",
        Notify: "$update",
        EInt: {
            E0: {
                Name: "_fuelEcos",
                Def: 0,
                Min: 0,
                Max: 255,
                Desc: this._ecos
            },
            Info: "Default Economic types where fuel will be available."
        },
    };
    
    this._rsGovernmentConfig = {
        Name: this.name,
        Display: "Fuel Stations: Governments",
        Alias: "Fuel Tweaks",
        Alive: "_rsGovernmentConfig",
        Notify: "$update",
        EInt: {
            E0: {
                Name: "_refuelGovs",
                Def: 0,
                Min: 0,
                Max: 255,
                Desc: this._govs
            },
            Info: "Default Governments where fuel stations will be available."
        },
    };
    
    this._rsEconomyConfig = {
        Name: this.name,
        Display: "Fuel Stations: Economies",
        Alias: "Fuel Tweaks",
        Alive: "_rsEconomyConfig",
        Notify: "$update",
        EInt: {
            E0: {
                Name: "_refuelEcos",
                Def: 0,
                Min: 0,
                Max: 255,
                Desc: this._ecos
            },
            Info: "Default Economic types where fuel stations will be available."
        },
    };
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function() {
    	for (var i = 0; i < 8 ; i++) this._govs.push(String.fromCharCode(i) + " " + this.$governmentDescription(i));
    	for (i = 0; i < 8 ; i++) this._ecos.push(String.fromCharCode(23 - i) + " " + this.$economyDescription(i));
    
        /*
        // 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 (missionVariables.FuelTweaks_SaveSettings) {
            this._saveSettings = (this._trueValues.indexOf(missionVariables.FuelTweaks_SaveSettings) >= 0 ? true : false);
        }
        if (this._saveSettings === true) {
            if (missionVariables.FuelTweaks_FuelAvailability) {
                this._fuelAvailability = JSON.parse(missionVariables.FuelTweaks_FuelAvailability);
                //delete missionVariables.FuelTweaks_FuelAvailability;
            }
            if (missionVariables.FuelTweaks_FuelMinTL) {
                this._defaultMinTL = parseInt(missionVariables.FuelTweaks_FuelMinTL);
            }
            if (missionVariables.FuelTweaks_MaxFuelRation) {
                this._maxFuelRation = parseInt(missionVariables.FuelTweaks_MaxFuelRation);
            }
            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_RefuelStationMinTL) {
                this._defaultRSMinTL = parseInt(missionVariables.FuelTweaks_RefuelStationMinTL);
            }
            if (missionVariables.FuelTweaks_Normal) {
                this._fuelNormal = (this._trueValues.indexOf(missionVariables.FuelTweaks_Normal) >= 0 ? true : false);
            }
            if (missionVariables.FuelTweaks_UseRations) {
                this._fuelUseRations = (this._trueValues.indexOf(missionVariables.FuelTweaks_UseRations) >= 0 ? true : false);
            }
            if (missionVariables.FuelTweaks_NPCUseStations) {
                this._npcUseStations = (this._trueValues.indexOf(missionVariables.FuelTweaks_NPCUseStations) >= 0 ? true : false);
            }
        }
        this.$updateIsisEquipment();
        delete this.startUp;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function() {
        this.$updateBitwiseValues();
    
        // register our settings, if Lib_Config is present
        if (worldScripts.Lib_Config) {
            worldScripts.Lib_Config._registerSet(this._feConfig);
            worldScripts.Lib_Config._registerSet(this._faAllegianceConfig);
            worldScripts.Lib_Config._registerSet(this._faGovernmentConfig);
            worldScripts.Lib_Config._registerSet(this._faEconomyConfig);
            worldScripts.Lib_Config._registerSet(this._rsGovernmentConfig);
            worldScripts.Lib_Config._registerSet(this._rsEconomyConfig);
        }
    
        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
        missionVariables.FuelTweaks_SaveSettings = this._saveSettings;
        if (this._saveSettings === true) {
            missionVariables.FuelTweaks_FuelAvailability = JSON.stringify(this._fuelAvailability);
            missionVariables.FuelTweaks_FuelMinTL = this._defaultMinTL;
            missionVariables.FuelTweaks_MaxFuelRation = this._maxFuelRation;
            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_RefuelStationMinTL = this._defaultRSMinTL;
            missionVariables.FuelTweaks_Normal = this._fuelNormal;
            missionVariables.FuelTweaks_UseRations = this._fuelUseRations;
            missionVariables.FuelTweaks_NPCUseStations = this._npcUseStations;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    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
            if (this._fuelAvailability.length > 1) {
                for (var i = 1; i < this._fuelAvailability.length; i++) this._fuelAvailability.splice(1, 1);
            }
            this._fuelSystemOverride = [];
            if (this._refuelStationAvailability.length > 1) {
                for (var i = 1; i < this._refuelStationAvailability.length; i++) this._refuelStationAvailability.splice(1, 1);
            }
            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 (ecoList && Array.isArray(ecoList) === false) {
            throw "Invalid settings - ecoList must be an array";
        }
        if (!ecoList) {
            ecoList = [0, 1, 2, 3, 4, 5, 6, 7];
        } else {
            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 (govList && Array.isArray(govList) === false) {
            throw "Invalid settings - govList must be an array";
        }
        if (!govList) {
            govList = [0, 1, 2, 3, 4, 5, 6, 7];
        } else {
            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 = 1; 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 (ecoList && Array.isArray(ecoList) === false) {
            throw "Invalid settings - ecoList must be an array";
        }
        if (!ecoList) {
            ecoList = [0, 1, 2, 3, 4, 5, 6, 7];
        } else {
            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 (govList && Array.isArray(govList) === false) {
            throw "Invalid settings - govList must be an array";
        }
        if (!govList) {
            govList = [0, 1, 2, 3, 4, 5, 6, 7];
        } else {
            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";
            }
        }
    
        // don't remove the default settings
        if (this._fuelAvailability.length > 1) {
            var test = JSON.stringify({eco:ecoList, gov:govList, tl:tl, rations:useRations, max:maxRation});
            for (var i = 1; 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 = this._allegiances;
    	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: " + this._allegiances.join();
    		}
    	}
    	this._fuelAllegiance = alleg;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // adds a refuel station availability register to the list
    this.$addRefuelStationAvailability = function(ecoList, govList, tl, factor) {
        if (ecoList && Array.isArray(ecoList) === false) {
            throw "Invalid settings - ecoList must be an array";
        }
        if (!ecoList) {
            ecoList = [0, 1, 2, 3, 4, 5, 6, 7];
        } else {
            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 (govList && Array.isArray(govList) === false) {
            throw "Invalid settings - govList must be an array";
        }
        if (!govList) {
            govList = [0, 1, 2, 3, 4, 5, 6, 7];
        } else {
            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";
        }
    
        if (this._refuelStationAvailability.length > 1) {
            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.indexOf(ecoID) >= 0) checkCount += 1; // itm.eco.length === 0 || 
            if (itm.gov.indexOf(govID) >= 0) checkCount += 1; // itm.gov.length === 0 || 
            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.useRation;
        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.maxRation;
        // 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 refuel 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.indexOf(ecoID) >= 0) checkCount += 1; // itm.eco.length === 0 || 
            if (itm.gov.indexOf(govID) >= 0) checkCount += 1; // itm.gov.length === 0 || 
            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;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$update = function() {
        this._fuelAllegiance = [];
        var set = 1;
        for (var i = 0; i < this._allegiances.length; i++) {
            if (this._fuelAllegiances & set) {
                this._fuelAllegiance.push(this._allegiances[i])
            }
            set *= 2;
        }
    
        // fuel availability
        var fa = {
            eco:[],
            gov:[],
            tl:(this._defaultMinTL - 1),
            useRation:this._fuelUseRations,
            maxRation:this._maxFuelRation
        };
        var set = 1;
        for (var i = 0; i < this._govs.length; i++) {
            if (this._fuelGovs & set) {
                fa.gov.push(i)
            }
            set *= 2;
        }
        var set = 1;
        for (var i = 0; i < this._ecos.length; i++) {
            if (this._fuelEcos & set) {
                fa.eco.push(i)
            }
            set *= 2;
        }
        
        if (this._fuelAvailability.length >= 1) {
            this._fuelAvailability[0] = fa;
        } else {
            this._fuelAvailability.push(fa);
        }
    
        // refuel stations
        var rs = {
            eco:[],
            gov:[],
            tl:(this._defaultRSMinTL - 1),
            factor:this._refuelStationCostFactor
        }
        var set = 1;
        for (var i = 0; i < this._govs.length; i++) {
            if (this._refuelGovs & set) {
                rs.gov.push(i)
            }
            set *= 2;
        }
        var set = 1;
        for (var i = 0; i < this._ecos.length; i++) {
            if (this._refuelEcos & set) {
                rs.eco.push(i)
            }
            set *= 2;
        }
        if (this._refuelStationAvailability.length >= 1) {
            this._refuelStationAvailability[0] = rs;
        } else {
            this._refuelStationAvailability.push(rs);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$updateBitwiseValues = function() {
        var bitVals = [1, 2, 4, 8, 16, 32, 64, 128, 256];
        this._fuelAllegiances = 0;
        for (var i = 0; i < this._fuelAllegiance.length; i++) {
            var idx = this._allegiances.indexOf(this._fuelAllegiance[i]);
            this._fuelAllegiances += bitVals[idx];
        }
        this._fuelGovs = 0;
        this._fuelEcos = 0;
        if (this._fuelAvailability.length > 0) {
            for (var i = 0; i < this._fuelAvailability[0].gov.length; i++) {
                this._fuelGovs += bitVals[(this._fuelAvailability[0].gov[i])];
            }
            for (var i = 0; i < this._fuelAvailability[0].eco.length; i++) {
                this._fuelEcos += bitVals[(this._fuelAvailability[0].eco[i])];
            }
        }
        this._refuelGovs = 0;
        this._refuelEcos = 0;
        if (this._refuelStationAvailability.length > 0) {
            for (var i = 0; i < this._refuelStationAvailability[0].gov.length; i++) {
                this._refuelGovs += bitVals[(this._refuelStationAvailability[0].gov[i])];
            }
            for (var i = 0; i < this._refuelStationAvailability[0].eco.length; i++) {
                this._refuelEcos += bitVals[(this._refuelStationAvailability[0].eco[i])];
            }
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // resets all fuel-related data
    this.$reset = function() {
        this._saveSettings = false;    
        this._fuelNormal = true;
        this._npcUseStations = false;
        this._fuelUseRations = false;
        this._fuelAvailability = [{eco:[0,1,2,3,4,5,6,7],gov:[0,1,2,3,4,5,6,7],tl:0,rations:false,max:1}];
        this._maxFuelRation = 1;
        this._fuelAllegiance = ["galcop"];
        this._fuelSystemOverride = [];
        this._refuelStationAvailability = [{eco:[0,1,2,3,4,5,6,7],gov:[0,1,2,3,4,5,6,7],tl:0,factor:0.15}];
        this._refuelStationSystemOverride = [];
        this._refuelStationCostFactor = 0.15
        this._defaultRSMinTL = 0;
        this._emergencyFuel = [];
        delete missionVariables.FuelTweaks_FuelAvailability;
        delete missionVariables.Fuel
        delete missionVariables.FuelTweaks_Allegiance;
        delete missionVariables.FuelTweaks_FuelSystemOverride;;
        delete missionVariables.FuelTweaks_RefuelStationAvailability;
        delete missionVariables.FuelTweaks_RefuelStationSystemOverride;
        delete missionVariables.FuelTweaks_RefuelStationCostFactor;
        delete missionVariables.FuelTweaks_RefuelStationMinTL;
        delete missionVariables.FuelTweaks_Normal;
        this.$updateBitwiseValues();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$governmentDescription = function $governmentDescription(gov) {
    	switch (gov) {
    		case 0: return "Anarchy";
    		case 1: return "Feudal";
    		case 2: return "Multi-Government";
    		case 3: return "Dictatorship";
    		case 4: return "Communist";
    		case 5: return "Confederacy";
    		case 6: return "Democracy";
    		case 7: return "Corporate State";
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$economyDescription = function $economyDescription(eco) {
    	if (worldScripts["market_tweak.js"]) {
    		switch (eco) {
    			case 0: return "Extreme Industrial";
    			case 1: return "Strong Industrial";
    			case 2: return "Common Industrial";
    			case 3: return "Mainly Industrial";
    			case 4: return "Mainly Agricultural";
    			case 5: return "Common Agricultural";
    			case 6: return "Strong Agricultural";
    			case 7: return "Extreme Agricultural";
    		}
    	} else {
    		switch (eco) {
    			case 0: return "Rich Industrial";
    			case 1: return "Average Industrial";
    			case 2: return "Poor Industrial";
    			case 3: return "Mainly Industrial";
    			case 4: return "Mainly Agricultural";
    			case 5: return "Rich Agricultural";
    			case 6: return "Average Agricultural";
    			case 7: return "Poor Agricultural";
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // this ensures our overrides to EQ_FUEL will get included if Isis Interstellar wins the install race
    // if, instead, we win, the Isis script wouldn't be called for EQ_FUEL anyway.
    this.$updateIsisEquipment = function() {
        if (worldScripts["oolite-II"]) {
            var ii = worldScripts["oolite-II"];
            ii.$hold_allowAwardEquipment = ii.II_allowAwardEquipment;
            ii.II_allowAwardEquipment = this.$II_allowAwardEquipment;
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$II_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;
        }
        return this.$hold_allowAwardEquipment(equipment, ship, context);
    }
    
    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.02; // 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);
            var eq = EquipmentInfo.infoForKey(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.02;
            ft._transferTimer.stop();
            player.consoleMessage("Fuel transfer stopped. 1t Quirium fuel consumed.");
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerStartedJumpCountdown = this.shipWillEnterWitchspace = function() {
        // starting a witchspace jump, or entering a wormhole, should now automatically stop any transfer in progress
        this.mode();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    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.02;
                        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.9995) {
                // equipment
                this.$performEquipmentDamage();
            }
            if (type >= 0.9995) {
                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; // slowly increate the damage chance.
    }
    
    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._mySound = null;
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipSpawned = function () {
    	this.ship.scannerDisplayColor1 = "greenColor";
    	this.ship.scannerDisplayColor2 = "lightGrayColor";
    
    	if (worldScripts.FuelTweaks_FuelEconomy._npcUseStations) {
    		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("green");
    	this.setPrice();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.setColour = function (colName) {
    	var rgb = [];
    	switch (colName) {
    		case "red":
    			rgb = [255, 0, 0];
    			break;
    		case "orange":
    			rgb = [255, 106, 0];
    			break;
    		case "green":
    			rgb = [0, 255, 0];
    	}
    	for (var i = 65; i < this.ship.flashers.length; i++) {
    		this.ship.flashers[i].color = rgb;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    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.$stopSound();
    		this.ship.flashers[40].active = true;
    		this.playerGone();
    		return;
    	}
    	var p = player.ship;
    	var d = this.ship.position.distanceTo(p);
    
    	if (d >= 150 && d < 700) {
    		this.setColour("orange");
    	}
    
    	if (d < 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) {
    					this.$playSound("fuelflow");
    					var scr = worldScripts.FuelTweaks_StationSetup;
    					this.ship.flashers[40].active = false;
    					system.addVisualEffect("fuelTweaks_alertFX", p.position.add(p.vectorForward.multiply(scr._fxForward)).add(p.vectorUp.multiply(scr._fxUp)));
    					player.consoleMessage("Fuel transfer is underway, please come to a halt.", 6);
    					this.firstMessage = false;
    					this.setColour("red");
    				}
    				return;
    			} else { // not enough funds left
    				player.consoleMessage("Insufficient credits remaining, transfer terminated.", 6);
    				this.ship.flashers[40].active = true;
    				this.setColor("green");
    				this.$playSound("fuelshutoff");
    				this.scanTimer.stop();
    				return;
    			}
    		} else { // Fuel tank full
    			player.consoleMessage("Fuel tanks are full.", 6);
    			this.ship.flashers[40].active = true;
    			this.setColour("green");
    			this.$playSound("fuelshutoff");
    			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);
    	this.setColour("green");
    	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();
    	if (Math.random() < 0.4) {
    		this.ship.becomeCascadeExplosion();
    	} else {
    		this.fuelCount = (Math.ceil(Math.random() * 30) + 30);
    		this.ship.spawn("fuelTweaks_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");
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // plays the sound of the fuel being filled
    this.$playSound = function $playSound(type) {
    	if (this._mySound && this._mySound.isPlaying) this._mySound.stop();
    	this._mySound = new SoundSource;
        switch (type) {
            case "fuelflow":
                this._mySound.sound = "fuelflow.ogg";
    			this._mySound.loop = true;
                break;
    		case "fuelshutoff":
                this._mySound.sound = "fuelshutoff.ogg";
    			this._mySound.loop = false;
        }
    	this._mySound.play();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$stopSound = function() {
    	if (this._mySound && this._mySound.isPlaying) {
    		this._mySound.stop();
    	}
    	this._mySound = null;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // 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._fxScale = 0.2;
    this._fxForward = 200;
    this._fxUp = 20;
    
    //-------------------------------------------------------------------------------------------------------------
    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;
    }