| Scripts/damagereport_mfd.js | "use strict";
this.name = "DamageReportMFD";
this.author = "phkb";
this.copyright = "2016 phkb";
this.description = "Displays damaged equipment in an MFD";
this.licence = "CC BY-NC-SA 4.0";
this._mfdID = -1;
this._mode = 0;							// can be 0 = Visible when damaged, 1 = Autohide 60, 2 = manual
this._timeout = 60;						// number of seconds mode 1 will take to autohide
this._maxpage = 0;						// total number of pages available for display
this._curpage = 0;						// the current page being displayed
this._msRows = 18;						// rows to display on the mission screen
this._displayMode = 0;					// controls the type of display (0 = master list, 1 = detail item)
this._selectedKey = ""; 				// equipment key of the currently selected item on the damage report interface screen.
this._routeMode = "SHORTEST";			// default mode for long range chart
this._exitScreen = "GUI_SCREEN_INTERFACES";
this._helper = false;
this._colorList = [
	"greenColor",
	"redColor",
	"blueColor",
	"orangeColor",
	"purpleColor",
	"whiteColor",
	"magentaColor"
];
this._color = 3;
//-------------------------------------------------------------------------------------------------------------
this.startUp = function () {
	this._suspendedDestination = null;
	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.startUpComplete = function () {
	if (missionVariables.DamageReportMFD_Mode) {
		// get the stored mode value
		this._mode = missionVariables.DamageReportMFD_Mode;
	}
	this.$initInterface(player.ship.dockedStation);
	// add a mission screen exception to Xenon UI
	if (worldScripts.XenonUI) {
		var wx = worldScripts.XenonUI;
		wx.$addMissionScreenException("oolite-damagereport-detail-map");
	}
	// add a mission screen exception to Xenon Redux UI
	if (worldScripts.XenonReduxUI) {
		var wxr = worldScripts.XenonReduxUI;
		wxr.$addMissionScreenException("oolite-damagereport-detail-map");
	}
	// add interface to HUD selector
	var h = worldScripts.hudselector;
	if (h) h.$HUDSelectorAddMFD(this.name, this.name);
	if (global.setExtraGuiScreenKeys) {
		setExtraGuiScreenKeys(this.name, {
			guiScreen: "GUI_SCREEN_STATUS",
			registerKeys: { "key1": [{ key: "d", mod1: true }] },
			callback: this.$initReport.bind(this)
		});
		if (worldScripts.ContextualHelp) {
			worldScripts.ContextualHelp.$addHelpTextToGuiScreen(this.name, "GUI_SCREEN_STATUS", expandDescription("[DR_contextual_help]"));
		}
	}
}
//=============================================================================================================
// event interfaces
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function () {
	// save the mode value
	missionVariables.DamageReportMFD_Mode = this._mode;
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillLaunchFromStation = function (station) {
	this.$updateMFD();
	if (this._mode == 0 && this.$hasDamagedEquipment() == false) {
		if (this._autoHide && this._autoHide.isRunning) this._autoHide.stop();
		this._autoHide = new Timer(this, this.$autoHideMFD, 1, 0);
	}
}
//-------------------------------------------------------------------------------------------------------------
this.shipDockedWithStation = function (station) {
	this.$initInterface(station);
}
//-------------------------------------------------------------------------------------------------------------
this.equipmentDamaged = function (equipment) {
	this.$updateMFD();
}
//-------------------------------------------------------------------------------------------------------------
this.equipmentRepaired = function (equipment) {
	// theoretically this shouldn't happen during flight, as repairs are normally conducted at a station.
	// but if something like "repair bots oxp" is installed, then it could potentially happen.
	// so we'll update the mfd here as well
	this.$updateMFD();
	if (player.ship.docked) this.$initInterface(player.ship.dockedStation);
}
//-------------------------------------------------------------------------------------------------------------
this.playerBoughtEquipment = function (equipment) {
	var p = player.ship;
	if (equipment == "EQ_DAMAGE_REPORT_MFD_REMOVAL") {
		p.removeEquipment("EQ_DAMAGE_REPORT_MFD");
		p.removeEquipment("EQ_DAMAGE_REPORT_MFD_REMOVAL");
		delete missionVariables.DamageReportMFD_Mode;
	}
	if (equipment == "EQ_DAMAGE_REPORT_MFD_PASSIVE_REMOVAL") {
		p.removeEquipment("EQ_DAMAGE_REPORT_MFD_PASSIVE");
		p.removeEquipment("EQ_DAMAGE_REPORT_MFD_PASSIVE_REMOVAL");
		delete missionVariables.DamageReportMFD_Mode;
	}
	if (equipment == "EQ_DAMAGE_REPORT_MFD") {
		this.$initInterface(p.dockedStation);
	}
}
//-------------------------------------------------------------------------------------------------------------
this.guiScreenChanged = function (to, from) {
	if (to == "GUI_SCREEN_STATUS" && this._helper == false) {
		this._helper = true;
		player.consoleMessage(expandDescription("[DR_shortcut_helper]"));
	}
}
//-------------------------------------------------------------------------------------------------------------
this.missionScreenEnded = function (id) {
	if (player.ship.hudHidden == true) player.ship.hudHidden = false;
	if (player.ship.docked) {
		if (this._suspendedDestination) player.ship.targetSystem = this._suspendedDestination;
		this._suspendedDestination = null;
	}
	if (this._marked) this.$unmarkSystems();
}
//=============================================================================================================
// MFD code
//-------------------------------------------------------------------------------------------------------------
// updates the text of the damage report MFD
this.$updateMFD = function () {
	function comparePrice(a, b) {
		if (a.price < b.price) return 1;
		if (a.price > b.price) return -1;
		return 0;
	}
	var output = "";
	var p = player.ship;
	// only report if the player is in space
	if (p.isInSpace == false) return;
	// if we haven't bought the mfd, or it's damaged itself, don't display anything
	if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD") != "EQUIPMENT_OK" && p.equipmentStatus("EQ_DAMAGE_REPORT_MFD_PASSIVE") != "EQUIPMENT_OK") return;
	var eq = p.equipment;
	var list = [];
	var lb = worldScripts["laserBooster_worldScript.js"];
	// look for any visible, damaged equipment
	for (var i = 0; i < eq.length; i++) {
		var q = eq[i];
		if (q.isVisible && p.equipmentStatus(q.equipmentKey) == "EQUIPMENT_DAMAGED") {
			if (q.equipmentKey.indexOf("LBOOST_REPAIRITEM") > 0 && lb) {
				var q2;
				switch (q.equipmentKey) {
					case "EQ_FORWARD_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["FORWARD"].primary);
						break;
					case "EQ_FORWARD_SECONDARY_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["FORWARD"].secondary);
						break;
					case "EQ_AFT_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["AFT"].primary);
						break;
					case "EQ_AFT_SECONDARY_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["AFT"].secondary);
						break;
					case "EQ_PORT_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["PORT"].primary);
						break;
					case "EQ_PORT_SECONDARY_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["PORT"].secondary);
						break;
					case "EQ_STARBOARD_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["STARBOARD"].primary);
						break;
					case "EQ_STARBOARD_SECONDARY_LBOOST_REPAIRITEM":
						q2 = EquipmentInfo.infoForKey(lb._holdDamage["STARBOARD"].secondary);
						break;
				}
				if (q2) {
					list.push({ key: q2.equipmentKey, price: q2.price, name: q2.name });
				}
			} else {
				list.push({ key: q.equipmentKey, price: q.price, name: q.name });
			}
		}
	}
	if (list.length == 0) {
		// no damaged equipment. yay!
		output = expandDescription("[DR_mfd_title]") + "\n\n" + expandDescription("[DR_mfd_all_good]");
	} else {
		// some damaged equipment. bummer.
		list.sort(comparePrice);
		output = expandDescription("[DR_mfd_title]") + " " + list.length + (list.length == 1 ? " " + expandDescription("[DR_mfd_item]") : expandDescription("[DR_mfd_items]"));
		// once we hit 9 items, we can't display any more so break out of the loop
		var limit = 9;
		if (list.length < 9) limit = list.length
		for (var i = 0; i < limit; i++) {
			output += "\n" + list[i].name;
		}
	}
	// set the text in the MFD
	p.setMultiFunctionText(this.name, output, false);
	// if the hud is hidden don't try an update - it will get confusing as to which mfd slot is open or not.
	if (p.hudHidden == false) {
		// mode 0 (on when damaged), and mode 1 (autohide after 60 secs), see if we need to force the mfd to display
		if (this._mode == 0 || this._mode == 1) {
			// find the slot currently set for this MFD
			this.$findMFDID();
			// if we haven't got a set slot (this._mfdID == -1) or the set slot we had is now unavailable...
			if (this._mfdID == -1 ||
				(p.multiFunctionDisplayList[this._mfdID] && p.multiFunctionDisplayList[this._mfdID] != "" && p.multiFunctionDisplayList[this._mfdID] != this.name)) {
				// find a free slot
				// first, make sure we reset our slot id marker (in the case where the previous one is in use)
				this._mfdID = -1;
				// search for a free slot
				for (var i = 0; i < p.multiFunctionDisplayList.length; i++) {
					if (!p.multiFunctionDisplayList[i] || p.multiFunctionDisplayList[i] == "") {
						this._mfdID = i;
						break;
					}
				}
			}
			// we have a free slot, so force the mfd to display
			if (this._mfdID != -1) {
				if (list.length > 0) {
					p.setMultiFunctionDisplay(this._mfdID, this.name);
				} else {
					// hide the MFD if there are no damaged items
					if (this._mode == 0) this.$autoHideMFD();
				}
				if (this._mode == 1) {
					// set a timer to hide the mfd
					if (this._autoHide && this._autoHide.isRunning) this._autoHide.stop();
					this._autoHide = new Timer(this, this.$autoHideMFD, this._timeout, 0);
				}
			}
		}
		// for mode 2 (Manual) we don't need to do anything. The player will control the visibility of the MFD
	}
}
//-------------------------------------------------------------------------------------------------------------
// records the index of the MFD that currently holds the damage report mfd
this.$findMFDID = function () {
	var p = player.ship;
	for (var i = 0; i < p.multiFunctionDisplayList.length; i++) {
		if (p.multiFunctionDisplayList[i] == this.name) this._mfdID = i;
	}
}
//-------------------------------------------------------------------------------------------------------------
// hides all instances of the damage report MFD
this.$autoHideMFD = function $autoHideMFD() {
	var p = player.ship;
	if (p && p.multiFunctionDisplayList) {
		for (var i = 0; i < p.multiFunctionDisplayList.length; i++) {
			if (p.multiFunctionDisplayList[i] == this.name) {
				p.setMultiFunctionDisplay(i, "");
			}
		}
	}
}
//=============================================================================================================
// Interface screen code
//-------------------------------------------------------------------------------------------------------------
// returns true if there is damaged equipment on the ship, otherwise false
this.$hasDamagedEquipment = function () {
	var p = player.ship;
	var eq = p.equipment;
	var result = false;
	for (var i = 0; i < eq.length; i++) {
		var itm = eq[i];
		if (p.equipmentStatus(itm.equipmentKey) == "EQUIPMENT_DAMAGED") {
			result = true;
			break;
		}
	}
	return result;
}
//-------------------------------------------------------------------------------------------------------------
this.$initInterface = function (station) {
	var p = player.ship;
	if ((p.equipmentStatus("EQ_DAMAGE_REPORT_MFD") == "EQUIPMENT_OK" || p.equipmentStatus("EQ_DAMAGE_REPORT_MFD_PASSIVE") == "EQUIPMENT_OK") || this.$hasDamagedEquipment() == true) {
		station.setInterface(this.name, {
			title: expandDescription("[DR_interface_title]"),
			category: expandDescription("[interfaces-category-logs]"),
			summary: expandDescription("[DR_interface_summary]"),
			callback: this.$initReport.bind(this)
		});
	} else {
		station.setInterface(this.name, null);
	}
}
//-------------------------------------------------------------------------------------------------------------
this.$initReport = function () {
	this._displayMode = 0;
	this._curpage = 0;
	delete this._lastchoice;
	this._routeMode = player.ship.routeMode;
	this._exitScreen = guiScreen;
	this.$showDamageReport();
}
//-------------------------------------------------------------------------------------------------------------
// displays either the list of damaged equipment (_displayMode = 0) or the long range chart with route to nearest fix (_displayMode = 1)
this.$showDamageReport = function () {
	function comparePrice(a, b) {
		if (a.price < b.price) return 1;
		if (a.price > b.price) return -1;
		return 0;
	}
	var p = player.ship;
	var curChoices = {};
	var def = "99_EXIT";
	var text = "";
	// turn off the HUD (unless the hud implements the big Gui)
	if (this.$isBigGuiActive() == false) p.hudHidden = true;
	this._msRows = 18;
	if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD") == "EQUIPMENT_OK" || p.equipmentStatus("EQ_DAMAGE_REPORT_MFD_PASSIVE") == "EQUIPMENT_OK")
		this._msRows = 17;
	var total = 0;
	var repairText = expandDescription("[DR_repair_text]") + ":";
	// lists all damaged equipment
	if (this._displayMode == 0) {
		var eq = p.equipment;
		var list = [];
		var lb = worldScripts["laserBooster_worldScript.js"];
		// look for any visible, damaged equipment
		for (var i = 0; i < eq.length; i++) {
			var q = eq[i];
			if (q.isVisible && p.equipmentStatus(q.equipmentKey) == "EQUIPMENT_DAMAGED") {
				if (q.equipmentKey.indexOf("LBOOST_REPAIRITEM") > 0 && lb) {
					var q2;
					switch (q.equipmentKey) {
						case "EQ_FORWARD_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["FORWARD"].primary);
							break;
						case "EQ_FORWARD_SECONDARY_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["FORWARD"].secondary);
							break;
						case "EQ_AFT_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["AFT"].primary);
							break;
						case "EQ_AFT_SECONDARY_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["AFT"].secondary);
							break;
						case "EQ_PORT_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["PORT"].primary);
							break;
						case "EQ_PORT_SECONDARY_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["PORT"].secondary);
							break;
						case "EQ_STARBOARD_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["STARBOARD"].primary);
							break;
						case "EQ_STARBOARD_SECONDARY_LBOOST_REPAIRITEM":
							q2 = EquipmentInfo.infoForKey(lb._holdDamage["STARBOARD"].secondary);
							break;
					}
					if (q2) {
						list.push({ key: q2.equipmentKey, price: q2.price, name: q2.name, techLevel: (q2.effectiveTechLevel == 0 ? 1 : q2.effectiveTechLevel), repairCost: (q2.price / 10) * 0.5 });
						total += (q2.price / 10) * 0.5;
					}
				} else {
					list.push({ key: q.equipmentKey, price: q.price, name: q.name, techLevel: (q.effectiveTechLevel == 0 ? 1 : q.effectiveTechLevel), repairCost: (q.price / 10) * 0.5 });
					total += (q.price / 10) * 0.5;
				}
			}
		}
		// look for ShipConfig damaged items
		if (worldScripts.ShipConfiguration_Core) {
			var sc = worldScripts.ShipConfiguration_Core;
			var arm = worldScripts.ShipConfiguration_Armour;
			var k2 = sc.$equipmentItemInUse("armour", player.ship);
			if (k2 !== "") {
				var cur = parseInt(parseInt(((200 - (arm._armourFront + arm._armourAft)) / 200) * 100) / 10);
				if ((arm._armourFront < 100 || arm._armourAft < 100) && cur === 0) cur = 1;
				if (cur > 0) {
					var k1 = k2 + "_REPAIR" + cur
					var q1 = EquipmentInfo.infoForKey(k1);
					list.push({ key: k1, price: q1.price, name: q1.name.replace(repairText, "").trim(), techLevel: (k1.effectiveTechLevel === 0 ? 1 : q1.effectiveTechLevel), repairCost: (q1.price / 10) * 0.5 });
					total += (q1.price / 10) * 0.5;
				}
			}
		}
		// iron hide damage?
		if (p.equipmentStatus("EQ_IRONHIDE") === "EQUIPMENT_OK") {
			if (missionVariables.ironHide_percentage < 100) {
				var q1 = EquipmentInfo.infoForKey("EQ_IRONHIDE_REPAIR");
				list.push({ key: q1.equipmentKey, price: q1.price, name: q1.name.replace(repairText, "").trim(), techLevel: (q1.effectiveTechLevel === 0 ? 1 : q1.effectiveTechLevel), repairCost: expandDescription("[DR_repair_unknown]") });
			}
		}
		var col1 = 15;
		var col2 = 9;
		var col3 = 8;
		if (list.length == 0) {
			// no damaged equipment. yay!
			text = expandDescription("[DR_mfd_all_good]");
			this._maxpage = 0;
			this._curpage = 0;
		} else {
			// some damaged equipment. bummer.
			list.sort(comparePrice);
			// calculate the max number of pages
			this._maxpage = Math.ceil(list.length / this._msRows);
			text = expandDescription("[DR_note_estimate]") +
				(list.length > 1 ? " " + expandDescription("[DR_estimated_costs]", { amount: formatCredits(total, false, true) }) : "") + "\n\n";
			text += this.$padTextRight(expandDescription("[DR_header_equip_item]"), col1);
			text += this.$padTextLeft(expandDescription("[DR_header_est_cost]"), col2);
			text += this.$padTextLeft(expandDescription("[DR_header_req_tl]"), col3);
			var items = 0;
			var start = this._curpage * this._msRows;
			var end = (this._curpage * this._msRows) + this._msRows;
			var itemText = "";
			var repairItem = 0;
			for (var i = 0; i < list.length; i++) {
				items += 1;
				if ((items - 1) >= start && (items - 1) < end) {
					repairItem += 1;
					itemText = this.$padTextRight(list[i].name, col1) +
						this.$padTextLeft((this.$isNumeric(list[i].repairCost) ? list[i].repairCost.toFixed(2) : list[i].repairCost), col2) +
						this.$padTextLeft(list[i].techLevel, col3);
					curChoices["01_" + (repairItem < 10 ? "0" : "") + repairItem + "_REPAIRITEM_" + i + ":" + list[i].key] = { text: itemText, color: "orangeColor", alignment: "LEFT" };
				}
			}
			for (var i = 0; i < (this._msRows + 1) - repairItem; i++) {
				curChoices["02_SPACER_" + i.toString()] = "";
			}
			if (this._curpage < this._maxpage - 1) {
				curChoices["10_GOTONEXT"] = { text: "[DR_OPTION_NEXTPAGE]", color: "yellowColor" };
			} else {
				curChoices["10_GOTONEXT"] = { text: "[DR_OPTION_NEXTPAGE]", color: "darkGrayColor", unselectable: true };
			}
			if (this._curpage > 0) {
				curChoices["11_GOTOPREV"] = { text: "[DR_OPTION_PREVPAGE]", color: "yellowColor" };
			} else {
				curChoices["11_GOTOPREV"] = { text: "[DR_OPTION_PREVPAGE]", color: "darkGrayColor", unselectable: true };
			}
		}
		if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD") == "EQUIPMENT_OK" || p.equipmentStatus("EQ_DAMAGE_REPORT_MFD_PASSIVE") == "EQUIPMENT_OK") {
			var mfdType = "DR_TYPE1";
			if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD_PASSIVE") == "EQUIPMENT_OK") mfdType = "DR_TYPE2";
			mfdType += "_MODE" + this._mode;
			curChoices["80_" + mfdType] = expandDescription("[" + mfdType + "]");
		}
		curChoices["99_EXIT"] = expandDescription("[DR_exit]");
		var opts = {
			screenID: "oolite-damagereport-main-summary",
			title: expandDescription("[DR_screen_title]", { page: (this._curpage + 1), max: (this._maxpage < 1 ? 1 : this._maxpage) }),
			allowInterrupt: true,
			exitScreen: this._exitScreen,
			overlay: { name: "dr-wrench.png", height: 546 },
			choices: curChoices,
			initialChoicesKey: this._lastchoice ? this._lastchoice : def,
			message: text
		};
	}
	// displays the long range chart with route to nearest fix, plus equipment repair details
	if (this._displayMode == 1) {
		var equip = EquipmentInfo.infoForKey(this._selectedKey);
		var closest = this.$findClosestTechLevel(equip.effectiveTechLevel - 1);
		var rt = system.info.routeToSystem(System.infoForSystem(galaxyNumber, closest.id), (this._routeMode === "SHORTEST" ? "OPTIMIZED_BY_JUMPS" : "OPTIMIZED_BY_TIME"));
		if (!p.docked) this.$mapRouteToSystem(closest.id, this._routeMode);
		text = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; // make sure we don't overlay the chart
		if (p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY") && rt && rt.route.length > 1) {
			text += this.$padTextRight("", 6.45) + expandDescription("[DR_jumps]", {jumps:(rt.route.length - 1)}) + "\n";
		} else {
			text += "\n";
		}
		text += this.$padTextRight(expandDescription("[DR_header_equip_item]") + ": ", 10) + this.$padTextLeft(equip.name.replace(repairText, "").trim(), 22) + "\n";
		if (equip.price > 0) {
			text += this.$padTextRight(expandDescription("[DR_header_est_cost_long]") + ": ", 15) + this.$padTextLeft(((equip.price / 10) * 0.5).toFixed(2), 17) + "\n";
		} else {
			text += this.$padTextRight(expandDescription("[DR_header_est_cost_long]") + ": ", 15) + this.$padTextLeft(expandDescription("[DR_repair_unknown]"), 17) + "\n";
		}
		text += this.$padTextRight(expandDescription("[DR_header_req_tl_long]") + ": ", 20) + this.$padTextLeft((equip.effectiveTechLevel == 0 ? 1 : equip.effectiveTechLevel).toString(), 12) + "\n";
		var bg = "LONG_RANGE_CHART";
		if (closest != null) {
			if (system.info.distanceToSystem(System.infoForSystem(galaxyNumber, closest.id)) < 7.4) bg = "SHORT_RANGE_CHART";
			// hold the player's destination
			if (p.docked) {
				this._suspendedDestination = p.targetSystem;
				// override it for the display
				p.targetSystem = closest.id;
			}
			text += this.$padTextRight(expandDescription("[DR_nearest_planet]") + ": ", 17)
				+ this.$padTextLeft(closest.name + " (TL:" + closest.techLevel + ") "
					+ this._ecos[closest.economy] + this._govs[closest.government]
					+ (closest.id === system.ID ? " " + expandDescription("[DR_current]") : ""), 15);
			if (bg === "LONG_RANGE_CHART") {
				if (p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY")) {
					if (this._routeMode == "SHORTEST") {
						bg = "LONG_RANGE_CHART_SHORTEST";
						curChoices["90_SHORTEST"] = { text: "[DR_shortest_route]", color: "darkGrayColor", unselectable: true };
						curChoices["91_QUICKEST"] = { text: "[DR_quickest_route]" };
					} else {
						bg = "LONG_RANGE_CHART_QUICKEST";
						curChoices["90_SHORTEST"] = {text: "[DR_shortest_route]"};
						curChoices["91_QUICKEST"] = { text: "[DR_quickest_route]", color: "darkGrayColor", unselectable: true };
					}
				}
			}
			if (p.docked && closest.id != system.ID && p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY")) {
				curChoices["96_SETCOURSE:" + closest.id] = expandDescription("[DR_set_course]", {sys: closest.name});
			}
		} else {
			text += "\n" + expandDescription("[DR_no_system_found]") + "\n";
			if (p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY")) {
				bg = "LONG_RANGE_CHART_SHORTEST";
			}
			// hold the player's destination
			if (p.docked) {
				this._suspendedDestination = p.targetSystem;
				p.targetSystem = system.ID;
			}
		}
		curChoices["98_CLOSE"] = expandDescription("[DR_close]");
		def = "98_CLOSE";
		var opts = {
			screenID: "oolite-damagereport-detail-map",
			title: expandDescription("[DR_damage_report_detail]"),
			backgroundSpecial: bg,
			allowInterrupt: true,
			exitScreen: this._exitScreen,
			choices: curChoices,
			initialChoicesKey: def,
			message: text
		};
	}
	if (global.setExtraGuiScreenKeys) {
		opts["registerKeys"] = { "keyEsc": [{ key: "esc" }] }
	}
	mission.runScreen(opts, this.$screenHandler, this);
}
//-------------------------------------------------------------------------------------------------------------
// handles UI responses on the damage report screen
this.$screenHandler = function (choice, key) {
	delete this._lastchoice;
	var newChoice = "";
	if (player.ship.docked) {
		if (this._suspendedDestination) player.ship.targetSystem = this._suspendedDestination;
		this._suspendedDestination = null;
	}
	if (key == "keyEsc") return;
	if (!choice) {
		return; // launched while reading?
	} else if (choice.indexOf("REPAIRITEM") >= 0) {
		// get the selected item
		// use the index attached to the end of the choice
		this._selectedKey = choice.substring(choice.indexOf(":") + 1);
		this._displayMode = 1;
		this._savedChoice = choice;
	} else if (choice == "11_GOTOPREV") {
		this._curpage -= 1;
		if (this._curpage == 0) {
			newChoice = "10_GOTONEXT";
		}
	} else if (choice == "10_GOTONEXT") {
		this._curpage += 1;
		if (this._curpage == this._maxpage - 1) {
			newChoice = "11_GOTOPREV";
		}
	} else if (choice.indexOf("80_") >= 0) {
		var mfdType = choice.substring(6, 11);
		var mfdMode = parseInt(choice.substring(16));
		mfdMode += 1;
		if (mfdMode == 3) {
			mfdMode = 0;
			if (mfdType == "TYPE1") {
				mfdType = "TYPE2";
			} else {
				mfdType = "TYPE1";
			}
		}
		this.$switchMFDType(mfdType);
		this._mode = mfdMode;
		newChoice = "80_DR_" + mfdType + "_MODE" + mfdMode;
	} else if (choice.indexOf("96_SETCOURSE") >= 0) {
		var id = parseInt(choice.substring(choice.indexOf(":") + 1));
		player.ship.targetSystem = id;
		player.ship.infoSystem = player.ship.targetSystem;
		// force the Xenon HUD to update it's destination
		if (worldScripts.XenonHUD) {
			var w = worldScripts.XenonHUD;
			w.guiScreenChanged("", "GUI_SCREEN_SHORT_RANGE_CHART");
		}
		this._displayMode = 0;
	} else if (choice == "90_SHORTEST") {
		this._routeMode = "SHORTEST";
	} else if (choice == "91_QUICKEST") {
		this._routeMode = "QUICKEST";
	} else if (choice == "98_CLOSE") {
		this.$unmarkSystems();
		this._displayMode = 0;
		this._selectedKey = "";
		newChoice = this._savedChoice;
		delete this._savedChoice;
	}
	this._lastchoice = choice;
	if (newChoice != "") {
		this._lastchoice = newChoice;
	}
	if (choice != "99_EXIT") {
		this.$showDamageReport();
	}
}
//-------------------------------------------------------------------------------------------------------------
// switch between the different types of MFD: TYPE1 = normal, with primable equipment, or TYPE2 = passive, can't be set during flight.
this.$switchMFDType = function (mfdType) {
	var p = player.ship;
	switch (mfdType) {
		case "TYPE2":
			if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD") != "EQUIPMENT_OK") return;
			if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD_PASSIVE") == "EQUIPMENT_OK") return;
			p.removeEquipment("EQ_DAMAGE_REPORT_MFD");
			p.awardEquipment("EQ_DAMAGE_REPORT_MFD_PASSIVE");
			break;
		case "TYPE1":
			if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD_PASSIVE") != "EQUIPMENT_OK") return;
			if (p.equipmentStatus("EQ_DAMAGE_REPORT_MFD") == "EQUIPMENT_OK") return;
			p.removeEquipment("EQ_DAMAGE_REPORT_MFD_PASSIVE");
			p.awardEquipment("EQ_DAMAGE_REPORT_MFD");
			break;
	}
}
//-------------------------------------------------------------------------------------------------------------
// appends space to currentText to the specified length in 'em'
this.$padTextRight = function (currentText, desiredLength, leftSwitch) {
	if (currentText == null) currentText = "";
	var hairSpace = String.fromCharCode(31);
	var ellip = "…";
	var currentLength = defaultFont.measureString(currentText.toString().replace(/%%/g, "%"));
	var hairSpaceLength = defaultFont.measureString(hairSpace);
	// calculate number needed to fill remaining length
	var padsNeeded = Math.floor((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 (defaultFont.measureString(tmp.replace(/%%/g, "%")) > desiredLength);
		currentLength = defaultFont.measureString(tmp);
		padsNeeded = Math.floor((desiredLength - currentLength) / hairSpaceLength);
		currentText = tmp;
	}
	// quick way of generating a repeated string of that number
	if (!leftSwitch || leftSwitch == false) {
		return currentText + new Array(padsNeeded).join(hairSpace);
	} else {
		return new Array(padsNeeded).join(hairSpace) + currentText;
	}
}
//-------------------------------------------------------------------------------------------------------------
// appends space to currentText to the specified length in 'em'
this.$padTextLeft = function (currentText, desiredLength) {
	return this.$padTextRight(currentText, desiredLength, true);
}
//-------------------------------------------------------------------------------------------------------------
// returns an object containing the id, name, tl, government and distance of the closest system whose TechLevel is greater than or equal to the passed value
this.$findClosestTechLevel = function (requiredTL) {
	var planets = SystemInfo.filteredSystems(this, function (other) {
		return (other.techlevel >= requiredTL);
	});
	var dist = 200;
	var selected = -1;
	var checkDist = 0;
	for (var i = 0; i < planets.length; i++) {
		var chkrt = system.info.routeToSystem(planets[i]);
		if (chkrt) {
			checkDist = chkrt.distance;
		} else {
			checkDist = system.info.distanceToSystem(planets[i]);
		}
		if (checkDist < dist) {
			dist = checkDist;
			selected = planets[i].systemID;
		}
	}
	if (selected != -1) {
		var info = System.infoForSystem(galaxyNumber, selected);
		var rt = system.info.routeToSystem(info);
		if (rt) {
			var dist = rt.distance;
		} else {
			var dist = system.info.distanceToSystem(info);
		}
		return { id: selected, techLevel: (info.techlevel + 1), name: info.name, economy: info.economy, government: info.government, distance: dist };
	} else {
		return null;
	}
}
//-------------------------------------------------------------------------------------------------------------
// returns true if a HUD with allowBigGUI is enabled, otherwise false
this.$isBigGuiActive = function () {
	if (oolite.compareVersion("1.83") <= 0) {
		return player.ship.hudAllowsBigGui;
	} else {
		var bigGuiHUD = ["XenonHUD.plist", "coluber_hud_ch01-dock.plist"]; 	// until there is a property we can check, I'll be listing HUD's that have the allow_big_gui property set here
		if (bigGuiHUD.indexOf(player.ship.hud) >= 0) {
			return true;
		} else {
			return false;
		}
	}
}
//-------------------------------------------------------------------------------------------------------------
// returns true if passed value is numeric, otherwise false
this.$isNumeric = function (n) {
	return !isNaN(parseFloat(n)) && isFinite(n);
}
//-------------------------------------------------------------------------------------------------------------
this.$mapRouteToSystem = function (id, mode) {
	var info = System.infoForSystem(galaxyNumber, id);
	this._currentRoute = system.info.routeToSystem(info, mode);
	if (this._currentRoute && this._currentRoute.route.length > 1) {
		for (var i = 0; i < this._currentRoute.route.length - 1; i++) {
			if (this._currentRoute.route[i] < this._currentRoute.route[i + 1]) {
				SystemInfo.setInterstellarProperty(galaxyNumber, this._currentRoute.route[i], this._currentRoute.route[i + 1], 2, "link_color", this._colorList[this._color]);
			} else {
				SystemInfo.setInterstellarProperty(galaxyNumber, this._currentRoute.route[i + 1], this._currentRoute.route[i], 2, "link_color", this._colorList[this._color]);
			}
		}
		this._marked = true;
	}
}
//-------------------------------------------------------------------------------------------------------------
this.$unmarkSystems = function $unmarkSystems() {
	if (this._currentRoute) {
		for (var i = 0; i < this._currentRoute.route.length - 1; i++) {
			if (this._currentRoute.route[i] < this._currentRoute.route[i + 1]) {
				SystemInfo.setInterstellarProperty(galaxyNumber, this._currentRoute.route[i], this._currentRoute.route[i + 1], 2, "link_color", null);
			} else {
				SystemInfo.setInterstellarProperty(galaxyNumber, this._currentRoute.route[i + 1], this._currentRoute.route[i], 2, "link_color", null);
			}
		}
	}
	this._currentRoute = null;
	this._marked = false;
} |