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

Expansion Navigation MFD

Content

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Display navigational information in an MFD. Information includes data from hyperdrive system and space compass. Display navigational information in an MFD. Information includes data from hyperdrive system and space compass.
Identifier oolite.oxp.spara.navigation_mfd oolite.oxp.spara.navigation_mfd
Title Navigation MFD Navigation MFD
Category HUDs HUDs
Author Mika Spara Mika Spara
Version 1.9.2 1.9.2
Tags mfd mfd
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Information URL https://wiki.alioth.net/index.php/Navigation_MFD n/a
Download URL https://wiki.alioth.net/img_auth.php/9/9a/Navigation_MFD_1.9.2.oxz n/a
License CC-BY-NC-SA 4.0 CC-BY-NC-SA 4.0
File Size n/a
Upload date 1700567193

Documentation

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

navigation_mfd_readme_&_license.txt

Navi MFD OXP ver 1.9.1 (18.1.2018)

Author: spara (Mika SpÄra)

_Overview_

Display navigational information in an MFD. Information includes data from hyperdrive system and space compass. Costs 650 credits.

_Requirements_

* Oolite 1.82

_Installing_

Install the OXP by copying navigation_mdf.oxz to your AddOns-folder.

_Credits_

------

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/

Equipment

Name Visible Cost [deci-credits] Tech-Level
Navigation MFD yes 6500 7+

Ships

This expansion declares no ships.

Models

This expansion declares no models.

Scripts

Path
Config/script.js
"use strict";
this.name = "navi_mfd";
this.author = "spara";
this.copyright = "2015 Spara";
this.description = "Show navigational info in an MFD";
this.licence = "CC BY-NC-SA 4.0";

//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.$ostronomicalUnits = [905520, 1000, 1, 2.08641];
this.$rounding = [6, 3, 0, 0];
this.$unitSetting = 0;
this._cancelled = false;

this.libSettings = {
	Name: this.name, Display: "Settings", Alias: "Navigation MFD", Alive: "libSettings",
	SInt: {
		S0: { Name: "$unitSetting", Def: 0, Min: 0, Max: 3, Desc: "Display units" },
		Info: "0 = OU, 1 = km, 2 = m, 3 = CZ (Cavezzi)"
	},
};

this.startUp = function () {
	this.$interval = 1; //Refresh frequency. (in secs)

	if (missionVariables.NavigationMFD_Units) {
		this.$unitSetting = parseInt(missionVariables.NavigationMFD_Units);
	}
	//timer for display update
	this.$distanceTimer = new Timer(this, this.$updateDistance, 0, this.$interval);
	this.$distanceTimer.stop();

	//storage variable
	this.$targetName = "unknown";

	//symbols
	this.$govs = new Array();
	for (var i = 0; i < 8; i++) {
		this.$govs.push(String.fromCharCode(i));
	}
	this.$ecos = new Array();
	for (i = 0; i < 8; i++) {
		this.$ecos.push(String.fromCharCode(23 - i));
	}
	this.$nova = String.fromCharCode(215) + " " + String.fromCharCode(215) + " ";

	//for route planner to work in interstellar space too	
	this.$savedSystem = system.ID;

	//bgs voice countdown timer differs from core countdown
	//hyper countdown is synced to bgs or ctz if present,
	//otherwise to core countdown
	if (worldScripts["BGS-M"] || worldScripts["countdown_to_zero"]) this.$BGS = true;

	//docking clearance status for stations
	this.$clearanceStation = null;
}

this.startUpComplete = function () {
	// register our settings, if Lib_Config is present
	if (worldScripts.Lib_Config) worldScripts.Lib_Config._registerSet(this.libSettings);
}

this.playerWillSaveGame = function () {
	missionVariables.NavigationMFD_Units = this.$unitSetting;
}

//start display timer when launching and entering system
this.shipWillLaunchFromStation = this.shipExitedWitchspace = function () {
	this._cancelled = 0;
	//for route planner to work in interstellar space too
	if (!system.isInterstellarSpace) this.$savedSystem = system.ID;
	this.$setHyperMessage();
	this.$distanceTimer.start();
}

//switch to countdown synced timer
this.playerStartedJumpCountdown = function (type, seconds) {
	if (this._cancelled == true) {
		this._cancelled = false;
		return;
	}
	if (type === "standard") {
		this.$distanceTimer.stop();
		this.$countdown = seconds;
		this.$hyperTimer = new Timer(this, this._hyperDriveCountdown, 0, 1);
	}
}

//switch back to basic timer
this.playerCancelledJumpCountdown = this.playerJumpFailed = function () {
	if (!this.$countdown) this._cancelled = true;
	if (this.$hyperTimer) {
		this.$hyperTimer.stop();
		delete this.$hyperTimer;
		delete this.$countdown;
	}
	this.$distanceTimer.start();
}

//update display once and stop countdown timer
this.shipWillEnterWitchspace = function () {
	//triggers "hyperjump in progress" message
	if (this.$hyperTimer) {
		this.$countdown = -1;
		this.$updateDistance();
		this.$hyperTimer.stop();
		delete this.$hyperTimer;
		delete this.$countdown;
	}
}

//update hyperspace display data when switching from map
this.guiScreenChanged = function (to, from) {
	if (from === "GUI_SCREEN_SHORT_RANGE_CHART" || from === "GUI_SCREEN_LONG_RANGE_CHART") {
		this.$setHyperMessage();
		this.$updateDistance();
	}
}

//update compass target data and start timer on launch
this.shipLaunchedFromStation = function () {
	this.compassTargetChanged(player.ship.compassTarget, player.ship.compassMode);
	this.$distanceTimer.start();
}

//stop timers when docking
this.shipWillDockWithStation = function () {
	//yes, it's possible to dock while hyperspace countdown is running
	if (this.$hyperTimer) {
		this.$hyperTimer.stop();
		delete this.$hyperTimer;
		delete this.$countdown;
		this.$setHyperMessage();
		this.$updateDistance();
	}
	this.$distanceTimer.stop();
}

//hyper countdown timer function
this._hyperDriveCountdown = function _hyperDriveCountdown() {
	this.$updateDistance();
	this.$countdown--;
}

//update mfd
this.$updateDistance = function $updateDistance() {
	if (player.ship.equipmentStatus("EQ_NAVIGATION_MFD") === "EQUIPMENT_OK") {
		player.ship.setMultiFunctionText("navi_mfd", this.$message());
	}
	else player.ship.setMultiFunctionText("navi_mfd", null);
}

//compose output
this.$message = function () {
	//hyperspace data is updated only when it changes
	var message = this.$hyperMessage;
	message += "Hyperdrive Status:\n" + this.$status();
	var target = player.ship.compassTarget;
	//valid target case
	if (target) {
		if (target.isStation) {
			var stationStatus = this._stationStatus(target);
		}
		else var stationStatus = "";
		message += this._paddedHyperInfo("Space Compass:") + stationStatus + "\n" + this.$truncate("  " + this.$targetName, 14) + "\n";
		if (this.$targetName != "Jump Marker") {
			var distInM = player.ship.position.distanceTo(target) - target.collisionRadius;
			if (distInM < 0) distInM = 0;
			var dist = distInM / this.$ostronomicalUnits[this.$unitSetting];
			message += "Distance: " + dist.toFixed(this.$rounding[this.$unitSetting]) + " " + this.$distUnits[this.$unitSetting] + "\n";
			message += "Estimated Travel Time: ";
			var vPtoT = target.position.subtract(player.ship.position); //player-target vector
			var dotVH = player.ship.velocity.dot(vPtoT); //dot product between velocity and heading
			if (dotVH > 0.1) {//check heading
				var vVelPtoT = vPtoT.multiply(dotVH / (vPtoT.dot(vPtoT))); //velocity vector projection on player-target vector    
				var timeToTarget = distInM / vVelPtoT.magnitude();
				var hours = Math.floor(timeToTarget / 3600);
				var mins = Math.floor((timeToTarget - 3600 * hours) / 60);
				var secs = Math.floor(timeToTarget - hours * 3600 - mins * 60);
				if (hours < 10)
					hours = "0" + hours;
				if (mins < 10)
					mins = "0" + mins;
				if (secs < 10)
					secs = "0" + secs;
				message += hours + ":" + mins + ":" + secs;
			}
			else message = message + "**:**:**";
		} else {
			message += "Distance: -\nEstimated Travel Time: **:**:**";
		}
	}
	//null case
	else {
		message += "Space Compass Target:\n  -\n";
		message += "Distance: -\n";
		message += "Estimated Travel Time: **:**:**";
	}
	return message;
}

//remember the station which clearance was asked from
this.playerRequestedDockingClearance = function () {
	this.$clearanceStation = player.ship.target;
}

//the docking status of stations
this._stationStatus = function (whom) {
	if (whom.requiresDockingClearance) {
		if (whom === this.$clearanceStation) {
			switch (player.dockingClearanceStatus) {
				case "DOCKING_CLEARANCE_STATUS_REQUESTED":
					return "Dock: Hold";
					break;
				case "DOCKING_CLEARANCE_STATUS_GRANTED":
					return "Dock: Granted";
					break;
				case "DOCKING_CLEARANCE_STATUS_TIMING_OUT":
					return "Dock: Expiring";
					break;
			}
		}
		return "Dock: Request";
	}
	return "Dock: Free";
}

//compose hyperspace output
this.$setHyperMessage = function () {

	// nextSystem new in for Oolite 1.86
	if (player.ship.hasOwnProperty("nextSystem") === true) {
		var hyperSystemObj = System.infoForSystem(galaxyNumber, player.ship.nextSystem);
	} else {
		var hyperSystemObj = System.infoForSystem(galaxyNumber, player.ship.targetSystem);

		//first condition for compatibility with older versions of Oolite
		if (player.ship.routeMode && player.ship.targetSystem !== system.ID) {

			var mode = player.ship.routeMode;
			if (mode === "OPTIMIZED_BY_JUMPS" || mode === "OPTIMIZED_BY_TIME") {
				// cope with the situation of being in interstellar space and then selecting your originating system as the target
				if (player.ship.targetSystem === this.$savedSystem && system.isInterstellarSpace === true) {
					hyperSystemObj = System.infoForSystem(galaxyNumber, this.$savedSystem);
				} else {
					var routeToNextSyst = System.infoForSystem(galaxyNumber, this.$savedSystem).routeToSystem(hyperSystemObj, mode);
					if (routeToNextSyst && routeToNextSyst.route.length >= 1 && routeToNextSyst.route[1]) {
						hyperSystemObj = System.infoForSystem(galaxyNumber, routeToNextSyst.route[1]);
					}
					//if no route can be plotted, set hyperSystemObj to current system to nullify target from printout
					else hyperSystemObj = system.info;
				}
			}
		}
	}
	var hyperSystem = hyperSystemObj.name;

	//in interstellar space the distance calculation is done manually.
	if (system.isInterstellarSpace) {
		var s = player.ship.galaxyCoordinatesInLY;
		var t = hyperSystemObj.coordinates;
		//this is officially weird
		this.$hyperDistance = 0.4 * Math.floor(2.5 * Math.sqrt(Math.pow(s[0] - t[0], 2) + Math.pow(s[1] - t[1], 2)));
	}
	else {
		this.$hyperDistance = hyperSystemObj.distanceToSystem(system.info);
	}
	//default to no target set
	var hyperTime = "**:**:**\n";
	var hyperDistance = "-";
	if (!hyperSystemObj.sun_gone_nova) {
		var planetDistance = ((hyperSystemObj.planet_distance - hyperSystemObj.radius * 10) / this.$ostronomicalUnits[this.$unitSetting]).toFixed(this.$rounding[this.$unitSetting]);// + " " + this.$distUnits[this.$unitSetting];
	}
	else var planetDistance = "-";

	if (hyperSystemObj.systemID != -1) {
		var W2P = Vector3D([0, 0, hyperSystemObj.planet_distance]);
		if (hyperSystemObj.sun_distance_modifier) {
			var P2SDist = hyperSystemObj.sun_distance_modifier * hyperSystemObj.radius * 10;
		}
		else if (hyperSystemObj.sun_distance_multiplier) {
			var P2SDist = hyperSystemObj.sun_distance * hyperSystemObj.sun_distance_multiplier;
		}
		else var P2SDist = hyperSystemObj.sun_distance;
		var P2S = Vector3D(hyperSystemObj.sun_vector.split(" ")).multiply(-1 * P2SDist);
		var sunDistance = ((W2P.add(P2S).magnitude() - hyperSystemObj.sun_radius) / this.$ostronomicalUnits[this.$unitSetting]).toFixed(this.$rounding[this.$unitSetting]) + " (" + this.$distUnits[this.$unitSetting] + ")";
	}

	//target system set
	if (hyperSystem !== system.name) {
		if (this.$hyperDistance < 0.1) var hyperDistance = "0.1";
		else var hyperDistance = this.$hyperDistance.toFixed(1);
		hyperDistance += " ly";

		//calculate time for valid cases only
		if (player.ship.hasHyperspaceMotor && this.$hyperDistance <= 7) {
			var hyperTime = this.$hyperDistance * this.$hyperDistance;//in hours
			var hours = Math.floor(hyperTime);
			var mins = Math.floor((hyperTime - hours) * 60);
			var secs = Math.floor((hyperTime - hours - mins / 60) * 3600);
			if (hours < 10) hours = "0" + hours;
			if (mins < 10) mins = "0" + mins;
			if (secs < 10) secs = "0" + secs;
			hyperTime = hours + ":" + mins + ":" + secs + "\n";
		}
	}

	if (system.isInterstellarSpace) {
		this.$hyperMessage = "Present System: Interstellar space\n";
	}
	else {
		if (!system.sun.hasGoneNova) {
			this.$hyperMessage = this._hyperSystemLine("Present System:", system.name + " (TL" + (system.techLevel + 1) + ")", this.$ecos[system.economy] + this.$govs[system.government]) + "\n";
		}
		else {
			this.$hyperMessage = this._hyperSystemLine("Present System:", system.name + " (TL0)", this.$nova) + "\n";
		}
	}
	if (hyperSystem !== system.name) {
		if (!hyperSystemObj.sun_gone_nova) {
			this.$hyperMessage += this._hyperSystemLine("Target System:", hyperSystem + " (TL" + (hyperSystemObj.techlevel + 1) + ")", this.$ecos[hyperSystemObj.economy] + this.$govs[hyperSystemObj.government]) + "\n";
		}
		else {
			this.$hyperMessage += this._hyperSystemLine("Target System:", hyperSystem + " (TL0)", this.$nova) + "\n";
		}
	}
	else this.$hyperMessage += "Target System: " + hyperSystem + "\n";

	//this.$hyperMessage = this.$hyperMessage + "Estimated Travel Time: " + hyperTime;
	this.$hyperMessage += this._paddedHyperInfo("  Distance: " + hyperDistance);
	this.$hyperMessage += "Time: " + hyperTime;
	//this.$hyperMessage += "  Main Lane: " + planetDistance + "\n";
	this.$hyperMessage += this._paddedHyperInfo("  Planet: " + (isNaN(planetDistance) ? "-" : planetDistance));
	this.$hyperMessage += "Sun: " + sunDistance + "\n";
}

//helper to format system lines
this._hyperSystemLine = function (preText, systemName, systemSymbol) {
	var line = preText + " " + systemName;
	return line + this._pads(line + systemSymbol, 14.4) + systemSymbol;
}

//helper to format 1st hyper system data line
this._paddedHyperInfo = function (text) {
	return text + this._pads(text, 7.1);
}

//padding function
this._pads = function (text, width) {
	var hairSpace = String.fromCharCode(31);
	var hairSpaceLength = defaultFont.measureString(hairSpace);
	var currentLength = global.defaultFont.measureString(text);
	var padsNeeded = Math.floor((width - currentLength) / hairSpaceLength);
	if (padsNeeded >= 1) {
		return new Array(padsNeeded).join(hairSpace);
	}
	else return "";
}

//update compass target name. there's some cim still here.
this.compassTargetChanged = function (whom, mode) {
	this.$targetName = "Initializing...";
	if (!whom) return;//null case
	if (whom.displayName) this.$targetName = whom.displayName;
	else if (whom.name) this.$targetName = whom.name;
	else if (whom.beaconLabel) this.$targetName = whom.beaconLabel;
	else if (whom.beaconCode) this.$targetName = whom.beaconCode;
	else this.$targetName = "Unidentified";
	if (mode === "COMPASS_MODE_BASIC") {
		if (whom.isPlanet) this.$targetName = "Planet";
		else this.$targetName = "Main Station";
	}
	else if (mode === "COMPASS_MODE_BEACONS") {
		// Escape capsule locator OXP
		if (this.$targetName === "Metal fragment" && whom.beaconCode.substr(0, 1) === "E")
			this.$targetName = "Escape Capsule";
		else if (this.$targetName === "Navigation Buoy") {
			if (whom.beaconCode.substr(0, 1) === "g")
				this.$targetName = "GRS Buoy Factory Nav Buoy";
			else if (whom.beaconCode.substr(0, 1) === "N")
				this.$targetName = "Main Station Nav Buoy";
		}
		// Tracker OXP
		else if (this.$targetName === "Tracker") {
			if (whom.target.displayName)
				this.$targetName = whom.target.displayName;
			else this.$targetName = whom.target.name;
			this.$targetName += " (Tracked)";
		}
	}
	else if (mode === "COMPASS_MODE_PLANET")
		this.$targetName = "Planet";
	else if (mode === "COMPASS_MODE_SUN") {
		//distant suns oxp
		if (system.info.sun_name)
			this.$targetName = system.info.sun_name + " (Sun)";
		else this.$targetName = "Sun";
	}
	else if (mode === "COMPASS_MODE_STATION")
		this.$targetName = "Main Station";
	this.$updateDistance();
}

//hyperdrive status. mass locks, fuel etc. there's some cim here too.
this.$status = function () {
	if (this.$countdown && this.$countdown === -1) {
		return "  Hyperjump in progress\n";
	}
	if (!player.ship.hasHyperspaceMotor) return "  Not installed\n";
	if (player.ship.targetSystem === system.ID) {
		return "  Present system targeted\n";
	}
	if (this.$hyperDistance > 7) return "  Target out of range\n";
	if (player.ship.fuel < this.$hyperDistance) {
		return "  Not enough fuel\n";
	}
	var position = player.ship.position;
	function isBlocker(entity) {
		if (!entity.isShip) return false;
		if (entity.mass / position.squaredDistanceTo(entity) >= 10) {
			return true;
		}
		return false;
	}
	var blockers = system.filteredEntities(this, isBlocker, player.ship, 25600);
	if (blockers.length > 0)
		return this.$truncate("  Too close to " + blockers[0].name, 14) + "\n";
	if (this.$countdown) {
		//sync to BGS countdown
		if (this.$BGS) {
			return "  Countdown in progress " + (this.$countdown - 1) + "\n";
		}
		//sync to core countdown
		else {
			return "  Countdown in progress " + this.$countdown + "\n";
		}
	}
	return "  Ready\n";
}

//squeezing looks ugly, so I'll truncate instead.
this.$truncate = function (line, width) {
	var lastChar = "";
	//remove characters from the end of the line.
	while (global.defaultFont.measureString(line) > width) {
		lastChar = line.charAt(line.length - 1);
		line = line.slice(0, -1);
	}
	//no chopping was done. return
	if (lastChar === "") return line;
	//if the last char is a space or last removed char was space, return
	if (line.charAt(line.length - 1) === " " || lastChar === " ") {
		return line;
	}
	//if the last char is a char and the second last is a space, remove the char and return
	if (line.charAt(line.length - 2) === " ") {
		return line.slice(0, -1);
	}
	//it seems that we have a chopped word in our hands. looks nicer to end it with a dot
	line += ".";
	while (global.defaultFont.measureString(line) > width) {
		line = line.slice(0, -2);
		line += ".";
	}
	return line;
}