Back to Index Page generated: Jun 25, 2025, 7:13:19 AM

Expansion Console Log MFD

Content

Warnings

  1. http://wiki.alioth.net/index.php/Console%20Log%20MFD -> 404 Not Found
  2. High hanging fruit

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Lists all console messages received in an MFD. Lists all console messages received in an MFD.
Identifier oolite.oxp.phkb.ConsoleLogMFD oolite.oxp.phkb.ConsoleLogMFD
Title Console Log MFD Console Log MFD
Category HUDs HUDs
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/ConsoleLogMFD n/a
Download URL https://wiki.alioth.net/img_auth.php/d/dd/ConsoleLogMFD.oxz n/a
License CC-BY-NC-SA 4.0 CC-BY-NC-SA 4.0
File Size n/a
Upload date 1749109289

Documentation

readme.txt

Console Log MFD
by phkb

This OXP records all console messages received by the player, and displays the most recent messages in an MFD. 

The Console log history is cleared each time you launch from a station.

When docked, a "Console Message Log" item will appear in the Interfaces (F4) screen. When opened, all messages received by the player will be listed, in date order (oldest first, newest last). From this screen there are several options:
	Previous Page:                      Move the list back one page.
	Next Page:                          Move the list forward one page.
	First Page:                         Go to the first page of the list.
	Last Page:                          Go to the last page of the list.
	Write console log to latest.log:    Write all messages to the latest.log file.
	Clear the log:                      Clears all messages from the log.

Only works with Oolite 1.91 or greater.

Installation
============
Install the OXP by copying ConsoleLogMFD.oxz to your AddOns folder, or downloading via the Expansion Manager in the game itself.

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/

Image "console" by Austin Andrews from "https://thenounproject.com/browse/icons/term/console/" (CC BY 3.0)

Version history
===============
1.1
- Improved method of turning HUD on/off.
- Prevented some messages from appearing in the log: Game paused messages, view change messages
- Duplicated messages (ie same message as the last one) are no longer logged.
- System arrival messages are slightly more meaningful. Rather than just "Lave.", it now says "Arrived Lave".
- Double spaces are replaced with single spaces, and line breaks are replaced with single spaces, to streamline the text somewhat.
- All text put into descriptions.plist for easier localisation.

1.0
- Initial release.

Equipment

Name Visible Cost [deci-credits] Tech-Level
Console Log MFD yes 500 2+
Remove Console Log MFD no 50 1+

Ships

This expansion declares no ships. This may be related to warnings.

Models

This expansion declares no models. This may be related to warnings.

Scripts

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