diff --git a/addons/bitwise/CfgFunctions.hpp b/addons/bitwise/CfgFunctions.hpp index 761ea99ce..af683d415 100644 --- a/addons/bitwise/CfgFunctions.hpp +++ b/addons/bitwise/CfgFunctions.hpp @@ -15,6 +15,7 @@ class CfgFunctions { PATHTO_FNC(bitwiseRSHFT); PATHTO_FNC(bitwiseXOR); PATHTO_FNC(logBase2); + PATHTO_FNC(toBitMask); }; }; }; diff --git a/addons/bitwise/fnc_toBitMask.sqf b/addons/bitwise/fnc_toBitMask.sqf new file mode 100644 index 000000000..180376be3 --- /dev/null +++ b/addons/bitwise/fnc_toBitMask.sqf @@ -0,0 +1,30 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_toBitMask +Description: + Convert an array of booleans into a number. + Takes Input (limited to float precision) + +Parameters: + _input - Boolean (least significant bit) + +Returns: + Bitmask + +Examples + (begin example) + [[true, false]] call CBA_fnc_toBitmask + (end) + +Author: + commy2 +---------------------------------------------------------------------------- */ +SCRIPT(toBitMask); +params [["_input", [], [[]]]]; + +private _result = 0; +{ + if (_x) then {_result = _result + 2 ^ _forEachIndex}; +} forEach _input; + +_result; diff --git a/addons/common/CfgFunctions.hpp b/addons/common/CfgFunctions.hpp index ee691f693..fbc16954b 100644 --- a/addons/common/CfgFunctions.hpp +++ b/addons/common/CfgFunctions.hpp @@ -12,6 +12,7 @@ class CfgFunctions { PATHTO_FNC(inheritsFrom); PATHTO_FNC(getTurret); PATHTO_FNC(getNonPresetClass); + PATHTO_FNC(isModLoaded); }; class Entities { @@ -153,6 +154,8 @@ class CfgFunctions { PATHTO_FNC(cssColorToHEX); PATHTO_FNC(cssColorToTexture); PATHTO_FNC(attachToBone); + PATHTO_FNC(binarizeNumber); + PATHTO_FNC(endRadioTransmission); }; class Broken { diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf index 3a02d3adc..eb1ac70e7 100644 --- a/addons/common/XEH_preInit.sqf +++ b/addons/common/XEH_preInit.sqf @@ -17,6 +17,8 @@ CBA_logic = objNull; }; }] call CBA_fnc_compileFinal; +GVAR(isModLoadedCache) = createHashMap; + // FSM GVAR(delayless) = QUOTE(PATHTOF(delayless.fsm)); GVAR(delayless_loop) = QUOTE(PATHTOF(delayless_loop.fsm)); @@ -41,7 +43,7 @@ GVAR(featureCamerasNames) = [ "animViewer", // Animation viewer camera "classic" // Classic camera ]; -if (isClass (configFile >> "CfgPatches" >> "missions_f_vietnam")) then { // Add SOG Cinematic module camera if CDLC loaded +if ("missions_f_vietnam" call CBA_fnc_isModLoaded) then { // Add SOG Cinematic module camera if CDLC loaded ["vn_cinematic", {missionNamespace getVariable ["vn_cinematic_running", false]}] call CBA_fnc_registerFeatureCamera; }; diff --git a/addons/common/fnc_binarizeNumber.sqf b/addons/common/fnc_binarizeNumber.sqf new file mode 100644 index 000000000..d60046b29 --- /dev/null +++ b/addons/common/fnc_binarizeNumber.sqf @@ -0,0 +1,49 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_binarizeNumber +Description: + Get a binary equivalent of a decimal number. + +Parameters: + _number - Decimal Number + _minLength - Minimum length of the returned Array, note: returned array can be larger (optional, default: 8) + +Returns: + Booleans + +Examples + (begin example) + [5, 5] call CBA_fnc_binarizeNumber + (end) + +Author: + commy2 +---------------------------------------------------------------------------- */ +SCRIPT(binarizeNumber); +params [ + ["_number", nil, [0]], + ["_minLength", 8, [0]] +]; + +if (isNil "_number") exitWith {}; + +_number = round _number; + +private _array = []; +_array resize _minLength; + +for "_index" from 0 to (_minLength - 1) do { + _array set [_index, false]; +}; + +private _index = 0; + +while {_number > 0} do { + private _rest = _number mod 2; + _number = floor (_number / 2); + + _array set [_index, _rest == 1]; + _index = _index + 1; +}; + +_array; diff --git a/addons/common/fnc_endRadioTransmission.sqf b/addons/common/fnc_endRadioTransmission.sqf new file mode 100644 index 000000000..f2d230d2c --- /dev/null +++ b/addons/common/fnc_endRadioTransmission.sqf @@ -0,0 +1,45 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_endRadioTransmission + +Description: + End radio transmissions of addons TFAR and ACRE2. TFAR v0.9.x, ACRE Public Beta 2.0.3.571, TFAR v1.0.-1.x + +Parameters: + None + +Returns: + None + +Examples: + (begin example) + [] call CBA_fnc_endRadioTransmission + (end) + +Author: + commy2 +---------------------------------------------------------------------------- */ +SCRIPT(endRadioTransmission); + +["CBA_endRadioTransmissions"] call CBA_fnc_localEvent; +["ace_endRadioTransmissions"] call CBA_fnc_localEvent; // Ported from ACE + +// ACRE +if ("acre_main" call CBA_fnc_isModLoaded) then { + [-1] call acre_sys_core_fnc_handleMultiPttKeyPressUp; + [0] call acre_sys_core_fnc_handleMultiPttKeyPressUp; + [1] call acre_sys_core_fnc_handleMultiPttKeyPressUp; + [2] call acre_sys_core_fnc_handleMultiPttKeyPressUp; +}; + +// TFAR +if ("task_force_radio" call CBA_fnc_isModLoaded) then { + if ("tfar_core" call CBA_fnc_isModLoaded) exitWith { // Beta TFAR, exit to avoid script errors from legacy functions not existing + ([] call CBA_fnc_currentUnit) call TFAR_fnc_releaseAllTangents; + }; + [] call TFAR_fnc_onSwTangentReleased; + [] call TFAR_fnc_onAdditionalSwTangentReleased; + [] call TFAR_fnc_onLRTangentReleased; + [] call TFAR_fnc_onAdditionalLRTangentReleased; + [] call TFAR_fnc_onDDTangentReleased; +}; diff --git a/addons/common/fnc_isModLoaded.sqf b/addons/common/fnc_isModLoaded.sqf new file mode 100644 index 000000000..de7a2e3b5 --- /dev/null +++ b/addons/common/fnc_isModLoaded.sqf @@ -0,0 +1,24 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_isModLoaded +Description: + Check in CfgPatches if an addon is loaded + +Parameters: + _modName - Classname of the mod in CfgPatches + +Returns: + True if addon is loaded, otherwise false + +Examples + (begin example) + "class" call CBA_fnc_isModLoaded + (end) + +Authors: + Glowbal, Grim +---------------------------------------------------------------------------- */ +SCRIPT(isModLoaded); +params [["_modName", "", [""]]]; + +GVAR(isModLoadedCache) getOrDefaultCall [toLowerANSI _modName, { isClass (configFile >> "CfgPatches" >> _modName) }, true] diff --git a/addons/main/config.cpp b/addons/main/config.cpp index bc04591e6..b4f7ff2a5 100644 --- a/addons/main/config.cpp +++ b/addons/main/config.cpp @@ -8,31 +8,39 @@ class CfgPatches { weapons[] = {}; requiredVersion = REQUIRED_VERSION; requiredAddons[] = { + "cba_accessory", + "cba_ai", + "cba_arrays", + "cba_bitwise", + "cba_characters", "cba_common", + "cba_diagnostic", + "cba_disposable", "cba_events", "cba_hashes", + "cba_help", + "cba_jam", + "cba_jam_finish", + "cba_jr", "cba_jr_prep", "cba_keybinding", + "cba_loadout", + "cba_main", "cba_modules", "cba_music", "cba_network", + "cba_optics", + "cba_pid", + "cba_pylons", + "cba_quicktime", "cba_settings", "cba_statemachine", + "cba_statuseffects", "cba_strings", - "cba_vectors", - "cba_xeh", - "cba_accessory", - "cba_ai", - "cba_arrays", - "cba_diagnostic", - "cba_help", - "cba_jr", - "cba_jam", "cba_ui", + "cba_vectors", "cba_versioning", - "cba_optics", - "cba_disposable", - "cba_quicktime" + "cba_xeh", }; author = "$STR_CBA_Author"; authors[] = {}; diff --git a/addons/settings/XEH_preInit.sqf b/addons/settings/XEH_preInit.sqf index 7bd750313..42a04dab4 100644 --- a/addons/settings/XEH_preInit.sqf +++ b/addons/settings/XEH_preInit.sqf @@ -118,4 +118,12 @@ private _ctrlAddonOptions = (uiNamespace getVariable "RscDisplayMain") displayCt _ctrlAddonOptions ctrlEnable true; _ctrlAddonOptions ctrlSetTooltip LLSTRING(menu_button_tooltip); +GVAR(runAtSettingsInitialized) = []; +["CBA_settingsInitialized", { + { + (_this select 1) call (_this select 0); + } forEach GVAR(runAtSettingsInitialized); + GVAR(runAtSettingsInitialized) = nil; +}] call CBA_fnc_addEventHandler; + ADDON = true; diff --git a/addons/statuseffects/$PBOPREFIX$ b/addons/statuseffects/$PBOPREFIX$ new file mode 100644 index 000000000..a7387fcb4 --- /dev/null +++ b/addons/statuseffects/$PBOPREFIX$ @@ -0,0 +1 @@ +x\cba\addons\statuseffects diff --git a/addons/statuseffects/CfgEventHandlers.hpp b/addons/statuseffects/CfgEventHandlers.hpp new file mode 100644 index 000000000..ab13d7467 --- /dev/null +++ b/addons/statuseffects/CfgEventHandlers.hpp @@ -0,0 +1,17 @@ +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); + }; +}; + +class Extended_Engine_EventHandlers { + class All { + ADDON = QUOTE(call FUNC(handleEngine)); + }; +}; diff --git a/addons/statuseffects/CfgFunctions.hpp b/addons/statuseffects/CfgFunctions.hpp new file mode 100644 index 000000000..75dd80c83 --- /dev/null +++ b/addons/statuseffects/CfgFunctions.hpp @@ -0,0 +1,9 @@ +class CfgFunctions { + class CBA { + class StatusEffects { + PATHTO_FNC(addStatusEffectType); + PATHTO_FNC(getStatusEffect); + PATHTO_FNC(setStatusEffect); + }; + }; +}; diff --git a/addons/statuseffects/XEH_PREP.hpp b/addons/statuseffects/XEH_PREP.hpp new file mode 100644 index 000000000..78d5e2db1 --- /dev/null +++ b/addons/statuseffects/XEH_PREP.hpp @@ -0,0 +1,5 @@ +PREP(handleEngine); +PREP(localEH); +PREP(resetVariables); +PREP(respawnEH); +PREP(sendEffects); diff --git a/addons/statuseffects/XEH_postInit.sqf b/addons/statuseffects/XEH_postInit.sqf new file mode 100644 index 000000000..d72323f55 --- /dev/null +++ b/addons/statuseffects/XEH_postInit.sqf @@ -0,0 +1,145 @@ +#include "script_component.hpp" + +[QGVAR(setStatusEffect), CBA_fnc_setStatusEffect] call CBA_fnc_addEventHandler; +["forceWalk", false, ["ace_advanced_fatigue", "ace_attach", "ace_dragging", "ace_explosives", "ace_medical_fracture", "ace_rearm", "ace_refuel", "ace_sandbag", "ace_switchunits", "ace_tacticalladder", "ace_trenches"]] call CBA_fnc_addStatusEffectType; +["blockSprint", false, ["ace_advanced_fatigue", "ace_dragging", "ace_medical_fracture"]] call CBA_fnc_addStatusEffectType; +["setCaptive", true, ["ace_captives_handcuffed", "ace_captives_surrendered"]] call CBA_fnc_addStatusEffectType; +["blockDamage", false, ["fixCollision", "ace_cargo"]] call CBA_fnc_addStatusEffectType; +["blockEngine", false, ["ace_refuel"]] call CBA_fnc_addStatusEffectType; +["blockThrow", false, ["ace_attach", "ace_concertina_wire", "ace_dragging", "ace_explosives", "ace_rearm", "ace_refuel", "ace_sandbag", "ace_tacticalladder", "ace_trenches", "ace_tripod"]] call CBA_fnc_addStatusEffectType; +["setHidden", true, ["ace_unconscious"]] call CBA_fnc_addStatusEffectType; +["blockRadio", false, ["ace_captives_handcuffed", "ace_captives_surrendered", "ace_unconscious"]] call CBA_fnc_addStatusEffectType; +["blockSpeaking", false, ["ace_unconscious"]] call CBA_fnc_addStatusEffectType; +["disableWeaponAssembly", false, ["CBA_lockVehicle", "ace_common", "ace_csw"]] call CBA_fnc_addStatusEffectType; +["lockInventory", true, [], true] call CBA_fnc_addStatusEffectType; +["disableCollision", true, [], true] call CBA_fnc_addStatusEffectType; +["disableNVGEquipment", false, []] call CBA_fnc_addStatusEffectType; +["disableTIEquipment", false, []] call CBA_fnc_addStatusEffectType; + +[QGVAR(forceWalk), { + params ["_object", "_set"]; + TRACE_2("forceWalk EH",_object,_set); + _object forceWalk (_set > 0); +}] call CBA_fnc_addEventHandler; + +[QGVAR(blockSprint), { // Name reversed from `allowSprint` because we want NOR logic + params ["_object", "_set"]; + TRACE_2("blockSprint EH",_object,_set); + _object allowSprint (_set == 0); +}] call CBA_fnc_addEventHandler; + +[QGVAR(setCaptive), { + params ["_object", "_set"]; + TRACE_2("setCaptive EH",_object,_set); + _object setCaptive (_set > 0); +}] call CBA_fnc_addEventHandler; + +[QGVAR(setHidden), { + params ["_object", "_set"]; + TRACE_2("setHidden EH",_object,_set); + // May report nil. Default to factor 1. + private _vis = [_object getUnitTrait "camouflageCoef"] param [0, 1]; + if (_set > 0) then { + if (_vis != 0) then { + _object setVariable [QGVAR(oldVisibility), _vis]; + _object setUnitTrait ["camouflageCoef", 0]; + { + if (side _x != side group _object) then { + _x forgetTarget _object; + }; + } forEach allGroups; + }; + } else { + _vis = _object getVariable [QGVAR(oldVisibility), _vis]; + _object setUnitTrait ["camouflageCoef", _vis]; + }; +}] call CBA_fnc_addEventHandler; + +[QGVAR(blockRadio), { + params ["_object", "_set"]; + TRACE_2("blockRadio EH",_object,_set); + private _disable = _set > 0; + if (_disable && { _object isEqualTo ([] call CBA_fnc_currentUnit) }) then { + [] call CBA_fnc_endRadioTransmission; + }; + if ("task_force_radio" call CBA_fnc_isModLoaded) then { + _object setVariable ["tf_unable_to_use_radio", _disable, true]; + }; + if ("acre_main" call CBA_fnc_isModLoaded) then { + _object setVariable ["acre_sys_core_isDisabledRadio", _disable, true]; + }; +}] call CBA_fnc_addEventHandler; + +[QGVAR(blockSpeaking), { + params ["_object", "_set"]; + TRACE_2("blockSpeaking EH",_object,_set); + if ("task_force_radio" call CBA_fnc_isModLoaded) then { + _object setVariable ["tf_voiceVolume", parseNumber (_set == 0), true]; + }; + if ("acre_main" call CBA_fnc_isModLoaded) then { + _object setVariable ["acre_sys_core_isDisabled", _set > 0, true]; + }; +}] call CBA_fnc_addEventHandler; + +[QGVAR(blockDamage), { // Name reversed from `allowDamage` because we want NOR logic + params ["_object", "_set"]; + if ((_object isKindOf "CAManBase") && { "ace_medical" call CBA_fnc_isModLoaded }) then { + TRACE_2("blockDamage EH (using medical)",_object,_set); + _object setVariable ["ace_medical_allowDamage", (_set == 0), true]; + } else { + TRACE_2("blockDamage EH (using allowDamage)",_object,_set); + _object allowDamage (_set == 0); + }; +}] call CBA_fnc_addEventHandler; + +[QGVAR(blockEngine), { + params ["_vehicle", "_set"]; + _vehicle setVariable ["CBA_blockEngine", _set > 0, true]; + _vehicle engineOn false; +}] call CBA_fnc_addEventHandler; + +[QGVAR(disableWeaponAssembly), { + params ["_object", "_set"]; + _object enableWeaponDisassembly (_set < 1); +}] call CBA_fnc_addEventHandler; + +[QGVAR(lockInventory), { + params ["_object", "_set"]; + TRACE_2("lockInventory EH",_object,_set); + _object lockInventory (_set > 0); +}] call CBA_fnc_addEventHandler; + +[QGVAR(lockVehicle), { + _this setVariable ["CBA_lockStatus", locked _this]; + _this lock 2; + if ([] isNotEqualTo getArray (configOf _this >> "assembleInfo" >> "dissasembleTo")) then { + [_this, "disableWeaponAssembly", "CBA_lockVehicle", true] call CBA_fnc_setStatusEffect; + }; +}] call CBA_fnc_addEventHandler; + +[QGVAR(unlockVehicle), { + _this lock (_this getVariable ["CBA_lockStatus", locked _this]); + if ([] isNotEqualTo getArray (configOf _this >> "assembleInfo" >> "dissasembleTo")) then { + [_this, "disableWeaponAssembly", "CBA_lockVehicle", false] call CBA_fnc_setStatusEffect; + }; +}] call CBA_fnc_addEventHandler; + +[QGVAR(disableCollision), { // Name "reversed" from `setPhysicsCollisionFlag` because we want NOR logic + params ["_object", "_set"]; + TRACE_2("disableCollision EH",_object,_set); + _object setPhysicsCollisionFlag (_set < 1); +}] call CBA_fnc_addEventHandler; + +// TODO: disableNVG/TIEquipment only work on vehicles, but we could make the status effects work for units as well +// One possible solution would be hooking into VisionModeChanged and using `player action ["NvGogglesOff", player]` +[QGVAR(disableNVGEquipment), { + params ["_object", "_set"]; + _object disableNVGEquipment (_set > 0); + TRACE_2("disableNVGEquipment EH",_object,_set); +}] call CBA_fnc_addEventHandler; + +[QGVAR(disableTIEquipment), { + params ["_object", "_set"]; + TRACE_2("disableTIEquipment EH",_object,_set); + _object disableTIEquipment (_set > 0); +}] call CBA_fnc_addEventHandler; diff --git a/addons/statuseffects/XEH_preInit.sqf b/addons/statuseffects/XEH_preInit.sqf new file mode 100644 index 000000000..da51b0844 --- /dev/null +++ b/addons/statuseffects/XEH_preInit.sqf @@ -0,0 +1,9 @@ +#include "script_component.hpp" + +ADDON = false; + +#include "XEH_PREP.hpp" + +GVAR(statusEffects) = createHashMap; + +ADDON = true; diff --git a/addons/statuseffects/XEH_preStart.sqf b/addons/statuseffects/XEH_preStart.sqf new file mode 100644 index 000000000..022888575 --- /dev/null +++ b/addons/statuseffects/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/statuseffects/config.cpp b/addons/statuseffects/config.cpp new file mode 100644 index 000000000..b3fd81b40 --- /dev/null +++ b/addons/statuseffects/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = CSTRING(component); + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"cba_common", "cba_settings"}; + author = "$STR_CBA_Author"; + authors[] = {"PabstMirror", "DartRuffian"}; + url = "$STR_CBA_URL"; + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgFunctions.hpp" diff --git a/addons/statuseffects/fnc_addStatusEffectType.sqf b/addons/statuseffects/fnc_addStatusEffectType.sqf new file mode 100644 index 000000000..c4775ebca --- /dev/null +++ b/addons/statuseffects/fnc_addStatusEffectType.sqf @@ -0,0 +1,47 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_addStatusEffectType +Description: + Adds a status effect that will be handled. + +Parameters: + _name - Status Effect Name, this should match a corresponding event name + _isGlobal - Send event globally (optional, default: false) + _commonReasonsArray - Common Effect Reasons to pre-seed during init (optional, default: []) + _sendJIP - Send event to JIP (requires sending event globally) (default: false) + _eventName - Event name (default: "CBA_statusEffects_") + +Returns: + None + +Examples + (begin example) + ["setCaptive", true, []] call CBA_fnc_addStatusEffectType + (end) + +Author: + PabstMirror +---------------------------------------------------------------------------- */ +SCRIPT(addStatusEffectType); +params [ + ["_name", "", [""]], + ["_isGlobal", false, [false]], + ["_commonReasonsArray", [], [[]]], + ["_sendJIP", false, [false]], + ["_eventName", "", [""]] +]; + +_name = toLowerANSI _name; +if (_name == "") exitWith {ERROR_1("addStatusEffectType - Bad Name %1",_this)}; +if (_name in GVAR(statusEffects)) exitWith {WARNING_1("addStatusEffectType - Effect Already Added (note, will not update global bit) %1",_this)}; +if (_sendJIP && !_isGlobal) exitWith {WARNING_1("addStatusEffectType - Trying to add non-global JIP effect %1",_this)}; +if (_eventName == "") then { _eventName = format [QGVAR(%1), _name]; }; + +GVAR(statusEffects) set [_name, [_isGlobal, _sendJIP, _eventName]]; + +// We add reasons at any time, but more efficenet to add all common ones at one time during init +if (isServer && {_commonReasonsArray isNotEqualTo []}) then { + // Switch case to lower: + _commonReasonsArray = _commonReasonsArray apply { toLowerANSI _x }; + missionNamespace setVariable [(format [QGVAR(statusEffects_%1), _name]), _commonReasonsArray, true]; +}; diff --git a/addons/statuseffects/fnc_getStatusEffect.sqf b/addons/statuseffects/fnc_getStatusEffect.sqf new file mode 100644 index 000000000..155a69166 --- /dev/null +++ b/addons/statuseffects/fnc_getStatusEffect.sqf @@ -0,0 +1,68 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_getStatusEffect +Description: + Retrieves list of current status effects + +Parameters: + _object - Vehicle that it will be attached to (player or vehicle) + _effectName - Effect Name + +Returns: + Effect status + - 0: is actively set (if false, the effect is ignored and never modified) + - 1: reasons why it is set true (list of strings, count of 0 = false, 1+ = true) + +Examples + (begin example) + [player, "forceWalk"] call CBA_fnc_getStatusEffect + (end) + +Author: + PabstMirror +---------------------------------------------------------------------------- */ +SCRIPT(getStatusEffect); +params [ + ["_object", objNull, [objNull]], + ["_effectName", "", [""]] +]; + +if (isNull _object) exitWith { + TRACE_1("null",_object); + [false, []] +}; + +[_object, false] call FUNC(resetVariables); // Check for mismatch + +// List of reasons +private _statusReasons = missionNamespace getVariable [(format [QGVAR(statusEffects_%1), _effectName]), []]; +if (_statusReasons isEqualTo []) exitWith { + TRACE_1("no reasons - bad effect?",_statusReasons); + [false, []] +}; + +// Get Effect Number +private _effectVarName = format [QGVAR(effect_%1), _effectName]; +private _effectNumber = _object getVariable [_effectVarName, -1]; +TRACE_2("current",_effectVarName,_effectNumber); + +if (_effectNumber == -1) exitWith { // Nil array - no effect + [false, []] +}; +if (_effectNumber == 0) exitWith { // Empty array - false effect + [true, []] +}; + +// If no change: skip sending publicVar and events +private _effectBoolArray = [_effectNumber, count _statusReasons] call CBA_fnc_binarizeNumber; +TRACE_1("bitArray",_effectBoolArray); + +private _activeEffects = []; +{ + if (_x) then { + _activeEffects pushBack (_statusReasons select _forEachIndex); + }; +} forEach _effectBoolArray; + +// Non-empty array - true effect +[true, _activeEffects] diff --git a/addons/statuseffects/fnc_handleEngine.sqf b/addons/statuseffects/fnc_handleEngine.sqf new file mode 100644 index 000000000..ddf5a9ef8 --- /dev/null +++ b/addons/statuseffects/fnc_handleEngine.sqf @@ -0,0 +1,27 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_statusEffects_fnc_handleEngine +Description: + Blocks turning on the vehicles engine if set by the status effect handler. + +Parameters: + _vehicle - Vehicle + _engineState - Engine state + +Returns: + None + +Examples + (begin example) + [player, true] call CBA_statusEffects_fnc_handleEngine + (end) + +Author: + BaerMitUmlaut +---------------------------------------------------------------------------- */ +SCRIPT(handleEngine); +params ["_vehicle", "_engineOn"]; + +if (local _vehicle && _engineOn && {_vehicle getVariable ["CBA_blockEngine", false]}) then { + _vehicle engineOn false; +}; diff --git a/addons/statuseffects/fnc_localEH.sqf b/addons/statuseffects/fnc_localEH.sqf new file mode 100644 index 000000000..dae0126e4 --- /dev/null +++ b/addons/statuseffects/fnc_localEH.sqf @@ -0,0 +1,39 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_statusEffects_fnc_localEH +Description: + Handles locality switch, runs a respawn check and then reapplies all effect events. + +Parameters: + _object - Vehicle that it will be attached to (player or vehicle) + _isLocal - Is local + +Returns: + None + +Examples + (begin example) + [player, true] call CBA_statusEffects_fnc_localEH + (end) + +Author: + PabstMirror +---------------------------------------------------------------------------- */ +SCRIPT(localEH); +params ["_object", "_isLocal"]; + +// Only run this after the settings are initialized +// Need to wait for all EH to be installed (local event will happen between pre and post init) +if !(missionNamespace getVariable [QEGVAR(settings,ready), false]) exitWith { + TRACE_1("pushing to runAtSettingsInitialized",_this); + EGVAR(settings,runAtSettingsInitialized) pushBack [FUNC(localEH), _this]; +}; + +if (!_isLocal) exitWith { TRACE_1("object no longer local",_this) }; +if (isNull _object) exitWith { TRACE_1("object null",_this) }; + +// Reset any variables because of respawn +[_object, false] call FUNC(resetVariables); + +// Send all Variables to client +[_object, ""] call FUNC(sendEffects); diff --git a/addons/statuseffects/fnc_resetVariables.sqf b/addons/statuseffects/fnc_resetVariables.sqf new file mode 100644 index 000000000..729cd156f --- /dev/null +++ b/addons/statuseffects/fnc_resetVariables.sqf @@ -0,0 +1,51 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_statusEffects_fnc_resetVariables +Description: + Resets all effect numbers to 0 when an object respawns (but does not apply the effect event). + +Parameters: + _object - Vehicle that it will be attached to (player or vehicle) + _setObjectRef - Explicitly set object reference (optional, default: false) + +Returns: + None + +Examples + (begin example) + [player, true] call CBA_statusEffects_fnc_resetVariables + (end) + +Author: + PabstMirror +---------------------------------------------------------------------------- */ +SCRIPT(resetVariables); +params [ + ["_object", objNull, [objNull]], + ["_setObjectRef", false, [false]] +]; + +if (isNull _object) exitWith {}; + +private _objectRef = _object getVariable QGVAR(object); +TRACE_2("testing",_object,_objectRef); + +// If nothing was ever set, or objects match, exit (always true unless respawned) +if (isNil "_objectRef") exitWith { + if (_setObjectRef) then { + _object setVariable [QGVAR(object), _object, true]; // Explicitly set new object ref + }; +}; +if (_object == _objectRef) exitWith {}; + +// Mismatch, so if effect has ever been defined, reset to 0 +{ + private _effectVarName = format [QGVAR(effect_%1), _x]; + private _effectNumber = _object getVariable [_effectVarName, -1]; + if (_effectNumber != -1) then { + TRACE_2("forced reset defined array on object mismatch",_x,_effectNumber); + _object setVariable [_effectVarName, 0, true]; // This always resets to 0 (not -1/nil)! + }; +} forEach GVAR(statusEffects); + +_object setVariable [QGVAR(statusEffect_object), _object, true]; diff --git a/addons/statuseffects/fnc_respawnEH.sqf b/addons/statuseffects/fnc_respawnEH.sqf new file mode 100644 index 000000000..0d05c5660 --- /dev/null +++ b/addons/statuseffects/fnc_respawnEH.sqf @@ -0,0 +1,38 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_statusEffects_fnc_respawnEH +Description: + Handles the Respawn Event Handler to reset effects. + +Parameters: + _object - Vehicle that it will be attached to (player or vehicle) + +Returns: + None + +Examples + (begin example) + [player, objNull] call CBA_statusEffects_fnc_respawnEH + (end) + +Author: + PabstMirror +---------------------------------------------------------------------------- */ +SCRIPT(respawnEH); +params ["_object"]; + +// Only run this after the settings are initialized +// Need to wait for all EH to be installed (local event will happen between pre and post init) +if !(missionNamespace getVariable [QEGVAR(settings,ready), false]) exitWith { + TRACE_1("pushing to runAtSettingsInitialized",_this); + EGVAR(settings,runAtSettingsInitialized) pushBack [FUNC(respawnEH), _this]; +}; + +if (!local _object) exitWith {TRACE_1("object no longer local",_this)}; +if (isNull _object) exitWith {TRACE_1("object null",_this)}; + + // Reset any variables on "real" respawn +[_object, false] call FUNC(resetVariables); + +// Send all Variables to client +[_object, ""] call FUNC(sendEffects); diff --git a/addons/statuseffects/fnc_sendEffects.sqf b/addons/statuseffects/fnc_sendEffects.sqf new file mode 100644 index 000000000..4fc690ba1 --- /dev/null +++ b/addons/statuseffects/fnc_sendEffects.sqf @@ -0,0 +1,60 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_statusEffects_fnc_sendEffects +Description: + Sends all status effects for an object (can be run on non-local objects) + +Parameters: + _object - Object + _effectName - Effect name (or "" to send all) + +Returns: + None + +Examples + (begin example) + [player, ""] call CBA_statusEffects_fnc_sendEffects + (end) + +Author: + PabstMirror +---------------------------------------------------------------------------- */ +SCRIPT(sendEffects); +params [ + ["_object", objNull, [objNull]], + ["_effectName", "", [""]] +]; + +if (isNull _object) exitWith {}; + +if (_effectName == "") exitWith { // Recurse through all possible effects + { + [_object, _x] call FUNC(sendEffects) + } forEach (keys GVAR(statusEffects)); +}; + + +private _effectVarName = format [QGVAR(effect_%1), _effectName]; +private _effectNumber = _object getVariable [_effectVarName, -1]; + +// We only do anything if the effect has been defined at some point in the game for this unit +TRACE_2("checking if event is nil",_effectName,_effectNumber); +if (_effectNumber != -1) then { + (GVAR(statusEffects) get toLowerANSI _effectName) params ["_isGlobal", "_sendJIP", "_eventName"]; + switch (true) do { + case (_sendJIP): { + TRACE_3("Sending Global JIP Event",_object,_effectNumber,_eventName); + private _jipID = format [QGVAR(effect_%1_%2), _eventName, hashValue _object]; + [_eventName, [_object, _effectNumber], _jipID] call CBA_fnc_globalEventJIP; + [_jipID, _object] call CBA_fnc_removeGlobalEventJIP; + }; + case (_isGlobal): { + TRACE_3("Sending Global Event",_object,_effectNumber,_eventName); + [_eventName, [_object, _effectNumber]] call CBA_fnc_globalEvent; + }; + default { + TRACE_3("Sending Target Event",_object,_effectNumber,_eventName); + [_eventName, [_object, _effectNumber], _object] call CBA_fnc_targetEvent; + }; + }; +}; diff --git a/addons/statuseffects/fnc_setStatusEffect.sqf b/addons/statuseffects/fnc_setStatusEffect.sqf new file mode 100644 index 000000000..d811c7bec --- /dev/null +++ b/addons/statuseffects/fnc_setStatusEffect.sqf @@ -0,0 +1,81 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_setStatusEffect +Description: + Adds or removes an id to a status effect and will send an event to apply. + +Parameters: + _object - Vehicle that it will be attached to (player or vehicle) + _effectName - Effect Name + _id - Unique Reason ID + _set - Is Set (true adds/false removes) + +Returns: + None + +Examples + (begin example) + [player, "setCaptive", "reason1", true] call CBA_fnc_setStatusEffect + (end) + +Author: + PabstMirror +---------------------------------------------------------------------------- */ +SCRIPT(sendEffects); +params [ + ["_object", objNull, [objNull]], + ["_effectName", "", [""]], + ["_id", "", [""]], + ["_set", true, [false]] +]; + +// Only run this after the settings are initialized +if !(missionNamespace getVariable [QEGVAR(settings,ready), false]) exitWith { + TRACE_1("pushing to runAtSettingsInitialized",_this); + EGVAR(settings,runAtSettingsInitialized) pushBack [CBA_fnc_setStatusEffect, _this]; +}; + +if (isNull _object) exitWith {TRACE_1("null",_object);}; + +[_object, true] call FUNC(resetVariables); // Check for mismatch, and set object ref + +// Check ID case and set globally if not already set: +_id = toLowerANSI _id; +private _statusReasons = missionNamespace getVariable [(format [QGVAR(statusEffects_%1), _effectName]), []]; +private _statusIndex = _statusReasons find _id; +if (_statusIndex == -1) then { + TRACE_2("ID not in global reasons, adding",_statusReasons,_id); + _statusIndex = _statusReasons pushBack _id; + missionNamespace setVariable [(format [QGVAR(statusEffects_%1), _effectName]), _statusReasons, true]; +}; + +private _effectVarName = format [QGVAR(effect_%1), _effectName]; +private _effectNumber = _object getVariable [_effectVarName, -1]; +TRACE_2("current",_effectVarName,_effectNumber); + +if ((_effectNumber == -1) && {!_set}) exitWith { + // Optimization for modules that always set an ID to false even if never set true + TRACE_2("Set False on nil array, exiting",_set,_effectNumber); +}; + +if (_effectNumber == -1) then {_effectNumber = 0}; // Reset (-1/nil) to 0 + +// If no change: skip sending publicVar and events +private _effectBoolArray = [_effectNumber, count _statusReasons] call CBA_fnc_binarizeNumber; +TRACE_2("bitArray",_statusIndex,_effectBoolArray); +if (_set isEqualTo (_effectBoolArray select _statusIndex)) exitWith { + TRACE_2("No Change, exiting",_set,_effectBoolArray select _statusIndex); +}; + +TRACE_2("Setting to new value",_set,_effectBoolArray select _statusIndex); +_effectBoolArray set [_statusIndex, _set]; +private _newEffectNumber = [_effectBoolArray] call CBA_fnc_toBitmask; // Convert array back to number + +TRACE_2("Saving globally",_effectVarName,_newEffectNumber); +_object setVariable [_effectVarName, _newEffectNumber, true]; + +if (_effectNumber == 0 || _newEffectNumber == 0) then { + [_object, _effectName] call FUNC(sendEffects); +} else { + LOG("not sending more than once"); +}; diff --git a/addons/statuseffects/script_component.hpp b/addons/statuseffects/script_component.hpp new file mode 100644 index 000000000..11d809d59 --- /dev/null +++ b/addons/statuseffects/script_component.hpp @@ -0,0 +1,16 @@ +#define COMPONENT statuseffects +#include "\x\cba\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define DEBUG_ENABLED_STATUSEFFECTS + +#ifdef DEBUG_ENABLED_STATUSEFFECTS + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_STATUSEFFECTS + #define DEBUG_SETTINGS DEBUG_SETTINGS_STATUSEFFECTS +#endif + +#include "\x\cba\addons\main\script_macros.hpp" diff --git a/addons/statuseffects/stringtable.xml b/addons/statuseffects/stringtable.xml new file mode 100644 index 000000000..427c5022e --- /dev/null +++ b/addons/statuseffects/stringtable.xml @@ -0,0 +1,8 @@ + + + + + Community Base Addons - Status Effects Component + + +