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;
}
|