| Scripts/ManifestScanner.js | //			~~~I STRONGLY encourage the modification and development of this free software by anyone to meet your needs, I only ask that you give me credit for the original work. Thanks and enjoy.~~~
"use strict";
this.author      = "Morgan Orr"; 
this.copyright   = "� 2011-2017 Morgan Orr."; 
this.licence = "CC-BY-SA 4.0";
this.version     = "1.3.2"; 
/* version 1.2 modifed by Nick Rogers (phkb)
 - made scan take a few seconds, rather than being instantaneous (makes it feel more real)
 - added manual/active scan modes (so you don't have to prime the equipment and activate a scan)
 - fixed issue with MFD where ships with more that 8 manifest types were not being displayed correctly. it was working on the basis of having 9 lines
   whereas there were only 8 lines available
 - if ship has more than 16 items, MFD will switch to a 3 column version. (Hopefully the chances of a ship needing 4 columns is remote!)
 - removed the framecallback for the scan process, reused it to check for lost target via wormholes
 - some general code tiding and refactoring.
*/
this.name        = "ManifestScanner";
this.description = "Scan a ship's manifest and displays results in a MFD";
this._scanTimer = null;
this._scanTime = 5;
this._scanMemory = [];
this.$manscanLst = false;
this.$manscanMsg =""; //message for mfd
this._scanMode = 0; // 0 = manual scanning, 1 = active scanning
this._loadedPrevScan = false;
this._validScanClasses = ["CLASS_NEUTRAL", "CLASS_POLICE", "CLASS_MILITARY"];
//-------------------------------------------------------------------------------------------------------------
this.startUp = function() {
	this.$manscanlogging = true;
}
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function() {
	if (missionVariables.ManifestScanner_ScanMode != null) this._scanMode = missionVariables.ManifestScanner_ScanMode;
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function() {
	missionVariables.ManifestScanner_ScanMode = this._scanMode;
}
//-------------------------------------------------------------------------------------------------------------
//update the mfd message and start a framecallback on launch
this.shipWillLaunchFromStation = function() {
	this.$manscanmfdInfo();
	if (!this.$manscanmfd)
		this.$manscanmfd = addFrameCallback(this.$checkForLostTarget.bind(this));
	
	player.ship.setMultiFunctionText("ManifestScanner", ""+this.$manscanMsg+"");
}
//-------------------------------------------------------------------------------------------------------------
//remove framecallback on docking or death
this.shipWillDockWithStation = function() {
	if (this._scanTimer && this._scanTimer.isRunning) this._scanTimer.stop();
	this.$removeFCB();
}
//-------------------------------------------------------------------------------------------------------------
this.shipDied = function(whom, why) {
	this.$removeFCB();
}
//-------------------------------------------------------------------------------------------------------------
this.activated = function() { //try to enable scanner as primed eq
	var w = worldScripts.ManifestScanner;
	if (this._scanTimer == null || this._scanTimer.isRunning == false) {
		if (w.$manscanMsg.indexOf("Invalid target") != -1 || 
			w.$manscanMsg.indexOf("No target") != -1 || 
			w.$manscanMsg.indexOf("Target lost") != -1 ||
			w.$manscanMsg.indexOf("Unable to scan") != -1) return;
		w.$manscanLst = true;
		w.$manscanmfdInfo(0);
		
		player.ship.setMultiFunctionText("ManifestScanner", w.$manscanMsg+"\n...scanning...");
			
		this._scanTimer = new Timer(this, this.$runScan.bind(this), this._scanTime, 0);
	} else if(this._scanTimer && this._scanTimer.isRunning) {
		this._scanTimer.stop();
		player.ship.setMultiFunctionText("ManifestScanner", w.$manscanMsg);
	}
}
//-------------------------------------------------------------------------------------------------------------
this.mode = function() { //attempt to make scanner update with "n" key
	var w = worldScripts.ManifestScanner;
	if (w._scanMode == 0) {
		w._scanMode = 1;
		player.consoleMessage("Manifest Scanner Active Scan Mode");
	} else {
		w._scanMode = 0;
		w._scanMemory = []; w.$manscanmfdInfo(0); if(w.$manscanlogging) log(w.name,w.name+" : Clear scan memory") // rustem // 1 method
		player.consoleMessage("Manifest Scanner Manual Scan Mode");
	}
}
//-------------------------------------------------------------------------------------------------------------
this.shipExitedWitchspace = function() {
	this._scanMemory = [];
	this.$manscanmfdInfo(0);
}
//-------------------------------------------------------------------------------------------------------------
this.shipEnteredWitchspace = function() {
	if (this._scanTimer && this._scanTimer.isRunning) this._scanTimer.stop();
	this.$manscanMsg = "Manifest Scanner: No target";
	this.$manscanmfdInfo();
	player.ship.setMultiFunctionText("ManifestScanner", ""+this.$manscanMsg+""); 
}	
//-------------------------------------------------------------------------------------------------------------
// update when new target aquired
this.shipTargetAcquired = function(target) {
	if (this._scanTimer && this._scanTimer.isRunning) this._scanTimer.stop();
	this.$manscanmfdInfo(0);
	//if(this.$manscanlogging) log(this.name,this.name+"Target? : "+player.ship.target)
	player.ship.setMultiFunctionText("ManifestScanner", ""+this.$manscanMsg+"");
	// if active scanning is enabled, run the scan as soon as we have a target
	if (this._scanMode == 1 && this._loadedPrevScan == false) {
		if (target.isShip && this._validScanClasses.indexOf(target.scanClass) >= 0) {
			this.activated();
		}
	}
}
//-------------------------------------------------------------------------------------------------------------
//remove list when target lost ~~~ version 0.2.3 attempt to turn off so must be activated every time a new target is aquired
this.shipTargetLost = function(target) {
	if (this._scanTimer && this._scanTimer.isRunning) this._scanTimer.stop();
	this.$manscanMsg = "Manifest Scanner: Target lost";
	player.ship.setMultiFunctionText("ManifestScanner", ""+this.$manscanMsg+""); 
}
//-------------------------------------------------------------------------------------------------------------
// removes the frame callback
this.$removeFCB = function() {
	if (this.$manscanmfd) {
		removeFrameCallback(this.$manscanmfd);
		delete this.$manscanmfd;
	}
}
//-------------------------------------------------------------------------------------------------------------
// runs the manifest scan and updates the MFD
this.$runScan = function() {
	this.$manscanLst = true;
	this.$manscanmfdInfo(1);
	player.ship.setMultiFunctionText("ManifestScanner", ""+this.$manscanMsg+"");
}
//-------------------------------------------------------------------------------------------------------------
// checks to see if the players current target has disappeared (eg into a wormhole)
this.$checkForLostTarget = function() {
	if (player.ship.target == null && this.$manscanMsg.indexOf("Manifest Scanner:") == -1) this.shipTargetLost();
}
//-------------------------------------------------------------------------------------------------------------
//display targets manifest in a MFD
this.$manscanmfdInfo = function(repType) {
	
	// rep type 0 = cargo capacity only
	// rep type 1 = all data
	var p = player.ship;
	if (!p || !p.isValid || p.equipmentStatus('EQ_MANIF_SCANNER') !== 'EQUIPMENT_OK') return;
	var target = "";
	var t = p.target;
	this._loadedPrevScan = false;
	if (t != null) {
		var prevScan = worldScripts.ManifestScanner.$findShipScan(t);
		if (prevScan != "") {
			this.$manscanMsg = prevScan;
			this._loadedPrevScan = true; 
			if(this.$manscanlogging) log(this.name,this.name+" : will loaded prevScan for "+t.displayName+"["+t.cargoSpaceUsed+"]"); // rustem
			return;
		}
	}
	var tdn = "";
	var message = "Manifest Scanner: ";
	if (!t) message += "No target";
	if (t && t.isValid) {
		if (this._validScanClasses.indexOf(t.scanClass) == -1) { 
			message += "Invalid target";
		} else if(t.isDerelict) {
			message += "Unable to scan\nNo power to ship systems.\nRemote query of manifest failed.";
		} else {
			tdn = t.displayName+"\nCargo " + t.cargoSpaceUsed + " t (" + t.cargoSpaceCapacity + " t):";
			if (t.cargoSpaceCapacity == 0 || t.cargoSpaceUsed == 0) {
				tdn += "\n  None.";
				// there is no capacity, or nothing stored, so no need to scan - tell calling routine to skip the scan process
				this._loadedPrevScan = true;
			}
			
			if (t.cargoSpaceCapacity > 0 && repType == 1) {
				var lst = t.cargoList;
				if (lst.length === 0) tdn += "\n  None.";
				if(this.$manscanLst) {
					var units = new Array();
					for (var i = 0; i < lst.length; i++) {
						var l = lst[i];
						units.push(l.quantity + " " + String.fromCharCode(215) + " "+ l.displayName);
					} 
					var columns = Math.ceil(units.length / 8);
					var colWidths = [15, 7.5, 7]; // 3rd column width is 7 - we want Oolite to squeeze the font in this instance
					var colWidth = colWidths[columns - 1];
					for (var i = 0; i < 8; i++) {
						var line = "";
						
						if (i < units.length) line = "\n" + this.$padTextRight(" " + units[i], colWidth);
						if ((i + 8) < units.length) line += this.$padTextRight(units[i+8], colWidth);
						if ((i + 16) < units.length) line += this.$padTextRight(units[i+8], colWidth);
						
						if (line != "") tdn += line;
					}
				}
			}
			message = tdn;
		}
	}
	this.$manscanMsg = message;
	if (t && t.isValid && t.isShip && t.isPiloted && repType == 1) worldScripts.ManifestScanner.$addShipScan(t, message);
}
//-------------------------------------------------------------------------------------------------------------
// adds or updates the scan for a ship
this.$addShipScan = function(shp, dta) {
	var index = null;
	var found = false;
	var shipKey = shp.displayName + shp.dataKey + shp.entityPersonality + shp.primaryRole; // rustem / 2 method: + shp.cargoSpaceUsed
	for (var i = 0; i < this._scanMemory.length; i++) {
		if (this._scanMemory[i].ship == shipKey) { // rustem / 3 method: add check cargoSpaceUsed + add replace scanData
			index = i;													// found an any data
			if (this._scanMemory[i].shipCSU == shp.cargoSpaceUsed) { 	// found a last correct data
				found = true;
				this._scanMemory[i].scanCSU = shp.cargoSpaceUsed;
				this._scanMemory[i].scanData = dta;
				break;
			}
		}
	}
	if (found == false) {
		if (index == null) {		// rustem
			this._scanMemory.push({ship:shipKey, scanCSU:shp.cargoSpaceUsed, scanData:dta});
			if(this.$manscanlogging) log(this.name,this.name+" : push data for "+shp.displayName+"["+shp.cargoSpaceUsed+"]");
		} else {
			//index = index+1;
			this._scanMemory.splice(index, 1, {ship:shipKey, scanCSU:shp.cargoSpaceUsed, scanData:dta});
			if(this.$manscanlogging) log(this.name,this.name+" : replace["+index+"] data for "+shp.displayName+"["+shp.cargoSpaceUsed+"]");			
		}
	}
}
//-------------------------------------------------------------------------------------------------------------
// checks the scan memory for a scan for this ship
this.$findShipScan = function(shp) {
	var shipKey = shp.displayName + shp.dataKey + shp.entityPersonality + shp.primaryRole; // rustem / 2 method: + shp.cargoSpaceUsed
	for (var i = 0; i < this._scanMemory.length; i++) {
		if (this._scanMemory[i].ship == shipKey && this._scanMemory[i].scanCSU == shp.cargoSpaceUsed) return this._scanMemory[i].scanData; // rustem / 3 method
	}
	return "";
}
//-------------------------------------------------------------------------------------------------------------
// 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);
	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) > 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;
	}
}
 | 
                
                    | Scripts/ManifestScannerEq.js | //			~~~I STRONGLY encourage the modification and development of this free software by anyone to meet your needs, I only ask that you give me credit for the original work. Thanks and enjoy.~~~
"use strict";
this.author      = "Morgan Orr"; 
this.copyright   = "� 2011-2017 Morgan Orr."; 
this.licence = "CC-BY-SA 4.0";
this.version     = "1.3.2"; 
/* version 1.2 modifed by Nick Rogers (phkb)
 - Cleaned up unnecessary lines in equipment.plist
 - Expanded text displayed if the player is discovered with a manifest scanner while doing a renovation.
 - included gov type 4 in all government checks
*/
this.name        = "ManifestScannerEq";
this.description = "Equipment control script for the manifest scanner";
//restrict from mainstations communist-corprate systems
this.allowAwardEquipment = function(equipment, ship, context) {
	var p = player.ship;
	var stn = p.dockedStation;
	if (context == "purchase" && system.government >= 4 && stn.allegiance == "galcop") {
		return false;
	} else {
		return true;
	}
}
this.playerBoughtEquipment = function(equipment) {
	var p = player.ship;
	var stn = p.dockedStation;
	if( equipment === "EQ_MANIF_SCANNERX" ) {
		p.removeEquipment("EQ_MANIF_SCANNERX");
		p.removeEquipment("EQ_MANIF_SCANNER");
		var info = EquipmentInfo.infoForKey("EQ_MANIF_SCANNER");
		var refund = parseInt(((info.price / 10) * p.dockedStation.equipmentPriceFactor) * 0.9218);
		
		player.credits += refund; //2950
	}
	//Remove and fine if techies at mainstation find it in communist-corprate systems 
	if (equipment === "EQ_RENOVATION" && 
		system.government >= 4 && 
		stn.allegiance == "galcop" && 
		(p.equipmentStatus("EQ_MANIF_SCANNER") == "EQUIPMENT_OK" || p.equipmentStatus("EQ_MANIF_SCANNER") == "EQUIPMENT_DAMAGED")) {
		this._scannerRemove = true;
		mission.runScreen({
			title: "Suspicious Activity", 
			message: "It appears that some of your equipment has been tampered with.", 
			model:"station"}
		);
	}
}
this.missionScreenOpportunity= function() {
	if(this._scannerRemove) {
    	this._scannerRemove = false;
        mission.runScreen({
			title: "Equipment Confiscated", 
			message: "Your Manifest Scanner has been confiscated as per GalCop regulation GC-149874-2 which states:" + 
			"\n\n'Devices designed to scan a ship's manifest while in space, operating in unauthorised vessels, are deemed to be illegal. " + 
			"Should such a device be discovered on a ship by a GalCop official in any capacity (be it law enforcement or engineering), it will be removed and destroyed.'" + 
			"\n\nWe would normally issue a fine for this offence, but decided that a warning was sufficient. Please take care to obey GalCop laws in future.", 
			model: "police"
		});
		player.ship.removeEquipment("EQ_MANIF_SCANNER");
    }
}
 |