From edf4a70ed664dc5e43df16e9e64a895daa7be5f3 Mon Sep 17 00:00:00 2001 From: Samuel Deutsch Date: Thu, 16 Feb 2023 18:06:11 -0800 Subject: [PATCH] Refuel - Added ability to refuel fuel sources (#8981) * Simplify main fuel loop * Remove unecessary action macro * Add container refueling * Fuel counter behaviour is now consistent for both limited and unlimited fuel sources * Update maxFuel and refuelContainer whenever fueling begins * Update maxFuel and refuelContainer whenever fueling begins * Prevent loading of fuel sources into cargo when they have a nozzle connected to them * Added action to check how much fuel is left in a jerry can * Prevent jerry cans from being picked up if they have a nozzle connected to them * Added function to check if a nozzle can be connected to an object * Prevent fuel sources which have their nozzle deployed from being loaded * Compute both tank volumes inside of refuel instead of durring turn on * Didn't mean to delete these * Allow for user defined fuel capacities * Handle more edge cases with infinite fuel sources * Refuel - Prevent fuel sources from being dragged while they're refueling other things * Refuel - Added flow rate multiplier for refueling fuel sources * Refuel - Use FUNC instead of DFUNC for nozzle actions * Refuel - getCapacity should return REFUEL_DISABLED_FUEL instead of 0 when argument is not a fuel source * Refuel - Correctly reset fuel counter when fueling a new target * Refuel - Implemented all suggested changes * Refuel - Added newlines to end of files * Refuel - Added missing newline at end of XEH_PREP * Only setFuel once per jerry can creation Co-authored-by: PabstMirror * Calling getFuel will initialize the fuel source * Refuel - Add newline to end of file --------- Co-authored-by: BaerMitUmlaut Co-authored-by: PabstMirror --- AUTHORS.txt | 3 +- addons/cargo/functions/fnc_canLoadItemIn.sqf | 4 +- addons/refuel/CfgVehicles.hpp | 91 +++++++------- addons/refuel/XEH_PREP.hpp | 2 + addons/refuel/XEH_postInit.sqf | 2 +- addons/refuel/config.cpp | 2 +- addons/refuel/functions/fnc_canCheckFuel.sqf | 2 +- .../refuel/functions/fnc_canConnectNozzle.sqf | 30 +++++ addons/refuel/functions/fnc_canTakeNozzle.sqf | 3 +- addons/refuel/functions/fnc_canTurnOn.sqf | 22 +++- .../functions/fnc_connectNozzleAction.sqf | 39 ++++-- addons/refuel/functions/fnc_disconnect.sqf | 8 +- addons/refuel/functions/fnc_dropNozzle.sqf | 2 +- addons/refuel/functions/fnc_getCapacity.sqf | 35 ++++++ addons/refuel/functions/fnc_getFuel.sqf | 4 +- addons/refuel/functions/fnc_makeJerryCan.sqf | 30 ++++- addons/refuel/functions/fnc_makeSource.sqf | 6 +- .../functions/fnc_onMouseButtonDown.sqf | 3 +- .../refuel/functions/fnc_readFuelCounter.sqf | 10 +- addons/refuel/functions/fnc_refuel.sqf | 115 ++++++++++-------- addons/refuel/functions/fnc_returnNozzle.sqf | 4 + addons/refuel/functions/fnc_setFuel.sqf | 11 +- .../functions/fnc_startNozzleInHandsPFH.sqf | 5 +- addons/refuel/functions/fnc_takeNozzle.sqf | 7 ++ addons/refuel/functions/fnc_turnOn.sqf | 4 +- addons/refuel/initSettings.sqf | 9 ++ addons/refuel/stringtable.xml | 10 ++ 27 files changed, 321 insertions(+), 142 deletions(-) create mode 100644 addons/refuel/functions/fnc_canConnectNozzle.sqf create mode 100644 addons/refuel/functions/fnc_getCapacity.sqf diff --git a/AUTHORS.txt b/AUTHORS.txt index 544a7d36b6..3c831bb7f7 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -145,6 +145,7 @@ PiZZADOX <509thParachuteInfantry@gmail.com> pokertour Professor Pterolatypus +QuantX QuickDagger rakowozz ramius86 @@ -182,4 +183,4 @@ wizpig64 YetheSamartaka xrufix Zakant -zGuba +zGuba \ No newline at end of file diff --git a/addons/cargo/functions/fnc_canLoadItemIn.sqf b/addons/cargo/functions/fnc_canLoadItemIn.sqf index 906bcc8868..1522ba3ff1 100644 --- a/addons/cargo/functions/fnc_canLoadItemIn.sqf +++ b/addons/cargo/functions/fnc_canLoadItemIn.sqf @@ -36,7 +36,9 @@ if (_item isEqualType "") then { _validItem = (alive _item) && {_ignoreInteraction || {([_item, _vehicle] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}} && - {!(_item getVariable [QEGVAR(cookoff,isCookingOff), false])}; + {!(_item getVariable [QEGVAR(cookoff,isCookingOff), false])} && + {isNull(_item getVariable [QEGVAR(refuel,nozzle), objNull])} && // Objects which have a refueling nozzle connected to them cannot be loaded + {isNull(_item getVariable [QEGVAR(refuel,ownedNozzle), objNull])}; // Fuel sources which have their nozzle out cannot be loaded }; _validItem && diff --git a/addons/refuel/CfgVehicles.hpp b/addons/refuel/CfgVehicles.hpp index 6415ab97e1..5fba336943 100644 --- a/addons/refuel/CfgVehicles.hpp +++ b/addons/refuel/CfgVehicles.hpp @@ -1,45 +1,3 @@ -#define MACRO_NOZZLE_ACTIONS \ - class ACE_Actions { \ - class ACE_MainActions { \ - displayName = CSTRING(Refuel); \ - distance = REFUEL_ACTION_DISTANCE; \ - position = "[0,-0.025,0.125]"; \ - condition = "true"; \ - statement = ""; \ - exceptions[] = {INTERACT_EXCEPTIONS}; \ - showDisabled = 0; \ - icon = QPATHTOF(ui\icon_refuel_interact.paa); \ - class GVAR(PickUpNozzle) { \ - displayName = CSTRING(TakeNozzle); \ - condition = QUOTE([ARR_2(_player,_target)] call FUNC(canTakeNozzle)); \ - statement = QUOTE([ARR_2(_player,_target)] call FUNC(takeNozzle)); \ - exceptions[] = {INTERACT_EXCEPTIONS_REFUELING}; \ - icon = QPATHTOF(ui\icon_refuel_interact.paa); \ - }; \ - class GVAR(TurnOn) { \ - displayName = CSTRING(TurnOn); \ - condition = QUOTE([ARR_2(_player,_target)] call FUNC(canTurnOn)); \ - statement = QUOTE([ARR_2(_player,_target)] call DFUNC(turnOn)); \ - exceptions[] = {INTERACT_EXCEPTIONS}; \ - icon = QPATHTOF(ui\icon_refuel_interact.paa); \ - }; \ - class GVAR(TurnOff) { \ - displayName = CSTRING(TurnOff); \ - condition = QUOTE([ARR_2(_player,_target)] call FUNC(canTurnOff)); \ - statement = QUOTE([ARR_2(_player,_target)] call DFUNC(turnOff)); \ - exceptions[] = {INTERACT_EXCEPTIONS}; \ - icon = QPATHTOF(ui\icon_refuel_interact.paa); \ - }; \ - class GVAR(Disconnect) { \ - displayName = CSTRING(Disconnect); \ - condition = QUOTE([ARR_2(_player,_target)] call FUNC(canDisconnect)); \ - statement = QUOTE([ARR_2(_player,_target)] call DFUNC(disconnect)); \ - exceptions[] = {INTERACT_EXCEPTIONS_REFUELING}; \ - icon = QPATHTOF(ui\icon_refuel_interact.paa); \ - }; \ - }; \ - } - class CBA_Extended_EventHandlers; class CfgNonAIVehicles { @@ -91,12 +49,59 @@ class CfgVehicles { class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {}; }; - MACRO_NOZZLE_ACTIONS; displayName = QGVAR(fuelNozzle); scope = 1; scopeCurator = 1; model = QPATHTOF(data\nozzle.p3d); destrType = "DestructNo"; + + class ACE_Actions { + class ACE_MainActions { + displayName = CSTRING(Refuel); + distance = REFUEL_ACTION_DISTANCE; + position = "[0,-0.025,0.125]"; + condition = "true"; + statement = ""; + exceptions[] = {INTERACT_EXCEPTIONS}; + showDisabled = 0; + icon = QPATHTOF(ui\icon_refuel_interact.paa); + class GVAR(PickUpNozzle) { + displayName = CSTRING(TakeNozzle); + condition = QUOTE([ARR_2(_player,_target)] call FUNC(canTakeNozzle)); + statement = QUOTE([ARR_2(_player,_target)] call FUNC(takeNozzle)); + exceptions[] = {INTERACT_EXCEPTIONS_REFUELING}; + icon = QPATHTOF(ui\icon_refuel_interact.paa); + }; + class GVAR(TurnOn) { + displayName = CSTRING(TurnOn); + condition = QUOTE([ARR_2(_player,_target)] call FUNC(canTurnOn)); + statement = QUOTE([ARR_2(_player,_target)] call FUNC(turnOn)); + exceptions[] = {INTERACT_EXCEPTIONS}; + icon = QPATHTOF(ui\icon_refuel_interact.paa); + }; + class GVAR(TurnOn_Container) { + displayName = CSTRING(TurnOn_Container); + condition = QUOTE([ARR_3(_player,_target,true)] call FUNC(canTurnOn)); + statement = QUOTE([ARR_3(_player,_target,true)] call FUNC(turnOn)); + exceptions[] = {INTERACT_EXCEPTIONS}; + icon = QPATHTOF(ui\icon_refuel_interact.paa); + }; + class GVAR(TurnOff) { + displayName = CSTRING(TurnOff); + condition = QUOTE([ARR_2(_player,_target)] call FUNC(canTurnOff)); + statement = QUOTE([ARR_2(_player,_target)] call FUNC(turnOff)); + exceptions[] = {INTERACT_EXCEPTIONS}; + icon = QPATHTOF(ui\icon_refuel_interact.paa); + }; + class GVAR(Disconnect) { + displayName = CSTRING(Disconnect); + condition = QUOTE([ARR_2(_player,_target)] call FUNC(canDisconnect)); + statement = QUOTE([ARR_2(_player,_target)] call FUNC(disconnect)); + exceptions[] = {INTERACT_EXCEPTIONS_REFUELING}; + icon = QPATHTOF(ui\icon_refuel_interact.paa); + }; + }; + }; }; class Rope; diff --git a/addons/refuel/XEH_PREP.hpp b/addons/refuel/XEH_PREP.hpp index e4c5298036..077c8f1aed 100644 --- a/addons/refuel/XEH_PREP.hpp +++ b/addons/refuel/XEH_PREP.hpp @@ -1,4 +1,5 @@ PREP(canCheckFuel); +PREP(canConnectNozzle); PREP(canDisconnect); PREP(canReturnNozzle); PREP(canTakeNozzle); @@ -8,6 +9,7 @@ PREP(checkFuel); PREP(connectNozzleAction); PREP(disconnect); PREP(dropNozzle); +PREP(getCapacity); PREP(getFuel); PREP(handleDisconnect); PREP(handleRespawn); diff --git a/addons/refuel/XEH_postInit.sqf b/addons/refuel/XEH_postInit.sqf index 14e9b439c9..c826efd3d4 100644 --- a/addons/refuel/XEH_postInit.sqf +++ b/addons/refuel/XEH_postInit.sqf @@ -20,7 +20,7 @@ GVAR(mainAction) = [ { alive _target && {[_player, _target, [INTERACT_EXCEPTIONS]] call EFUNC(common,canInteractWith)} - && {REFUEL_DISABLED_FUEL != [_target] call FUNC(getFuel)} + && {REFUEL_DISABLED_FUEL != ([_target] call FUNC(getCapacity))} }, {}, [], [0,0,0], REFUEL_ACTION_DISTANCE diff --git a/addons/refuel/config.cpp b/addons/refuel/config.cpp index 2697b53a09..b39b665059 100644 --- a/addons/refuel/config.cpp +++ b/addons/refuel/config.cpp @@ -8,7 +8,7 @@ class CfgPatches { requiredVersion = REQUIRED_VERSION; requiredAddons[] = {"ace_interaction"}; author = ECSTRING(common,ACETeam); - authors[] = {"GitHawk"}; + authors[] = {"GitHawk", "QuantX"}; url = ECSTRING(main,URL); VERSION_CONFIG; }; diff --git a/addons/refuel/functions/fnc_canCheckFuel.sqf b/addons/refuel/functions/fnc_canCheckFuel.sqf index f7bb8a4aa8..22dfe616e7 100644 --- a/addons/refuel/functions/fnc_canCheckFuel.sqf +++ b/addons/refuel/functions/fnc_canCheckFuel.sqf @@ -23,4 +23,4 @@ params [["_unit", objNull, [objNull]], ["_source", objNull, [objNull]]]; {!local _unit} || {!alive _source} || {([_unit, _source] call EFUNC(interaction,getInteractionDistance)) > REFUEL_ACTION_DISTANCE} || - {(_source call FUNC(getFuel) == REFUEL_INFINITE_FUEL)}) + {(_source call FUNC(getCapacity)) in [REFUEL_INFINITE_FUEL, REFUEL_DISABLED_FUEL]}) diff --git a/addons/refuel/functions/fnc_canConnectNozzle.sqf b/addons/refuel/functions/fnc_canConnectNozzle.sqf new file mode 100644 index 0000000000..94e4eb7845 --- /dev/null +++ b/addons/refuel/functions/fnc_canConnectNozzle.sqf @@ -0,0 +1,30 @@ +#include "script_component.hpp" +/* + * Author: QuantX + * Checks if an object can have a nozzle connected to it. + * + * Arguments: + * 0: Object + * + * Return Value: + * Can nozzle be connected + * + * Example: + * [myVehicle] call ace_refuel_fnc_canConnectNozzle; + * [myJerryCan] call ace_refuel_fnc_canConnectNozzle; + * + * Public: No + */ + +params [["_object", objNull, [objNull]]]; + +// Make sure object doesn't already have a nozzle connected +if (isNull _object || {!isNull (_object getVariable [QGVAR(nozzle), objNull])} ) exitWith {false}; + +// Can't fuel a jerry can that is connected to another object +if (_object getVariable [QGVAR(jerryCan), false]) exitWith {!(_object getVariable [QGVAR(isConnected), false])}; + +// We need to check "canReceive" before we check if the tank can be filled +// This handles the edge case where a fuel truck has an infintite supply (i.e. the truck can be refueled, but the tank cannot) +(getNumber ((configOf _object) >> QGVAR(canReceive)) == 1) || + {!(([_object] call FUNC(getCapacity)) in [REFUEL_INFINITE_FUEL, REFUEL_DISABLED_FUEL])} diff --git a/addons/refuel/functions/fnc_canTakeNozzle.sqf b/addons/refuel/functions/fnc_canTakeNozzle.sqf index 82ca8452bc..db644c382c 100644 --- a/addons/refuel/functions/fnc_canTakeNozzle.sqf +++ b/addons/refuel/functions/fnc_canTakeNozzle.sqf @@ -22,7 +22,8 @@ if (isNull _unit || {!(_unit isKindOf "CAManBase")} || {!local _unit} || {!alive _object} || - {!isNull (_unit getVariable [QGVAR(nozzle), objNull])} || + {!isNull (_unit getVariable [QGVAR(nozzle), objNull])} || // Not already carrying a nozzle + {(_object getVariable [QGVAR(jerryCan), false]) && {!isNull (_object getVariable [QGVAR(nozzle), objNull])}} || // Prevent jerry cans from being picked up if they have a nozzle connected {typeOf _object == QGVAR(fuelNozzle) && {!isNull (attachedTo _object)}} || // Not carried by someone else {([_unit, _object] call EFUNC(interaction,getInteractionDistance)) > REFUEL_ACTION_DISTANCE}) exitWith {false}; diff --git a/addons/refuel/functions/fnc_canTurnOn.sqf b/addons/refuel/functions/fnc_canTurnOn.sqf index 855837d97c..65c88a7068 100644 --- a/addons/refuel/functions/fnc_canTurnOn.sqf +++ b/addons/refuel/functions/fnc_canTurnOn.sqf @@ -1,11 +1,12 @@ #include "script_component.hpp" /* * Author: GitHawk - * Check if a unit can turn on a fuel nozzle + * Check if a unit can turn on a fuel nozzle. * * Arguments: * 0: Unit * 1: Nozzle + * 2: Refuel container (default: false) * * Return Value: * Can turn on @@ -16,7 +17,7 @@ * Public: No */ -params [["_unit", objNull, [objNull]], ["_nozzle", objNull, [objNull]]]; +params [["_unit", objNull, [objNull]], ["_nozzle", objNull, [objNull]], ["_refuelContainer", false, [false]]]; if (isNull _unit || {isNull _nozzle} || @@ -24,7 +25,18 @@ if (isNull _unit || {!local _unit} || {(_nozzle distance _unit) > REFUEL_ACTION_DISTANCE}) exitWith {false}; +private _source = _nozzle getVariable [QGVAR(source), objNull]; +private _sink = _nozzle getVariable [QGVAR(sink), objNull]; + +if (isNull _source || {isNull _sink}) exitWith {false}; + +private _isSinkFull = if (_refuelContainer) then { + ([_sink] call FUNC(getCapacity)) in [REFUEL_DISABLED_FUEL, REFUEL_INFINITE_FUEL, [_sink] call FUNC(getFuel)] +} else { + fuel _sink == 1 +}; + !(_nozzle getVariable [QGVAR(isRefueling), false]) && - {[_nozzle getVariable QGVAR(source)] call FUNC(getFuel) != 0} && - {!isNull (_nozzle getVariable [QGVAR(sink), objNull])} && - {(fuel (_nozzle getVariable QGVAR(sink))) < 1} + {(([_source] call FUNC(getCapacity)) == REFUEL_INFINITE_FUEL) || {[_source] call FUNC(getFuel) > 0}} && // Make sure the source has fuel + {!_isSinkFull} && // Make sure the sink isn't full + {!(_refuelContainer && {_source == _sink})}; // No endless container ot itself loop diff --git a/addons/refuel/functions/fnc_connectNozzleAction.sqf b/addons/refuel/functions/fnc_connectNozzleAction.sqf index 97778d3e83..de5660f19f 100644 --- a/addons/refuel/functions/fnc_connectNozzleAction.sqf +++ b/addons/refuel/functions/fnc_connectNozzleAction.sqf @@ -72,6 +72,8 @@ private _attachPosModel = _sink worldToModel (ASLtoAGL _bestPosASL); _args params [["_unit", objNull, [objNull]], ["_nozzle", objNull, [objNull]], ["_sink", objNull, [objNull]], ["_endPosTestOffset", [0,0,0], [[]], 3]]; _unit setVariable [QGVAR(nozzle), nil, true]; _unit setVariable [QGVAR(isRefueling), false]; + + private _source = _nozzle getVariable QGVAR(source); detach _nozzle; _nozzle attachTo [_sink, _endPosTestOffset]; @@ -111,21 +113,34 @@ private _attachPosModel = _sink worldToModel (ASLtoAGL _bestPosASL); _nozzle setVariable [QGVAR(isConnected), true, true]; _sink setVariable [QGVAR(nozzle), _nozzle, true]; - _source = _nozzle getVariable QGVAR(source); - private _fuel = [_source] call FUNC(getFuel); - if (_fuel == REFUEL_INFINITE_FUEL) then { - _source setVariable [QGVAR(fuelCounter), 0, true]; - } else { - _source setVariable [QGVAR(fuelCounter), _fuel, true]; - }; + // Reset fuel counter + _source setVariable [QGVAR(fuelCounter), 0, true]; [_unit, _sink, _nozzle, _endPosTestOffset] call FUNC(refuel); - if ([_unit, _nozzle] call FUNC(canTurnOn)) then { - _unit setVariable [QGVAR(tempFuel), nil]; - [_unit, _nozzle] call FUNC(turnOn); - } else { - [localize LSTRING(CouldNotTurnOn)] call EFUNC(common,displayText); + private _canReceive = getNumber ((configOf _sink) >> QGVAR(canReceive)) == 1; + private _isContainer = ([_sink] call FUNC(getCapacity)) != REFUEL_DISABLED_FUEL; + + // Decide if cargo or vehicle will be refueled + switch (true) do { + case (_canReceive && {!_isContainer || {_sink == _source}}): { + // is not a refueling vehicle or refueling vehicle tries to refuel itself + if ([_unit, _nozzle, false] call FUNC(canTurnOn)) then { + [_unit, _nozzle, false] call FUNC(turnOn); + } else { + [localize LSTRING(CouldNotTurnOn)] call EFUNC(common,displayText); + }; + }; + case (!_canReceive && _isContainer): { + if ([_unit, _nozzle, true] call FUNC(canTurnOn)) then { + [_unit, _nozzle, true] call FUNC(turnOn); + } else { + [localize LSTRING(CouldNotTurnOn)] call EFUNC(common,displayText); + }; + }; + default { + /* Target is a refueling vehicle, let user manually decide if he wants to refuel cargo or vehicle itself */ + }; }; }, "", diff --git a/addons/refuel/functions/fnc_disconnect.sqf b/addons/refuel/functions/fnc_disconnect.sqf index b227b9fcc9..e27f220125 100644 --- a/addons/refuel/functions/fnc_disconnect.sqf +++ b/addons/refuel/functions/fnc_disconnect.sqf @@ -1,10 +1,10 @@ #include "script_component.hpp" /* * Author: GitHawk - * Disconnect a fuel nozzle. + * Disconnects a fuel nozzle and makes unit pick it up. * * Arguments: - * 0: Unit + * 0: Unit (default: objNull) * 1: Nozzle * * Return Value: @@ -27,4 +27,6 @@ _nozzle setVariable [QGVAR(sink), nil, true]; _nozzle setVariable [QGVAR(isConnected), false, true]; [objNull, _nozzle, true] call FUNC(dropNozzle); -[_unit, _nozzle] call FUNC(takeNozzle); +if (!isNull _unit) then { + [_unit, _nozzle] call FUNC(takeNozzle); +}; diff --git a/addons/refuel/functions/fnc_dropNozzle.sqf b/addons/refuel/functions/fnc_dropNozzle.sqf index 69b08b9026..28b8996864 100644 --- a/addons/refuel/functions/fnc_dropNozzle.sqf +++ b/addons/refuel/functions/fnc_dropNozzle.sqf @@ -4,7 +4,7 @@ * Detaches the fuel nozzle, drops it and removes player variables. * * Arguments: - * 0: Unit (optional) + * 0: Unit (default: objNull) * 1: Nozzle * 2: Disconnect Only * diff --git a/addons/refuel/functions/fnc_getCapacity.sqf b/addons/refuel/functions/fnc_getCapacity.sqf new file mode 100644 index 0000000000..e67b5a5f06 --- /dev/null +++ b/addons/refuel/functions/fnc_getCapacity.sqf @@ -0,0 +1,35 @@ +#include "script_component.hpp" +/* + * Author: QuantX + * Gets the capacity of a fuel source's tank. + * + * Arguments: + * 0: Fuel Source + * + * Return Value: + * Fuel capacity (-10 means infinte fuel, -1 means not a fuel source, >0 is a capacity in liters) + * + * Example: + * [fuelTruck] call ace_refuel_fnc_getCapacity + * + * Public: Yes + */ + +params [["_source", objNull, [objNull]]]; + +if (isNull _source) exitWith {REFUEL_DISABLED_FUEL}; + +private _capacity = _source getVariable QGVAR(capacity); + +// Initialize fuel truck if needed +if (isNil "_capacity") then { + // Check if this object has a fuelCargo config entry + private _fuelCargo = configOf _source >> QGVAR(fuelCargo); + _capacity = if (isNumber _fuelCargo) then {getNumber _fuelCargo} else {REFUEL_DISABLED_FUEL}; + + // Set capacity even if this isn't a fuel source to save on config lookup time in the event this function is used in a loop + _source setVariable [QGVAR(capacity), _capacity, true]; + [_source, _capacity] call FUNC(setFuel); +}; + +_capacity; diff --git a/addons/refuel/functions/fnc_getFuel.sqf b/addons/refuel/functions/fnc_getFuel.sqf index a51b6df411..0cc2cac0da 100644 --- a/addons/refuel/functions/fnc_getFuel.sqf +++ b/addons/refuel/functions/fnc_getFuel.sqf @@ -22,8 +22,8 @@ if (isNull _source) exitWith {0}; private _fuel = _source getVariable QGVAR(currentFuelCargo); if (isNil "_fuel") then { - _fuel = getNumber (configOf _source >> QGVAR(fuelCargo)); - _source setVariable [QGVAR(currentFuelCargo), _fuel, true]; + // Calling getCapacity will initialize the fuel source and return the amount of fuel in the tank + _fuel = [_source] call FUNC(getCapacity); }; _fuel diff --git a/addons/refuel/functions/fnc_makeJerryCan.sqf b/addons/refuel/functions/fnc_makeJerryCan.sqf index 4c4cd22aa1..c5fbc1ef09 100644 --- a/addons/refuel/functions/fnc_makeJerryCan.sqf +++ b/addons/refuel/functions/fnc_makeJerryCan.sqf @@ -22,12 +22,12 @@ if (isNull _target || {_target isKindOf "AllVehicles"} || {_target getVariable [QGVAR(jerryCan), false]}) exitWith {}; -if (isServer) then { - [_target, _fuelAmount] call FUNC(setFuel); // has global effects -}; _target setVariable [QGVAR(jerryCan), true]; _target setVariable [QGVAR(source), _target]; +_target setVariable [QGVAR(capacity), _fuelAmount]; +if (isServer) then { [_target, _fuelAmount] call FUNC(setFuel); }; + // Main Action private _action = [QGVAR(Refuel), localize LSTRING(Refuel), @@ -64,6 +64,30 @@ _action = [QGVAR(TurnOn), REFUEL_ACTION_DISTANCE] call EFUNC(interact_menu,createAction); [_target, 0, ["ACE_MainActions", QGVAR(Refuel)], _action] call EFUNC(interact_menu,addActionToObject); +// Add turnOn container +_action = [QGVAR(TurnOn_Container), + localize LSTRING(TurnOn_Container), + QPATHTOF(ui\icon_refuel_interact.paa), + {[_player, _target, true] call FUNC(turnOn)}, + {[_player, _target, true] call FUNC(canTurnOn)}, + {}, + [], + [0, 0, 0], + REFUEL_ACTION_DISTANCE] call EFUNC(interact_menu,createAction); +[_target, 0, ["ACE_MainActions", QGVAR(Refuel)], _action] call EFUNC(interact_menu,addActionToObject); + +// Add check fuel +_action = [QGVAR(CheckFuel), + localize LSTRING(CheckFuel), + QPATHTOF(ui\icon_refuel_interact.paa), + {[_player, _target] call FUNC(checkFuel)}, + {[_player, _target] call FUNC(canCheckFuel)}, + {}, + [], + [0,0,0], + REFUEL_ACTION_DISTANCE] call EFUNC(interact_menu,createAction), +[_target, 0, ["ACE_MainActions", QGVAR(Refuel)], _action] call EFUNC(interact_menu,addActionToObject); + // Add turnOff _action = [QGVAR(TurnOff), localize LSTRING(TurnOff), diff --git a/addons/refuel/functions/fnc_makeSource.sqf b/addons/refuel/functions/fnc_makeSource.sqf index 5553e1a906..823b152643 100644 --- a/addons/refuel/functions/fnc_makeSource.sqf +++ b/addons/refuel/functions/fnc_makeSource.sqf @@ -40,10 +40,14 @@ if ( || {_fuelCargo != 0 && {_fuelCargo == _fuelCargoConfig}} ) exitWith {}; -[_source, _fuelCargo] call FUNC(setFuel); +private _capacity = if (_fuelCargo < 0) then {_fuelCargo} else {_fuelCargoConfig max _fuelCargo}; + +_source setVariable [QGVAR(capacity), _capacity, true]; if (_fuelCargo == REFUEL_DISABLED_FUEL) exitWith {}; +[_source, _fuelCargo] call FUNC(setFuel); + if ( !isNil "_hooks" && {_hooks isEqualTypeAll []} diff --git a/addons/refuel/functions/fnc_onMouseButtonDown.sqf b/addons/refuel/functions/fnc_onMouseButtonDown.sqf index 184ede22eb..aa67b198ae 100644 --- a/addons/refuel/functions/fnc_onMouseButtonDown.sqf +++ b/addons/refuel/functions/fnc_onMouseButtonDown.sqf @@ -42,10 +42,11 @@ private _virtualPosASL = (eyePos _unit) vectorAdd (positionCameraToWorld [0,0,0. if (cameraView == "EXTERNAL") then { _virtualPosASL = _virtualPosASL vectorAdd ((positionCameraToWorld [0.3,0,0]) vectorDiff (positionCameraToWorld [0,0,0])); }; + if ( !isNull _cursorObject && {_distance < REFUEL_NOZZLE_ACTION_DISTANCE} - && {1 == getNumber (configOf _cursorObject >> QGVAR(canReceive))} + && {[_cursorObject] call FUNC(canConnectNozzle)} && {isNull (_cursorObject getVariable [QGVAR(nozzle), objNull])} && {!lineIntersects [eyePos _unit, _virtualPosASL, _unit]} ) then { diff --git a/addons/refuel/functions/fnc_readFuelCounter.sqf b/addons/refuel/functions/fnc_readFuelCounter.sqf index cc851a549f..cf5ddd2f50 100644 --- a/addons/refuel/functions/fnc_readFuelCounter.sqf +++ b/addons/refuel/functions/fnc_readFuelCounter.sqf @@ -18,12 +18,6 @@ params [["_unit", objNull, [objNull]], ["_source", objNull, [objNull]]]; -private _currentFuel = [_source] call FUNC(getFuel); -private _fuelCounter = if (_currentFuel == REFUEL_INFINITE_FUEL) then { - _source getVariable [QGVAR(fuelCounter), 0] -} else { - (_source getVariable [QGVAR(fuelCounter), _currentFuel]) - _currentFuel -}; - -private _fuelCounter = 0.01 * round (100 * _fuelCounter); +private _fuelCounter = _source getVariable [QGVAR(fuelCounter), 0]; +_fuelCounter = 0.01 * round (100 * _fuelCounter); [[LSTRING(Hint_FuelCounter), _fuelCounter], 1.5, _unit] call EFUNC(common,displayTextStructured); diff --git a/addons/refuel/functions/fnc_refuel.sqf b/addons/refuel/functions/fnc_refuel.sqf index 92a654e295..d588eb39ca 100644 --- a/addons/refuel/functions/fnc_refuel.sqf +++ b/addons/refuel/functions/fnc_refuel.sqf @@ -1,6 +1,6 @@ #include "script_component.hpp" /* - * Author: GitHawk + * Author: GitHawk, QuantX * Refuels the vehicle. * * Arguments: @@ -21,93 +21,111 @@ params [["_unit", objNull, [objNull]], ["_sink", objNull, [objNull]], ["_nozzle", objNull, [objNull]], ["_connectToPoint", [0,0,0], [[]], 3]]; private _config = configOf _sink; +private _rate = if (isNumber (_config >> QGVAR(flowRate))) then { + getNumber (_config >> QGVAR(flowRate)) * GVAR(rate) +} else { + // Jerry cans for example have no flow rate defined, default to 1 + GVAR(rate) +}; -private _rate = getNumber (_config >> QGVAR(flowRate)) * GVAR(rate); -private _maxFuel = getNumber (_config >> QGVAR(fuelCapacity)); - +// How much fuel is in a vehicle's fuel tank +private _maxFuelTank = getNumber (_config >> QGVAR(fuelCapacity)); // Fall back to vanilla fuelCapacity value (only air and sea vehicles don't have this defined by default by us) // Air and sea vehicles have that value properly defined in liters, unlike ground vehicles which is is formula of (range * tested factor) - different fuel consumption system than ground vehicles -if (_maxFuel == 0) then { - _maxFuel = getNumber (_config >> "fuelCapacity"); +if (_maxFuelTank == 0) then { + _maxFuelTank = getNumber (_config >> "fuelCapacity"); }; [{ params ["_args", "_pfID"]; - _args params [["_source", objNull, [objNull]], ["_sink", objNull, [objNull]], ["_unit", objNull, [objNull]], ["_nozzle", objNull, [objNull]], ["_rate", 1, [0]], ["_startFuel", 0, [0]], ["_maxFuel", 0, [0]], ["_connectFromPoint", [0,0,0], [[]], 3], ["_connectToPoint", [0,0,0], [[]], 3]]; + _args params [["_source", objNull, [objNull]], ["_sink", objNull, [objNull]], ["_unit", objNull, [objNull]], ["_nozzle", objNull, [objNull]], ["_rate", 1, [0]], ["_maxFuelTank", 1, [0]], ["_connectFromPoint", [0,0,0], [[]], 3], ["_connectToPoint", [0,0,0], [[]], 3]]; if !(_nozzle getVariable [QGVAR(isConnected), false]) exitWith { [_pfID] call CBA_fnc_removePerFrameHandler; }; + // Quit if target or fuel tank got destroyed if (!alive _source || {!alive _sink}) exitWith { - [objNull, _nozzle] call FUNC(dropNozzle); - _nozzle setVariable [QGVAR(isConnected), false, true]; - if (_nozzle isKindOf "Land_CanisterFuel_F") then { _nozzle setVariable [QEGVAR(cargo,canLoad), true, true]; }; - _nozzle setVariable [QGVAR(sink), nil, true]; - _sink setVariable [QGVAR(nozzle), nil, true]; + [objNull, _nozzle] call FUNC(disconnect); [_pfID] call CBA_fnc_removePerFrameHandler; }; + + // Quit if hose distance was exceeded private _hoseLength = _source getVariable [QGVAR(hoseLength), GVAR(hoseLength)]; private _tooFar = ((_sink modelToWorld _connectToPoint) distance (_source modelToWorld _connectFromPoint)) > (_hoseLength - 2); if (_tooFar && {!(_nozzle getVariable [QGVAR(jerryCan), false])}) exitWith { [LSTRING(Hint_TooFar), 2, _unit] call EFUNC(common,displayTextStructured); - - [objNull, _nozzle] call FUNC(dropNozzle); - _nozzle setVariable [QGVAR(isConnected), false, true]; - if (_nozzle isKindOf "Land_CanisterFuel_F") then { _nozzle setVariable [QEGVAR(cargo,canLoad), true, true]; }; - _nozzle setVariable [QGVAR(sink), nil, true]; - _sink setVariable [QGVAR(nozzle), nil, true]; + [objNull, _nozzle] call FUNC(disconnect); [_pfID] call CBA_fnc_removePerFrameHandler; }; + // Main fueling process private _finished = false; private _fueling = _nozzle getVariable [QGVAR(isRefueling), false]; if (_fueling) then { - private _fuelInSource = [_source] call FUNC(getFuel); - if (_fuelInSource == 0) exitWith { - [LSTRING(Hint_SourceEmpty), 2, _unit] call EFUNC(common,displayTextStructured); - _nozzle setVariable [QGVAR(lastTickMissionTime), nil]; - _nozzle setVariable [QGVAR(isRefueling), false, true]; - }; - + private _refuelContainer = _nozzle getVariable [QGVAR(refuelContainer), false]; + + // Use special cargo refuel rate when refueling containers + // TODO: Add flow dedicated input/output flow rates for every container and use the lower of the two instead + if (_refuelContainer) then {_rate = GVAR(cargoRate)}; + // Calculate rate using mission time to take time acceleration and pause into account - private _rateTime = _rate * (CBA_missionTime - (_nozzle getVariable [QGVAR(lastTickMissionTime), CBA_missionTime])); + private _addedFuel = _rate * (CBA_missionTime - (_nozzle getVariable [QGVAR(lastTickMissionTime), CBA_missionTime])); _nozzle setVariable [QGVAR(lastTickMissionTime), CBA_missionTime]; - if (_fuelInSource != REFUEL_INFINITE_FUEL) then { - if (_rateTime > _fuelInSource) then { - _rateTime = _fuelInSource; + // Figure out exactly how much fuel to transfer while being sure not to take too much from source + private _fuelInSource = [_source] call FUNC(getFuel); + if (([_source] call FUNC(getCapacity)) != REFUEL_INFINITE_FUEL) then { + if (_addedFuel > _fuelInSource) then { + _addedFuel = _fuelInSource; _fuelInSource = 0; + _finished = true; + [LSTRING(Hint_SourceEmpty), 2, _unit] call EFUNC(common,displayTextStructured); } else { - _fuelInSource = _fuelInSource - _rateTime; + _fuelInSource = _fuelInSource - _addedFuel; }; + }; + + private _fuelInSink = (if (_refuelContainer) then { + [_sink] call FUNC(getFuel) } else { - _source setVariable [QGVAR(fuelCounter), (_source getVariable [QGVAR(fuelCounter), 0]) + _rateTime, true]; - }; - if (_fuelInSource <= 0 && {_fuelInSource != REFUEL_INFINITE_FUEL}) then { - _fuelInSource = 0; - [_source, _fuelInSource] call FUNC(setFuel); - _finished = true; - [LSTRING(Hint_SourceEmpty), 2, _unit] call EFUNC(common,displayTextStructured); - }; - - private _fuelInSink = (_unit getVariable [QGVAR(tempFuel), _startFuel]) + ( _rateTime / _maxFuel); - if (_fuelInSink > 1) then { - _fuelInSink = 1; + // How full the gas tank is. We keep our own record, since `fuel _sink` doesn't update quick enough + (_nozzle getVariable [QGVAR(tempFuel), fuel _sink]) * _maxFuelTank + }) + _addedFuel; + + // Add fuel to target while being sure not to put too much into sink + private _maxFuelContainer = [_sink] call FUNC(getCapacity); + private _maxFuel = [_maxFuelTank, _maxFuelContainer] select _refuelContainer; + if (_fuelInSink >= _maxFuel) then { + // Put any extra fuel back + _fuelInSource = _fuelInSource + (_fuelInSink - _maxFuel); + _addedFuel = _maxFuel - _fuelInSink; + // We're done + _fuelInSink = _maxFuel; _finished = true; [LSTRING(Hint_Completed), 2, _unit] call EFUNC(common,displayTextStructured); }; - _unit setVariable [QGVAR(tempFuel), _fuelInSink]; + + if (_refuelContainer) then { + [_sink, _fuelInSink] call FUNC(setFuel); + } else { + private _fillRatio = _fuelInSink / _maxFuelTank; + [QEGVAR(common,setFuel), [_sink, _fillRatio], _sink] call CBA_fnc_targetEvent; + _nozzle setVariable [QGVAR(tempFuel), _fillRatio]; + }; + + // Increment fuel counter + _source setVariable [QGVAR(fuelCounter), (_source getVariable [QGVAR(fuelCounter), 0]) + _addedFuel, true]; - [QGVAR(tick), [_source, _sink, _rateTime]] call CBA_fnc_localEvent; + [QGVAR(tick), [_source, _sink, _addedFuel, _refuelContainer]] call CBA_fnc_localEvent; - [QEGVAR(common,setFuel), [_sink, _fuelInSink], _sink] call CBA_fnc_targetEvent; [_source, _fuelInSource] call FUNC(setFuel); } else { - _unit setVariable [QGVAR(tempFuel), fuel _sink]; + _nozzle setVariable [QGVAR(tempFuel), fuel _sink]; }; - if (_finished) exitWith { + // Reset variables when done + if (_finished) then { [QGVAR(stopped), [_source, _sink]] call CBA_fnc_localEvent; _nozzle setVariable [QGVAR(lastTickMissionTime), nil]; _nozzle setVariable [QGVAR(isRefueling), false, true]; @@ -118,8 +136,7 @@ if (_maxFuel == 0) then { _unit, _nozzle, _rate, - fuel _sink, - _maxFuel, + _maxFuelTank, _nozzle getVariable [QGVAR(attachPos), [0,0,0]], _connectToPoint ]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/refuel/functions/fnc_returnNozzle.sqf b/addons/refuel/functions/fnc_returnNozzle.sqf index 5f1eed2721..f891335d87 100644 --- a/addons/refuel/functions/fnc_returnNozzle.sqf +++ b/addons/refuel/functions/fnc_returnNozzle.sqf @@ -43,6 +43,10 @@ if (isNull _nozzle || {_source != _nozzle getVariable QGVAR(source)}) exitWith { deleteVehicle _helper; }; deleteVehicle _nozzle; + + // Restore ability to drag and carry this object + _source setVariable [QEGVAR(dragging,canCarry), _source getVariable [QGVAR(canCarryLast), false], true]; + _source setVariable [QEGVAR(dragging,canDrag), _source getVariable [QGVAR(canDragLast), false], true]; [_source, "blockEngine", "ACE_Refuel", false] call EFUNC(common,statusEffect_set); }, diff --git a/addons/refuel/functions/fnc_setFuel.sqf b/addons/refuel/functions/fnc_setFuel.sqf index f95596f4f1..a7f35e8754 100644 --- a/addons/refuel/functions/fnc_setFuel.sqf +++ b/addons/refuel/functions/fnc_setFuel.sqf @@ -18,7 +18,12 @@ params [["_source", objNull, [objNull]], ["_fuel", nil, [0]]]; -if (isNull _source || - {isNil "_fuel"}) exitWith {}; +// Ensure valid fuel quantity +if (isNull _source || {isNil "_fuel"}) exitWith {}; -_source setVariable [QGVAR(currentFuelCargo), _fuel, true]; +// Make sure this is actually a finite fuel source +private _capacity = [_source] call FUNC(getCapacity); +if (_capacity in [REFUEL_INFINITE_FUEL, REFUEL_DISABLED_FUEL]) exitWith {}; + +// Don't overfill or underfill tank +_source setVariable [QGVAR(currentFuelCargo), (_fuel min _capacity) max 0, true]; diff --git a/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf b/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf index 7922a9cb91..5d72ce8434 100644 --- a/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf +++ b/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf @@ -95,10 +95,7 @@ TRACE_2("start",_unit,_nozzle); getCursorObjectParams params ["_cursorObject", "", "_distance"]; if (!isNull _cursorObject && {_distance < REFUEL_NOZZLE_ACTION_DISTANCE}) then { - if ( - 1 == getNumber (configOf _cursorObject >> QGVAR(canReceive)) - && {isNull (_cursorObject getVariable [QGVAR(nozzle), objNull])} - ) then { + if ([_cursorObject] call FUNC(canConnectNozzle)) then { _hintLMB = localize LSTRING(Connect); }; if ([_unit, _cursorObject] call FUNC(canReturnNozzle)) then { diff --git a/addons/refuel/functions/fnc_takeNozzle.sqf b/addons/refuel/functions/fnc_takeNozzle.sqf index 0292e9ec66..1678be5ec5 100644 --- a/addons/refuel/functions/fnc_takeNozzle.sqf +++ b/addons/refuel/functions/fnc_takeNozzle.sqf @@ -77,6 +77,13 @@ params [ [_source, "blockEngine", "ACE_Refuel", true] call EFUNC(common,statusEffect_set); _source setVariable [QGVAR(isConnected), true, true]; _source setVariable [QGVAR(ownedNozzle), _nozzle, true]; + + // Prevent moving the fuel source while the hose is out + _source setVariable [QGVAR(canCarryLast), _source getVariable [QEGVAR(dragging,canCarry), false], true]; + _source setVariable [QGVAR(canDragLast), _source getVariable [QEGVAR(dragging,canDrag), false], true]; + + _source setVariable [QEGVAR(dragging,canCarry), false, true]; + _source setVariable [QEGVAR(dragging,canDrag), false, true]; }; _unit setVariable [QGVAR(nozzle), _nozzle, true]; diff --git a/addons/refuel/functions/fnc_turnOn.sqf b/addons/refuel/functions/fnc_turnOn.sqf index b96cc6cda4..24c3aad8ae 100644 --- a/addons/refuel/functions/fnc_turnOn.sqf +++ b/addons/refuel/functions/fnc_turnOn.sqf @@ -6,6 +6,7 @@ * Arguments: * 0: Unit * 1: Nozzle + * 2: Refuel container (default: false) * * Return Value: * None @@ -16,9 +17,10 @@ * Public: No */ -params [["_unit", objNull, [objNull]], ["_nozzle", objNull, [objNull]]]; +params [["_unit", objNull, [objNull]], ["_nozzle", objNull, [objNull]], ["_refuelContainer", false, [false]]]; _nozzle setVariable [QGVAR(lastTickMissionTime), CBA_missionTime]; +_nozzle setVariable [QGVAR(refuelContainer), _refuelContainer]; _nozzle setVariable [QGVAR(isRefueling), true, true]; [LSTRING(Hint_Started), 1.5, _unit] call EFUNC(common,displayTextStructured); [QGVAR(started), [_nozzle getVariable QGVAR(source), _nozzle getVariable QGVAR(sink)]] call CBA_fnc_localEvent; diff --git a/addons/refuel/initSettings.sqf b/addons/refuel/initSettings.sqf index 52e3c7ee8c..087e253dc4 100644 --- a/addons/refuel/initSettings.sqf +++ b/addons/refuel/initSettings.sqf @@ -7,6 +7,15 @@ {[QGVAR(rate), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; +[ + QGVAR(cargoRate), "SLIDER", + [LSTRING(RefuelSettings_speedCargo_DisplayName), LSTRING(RefuelSettings_speedCargo_Description)], + [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_refuel"], + [0,250,10,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] + true, // isGlobal + {[QGVAR(cargoRate), _this] call EFUNC(common,cbaSettings_settingChanged)} +] call CBA_fnc_addSetting; + [ QGVAR(hoseLength), "SLIDER", [LSTRING(RefuelSettings_hoseLength_DisplayName)], diff --git a/addons/refuel/stringtable.xml b/addons/refuel/stringtable.xml index 65bbc41934..68f4bcaa3d 100644 --- a/addons/refuel/stringtable.xml +++ b/addons/refuel/stringtable.xml @@ -49,6 +49,12 @@ 載具多快會加油完畢? Bir araca ne kadar hızlı yakıt ikmali yapılmalıdır? + + Cargo Flow Rate + + + How fast should a fuel source's tank be filled? + Refuel Betankung @@ -289,6 +295,10 @@ 開始加油 Yakıt Doldurmayı Başlat + + Start fueling (container) + Betankung beginnen (Container) + Couldn't turn on fuel nozzle Kann Zapfpistole nicht anschalten