| Config/script.js | "use strict";
this.name = "oreProcessor";
this.author = "Eric, spara";
this.copyright = "Creative Commons: attribution, non-commercial, sharealike.";
this.description = "Ore processor main";
//2.2.5 Moved text to descriptions.plist. Added a Hardwire Ore Scanner equipment item.
//2.2.4 Custom splinters can now be turned on/off via library config.
//2.2.3 set ranges into dictionary, moved to core game commodity names, using core function for display names
//2.2.1 Gem-Stones bug fix for Oolite 1.81
//2.2 scanner is now a separate equipment/upgrade. Failure chance is removed.
//2.1.1 added support for manifest_mfd
//2.1 added support for griff's additional shipset splinters
//2.1 added the possibility to hard-wire the processor to work without activation
this._splinter = new Array(); // array that will hold a list of splinter records
this._config = {
	useCustomSplinters: false,
};
this._opConfig = {
	Name: this.name,
	Alias: expandDescription("[orep_config_alias]"),
	Display: expandDescription("[orep_config_display]"),
	Alive: "_opConfig",
	Bool: {
		B0: { Name: "_config.useCustomSplinters", Def: false, Desc: expandDescription("[orep_custom_splinters]") },
		Info: expandDescription("[orep_config_bool_info]")
	},
};
this.startUp = function () {
	this._oreTimer = new Timer(this, this.$processOre.bind(this), 5, 0.5);
	this._oreTimer.stop();
	this._scanTimer = new Timer(this, this.$scanForMinerals.bind(this), 1, 1);
	this._scanTimer.stop();
	this._mySound = new SoundSource;
	this._scanSound = new SoundSource;
	this._mySound.sound = "op_process.ogg";
	this._mySound.loop = false;
	this._powerDrain = 6.4;
	this._scanDrain = 3.2;
	this._spec = {
		"300": { type: "alloys", quantity: 1, message: expandDescription("[orep_extract_alloys]") },
		"315": { type: "gem_stones", quantity: -5, message: expandDescription("[orep_extract_gems]") },
		"330": { type: "gem_stones", quantity: -7, message: expandDescription("[orep_extract_gems]") },
		"346": { type: "gem_stones", quantity: -10, message: expandDescription("[orep_extract_gems]") },
		"386": { type: "gold", quantity: -2, message: expandDescription("[orep_extract_gold]") },
		"396": { type: "gold", quantity: -3, message: expandDescription("[orep_extract_gold]") },
		"406": { type: "gold", quantity: -6, message: expandDescription("[orep_extract_gold]") },
		"421": { type: "platinum", quantity: -2, message: expandDescription("[orep_extract_platinum]") },
		"444": { type: "platinum", quantity: -3, message: expandDescription("[orep_extract_platinum]") },
		"452": { type: "platinum", quantity: -6, message: expandDescription("[orep_extract_platinum]") },
		"592": { type: "radioactives", quantity: 1, message: expandDescription("[orep_extract_radioactives]") },
		"-99": { type: "minerals", quantity: 1, message: expandDescription("[orep_extract_minerals]") },
	};
	if (missionVariables.OreProcessor) {
		this._opConfig = JSON.parse(missionVariables.OreProcessor);
	}
}
this.startUpComplete = function () {
	// register our settings, if Lib_Config is present
	if (worldScripts.Lib_Config) {
		var lib = worldScripts.Lib_Config;
		lib._registerSet(this._opConfig);
	}
}
this.playerWillSaveGame = function () {
	missionVariables.OreProcessor = JSON.stringify(this._opConfig);
}
this.shipDockedWithStation = function (station) {
	this._splinter.length = 0; // cleanup
	if (this.shipTargetAcquired) delete this.shipTargetAcquired;
}
this.shipWillLaunchFromStation = function(station) {
	if (player.ship.equipmentStatus("EQ_HARDWIRE_ORE_SCANNER") == "EQUIPMENT_OK" && player.ship.equipmentStatus("EQ_ORE_SCANNER") == "EQUIPMENT_OK") 
		this.shipTargetAcquired = this.hold_shipTargetAcquired;
}
this.playerBoughtEquipment = function (equipment) {
	var p = player.ship;
	if (equipment === "EQ_UNDO_HARDWIRE_ORE_PROCESSOR") {
		p.removeEquipment("EQ_HARDWIRE_ORE_PROCESSOR");
		p.removeEquipment("EQ_UNDO_HARDWIRE_ORE_PROCESSOR");
		return;
	}
	if (equipment === "EQ_UNDO_HARDWIRE_ORE_SCANNER") {
		p.removeEquipment("EQ_HARDWIRE_ORE_SCANNER");
		p.removeEquipment("EQ_UNDO_HARDWIRE_ORE_SCANNER");
		return;
	}
	if (equipment == "EQ_HARDWIRE_ORE_PROCESSOR" || equipment == "EQ_HARDWIRE_ORE_SCANNER") {
		var eq1 = p.equipmentStatus("EQ_HARDWIRE_ORE_PROCESSOR");
		var eq2 = p.equipmentStatus("EQ_HARDWIRE_ORE_SCANNER");
		if (eq1 == "EQUIPMENT_OK" && eq2 == "EQUIPMENT_OK") {
			var eq = p.equipmentStatus("EQ_ORE_PROCESSOR");
			p.awardEquipment("EQ_ORE_PROCESSOR_FULLAUTO");
			p.setEquipmentStatus("EQ_ORE_PROCESSOR_FULLAUTO", eq);
			p.removeEquipment("EQ_ORE_PROCESSOR");
		}
	}
}
this.equipmentRemoved = function(equipment) {
	if (equipment == "EQ_HARDWIRE_ORE_PROCESSOR" || equipment == "EQ_HARDWIRE_ORE_SCANNER") {
		var p = player.ship;
		var installed = ["EQUIPMENT_OK", "EQUIPMENT_DAMAGED"];
		var status = p.equipmentStatus("EQ_ORE_PROCESSOR_FULLAUTO");
		if (installed.indexOf(status) >= 0) {
			p.awardEquipment("EQ_ORE_PROCESSOR");
			p.setEquipmentStatus("EQ_ORE_PROCESSOR", status);
			p.removeEquipment("EQ_ORE_PROCESSOR_FULLAUTO");
		}
	}
}
this.hold_shipTargetAcquired = function(target) {
	if (player.ship.equipmentStatus("EQ_HARDWIRE_ORE_SCANNER") != "EQUIPMENT_OK" || this.$checkEquipment() != "EQUIPMENT_OK") return;
	if (this._scanTimer.isRunning) {
		this._scanTimer.stop();
		this._scanSound.stop();
	}
	if ((target.primaryRole == "splinter" || target.primaryRole == "griff_splinter") && target.displayName.indexOf("(") == -1 && player.ship.position.distanceTo(target) <= 2500) {
		this.$activateScan();
	}
}
// Add scooped splinter to splinter array.
this.shipScoopedOther = function (whom) {
	// Check that the scooped item is a splinter, contains minerals and is not scripted
	if ((whom.primaryRole !== "splinter" && whom.primaryRole !== "griff_splinter") || whom.commodity !== "minerals" || whom.script.name !== "oolite-default-ship-script") return;
	// Check that the splinter is not already added to prevent double booking. This happens when scooping, dumping, scooping...
	for (var i = 0; i < this._splinter.length; i++) {
		if (this._splinter[i] === whom)
			this._splinter.splice(i, 1);
	}
	// Add valuables to the scooped splinter
	this.$addValuablesToSplinter(whom);
	// Add unprocessed scooped splinter to the list of unprocessed splinters
	if (whom.$oreProcessor.count > 0) this._splinter.push(whom);
	// Automagically start processing if the processor has been hardwired
	if (player.ship.equipmentStatus("EQ_HARDWIRE_ORE_PROCESSOR") === "EQUIPMENT_OK" && this.$checkEquipment() === "EQUIPMENT_OK" && this._splinter.length > 0 && !this._oreTimer.isRunning) {
		this.$extract();
	}
}
this.$processOre = function $processOre() {
	// remove lost splinters from the array and stop processing if we run out splinters
	while (this._splinter[0].status !== "STATUS_IN_HOLD") {
		// remove dumped splinter from process array
		this._splinter.shift();
		// stop processing if out of splinters
		if (this._splinter.length === 0) {
			this._oreTimer.stop();
			this._mySound.stop();
			return;
		}
	}
	// busy processing splinter
	if (parseInt(this._splinter[0].$oreProcessor.count) > 0 && player.ship.energy > this._powerDrain) {
		player.consoleMessage(expandDescription("[orep_processing]"));
		this._splinter[0].$oreProcessor.count--;
		player.ship.energy -= this._powerDrain;
	} else {
		if (this.toggle) this.toggle = false;
		else this.toggle = true; // to avoid identical message suppression.
		if (parseInt(this._splinter[0].$oreProcessor.count) === 0) {
			// process splinter
			if (this._splinter[0].status === "STATUS_IN_HOLD") {
				player.consoleMessage(expandDescription(this._splinter[0].$oreProcessor.message) + (this.toggle ? "" : " "));
				this._splinter[0].setCargo(this._splinter[0].$oreProcessor.type, this._splinter[0].$oreProcessor.quantity);
				this._splinter[0].displayName = expandDescription("[orep_process_splinter]", { commodity: displayNameForCommodity(this._splinter[0].$oreProcessor.type) });
				this._splinter.shift(); // remove the processed splinter from the unprocessed splinter array.
				// notify manifest_mfd about content cargo change
				if (worldScripts["manifest_mfd"])
					worldScripts["manifest_mfd"].notifyCargoChange();
			}
		} else {
			// stop processing if out of energy
			player.consoleMessage(expandDescription("[orep_no_energy]"));
			this._oreTimer.stop();
			this._mySound.stop();
			return;
		}
		// restart the sound for next splinter
		if (this._splinter.length > 0) this._mySound.play(10);
		else {
			// last splinter processed, lets stop
			this._oreTimer.stop();
			this._mySound.stop();
		}
	}
}
// Add contents to splinters
this.$addValuablesToSplinter = function $addValuablesToSplinter(ship) {
	// Check if the splinter has already been handled
	if (!ship.$oreProcessor) {
		var type, quantity, message;
		// handle custom splinters
		if (ship.scriptInfo.cargotype) {
			type = ship.scriptInfo.cargotype;
			quantity = parseInt(ship.scriptInfo.quantity);
			message = ship.scriptInfo.message;
		}
		// handle regular splinters
		else {
			var randomOre = Math.floor(992 * Math.random()); //0 - 991
			var ranges = Object.keys(this._spec);
			var found = false;
			for (var i = 0; i < ranges.length; i++) {
				if (randomOre < parseInt(ranges[i])) {
					var range = this._spec[ranges[i]];
					type = range.type;
					quantity = range.quantity;
					message = range.message;
					found = true;
					break;
				}
			}
			if (found === false) {
				type = this._spec["-99"].type;
				quantity = this._spec["-99"].quantity;
				message = this._spec["-99"].message;
			}
		}
		if (quantity < 0) quantity = Math.ceil(Math.random() * (-quantity)); // only negative values are randomised.
		ship.$oreProcessor = {
			message: message.replace("@1", quantity),
			type: type,
			quantity: quantity,
			// randomize hardness of the splinter
			count: 5 + Math.random() * 15
		};
	}
}
//Activate/deactivate the ore processor
this.$extract = function $extract() {
	// Start processing
	if (!this._oreTimer.isRunning) {
		if (player.ship.energy > this._powerDrain) {
			var process = false;
			// check that there is a splinter to process in the hold. If unprocessed splinter has been dumped or it is destroyed, it cannot be processed, thus the record is removed.
			for (var i = this._splinter.length - 1; i >= 0; i--) {
				if (this._splinter[i].status === "STATUS_IN_HOLD") {
					process = true;
					break;
				} else this._splinter.pop();
			}
			// found something to process, let's go
			if (process) {
				this._oreTimer.start();
				if (!this._mySound.isPlaying) this._mySound.play(10);
			}
			// nothing to process, let's not go
			else player.consoleMessage(expandDescription("[orep_no_splinters]"));
		} else player.consoleMessage(expandDescription("[orep_insufficient_energy]"));
	}
	// Stop processing
	else {
		this._oreTimer.stop();
		this._mySound.stop();
		player.consoleMessage(expandDescription("[orep_abort_process]"));
	}
}
// Activate scan
this.$activateScan = function $activateScan() {
	if (!this._scanTimer.isRunning) {
		if (player.ship.energy > this._scanDrain) {
			this.$pass = 0;
			this.$originalTarget = player.ship.target;
			//randomize the time that a scan will take.
			//this.$scanRounds = 5 + Math.round(Math.random() * 5);
			this._scanTimer = new Timer(this, this.$scanForMinerals.bind(this), 0);
		} else player.consoleMessage(expandDescription("[orep_insufficient_energy_scan]"));
	} else {
		this._scanTimer.stop();
		this._scanSound.stop();
		player.consoleMessage(expandDescription("[orep_abort_scan]"));
	}
}
// The actual scanning function
this.$scanForMinerals = function $scanForMinerals() {
	var target = player.ship.target;
	// notify sound
	this._scanSound.sound = "[@boop]";
	// No target
	if (!target) {
		this._scanSound.play();
		player.consoleMessage(expandDescription("[orep_no_target]"));
		return;
	}
	// Target switched while scanning
	if (this.$originalTarget !== target) {
		this._scanSound.play();
		player.consoleMessage(expandDescription("[orep_target_lost]"));
		return;
	}
	// Target is not a splinter
	if (target.primaryRole !== "splinter" && target.primaryRole !== "griff_splinter") {
		this._scanSound.play();
		player.consoleMessage(expandDescription("[orep_not_splinter]"));
		return;
	}
	// Target is too far
	if (player.ship.position.distanceTo(target) > 2500) {
		this._scanSound.play();
		player.consoleMessage(expandDescription("[orep_too_far]"));
		return;
	}
	// Valuables are already detected
	if (target.displayName.indexOf("(") !== -1) {
		this._scanSound.play();
		player.consoleMessage(expandDescription("[orep_already_scanned]"));
		return;
	}
	// If enough energy, scan
	if (player.ship.energy > this._scanDrain) {
		this._scanSound.sound = "op_scan.ogg";
		this._scanSound.play();
		if (this.$pass < 9 /*this.$scanRounds*/) {
			player.consoleMessage(expandDescription("[orep_scanning]"));
			player.ship.energy -= this._scanDrain;
			this.$pass++;
			this._scanTimer = new Timer(this, this.$scanForMinerals.bind(this), 0.5);
			return;
		} else {
			this.$addValuablesToSplinter(target);
			if (target.$oreProcessor.type !== "minerals") {
				this.$addValuablesToSplinter(target);
				player.consoleMessage(expandDescription("[orep_detected]", {commodity:displayNameForCommodity(target.$oreProcessor.type)}));
				target.displayName = target.name + " (" + displayNameForCommodity(target.$oreProcessor.type) + ")";
				return;
			}
		}
	}
	// Energy low, abort
	else {
		this._scanSound.play();
		player.consoleMessage(expandDescription("[orep_no_energy_scan]"));
		return;
	}
	// No valuables found
	player.consoleMessage(expandDescription("[orep_nothing_special]"));
	target.displayName = target.name + expandDescription("[orep_common_minerals]");
}
this.$checkEquipment = function() {
	var eq1 = player.ship.equipmentStatus("EQ_ORE_SCANNER");
	var eq2 = player.ship.equipmentStatus("EQ_ORE_SCANNER_FULLAUTO");
	if (eq1 == "EQUIPMENT_OK" || eq1 == "EQUIPMENT_DAMAGED") return eq1;
	return eq2;
} |