From 7838dea543414806f452bce804c31623f82d1b2a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:01:39 +0200 Subject: [PATCH] Common - Improve persistent lights/lasers (#10118) * Improve persistent lasers * Update addons/common/functions/fnc_switchPersistentLaser.sqf Co-authored-by: PabstMirror * Fix inventory changes toggling laser, removed alignment code * Update addons/common/functions/fnc_switchPersistentLaser.sqf Co-authored-by: PabstMirror * Added API for setting weapon lights/lasers * Fix undefined variables --------- Co-authored-by: PabstMirror --- addons/common/XEH_PREP.hpp | 1 + .../fnc_setWeaponLightLaserState.sqf | 59 ++++++++++ .../functions/fnc_switchPersistentLaser.sqf | 108 ++++++++++++------ 3 files changed, 131 insertions(+), 37 deletions(-) create mode 100644 addons/common/functions/fnc_setWeaponLightLaserState.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index d3972dc7b30..36147753459 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -178,6 +178,7 @@ PREP(setupLocalUnitsHandler); PREP(setVariableJIP); PREP(setVariablePublic); PREP(setVolume); +PREP(setWeaponLightLaserState); PREP(showHud); PREP(statusEffect_addType); PREP(statusEffect_get); diff --git a/addons/common/functions/fnc_setWeaponLightLaserState.sqf b/addons/common/functions/fnc_setWeaponLightLaserState.sqf new file mode 100644 index 00000000000..7f50573acb7 --- /dev/null +++ b/addons/common/functions/fnc_setWeaponLightLaserState.sqf @@ -0,0 +1,59 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Toggles the unit's current weapon's light & laser. + * API for persistent lasers. Doesn't work on AI, as they have their own logic. + * + * Arguments: + * 0: Unit + * 1: Weapon light/laser state (default: false) + * + * Return Value: + * None + * + * Example: + * [player, true] call ace_common_fnc_setWeaponLightLaserState + * + * Public: Yes + */ + +params [["_unit", objNull, [objNull]], ["_state", false, [false]]]; + +if (!local _unit || {!alive _unit} || {!(_unit call FUNC(isPlayer))}) exitWith {}; + +if !(_unit call CBA_fnc_canUseWeapon) exitWith {}; + +private _currentWeapon = currentWeapon _unit; + +// Exit if unit has no weapon selected +if (_currentWeapon == "") exitWith {}; + +private _weaponIndex = [_unit, _currentWeapon] call FUNC(getWeaponIndex); + +// Ignore binoculars +if (_weaponIndex == -1) exitWith {}; + +_unit setVariable [QGVAR(laserEnabled_) + str _weaponIndex, _state]; + +// Turn off light/laser (switching between weapons can leave previous weapon laser on) +action ["GunLightOff", _unit]; +action ["IRLaserOff", _unit]; + +// Light/laser is off, don't need to do anything more +if (!_state) exitWith {}; + +// Turn laser on next frame (if weapon hasn't changed) +[{ + params ["_unit", "_currentWeapon"]; + + private _weaponState = (weaponState _unit) select [0, 3]; + + if (_weaponState select 0 != _currentWeapon) exitWith {}; + + action ["GunLightOn", _unit]; + action ["IRLaserOn", _unit]; + + _unit selectWeapon _weaponState; +}, [_unit, _currentWeapon]] call CBA_fnc_execNextFrame; + +nil diff --git a/addons/common/functions/fnc_switchPersistentLaser.sqf b/addons/common/functions/fnc_switchPersistentLaser.sqf index a2b7b9c1a8d..d258284edb6 100644 --- a/addons/common/functions/fnc_switchPersistentLaser.sqf +++ b/addons/common/functions/fnc_switchPersistentLaser.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: Dystopian + * Author: Dystopian, johnb43 * Controls persistent laser state. * * Arguments: @@ -17,51 +17,85 @@ params ["_enabled"]; +if (!hasInterface) exitwith {}; + +// Reset state +{ + ACE_player setVariable [QGVAR(laserEnabled_) + str _x, nil]; +} forEach [0, 1, 2]; + if (!_enabled) exitWith { if (isNil QGVAR(laserKeyDownEH)) exitWith {}; - ["KeyDown", GVAR(laserKeyDownEH)] call CBA_fnc_removeDisplayHandler; + + removeUserActionEventHandler ["headlights", "Activate", GVAR(laserKeyDownEH)]; + ["loadout", GVAR(laserLoadoutEH)] call CBA_fnc_removePlayerEventHandler; ["turret", GVAR(laserTurretEH)] call CBA_fnc_removePlayerEventHandler; ["vehicle", GVAR(laserVehicleEH)] call CBA_fnc_removePlayerEventHandler; ["weapon", GVAR(laserWeaponEH)] call CBA_fnc_removePlayerEventHandler; + + GVAR(laserKeyDownEH) = nil; + GVAR(laserLoadoutEH) = nil; + GVAR(laserTurretEH) = nil; + GVAR(laserVehicleEH) = nil; + GVAR(laserWeaponEH) = nil; }; -GVAR(laserKeyDownEH) = ["KeyDown", { - if !((_this select 1) in actionKeys "headlights") exitWith {false}; - private _weapon = currentWeapon ACE_player; +private _fnc_getLightLaserState = { + private _currentWeapon = currentWeapon ACE_player; + + if (_currentWeapon == "") exitWith {}; + + // Ignore in vehicle except FFV + if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {}; + + private _weaponIndex = [ACE_player, _currentWeapon] call FUNC(getWeaponIndex); + + if (_weaponIndex == -1) exitWith {}; + + // Light/laser state only changes in the next frame + [{ + ACE_player setVariable [ + QGVAR(laserEnabled_) + str (_this select 1), + ACE_player isIRLaserOn (_this select 0) || {ACE_player isFlashlightOn (_this select 0)} + ]; + }, [_currentWeapon, _weaponIndex]] call CBA_fnc_execNextFrame; +}; + +// Get current weapon light/laser state +call _fnc_getLightLaserState; + +// Update state every time it's changed +GVAR(laserKeyDownEH) = addUserActionEventHandler ["headlights", "Activate", _fnc_getLightLaserState]; + +// Dropping weapons turns off lights/lasers +GVAR(lastWeapons) = [primaryWeapon ACE_player, handgunWeapon ACE_player, secondaryWeapon ACE_player]; + +// Monitor weapon addition/removal here +GVAR(laserLoadoutEH) = ["loadout", { + params ["_unit"]; + + private _weapons = [primaryWeapon _unit, handgunWeapon _unit, secondaryWeapon _unit]; + + if (_weapons isEqualTo GVAR(lastWeapons)) exitWith {}; + + GVAR(lastWeapons) = _weapons; + [ - { - params ["_weapon", "_laserWasEnabled"]; - private _laserEnabled = ACE_player isIRLaserOn _weapon || {ACE_player isFlashlightOn _weapon}; - if (_laserEnabled && {_laserWasEnabled} || {!_laserEnabled && {!_laserWasEnabled}}) exitWith {}; - private _weaponIndex = [ACE_player, _weapon] call FUNC(getWeaponIndex); - ACE_player setVariable [QGVAR(laserEnabled_) + str _weaponIndex, [nil, true] select _laserEnabled]; - }, - [_weapon, ACE_player isIRLaserOn _weapon || {ACE_player isFlashlightOn _weapon}] - ] call CBA_fnc_execNextFrame; - false -}] call CBA_fnc_addDisplayHandler; - -private _laserEH = { - if (sunOrMoon == 1) exitWith {}; - params ["_player"]; - private _weaponIndex = [_player, currentWeapon _player] call FUNC(getWeaponIndex); - if ( - !(_player getVariable [QGVAR(laserEnabled_) + str _weaponIndex, false]) - || {_weaponIndex > 0 && {"" != primaryWeapon _player}} // Arma switches to primary weapon if exists - || {!(_player call CBA_fnc_canUseWeapon)} // ignore in vehicle except FFV - ) exitWith {}; + _unit, + _unit getVariable [QGVAR(laserEnabled_) + str ([_unit, currentWeapon _unit] call FUNC(getWeaponIndex)), false] + ] call FUNC(setWeaponLightLaserState); +}] call CBA_fnc_addPlayerEventHandler; + +private _fnc_switchPersistentLaserEH = { + params ["_unit"]; + [ - // wait for weapon in "ready to fire" direction - {0.01 > getCameraViewDirection _this vectorDistance (_this weaponDirection currentWeapon _this)}, - {{_this action [_x, _this]} forEach ["GunLightOn", "IRLaserOn"]}, - _player, - 3, - {{_this action [_x, _this]} forEach ["GunLightOn", "IRLaserOn"]} - ] call CBA_fnc_waitUntilAndExecute; + _unit, + _unit getVariable [QGVAR(laserEnabled_) + str ([_unit, currentWeapon _unit] call FUNC(getWeaponIndex)), false] + ] call FUNC(setWeaponLightLaserState); }; -GVAR(laserLoadoutEH) = ["loadout", _laserEH] call CBA_fnc_addPlayerEventHandler; -GVAR(laserTurretEH) = ["turret", _laserEH] call CBA_fnc_addPlayerEventHandler; -GVAR(laserVehicleEH) = ["vehicle", _laserEH] call CBA_fnc_addPlayerEventHandler; -GVAR(laserWeaponEH) = ["weapon", _laserEH] call CBA_fnc_addPlayerEventHandler; +GVAR(laserTurretEH) = ["turret", _fnc_switchPersistentLaserEH] call CBA_fnc_addPlayerEventHandler; +GVAR(laserVehicleEH) = ["vehicle", _fnc_switchPersistentLaserEH] call CBA_fnc_addPlayerEventHandler; +GVAR(laserWeaponEH) = ["weapon", _fnc_switchPersistentLaserEH] call CBA_fnc_addPlayerEventHandler;