From 62556d303b282ddbed6c66b337551ee0645af488 Mon Sep 17 00:00:00 2001 From: LinkIsGrim Date: Thu, 26 Oct 2023 20:10:36 -0400 Subject: [PATCH 01/14] groundwork (replace items on heal order) --- addons/medical_engine/CfgWeapons.hpp | 11 -------- addons/medical_engine/XEH_PREP.hpp | 1 + addons/medical_engine/XEH_postInit.sqf | 16 ++++++++++- addons/medical_engine/config.cpp | 1 - .../functions/fnc_commandChanged.sqf | 27 +++++++++++++++++++ addons/medical_treatment/XEH_postInit.sqf | 1 - addons/medical_treatment/initSettings.sqf | 2 +- 7 files changed, 44 insertions(+), 15 deletions(-) delete mode 100644 addons/medical_engine/CfgWeapons.hpp create mode 100644 addons/medical_engine/functions/fnc_commandChanged.sqf diff --git a/addons/medical_engine/CfgWeapons.hpp b/addons/medical_engine/CfgWeapons.hpp deleted file mode 100644 index b4e3572620e..00000000000 --- a/addons/medical_engine/CfgWeapons.hpp +++ /dev/null @@ -1,11 +0,0 @@ - -class CfgWeapons { - // Remove items from Virtual Arsenal. - class ItemCore; - class FirstAidKit: ItemCore { - type = 0; - }; - class Medikit: ItemCore { - type = 0; - }; -}; diff --git a/addons/medical_engine/XEH_PREP.hpp b/addons/medical_engine/XEH_PREP.hpp index ffc3543745d..349f95be5e7 100644 --- a/addons/medical_engine/XEH_PREP.hpp +++ b/addons/medical_engine/XEH_PREP.hpp @@ -1,4 +1,5 @@ PREP(applyAnimAfterRagdoll); +PREP(commandChanged); PREP(damageBodyPart); PREP(disableThirdParty); PREP(getHitpointArmor); diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index 6455904f95e..35e3bc1e662 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -30,6 +30,11 @@ }; }, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; +if !("ace_medical_treatment" call EFUNC(common,isModLoaded)) then { + [TYPE_FIRST_AID_KIT, ""] call EFUNC(common,registerItemReplacement); + [TYPE_MEDIKIT, ""] call EFUNC(common,registerItemReplacement); +}; + #ifdef DEBUG_MODE_FULL [QEGVAR(medical,woundReceived), { params ["_unit", "_damages", "_shooter", "_ammo"]; @@ -38,7 +43,6 @@ }] call CBA_fnc_addEventHandler; #endif - // this handles moving units into vehicles via load functions or zeus // needed, because the vanilla INCAPACITATED state does not handle vehicles ["CAManBase", "GetInMan", { @@ -96,3 +100,13 @@ [_unit] call FUNC(unlockUnconsciousSeat); }; }, true, []] call CBA_fnc_addClassEventHandler; + +// Used for preventing vanilla heal by replacing items +addMissionEventHandler ["GroupCreated", { + params ["_group"]; + _group addEventHandler ["CommandChanged", {_this call FUNC(commandChanged)}]; +}]; + +{ + _x addEventHandler ["CommandChanged", {_this call FUNC(commandChanged)}]; +} forEach allGroups; diff --git a/addons/medical_engine/config.cpp b/addons/medical_engine/config.cpp index 8d718155d1f..a005dcebd0c 100644 --- a/addons/medical_engine/config.cpp +++ b/addons/medical_engine/config.cpp @@ -27,6 +27,5 @@ class CfgPatches { #include "CfgFunctions.hpp" #include "CfgMoves.hpp" #include "CfgVehicles.hpp" -#include "CfgWeapons.hpp" #endif diff --git a/addons/medical_engine/functions/fnc_commandChanged.sqf b/addons/medical_engine/functions/fnc_commandChanged.sqf new file mode 100644 index 00000000000..392de21362e --- /dev/null +++ b/addons/medical_engine/functions/fnc_commandChanged.sqf @@ -0,0 +1,27 @@ +#include "..\script_component.hpp" +/* + * Author: LinkIsGrim + * Intercepts group heal attempts and replaces items + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_medical_engine_fnc_commandChanged + * + * Public: No + */ +params ["_group", "_newCommand"]; + +if (!local _group) exitWith {}; +if !(_newCommand in ["HEAL", "HEAL SOLDIER", "PATCH SOLDIER", "FIRST AID", "HEAL SELF", "SUPPORT"]) exitWith {}; + +{ + _x call EFUNC(common,replaceRegisteredItems); + if (!unitReady _x) then { + [_x] joinSilent (leader _group) + }; +} forEach (units _group); diff --git a/addons/medical_treatment/XEH_postInit.sqf b/addons/medical_treatment/XEH_postInit.sqf index 4c7a780fc3b..c76ecc81f36 100644 --- a/addons/medical_treatment/XEH_postInit.sqf +++ b/addons/medical_treatment/XEH_postInit.sqf @@ -36,7 +36,6 @@ if (isServer) then { // replace medical items with their ACE equivalents ["CBA_settingsInitialized", { TRACE_1("CBA_settingsInitialized EH",GVAR(convertItems)); // 0: Enabled 1: RemoveOnly 2:Disabled - if (GVAR(convertItems) == 2) exitWith {}; { // turn [["stuff", 2], ...] into ["stuff", "stuff", ...] private _replacements = []; diff --git a/addons/medical_treatment/initSettings.sqf b/addons/medical_treatment/initSettings.sqf index 0193a445466..b09efe186cf 100644 --- a/addons/medical_treatment/initSettings.sqf +++ b/addons/medical_treatment/initSettings.sqf @@ -85,7 +85,7 @@ "LIST", [LSTRING(ConvertItems_DisplayName), LSTRING(ConvertItems_Description)], [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], - [[0, 1, 2], [ELSTRING(common,Enabled), LSTRING(ConvertItems_RemoveOnly), ELSTRING(common,Disabled)], 0], + [[0, 1], [ELSTRING(common,Enabled), LSTRING(ConvertItems_RemoveOnly)], 0], true ] call CBA_fnc_addSetting; From 7d6508eb82b91eaa73bfb7e3835a57174f51438a Mon Sep 17 00:00:00 2001 From: LinkIsGrim Date: Thu, 26 Oct 2023 20:13:22 -0400 Subject: [PATCH 02/14] CfgActions --- addons/medical_engine/CfgActions.hpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/addons/medical_engine/CfgActions.hpp b/addons/medical_engine/CfgActions.hpp index 425b33dbceb..3b14e56be85 100644 --- a/addons/medical_engine/CfgActions.hpp +++ b/addons/medical_engine/CfgActions.hpp @@ -1,18 +1,6 @@ class CfgActions { class None; - class Heal: None { - show = 0; - }; - class HealSoldier: None { - show = 0; - }; - class HealSoldierSelf: None { - show = 0; - }; - class FirstAid: None { - show = 0; - }; class UnloadUnconsciousUnits: None { show = 0; }; From 3264e9ecb2e16a8ab3ef146388e980557c1a530c Mon Sep 17 00:00:00 2001 From: LinkIsGrim Date: Thu, 26 Oct 2023 20:28:46 -0400 Subject: [PATCH 03/14] add setting, stringtable --- addons/medical_engine/initSettings.sqf | 12 ++++++++++++ addons/medical_engine/stringtable.xml | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/addons/medical_engine/initSettings.sqf b/addons/medical_engine/initSettings.sqf index 062e2a08220..b60ab233443 100644 --- a/addons/medical_engine/initSettings.sqf +++ b/addons/medical_engine/initSettings.sqf @@ -1,3 +1,15 @@ +[ + QEGVAR(medical,enabled), + "CHECKBOX", + [LSTRING(Enabled_DisplayName), LSTRING(Enabled_Description)], + ELSTRING(medical,Category), + true, + true, { + [QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged) + }, + true // Needs mission restart +] call CBA_fnc_addSetting; + [ QEGVAR(medical,enableVehicleCrashes), "CHECKBOX", diff --git a/addons/medical_engine/stringtable.xml b/addons/medical_engine/stringtable.xml index ac2968bd0f2..a4614d57ae4 100644 --- a/addons/medical_engine/stringtable.xml +++ b/addons/medical_engine/stringtable.xml @@ -1,6 +1,12 @@ + + Enable Medical System + + + Controls whether ACE's Medical System is enabled. Disabling the medical system through this setting is experimental, and may not be compatible with other mods.\nUse the No Medical optional component instead if you have issues. + Enable Vehicle Crash Damage Вкл. урон при аварии в транспорте From e0c99fb6b5634ccfa3aba953678b551bd02b4b9d Mon Sep 17 00:00:00 2001 From: LinkIsGrim Date: Thu, 26 Oct 2023 20:32:19 -0400 Subject: [PATCH 04/14] indentation --- addons/medical_engine/stringtable.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/medical_engine/stringtable.xml b/addons/medical_engine/stringtable.xml index a4614d57ae4..4f503e7ca4e 100644 --- a/addons/medical_engine/stringtable.xml +++ b/addons/medical_engine/stringtable.xml @@ -1,7 +1,7 @@ - + Enable Medical System From 9db6e4cbeecde90c46d4856bb50baded18806b41 Mon Sep 17 00:00:00 2001 From: LinkIsGrim Date: Tue, 31 Oct 2023 19:43:08 -0400 Subject: [PATCH 05/14] add team handling, improve unit selection --- addons/medical_engine/XEH_postInit.sqf | 1 - addons/medical_engine/XEH_preInit.sqf | 2 ++ .../medical_engine/functions/fnc_commandChanged.sqf | 13 +++++-------- addons/medical_engine/script_macros_medical.hpp | 3 +++ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index 35e3bc1e662..d65c6723e71 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -6,7 +6,6 @@ [_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture) }, true] call CBA_fnc_addPlayerEventHandler; - ["CAManBase", "init", { params ["_unit"]; diff --git a/addons/medical_engine/XEH_preInit.sqf b/addons/medical_engine/XEH_preInit.sqf index 379b30da4bc..68e85f8641d 100644 --- a/addons/medical_engine/XEH_preInit.sqf +++ b/addons/medical_engine/XEH_preInit.sqf @@ -31,6 +31,8 @@ if (isNil QUOTE(FATAL_SUM_DAMAGE_WEIBULL_K) || isNil QUOTE(FATAL_SUM_DAMAGE_WEIB FATAL_SUM_DAMAGE_WEIBULL_L = _x1 / _b1^(1/FATAL_SUM_DAMAGE_WEIBULL_K); }; +OVERRIDDEN_COMMANDS = ["HEAL", "HEAL SOLDIER", "PATCH SOLDIER", "FIRST AID", "HEAL SELF", "SUPPORT"] createHashMapFromArray []; + // Cache for armor values of equipped items (vests etc) GVAR(armorCache) = createHashMap; diff --git a/addons/medical_engine/functions/fnc_commandChanged.sqf b/addons/medical_engine/functions/fnc_commandChanged.sqf index 392de21362e..3b341188340 100644 --- a/addons/medical_engine/functions/fnc_commandChanged.sqf +++ b/addons/medical_engine/functions/fnc_commandChanged.sqf @@ -9,19 +9,16 @@ * Return Value: * None * - * Example: - * [] call ace_medical_engine_fnc_commandChanged - * * Public: No */ params ["_group", "_newCommand"]; if (!local _group) exitWith {}; -if !(_newCommand in ["HEAL", "HEAL SOLDIER", "PATCH SOLDIER", "FIRST AID", "HEAL SELF", "SUPPORT"]) exitWith {}; +if !(_newCommand in OVERRIDDEN_COMMANDS) exitWith {}; { _x call EFUNC(common,replaceRegisteredItems); - if (!unitReady _x) then { - [_x] joinSilent (leader _group) - }; -} forEach (units _group); + private _assignedTeam = assignedTeam _x; + [_x] joinSilent (leader _group); + _x assignTeam _assignedTeam; +} forEach ((units _group) select {(currentCommand _x) == _newCommand}); diff --git a/addons/medical_engine/script_macros_medical.hpp b/addons/medical_engine/script_macros_medical.hpp index 56c1eec4016..07448c9ce88 100644 --- a/addons/medical_engine/script_macros_medical.hpp +++ b/addons/medical_engine/script_macros_medical.hpp @@ -106,6 +106,9 @@ #define FRACTURE_DAMAGE_THRESHOLD EGVAR(medical,const_fractureDamageThreshold) #define FRACTURE_DAMAGE_THRESHOLD_DEFAULT 0.50 +// Overridden commands for group healing +#define OVERRIDDEN_COMMANDS EGVAR(medical,overriddenCommands) + // Minimum body part damage required for blood effect on uniform #define VISUAL_BODY_DAMAGE_THRESHOLD 0.35 From b7d1bc5bb6133492df23c578fe8147e740f01037 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 14 Jul 2024 11:10:53 +0200 Subject: [PATCH 06/14] Minor tweaks --- addons/medical_engine/initSettings.inc.sqf | 5 ++--- addons/medical_treatment/XEH_postInit.sqf | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/addons/medical_engine/initSettings.inc.sqf b/addons/medical_engine/initSettings.inc.sqf index b60ab233443..905f6c005a0 100644 --- a/addons/medical_engine/initSettings.inc.sqf +++ b/addons/medical_engine/initSettings.inc.sqf @@ -4,9 +4,8 @@ [LSTRING(Enabled_DisplayName), LSTRING(Enabled_Description)], ELSTRING(medical,Category), true, - true, { - [QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged) - }, + true, + {[QEGVAR(medical,enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, true // Needs mission restart ] call CBA_fnc_addSetting; diff --git a/addons/medical_treatment/XEH_postInit.sqf b/addons/medical_treatment/XEH_postInit.sqf index c76ecc81f36..932ee43fb88 100644 --- a/addons/medical_treatment/XEH_postInit.sqf +++ b/addons/medical_treatment/XEH_postInit.sqf @@ -35,7 +35,7 @@ if (isServer) then { // replace medical items with their ACE equivalents ["CBA_settingsInitialized", { - TRACE_1("CBA_settingsInitialized EH",GVAR(convertItems)); // 0: Enabled 1: RemoveOnly 2:Disabled + TRACE_1("CBA_settingsInitialized EH",GVAR(convertItems)); // 0: Enabled 1: RemoveOnly { // turn [["stuff", 2], ...] into ["stuff", "stuff", ...] private _replacements = []; From df60c744c1f97db28f3900fe4db484cc4c0ad007 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 15 Jul 2024 19:28:56 +0200 Subject: [PATCH 07/14] Use HandleHeal instead Return value of HandleHeal is ignored, but AISFinishHeal works --- addons/medical_engine/XEH_PREP.hpp | 1 - addons/medical_engine/XEH_postInit.sqf | 27 +++++++++++-------- addons/medical_engine/XEH_preInit.sqf | 7 +---- .../functions/fnc_commandChanged.sqf | 24 ----------------- addons/medical_engine/initSettings.inc.sqf | 6 ++--- 5 files changed, 20 insertions(+), 45 deletions(-) delete mode 100644 addons/medical_engine/functions/fnc_commandChanged.sqf diff --git a/addons/medical_engine/XEH_PREP.hpp b/addons/medical_engine/XEH_PREP.hpp index 349f95be5e7..ffc3543745d 100644 --- a/addons/medical_engine/XEH_PREP.hpp +++ b/addons/medical_engine/XEH_PREP.hpp @@ -1,5 +1,4 @@ PREP(applyAnimAfterRagdoll); -PREP(commandChanged); PREP(damageBodyPart); PREP(disableThirdParty); PREP(getHitpointArmor); diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index 72a7568c1dd..cd25dee2e09 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -1,6 +1,7 @@ #include "script_component.hpp" [QGVAR(updateDamageEffects), LINKFUNC(updateDamageEffects)] call CBA_fnc_addEventHandler; + ["unit", { params ["_new"]; [_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture) @@ -23,9 +24,23 @@ QEGVAR(medical,HandleDamageEHID), _unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}] ]; + + _unit addEventHandler ["HandleHeal", { + params ["_injured", "_healer"]; + + // Replace the items so that the unit can't heal + _healer call EFUNC(common,replaceRegisteredItems); + + AISFinishHeal [_injured, _healer, true]; + + // Set animation to what it was before starting the healing animation + [{"dnon_medic" in animationState (_this select 0)}, { + [_this select 0, _this select 1, 2] call EFUNC(common,doAnimation); + }, [_healer, _healer call EFUNC(common,getDefaultAnim)], 5] call CBA_fnc_waitUntilAndExecute; + }]; }, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; -if !("ace_medical_treatment" call EFUNC(common,isModLoaded)) then { +if !(["ace_medical_treatment"] call EFUNC(common,isModLoaded)) then { [TYPE_FIRST_AID_KIT, ""] call EFUNC(common,registerItemReplacement); [TYPE_MEDIKIT, ""] call EFUNC(common,registerItemReplacement); }; @@ -95,13 +110,3 @@ if !("ace_medical_treatment" call EFUNC(common,isModLoaded)) then { [_unit] call FUNC(unlockUnconsciousSeat); }; }, true, []] call CBA_fnc_addClassEventHandler; - -// Used for preventing vanilla heal by replacing items -addMissionEventHandler ["GroupCreated", { - params ["_group"]; - _group addEventHandler ["CommandChanged", {_this call FUNC(commandChanged)}]; -}]; - -{ - _x addEventHandler ["CommandChanged", {_this call FUNC(commandChanged)}]; -} forEach allGroups; diff --git a/addons/medical_engine/XEH_preInit.sqf b/addons/medical_engine/XEH_preInit.sqf index 79f18d87a9a..8d6e419ab64 100644 --- a/addons/medical_engine/XEH_preInit.sqf +++ b/addons/medical_engine/XEH_preInit.sqf @@ -32,8 +32,6 @@ if (isNil QUOTE(FATAL_SUM_DAMAGE_WEIBULL_K) || isNil QUOTE(FATAL_SUM_DAMAGE_WEIB FATAL_SUM_DAMAGE_WEIBULL_L = _x1 / _b1^(1/FATAL_SUM_DAMAGE_WEIBULL_K); }; -OVERRIDDEN_COMMANDS = ["HEAL", "HEAL SOLDIER", "PATCH SOLDIER", "FIRST AID", "HEAL SELF", "SUPPORT"] createHashMapFromArray []; - // Cache for armor values of equipped items (vests etc) GVAR(armorCache) = createHashMap; @@ -87,9 +85,6 @@ addMissionEventHandler ["Loaded", { }; }] call CBA_fnc_addEventhandler; -[] call FUNC(disableThirdParty); - -// Future-proofing -EGVAR(medical,enabled) = true; // TODO: remove when medical enable setting is implemented +call FUNC(disableThirdParty); ADDON = true; diff --git a/addons/medical_engine/functions/fnc_commandChanged.sqf b/addons/medical_engine/functions/fnc_commandChanged.sqf deleted file mode 100644 index 3b341188340..00000000000 --- a/addons/medical_engine/functions/fnc_commandChanged.sqf +++ /dev/null @@ -1,24 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: LinkIsGrim - * Intercepts group heal attempts and replaces items - * - * Arguments: - * None - * - * Return Value: - * None - * - * Public: No - */ -params ["_group", "_newCommand"]; - -if (!local _group) exitWith {}; -if !(_newCommand in OVERRIDDEN_COMMANDS) exitWith {}; - -{ - _x call EFUNC(common,replaceRegisteredItems); - private _assignedTeam = assignedTeam _x; - [_x] joinSilent (leader _group); - _x assignTeam _assignedTeam; -} forEach ((units _group) select {(currentCommand _x) == _newCommand}); diff --git a/addons/medical_engine/initSettings.inc.sqf b/addons/medical_engine/initSettings.inc.sqf index 905f6c005a0..01da5cf2452 100644 --- a/addons/medical_engine/initSettings.inc.sqf +++ b/addons/medical_engine/initSettings.inc.sqf @@ -4,7 +4,7 @@ [LSTRING(Enabled_DisplayName), LSTRING(Enabled_Description)], ELSTRING(medical,Category), true, - true, + 1, {[QEGVAR(medical,enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, true // Needs mission restart ] call CBA_fnc_addSetting; @@ -15,7 +15,7 @@ [LSTRING(EnableVehicleCrashes_DisplayName), LSTRING(EnableVehicleCrashes_Description)], ELSTRING(medical,Category), true, - true + 1 ] call CBA_fnc_addSetting; [ @@ -24,5 +24,5 @@ [LSTRING(damagePassThroughEffect_displayName), LSTRING(damagePassThroughEffect_description)], ELSTRING(medical,Category), [0, 1, 1, 2, true], - true + 1 ] call CBA_fnc_addSetting; From 583c182df14f801bf0c3f6ea41330bcbd886ee3e Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 15 Jul 2024 19:30:30 +0200 Subject: [PATCH 08/14] Update script_macros_medical.hpp --- addons/medical_engine/script_macros_medical.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/addons/medical_engine/script_macros_medical.hpp b/addons/medical_engine/script_macros_medical.hpp index 9fa7a0fdfab..167765c5767 100644 --- a/addons/medical_engine/script_macros_medical.hpp +++ b/addons/medical_engine/script_macros_medical.hpp @@ -108,9 +108,6 @@ #define FRACTURE_DAMAGE_THRESHOLD EGVAR(medical,const_fractureDamageThreshold) #define FRACTURE_DAMAGE_THRESHOLD_DEFAULT 0.50 -// Overridden commands for group healing -#define OVERRIDDEN_COMMANDS EGVAR(medical,overriddenCommands) - // Minimum cardiac output #define CARDIAC_OUTPUT_MIN EGVAR(medical,const_minCardiacOutput) #define CARDIAC_OUTPUT_MIN_DEFAULT 0.05 From 6d65fc42e87f2deab405695be41b6ff439aad200 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:49:23 +0200 Subject: [PATCH 09/14] Use variable to enable/disable aspects --- addons/medical/XEH_postInit.sqf | 34 +-- .../medical/functions/fnc_addDamageToUnit.sqf | 6 + .../medical/functions/fnc_adjustPainLevel.sqf | 10 +- .../functions/fnc_deserializeState.sqf | 7 + .../medical/functions/fnc_serializeState.sqf | 9 +- .../medical/functions/fnc_setUnconscious.sqf | 11 +- addons/medical_ai/XEH_postInit.sqf | 6 +- addons/medical_blood/XEH_postInit.sqf | 40 +-- addons/medical_engine/XEH_postInit.sqf | 188 ++++++------- addons/medical_feedback/XEH_postInit.sqf | 250 +++++++++--------- addons/medical_gui/CfgVehicles.hpp | 8 +- addons/medical_gui/XEH_postInit.sqf | 158 ++++------- .../medical_gui/functions/fnc_canOpenMenu.sqf | 2 + .../functions/fnc_modifyActionTriageLevel.sqf | 3 + addons/medical_gui/initKeybinds.inc.sqf | 56 ++++ addons/medical_statemachine/XEH_postInit.sqf | 24 +- addons/medical_status/XEH_postInit.sqf | 73 ++--- addons/medical_treatment/XEH_postInit.sqf | 141 +++++----- .../functions/fnc_canUnloadUnit.sqf | 2 + .../zeus/functions/fnc_moduleUnconscious.sqf | 2 +- 20 files changed, 549 insertions(+), 481 deletions(-) create mode 100644 addons/medical_gui/initKeybinds.inc.sqf diff --git a/addons/medical/XEH_postInit.sqf b/addons/medical/XEH_postInit.sqf index 23c90b25793..acba4f58ad2 100644 --- a/addons/medical/XEH_postInit.sqf +++ b/addons/medical/XEH_postInit.sqf @@ -1,22 +1,26 @@ // #define DEBUG_MODE_FULL #include "script_component.hpp" -[QEGVAR(medical,setUnconscious), LINKFUNC(setUnconscious)] call CBA_fnc_addEventHandler; +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; -if (!hasInterface) exitWith {}; + [QEGVAR(medical,setUnconscious), LINKFUNC(setUnconscious)] call CBA_fnc_addEventHandler; -// Fractures affect base sway, pain makes it worse -["baseline", { - ACE_player getVariable [QEGVAR(medical_engine,aimFracture), 0] -}, QUOTE(ADDON)] call EFUNC(common,addSwayFactor); + if (!hasInterface) exitWith {}; -// Max pain = 5x sway -["multiplier", { - 1 + (GET_PAIN_PERCEIVED(ACE_player) * 4) -}, QUOTE(ADDON)] call EFUNC(common,addSwayFactor); + // Fractures affect base sway, pain makes it worse + ["baseline", { + ACE_player getVariable [QEGVAR(medical_engine,aimFracture), 0] + }, QUOTE(ADDON)] call EFUNC(common,addSwayFactor); -#ifdef DEBUG_MODE_FULL - call compile preprocessFileLineNumbers QPATHTOF(dev\reportSettings.sqf); - call compile preprocessFileLineNumbers QPATHTOF(dev\watchVariable.sqf); - call compile preprocessFileLineNumbers QPATHTOF(dev\debugDisplay.sqf); -#endif + // Max pain = 5x sway + ["multiplier", { + 1 + (GET_PAIN_PERCEIVED(ACE_player) * 4) + }, QUOTE(ADDON)] call EFUNC(common,addSwayFactor); + + #ifdef DEBUG_MODE_FULL + call compile preprocessFileLineNumbers QPATHTOF(dev\reportSettings.sqf); + call compile preprocessFileLineNumbers QPATHTOF(dev\watchVariable.sqf); + call compile preprocessFileLineNumbers QPATHTOF(dev\debugDisplay.sqf); + #endif +}] call CBA_fnc_addEventHandler; diff --git a/addons/medical/functions/fnc_addDamageToUnit.sqf b/addons/medical/functions/fnc_addDamageToUnit.sqf index e490399c4bf..42d43ae5f3a 100644 --- a/addons/medical/functions/fnc_addDamageToUnit.sqf +++ b/addons/medical/functions/fnc_addDamageToUnit.sqf @@ -23,6 +23,12 @@ */ // #define DEBUG_TESTRESULTS +if (!EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(addDamageToUnit), _this]; +}; + +if !(GETEGVAR(medical,enabled,false)) exitWith {false}; + params [ ["_unit", objNull, [objNull]], ["_damageToAdd", -1, [0]], diff --git a/addons/medical/functions/fnc_adjustPainLevel.sqf b/addons/medical/functions/fnc_adjustPainLevel.sqf index f5c3d9a35d8..ba2250955b0 100644 --- a/addons/medical/functions/fnc_adjustPainLevel.sqf +++ b/addons/medical/functions/fnc_adjustPainLevel.sqf @@ -12,12 +12,18 @@ * The new pain level * * Example: - * [guy, 0.5] call ace_medical_fnc_adjustPainLevel + * [player, 0.5] call ace_medical_fnc_adjustPainLevel * * Public: Yes */ -params ["_unit", "_addedPain"]; +if (!EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(adjustPainLevel), _this]; +}; + +if !(GETEGVAR(medical,enabled,false)) exitWith {}; + +params [["_unit", objNull, [objNull]], ["_addedPain", 0, [0]]]; if (!local _unit) exitWith { ERROR_1("unit [%1] is not local",_unit); }; diff --git a/addons/medical/functions/fnc_deserializeState.sqf b/addons/medical/functions/fnc_deserializeState.sqf index b7846bf9015..24f583d7e9b 100644 --- a/addons/medical/functions/fnc_deserializeState.sqf +++ b/addons/medical/functions/fnc_deserializeState.sqf @@ -15,6 +15,13 @@ * * Public: Yes */ + +if (!EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(deserializeState), _this]; +}; + +if !(GETEGVAR(medical,enabled,false)) exitWith {}; + params [["_unit", objNull, [objNull]], ["_json", "{}", [""]]]; // Don't run in scheduled environment diff --git a/addons/medical/functions/fnc_serializeState.sqf b/addons/medical/functions/fnc_serializeState.sqf index 67783e85d94..75cc04ff8a2 100644 --- a/addons/medical/functions/fnc_serializeState.sqf +++ b/addons/medical/functions/fnc_serializeState.sqf @@ -10,10 +10,17 @@ * Serialized state as JSON string * * Example: - * [player] call ace_medical_fnc_serializeState + * player call ace_medical_fnc_serializeState * * Public: Yes */ + +if (!EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(serializeState), _this]; +}; + +if !(GETEGVAR(medical,enabled,false)) exitWith {""}; + params [["_unit", objNull, [objNull]]]; private _state = [] call CBA_fnc_createNamespace; diff --git a/addons/medical/functions/fnc_setUnconscious.sqf b/addons/medical/functions/fnc_setUnconscious.sqf index a1de71c36b4..cb3550222eb 100644 --- a/addons/medical/functions/fnc_setUnconscious.sqf +++ b/addons/medical/functions/fnc_setUnconscious.sqf @@ -6,8 +6,8 @@ * Arguments: * 0: The unit that will be put in an unconscious state * 1: Set unconsciouns (default: true) - * 2: Minimum unconscious time (set to 0 to ignore) (default: 0) - * 3: Force wakeup at given time if vitals are stable (default: false) + * 2: Minimum unconscious time (set to 0 to ignore) (default: 0) + * 3: Force wakeup at given time if vitals are stable (default: false) * * Return Value: * Success? @@ -19,11 +19,12 @@ * Public: Yes */ -// only run this after the settings are initialized -if !(EGVAR(common,settingsInitFinished)) exitWith { - EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this]; +if (!EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(setUnconscious), _this]; }; +if !(GETEGVAR(medical,enabled,false)) exitWith {}; + params [["_unit", objNull, [objNull]], ["_knockOut", true, [false]], ["_minWaitingTime", 0, [0]], ["_forcedWakup", false, [false]]]; TRACE_4("setUnconscious",_unit,_knockOut,_minWaitingTime,_forcedWakup); diff --git a/addons/medical_ai/XEH_postInit.sqf b/addons/medical_ai/XEH_postInit.sqf index 0b225c7f0b0..97b4567196d 100644 --- a/addons/medical_ai/XEH_postInit.sqf +++ b/addons/medical_ai/XEH_postInit.sqf @@ -1,8 +1,9 @@ #include "script_component.hpp" ["CBA_settingsInitialized", { - TRACE_1("settingsInitialized",GVAR(enabledFor)); - if (GVAR(enabledFor) == 0) exitWith {}; // 0: disabled + TRACE_2("settingsInitialized",GVAR(enabledFor),GETEGVAR(medical,enabled,false)); + + if (GVAR(enabledFor) == 0 || {!(GETEGVAR(medical,enabled,false))}) exitWith {}; // 0: disabled if ((GVAR(enabledFor) == 1) && {!isServer} && {hasInterface}) exitWith {}; // 1: Don't Run on non-hc Clients ["ace_firedNonPlayer", { @@ -20,5 +21,4 @@ }] call CBA_fnc_addClassEventHandler; #include "stateMachine.inc.sqf" - }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_blood/XEH_postInit.sqf b/addons/medical_blood/XEH_postInit.sqf index b08921b441e..fe64fffc540 100644 --- a/addons/medical_blood/XEH_postInit.sqf +++ b/addons/medical_blood/XEH_postInit.sqf @@ -1,25 +1,29 @@ #include "script_component.hpp" -// To support public API regardless of component settings -[QGVAR(spurt), LINKFUNC(spurt)] call CBA_fnc_addEventHandler; +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; -if (isServer) then { - GVAR(bloodDrops) = []; + // To support public API regardless of component settings + [QGVAR(spurt), LINKFUNC(spurt)] call CBA_fnc_addEventHandler; - [QGVAR(bloodDropCreated), { - params ["_bloodDrop", "_source"]; + if (isServer) then { + GVAR(bloodDrops) = []; - // Add to created queue with format: [expire time, blood object, source unit] - private _index = GVAR(bloodDrops) pushBack [CBA_missionTime + GVAR(bloodLifetime), _bloodDrop, _source]; + [QGVAR(bloodDropCreated), { + params ["_bloodDrop", "_source"]; - if (count GVAR(bloodDrops) >= GVAR(maxBloodObjects)) then { - (GVAR(bloodDrops) deleteAt 0) params ["", "_deletedBloodDrop"]; - deleteVehicle _deletedBloodDrop; - }; + // Add to created queue with format: [expire time, blood object, source unit] + private _index = GVAR(bloodDrops) pushBack [CBA_missionTime + GVAR(bloodLifetime), _bloodDrop, _source]; - // Start the cleanup loop - if (_index == 0) then { - [LINKFUNC(cleanupLoop), [], GVAR(bloodLifetime)] call CBA_fnc_waitAndExecute; - }; - }] call CBA_fnc_addEventHandler; -}; + if (count GVAR(bloodDrops) >= GVAR(maxBloodObjects)) then { + (GVAR(bloodDrops) deleteAt 0) params ["", "_deletedBloodDrop"]; + deleteVehicle _deletedBloodDrop; + }; + + // Start the cleanup loop + if (_index == 0) then { + [LINKFUNC(cleanupLoop), [], GVAR(bloodLifetime)] call CBA_fnc_waitAndExecute; + }; + }] call CBA_fnc_addEventHandler; + }; +}] call CBA_fnc_addEventHandler; diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index cd25dee2e09..e122b7aad0f 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -1,112 +1,116 @@ #include "script_component.hpp" -[QGVAR(updateDamageEffects), LINKFUNC(updateDamageEffects)] call CBA_fnc_addEventHandler; +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; -["unit", { - params ["_new"]; - [_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture) -}, true] call CBA_fnc_addPlayerEventHandler; + [QGVAR(updateDamageEffects), LINKFUNC(updateDamageEffects)] call CBA_fnc_addEventHandler; -["CAManBase", "init", { - params ["_unit"]; + ["unit", { + params ["_new"]; + [_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture) + }, true] call CBA_fnc_addPlayerEventHandler; - if (unitIsUAV _unit) exitWith {TRACE_1("ignore UAV AI",typeOf _unit);}; - if (getNumber (configOf _unit >> "isPlayableLogic") == 1) exitWith {TRACE_1("ignore logic unit",typeOf _unit);}; + ["CAManBase", "init", { + params ["_unit"]; - private _allHitPoints = getAllHitPointsDamage _unit param [0, []]; - if ((GVAR(customHitpoints) arrayIntersect _allHitPoints) isNotEqualTo GVAR(customHitpoints)) exitWith { - ERROR_1("Bad hitpoints for unit type ""%1""",typeOf _unit); - }; + if (unitIsUAV _unit) exitWith {TRACE_1("ignore UAV AI",typeOf _unit);}; + if (getNumber (configOf _unit >> "isPlayableLogic") == 1) exitWith {TRACE_1("ignore logic unit",typeOf _unit);}; - // Calling this function inside curly brackets allows the usage of - // "exitWith", which would be broken with "HandleDamage" otherwise. - _unit setVariable [ - QEGVAR(medical,HandleDamageEHID), - _unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}] - ]; - - _unit addEventHandler ["HandleHeal", { - params ["_injured", "_healer"]; - - // Replace the items so that the unit can't heal - _healer call EFUNC(common,replaceRegisteredItems); - - AISFinishHeal [_injured, _healer, true]; - - // Set animation to what it was before starting the healing animation - [{"dnon_medic" in animationState (_this select 0)}, { - [_this select 0, _this select 1, 2] call EFUNC(common,doAnimation); - }, [_healer, _healer call EFUNC(common,getDefaultAnim)], 5] call CBA_fnc_waitUntilAndExecute; - }]; -}, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; - -if !(["ace_medical_treatment"] call EFUNC(common,isModLoaded)) then { - [TYPE_FIRST_AID_KIT, ""] call EFUNC(common,registerItemReplacement); - [TYPE_MEDIKIT, ""] call EFUNC(common,registerItemReplacement); -}; - -#ifdef DEBUG_MODE_FULL -[QEGVAR(medical,woundReceived), { - params ["_unit", "_damages", "_shooter", "_ammo"]; - TRACE_4("wound",_unit,_damages,_shooter,_ammo); - //systemChat str _this; -}] call CBA_fnc_addEventHandler; -#endif + private _allHitPoints = getAllHitPointsDamage _unit param [0, []]; + if ((GVAR(customHitpoints) arrayIntersect _allHitPoints) isNotEqualTo GVAR(customHitpoints)) exitWith { + ERROR_1("Bad hitpoints for unit type ""%1""",typeOf _unit); + }; -// this handles moving units into vehicles via load functions or zeus -// needed, because the vanilla INCAPACITATED state does not handle vehicles -["CAManBase", "GetInMan", { - params ["_unit", "", "_vehicle"]; + // Calling this function inside curly brackets allows the usage of + // "exitWith", which would be broken with "HandleDamage" otherwise. + _unit setVariable [ + QEGVAR(medical,HandleDamageEHID), + _unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}] + ]; - if (local _unit && {lifeState _unit == "INCAPACITATED"}) then { - [_unit, true] call FUNC(setUnconsciousAnim); - }; + _unit addEventHandler ["HandleHeal", { + params ["_injured", "_healer"]; - if (local _vehicle) then { - [_unit] call FUNC(lockUnconsciousSeat); - }; -}] call CBA_fnc_addClassEventHandler; + // Replace the items so that the unit can't heal + _healer call EFUNC(common,replaceRegisteredItems); -["CAManBase", "GetOutMan", { - params ["_unit", "", "_vehicle"]; + AISFinishHeal [_injured, _healer, true]; - if (local _vehicle) then { - [_unit] call FUNC(unlockUnconsciousSeat); - }; -}] call CBA_fnc_addClassEventHandler; + // Set animation to what it was before starting the healing animation + [{"dnon_medic" in animationState (_this select 0)}, { + [_this select 0, _this select 1, 2] call EFUNC(common,doAnimation); + }, [_healer, _healer call EFUNC(common,getDefaultAnim)], 5] call CBA_fnc_waitUntilAndExecute; + }]; + }, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; -// Fixes units being stuck in unconscious animation when being knocked over by a PhysX object -["CAManBase", "AnimDone", { - params ["_unit", "_anim"]; - if (local _unit && {_anim find QUNCON_ANIM(face) != -1 && {lifeState _unit != "INCAPACITATED"}}) then { - [_unit, false] call FUNC(setUnconsciousAnim); + if !(["ace_medical_treatment"] call EFUNC(common,isModLoaded)) then { + [TYPE_FIRST_AID_KIT, ""] call EFUNC(common,registerItemReplacement); + [TYPE_MEDIKIT, ""] call EFUNC(common,registerItemReplacement); }; -}] call CBA_fnc_addClassEventHandler; -["ace_unconscious", { - params ["_unit", "_unconscious"]; - TRACE_3("unit uncon",_unit,objectParent _unit,local _unit); - if (!isNull objectParent _unit && {local objectParent _unit}) then { - if (_unconscious) then { + #ifdef DEBUG_MODE_FULL + [QEGVAR(medical,woundReceived), { + params ["_unit", "_damages", "_shooter", "_ammo"]; + TRACE_4("wound",_unit,_damages,_shooter,_ammo); + //systemChat str _this; + }] call CBA_fnc_addEventHandler; + #endif + + // this handles moving units into vehicles via load functions or zeus + // needed, because the vanilla INCAPACITATED state does not handle vehicles + ["CAManBase", "GetInMan", { + params ["_unit", "", "_vehicle"]; + + if (local _unit && {lifeState _unit == "INCAPACITATED"}) then { + [_unit, true] call FUNC(setUnconsciousAnim); + }; + + if (local _vehicle) then { [_unit] call FUNC(lockUnconsciousSeat); - } else { + }; + }] call CBA_fnc_addClassEventHandler; + + ["CAManBase", "GetOutMan", { + params ["_unit", "", "_vehicle"]; + + if (local _vehicle) then { [_unit] call FUNC(unlockUnconsciousSeat); }; - }; -}] call CBA_fnc_addEventHandler; + }] call CBA_fnc_addClassEventHandler; -["ace_killed", { // global event - params ["_unit"]; - TRACE_3("unit Killed",_unit,objectParent _unit,local _unit); - if (!isNull objectParent _unit && {local objectParent _unit}) exitWith { - [_unit] call FUNC(lockUnconsciousSeat); - }; -}] call CBA_fnc_addEventHandler; + // Fixes units being stuck in unconscious animation when being knocked over by a PhysX object + ["CAManBase", "AnimDone", { + params ["_unit", "_anim"]; + if (local _unit && {_anim find QUNCON_ANIM(face) != -1 && {lifeState _unit != "INCAPACITATED"}}) then { + [_unit, false] call FUNC(setUnconsciousAnim); + }; + }] call CBA_fnc_addClassEventHandler; + + ["ace_unconscious", { + params ["_unit", "_unconscious"]; + TRACE_3("unit uncon",_unit,objectParent _unit,local _unit); + if (!isNull objectParent _unit && {local objectParent _unit}) then { + if (_unconscious) then { + [_unit] call FUNC(lockUnconsciousSeat); + } else { + [_unit] call FUNC(unlockUnconsciousSeat); + }; + }; + }] call CBA_fnc_addEventHandler; -["CAManBase", "Deleted", { - params ["_unit"]; - TRACE_3("unit deleted",_unit,objectParent _unit,local _unit); - if ((!isNull objectParent _unit) && {local objectParent _unit}) then { - [_unit] call FUNC(unlockUnconsciousSeat); - }; -}, true, []] call CBA_fnc_addClassEventHandler; + ["ace_killed", { // global event + params ["_unit"]; + TRACE_3("unit Killed",_unit,objectParent _unit,local _unit); + if (!isNull objectParent _unit && {local objectParent _unit}) exitWith { + [_unit] call FUNC(lockUnconsciousSeat); + }; + }] call CBA_fnc_addEventHandler; + + ["CAManBase", "Deleted", { + params ["_unit"]; + TRACE_3("unit deleted",_unit,objectParent _unit,local _unit); + if ((!isNull objectParent _unit) && {local objectParent _unit}) then { + [_unit] call FUNC(unlockUnconsciousSeat); + }; + }, true, []] call CBA_fnc_addClassEventHandler; +}] call CBA_fnc_addEventHandler; diff --git a/addons/medical_feedback/XEH_postInit.sqf b/addons/medical_feedback/XEH_postInit.sqf index f01394e9199..12009987398 100644 --- a/addons/medical_feedback/XEH_postInit.sqf +++ b/addons/medical_feedback/XEH_postInit.sqf @@ -1,141 +1,145 @@ #include "script_component.hpp" -[QEGVAR(medical,injured), { - params ["_unit", "_painLevel"]; - [_unit, "hit", PAIN_TO_SCREAM(_painLevel)] call FUNC(playInjuredSound); - - if (hasInterface && {_unit == ace_player}) then { - [true] call FUNC(handleEffects); - }; -}] call CBA_fnc_addEventHandler; - -[QEGVAR(medical,moan), { - params ["_unit", "_painLevel"]; - [_unit, "moan", PAIN_TO_MOAN(_painLevel)] call FUNC(playInjuredSound); -}] call CBA_fnc_addEventHandler; - -if (!hasInterface) exitWith {}; - -[QEGVAR(medical,fracture), { - params ["_unit"]; - if (_unit == ACE_player) then { - playSound SND_FRACTURE; - }; -}] call CBA_fnc_addEventHandler; - -GVAR(nextFadeIn) = 0; -GVAR(heartBeatEffectRunning) = false; -GVAR(lastHeartBeatSound) = 0; -GVAR(bloodTickCounter) = 0; - -[false] call FUNC(initEffects); -[true] call FUNC(handleEffects); -[LINKFUNC(handleEffects), 1, false] call CBA_fnc_addPerFrameHandler; +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; + + [QEGVAR(medical,injured), { + params ["_unit", "_painLevel"]; + [_unit, "hit", PAIN_TO_SCREAM(_painLevel)] call FUNC(playInjuredSound); + + if (hasInterface && {_unit == ace_player}) then { + [true] call FUNC(handleEffects); + }; + }] call CBA_fnc_addEventHandler; + + [QEGVAR(medical,moan), { + params ["_unit", "_painLevel"]; + [_unit, "moan", PAIN_TO_MOAN(_painLevel)] call FUNC(playInjuredSound); + }] call CBA_fnc_addEventHandler; + + if (!hasInterface) exitWith {}; + + [QEGVAR(medical,fracture), { + params ["_unit"]; + if (_unit == ACE_player) then { + playSound SND_FRACTURE; + }; + }] call CBA_fnc_addEventHandler; + + GVAR(nextFadeIn) = 0; + GVAR(heartBeatEffectRunning) = false; + GVAR(lastHeartBeatSound) = 0; + GVAR(bloodTickCounter) = 0; + + [false] call FUNC(initEffects); + [true] call FUNC(handleEffects); + [LINKFUNC(handleEffects), 1, false] call CBA_fnc_addPerFrameHandler; -["ace_unconscious", { - params ["_unit", "_unconscious"]; + ["ace_unconscious", { + params ["_unit", "_unconscious"]; - if (_unit != ACE_player) exitWith {}; - TRACE_1("player unconscious eh",_unconscious); + if (_unit != ACE_player) exitWith {}; + TRACE_1("player unconscious eh",_unconscious); - if (_unconscious && {cameraView == "GUNNER"} && {(vehicle _unit) != _unit} && {cameraOn == vehicle _unit}) then { - TRACE_2("exiting gunner view",cameraOn,cameraView); - ACE_player switchCamera "INTERNAL"; - }; + if (_unconscious && {cameraView == "GUNNER"} && {(vehicle _unit) != _unit} && {cameraOn == vehicle _unit}) then { + TRACE_2("exiting gunner view",cameraOn,cameraView); + ACE_player switchCamera "INTERNAL"; + }; - [!_unconscious, _unit] call EFUNC(common,setVolume); + [!_unconscious, _unit] call EFUNC(common,setVolume); - // Greatly reduce player's hearing ability while unconscious (affects radio addons) - private _volume = missionNamespace getVariable [QEGVAR(hearing,unconsciousnessVolume), VOL_UNCONSCIOUS]; - [QUOTE(ADDON), _volume, _unconscious] call EFUNC(common,setHearingCapability); + // Greatly reduce player's hearing ability while unconscious (affects radio addons) + private _volume = missionNamespace getVariable [QEGVAR(hearing,unconsciousnessVolume), VOL_UNCONSCIOUS]; + [QUOTE(ADDON), _volume, _unconscious] call EFUNC(common,setHearingCapability); - [_unconscious, 1] call FUNC(effectUnconscious); - [true] call FUNC(handleEffects); - ["unconscious", _unconscious] call EFUNC(common,setDisableUserInputStatus); -}] call CBA_fnc_addEventHandler; - -// Reset volume upon death for spectators -[QEGVAR(medical,death), { - params ["_unit"]; + [_unconscious, 1] call FUNC(effectUnconscious); + [true] call FUNC(handleEffects); + ["unconscious", _unconscious] call EFUNC(common,setDisableUserInputStatus); + }] call CBA_fnc_addEventHandler; - if (_unit != ACE_player) exitWith {}; - // Players always able to hear for any systems that might run while dead (e.g. spectator) - [true, _unit] call EFUNC(common,setVolume); + // Reset volume upon death for spectators + [QEGVAR(medical,death), { + params ["_unit"]; - [QUOTE(ADDON), 1, false] call EFUNC(common,setHearingCapability); -}] call CBA_fnc_addEventHandler; + if (_unit != ACE_player) exitWith {}; + // Players always able to hear for any systems that might run while dead (e.g. spectator) + [true, _unit] call EFUNC(common,setVolume); -// Update effects to match new unit's current status (this also handles respawn) -["unit", { - params ["_new"]; - private _status = IS_UNCONSCIOUS(_new); + [QUOTE(ADDON), 1, false] call EFUNC(common,setHearingCapability); + }] call CBA_fnc_addEventHandler; - [!_status, _new] call EFUNC(common,setVolume); + // Update effects to match new unit's current status (this also handles respawn) + ["unit", { + params ["_new"]; + private _status = IS_UNCONSCIOUS(_new); - private _volume = missionNamespace getVariable [QEGVAR(hearing,unconsciousnessVolume), VOL_UNCONSCIOUS]; - [QUOTE(ADDON), _volume, _status] call EFUNC(common,setHearingCapability); - [true] call FUNC(handleEffects); - ["unconscious", _status] call EFUNC(common,setDisableUserInputStatus); -}] call CBA_fnc_addPlayerEventHandler; + [!_status, _new] call EFUNC(common,setVolume); -// Update effects for featureCamera (curator, arsenal, etc) -["featureCamera", { - params ["_unit", "_newCamera"]; + private _volume = missionNamespace getVariable [QEGVAR(hearing,unconsciousnessVolume), VOL_UNCONSCIOUS]; + [QUOTE(ADDON), _volume, _status] call EFUNC(common,setHearingCapability); + [true] call FUNC(handleEffects); + ["unconscious", _status] call EFUNC(common,setDisableUserInputStatus); + }] call CBA_fnc_addPlayerEventHandler; - [true] call FUNC(handleEffects); + // Update effects for featureCamera (curator, arsenal, etc) + ["featureCamera", { + params ["_unit", "_newCamera"]; - private _volume = missionNamespace getVariable [QEGVAR(hearing,unconsciousnessVolume), VOL_UNCONSCIOUS]; + [true] call FUNC(handleEffects); - if (_newCamera == "") then { // switched back to player view - private _status = IS_UNCONSCIOUS(_unit); - [!_status, _unit] call EFUNC(common,setVolume); - [QUOTE(ADDON), _volume, _status] call EFUNC(common,setHearingCapability); - ["unconscious", _status] call EFUNC(common,setDisableUserInputStatus); - } else { // camera view - [true, _unit] call EFUNC(common,setVolume); - [QUOTE(ADDON), 1, false] call EFUNC(common,setHearingCapability); - ["unconscious", false] call EFUNC(common,setDisableUserInputStatus); - }; -}] call CBA_fnc_addPlayerEventHandler; - -// Forced say3D -[QGVAR(forceSay3D), { - params ["_unit", "_sound", "_distance"]; - - if (ACE_player distance _unit > _distance) exitWith {}; - - if (isNull objectParent _unit) then { - // say3D waits for the previous sound to finish, so use a dummy instead - private _dummy = "#dynamicsound" createVehicleLocal [0, 0, 0]; - _dummy attachTo [_unit, [0, 0, 0], "camera"]; - _dummy say3D [_sound, _distance, 1, false]; - - [{ - detach _this; - deleteVehicle _this; - }, _dummy, 5] call CBA_fnc_waitAndExecute; - } else { - // Fallback: attachTo doesn't work within vehicles - _unit say3D [_sound, _distance, 1, false]; - }; + private _volume = missionNamespace getVariable [QEGVAR(hearing,unconsciousnessVolume), VOL_UNCONSCIOUS]; + + if (_newCamera == "") then { // switched back to player view + private _status = IS_UNCONSCIOUS(_unit); + [!_status, _unit] call EFUNC(common,setVolume); + [QUOTE(ADDON), _volume, _status] call EFUNC(common,setHearingCapability); + ["unconscious", _status] call EFUNC(common,setDisableUserInputStatus); + } else { // camera view + [true, _unit] call EFUNC(common,setVolume); + [QUOTE(ADDON), 1, false] call EFUNC(common,setHearingCapability); + ["unconscious", false] call EFUNC(common,setDisableUserInputStatus); + }; + }] call CBA_fnc_addPlayerEventHandler; + + // Forced say3D + [QGVAR(forceSay3D), { + params ["_unit", "_sound", "_distance"]; + + if (ACE_player distance _unit > _distance) exitWith {}; + + if (isNull objectParent _unit) then { + // say3D waits for the previous sound to finish, so use a dummy instead + private _dummy = "#dynamicsound" createVehicleLocal [0, 0, 0]; + _dummy attachTo [_unit, [0, 0, 0], "camera"]; + _dummy say3D [_sound, _distance, 1, false]; + + [{ + detach _this; + deleteVehicle _this; + }, _dummy, 5] call CBA_fnc_waitAndExecute; + } else { + // Fallback: attachTo doesn't work within vehicles + _unit say3D [_sound, _distance, 1, false]; + }; + }] call CBA_fnc_addEventHandler; + + // Kill vanilla bleeding feedback effects. + #ifdef DISABLE_VANILLA_DAMAGE_EFFECTS + TRACE_1("disabling vanilla bleeding feedback effects",_this); + [{ + {isNil _x} count [ + "BIS_fnc_feedback_damageCC", + "BIS_fnc_feedback_damageRadialBlur", + "BIS_fnc_feedback_damageBlur" + ] == 0 + }, { + { + ppEffectDestroy _x; + } forEach [ + BIS_fnc_feedback_damageCC, + BIS_fnc_feedback_damageRadialBlur, + BIS_fnc_feedback_damageBlur + ]; + }] call CBA_fnc_waitUntilAndExecute; + #endif }] call CBA_fnc_addEventHandler; - -// Kill vanilla bleeding feedback effects. -#ifdef DISABLE_VANILLA_DAMAGE_EFFECTS -TRACE_1("disabling vanilla bleeding feedback effects",_this); -[{ - {isNil _x} count [ - "BIS_fnc_feedback_damageCC", - "BIS_fnc_feedback_damageRadialBlur", - "BIS_fnc_feedback_damageBlur" - ] == 0 -}, { - { - ppEffectDestroy _x; - } forEach [ - BIS_fnc_feedback_damageCC, - BIS_fnc_feedback_damageRadialBlur, - BIS_fnc_feedback_damageBlur - ]; -}] call CBA_fnc_waitUntilAndExecute; -#endif diff --git a/addons/medical_gui/CfgVehicles.hpp b/addons/medical_gui/CfgVehicles.hpp index 502039325ad..3e4a67ec4fd 100644 --- a/addons/medical_gui/CfgVehicles.hpp +++ b/addons/medical_gui/CfgVehicles.hpp @@ -4,7 +4,7 @@ class CfgVehicles { class ACE_SelfActions { class ACE_Medical { displayName = CSTRING(Medical); - condition = QGVAR(enableSelfActions); + condition = QUOTE(missionNamespace getVariable [ARR_2(QQEGVAR(medical,enabled),false)] && GVAR(enableSelfActions)); exceptions[] = {"isNotInside", "isNotSitting", "isNotSwimming"}; statement = QUOTE([ARR_2(_target,-1)] call FUNC(displayPatientInformation)); runOnHover = 1; @@ -23,7 +23,7 @@ class CfgVehicles { }; }; class ACE_Actions { - #define ACTION_CONDITION condition = QUOTE(GVAR(enableActions) == 0); + #define ACTION_CONDITION condition = QUOTE(missionNamespace getVariable [ARR_2(QQEGVAR(medical,enabled),false)] && GVAR(enableActions) == 0); #include "InteractionBodyParts.hpp" #undef ACTION_CONDITION class ACE_MainActions { @@ -38,7 +38,7 @@ class CfgVehicles { }; class ACE_Medical_Radial { displayName = CSTRING(Medical); - condition = QUOTE((GVAR(enableActions) == 1 || {GVAR(enableActions) != 2 && {!isNull objectParent _target && {objectParent _target isEqualTo objectParent _player}}})); + condition = QUOTE(missionNamespace getVariable [ARR_2(QQEGVAR(medical,enabled),false)] && (GVAR(enableActions) == 1 || {GVAR(enableActions) != 2 && {!isNull objectParent _target && {objectParent _target isEqualTo objectParent _player}}})); exceptions[] = {"isNotInside", "isNotSitting"}; statement = QUOTE([ARR_2(_target,-1)] call FUNC(displayPatientInformation)); runOnHover = 1; @@ -49,7 +49,7 @@ class CfgVehicles { }; class ACE_LoadPatient { displayName = CSTRING(LoadPatient); - condition = QUOTE(_target getVariable [ARR_2('ACE_isUnconscious',false)] && {alive _target} && {isNull objectParent _target} && {(_target call EFUNC(common,nearestVehiclesFreeSeat)) isNotEqualTo []}); + condition = QUOTE(missionNamespace getVariable [ARR_2(QQEGVAR(medical,enabled),false)] && {_target getVariable [ARR_2('ACE_isUnconscious',false)]} && {alive _target} && {isNull objectParent _target} && {(_target call EFUNC(common,nearestVehiclesFreeSeat)) isNotEqualTo []}); exceptions[] = {"isNotDragging", "isNotCarrying"}; statement = QUOTE([ARR_2(_player,_target)] call EFUNC(medical_treatment,loadUnit)); icon = QPATHTOF(ui\cross.paa); diff --git a/addons/medical_gui/XEH_postInit.sqf b/addons/medical_gui/XEH_postInit.sqf index 2b7fb8ce523..841291b7a7f 100644 --- a/addons/medical_gui/XEH_postInit.sqf +++ b/addons/medical_gui/XEH_postInit.sqf @@ -2,115 +2,63 @@ if (!hasInterface) exitWith {}; -GVAR(target) = objNull; -GVAR(previousTarget) = objNull; -GVAR(selectedBodyPart) = 0; -GVAR(selectedCategory) = "triage"; - -GVAR(lastOpenedOn) = -1; -GVAR(pendingReopen) = false; - -GVAR(menuPFH) = -1; - -GVAR(peekLastOpenedOn) = -1; -GVAR(peekOnHitLastOpenedOn) = -1; - -GVAR(selfInteractionActions) = []; -[] call FUNC(addTreatmentActions); -[] call FUNC(collectActions); - -[QEGVAR(interact_menu,newControllableObject), { - params ["_type"]; // string of the object's classname - if !(_type isKindOf "CAManBase") exitWith {}; - { - _x set [0, _type]; - _x call EFUNC(interact_menu,addActionToClass); - } forEach GVAR(selfInteractionActions); -}] call CBA_fnc_addEventHandler; - -["ace_treatmentSucceded", { - if (GVAR(openAfterTreatment) && {GVAR(pendingReopen)}) then { - GVAR(pendingReopen) = false; - [FUNC(openMenu), GVAR(target)] call CBA_fnc_execNextFrame; - }; -}] call CBA_fnc_addEventHandler; - -["ACE3 Common", QGVAR(openMedicalMenuKey), localize LSTRING(OpenMedicalMenu), { - // Get target (cursorTarget, cursorObject, and lineIntersectsSurfaces along camera to maxDistance), if not valid then target is ACE_player - TRACE_3("Open menu key",cursorTarget,cursorObject,ACE_player); - private _target = cursorTarget; - if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { - _target = cursorObject; - if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { - private _start = AGLToASL positionCameraToWorld [0, 0, 0]; - private _end = AGLToASL positionCameraToWorld [0, 0, GVAR(maxDistance)]; - private _intersections = lineIntersectsSurfaces [_start, _end, ACE_player, objNull, true, -1, "FIRE"]; - { - _x params ["", "", "_intersectObject"]; - // Only look "through" player and player's vehicle - if (!(_intersectObject isKindOf "CAManBase") && {_intersectObject != vehicle ACE_player}) exitWith {}; - if (_intersectObject != ACE_player && {_intersectObject isKindOf "CAManBase" && {[ACE_player, _intersectObject] call FUNC(canOpenMenu)}}) exitWith { - _target =_intersectObject - }; - } forEach _intersections; - if (!(_target isKindOf "CAManBase") || {!([ACE_player, _target] call FUNC(canOpenMenu))}) then { - _target = ACE_player; - }; +#include "initKeybinds.inc.sqf" + +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; + + GVAR(target) = objNull; + GVAR(previousTarget) = objNull; + GVAR(selectedBodyPart) = 0; + GVAR(selectedCategory) = "triage"; + + GVAR(lastOpenedOn) = -1; + GVAR(pendingReopen) = false; + + GVAR(menuPFH) = -1; + + GVAR(peekLastOpenedOn) = -1; + GVAR(peekOnHitLastOpenedOn) = -1; + + GVAR(selfInteractionActions) = []; + [] call FUNC(addTreatmentActions); + [] call FUNC(collectActions); + + [QEGVAR(interact_menu,newControllableObject), { + params ["_type"]; // string of the object's classname + if !(_type isKindOf "CAManBase") exitWith {}; + { + _x set [0, _type]; + _x call EFUNC(interact_menu,addActionToClass); + } forEach GVAR(selfInteractionActions); + }] call CBA_fnc_addEventHandler; + + ["ace_treatmentSucceded", { + if (GVAR(openAfterTreatment) && {GVAR(pendingReopen)}) then { + GVAR(pendingReopen) = false; + [FUNC(openMenu), GVAR(target)] call CBA_fnc_execNextFrame; }; - }; - - // Check conditions: canInteract and canOpenMenu - if !([ACE_player, _target, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - if !([ACE_player, _target] call FUNC(canOpenMenu)) exitWith {false}; - - // Statement - [_target] call FUNC(openMenu); - false -}, { - // Close menu if enough time passed from opening - if (CBA_missionTime - GVAR(lastOpenedOn) > 0.5) exitWith { - [objNull] call FUNC(openMenu); - }; - false -}, [DIK_H, [false, false, false]], false, 0] call CBA_fnc_addKeybind; - -["ACE3 Common", QGVAR(peekMedicalInfoKey), localize LSTRING(PeekMedicalInfo), -{ - // Conditions: canInteract - if !([ACE_player, objNull, []] call EFUNC(common,canInteractWith)) exitWith {false}; + }] call CBA_fnc_addEventHandler; - // Statement - [ACE_player, -1] call FUNC(displayPatientInformation); - false -}, { - if (CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay)) then { - [{ - CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay) - }, {QGVAR(RscPatientInfo) cutFadeOut 0.3}] call CBA_fnc_waitUntilAndExecute; - }; - GVAR(peekLastOpenedOn) = CBA_missionTime; - false -}, [DIK_H, [false, true, false]], false, 0] call CBA_fnc_addKeybind; + // Close patient information display when interaction menu is closed + ["ace_interactMenuClosed", { + QGVAR(RscPatientInfo) cutFadeOut 0.3; + }] call CBA_fnc_addEventHandler; + [QEGVAR(medical,woundReceived), { + params ["_unit", "_allDamages", ""]; + if !(GVAR(peekMedicalOnHit) && {_unit == ACE_player}) exitWith {}; -// Close patient information display when interaction menu is closed -["ace_interactMenuClosed", { - QGVAR(RscPatientInfo) cutFadeOut 0.3; -}] call CBA_fnc_addEventHandler; - -[QEGVAR(medical,woundReceived), { - params ["_unit", "_allDamages", ""]; - if !(GVAR(peekMedicalOnHit) && {_unit == ACE_player}) exitWith {}; + private _bodypart = toLowerANSI (_allDamages select 0 select 1); + private _bodypartIndex = ALL_BODY_PARTS find _bodypart; - private _bodypart = toLowerANSI (_allDamages select 0 select 1); - private _bodypartIndex = ALL_BODY_PARTS find _bodypart; + [ACE_player, _bodypartIndex] call FUNC(displayPatientInformation); - [ACE_player, _bodypartIndex] call FUNC(displayPatientInformation); - - if (CBA_missionTime - GVAR(peekOnHitLastOpenedOn) > GVAR(peekMedicalOnHitDuration)) then { - [{ - CBA_missionTime - GVAR(peekOnHitLastOpenedOn) > GVAR(peekMedicalOnHitDuration) - }, {QGVAR(RscPatientInfo) cutFadeOut 0.3}] call CBA_fnc_waitUntilAndExecute; - }; - GVAR(peekOnHitLastOpenedOn) = CBA_missionTime; + if (CBA_missionTime - GVAR(peekOnHitLastOpenedOn) > GVAR(peekMedicalOnHitDuration)) then { + [{ + CBA_missionTime - GVAR(peekOnHitLastOpenedOn) > GVAR(peekMedicalOnHitDuration) + }, {QGVAR(RscPatientInfo) cutFadeOut 0.3}] call CBA_fnc_waitUntilAndExecute; + }; + GVAR(peekOnHitLastOpenedOn) = CBA_missionTime; + }] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_gui/functions/fnc_canOpenMenu.sqf b/addons/medical_gui/functions/fnc_canOpenMenu.sqf index fc2ac3879e7..45fd8f79dfe 100644 --- a/addons/medical_gui/functions/fnc_canOpenMenu.sqf +++ b/addons/medical_gui/functions/fnc_canOpenMenu.sqf @@ -16,6 +16,8 @@ * Public: No */ +if !(GETEGVAR(medical,enabled,false)) exitWith {false}; + params ["_player", "_target"]; // If in Zeus diff --git a/addons/medical_gui/functions/fnc_modifyActionTriageLevel.sqf b/addons/medical_gui/functions/fnc_modifyActionTriageLevel.sqf index b8cca898f26..9ac0d61c1bc 100644 --- a/addons/medical_gui/functions/fnc_modifyActionTriageLevel.sqf +++ b/addons/medical_gui/functions/fnc_modifyActionTriageLevel.sqf @@ -18,7 +18,10 @@ * Public: No */ +if !(GETEGVAR(medical,enabled,false)) exitWith {}; + params ["_target", "_player", "", "_actionData"]; + if ( GVAR(interactionMenuShowTriage) == 1 // Anyone || {GVAR(interactionMenuShowTriage) == 2 && {[_player] call EFUNC(medical_treatment,isMedic)}} // Medics & Doctors diff --git a/addons/medical_gui/initKeybinds.inc.sqf b/addons/medical_gui/initKeybinds.inc.sqf new file mode 100644 index 00000000000..5d5528c59c5 --- /dev/null +++ b/addons/medical_gui/initKeybinds.inc.sqf @@ -0,0 +1,56 @@ +["ACE3 Common", QGVAR(openMedicalMenuKey), LLSTRING(OpenMedicalMenu), { + // Get target (cursorTarget, cursorObject, and lineIntersectsSurfaces along camera to maxDistance), if not valid then target is ACE_player + TRACE_3("Open menu key",cursorTarget,cursorObject,ACE_player); + private _target = cursorTarget; + if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { + _target = cursorObject; + if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { + private _start = AGLToASL positionCameraToWorld [0, 0, 0]; + private _end = AGLToASL positionCameraToWorld [0, 0, GVAR(maxDistance)]; + private _intersections = lineIntersectsSurfaces [_start, _end, ACE_player, objNull, true, -1, "FIRE"]; + { + _x params ["", "", "_intersectObject"]; + // Only look "through" player and player's vehicle + if (!(_intersectObject isKindOf "CAManBase") && {_intersectObject != vehicle ACE_player}) exitWith {}; + if (_intersectObject != ACE_player && {_intersectObject isKindOf "CAManBase" && {[ACE_player, _intersectObject] call FUNC(canOpenMenu)}}) exitWith { + _target = _intersectObject + }; + } forEach _intersections; + if (!(_target isKindOf "CAManBase") || {!([ACE_player, _target] call FUNC(canOpenMenu))}) then { + _target = ACE_player; + }; + }; + }; + + // Check conditions: canInteract and canOpenMenu + if !([ACE_player, _target, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + if !([ACE_player, _target] call FUNC(canOpenMenu)) exitWith {false}; + + // Statement + [_target] call FUNC(openMenu); + false +}, { + // Close menu if enough time passed from opening + if (CBA_missionTime - GVAR(lastOpenedOn) > 0.5) exitWith { + [objNull] call FUNC(openMenu); + }; +}, [DIK_H, [false, false, false]], false, 0] call CBA_fnc_addKeybind; + +["ACE3 Common", QGVAR(peekMedicalInfoKey), localize LSTRING(PeekMedicalInfo), +{ + if !(GETEGVAR(medical,enabled,false)) exitWith {}; + + // Conditions: canInteract + if !([ACE_player, objNull, []] call EFUNC(common,canInteractWith)) exitWith {false}; + + // Statement + [ACE_player, -1] call FUNC(displayPatientInformation); + false +}, { + if (CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay)) then { + [{ + CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay) + }, {QGVAR(RscPatientInfo) cutFadeOut 0.3}] call CBA_fnc_waitUntilAndExecute; + }; + GVAR(peekLastOpenedOn) = CBA_missionTime; +}, [DIK_H, [false, true, false]], false, 0] call CBA_fnc_addKeybind; diff --git a/addons/medical_statemachine/XEH_postInit.sqf b/addons/medical_statemachine/XEH_postInit.sqf index a7c7740a390..8a7ff289520 100644 --- a/addons/medical_statemachine/XEH_postInit.sqf +++ b/addons/medical_statemachine/XEH_postInit.sqf @@ -1,14 +1,18 @@ #include "script_component.hpp" -["ace_killed", { // global event - params ["_unit"]; +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; - // Prevent second ragdoll of uncon units when they're killed - if ( - IS_UNCONSCIOUS(_unit) && !isAwake _unit // uncon and not ragdolling - && {isPlayer _unit || {_unit getVariable [QGVAR(AIUnconsciousness), GVAR(AIUnconsciousness)]}} - ) then { - _unit enableSimulation false; - [{_this enableSimulation true}, _unit, 2] call CBA_fnc_waitAndExecute; - }; + ["ace_killed", { // global event + params ["_unit"]; + + // Prevent second ragdoll of uncon units when they're killed + if ( + IS_UNCONSCIOUS(_unit) && !isAwake _unit // uncon and not ragdolling + && {isPlayer _unit || {_unit getVariable [QGVAR(AIUnconsciousness), GVAR(AIUnconsciousness)]}} + ) then { + _unit enableSimulation false; + [{_this enableSimulation true}, _unit, 2] call CBA_fnc_waitAndExecute; + }; + }] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_status/XEH_postInit.sqf b/addons/medical_status/XEH_postInit.sqf index 3f342987c92..36a64c61625 100644 --- a/addons/medical_status/XEH_postInit.sqf +++ b/addons/medical_status/XEH_postInit.sqf @@ -1,36 +1,41 @@ #include "script_component.hpp" -// Handle pain changes on injury -[QEGVAR(medical,injured), LINKFUNC(adjustPainLevel)] call CBA_fnc_addEventHandler; - - -// Add inventory and open backpack actions to units -[QGVAR(addInventoryActions), LINKFUNC(addInventoryActions)] call CBA_fnc_addEventHandler; -// apply to all living and dead now -{ - [QGVAR(addInventoryActions), _x] call CBA_fnc_localEvent; -} forEach (allUnits + allDeadMen); -// apply to all future units -["CAManBase", "init", LINKFUNC(addInventoryActions), true, [], false] call CBA_fnc_addClassEventHandler; -// Respawn is called locally -["CAManBase", "respawn", { - params ["_unit"]; - if (!local _unit) exitWith {}; - [QGVAR(addInventoryActions), _unit] call CBA_fnc_globalEvent; -}, true] call CBA_fnc_addClassEventHandler; - - -// Handle comms status effects for spectator -// Separate from medical_feedback as these affect unit behavior rather than what the player sees -["featureCamera", { - params ["_unit", "_newCamera"]; - - if (_unit isNotEqualTo ACE_player) exitWith {}; - - if (_newCamera == "") then { // switched back to player view - private _status = IS_UNCONSCIOUS(_unit); - [_unit, _status] call FUNC(setStatusEffects); - } else { - [_unit, false, true] call FUNC(setStatusEffects); - }; -}] call CBA_fnc_addPlayerEventHandler; +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; + + // Handle pain changes on injury + [QEGVAR(medical,injured), LINKFUNC(adjustPainLevel)] call CBA_fnc_addEventHandler; + + // Add inventory and open backpack actions to units + [QGVAR(addInventoryActions), LINKFUNC(addInventoryActions)] call CBA_fnc_addEventHandler; + + // Apply to all living and dead now + { + [QGVAR(addInventoryActions), _x] call CBA_fnc_localEvent; + } forEach (allUnits + allDeadMen); + + // Apply to all future units + ["CAManBase", "init", LINKFUNC(addInventoryActions), true, [], false] call CBA_fnc_addClassEventHandler; + + // Respawn is called locally + ["CAManBase", "respawn", { + params ["_unit"]; + if (!local _unit) exitWith {}; + [QGVAR(addInventoryActions), _unit] call CBA_fnc_globalEvent; + }, true] call CBA_fnc_addClassEventHandler; + + // Handle comms status effects for spectator + // Separate from medical_feedback as these affect unit behavior rather than what the player sees + ["featureCamera", { + params ["_unit", "_newCamera"]; + + if (_unit isNotEqualTo ACE_player) exitWith {}; + + if (_newCamera == "") then { // switched back to player view + private _status = IS_UNCONSCIOUS(_unit); + [_unit, _status] call FUNC(setStatusEffects); + } else { + [_unit, false, true] call FUNC(setStatusEffects); + }; + }] call CBA_fnc_addPlayerEventHandler; +}] call CBA_fnc_addEventHandler; diff --git a/addons/medical_treatment/XEH_postInit.sqf b/addons/medical_treatment/XEH_postInit.sqf index 932ee43fb88..1746753dd83 100644 --- a/addons/medical_treatment/XEH_postInit.sqf +++ b/addons/medical_treatment/XEH_postInit.sqf @@ -1,41 +1,44 @@ #include "script_component.hpp" -[QEGVAR(medical_status,initialized), { - params ["_unit"]; +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; - // Clear all saved medical logs - { - _unit setVariable [_x, nil, true]; - } forEach (_unit getVariable [QEGVAR(medical,allLogs), []]); + TRACE_1("CBA_settingsInitialized EH",GVAR(convertItems)); // 0: Enabled 1: RemoveOnly - _unit setVariable [QEGVAR(medical,allLogs), [], true]; -}] call CBA_fnc_addEventHandler; + [QEGVAR(medical_status,initialized), { + params ["_unit"]; -// Handle body removal and litter on server -if (isServer) then { - [QGVAR(createLitterServer), LINKFUNC(createLitterServer)] call CBA_fnc_addEventHandler; - ["ace_placedInBodyBag", LINKFUNC(removeBody)] call CBA_fnc_addEventHandler; -}; - -// Treatment events -[QGVAR(bandageLocal), LINKFUNC(bandageLocal)] call CBA_fnc_addEventHandler; -[QGVAR(checkBloodPressureLocal), LINKFUNC(checkBloodPressureLocal)] call CBA_fnc_addEventHandler; -[QGVAR(checkPulseLocal), LINKFUNC(checkPulseLocal)] call CBA_fnc_addEventHandler; -[QGVAR(cprLocal), LINKFUNC(cprLocal)] call CBA_fnc_addEventHandler; -[QGVAR(fullHealLocal), LINKFUNC(fullHealLocal)] call CBA_fnc_addEventHandler; -[QGVAR(ivBagLocal), LINKFUNC(ivBagLocal)] call CBA_fnc_addEventHandler; -[QGVAR(medicationLocal), LINKFUNC(medicationLocal)] call CBA_fnc_addEventHandler; -[QGVAR(placeInBodyBagOrGrave), LINKFUNC(placeInBodyBagOrGrave)] call CBA_fnc_addEventHandler; -[QGVAR(splintLocal), LINKFUNC(splintLocal)] call CBA_fnc_addEventHandler; -[QGVAR(tourniquetLocal), LINKFUNC(tourniquetLocal)] call CBA_fnc_addEventHandler; - -// Logging events -[QGVAR(addToLog), LINKFUNC(addToLog)] call CBA_fnc_addEventHandler; -[QGVAR(addToTriageCard), LINKFUNC(addToTriageCard)] call CBA_fnc_addEventHandler; - -// replace medical items with their ACE equivalents -["CBA_settingsInitialized", { - TRACE_1("CBA_settingsInitialized EH",GVAR(convertItems)); // 0: Enabled 1: RemoveOnly + // Clear all saved medical logs + { + _unit setVariable [_x, nil, true]; + } forEach (_unit getVariable [QEGVAR(medical,allLogs), []]); + + _unit setVariable [QEGVAR(medical,allLogs), [], true]; + }] call CBA_fnc_addEventHandler; + + // Handle body removal and litter on server + if (isServer) then { + [QGVAR(createLitterServer), LINKFUNC(createLitterServer)] call CBA_fnc_addEventHandler; + ["ace_placedInBodyBag", LINKFUNC(removeBody)] call CBA_fnc_addEventHandler; + }; + + // Treatment events + [QGVAR(bandageLocal), LINKFUNC(bandageLocal)] call CBA_fnc_addEventHandler; + [QGVAR(checkBloodPressureLocal), LINKFUNC(checkBloodPressureLocal)] call CBA_fnc_addEventHandler; + [QGVAR(checkPulseLocal), LINKFUNC(checkPulseLocal)] call CBA_fnc_addEventHandler; + [QGVAR(cprLocal), LINKFUNC(cprLocal)] call CBA_fnc_addEventHandler; + [QGVAR(fullHealLocal), LINKFUNC(fullHealLocal)] call CBA_fnc_addEventHandler; + [QGVAR(ivBagLocal), LINKFUNC(ivBagLocal)] call CBA_fnc_addEventHandler; + [QGVAR(medicationLocal), LINKFUNC(medicationLocal)] call CBA_fnc_addEventHandler; + [QGVAR(placeInBodyBagOrGrave), LINKFUNC(placeInBodyBagOrGrave)] call CBA_fnc_addEventHandler; + [QGVAR(splintLocal), LINKFUNC(splintLocal)] call CBA_fnc_addEventHandler; + [QGVAR(tourniquetLocal), LINKFUNC(tourniquetLocal)] call CBA_fnc_addEventHandler; + + // Logging events + [QGVAR(addToLog), LINKFUNC(addToLog)] call CBA_fnc_addEventHandler; + [QGVAR(addToTriageCard), LINKFUNC(addToTriageCard)] call CBA_fnc_addEventHandler; + + // Replace medical items with their ACE equivalents { // turn [["stuff", 2], ...] into ["stuff", "stuff", ...] private _replacements = []; @@ -59,41 +62,43 @@ if (isServer) then { // register replacement [_toReplace, _replacements] call EFUNC(common,registerItemReplacement); } forEach (configProperties [configFile >> QEGVAR(medical,replacementItems), "isArray _x"]); -}] call CBA_fnc_addEventHandler; -if (["ace_trenches"] call EFUNC(common,isModLoaded)) then { - if (hasInterface) then { - private _checkHeadstoneAction = [ - QGVAR(checkHeadstone), - LLSTRING(checkHeadstoneName), - QPATHTOEF(medical_gui,ui\grave.paa), - { - [ - [_target getVariable QGVAR(headstoneData)], - true - ] call CBA_fnc_notify; - }, - {!isNil {_target getVariable QGVAR(headstoneData)}} - ] call EFUNC(interact_menu,createAction); - - [missionNameSpace getVariable [QGVAR(graveClassname), "ACE_Grave"], 0, [], _checkHeadstoneAction] call EFUNC(interact_menu,addActionToClass); - }; + if (["ace_trenches"] call EFUNC(common,isModLoaded)) then { + if (hasInterface) then { + private _checkHeadstoneAction = [ + QGVAR(checkHeadstone), + LLSTRING(checkHeadstoneName), + QPATHTOEF(medical_gui,ui\grave.paa), + { + [ + [_target getVariable QGVAR(headstoneData)], + true + ] call CBA_fnc_notify; + }, + {!isNil {_target getVariable QGVAR(headstoneData)}} + ] call EFUNC(interact_menu,createAction); - if (isServer) then { - ["ace_placedInBodyBag", { - params ["_target", "_restingPlace"]; - TRACE_2("ace_placedInBodyBag eh",_target,_restingPlace); - if (isNull _restingPlace) exitWith {}; - - private _targetName = ""; - if (_target isKindOf "ACE_bodyBagObject") then { - _targetName = _target getVariable [QGVAR(headstoneData), ""]; - } else { - _targetName = [_target, false, true] call EFUNC(common,getName); - }; - - if (_targetName == "") exitWith {}; - _restingPlace setVariable [QGVAR(headstoneData), _targetName, true]; - }] call CBA_fnc_addEventHandler; + [missionNameSpace getVariable [QGVAR(graveClassname), "ACE_Grave"], 0, [], _checkHeadstoneAction] call EFUNC(interact_menu,addActionToClass); + }; + + if (isServer) then { + ["ace_placedInBodyBag", { + params ["_target", "_restingPlace"]; + + TRACE_2("ace_placedInBodyBag eh",_target,_restingPlace); + + if (isNull _restingPlace) exitWith {}; + + private _targetName = if (_target isKindOf "ACE_bodyBagObject") then { + _target getVariable [QGVAR(headstoneData), ""] + } else { + [_target, false, true] call EFUNC(common,getName) + }; + + if (_targetName == "") exitWith {}; + + _restingPlace setVariable [QGVAR(headstoneData), _targetName, true]; + }] call CBA_fnc_addEventHandler; + }; }; -}; +}] call CBA_fnc_addEventHandler; diff --git a/addons/medical_treatment/functions/fnc_canUnloadUnit.sqf b/addons/medical_treatment/functions/fnc_canUnloadUnit.sqf index f1a15f04f91..7a00aa8eadb 100644 --- a/addons/medical_treatment/functions/fnc_canUnloadUnit.sqf +++ b/addons/medical_treatment/functions/fnc_canUnloadUnit.sqf @@ -16,6 +16,8 @@ * Public: No */ +if !(GETEGVAR(medical,enabled,false)) exitWith {false}; + params ["_unloader", "_target"]; !isNull objectParent _target && diff --git a/addons/zeus/functions/fnc_moduleUnconscious.sqf b/addons/zeus/functions/fnc_moduleUnconscious.sqf index 7eede3cdece..bd3def1c686 100644 --- a/addons/zeus/functions/fnc_moduleUnconscious.sqf +++ b/addons/zeus/functions/fnc_moduleUnconscious.sqf @@ -21,7 +21,7 @@ params ["_logic"]; if !(local _logic) exitWith {}; -if (isNil QEFUNC(medical,setUnconscious)) then { +if !(GETEGVAR(medical,enabled,false)) then { [LSTRING(RequiresAddon)] call FUNC(showMessage); } else { private _mouseOver = GETMVAR(bis_fnc_curatorObjectPlaced_mouseOver,[""]); From 066ea1424e2db0ae0df86ee5808d991223849eab Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 28 Jul 2024 15:50:39 +0200 Subject: [PATCH 10/14] Stop messing with type of healing items --- addons/medical_treatment/CfgWeapons.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/medical_treatment/CfgWeapons.hpp b/addons/medical_treatment/CfgWeapons.hpp index 7b31e10bee6..ea08d75fe54 100644 --- a/addons/medical_treatment/CfgWeapons.hpp +++ b/addons/medical_treatment/CfgWeapons.hpp @@ -7,14 +7,12 @@ class CfgWeapons { class MedikitItem; class FirstAidKit: ItemCore { - type = 0; ACE_isMedicalItem = 1; class ItemInfo: InventoryFirstAidKitItem_Base_F { mass = 4; }; }; class Medikit: ItemCore { - type = 0; ACE_isMedicalItem = 1; class ItemInfo: MedikitItem { mass = 60; From 9f0ba6a759c6b0cd32346944ccac156f13ab680d Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:38:42 +0200 Subject: [PATCH 11/14] Take setting into account --- addons/medical_ai/XEH_postInit.sqf | 7 +++++++ addons/medical_ai/XEH_preInit.sqf | 7 ------- addons/medical_treatment/CfgVehicles.hpp | 2 +- addons/medical_vitals/initSettings.inc.sqf | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/addons/medical_ai/XEH_postInit.sqf b/addons/medical_ai/XEH_postInit.sqf index 2b9d15d3e82..982094e74de 100644 --- a/addons/medical_ai/XEH_postInit.sqf +++ b/addons/medical_ai/XEH_postInit.sqf @@ -6,6 +6,13 @@ if (GVAR(enabledFor) == 0 || {!(GETEGVAR(medical,enabled,false))}) exitWith {}; // 0: disabled if ((GVAR(enabledFor) == 1) && {!isServer} && {hasInterface}) exitWith {}; // 1: Don't Run on non-hc Clients + // default time values for AI being ready to heal, used in fnc_isSafe + if (isNil QGVAR(timeSafe_shoot)) then { GVAR(timeSafe_shoot) = 30; }; + if (isNil QGVAR(timeSafe_hit)) then { GVAR(timeSafe_hit) = 30; }; + if (isNil QGVAR(timeSafe_suppressed)) then { GVAR(timeSafe_suppressed) = 30; }; + + GVAR(itemHash) = uiNamespace getVariable QGVAR(itemHash); + ["ace_firedNonPlayer", { _unit setVariable [QGVAR(lastFired), CBA_missionTime]; }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_ai/XEH_preInit.sqf b/addons/medical_ai/XEH_preInit.sqf index 8cdc2ee6ad8..894773534a4 100644 --- a/addons/medical_ai/XEH_preInit.sqf +++ b/addons/medical_ai/XEH_preInit.sqf @@ -8,11 +8,4 @@ PREP_RECOMPILE_END; #include "initSettings.inc.sqf" -// default time values for AI being ready to heal, used in fnc_isSafe -if (isNil QGVAR(timeSafe_shoot)) then { GVAR(timeSafe_shoot) = 30; }; -if (isNil QGVAR(timeSafe_hit)) then { GVAR(timeSafe_hit) = 30; }; -if (isNil QGVAR(timeSafe_suppressed)) then { GVAR(timeSafe_suppressed) = 30; }; - -GVAR(itemHash) = uiNamespace getVariable QGVAR(itemHash); - ADDON = true; diff --git a/addons/medical_treatment/CfgVehicles.hpp b/addons/medical_treatment/CfgVehicles.hpp index 4f922eb1996..4d296d07c85 100644 --- a/addons/medical_treatment/CfgVehicles.hpp +++ b/addons/medical_treatment/CfgVehicles.hpp @@ -31,7 +31,7 @@ class CfgVehicles { selection = ""; class GVAR(buryBodyBag) { displayName = CSTRING(DigGrave); - condition = QUOTE([ARR_2(_this#1,_this#0)] call FUNC(canDigGrave)); + condition = QUOTE(GETEGVAR(medical,enabled,false) && {[ARR_2(_this#1,_this#0)] call FUNC(canDigGrave)}); statement = QUOTE(_this call FUNC(placeBodyBagInGrave)); icon = QPATHTOEF(medical_gui,ui\grave.paa); }; diff --git a/addons/medical_vitals/initSettings.inc.sqf b/addons/medical_vitals/initSettings.inc.sqf index db762d2c522..513636eeca5 100644 --- a/addons/medical_vitals/initSettings.inc.sqf +++ b/addons/medical_vitals/initSettings.inc.sqf @@ -6,7 +6,7 @@ true, 1, { - if (_this) exitWith {}; // skip if true + if (_this || {!(GETEGVAR(medical,enabled,false))}) exitWith {}; // skip if true or if medical system disabled { _x setVariable [VAR_OXYGEN_DEMAND, 0, true]; _x setVariable [VAR_SPO2, DEFAULT_SPO2, true]; From 34be857859e8b49e6ea8dd26883a9a9462979754 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:42:23 +0200 Subject: [PATCH 12/14] Update CfgVehicles.hpp --- addons/medical_treatment/CfgVehicles.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/medical_treatment/CfgVehicles.hpp b/addons/medical_treatment/CfgVehicles.hpp index 4d296d07c85..e82624bbfae 100644 --- a/addons/medical_treatment/CfgVehicles.hpp +++ b/addons/medical_treatment/CfgVehicles.hpp @@ -31,7 +31,7 @@ class CfgVehicles { selection = ""; class GVAR(buryBodyBag) { displayName = CSTRING(DigGrave); - condition = QUOTE(GETEGVAR(medical,enabled,false) && {[ARR_2(_this#1,_this#0)] call FUNC(canDigGrave)}); + condition = QUOTE(missionNamespace getVariable [ARR_2(QQEGVAR(medical,enabled),false)] && {[ARR_2(_this#1,_this#0)] call FUNC(canDigGrave)}); statement = QUOTE(_this call FUNC(placeBodyBagInGrave)); icon = QPATHTOEF(medical_gui,ui\grave.paa); }; From f4572d99ab5d5593674b3d5009504ef05f4cd93a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 9 Aug 2024 23:56:55 +0200 Subject: [PATCH 13/14] Cancel healing at vehicles --- addons/medical_engine/XEH_postInit.sqf | 30 ++++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index e122b7aad0f..2e9ce3896f5 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -1,7 +1,11 @@ #include "script_component.hpp" ["CBA_settingsInitialized", { - if !(GETEGVAR(medical,enabled,false)) exitWith {}; + if !(GETEGVAR(medical,enabled,false)) exitWith { + // Call manually (see CfgFunctions.hpp) + // https://community.bistudio.com/wiki/Arma_3:_Functions_Library#Config_Levels + ["postInit", didJIP] spawn BIS_fnc_reviveInit; + }; [QGVAR(updateDamageEffects), LINKFUNC(updateDamageEffects)] call CBA_fnc_addEventHandler; @@ -28,18 +32,26 @@ _unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}] ]; + // Fires where healer is local _unit addEventHandler ["HandleHeal", { - params ["_injured", "_healer"]; + params ["", "_healer", "", "_atVehicle"]; // Replace the items so that the unit can't heal - _healer call EFUNC(common,replaceRegisteredItems); - - AISFinishHeal [_injured, _healer, true]; + // AI stay in healing loop if they have healing items available + if (isNull _atVehicle) then { + _healer call EFUNC(common,replaceRegisteredItems); + } else { + if (_healer call EFUNC(common,isPlayer)) exitWith {}; + + // This resets their action + private _assignedTeam = assignedTeam _healer; + private _groupInfo = [group _healer, groupId _healer]; + [_healer] joinSilent grpNull; // If unit doesn't leave group first, it will take the lowest Id when joinAsSilent is run, regardless of parameters + _healer joinAsSilent _groupInfo; + _healer assignTeam _assignedTeam; + }; - // Set animation to what it was before starting the healing animation - [{"dnon_medic" in animationState (_this select 0)}, { - [_this select 0, _this select 1, 2] call EFUNC(common,doAnimation); - }, [_healer, _healer call EFUNC(common,getDefaultAnim)], 5] call CBA_fnc_waitUntilAndExecute; + true }]; }, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; From 840b2c6013c50d347bfc1fbfdfdfbe223fcfe3ae Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 17 Aug 2024 12:18:33 +0200 Subject: [PATCH 14/14] Update XEH_postInit.sqf --- addons/medical_engine/XEH_postInit.sqf | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index 2e9ce3896f5..31f3ee254c5 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -1,11 +1,7 @@ #include "script_component.hpp" ["CBA_settingsInitialized", { - if !(GETEGVAR(medical,enabled,false)) exitWith { - // Call manually (see CfgFunctions.hpp) - // https://community.bistudio.com/wiki/Arma_3:_Functions_Library#Config_Levels - ["postInit", didJIP] spawn BIS_fnc_reviveInit; - }; + if !(GETEGVAR(medical,enabled,false)) exitWith {}; [QGVAR(updateDamageEffects), LINKFUNC(updateDamageEffects)] call CBA_fnc_addEventHandler; @@ -34,21 +30,27 @@ // Fires where healer is local _unit addEventHandler ["HandleHeal", { - params ["", "_healer", "", "_atVehicle"]; + params ["_injured", "_healer", "_isMedic", "_atVehicle"]; + + AISFinishHeal [_injured, _healer, _isMedic]; // Replace the items so that the unit can't heal // AI stay in healing loop if they have healing items available if (isNull _atVehicle) then { _healer call EFUNC(common,replaceRegisteredItems); } else { + // If medical_treatment isn't loaded, interrupt healing command by forcing the unit to leave and rejoin the group if (_healer call EFUNC(common,isPlayer)) exitWith {}; - // This resets their action + // This resets their command/action private _assignedTeam = assignedTeam _healer; private _groupInfo = [group _healer, groupId _healer]; [_healer] joinSilent grpNull; // If unit doesn't leave group first, it will take the lowest Id when joinAsSilent is run, regardless of parameters _healer joinAsSilent _groupInfo; - _healer assignTeam _assignedTeam; + + if (_assignedTeam != "") then { + _healer assignTeam _assignedTeam; + }; }; true