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

Expansion Navigation Beacons MFD

Content

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Lists all visible navigation beacons in an MFD, along with distances. Lists all visible navigation beacons in an MFD, along with distances.
Identifier oolite.oxp.phkb.NavigationBeaconsMFD oolite.oxp.phkb.NavigationBeaconsMFD
Title Navigation Beacons MFD Navigation Beacons MFD
Category HUDs MFDs HUDs MFDs
Author phkb phkb
Version 1.1 1.1
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Information URL https://wiki.alioth.net/index.php/Navigation_Beacons_MFD n/a
Download URL https://wiki.alioth.net/img_auth.php/3/3c/NavigationBeaconsMFD.oxz n/a
License CC-BY-NC-SA 4.0 CC-BY-NC-SA 4.0
File Size n/a
Upload date 1716770288

Documentation

Also read http://wiki.alioth.net/index.php/Navigation%20Beacons%20MFD

readme.txt

Navigation Beacons MFD
by phkb

Overview
========
This mod lists all navigation beacons visible to the player in an MFD, along with their distance from the player. The beacons are sorted in order of distance, with the closest ones at the top of the list. Whatever target the player has with their space compass will be indicated with a "•" character, if it is one of the top 9 beacons.

Settings
========
There are two settings available via Library Config.

Flag - Ship/Station beacons only: When set to "true", the only navigation beacons the MFD will display are ship or station beacons. Other stellar bodies (planets, moons, etc), will be ignored.

Value - Display units: This value allows the units used in the MFD to be changed. The available options are:
    0 = OU 
    1 = km (default)
    2 = m
    3 = CZ (Cavezzi)

Equipment
=========
The Navigation Beacons MFD costs 50cr, and can be purchased at at TL8 system. The Advanced Space Compass is a requirement.

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/

Version History
===============
1.1
- Tweak to prevent Telescope visual target VEs and Escort Deck ships from appearing in beacon list.

1.0
- Initial release.

Equipment

Name Visible Cost [deci-credits] Tech-Level
Navigation Beacons MFD yes 500 8+

Ships

This expansion declares no ships.

Models

This expansion declares no models.

Scripts

Path
Config/script.js
"use strict";
this.name = "NavBeaconsMFD";
this.author = "phkb";
this.copyright = "2023 phkb";
this.description = "Lists all nav beacons in the system, along with distances to them.";
this.license = "CC BY-NC-SA 4.0";

this._hairSpace = String.fromCharCode(31);
this._hairSpaceLength = defaultFont.measureString(this._hairSpace);
this._ellip = "…";
this._bullet = "•";
this._bulletSpace = "";

this._timer = null;
this._distTimer = null;
this._beaconShips = [];
this._final = [];
this._finalID = [];
this._current = 0;
this._rightCol = defaultFont.measureString("9999 km") + 0.1;
this._leftCol = 14.2 - this._rightCol;
this._shipsOnly = false;

this._unitSetting = 1;
//distance unit to show in mfd.
this._distUnits = ["OU", "km", "m", "CZ"];
//basis in meters for one distUnit.
//for kiloometers, set to 1000
//for OUs, set to 905520, which is roughly the distance of planet and sun in Lave in an unmodified game.
this._unitFactor = [905520, 1000, 1, 2.08641];
this._unitRounding = [4, 0, 0, 0];

this._libSettings = {
	Name: this.name, Display: "Settings", Alias: "Navigation Beacons MFD", Alive: "_libSettings",
    Bool: {
        B0: { Name:"_shipsOnly", Def: false, Desc:"Ship/Station beacons only"},
        Info: "0 = Display beacons from ships and stations only"
    },
	SInt: {
		S0: { Name: "_unitSetting", Def: 1, Min: 0, Max: 3, Desc: "Display units" },
		Info: "0 = OU, 1 = km, 2 = m, 3 = CZ (Cavezzi)"
	},
};

//-------------------------------------------------------------------------------------------------------------
this.startUp = function() {
	if (missionVariables.NavigationBeaconsMFD_Units) {
		this._unitSetting = parseInt(missionVariables.NavigationBeaconsMFD_Units);
	}
    if (missionVariables.NavigationBeaconsMFD_ShipsOnly) {
        this._shipsOnly = (missionVariables.NavigationBeaconsMFD_ShipsOnly == "yes" ? true : false);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
    var measure = defaultFont.measureString;
	// register our settings, if Lib_Config is present
	if (worldScripts.Lib_Config) worldScripts.Lib_Config._registerSet(this._libSettings);

    this._bulletWidth = defaultFont.measureString(this._bullet);
    while (measure(this._bulletSpace) < this._bulletWidth) {
        this._bulletSpace += this._hairSpace;
    }
}

//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function () {
	missionVariables.NavigationBeaconsMFD_Units = this._unitSetting;
    missionVariables.NavigationBeaconsMFD_ShipsOnly = (this._shipsOnly == true ? "yes" : "no");
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillLaunchFromStation = function() {
    // recalc the left/right col widths, based on unit setting
    this._rightCol = defaultFont.measureString("9999" + (this._unitSetting > 1 ? "99" : "") + " " + this._unitFactor[this._unitSetting]) + 0.1;
    this._leftCol = 14.2 - this._rightCol;
}

//-------------------------------------------------------------------------------------------------------------
this.shipExitedWitchspace = this.shipLaunchedFromStation = function() {
    if (!player.ship.hasEquipmentProviding("EQ_ADVANCED_COMPASS")) return;
    if (player.ship.equipmentStatus("EQ_NAVBEACONS_MFD") != "EQUIPMENT_OK") return;
    if (!player.ship.isInSpace) return;
    // do a quick update to put "scanning" on the display
    this._final.length = 0;
    this._beaconShips.length = 0;
    this.$updateMFD(true);
    // first run after 2 seconds, rerun every 5 seconds
    this._timer = new Timer(this, this.$collateInfo.bind(this), 2, 5); 
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillEnterWitchspace = function() {
    this.$stopTimers();
    if (player.ship.equipmentStatus("EQ_NAVBEACONS_MFD") == "EQUIPMENT_OK")
        player.ship.setMultiFunctionText("NavigationBeaconsMFD", "NAVIGATION BEACONS:\n\n\nInitialising...\n", false);
}

//-------------------------------------------------------------------------------------------------------------
this.shipDockedWithStation = this.shipDied = function() {
    this.$stopTimers()
    // switch the display to "Scanning" now, so when we next launch we don't get an old display showing up first before the timer clears it
    this.$updateMFD(true); 
}

//-------------------------------------------------------------------------------------------------------------
this.equipmentDamaged = function(equipKey) {
    if (equipKey == "EQ_NAVBEACONS_MFD" || equipKey == "EQ_ADVANCED_COMPASS") {
        this.$updateMFD();
        this.$stopTimers();
    }
}

//-------------------------------------------------------------------------------------------------------------
this.equipmentRepaired = function(equipKey) {
    var p = player.ship;
    if (player.ship.equipmentStatus("EQ_NAVBEACONS_MFD") != "EQUIPMENT_DAMAGED" && p.hasEquipmentProviding("EQ_ADVANCED_COMPASS")) {
        this.shipExitedWitchspace();
    } else {
        this.$updateMFD();
    }
}

//-------------------------------------------------------------------------------------------------------------
this.compassTargetChanged = function(whom, mode) {
    this.$updateMFD();
}

//-------------------------------------------------------------------------------------------------------------
this.$stopTimers = function() {
    if (this._timer && this._timer.isRunning) this._timer.stop();
    if (this._distTimer && this._distTimer.isRunning) this._distTimer.stop();    
}

//-------------------------------------------------------------------------------------------------------------
this.$collateInfo = function $collateInfo() {
    this._beaconShips = this.$findShipsWithBeacons();
    var i = this._beaconShips.length;
    while (i--) {
        this._beaconShips[i]._nb_ID = i;
    }
    if (this._distTimer && this._distTimer.isRunning) return; 
    this._distTimer = new Timer(this, this.$calcDistances.bind(this), 0.25, 1.5);
}

//-------------------------------------------------------------------------------------------------------------
this.$calcDistances = function $calcDistances() {
    var that = $calcDistances;
    var measure = (that.measure = that.measure || defaultFont.measureString);
    var _p = (that._p = that._p || player.ship);
    this._final.length = 0;
    this._finalID.length = 0;
    if (!_p || !_p.isValid || !_p.position) return;
    var i = this._beaconShips.length;
    if (i > 9) i = 9;
    while (i--) {
        var shp = this._beaconShips[i];
        var check = ~~((_p.position.distanceTo(shp) - shp.collisionRadius - _p.collisionRadius) + 0.5);
        var dist = check > 0 ? check : 0;
        var nm = (shp.beaconLabel != "" && shp.beaconLabel != null ? shp.beaconLabel : shp.displayName);
        this._finalID.unshift(shp._nb_ID);
        var distOut = " " + (dist / this._unitFactor[this._unitSetting]).toFixed(this._unitRounding[this._unitSetting]) + " " + this._distUnits[this._unitSetting] + " ";
        var width = measure(distOut) + 0.5;
        this._final.unshift(this.$padText(this._bullet + nm, 15 - width) + distOut);
    }
    this.$updateMFD();
}

//-------------------------------------------------------------------------------------------------------------
this.$findShipsWithBeacons = function() {
	function _beacons(entity) {
		return !(entity.isPlayer) && 
            (this._shipsOnly == false || entity.isShip) && 
            (entity.beaconCode != "" && entity.beaconCode != null) && 
            (entity.displayName != "Jump Marker") &&
            (entity.AI != "EscortDeck_AI.plist") &&
            (entity.isVisualEffect == false || entity.dataKey == "almanacCompass_planet" || entity.dataKey == "almanacCompass_moon");
	}
	return system.filteredEntities(this, _beacons, player.ship);
}

//-------------------------------------------------------------------------------------------------------------
this.$updateMFD = function(init) {
    var p = player.ship
    if (!p || !p.isValid) return;
    var output = "NAVIGATION BEACONS:\n";
    if (p.equipmentStatus("EQ_NAVBEACONS_MFD") == "EQUIPMENT_DAMAGED") {
        output += "\n\nEquipment damaged.\n";
    } else if (!p.hasEquipmentProviding("EQ_ADVANCED_COMPASS")) {
        output += "\n\nNo data. ASC not available.";
    } else {
        if (init == true) {
            output += "\n\nScanning...\n";
        } else {
            var max = this._final.length;
            if (max == 0) {
                output += "\n\nNo beacons in range\n";
            } else {
                if (max > 9) max = 9
                var ct = p.compassTarget;
                if (ct) {
                    //var ctn = (ct.beaconLabel != "" && ct.beaconLabel != null ? ct.beaconLabel : ct.displayName)
                    var ctn = ct._nb_ID;
                    for (var i = 0; i < max; i++) {
                        var txt = this._final[i];
                        if (ctn == this._finalID[i]) {
                            txt = this._bullet + txt.replace(this._bullet, "");
                        } else {
                            txt = txt.replace(this._bullet, this._bulletSpace);
                        }
                        output += txt + "\n";
                    }
                }
            }
        }
    }
    p.setMultiFunctionText("NavigationBeaconsMFD", output, false);
}

//-------------------------------------------------------------------------------------------------------------
// appends space to currentText to the specified length in 'em'
this.$padText = function $padText(currentText, desiredLength, leftSwitch, centreSwitch) {
    var that = $padText;
    var hairSpace = (that.hairSpace = that.hairSpace || this._hairSpace);
    var ellip = (that.ellip = that.ellip || this._ellip);
    var hairSpaceLength = (that.hairSpaceLength = that.hairSpaceLength || this._hairSpaceLength);
    var measure = (that.measure = that.measure || defaultFont.measureString);

    if (currentText == null) currentText = "";
    var currentLength = measure(currentText.replace(/%%/g, "%"));
    // calculate number needed to fill remaining length
    var padsNeeded = ~~((desiredLength - currentLength) / hairSpaceLength);
    if (padsNeeded < 1) {
        // text is too long for column, so start pulling characters off
        var tmp = currentText;
        do {
            tmp = tmp.substring(0, tmp.length - 2) + ellip;
            if (tmp === ellip) break;
        } while (measure(tmp.replace(/%%/g, "%")) > desiredLength);
        currentLength = measure(tmp.replace(/%%/g, "%"));
        padsNeeded = ~~((desiredLength - currentLength) / hairSpaceLength);
        currentText = tmp;
    }
    // quick way of generating a repeated string of that number
    if (!leftSwitch || leftSwitch === false) {
        if (!centreSwitch || centreSwitch === false) {
            return currentText + new Array(padsNeeded).join(hairSpace);
        } else {
            return currentText + new Array(parseInt(padsNeeded / 2)).join(hairSpace);
        }
    } else {
        if (!centreSwitch || centreSwitch === false) {
            return new Array(padsNeeded).join(hairSpace) + currentText;
        } else {
            return new Array(parseInt(padsNeeded / 2)).join(hairSpace) + currentText;
        }
    }
}