Back to Index Page generated: Dec 20, 2024, 7:22:09 AM

Expansion MFD - Combat MFD

Content

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Makes the Multi-Function Displays more useful by displaying some info from your ship and your target. Fill up 40 custom HUD dials with useful values for HUDs in HUDSelector. Makes the Multi-Function Displays more useful by displaying some info from your ship and your target. Fill up 40 custom HUD dials with useful values for HUDs in HUDSelector.
Identifier oolite.oxp.Norby.CombatMFD oolite.oxp.Norby.CombatMFD
Title MFD - Combat MFD MFD - Combat MFD
Category HUDs HUDs
Author Norby, Zireael Norby, Zireael
Version 1.19 1.19
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
  • oolite.oxp.Norby.HUDSelector:1.8
  • oolite.oxp.CommonSenseOTB.NumericHUD:3.26
  • oolite.oxp.Norby.HUDSelector:1.8
  • oolite.oxp.CommonSenseOTB.NumericHUD:3.26
  • Conflict Expansions
    Information URL https://wiki.alioth.net/index.php/CombatMFD n/a
    Download URL https://wiki.alioth.net/img_auth.php/6/6d/CombatMFD-1.19.oxz n/a
    License CC BY-NC-SA 3 CC BY-NC-SA 3
    File Size n/a
    Upload date 1713496591

    Documentation

    Also read http://wiki.alioth.net/index.php/MFD%20-%20Combat%20MFD

    Readme.txt

    Combat MFD
    ----------
    v1.14, by Norby
    
    If you buy Combat MFD equipment then your Multi-Function Displays will display many info from your ship:
    -energy and SEE indicator (see below) in the first line,
    -forward and aft shields (including Shield Capacitors), Shield Cycler mode (Equal, Forward, Aft or Disabled),  then equipment and one-shot indicators (see below),
    -legal status, fuel and speed (including Q-Charger, Torus To Sun multiplier and FTL speeds),
    -the name of the lastly damaged equipment then the number of how many others are damaged,
    
    then your target's:
    -name,
    -distance, mass and speed,
    -shield radius, then Front/Aft orientation display and Damaged!/Weak!/Derelict flag.
    -laser weapon type and range (after a shot),
    -status: Clean/Offender/Fugitive, if derelict then Trap or Treasure/Empty/Mined/Usable (see Towbar OXP).
    -fired missiles counter with "Hard" flag.
    
    Telescope can display the newly detected target in the last line.
    
    Use the ";" and ":" keys to select an MFD and enjoy the view. ;)
    
    Compatible with Telescope OXP if lock far targets and ShieldEqualizer+Capacitors OXP: if shields are over 100% then either Shield Boosters are installed or shield capacitors are filled also.
    
    The "Damaged!" flag shown when the target's exhaust plumes are blinking (below 40% energy) and "Weak!" when blinking strongly and drop sparks with CustomShields OXP (below 20%).
    If your HUD has support for this (like NumericHUDv3.25) then you will see these words near your crosshairs also. The support mean the following lines in the legends section of your hud.plist:
     { equipment_required="EQ_DTADAM"; x=30; y=40; y_origin=0; height=20; width=16; text="Damaged"; alpha=0.5; },
     { equipment_required="EQ_DTAWEA"; x=30; y=40; y_origin=0; height=20; width=16; text="Weak"; alpha=0.5; },
     { equipment_required="EQ_DTADER"; x=30; y=40; y_origin=0; height=20; width=16; text="Derelict"; },
    
    
    SEE indicator
    -------------
    
    The top right corner show letters about how many shields, armour and energy remaining.
    Each letter represents 2 energy banks in strength and ordered by from outside to inside.
    Small letters mean one side is up only.
    -C: Shield Capacitors (+50%),
    -M: Military shields (300%),
    -B: Shield Boosters (200%),
    -S: Shields (100%),
    -A: Armours in HardShips OXP (front and aft only), or Ship Configuration OXP
    -H: IronHide Armour OXP.
    -E: Energy (EE=4 banks).
    
    "SEE" mean you have basic Shields (2 banks=128 points) and 2*2 Energy banks filled (4 banks=256 points), as a Cobra Mark III at start.
    
    The total length is relative with your ship's defensive strength. The strongest Andromeda has CCCCCCCCMBSAAAAAAAAHHHEEEEEEEE. :)
    
    A letter will be changed to "-" if drops below the half of the banks represented by this letter so "-E" mean less than 3 banks filled and more than one.
    
    Underscore "_" mean equipment damage which prevent regeneration, you should fix it in a dock. Checked damages:
    -Shield Capacitors (includung big ones in HardShips OXP),
    -Military Shield Enhancement,
    -Shield Boosters,
    -Breakable Shield Generators,
    -Breakable Energy Unit.
    
    The number in the corner show the total value in banks (64 points).
    
    If you see "LAST BANK!" here instead of letters then ... well, you know. (Flee! ;))
    
    
    Equipment indicator
    -------------------
    
    Next to the shield values there are letters which show if the following equipments are installed and turned on:
    -"ECM" mean Auto ECM is active,
    -"Turret" mean Turret Toggler allow your turrets to fire.
    
    
    One-shot indicator
    ------------------
    
    The space rightwards from shield percentages show letters to indicate one-shot equipments, in order:
    -B: Energy Bomb,
    -C: Additional Core Hull (this and next from HardShips OXP),
    -E: Emergency Energy Generator (will be damaged at the second usage if High-Tech Catalyst is installed also),
    -G: Galactic Hyperdrive,
    -H: High-Tech Catalyst (from HardShips OXP, will be damaged at the first usage of Emergency Energy Generator),
    -P: Escape Pod,
    -R: Renewable Energy Generator (from HardShips OXP),
    -U: Emergency Energy Unit (from Energy Equipment OXP),
    
    
    
    Custom HUD dials
    ----------------
    
    Oolite v1.81 provide drawCustomText: HUD dial which can display informations without MFD.
    You still must buy the CombatMFD equipment for the followings but you must not show up the MFD if your HUD has support for these (like the Original and Small HUDs in HUDSelector).
    
    CombatMFD fill up the following dials with values, so HUD designers can use these:
    
     data_source   	description
     combatAftSh	aft shield numeric value, including capacitors
     combatAftShP	aft shield percent value, over 100% if upgraded
     combatAlt      altitude over the nearest planet, moon or sun in km
     combatAltR     altitude over a planet, moon or sun in radius
     combatCredits	credits of player
     combatCTemp	cabin temp
     combatDmgEq	name of the lastly damaged equipment
     combatDEqNum	number of the damaged equipments
     combatEnergy	energy of player ship in numeric form
     combatEnergyP	energy of player ship in percent
     combatFwSh     forward shield numeric value, including capacitors
     combatFwShP	forward shield percent value, over 100% if upgraded
     combatFuel     remaining fuel in the main tank in ly, min. 0.0, max. 7.0
     combatFuelReq	required fuel of a declared hyperjump
     combatFuelRes	reserve fuel in extra tanks (integer)
     combatLegal	legal status of player, Clean/Offender/Fugitive
     combatLegalNum	legal status of player, bounty
     combatNewTelT	name of the newest target detected by Telescope
     combatOneShot	letters of One-shot indicator (BCEGHPRU)
     combatSCTDist	distance of space compass target
     combatSEE      letters of SEE indicator about the player ship (CMBSAHE)
     combatSEEMax	maximum number of ship durability: max of shield+armour+energy
     combatSEENum	number of ship durability: shield+armour+energy
     combatSpeed	actual speed of player ship in m/s
     combatTDist	distance of the current target
     combatTDmg     damaged/weak/derelict status of the current target
     combatTEnergy	energy of the current target, use for debug only
     combatTLaser	laser weapon of the current target
     combatTLegal	legal status of the current target, if derelict then Towbar status
     combatTLRange	range of the target's laser weapon
     combatTMissile	missile type fired by the target, Normal/Hard/Unknown
     combatTMissNum	number of missiles fired by the target so far
     combatTName	full name of the current target
     combatTRadius	shield radius of the current target
     combatTSpeed	speed of the current target
    
    Numeric values are centered in a 28 character wide field by default, texts are left aligned (you can align to right in hud plist with align=1).
    The default width of centered fields is adjustable in the worldScripts.combat_MFD.$DW variable.
    If $DW is 0 then all field will be left aligned.
    If $DW negative then right aligned in the given width.
    
    Using the drawCustomBar: selector HUDs can give graphical feedback about the following values:
    
     data_source   	description
     combatAftShBar	aft shield bar including capacitors
     combatCargoBar	how filled the cargo bay of player ship
     combatFwShBar	forward shield bar including capacitors
     combatSEEBar	total durability bar of player ship based on the SEE indicator
     combatSLBar	service level bar of player ship
    
    
    Original HUD display numeric speed over the speed bar (available in HUDSelector).
    This need the following code in the dials section:
    
     {
     	data_source = "combatSpeed";
     	selector = "drawCustomText:";
     //	alert_conditions = 2; //uncomment if you want to see in green alert only
     	alpha = 1.0;
     	height = 13;
     	width = 15;
     	x = 151;
     	y = 87;
     	y_origin = -1;
     },
    
    
    OXP developers can reach all data in worldScripts.combat_MFD.$Data object using the same data_soucre key names, so for speed use $Data.combatSpeed .
    
    The access of worldScript name is slow, so you should get a pointer once in startUp:
    
     this.startUp = function() {
     	this.$combatWS = worldScripts.combat_MFD; //slow access for the pointer, one time only
     }
     this.$displaySpeed = function() {
     	if( this.$combatWS ) //must check CombatMFD existence to prevent an error
     		player.consoleMessage( this.$combatWS.$Data.combatSpeed ); //fast access
     	else log(this.name, "Can not display speed value, CombatMFD OXP is missing");
     }
    
    
    The $DataArray contain all available data_source keys.
    
     this.$combatKeyIsExists = function( key ) {
     	if( this.$combatWS && this.$combatWS.$DataArray.indexOf( key ) > -1 )
     		return true;
     	else return false;
     }
    
    
    The $DataShow can disable the display of any data in the HUD:
    
     this.$disableKey = function(combatKey) {
     	if( this.$combatWS ) this.$combatWS.$DataShow[combatKey] = false;
     }
    
    
    
    Dependencies
    ------------
    
    Oolite 1.79 or later.
    
    Instructions:
    
    Do not unzip the .oxz file, just move into the AddOns folder of your Oolite installation.
    
    License
    -------
    
    This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License version 4.0.
    If you are re-using any piece of this OXP, please let me know by sending an e-mail to norbylite@gmail.com.
    
    
    Changelog
    ---------
     2024.04.18. v1.19 Added closure in $showCombatInfo function.
                       Limited altimeter value to 3 decimal places when less than 1km.
     2024.02.24. v1.18 Small code tweaks.
     2023.10.24. v1.17 Better handling of Shield Cycler (previous version). 
                       Correct player speed value display when FICC in use.
     2023.10.22. v1.16 Hide compass distance for Manual Witchspace Alignment jump target.
     2023.09.26. v1.15 Speed values are taken directly from entity speed property when below the 
                       maxspeed value.
    
     2020.11.23. v1.14 Adds target's mass to MFD.
    
     2020.11.18. v1.13 Shows Shield Cycler mode (Equal, Forward, Aft or Disabled).
    
     2015.10.03. v1.12 Show Auto ECM and Turret Toggler active status if installed.
                       Do not display 0 as bounty and damaged equipments if none.
                       Fixed a bug if both HardShips and IronHide Armour is installed.
    
     2015.05.18. v1.11 Speed formula updated for time forwarding in TorusToSun v1.5.
    
     2015.01.08. v1.10 Small fix of a harmless message in Oolite 1.80, thanks to phkb.
    
     2014.10.20. v1.9  Custom dials of player always calculated, dials of target need the equipment.
                       Altitude custom dial in km added.
    
     2014.10.16. v1.8  HUD dials added, need Oolite 1.81 and support in HUD plist.
    
     2014.10.11. v1.7  Telescope display the newest detected target in the last line.
                       Fuel display counts additional FuelTank, DuplexFuelTank, ExtraFuelTanks and
                       the reserve fuel of Andromeda also.
                       Better energy feedback for ships with a single energy bank.
    
     2014.08.11. v1.6  Damaged, Weak and Derelict display on HUDs with support for this feature.
                       Show FW instead of 8x when TorusToSun use time forwarding at max. speed.
    
     2014.07.24. v1.5  Equipment cost raised to 1000cr due to the MFD pricing thread.
                       Show Torus multiplier before player speed if Torus To Sun is installed.
                       Line length fine tune with hair spaces, thanks to spara.
    
     2014.07.09. v1.4  SEE and One-shot indicators added.
                       Player legal status added.
                       Missile counter with "Hard" flag added.
                       Energy and Shields percents are rounded to 10 for better readability.
                       Target Front/Aft orientation display.
                       Speed display use velocity for Q-Charger.
                       A fix against garbage-collected timer in log.
    
     2014.07.07. v1.3  Informations added in top right and bottom right corners.
                       Speed labels removed to prevent twithcing.
                       A small fix about Telescope far targets.
    
     2014.07.06. v1.2  Show the name of the lastly damaged equipment.
                       Show the target's laser type and range after a shot.
                       Energy and Shields are displayed in percents only.
    
     2014.07.05. v1.1  Must buy Combat MFD as an equipment.
                       Legal status display need Scanner Targeting Enhancement.
                       Show Telescope far target names without km.
                       Can show Empty, Mined and Usable ship status with Towbar.
                       Wormhole target supported with Wormhole Scanner equipment.
    
     2014.07.02. v1.0  More info displayed by Norby.
    
     2014.06.30. v0.1  Some info displayed by Zireael.
    

    Equipment

    Name Visible Cost [deci-credits] Tech-Level
    Combat MFD yes 10000 5+
    HUD no 0 100+
    HUD no 0 100+
    HUD no 0 100+

    Ships

    This expansion declares no ships.

    Models

    This expansion declares no models.

    Scripts

    Path
    Config/script.js
    "use strict";
    this.name = "combat_MFD";
    this.author = "Norby, Zireael";
    this.copyright = "2014 Norby, Zireael";
    this.description = "Makes MFDs more useful by displaying some info";
    this.licence = "CC BY-NC-SA 4.0";
    this.version = "1.17";
    
    this.$DW = 28; //default width of centered textfields in setCustomHUDDial
    this.$ExactNumbers = false; //energy and shield values for debug
    
    this.$combat_MFD = null; //store the final displayed string with player and target data
    this.$Data = {}; //storage of calculated values for external usage
    this.$DataArray = [ //data_source key names for drawCustomText and drawCustomBar HUD dials
        "combatAftSh",    //aft shield numeric value (including capacitors)
        "combatAftShBar",    //aft shield bar including capacitors
        "combatAftShP",    //aft shield percent value (over 100% if upgraded)
        "combatAlt",    //altitude over the nearest planet, moon or sun in km
        "combatAltR",    //altitude over a planet, moon or sun in radius
        "combatCargoBar",    //how filled the cargo bay of player ship
        "combatCredits",    //credits of player
        "combatCTemp",    //cabin temp
        "combatDmgEq",    //name of the lastly damaged equipment
        "combatDEqNum",    //number of the damaged equipments
        "combatEnergy",    //energy of player ship in numeric form
        "combatEnergyP",    //energy of player ship in percent
        "combatFwSh",    //forward shield numeric value (including capacitors)
        "combatFwShBar",    //forward shield bar including capacitors
        "combatFwShP",    //forward shield percent value (over 100% if upgraded)
        "combatFuel",    //remaining fuel in the main tank in ly (min. 0.0, max. 7.0)
        "combatFuelReq",    //required fuel of a declared hyperjump
        "combatFuelRes",    //reserve fuel in extra tanks (integer)
        "combatLegal",    //legal status of player (word)
        "combatLegalNum",    //legal status of player (number)
        "combatNewTelT",    //name of the newest target detected by Telescope
        "combatOneShot",    //letters of One-shot indicator (BCEGHPRU)
        "combatSCTDist",    //distance of space compass target
        "combatSEE",    //letters of SEE indicator about the player ship (CMBSAHE)
        "combatSEEBar",    //total durability bar of player ship based on the SEE indicator
        "combatSEEMax",    //maximum number of ship durability: max of shield+armour+energy
        "combatSEENum",    //number of ship durability: shield+armour+energy
        "combatSLBar",    //service level bar of player ship
        "combatSpeed",    //actual speed of player ship in m/s
        "combatTDist",    //distance of the current target
        "combatTDmg",    //damaged/weak/derelict status of the current target
        "combatTEnergy",    //energy of the current target, use for debug only
        "combatTLaser",    //laser weapon of the current target
        "combatTLegal",    //legal status of the current target, if derelict then Towbar status
        "combatTLRange",    //range of the target's laser weapon
        "combatTMissile",    //missile type fired by the target (Hard, etc.)
        "combatTMissNum",    //number of missiles fired by the target so far
        "combatTName",    //full name of the current target
        "combatTRadius",    //shield radius of the current target
        "combatTSpeed"    //speed of the current target
    ];
    this.$DataShow = {}; //allow or deny display of the mentioned values in CustomHUDDial
    this.$DmgEqs = []; //store damaged eq keys
    this.$InfoTimer = null; //store pointer to timer
    this.$InfoTimer2 = null; //store pointer to timer2
    this.$TelescopeLine = ""; //the 5. line in this MFD is filled by Telescope_1.9.oxz
    this.$WasOk = false; //store the previous state of Equipment
    this.$lastTarget = null;
    this._altimeterDecimals = 3;
    
    this.startUp = function () {
        var h = worldScripts.hudselector;
        if (h && h.$HUDSelectorAddMFD) h.$HUDSelectorAddMFD(this.name);
    
        for (var i = 0; i < this.$DataArray.length; i++) {
            this.$Data[this.$DataArray[i]] = 0; //fill up Data object with key names
            this.$DataShow[this.$DataArray[i]] = true; //allow display all data by default
        }
    
        if (player.ship && player.ship.isValid)
            this.$PlayerPrevPos = player.ship.position;
        else this.$PlayerPrevPos = [0, 0, 0];
        this.$Target = null;
        this.$TargetPrevPos = [0, 0, 0];
        this.$Aws = worldScripts.andromeda;
        this.$Cws = worldScripts["Automatic ECM System"];
        this.$Dws = worldScripts.duplex_fuel_tank;
        this.$Ews = worldScripts["extra_tanks_script.js"];
        this.$Hws = worldScripts.hardships;
        this.$Iws = worldScripts["IronHide Armour Script"];
        this.$Sca = worldScripts.ShipConfiguration_Armour;
        this.$Ows = worldScripts.towbar;
        this.$Rws = worldScripts.torustosun;
        this.$Sws = worldScripts.shieldequalizercapacitors;
        this.$Scs = worldScripts["Shield Cycler"];
        this.$Tws = worldScripts.telescope;
        this.$Uws = worldScripts["Turret Toggler"];
        this.$InfoTimer = null; //store pointer to timer
        this.$InfoTimer2 = null; //store pointer to timer2
    
        this.$DmgEqs = []; //store damaged eq keys
        var eq = player.ship.equipment;
        var i = -1;
        while (eq[++i]) { //skip noname eqs awarded by NumericHUD
            if (eq[i].name.length > 0
                && player.ship.equipmentStatus(eq[i].equipmentKey) == "EQUIPMENT_DAMAGED")
                this.$DmgEqs.push(eq[i].equipmentKey);
        }
    }
    
    this.equipmentDamaged = function (equipment) {
        this.$DmgEqs.push(equipment);
        //    log("combat_MFD", "DmgEqs: "+this.$DmgEqs); //debug
    }
    
    this.shipAttackedWithMissile = function (missile, whom) {
        if (whom && whom.script) {
            if (whom.script.$combat_MFD_missiles && whom.script.$combat_MFD_missiles > 0)
                whom.script.$combat_MFD_missiles++;
            else whom.script.$combat_MFD_missiles = 1;
            if (missile.dataKey == "missile")
                whom.script.$combat_MFD_normalmissile = true;
            else if (missile.dataKey == "ecm-proof-missile")
                whom.script.$combat_MFD_hardmissile = true;
        }
    }
    
    this.shipBeingAttacked = this.shipBeingAttackedUnsuccessfully = function (whom) {
        if (whom && whom.script) whom.script.$combat_MFD_attacked = true; //flag for display Laser type
    }
    
    this.shipTargetAcquired = function (target) {
        this.$showCombatInfo(); //update MFD
    }
    
    this.shipTargetLost = function (losttarget) {
        this.$showCombatInfo(); //update MFD
    }
    
    this.shipWillDockWithStation = function () {
        this.$TelescopeLine = "";
        if (this.$InfoTimer) {
            this.$InfoTimer.stop();
            delete this.$InfoTimer;
        }
        var p = player.ship;
        if (p.setCustomHUDDial) //need Oolite v1.81
            for (var key in this.$Data) p.setCustomHUDDial(key, ""); //clear custom dials
    }
    
    this.shipWillEnterWitchspace = function () {
        this.$TelescopeLine = "";
    }
    
    this.shipWillLaunchFromStation = function () {
        //the timer interval is bound to the multipliers in speed calculations so must change together
        if (!this.$InfoTimer) {
            this.$InfoTimer = new Timer(this, this.$showCombatInfo.bind(this), 0, 0.25);
            if (this.$Sws) { //turn of irritating messages and sounds which is unneccesary with this MFD
                this.$Sws.togglemessages = "OFF";
                this.$Sws.togglesoundfx2 = "OFF";
            }
        }
        //log("CombatMFD",player.ship.equipmentStatus("EQ_COMBATMFD")+" "+this.$InfoTimer);//debug
        this.$InfoTimer2Done = false;
    
        if (this.$ExactNumbers) {//debug
            var s = system.addShips("pirate", 1,
                system.mainStation.position.add(player.ship.heading.multiply(3000)), 100);//debug target
            if (s && s[0]) {
                //s[0].forwardWeapon = null;//setAI("nullAI.plist");
                s[0].bounty = 1;
                s[0].target = player.ship;
                //s[0].displayName = s[0].name + " Target";
            }
        }
    }
    
    this.$showCombatInfo = function $showCombatInfo () {
        var that = $showCombatInfo;
        var _p = (that._p = that._p || player.ship);
        var _decimals = (that._decimals = that._decimals || this._altimeterDecimals);
    
        //var p = player.ship;
        //    log("combat_MFD", "EQ_COMBATMFD: "+p.equipmentStatus("EQ_COMBATMFD")); //debug
        if (!_p || !_p.isValid) return;
        if (this.$WasOk && _p.equipmentStatus("EQ_COMBATMFD") == "EQUIPMENT_DAMAGED") {
            this.$WasOk = false;
            _p.removeEquipment("EQ_DTADER"); //remove text legends in NumericHUD
            _p.removeEquipment("EQ_DTADAM");
            _p.removeEquipment("EQ_DTAWEA");
            _p.setMultiFunctionText(this.name, "Combat MFD is damaged", false);
        }
        var pp = _p.position;
        var target = "\n\n\n\n"; //gather data of player's current target, skip the lines if no target
        var ceq = false;
        //always clear combatT dials for sure (no eq, no target or not applicable due to other reason)
        this.$setData("combatTDist", "");    //distance of the current target
        this.$setData("combatTDmg", "");    //damaged/weak/derelict status of the current target
        this.$setData("combatTEnergy", "");    //energy of the current target, use for debug only
        this.$setData("combatTLaser", "");    //laser weapon of the current target
        this.$setData("combatTLegal", "");    //legal status of the current target, if derelict then Towbar status
        this.$setData("combatTLRange", "");    //range of the target's laser weapon
        this.$setData("combatTMissile", "");    //missile type fired by the target (Hard, etc.)
        this.$setData("combatTMissNum", "");    //number of missiles fired by the target so far
        this.$setData("combatTName", "");    //full name of the current target
        this.$setData("combatTRadius", "");    //shield radius of the current target
        this.$setData("combatTSpeed", "");    //speed of the current target
        if (_p.equipmentStatus("EQ_COMBATMFD") == "EQUIPMENT_OK") {
            var ceq = true;
            this.$WasOk = true;
            var t = _p.target;
            if (t != this.$lastTarget) {
                _p.removeEquipment("EQ_DTADER"); //remove text legends in NumericHUD
                _p.removeEquipment("EQ_DTADAM");
                _p.removeEquipment("EQ_DTAWEA");
                this.$lastTarget = t;
            }
            if (t && t.isValid) {
                var tdn = t.displayName;//must read name before handle telescopemarker
                var st = "";
                if (t.isWormhole) {
                    tdn = "Wormhole";
                    if (_p.equipmentStatus("EQ_WORMHOLE_SCANNER") == "EQUIPMENT_OK") {
                        if (this.$InfoTimer2Done && this.$LastWormhole == t) {
                            //log("CombatMFD",t.expiryTime+" "+clock.seconds+" "+t.arrivalTime);//debug
                            if (t.destination) tdn += " to " + System.systemNameForID(t.destination);
                            if (t.expiryTime) tdn = this.$AlignedText(tdn, "expire in " +
                                Math.round(t.expiryTime - clock.seconds) + " s");
                            if (t.arrivalTime) {
                                st = "Travel Time: " + (Math.round(
                                    (t.arrivalTime - clock.seconds) / 360) / 10) + " h";
                                this.$setData("combatTLegal", st);
                            }
                        } else { //5s delay before show Wormhole info
                            tdn += " scanning...";
                            if (this.$LastWormhole != t) {
                                this.$LastWormhole = t;
                                this.$InfoTimer2Done = false;
                                if (this.$InfoTimer2) {
                                    this.$InfoTimer2.stop();
                                    delete this.$InfoTimer2;
                                }
                                this.$InfoTimer2 = new Timer(this, this.$showWormholeInfo.bind(this), 6);
                            }
                        }
                    }
                }
    
                //telescope far target over scanner range
                var t2 = null;
                if (this.$Tws && t.dataKey == "telescopemarker") {//change the pointer to the real target
                    t2 = this.$Tws.$TelescopeList[this.$Tws.$TelescopeListi - 1];
                    //this.$Tws.$TelescopeTarget is not good: not refreshed when
                    //the target is changed automatically in weapons offline mode
                    if (t2 && t2.isValid) t = t2;
                    var k = tdn.indexOf("km "); //chop the x km from the begin of marker name
                    if (k > -1 && k < 10) tdn = tdn.substr(k + 3);
                }
                this.$setData("combatTName", tdn);
    
                //target speed
                var tsp = 0;
                var ts = "0";
                if (t.maxSpeed > 0) {
                    if (t.speed > t.maxSpeed * t.injectorSpeedFactor || (t.speed == 0 && t.velocity.magnitude() != 0)) { // only do the calc if the speed value is greater than the maxspeed setting
                        if (this.$Target == t) { //need 2 pos. for speed, use velocity for Q-Charger
                            tsp = Math.round(t.velocity.magnitude() / 10) * 10; //stable but can not show FTL drive
                            if (tsp > 31 * t.maxSpeed) { //support for FarPlanets
                                var psp = Math.round(0.1 * t.position.distanceTo(this.$TargetPrevPos)) * 10;
                                if (psp > 1.1 * tsp) tsp = psp;//instable but need to follow position changes
                            }
                        } else {
                            this.$Target = t; //first time save position
                            tsp = Math.round(t.velocity.magnitude() / 10) * 10;
                        }
                        if (tsp > 10000000) tsp = Math.round(tsp / 1000000) + " M";
                        else if (tsp > 1000000) tsp = Math.round(tsp / 1000) + " k";
                        else tsp = Math.round(tsp) + " ";
                        ts = tsp;
                        tsp += "m/s";
                    } else {
                        // otherwise, we can just rely on the standard speed value
                        ts = t.speed.toFixed(0) + " ";
                        tsp = ts + "m/s";
                    }
                    //tsp = "Speed: " + tsp;
                } else tsp = ""; //nothing for stationary objects, zero for others
                this.$setData("combatTSpeed", ts, this.$DW);
                this.$TargetPrevPos = t.position;
    
                //target distance
                var ra = Math.round(t.collisionRadius);
                var di = Math.max(0, Math.round(t.position.distanceTo(pp) - ra - _p.collisionRadius));
                if (di >= 1000000000) di = Math.floor(di / 1000000000) + "Mkm";
                else if (di >= 1000) di = Math.floor(di / 1000) + "km";
                else di += "m";
                this.$setData("combatTDist", di, this.$DW);
                if (ra > 100000) ra = Math.round(ra / 1000) + "km";
                else ra += "m";
    
                //target radius
                var sr = "";
                if (!t.isShip || t.isPlanet || t.isSun || t.isRock) {
                    sr = "Radius: " + ra;
                    this.$setData("combatTRadius", sr);
                    //                this.$setData("combatTDmg", "");
                } else {    //facing shield
                    if (!t2) { //within scanner range only
                        sr = "Shield Radius: ";
                        if (this.$AftShieldFacing(t)) sr = sr + ra + "    Aft";
                        else sr = sr + ra + "   Front";
                        this.$setData("combatTRadius", sr);
                    }
    
                    var d = false;
                    if (t.isDerelict) {
                        d = "Derelict";
                        //                    log(this.name, "Awarding DTADER, target is derelict");
                        _p.awardEquipment("EQ_DTADER"); //show text legend in NumericHUD
                    } else {
                        if (!t2 && t.energy && t.maxEnergy) {
                            if (t.energy < 0.2 * t.maxEnergy) {
                                d = "Weak!";
                                _p.awardEquipment("EQ_DTAWEA");
                            } else if (t.energy < 0.4 * t.maxEnergy) {
                                d = "Damaged!";
                                _p.awardEquipment("EQ_DTADAM");
                            }
                        }
                    }
                    if (d) {
                        sr = this.$AlignedText(sr, d);
                        this.$setData("combatTDmg", d);
                    } //else this.$setData("combatTDmg", "");
                }
    
                //target laser
                var laser = "";
                if (t.script && t.script.$combat_MFD_attacked && t.currentWeapon) {
                    laser = "Laser: " + t.currentWeapon.name;
                    this.$setData("combatTLaser", laser);
                    var rng = "Range: " + Math.round(t.weaponRange / 100) / 10 + "km";
                    this.$setData("combatTLRange", rng);
                    laser = this.$AlignedText(laser, rng);
                } else if (t.forwardWeapon) {
                    laser = "Laser: Unknown";
                    this.$setData("combatTLaser", laser);
                    //                this.$setData("combatTLRange", "");
                }
    
                //target status
                if (!t2 && _p.equipmentStatus("EQ_SCANNER_SHOW_MISSILE_TARGET") == "EQUIPMENT_OK"
                    && (!t.isWormhole && t.isShip && t.isPiloted || t.isDerelict)) {
                    st = "Status:";
                    if (t.isDerelict) {
                        if (this.$Ows && t.script) { //Towbar status
                            if (t.script.$TowbarUsableShip) st += " Usable!";
                            else if (t.script.$TowbarMinedShip) st += " Mined";
                            if (t.script.$TowbarEmptyShip) st += " Empty";
                            else st += " Trap or Treasure";
                        }
                    } else if (t.bounty > 50) st += " Fugitive"; //legal status
                    else if (t.bounty > 0) st += " Offender";
                    else st += " Clean";
                    this.$setData("combatTLegal", st);
    
                    if (this.$ExactNumbers) st += " " + Math.round(t.energy);//for debug
                    this.$setData("combatTEnergy", Math.round(t.energy), this.$DW);
    
                    //                this.$setData("combatTMissNum", 2); this.$setData("combatTMissile", "Normal");//debug
                    //Missiles fired
                    if (t.script) {
                        var m = t.script.$combat_MFD_missiles;
                        if (m > 0) {
                            this.$setData("combatTMissNum", m);
                            var s = "";
                            if (m > 1) s = "s";
                            if (t.script.$combat_MFD_hardmissile) {
                                m += " Hard";
                                this.$setData("combatTMissile", "Hard");
                            } else if (t.script.$combat_MFD_normalmissile) {
                                this.$setData("combatTMissile", "Normal");
                            } else {
                                m += " Unknown type";
                                this.$setData("combatTMissile", "Unknown");
                            }
                            st = this.$AlignedText(st, " Missile" + s + " fired: " + m);
                        }
                    }
                }
    
                //concatenate target info
                target = tdn + "\n" + this.$AlignedText("Distance: " + di + ", Mass: " + (t.mass / 1000).toFixed(1) + "t", tsp) +
                    "\n" + sr + "\n" + laser + "\n" + st;
            }
            else {
                _p.removeEquipment("EQ_DTADER"); //remove text legends in NumericHUD
                _p.removeEquipment("EQ_DTADAM");
                _p.removeEquipment("EQ_DTAWEA");
                this.$Target = null;
            }
        }
    
        //player energy
        this.$setData("combatEnergy", Math.round(_p.energy), this.$DW);
        var ep = "Energy: " + 10 * Math.round(10 * _p.energy / _p.maxEnergy) + "%";
        this.$setData("combatEnergyP", ep, this.$DW);
    
        var eb = Math.floor(_p.maxEnergy / 64);//how many energy banks shown in hud
        var e = Math.ceil(_p.energy / (_p.maxEnergy / eb));
        var en = "";
        var seemax = _p.maxEnergy;
    
        var ihv = 0;
        if (this.$Iws) { //IronHide armour
            var ihs = missionVariables.ironHide_strength;
            seemax += ihs;
            var ihp = missionVariables.ironHide_percentage;
            if (ihs > 0 && ihp > 0) ihv = ihs * (ihp / 100);
            //        log("combat_MFD", "H: "+ihs+" "+ihp+" "+ihv); //debug
        }
        var asmax = _p.maxAftShield;
        var fsmax = _p.maxForwardShield;
        seemax += Math.max(asmax, fsmax);
        if (this.$Sws && //Shield capacitor
            (_p.equipmentStatus("EQ_FORWARD_SHIELD_CAPACITOR") != "EQUIPMENT_UNAVAILABLE"
                || _p.equipmentStatus("EQ_AFT_SHIELD_CAPACITOR") != "EQUIPMENT_UNAVAILABLE")) {
            var max = 64;
            if (this.$Sws.secforwardshieldcapacitormax) {
                max = Math.max(max, this.$Sws.secforwardshieldcapacitormax);
                fsmax += this.$Sws.secforwardshieldcapacitormax;
            } else if (_p.equipmentStatus("EQ_FORWARD_SHIELD_CAPACITOR") == "EQUIPMENT_OK")
                fsmax += 64;
            if (this.$Sws.secaftshieldcapacitormax) {
                max = Math.max(max, this.$Sws.secaftshieldcapacitormax);
                asmax += this.$Sws.secaftshieldcapacitormax;
            } else if (_p.equipmentStatus("EQ_AFT_SHIELD_CAPACITOR") == "EQUIPMENT_OK")
                asmax += 64;
            seemax += max;
            en += this.$SEELetters("C", max,
                this.$Sws.secforwardshieldcapacitor,
                this.$Sws.secaftshieldcapacitor,
                "EQ_FORWARD_SHIELD_CAPACITOR",
                "EQ_AFT_SHIELD_CAPACITOR",
                "EQ_BIGSHCAP", "EQ_BIGSHCAP2", "EQ_BIGSHCAP3");
        }
        if (this.$Hws) { //armours in HardShips OXP
            var hmax = Math.max(this.$Hws.$HardShips_AMax[0][0], //fw
                this.$Hws.$HardShips_AMax[0][1]); //aft
            seemax += hmax;
        }
        if (this.$Sca) { // armour in ShipConfig
            var scmax = Math.max(_p.script._frontArmourStrength, _p.script._aftArmourStrength);
            // lowest max is 100, highest is 400. convert of factors of 128
            scmax *= 1.28;
            seemax += scmax;
        }
        if (e < 2 && _p.maxEnergy > 96) { //not exactly below 64, for example in Fer-De-Lance below 75
            en = "LAST BANK!";
        } else { //"SEE" indicator: letters mean shields, armour and energy for each double banks
            if (_p.equipmentStatus("EQ_NAVAL_SHIELD_BOOSTER") != "EQUIPMENT_UNAVAILABLE")
                en += this.$SEELetters("M", 128,
                    Math.max(0, _p.forwardShield - 256),
                    Math.max(0, _p.aftShield - 256),
                    "EQ_NAVAL_SHIELD_BOOSTER");
            if (_p.equipmentStatus("EQ_SHIELD_BOOSTER") != "EQUIPMENT_UNAVAILABLE")
                en += this.$SEELetters("B", 128,
                    Math.min(128, Math.max(0, _p.forwardShield - 128)),
                    Math.min(128, Math.max(0, _p.aftShield - 128)),
                    "EQ_SHIELD_BOOSTER");
            en += this.$SEELetters("S", 128,
                Math.min(128, _p.forwardShield),
                Math.min(128, _p.aftShield),
                "EQ_BREAKABLE_SHIELD_FORE_SMALL",
                "EQ_BREAKABLE_SHIELD_AFT_SMALL",
                "EQ_BREAKABLE_SHIELD_FORE_MEDIUM",
                "EQ_BREAKABLE_SHIELD_AFT_MEDIUM",
                "EQ_BREAKABLE_SHIELD_FORE_LARGE",
                "EQ_BREAKABLE_SHIELD_AFT_LARGE");
            if (this.$Hws) { //armours in HardShip OXP
                en += this.$SEELetters("A", hmax,
                    this.$Hws.$HardShips_Armour[0][0], //fw armour value
                    this.$Hws.$HardShips_Armour[0][1]);//aft
                //IronHide handled by HardShips
                var ihs = this.$Hws.$HardShips_AMax[0][7];
                var ihv = this.$Hws.$HardShips_Armour[0][7];
            }
            if (ihv > 0) en += this.$SEELetters("H", ihs, ihv, ihv);
            if (this.$Sca) { // armour in ShipConfig
                en += this.$SEELetters("A", scmax, ((_p.script._armourFront / 100) * _p.script._frontArmourStrength) * 1.28, ((_p.script._armourAft / 100) * _p.script._aftArmourStrength) * 1.28);
            }
            en += this.$SEELetters("E", _p.maxEnergy, _p.energy, _p.energy,
                "EQ_BREAKABLE_ENERGY_UNIT_SMALL",
                "EQ_BREAKABLE_ENERGY_UNIT_MEDIUM",
                "EQ_BREAKABLE_ENERGY_UNIT_LARGE");
        }
        //"SEE" indicator is done at this point in en variable
        this.$setData("combatSEE", en);
    
        //count enery+armour+shield banks
        e = _p.energy + Math.min(_p.forwardShield, _p.aftShield);
        if (this.$Sws) e += Math.min(this.$Sws.secforwardshieldcapacitor,
            this.$Sws.secaftshieldcapacitor);
        if (this.$Hws) e += Math.min(this.$Hws.$HardShips_Armour[0][0], //fw
            Math.min(this.$Hws.$HardShips_Armour[0][1],//aft
                Math.min(this.$Hws.$HardShips_Armour[0][2],//port
                    Math.min(this.$Hws.$HardShips_Armour[0][3],//sb
                        Math.min(this.$Hws.$HardShips_Armour[0][4],//top
                            this.$Hws.$HardShips_Armour[0][5])))));//bottom
        e += ihv; //ironhide value, calculated above
        en += " (" + Math.round(e / 64) + ")"; //in banks
        this.$setData("combatSEEMax", seemax, this.$DW);//maximum of exact SEE value
        this.$setData("combatSEENum", Math.round(e), this.$DW);//exact value
        this.$setData("combatSEEBar", e / seemax);//0-1
    
        //player shields
        var fs = Math.round(_p.forwardShield);
        if (this.$Sws) fs += Math.round(this.$Sws.secforwardshieldcapacitor);
        this.$setData("combatFwSh", fs, this.$DW);
        this.$setData("combatFwShBar", fs / fsmax);
        var as = Math.round(_p.aftShield);
        if (this.$Sws) as += Math.round(this.$Sws.secaftshieldcapacitor);
        this.$setData("combatAftSh", as, this.$DW);
        this.$setData("combatAftShBar", as / asmax);
        var fp = this.$ForwardPercent(fs);
        var ap = this.$AftPercent(as);
        var sh = "Shields: " + fp + "%/" + ap + "%";
        var ws_sc = this.$Scs;
        if (ws_sc && (ws_sc.hasOwnProperty("_sc_get_sc_versions") && (ws_sc._sc_get_sc_versions(null)).version > 0) && !ws_sc.$sc_disabled && ws_sc.$sc_settings.version > 0) 
            sh += " " + ws_sc.$sc_const.mode_names[ws_sc.$sc_settings.current_configuration];
        this.$setData("combatFwShP", fp + "%", this.$DW);
        this.$setData("combatAftShP", ap + "%", this.$DW);
    
        if (this.$ExactNumbers) { //for debug
            en += ": " + Math.round(_p.energy);
            sh += " (" + fs + "/" + as + ")";
        }
    
        //Auto ECM and Turret Toggler indicators
        var one = "";
        if (this.$Cws && missionVariables.autoECM == 1
            && _p.equipmentStatus("EQ_AUTOECM") == "EQUIPMENT_OK") one += " ECM ";
        if (this.$Uws && this.$Uws._tt_turret_status == "active"
            && _p.equipmentStatus("EQ_UNI_TURRET") == "EQUIPMENT_OK") one += " Turret ";
        if (one.length > 0) one = " " + one + " ";
    
        //"One-shot" indicator for Energy Bomb and one-shot equipments in HardShips OXP
        if (_p.equipmentStatus("EQ_ENERGY_BOMB") == "EQUIPMENT_OK") one += "B";
        if (this.$Hws) {
            if (_p.equipmentStatus("EQ_ADDITIONAL_CORE_HULL") == "EQUIPMENT_OK") one += "C";
            if (_p.equipmentStatus("EQ_EEG") == "EQUIPMENT_OK") one += "E";
        }
        if (_p.equipmentStatus("EQ_GAL_DRIVE") == "EQUIPMENT_OK") one += "G";
        if (this.$Hws && _p.equipmentStatus("EQ_HTCAT") == "EQUIPMENT_OK") one += "H";
        if (_p.equipmentStatus("EQ_ESCAPE_POD") == "EQUIPMENT_OK") one += "P";
        if (this.$Hws && _p.equipmentStatus("EQ_REG") == "EQUIPMENT_OK") one += "R";
        if (_p.equipmentStatus("EQ_EEU") == "EQUIPMENT_OK") one += "U";
        sh = this.$AlignedText(sh, one);
        this.$setData("combatOneShot", one);
    
        //player legal status
        var ps = "";
        var psw = "Clean";
        if (_p.bounty > 50) {
            psw = "Fugitive";
            ps += psw + " (" + _p.bounty + ")";
            if (_p.bounty < 100) ps += "  ";
        } else if (_p.bounty > 0) {
            psw = "Offender";
            ps += psw + " (" + _p.bounty + ") ";
            if (_p.bounty < 10) ps += "  ";
        } else ps += "Status: " + psw + " ";
        this.$setData("combatLegal", psw);
        var b = Math.round(_p.bounty);
        if (b == 0) b = "";
        this.$setData("combatLegalNum", b, this.$DW);
    
        //player fuel
        var extrafuel = "";
        var ef = 0;
        if (this.$Aws && _p.dataKey == "andromeda-player"
            && this.$Aws.$AndromedaFuelReserve > 0)
            ef += this.$Aws.$AndromedaFuelReserve;
        if (this.$Dws) { //DuplexFuelTank.oxz
            if (_p.equipmentStatus("EQ_DUPLEX_FUEL_TANK_STATE_1") == "EQUIPMENT_OK") ef += 1;
            else if (_p.equipmentStatus("EQ_DUPLEX_FUEL_TANK_STATE_2") == "EQUIPMENT_OK") ef += 2;
            else if (_p.equipmentStatus("EQ_DUPLEX_FUEL_TANK_STATE_3") == "EQUIPMENT_OK") ef += 3;
        }
        if (this.$Ews) { //ExtraFuelTanks-v1.4.1.oxz
            if (_p.equipmentStatus("EQ_RESERVE_TANK") == "EQUIPMENT_OK") ef += 1;
            else if (_p.equipmentStatus("EQ_AUX_TANK") == "EQUIPMENT_OK") ef += 3;
        }
        if (_p.equipmentStatus("EQ_FUELTANK_MINE") == "EQUIPMENT_OK") { //Fuel_Tank_2.2.oxz
            //        log(this.name, _p.missiles); //debug
            for (var i = 0; i < _p.missiles.length; i++) {
                if (_p.missiles[i].equipmentKey == "EQ_FUELTANK_MINE")
                    ef += 3;
            }
        }
        if (ef > 0) extrafuel = "+" + Math.round(ef); //display total reserve fuel in addition
        var f = (_p.fuel).toFixed(1);
        this.$setData("combatFuel", f);
        this.$setData("combatFuelRes", extrafuel);
        ps += " Fuel: " + f + extrafuel + "ly";
    
        var fr = ""; //fuel required for hyperjump
        if (_p.targetSystem)
            fr = (System.infoForSystem(galaxyNumber, system.info.systemID)
                .distanceToSystem(System.infoForSystem(galaxyNumber, _p.targetSystem))
            ).toFixed(1);
        this.$setData("combatFuelReq", fr);
    
        //torus multiplier and player speed
        var tm = "";
        var sp = 0;
        if (_p.speed > _p.maxSpeed * _p.injectorSpeedFactor || _p.script._ficcEngaged) {
            sp = Math.round(_p.velocity.magnitude() / 10) * 10; //stable but can not show FTL drive nor Torus multiplier
            if (this.$Rws && this.$Rws.$TorusToSunBonus > 1) {
                tm = " " + Math.round(this.$Rws.$TorusToSunBonus) + "x";
                sp = Math.round(this.$Rws.$TorusToSunBonus * 3.2 * _p.maxSpeed) * 10;
                if (this.$Rws.$TimeFw > 1) { //time forwarding active
                    tm += Math.round(this.$Rws.$TimeFw);
                    sp *= this.$Rws.$TimeFw;
                }
            } else {
                if (sp > 31 * _p.maxSpeed) { //support for FarPlanets and any other position changer drives
                    var psp = Math.round(0.1 * pp.distanceTo(this.$PlayerPrevPos)) * 10;
                    if (psp > 1.1 * sp) sp = psp;//unstable but need to follow position changes
                }
            }
            if (sp > 10000000) sp = Math.round(sp / 1000000) + " M";
            else if (sp > 1000000) sp = Math.round(sp / 1000) + " k";
        } else {
            sp = _p.speed.toFixed(0);
        }
        this.$setData("combatSpeed", sp, this.$DW);
        if (tm.length > 0) sp += "m/s"; else sp += " m/s";
        this.$PlayerPrevPos = pp;
    
        //damaged equipment if any
        var dm = "";
        var dmg = "";
        var dmgeqs = [];
        //    log("combat_MFD", "DmgEqs: "+this.$DmgEqs); //debug
        //    _p.setEquipmentStatus("EQ_ECM","EQUIPMENT_DAMAGED");//debug
        for (var i = 0; i < this.$DmgEqs.length; i++) //remove fixed ones from the damaged list
            if (_p.equipmentStatus(this.$DmgEqs[i]) == "EQUIPMENT_DAMAGED")
                dmgeqs.push(this.$DmgEqs[i]);
        this.$DmgEqs = dmgeqs;
        //    log("combat_MFD", "DmgEqs: "+this.$DmgEqs); //debug
        var b = ""; //hide 0 length value when no damaged eq
        if (dmgeqs && dmgeqs.length > 0) {  //show the name of the lastly damaged equipment
            b = dmgeqs.length;
            dmg = EquipmentInfo.infoForKey(dmgeqs[dmgeqs.length - 1]).name;
            if (dmgeqs.length > 1) dm = "(+" + (dmgeqs.length - 1) + ")";//+how many other eq damaged
        }
        this.$setData("combatDmgEq", dmg);
        this.$setData("combatDEqNum", b, this.$DW);
        if (dmg.length > 0) dmg = this.$AlignedText("Damaged: " + dmg, dm);
    
        if (ceq) { //if CombatMFD equipment is ok then show the result in MFD
            this.$combat_MFD = this.$AlignedText(ep, en) + "\n" + //1.line
                sh + "\n" + //2.line
                this.$AlignedText(ps, sp + tm) + "\n" + //3.line
                dmg + "\n" + //4.line
                target + "\n" +  //5.-9.lines
                this.$TelescopeLine; //10.line
            _p.setMultiFunctionText(this.name, this.$combat_MFD, false);
        }
    
    
        //extra data sources (not in MFD)
    
        //altimeter
        var c = system.sun; //closest planetary object
        if (c) var d = _p.position.distanceTo(c.position);
        else var d = 100000000000000000000.0; //10^20m for sure
        var l = system.planets;
        var len = l.length;
        for (var i = 0; i < len; i++) { //find the smallest distance
            var s = pp.distanceTo(l[i].position) - l[i].radius;
            if (d > s) {
                d = s;
                c = l[i];
            }
        }
        var alt = ""; //clear if no planetary object
        var altr = "";
        if (c) {
            alt = pp.distanceTo(c) - c.radius - _p.collisionRadius;
            altr = Math.round(100 * alt / c.radius) / 100; //how many radius far
            if (alt >= 1000000000) alt = Math.floor(alt / 1000000000) + "Mkm";
            else if (alt >= 1000) alt = Math.floor(alt / 1000) + "km";
            else alt = alt.toFixed(_decimals) + "m";
        }
        this.$setData("combatAlt", alt, this.$DW);
        this.$setData("combatAltR", altr, this.$DW);
    
        //credits of player
        this.$setData("combatCredits", formatCredits(player.credits, true, true), this.$DW);
    
        //cabin temp
        var ct = Math.max(Math.round(100 * _p.temperature), 23); //prevent flickering below 23
        this.$setData("combatCTemp", ct);
    
        //the newest target detected by Telescope
        this.$setData("combatNewTelT", this.$TelescopeLine);
    
        //distance of space compass target
        var di = "";
        var c = _p.compassTarget;
        if (c && c.isValid && c.displayName != "Jump Marker") di = Math.max(0, Math.round(pp.distanceTo(c) - c.collisionRadius - _p.collisionRadius));
        if (di >= 1000000000) di = Math.floor(di / 1000000000) + "Mkm";
        else if (di >= 1000) di = Math.floor(di / 1000) + "km";
        else if (c && c.isValid && c.displayName != "Jump Marker") di += "m";
        this.$setData("combatSCTDist", di, this.$DW);
    
        //how filled the cargo bay of player ship
        this.$setData("combatCargoBar", _p.cargoSpaceUsed / _p.cargoSpaceCapacity);
    
        //service level bar of player ship
        this.$setData("combatSLBar", (_p.serviceLevel - 75) / 25);
    }
    
    this.$ForwardPercent = function (current) {
        var max = 128;//player.ship.maxForwardShield;
        var result = 10 * Math.round(10 * current / max);
        return result;
    }
    
    this.$AftPercent = function (current) {
        var max = 128;//player.ship.maxAftShield;
        var result = 10 * Math.round(10 * current / max);
        return result;
    }
    
    this.$showWormholeInfo = function () { //6s delay before show Wormhole info
        this.$InfoTimer2Done = true;
        if (this.$InfoTimer2) {
            this.$InfoTimer2.stop();
            delete this.$InfoTimer2;
        }
    }
    
    this.$AlignedText = function (left, right) { //insert as many spaces between as fill the line
        var width = 14.2;
        var space = " ";
        left += space;
        var t = left + right;
        while (defaultFont.measureString(t) < width) {
            left += space;
            t = left + right;
        }
        //fine tune with hair spaces - from spara's marketObserver
        var hairSpace = String.fromCharCode(31);
        while (defaultFont.measureString(t + hairSpace) < width) {
            left += hairSpace;
            t = left + right;
        }
        return (t);
    }
    
    this.$CenteredText = function (txt, width) { //insert spaces before text to align to center in width
        var t = "" + txt; //force to srting, else txt.length is undefined for numbers
        var w = width / 2;
        //    log("combat_MFD", "CT1 "+txt+" "+t.length+" "+w); //debug
        while (t && t.length < w) { //for fixed with font in setCustomHUDDial
            t = " " + t;
        }
        return (t);
    }
    
    this.$RightText = function (txt, width) { //insert spaces before text to align to right in width
        var t = "" + txt; //force to srting, else txt.length is undefined for numbers
        while (t && t.length < width) { //for fixed with font in setCustomHUDDial
            t = " " + t;
        }
        return (t);
    }
    
    this.$SEELetters = function (letter, max, fw, aft, eq1, eq2, eq3, eq4, eq5, eq6) {
        var s = 0; //smaller shield side
        var l = 0; //larger shield side
        var p = player.ship;
        if (eq1 && p.equipmentStatus(eq1) == "EQUIPMENT_DAMAGED" ||
            eq2 && p.equipmentStatus(eq2) == "EQUIPMENT_DAMAGED" ||
            eq3 && p.equipmentStatus(eq3) == "EQUIPMENT_DAMAGED" ||
            eq4 && p.equipmentStatus(eq4) == "EQUIPMENT_DAMAGED" ||
            eq5 && p.equipmentStatus(eq5) == "EQUIPMENT_DAMAGED" ||
            eq6 && p.equipmentStatus(eq6) == "EQUIPMENT_DAMAGED")
            letter = "_"; //damaged
        s = Math.round(Math.min(fw, aft) / 128);
        l = Math.round(Math.max(fw, aft) / 128);
        var r = "";
        var t = Math.round(max / 128); //total letters
        for (var i = 0; i < t; i++)
            if (letter == "_") r += letter; //damaged equipment
            else if (i < t - l) r += "-"; //empty bank
            else if (i < t - s) r += letter.toLowerCase(); //one side of shield is up only
            else r += letter; //both forward and aft shield is up
            //log("combat_MFD", letter+": "+max+" "+fw+" "+aft+" "+i+". "+(t-s)+" "+(t-l)+" "+t+" "+r); //debug
        return (r);
    }
    
    this.$AftShieldFacing = function (ship) { //determine which shield of the target facing to player ship
        if (ship.vectorForward.angleTo(ship.position.subtract(player.ship.position)) <= Math.PI / 2)
            return (true);
        return (false);
    }
    
    this.$combatKeyIsExists = function (key) {
        if (this.$DataArray.indexOf(key) > -1) return true;
        else return false;
    }
    
    this.$disableKey = function (combatKey) {
        this.$DataShow[combatKey] = false;
    }
    
    this.$enableKey = function (combatKey) {
        this.$DataShow[combatKey] = true;
    }
    
    this.$setData = function (key, v, align) { //align=0:left, >0:center in this width, <0:right
        this.$Data[key] = v; //save for external access
        var p = player.ship;
        if (p.setCustomHUDDial && this.$DataShow[key]) {
            if (align > 0) v = this.$CenteredText(v, align); //centered in an align wide box
            else if (align < 0) v = this.$RightText(v, -align); //right in a -align wide box
            p.setCustomHUDDial(key, v);
        }
    }