Q-Charger, if activated, operates while speed is between 95% and 100%. FICC operates at maxSpeed (100%). Instead of disabling FICC when Q-Charger is active at 100%, I'd like it if FICC would disable Q-Charger, so Q-Charger would be for 95-99% and FICC would be for 100%. I think you could call worldScripts.Q-Charger.qchargerCheckTimer.stop(); when FICC starts and start the timer when FICC stops (only if it was running before).
Something like this:
Code: Select all
"use strict";
this.name = "FuelInjectionCruiseControl";
this.author = "phkb";
this.copyright = "2018 phkb";
this.description = "Mode/Activation code for the FICC equipment";
this.licence = "CC BY-NC-SA 4.0";
this._bgs = false; // is BGS installed?
this._qcharger = false; // is the Q-Charger OXP installed?
this._surjectors = false; // is the Surjectors OXP installed?
this._engaged = false;
this._autoEngage = true;
this._disableAutoOnRedAlert = false;
this._disableAutoOnDocking = false;
this._trueValues = ["yes", "1", 1, "true", true];
/*
TODO:
Can we get the space dust effect to work the same as it does for normal injectors?
Chase mode - match speed to target, or match speed when within 10km of target?
*/
// Library config
this._libraryConfig = {
Name: this.name,
Alias: "Fuel Injection Cruise Control",
Display: "Config",
Alive: "_libraryConfig",
Bool: {
B0: {
Name: "_autoEngage",
Def: true,
Desc: "Auto-engage FICC"
},
B1: {
Name: "_disableAutoOnRedAlert",
Def: false,
Desc: "Red alert disable auto on"
},
B2: {
Name: "_disableAutoOnDocking",
Def: false,
Desc: "Docking disable auto on"
},
Info: "0 - Auto-engage FICC when maximum speed reached.\n1 - Disable auto on feature during red alert condition.\n2 - Disable auto on feature during docking."
},
};
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
if (worldScripts.BGS) this._bgs = true;
if (worldScripts["Q-Charger"]) this._qcharger = true;
if (worldScripts.Surjectors) this._surjectors = true;
if (missionVariables.FICC_AutoEngage) this._autoEngage = (this._trueValues.indexOf(missionVariables.FICC_AutoEngage) >= 0 ? true : false);
// register our settings, if Lib_Config is present
if (worldScripts.Lib_Config) {
worldScripts.Lib_Config._registerSet(this._libraryConfig);
// only restore settings if library config is present - otherwise, we'll keep the values set in the script (in case of manual override)
if (missionVariables.FICC_AutoEngageRedAlertDisable) this._disableAutoOnRedAlert = (this._trueValues.indexOf(missionVariables.FICC_AutoEngageRedAlertDisable) >= 0 ? true : false);
if (missionVariables.FICC_AutoEngageDockingDisable) this._disableAutoOnDocking = (this._trueValues.indexOf(missionVariables.FICC_AutoEngageDockingDisable) >= 0 ? true : false);
}
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function () {
missionVariables.FICC_AutoEngage = this._autoEngage;
if (worldScripts.Lib_Config) {
missionVariables.FICC_AutoEngageRedAlertDisable = this._disableAutoOnRedAlert;
missionVariables.FICC_AutoEngageDockingDisable = this._disableAutoOnDocking;
} else {
delete missionVariables.FICC_AutoEngageRedAlertDisable;
delete missionVariables.FICC_AutoEngageDockingDisable;
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipWillLaunchFromStation = function (station) {
var p = player.ship, ps = p.script;
ps._fuelDeduct = 0;
ps._qcharger_toggled = false;
ps._surjectorsApplied = false;
ps._surjectors = (this._surjectors === true);
}
//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation = this.shipExitedWitchspace = function () {
var p = player.ship, ps = p.script;
ps._qchargerCheck = (this._qcharger === true && p.equipmentStatus("EQ_Q-CHARGER") === "EQUIPMENT_OK" && ((p.equipmentStatus("EQ_ENERGY_UNIT") === "EQUIPMENT_OK") || (p.equipmentStatus("EQ_NAVAL_ENERGY_UNIT") === "EQUIPMENT_OK")));
ps._ficc_ok = (p.hasEquipmentProviding("EQ_FUEL_INJECTION") === true && p.equipmentStatus("EQ_FUEL_INJECTION_CRUISECONTROL") === "EQUIPMENT_OK");
if (this._autoEngage === true) {
this.$startCheckSpeedFCB(true);
}
}
//-------------------------------------------------------------------------------------------------------------
this.shipDied = this.shipWillDockWithStation = this.shipWillEnterWitchspace = function () {
if (isValidFrameCallback(this._fcbID)) removeFrameCallback(this._fcbID);
// turn the speed check fcb off as well, although if this is the shipWillEnterWitchspace event, it will be turned back on again when we exit witchspace
if (isValidFrameCallback(this._checkSpeedFCB)) removeFrameCallback(this._checkSpeedFCB);
}
//-------------------------------------------------------------------------------------------------------------
this.playerRequestedDockingClearance = function (message) {
var ps = player.ship.script;
if (message === "DOCKING_CLEARANCE_GRANTED" || message === "DOCKING_CLEARANCE_EXTENDED" || message === "DOCKING_CLEARANCE_DENIED_TRAFFIC_INBOUND" || message === "DOCKING_CLEARANCE_DENIED_TRAFFIC_OUTBOUND") {
ps._ficc_playerIsDocking = true;
} else {
ps._ficc_playerIsDocking = false;
}
}
//-------------------------------------------------------------------------------------------------------------
// for oolite 1.85++
this.playerDockingClearanceCancelled = function () {
var ps = player.ship.script;
ps._ficc_playerIsDocking = false;
}
//-------------------------------------------------------------------------------------------------------------
// for oolite 1.83++
this.playerDockingClearanceExpired = function () {
this.playerDockingClearanceCancelled();
}
//-------------------------------------------------------------------------------------------------------------
this.activated = function () {
var ficc = worldScripts.FuelInjectionCruiseControl;
// if it's already on, turn it off
if (isValidFrameCallback(ficc._fcbID)) {
player.consoleMessage(expandDescription("[ficc_disengaged]"));
ficc.$playSound("engineDown");
ficc.$stopFCB();
return;
}
var p = player.ship;
if (p.torusEngaged) {
player.consoleMessage(expandDescription("[ficc_torus]"));
return;
}
// no injectors
if (p.hasEquipmentProviding("EQ_FUEL_INJECTION") === false) {
player.consoleMessage(expandDescription("[ficc_unavailable]"));
return;
}
// no fuel
if (p.fuel <= 0) {
player.consoleMessage(expandDescription("[fuel-out]"));
return;
}
// not at max speed
if (p.speed < p.maxSpeed) {
player.consoleMessage(expandDescription("[ficc_accelerate]"));
return;
}
// qcharger only operates if fuel is >= 0.1 and there is a working energy unit (normal or naval)
// if (p.equipmentStatus("EQ_Q-CHARGER") === "EQUIPMENT_OK" &&
// (worldScripts["Q-Charger"].qchargercondition === "ON" || (p.fuel >= 0.1 && (p.equipmentStatus("EQ_ENERGY_UNIT") == "EQUIPMENT_DAMAGED" || p.equipmentStatus("EQ_NAVAL_ENERGY_UNIT") === "EQUIPMENT_DAMAGED")))) {
// player.consoleMessage(expandDescription("[ficc_qcharger]"));
// return;
// }
player.consoleMessage(expandDescription("[ficc_engaged]"));
ficc.$startFCB();
}
//-------------------------------------------------------------------------------------------------------------
this.mode = function () {
var ficc = worldScripts.FuelInjectionCruiseControl;
if (isValidFrameCallback(ficc._checkSpeedFCB)) {
ficc._autoEngage = false;
removeFrameCallback(ficc._checkSpeedFCB);
player.consoleMessage(expandDescription("[ficc_autoEngageOff]"));
if (ficc._engaged) this.activated();
} else {
// start a fcb to monitor speed and auto-engage CC when max speed reached
ficc._autoEngage = true;
ficc.$startCheckSpeedFCB(false)
}
}
//-------------------------------------------------------------------------------------------------------------
this.equipmentDamaged = function (equipmentKey) {
var p = player.ship, ps = p.script;
if (!ps) return; // script is undefined when player ship is destroyed
if (p.equipmentStatus("EQ_FUEL_INJECTION_CRUISECONTROL") !== "EQUIPMENT_OK" || p.hasEquipmentProviding("EQ_FUEL_INJECTION") === false) {
ps._ficc_ok = false;
if (isValidFrameCallback(this._fcbID)) {
player.consoleMessage(expandDescription("[ficc_disengaged]"));
this.$playSound("engineDown");
this.$stopFCB();
}
if (isValidFrameCallback(this._checkSpeedFCB)) removeFrameCallback(this._checkSpeedFCB);
}
// monitor when the qcharger state changes (needs either EQ_ENERGY_UNIT or EQ_NAVAL_ENERGY_UNIT in addition to its own equipment)
if ( this._qcharger === true && ps._qchargerCheck === true &&
(p.equipmentStatus("EQ_Q-CHARGER") !== "EQUIPMENT_OK" || (p.equipmentStatus("EQ_ENERGY_UNIT") !== "EQUIPMENT_OK" && p.equipmentStatus("EQ_NAVAL_ENERGY_UNIT") !== "EQUIPMENT_OK")) ) {
ps._qchargerCheck = false;
}
}
//-------------------------------------------------------------------------------------------------------------
this.equipmentRepaired = function (equipmentKey) { // if in-flight repairs restored functionality
if (player.ship.status === "STATUS_IN_FLIGHT") this.shipLaunchedFromStation(); // check FICC and Q-Charger equipment and re-activate FICC auto-engage monitoring FCB if configured to do so
}
//-------------------------------------------------------------------------------------------------------------
this.$startFCB = function $startFCB() {
var p = player.ship;
p.script._soundCounter = 0;
p.script._accel = (p.speed / (p.maxSpeed * p.injectorSpeedFactor));
if (p.script._accel > 1) p.script._accel = 1; // in case we're slowing from torus speed
// turn on some flags so other OXP's have an easier way of determining that the ficc is engaged
this._engaged = true;
p.script._ficcEngaged = true;
// only play the engine up sound if we are actually speeding up
if (p.speed < (p.maxSpeed * p.injectorSpeedFactor)) this.$playSound("engineUp");
this.$playSound("afterburner");
// set up the frame callback
this._fcbID = addFrameCallback(function _fcbID(delta) {
var p = (_fcbID.p = _fcbID.p || player.ship), ps = (_fcbID.ps = _fcbID.ps || p.script); // cache the player.ship and player.ship.script references
var ficc = (_fcbID.ficc = _fcbID.ficc || worldScripts.FuelInjectionCruiseControl); // cache the worldScript reference
var wsq = (_fcbID.wsq = _fcbID.wsq || worldScripts["Q-Charger"]); // cache the worldScript reference
if (!p || !p.isValid || !ps._ficc_ok) {
ficc.$stopFCB();
return;
}
if (p.torusEngaged || p.injectorsEngaged) {
player.consoleMessage(expandDescription("[ficc_disengaged]"));
ficc.$stopFCB();
return;
}
if (p.speed < p.maxSpeed) {
player.consoleMessage(expandDescription("[ficc_disengaged]"));
ficc.$playSound("engineDown");
ficc.$stopFCB();
return;
}
if (p.fuel <= 0) {
player.consoleMessage(expandDescription("[fuel-out]"));
ficc.$playSound("engineDown");
ficc.$stopFCB();
return;
}
if (ps._qchargerCheck === true) { // this is a do-once
if (wsq.qchargerenabled) {
// FICC takes over from Q-Charger at 100% speed (Q-Charger handles 95-99% speed)
ps._qcharger_toggled = true;
wsq.qchargerCheckTimer.stop(); // stop Q-Charger's timer while FICC is running (expectation, currently true: if the player toggles Q-Charger manually, it doesn't restart the timer)
//ficc.$playSound("engineDown");
//ficc.$stopFCB();
//return;
}
ps._qchargerCheck = false; // don't need to check Q-Charger again while FICC is running
}
ps._soundCounter += delta;
if (ps._soundCounter > 1) {
ps._soundCounter = 0;
ficc.$playSound("afterburner");
}
// note: this method will not change the actual speed of the ship,
// so I've included the requirement that the ship must be at full speed before engaging
// velocity adjustment method
p.velocity = p.vectorForward.multiply(parseFloat(p.maxSpeed * p.injectorSpeedFactor) * ps._accel);
if (ps._accel < 1) ps._accel += 0.01 + (p.maxThrust / 15000);
else if (ps._accel > 1) ps._accel = 1;
// deduct fuel
var br = p.injectorBurnRate;
// surjectors changes the way injectors work at the base level, rather than at an equipment level
// so, if the OXP is installed, and weapons are offline, the code kicks in
// because we are simulating injectors here, not actually doing injectors, we need to implement the surjector code
if (ps._surjectors && !p.weaponsOnline) {
ps._surjectorsApplied = true;
br = 0.01;
p.aftShield -= 0.1;
p.forwardShield -= 0.1;
p.aftShieldRechargeRate = 0;
p.forwardShieldRechargeRate = 0;
p.energyRechargeRate = 0;
}
ps._fuelDeduct += ((br / 10) * delta);
if (ps._fuelDeduct > 0.1) {
p.fuel -= 0.1;
ps._fuelDeduct -= 0.1;
if (p.fuel < 0) p.fuel = 0;
}
});
}
//-------------------------------------------------------------------------------------------------------------
this.$stopFCB = function $stopFCB() {
if (isValidFrameCallback(this._fcbID)) {
removeFrameCallback(this._fcbID);
var p = player.ship, ps = p.script;
ps._ficcEngaged = false;
this._engaged = false;
// restore surjector shield/energy recharge rates
if (ps._surjectorsApplied) {
var s = worldScripts.Surjectors;
if (!p.injectorsEngaged) { // don't reset anything if the injectors are engaged, otherwise we might override surjectors
p.aftShieldRechargeRate = s.$savedAftRate;
p.forwardShieldRechargeRate = s.$savedFwdRate;
p.energyRechargeRate = s.$savedERate;
}
ps._surjectorsApplied = false;
}
// reset velocity
// we have to set this back to the current speed value, otherwise we'll get the "sliding" issue
p.velocity = p.vectorForward.multiply(p.speed);
// resume Q-Charger if it was active before FICC took over
if (ps._qcharger_toggled === true) {
ps._qcharger_toggled = false;
worldScripts["Q-Charger"].qchargerCheckTimer.start();
}
ps._qchargerCheck = true; // need to check Q-Charger again next time FICC starts
}
}
//-------------------------------------------------------------------------------------------------------------
this.$startCheckSpeedFCB = function $startCheckSpeedFCB(silent) {
var p = player.ship, ps = p.script;
if (ps._ficc_ok) {
if (silent === false) player.consoleMessage(expandDescription("[ficc_autoEngageOn]"));
this._checkSpeedFCB = addFrameCallback(function _checkSpeedFCB(delta) {
var p = (_checkSpeedFCB.p = _checkSpeedFCB.p || player.ship); // cache the player.ship reference
if (p && p.isInSpace && p.isValid) { // removed && p.script._qchargerCheck === false
var ficc = (_checkSpeedFCB.ficc = _checkSpeedFCB.ficc || worldScripts.FuelInjectionCruiseControl); // cache the worldScript reference
if (p.speed == p.maxSpeed && p.fuel > 0 && p.torusEngaged === false && p.injectorsEngaged === false && !isValidFrameCallback(ficc._fcbID)) {
var _disableAutoOnRedAlert = (_checkSpeedFCB._disableAutoOnRedAlert = _checkSpeedFCB._disableAutoOnRedAlert || ficc._disableAutoOnRedAlert); // cache the config value
var _disableAutoOnDocking = (_checkSpeedFCB._disableAutoOnDocking = _checkSpeedFCB._disableAutoOnDocking || ficc._disableAutoOnDocking); // cache the config value
if (_disableAutoOnRedAlert && p.alertCondition === 3) return;
if (_disableAutoOnDocking && p.script._ficc_playerIsDocking) return;
ficc.activated();
}
}
});
}
}
//-------------------------------------------------------------------------------------------------------------
// player the buy/sell sound effects
this.$playSound = function $playSound(soundtype) {
var mySound;
switch (soundtype) {
case "afterburner":
mySound = new SoundSource;
mySound.sound = "afterburner1.ogg";
break;
case "engineUp":
if (this._bgs) {
mySound = new SoundSource;
mySound.sound = worldScripts.BGS.$BGS.def["engineUp"];
} else return;
break;
case "engineDown":
if (this._bgs) {
mySound = new SoundSource;
mySound.sound = worldScripts.BGS.$BGS.def["engineDown"];
} else return;
break;
}
mySound.loop = false;
mySound.play();
}
I've implemented my idea, made some other optimizations and added extra checks (like checking if FICC equipment is still undamaged in the FCB, not just when starting FICC mode, but doing it by checking a flag on the script that gets updated by the event handlers so we don't have to scan the equipment list on every frame) and handling for in-flight repairs, and tested the basic functionality, which seems to be working as intended. (I didn't test damage/repair.)
TODO: I would prefer to remove the primeable equipment and make autoEngage mode always active, and the chase mode idea is interesting. Maybe as a safety feature, disengage injectors automatically if less than 1km from the target and player heading angle to player-target vector is under 2 degrees +/-, i.e., target is close and in front of the player.