From ac41e9770980feb57c2a7c03e95db0db78c01794 Mon Sep 17 00:00:00 2001 From: Blue Date: Sat, 25 Nov 2023 21:15:47 +0100 Subject: [PATCH 1/2] Add tourniquet effects --- addons/misc/CfgFunctions.hpp | 8 ++ addons/misc/XEH_PREP.hpp | 2 + addons/misc/XEH_postInit.sqf | 16 ++- addons/misc/functions/fnc_fullHealLocal.sqf | 6 ++ addons/misc/functions/fnc_handleRespawn.sqf | 5 + .../functions/fnc_handleTourniquetEffects.sqf | 90 ++++++++++++++++ .../functions/fnc_updateDamageEffects.sqf | 102 ++++++++++++++++++ addons/misc/script_component.hpp | 3 + addons/pharma/XEH_PREP.hpp | 1 + 9 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 addons/misc/functions/fnc_handleTourniquetEffects.sqf create mode 100644 addons/misc/functions/fnc_updateDamageEffects.sqf diff --git a/addons/misc/CfgFunctions.hpp b/addons/misc/CfgFunctions.hpp index ed06afafc..e0e22c764 100644 --- a/addons/misc/CfgFunctions.hpp +++ b/addons/misc/CfgFunctions.hpp @@ -18,6 +18,14 @@ class CfgFunctions { }; }; }; + class overwrite_ace_medical_engine { + tag = "ace_medical_engine"; + class ace_medical_engine { + class updateDamageEffects { + file = QPATHTOF(functions\fnc_updateDamageEffects.sqf); + }; + }; + }; class overwrite_medical_treatment { tag = "ace_medical_treatment"; class ace_medical_treatment { diff --git a/addons/misc/XEH_PREP.hpp b/addons/misc/XEH_PREP.hpp index 7019062bb..b3e145148 100644 --- a/addons/misc/XEH_PREP.hpp +++ b/addons/misc/XEH_PREP.hpp @@ -28,6 +28,7 @@ PREP(getMagazineAmmoCounts); PREP(getUniqueItems); PREP(groupID); PREP(handleRespawn); +PREP(handleTourniquetEffects); PREP(handleUnconscious); PREP(hasItem); PREP(hasStableVitals); @@ -50,4 +51,5 @@ PREP(treatmentIV); PREP(treatmentSuccess); PREP(unloadAndCarryPatient); PREP(unSlingArmband); +PREP(updateDamageEffects); PREP(useItem); \ No newline at end of file diff --git a/addons/misc/XEH_postInit.sqf b/addons/misc/XEH_postInit.sqf index d263ca7d6..9440bac59 100644 --- a/addons/misc/XEH_postInit.sqf +++ b/addons/misc/XEH_postInit.sqf @@ -52,4 +52,18 @@ if (GVAR(incompatibilityWarning)) then { [_carrier, _target] call ACEFUNC(dragging,dropObject_carry); }] call CBA_fnc_addEventHandler; -call FUNC(FAK_updateContents); \ No newline at end of file +call FUNC(FAK_updateContents); + +[QACEGVAR(medical_treatment,tourniquetLocal), LINKFUNC(handleTourniquetEffects)] call CBA_fnc_addEventHandler; + +["baseline", { + private _activeTourniquets = GET_TOURNIQUETS(ACE_player); + ((_activeTourniquets select 2) + (_activeTourniquets select 3) min 1); +}, QUOTE(ADDON)] call ACEFUNC(common,addSwayFactor); + +["multiplier", { + private _activeTourniquets = GET_TOURNIQUETS(ACE_player); + if (ACE_player getVariable [QGVAR(Tourniquet_ArmNecrosis), 0] > 0) then { + (ACE_player getVariable [QGVAR(Tourniquet_ArmNecrosis), 0]) / 10 + } else {0}; +}, QUOTE(ADDON)] call ACEFUNC(common,addSwayFactor); \ No newline at end of file diff --git a/addons/misc/functions/fnc_fullHealLocal.sqf b/addons/misc/functions/fnc_fullHealLocal.sqf index dcc163f72..a8a01e824 100644 --- a/addons/misc/functions/fnc_fullHealLocal.sqf +++ b/addons/misc/functions/fnc_fullHealLocal.sqf @@ -122,6 +122,12 @@ _unit setVariable [QEGVAR(surgery,lidocaine), false, true]; _unit setVariable [QEGVAR(surgery,etomidate), false, true]; _unit setVariable [QEGVAR(surgery,sedated), false, true]; +// KAT Misc +_unit setVariable [QGVAR(Tourniquet_ArmNecrosis), 0]; +_unit setVariable [QGVAR(Tourniquet_LegNecrosis), 0]; +_unit setVariable [QGVAR(Tourniquet_PFH), -1]; +_unit setVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0, true]; + // Damage storage _unit setVariable [QACEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0], true]; diff --git a/addons/misc/functions/fnc_handleRespawn.sqf b/addons/misc/functions/fnc_handleRespawn.sqf index 6101afb72..8e4961925 100644 --- a/addons/misc/functions/fnc_handleRespawn.sqf +++ b/addons/misc/functions/fnc_handleRespawn.sqf @@ -92,6 +92,11 @@ _unit setVariable [QEGVAR(misc,isRightArmFree), true, true]; _unit setVariable [QEGVAR(misc,isLeftLegFree), true, true]; _unit setVariable [QEGVAR(misc,isRightLegFree), true, true]; +_unit setVariable [QGVAR(Tourniquet_ArmNecrosis), 0]; +_unit setVariable [QGVAR(Tourniquet_LegNecrosis), 0]; +_unit setVariable [QGVAR(Tourniquet_PFH), -1]; +_unit setVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0, true]; + // KAT Pharmacy _unit setVariable [QEGVAR(pharma,alphaAction), 1, true]; diff --git a/addons/misc/functions/fnc_handleTourniquetEffects.sqf b/addons/misc/functions/fnc_handleTourniquetEffects.sqf new file mode 100644 index 000000000..40bd7b55c --- /dev/null +++ b/addons/misc/functions/fnc_handleTourniquetEffects.sqf @@ -0,0 +1,90 @@ +#include "..\script_component.hpp" +/* + * Author: Blue + * Handle effects for when tourniquet is applied for prolonged time + * + * Arguments: + * 0: Unit + * + * Return Value: + * None + * + * Example: + * [player] call kat_misc_fnc_handleTourniquetEffects; + * + * Public: No + */ + +params ["_unit"]; + +if (_unit getVariable [QGVAR(Tourniquet_PFH), -1] != -1) exitWith {}; +_unit setVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0, true]; + +private _handleLegEffects = { + params ["_unit", "_threshold"]; + + if (_unit getVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0] != _threshold) then { + _unit setVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), _threshold, true]; + [_unit] call FUNC(updateDamageEffects); + }; +}; + +private _tourniquetPFH = [{ + params ["_args", "_idPFH"]; + _args params ["_unit", "_handleLegEffects"]; + + private _tourniquet_ArmNecrosis = _unit getVariable [QGVAR(Tourniquet_ArmNecrosis), 0]; + private _tourniquet_LegNecrosis = _unit getVariable [QGVAR(Tourniquet_LegNecrosis), 0]; + + private _activeTourniquets = GET_TOURNIQUETS(_unit); + private _armTourniquets = (_activeTourniquets select 2) + (_activeTourniquets select 3); + private _legTourniquets = (_activeTourniquets select 4) + (_activeTourniquets select 5); + + if (_armTourniquets > 1) then { + _tourniquet_ArmNecrosis = _tourniquet_ArmNecrosis + 1.6; //0.15 + + if (_tourniquet_ArmNecrosis >= 100) then { + _tourniquet_ArmNecrosis = 100; + }; + } else { + _tourniquet_ArmNecrosis = _tourniquet_ArmNecrosis - 3.2; //0.30 + + if (_tourniquet_ArmNecrosis <= 0) then { + _tourniquet_ArmNecrosis = 0; + }; + }; + + if (_legTourniquets > 1) then { + _tourniquet_LegNecrosis = _tourniquet_LegNecrosis + 1.6; + + if (_tourniquet_LegNecrosis >= 100) then { + _tourniquet_LegNecrosis = 100; + }; + } else { + _tourniquet_LegNecrosis = _tourniquet_LegNecrosis - 3.2; + + if (_tourniquet_LegNecrosis <= 0) then { + _tourniquet_LegNecrosis = 0; + }; + }; + + switch (true) do { + case (_tourniquet_LegNecrosis > 20 && _tourniquet_LegNecrosis < 60): {[_unit, 20] call _handleLegEffects;}; + case (_tourniquet_LegNecrosis > 60 && _tourniquet_LegNecrosis < 90): {[_unit, 60] call _handleLegEffects;}; + case (_tourniquet_LegNecrosis > 90): {[_unit, 90] call _handleLegEffects;}; + default {[_unit, 0] call _handleLegEffects;}; + }; + + if ((_tourniquet_ArmNecrosis + _tourniquet_LegNecrosis <= 0 && _armTourniquets + _legTourniquets == 0) || !(alive _unit)) exitWith { + _unit setVariable [QGVAR(Tourniquet_ArmNecrosis), 0]; + _unit setVariable [QGVAR(Tourniquet_LegNecrosis), 0]; + _unit setVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0, true]; + _unit setVariable [QGVAR(Tourniquet_PFH), -1]; + [_idPFH] call CBA_fnc_removePerFrameHandler; + }; + + _unit setVariable [QGVAR(Tourniquet_ArmNecrosis), _tourniquet_ArmNecrosis]; + _unit setVariable [QGVAR(Tourniquet_LegNecrosis), _tourniquet_LegNecrosis]; +}, 1, [_unit, _handleLegEffects]] call CBA_fnc_addPerFrameHandler; + +_unit setVariable [QGVAR(Tourniquet_PFH), _tourniquetPFH]; \ No newline at end of file diff --git a/addons/misc/functions/fnc_updateDamageEffects.sqf b/addons/misc/functions/fnc_updateDamageEffects.sqf new file mode 100644 index 000000000..56d90706d --- /dev/null +++ b/addons/misc/functions/fnc_updateDamageEffects.sqf @@ -0,0 +1,102 @@ +#include "..\script_component.hpp" +/* + * Author: commy2, PabstMirror + * Modified: Blue + * Updates damage effects for limping and fractures. + * + * Arguments: + * 0: Unit + * + * Return Value: + * None + * + * Example: + * [player] call ace_medical_engine_fnc_updateDamageEffects + * + * Public: No + */ + +params [["_unit", objNull, [objNull]]]; + +if (!local _unit) exitWith { ERROR_2("updateDamageEffects: Unit not local or null [%1:%2]",_unit,typeOf _unit); }; + +private _isLimping = false; +private _hasLegSplint = false; +private _noSprint = false; +private _noJog = false; + +if (ACEGVAR(medical,fractures) > 0) then { + private _fractures = GET_FRACTURES(_unit); + TRACE_1("",_fractures); + if (((_fractures select 4) == 1) || {(_fractures select 5) == 1}) then { + TRACE_1("limping because of fracture",_fractures); + _isLimping = true; + }; + private _aimFracture = 0; + if ((_fractures select 2) == 1) then { _aimFracture = _aimFracture + 4; }; + if ((_fractures select 3) == 1) then { _aimFracture = _aimFracture + 4; }; + + if (ACEGVAR(medical,fractures) in [2, 3]) then { // the limp with a splint will still cause effects + // Block sprint / force walking based on fracture setting and leg splint status + _hasLegSplint = (_fractures select 4) == -1 || {(_fractures select 5) == -1}; + if (ACEGVAR(medical,fractures) == 2) then { + _noSprint = _hasLegSplint; + } else { + _noJog = _hasLegSplint; + }; + + if ((_fractures select 2) == -1) then { _aimFracture = _aimFracture + 2; }; + if ((_fractures select 3) == -1) then { _aimFracture = _aimFracture + 2; }; + }; + _unit setVariable [QACEGVAR(medical_engine,aimFracture), _aimFracture, false]; // local only var, used in ace_medical's postInit to set ACE_setCustomAimCoef +}; + +if (!_isLimping && {ACEGVAR(medical,limping) > 0}) then { + private _openWounds = GET_OPEN_WOUNDS(_unit); + + // Want a copy of combined arrays to prevent wound mixing + private _legWounds = (_openWounds getOrDefault ["leftleg", []]) + + (_openWounds getOrDefault ["rightleg", []]); + + if (ACEGVAR(medical,limping) == 2) then { + private _bandagedWounds = GET_BANDAGED_WOUNDS(_unit); + _legWounds = _legWounds + + (_bandagedWounds getOrDefault ["leftleg", []]) + + (_bandagedWounds getOrDefault ["rightleg", []]); + }; + + { + _x params ["_xClassID", "_xAmountOf", "", "_xDamage"]; + if ( + (_xAmountOf > 0) + && {_xDamage > LIMPING_DAMAGE_THRESHOLD_DEFAULT} + // select _causeLimping from woundDetails + && {(ACEGVAR(medical_damage,woundDetails) get (_xClassID / 10)) select 3} + ) exitWith { + TRACE_1("limping because of wound",_x); + _isLimping = true; + }; + } forEach _legWounds; +}; + +if (_unit getVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0] >= 20) then { + _noSprint = true; +}; + +if (_unit getVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0] >= 60) then { + _noJog = true; +}; + +if (_unit getVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0] >= 90) then { + _isLimping = true; +}; + +[_unit, "blockSprint", QACEGVAR(medical,fracture), _noSprint] call ACEFUNC(common,statusEffect_set); +[_unit, "forceWalk", QACEGVAR(medical,fracture), _noJog] call ACEFUNC(common,statusEffect_set); + +_unit setVariable [QACEGVAR(medical,isLimping), _isLimping, true]; + +// refresh +private _isDamaged = _unit getHitPointDamage "HitLegs" >= DAMAGED_MIN_THRESHOLD && {_unit getHitPointDamage "HitLegs" != LIMPING_MIN_DAMAGE}; + +[_unit, "Legs", _isDamaged] call ACEFUNC(medical_engine,damageBodyPart); diff --git a/addons/misc/script_component.hpp b/addons/misc/script_component.hpp index cda06aac4..56d64c140 100644 --- a/addons/misc/script_component.hpp +++ b/addons/misc/script_component.hpp @@ -17,3 +17,6 @@ #include "\x\kat\addons\main\script_macros.hpp" #define MEDICAL_TREATMENT_ITEMS (call (uiNamespace getVariable [QACEGVAR(medical_treatment,treatmentItems), {[]}])) + +#define DAMAGED_MIN_THRESHOLD 0.45 +#define LIMPING_MIN_DAMAGE 0.5 \ No newline at end of file diff --git a/addons/pharma/XEH_PREP.hpp b/addons/pharma/XEH_PREP.hpp index 972afa228..051a45ac5 100644 --- a/addons/pharma/XEH_PREP.hpp +++ b/addons/pharma/XEH_PREP.hpp @@ -5,6 +5,7 @@ PREP(fluid); PREP(fluidLocal); PREP(getBloodLoss); PREP(getBloodVolumeChange); +PREP(tourniquetRemove); PREP(init); PREP(inspectCatheter); PREP(medication); From 1aa5c672a1ea229a7f18c87f61a42bef9b497387 Mon Sep 17 00:00:00 2001 From: Blue Date: Mon, 27 Nov 2023 22:52:19 +0100 Subject: [PATCH 2/2] Add settings --- addons/misc/XEH_postInit.sqf | 4 ++- addons/misc/XEH_preInit.sqf | 31 +++++++++++++++++-- .../functions/fnc_handleTourniquetEffects.sqf | 11 +++---- addons/misc/stringtable.xml | 12 +++++++ 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/addons/misc/XEH_postInit.sqf b/addons/misc/XEH_postInit.sqf index 9440bac59..a5e4b932f 100644 --- a/addons/misc/XEH_postInit.sqf +++ b/addons/misc/XEH_postInit.sqf @@ -58,7 +58,9 @@ call FUNC(FAK_updateContents); ["baseline", { private _activeTourniquets = GET_TOURNIQUETS(ACE_player); - ((_activeTourniquets select 2) + (_activeTourniquets select 3) min 1); + if (GVAR(tourniquetEffects_Enable)) then { + ((_activeTourniquets select 2) + (_activeTourniquets select 3) min 1) + } else {0}; }, QUOTE(ADDON)] call ACEFUNC(common,addSwayFactor); ["multiplier", { diff --git a/addons/misc/XEH_preInit.sqf b/addons/misc/XEH_preInit.sqf index 4e0737774..737aa832c 100644 --- a/addons/misc/XEH_preInit.sqf +++ b/addons/misc/XEH_preInit.sqf @@ -32,7 +32,7 @@ PREP_RECOMPILE_END; QGVAR(treatmentTimeDetachTourniquet), "SLIDER", [LLSTRING(SETTING_treatmentTimeDetachTourniquet)], - [CBA_SETTINGS_CAT, ELSTRING(GUI,SubCategory_Basic)], + [CBA_SETTINGS_CAT, LSTRING(SubCategory_Tourniquet)], [1, 60, 7, 1], true ] call CBA_Settings_fnc_init; @@ -41,11 +41,38 @@ PREP_RECOMPILE_END; QGVAR(neckTourniquet), "CHECKBOX", [LLSTRING(neckTourniquetDescription)], - [CBA_SETTINGS_CAT, ELSTRING(GUI,SubCategory_Basic)], + [CBA_SETTINGS_CAT, LSTRING(SubCategory_Tourniquet)], [false], true ] call CBA_Settings_fnc_init; +[ + QGVAR(tourniquetEffects_Enable), + "CHECKBOX", + [LLSTRING(SETTING_tourniquetEffects_Enable)], + [CBA_SETTINGS_CAT, LSTRING(SubCategory_Tourniquet)], + [true], + true +] call CBA_Settings_fnc_init; + +[ + QGVAR(tourniquetEffects_PositiveMultiplier), + "SLIDER", + [LLSTRING(SETTING_tourniquetEffects_PositiveMultiplier)], + [CBA_SETTINGS_CAT, LSTRING(SubCategory_Tourniquet)], + [0.1, 10, 1, 1], + true +] call CBA_Settings_fnc_init; + +[ + QGVAR(tourniquetEffects_NegativeMultiplier), + "SLIDER", + [LLSTRING(SETTING_tourniquetEffects_NegativeMultiplier)], + [CBA_SETTINGS_CAT, LSTRING(SubCategory_Tourniquet)], + [0.1, 10, 1, 1], + true +] call CBA_Settings_fnc_init; + //Incompatibility Warning with other addons [ diff --git a/addons/misc/functions/fnc_handleTourniquetEffects.sqf b/addons/misc/functions/fnc_handleTourniquetEffects.sqf index 40bd7b55c..01f9f3316 100644 --- a/addons/misc/functions/fnc_handleTourniquetEffects.sqf +++ b/addons/misc/functions/fnc_handleTourniquetEffects.sqf @@ -17,7 +17,7 @@ params ["_unit"]; -if (_unit getVariable [QGVAR(Tourniquet_PFH), -1] != -1) exitWith {}; +if (_unit getVariable [QGVAR(Tourniquet_PFH), -1] != -1 || !(GVAR(tourniquetEffects_Enable))) exitWith {}; _unit setVariable [QGVAR(Tourniquet_LegNecrosis_Threshold), 0, true]; private _handleLegEffects = { @@ -41,13 +41,12 @@ private _tourniquetPFH = [{ private _legTourniquets = (_activeTourniquets select 4) + (_activeTourniquets select 5); if (_armTourniquets > 1) then { - _tourniquet_ArmNecrosis = _tourniquet_ArmNecrosis + 1.6; //0.15 - + _tourniquet_ArmNecrosis = _tourniquet_ArmNecrosis + (0.16 * GVAR(tourniquetEffects_PositiveMultiplier)); if (_tourniquet_ArmNecrosis >= 100) then { _tourniquet_ArmNecrosis = 100; }; } else { - _tourniquet_ArmNecrosis = _tourniquet_ArmNecrosis - 3.2; //0.30 + _tourniquet_ArmNecrosis = _tourniquet_ArmNecrosis - (0.32 * GVAR(tourniquetEffects_NegativeMultiplier)); if (_tourniquet_ArmNecrosis <= 0) then { _tourniquet_ArmNecrosis = 0; @@ -55,13 +54,13 @@ private _tourniquetPFH = [{ }; if (_legTourniquets > 1) then { - _tourniquet_LegNecrosis = _tourniquet_LegNecrosis + 1.6; + _tourniquet_LegNecrosis = _tourniquet_LegNecrosis + (0.16 * GVAR(tourniquetEffects_PositiveMultiplier)); if (_tourniquet_LegNecrosis >= 100) then { _tourniquet_LegNecrosis = 100; }; } else { - _tourniquet_LegNecrosis = _tourniquet_LegNecrosis - 3.2; + _tourniquet_LegNecrosis = _tourniquet_LegNecrosis - (0.32 * GVAR(tourniquetEffects_NegativeMultiplier)); if (_tourniquet_LegNecrosis <= 0) then { _tourniquet_LegNecrosis = 0; diff --git a/addons/misc/stringtable.xml b/addons/misc/stringtable.xml index d3d026be2..fa4c1ebb3 100644 --- a/addons/misc/stringtable.xml +++ b/addons/misc/stringtable.xml @@ -357,6 +357,18 @@ [ADVERTENCIA DE KAM] Addon(s) incompatibles que podrían afectar negativamente el funcionamiento del mod fueron detectados. El equipo de desarollo de KAT - Advanced Medical REWRITE recomienda fuertemente remover estos addons. %1 [AVISO DO KAM] Detectados addons incompatíveis que podem afetar negativamente a funcionalidade correta. KAT - A equipe de desenvolvimento do Advanced Medical REWRITE recomenda fortemente a remoção destes complementos: %1 + + Tourniquet Settings + + + Enable tourniquet effects + + + Tourniquet effects positive multiplier + + + Tourniquet effects negative multiplier + Time to take off tourniquet Tiempo para retirar un torniquete