Config/script.js |
"use strict";
this.name = "ConsoleLogMFD";
this.author = "phkb";
this.copyright = "(C) 2023 phkb.";
this.licence = "CC-NC-by-SA 4.0";
this.description = "Console Log MFD main script";
/*
Logic: console log messages received will be displayed in an MFD.
Content of MFD is not scrollable. Content is recycled after docking.
Content is not saved between sessions.
*/
this._messages = [];
this._msRows = 18; // rows to display on the mission screen
this._msCols = 32; // columns to display on the mission screen
this._linePad = "";
this._hairSpace = String.fromCharCode(31);
this._lastText = "";
this._holdText = [];
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
// add interface to HUD selector
var h = worldScripts.hudselector;
if (h) h.$HUDSelectorAddMFD(this.name, this.name, expandDescription("[consolelog_mfd_name]"));
this.shipDockedWithStation(player.ship.dockedStation);
var w = defaultFont.measureString("> ");
while (defaultFont.measureString(this._linePad) < w) {
this._linePad += this._hairSpace;
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipDockedWithStation = function (station) {
this.$initInterface(station);
this._holdText.length = 0;
}
//-------------------------------------------------------------------------------------------------------------
this.viewDirectionChanged = function (to, from) {
this._holdText.shift();
}
//-------------------------------------------------------------------------------------------------------------
this.consoleMessageReceived = function (text) {
// consoleMessageReceived happens before the viewDirectionChanged event
// so in order to work out if the view has changed so we can ignore the message, we have to wait a moment
// so each time a console message appears we start a 0.25 sec timer, which gives the viewDirectionChanged
// event time to fire and potentially clear the message
// Note: this probably isn't foolproof. A lot of messages arriving simultaneously might result in the wrong
// text being dropped, or the change view message might get logged anyway.
this._holdText.push(text);
if (this._timer && this._timer.isRunning) return;
this._timer = new Timer(this, this.$pushChange.bind(this), 0.25, 0);
}
//-------------------------------------------------------------------------------------------------------------
this.$pushChange = function (text) {
if (text == undefined && this._holdText.length > 0) text = this._holdText.shift();
if (text == "" || text == undefined) return;
text = text.trim();
// make arrival message slightly more meaningful.
if (text == system.name + ".") text = expandDescription("[consolelog_arrived]") + " " + system.name + ".";
// we don't need to record game paused messages
if (text == expandDescription("[game-paused]", { pauseKey: expandDescription("[oolite_key_pausebutton]") })) return;
// the forward view message gets past the defence onb launch, so whack it here.
if (text == expandDescription("[forward-view-string]")) return;
// remove any line breaks
do {
text = text.replace(/\n/gm, " ");
} while (text.indexOf("\n") >= 0);
// remove any double spaces
do {
text = text.replace(/ /gm, " ");
} while (text.indexOf(" ") >= 0);
// if the final text is the same as the last one, skip it.
if (text == this._lastText) return;
// update the last text variable for later checking
this._lastText = text;
this._messages.push("> " + text);
if (!player.ship.docked) {
this.$updateMFD();
}
if (this._holdText.length > 0) this._timer = new Timer(this, this.$pushChange.bind(this), 0.25, 0);
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillLaunchFromStation = function () {
this._messages.length = 0;
this.$updateMFD();
}
//-------------------------------------------------------------------------------------------------------------
this.missionScreenEnded = function () {
if (player.ship.hudHidden == true) player.ship.hudHidden = false;
}
//-------------------------------------------------------------------------------------------------------------
this.$updateMFD = function () {
var p = player.ship;
if (p.equipmentStatus("EQ_CONSOLELOGMFD") === "EQUIPMENT_OK") {
var output = [];
this.$reformatData(this._messages, output, 14.8);
var text = "";
var start = output.length - 9;
if (start < 0) start = 0;
for (var i = start; i < output.length; i++) {
text += (text == "" ? "" : "\n") + output[i];
}
if (text == "") {
text = expandDescription("[consolelog_header]") + ":\n\n" + expandDescription("[consolelog_none]");
} else {
text = expandDescription("[consolelog_header]") + ":\n" + text;
}
// send output to MFD
p.setMultiFunctionText("ConsoleLogMFD", text, false);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$initInterface = function (station) {
station.setInterface(this.name, {
title: expandDescription("[consolelog_interface_title]"),
category: expandDescription("[interfaces-category-logs]"),
summary: expandDescription("[consolelog_interface_summary]"),
callback: this.$showConsoleLog.bind(this)
});
}
//-------------------------------------------------------------------------------------------------------------
this.$showConsoleLog = function $showConsoleLog() {
this._syslines = [];
this.$reformatData(this._messages, this._syslines, this._msCols);
this._maxpage = Math.ceil(this._syslines.length / this._msRows);
this._curpage = 0;
this.$showPage();
}
//-------------------------------------------------------------------------------------------------------------
this.$consoleLogPage = function (cpage, lines) {
var output = "";
var iStart = 0;
var iEnd = 0;
var textCount = 0;
// set out initial end point
iEnd = iStart + lines;
if (cpage != 0) {
iStart = cpage * lines;
iEnd = iStart + lines;
}
if (iEnd > this._syslines.length) iEnd = this._syslines.length;
for (var i = iStart; i < iEnd; i++) {
textCount += this._syslines[i].trim().length;
output += this._syslines[i] + "\n";
}
if (cpage === 0 && iStart === 0 && iEnd === 0 && (this._syslines[0] == null || textCount == 0)) output = expandDescription("[consolelog_empty]");
return output;
}
//-------------------------------------------------------------------------------------------------------------
this.$showPage = function $showPage() {
var p = player.ship;
if (this.$isBigGuiActive() === false) p.hudHidden = true;
this._consoleLogOpen = true;
var text = this.$consoleLogPage(this._curpage, this._msRows);
var opts;
var curChoices = {};
var def = "09_NEXT";
if (this._maxpage <= 1) {
def = "99_EXIT";
curChoices["01_PREV"] = { text: "[consolelog_prevpage]", color: "darkGrayColor", unselectable: true };
curChoices["09_NEXT"] = { text: "[consolelog_nextpage]", color: "darkGrayColor", unselectable: true };
curChoices["10_FIRST"] = { text: "[consolelog_firstpage]", color: "darkGrayColor", unselectable: true };
curChoices["11_LAST"] = { text: "[consolelog_lastpage]", color: "darkGrayColor", unselectable: true };
} else {
if (this._curpage === 0) {
curChoices["01_PREV"] = { text: "[consolelog_prevpage]", color: "darkGrayColor", unselectable: true };
curChoices["09_NEXT"] = { text: "[consolelog_nextpage]", color: this._menuColor };
curChoices["10_FIRST"] = { text: "[consolelog_firstpage]", color: "darkGrayColor", unselectable: true };
curChoices["11_LAST"] = { text: "[consolelog_lastpage]", color: "orangeColor" };
} else {
curChoices["01_PREV"] = { text: "[consolelog_prevpage]", color: this._menuColor };
if (this._curpage + 1 === this._maxpage) {
def = "01_PREV";
curChoices["09_NEXT"] = { text: "[consolelog_nextpage]", color: "darkGrayColor", unselectable: true };
curChoices["10_FIRST"] = { text: "[consolelog_firstpage]", color: this._menuColor };
curChoices["11_LAST"] = { text: "[consolelog_lastpage]", color: "darkGrayColor", unselectable: true };
} else {
curChoices["09_NEXT"] = { text: "[consolelog_nextpage]", color: this._menuColor };
curChoices["10_FIRST"] = { text: "[consolelog_firstpage]", color: this._menuColor };
curChoices["11_LAST"] = { text: "[consolelog_lastpage]", color: this._menuColor };
}
}
}
if (text != "(empty)") {
curChoices["15_DUMPLOG"] = { text: "[consolelog_write]", color: this._menuColor };
curChoices["20_CLEARLOG"] = { text: "[consolelog_clear]", color: this._menuColor };
} else {
curChoices["15_DUMPLOG"] = { text: "[consolelog_write]", color: "darkGrayColor", unselectable: true };
curChoices["20_CLEARLOG"] = { text: "[consolelog_clear]", color: "darkGrayColor", unselectable: true };
}
curChoices["99_EXIT"] = { text: "[consolelog_exit]", color: this._exitColor };
var opts = {
screenID: "oolite-consolelog-main-map",
title: expandDescription("[consolelog_screen_title]", { page: (this._curpage + 1).toString(), max: (this._maxpage == 0 ? "1" : this._maxpage.toString()) }),
allowInterrupt: true,
choices: curChoices,
exitScreen: "GUI_SCREEN_INTERFACES",
overlay: { name: "consolelog_overlay.png", height: 546 },
initialChoicesKey: this._lastchoice ? this._lastchoice : def,
message: text
};
mission.runScreen(opts, this.$logHandler.bind(this));
}
//-------------------------------------------------------------------------------------------------------------
this.$logHandler = function $logHandler(choice) {
delete this._lastchoice;
var newChoice = null;
if (!choice) {
return; // launched while reading?
} else if (choice === "01_PREV") {
if (this._curpage > 0) this._curpage -= 1;
} else if (choice === "09_NEXT") {
if (this._curpage < this._maxpage - 1) this._curpage += 1;
} else if (choice === "10_FIRST") {
this._curpage = 0;
} else if (choice === "11_LAST") {
this._curpage = this._maxpage - 1;
} else if (choice === "15_DUMPLOG") {
this.$dumpLog();
} else if (choice === "20_CLEARLOG") {
this._scrollLaunch = 0;
this._message = [];
this._syslines = [];
this._maxpage = 1;
this._curpage = 0;
}
this._lastchoice = choice;
if (newChoice) this._lastchoice = newChoice;
if (choice != "99_EXIT") {
this.$showPage();
}
}
//-------------------------------------------------------------------------------------------------------------
// output the console log to the latest.log
this.$dumpLog = function () {
var msg = "";
for (var i = 0; i < this._messages.length; i++) {
log(this.name, "> " + this._messages[i]);
}
}
//-------------------------------------------------------------------------------------------------------------
this.$reformatData = function (srcArray, destArray, lineWidth) {
//rebuild data into wide screen format
var msg = "";
for (var i = 0; i < srcArray.length; i++) {
if (srcArray[i].substring(0, 1) != " " && msg != "") {
// this is a new message, so output the current one and reset
this.$addMsgToArray(msg, destArray, lineWidth);
msg = "";
}
// add the message line to the current message
// we'll trim off any leading and trailing spaces and add them back manually
msg += srcArray[i].trim() + " ";
}
if (msg != "") {
// output the remaining message
this.$addMsgToArray(msg, destArray, lineWidth);
}
}
//-------------------------------------------------------------------------------------------------------------
// adds a message to an array, splitting the lines based on a line width
this.$addMsgToArray = function (msg, ary, linewidth) {
var prt = "";
if (defaultFont.measureString(msg) > linewidth) {
var words = msg.split(" ");
var iPoint = 0
var nextWord = "";
do {
// add the space in (after the first word)
if (prt != "") {
prt += " ";
}
// add the word on
prt = prt + words[iPoint];
// get the next word in the array
if (iPoint < words.length - 1) {
nextWord = " " + words[iPoint + 1];
} else {
nextWord = ""
}
// check the width of the next with the nextword added on
if (defaultFont.measureString(prt + nextWord) > linewidth) {
// hit the max width - add the line and start again
ary.push(prt);
// subsequent lines of a message will be indented slightly
prt = this._linePad;
}
iPoint += 1;
// check for the end of the array, and output remaining text
if ((iPoint >= words.length) && (prt.trim() != "")) {
ary.push(prt);
}
} while (iPoint < words.length);
words = [];
} else {
ary.push(msg);
}
}
//-------------------------------------------------------------------------------------------------------------
// 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;
}
}
}
|