From f2c3b8071a0bf17655a8f33d73da0e589f40196a Mon Sep 17 00:00:00 2001 From: LinkIsGrim <69561145+LinkIsGrim@users.noreply.github.com> Date: Wed, 18 Dec 2024 23:38:29 -0300 Subject: [PATCH 1/6] Medical Damage - Pass ammo to wound handlers --- addons/medical_damage/functions/fnc_woundReceived.sqf | 4 ++-- docs/wiki/framework/medical-framework.md | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/addons/medical_damage/functions/fnc_woundReceived.sqf b/addons/medical_damage/functions/fnc_woundReceived.sqf index c31cf5b3789..4374a210a52 100644 --- a/addons/medical_damage/functions/fnc_woundReceived.sqf +++ b/addons/medical_damage/functions/fnc_woundReceived.sqf @@ -25,14 +25,14 @@ private _typeOfDamage = _ammo call FUNC(getTypeOfDamage); if (_typeOfDamage in GVAR(damageTypeDetails)) then { (GVAR(damageTypeDetails) get _typeOfDamage) params ["", "", "_woundHandlers"]; - private _damageData = [_unit, _allDamages, _typeOfDamage]; + private _damageData = [_unit, _allDamages, _typeOfDamage, _ammo]; { _damageData = _damageData call _x; TRACE_1("Wound handler returned",_damageData); // If invalid return, exit - if (isNil "_damageData" || {!(_damageData isEqualType [])} || {(count _damageData) < 3}) exitWith { + if (isNil "_damageData" || {!(_damageData isEqualType [])} || {(count _damageData) < 4}) exitWith { TRACE_1("Return invalid, skipping wound handling",_damageData); }; } forEach _woundHandlers; diff --git a/docs/wiki/framework/medical-framework.md b/docs/wiki/framework/medical-framework.md index c0e94b5f9ee..854ae3654aa 100644 --- a/docs/wiki/framework/medical-framework.md +++ b/docs/wiki/framework/medical-framework.md @@ -224,18 +224,22 @@ Custom wound handlers should follow the same spec as the built-in handler: | 0 | Unit that was hit | Object | Required | | 1 | Array of damage dealt to each body part | Array | Required | | 2 | Type of damage | String | Required | +| 3 | Ammo classname | String | Required | | **R** | Parameters to be passed to the next handler in the list, e.g. `_this` or a modified copy of it. Return `[]` to prevent further handling. | Array | Required | The damage elements are sorted in descending order according to how much damage was dealt to each body part _before armor was taken into account_, but the actual damage values are _after armor_. +We recommend modifying `_this` with `set` instead of returning a copy of the array to prevent any issues with API changes. Existing parameters will not change in type, function, or format without warning, but new parameters may be added. + ### Example -`[player, [[0.5, "Body", 1], [0.3, "Head", 0.6]], "grenade"] ace_medical_damage_fnc_woundsHandlerBase` +`[player, [[0.5, "Body", 1], [0.3, "Head", 0.6]], "grenade", "grenade_ammo"] ace_medical_damage_fnc_woundsHandlerBase` | | Arguments | Explanation | | ---| --------- | ----------- | | 0 | `player` | Unit that was hit | | 1 | `[[0.5, "Body", 1], [0.3, "Head", 0.6]]` | 0.5 damage to body (was 1 before armor), 0.3 damage to head (was 0.6 before armor) | | 2 | `"grenade"` | type grenade (non-selection-specific) | +| 3 | `"grenade_ammo"` | grenade ammo classname from CfgAmmo | ## 5. Tweaking internal variables Some of ACE Medical's underlying behavior, primarily related to damage handling and the vitals loop, can be fine-tuned by editing `ace_medical_const_` variables, found in [script_macros_medical.hpp](https://github.com/acemod/ACE3/blob/master/addons/medical_engine/script_macros_medical.hpp). From f1d734fb98409620881713e6f3e31dd8f4037b14 Mon Sep 17 00:00:00 2001 From: LinkIsGrim <69561145+LinkIsGrim@users.noreply.github.com> Date: Thu, 19 Dec 2024 00:10:20 -0300 Subject: [PATCH 2/6] Docs: add note on ammo --- docs/wiki/framework/medical-framework.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/wiki/framework/medical-framework.md b/docs/wiki/framework/medical-framework.md index 854ae3654aa..c00555360ce 100644 --- a/docs/wiki/framework/medical-framework.md +++ b/docs/wiki/framework/medical-framework.md @@ -224,12 +224,14 @@ Custom wound handlers should follow the same spec as the built-in handler: | 0 | Unit that was hit | Object | Required | | 1 | Array of damage dealt to each body part | Array | Required | | 2 | Type of damage | String | Required | -| 3 | Ammo classname | String | Required | +| 3 | Ammo | String | Required | | **R** | Parameters to be passed to the next handler in the list, e.g. `_this` or a modified copy of it. Return `[]` to prevent further handling. | Array | Required | +We recommend modifying `_this` with `set` instead of returning a copy of the array to prevent any issues with API changes. Existing parameters will not change in type, function, or format without warning, but new parameters may be added. + The damage elements are sorted in descending order according to how much damage was dealt to each body part _before armor was taken into account_, but the actual damage values are _after armor_. -We recommend modifying `_this` with `set` instead of returning a copy of the array to prevent any issues with API changes. Existing parameters will not change in type, function, or format without warning, but new parameters may be added. +Ammo can be a CfgAmmo classname (like `" B_556x45_Ball"`), empty string, or special ammo from `medical_engine`/another wound handler. Check if the passed ammo is within your expected values (like `!isNull (configFile >> "CfgAmmo" >> _ammo)` for CfgAmmo classes) before using it. ### Example `[player, [[0.5, "Body", 1], [0.3, "Head", 0.6]], "grenade", "grenade_ammo"] ace_medical_damage_fnc_woundsHandlerBase` @@ -239,7 +241,7 @@ We recommend modifying `_this` with `set` instead of returning a copy of the arr | 0 | `player` | Unit that was hit | | 1 | `[[0.5, "Body", 1], [0.3, "Head", 0.6]]` | 0.5 damage to body (was 1 before armor), 0.3 damage to head (was 0.6 before armor) | | 2 | `"grenade"` | type grenade (non-selection-specific) | -| 3 | `"grenade_ammo"` | grenade ammo classname from CfgAmmo | +| 3 | `"grenade_ammo"` | ammo | ## 5. Tweaking internal variables Some of ACE Medical's underlying behavior, primarily related to damage handling and the vitals loop, can be fine-tuned by editing `ace_medical_const_` variables, found in [script_macros_medical.hpp](https://github.com/acemod/ACE3/blob/master/addons/medical_engine/script_macros_medical.hpp). From 2b8628d8ced7924f86a29916f39abafddf22c8c0 Mon Sep 17 00:00:00 2001 From: LinkIsGrim <69561145+LinkIsGrim@users.noreply.github.com> Date: Thu, 19 Dec 2024 18:05:42 -0300 Subject: [PATCH 3/6] add error if missing ammo on return --- .../functions/fnc_parseWoundHandlersCfg.sqf | 5 +++-- .../medical_damage/functions/fnc_woundReceived.sqf | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf b/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf index 010f02b7f5d..f0ed3ca38f9 100644 --- a/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf +++ b/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf @@ -22,6 +22,7 @@ private _entries = []; { private _entryResult = getText _x; + private _entryName = configName _x; if (_entryResult != "") then { if (ADDON) then { @@ -30,9 +31,9 @@ private _entries = []; if (!isNil "_entryResult") then { if (_entryResult isEqualType {}) then { - _entries pushBack _entryResult; + _entries pushBack [_entryName, _entryResult]; } else { - ERROR_2("Wound handler '%1' needs to be a function, but is of type %2.",configName _x,toLowerANSI typeName _entryResult); + ERROR_2("Wound handler '%1' needs to be a function, but is of type %2.",_entryName,toLowerANSI typeName _entryResult); }; }; } else { diff --git a/addons/medical_damage/functions/fnc_woundReceived.sqf b/addons/medical_damage/functions/fnc_woundReceived.sqf index 4374a210a52..bc4cb9aecb3 100644 --- a/addons/medical_damage/functions/fnc_woundReceived.sqf +++ b/addons/medical_damage/functions/fnc_woundReceived.sqf @@ -28,12 +28,18 @@ if (_typeOfDamage in GVAR(damageTypeDetails)) then { private _damageData = [_unit, _allDamages, _typeOfDamage, _ammo]; { - _damageData = _damageData call _x; - TRACE_1("Wound handler returned",_damageData); + _x params ["_handlerName", "_handlerCode"]; + _damageData = _damageData call _handlerCode; + TRACE_2("Wound handler returned",_damageData,_handlerName); + + if ((count _damageData) == 3) then { + ERROR_1("Wound handler '%1' missing _ammo in return, readding. This will be deprecated in the future, check Medical Framework wiki.",_handlerName); + _damageData pushBack _ammo; + }; // If invalid return, exit if (isNil "_damageData" || {!(_damageData isEqualType [])} || {(count _damageData) < 4}) exitWith { - TRACE_1("Return invalid, skipping wound handling",_damageData); + TRACE_2("Return invalid, skipping wound handling",_damageData,_handlerName); }; } forEach _woundHandlers; }; From 9e0186f44574036b0a5b7894b9d40f6f4a36668a Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Fri, 20 Dec 2024 19:21:15 -0300 Subject: [PATCH 4/6] Update docs/wiki/framework/medical-framework.md --- docs/wiki/framework/medical-framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/wiki/framework/medical-framework.md b/docs/wiki/framework/medical-framework.md index c00555360ce..c3ec6d31de4 100644 --- a/docs/wiki/framework/medical-framework.md +++ b/docs/wiki/framework/medical-framework.md @@ -227,7 +227,7 @@ Custom wound handlers should follow the same spec as the built-in handler: | 3 | Ammo | String | Required | | **R** | Parameters to be passed to the next handler in the list, e.g. `_this` or a modified copy of it. Return `[]` to prevent further handling. | Array | Required | -We recommend modifying `_this` with `set` instead of returning a copy of the array to prevent any issues with API changes. Existing parameters will not change in type, function, or format without warning, but new parameters may be added. +We recommend modifying `_this` with `set` and returning it instead of returning a copy of the array to prevent any issues with API changes. Existing parameters will not change in type, function, or format without warning, but new parameters may be added. The damage elements are sorted in descending order according to how much damage was dealt to each body part _before armor was taken into account_, but the actual damage values are _after armor_. From 869ad1972d7893355eea81108ee54ea712a01eba Mon Sep 17 00:00:00 2001 From: LinkIsGrim <69561145+LinkIsGrim@users.noreply.github.com> Date: Fri, 20 Dec 2024 19:45:31 -0300 Subject: [PATCH 5/6] early return in wound received and throw an error for invalid return --- .../functions/fnc_woundReceived.sqf | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/addons/medical_damage/functions/fnc_woundReceived.sqf b/addons/medical_damage/functions/fnc_woundReceived.sqf index bc4cb9aecb3..f5998253bf4 100644 --- a/addons/medical_damage/functions/fnc_woundReceived.sqf +++ b/addons/medical_damage/functions/fnc_woundReceived.sqf @@ -22,24 +22,26 @@ params ["_unit", "_allDamages", "_shooter", "_ammo"]; private _typeOfDamage = _ammo call FUNC(getTypeOfDamage); -if (_typeOfDamage in GVAR(damageTypeDetails)) then { - (GVAR(damageTypeDetails) get _typeOfDamage) params ["", "", "_woundHandlers"]; - - private _damageData = [_unit, _allDamages, _typeOfDamage, _ammo]; - - { - _x params ["_handlerName", "_handlerCode"]; - _damageData = _damageData call _handlerCode; - TRACE_2("Wound handler returned",_damageData,_handlerName); - - if ((count _damageData) == 3) then { - ERROR_1("Wound handler '%1' missing _ammo in return, readding. This will be deprecated in the future, check Medical Framework wiki.",_handlerName); - _damageData pushBack _ammo; - }; - - // If invalid return, exit - if (isNil "_damageData" || {!(_damageData isEqualType [])} || {(count _damageData) < 4}) exitWith { - TRACE_2("Return invalid, skipping wound handling",_damageData,_handlerName); - }; - } forEach _woundHandlers; -}; +if !(_typeOfDamage in GVAR(damageTypeDetails)) exitWith {}; + +(GVAR(damageTypeDetails) get _typeOfDamage) params ["", "", "_woundHandlers"]; + +private _damageData = [_unit, _allDamages, _typeOfDamage, _ammo]; +private _originalCount = count _damageData; + +{ + _x params ["_handlerName", "_handlerCode"]; + _damageData = _damageData call _handlerCode; + TRACE_2("Wound handler returned",_damageData,_handlerName); + + if ((count _damageData) == (_originalCount - 1)) then { + ERROR_1("Wound handler '%1' missing latest param in return, readding. This will be deprecated in the future, check Medical Framework wiki.",_handlerName); + _damageData pushBack _ammo; + }; + + // If invalid return, log an error and exit + if (isNil "_damageData" || {!(_damageData isEqualType [])} || {(count _damageData) < _originalCount}) then { + ERROR_2("Return for handler '%1' invalid - '%2', skipping wound handling",_damageData,_handlerName); + break + }; +} forEach _woundHandlers; From 825179599343e021a0a55eb5109b642c8f437973 Mon Sep 17 00:00:00 2001 From: LinkIsGrim <69561145+LinkIsGrim@users.noreply.github.com> Date: Fri, 20 Dec 2024 19:46:12 -0300 Subject: [PATCH 6/6] refactor getTypeOfDamage --- .../functions/fnc_getTypeOfDamage.sqf | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/addons/medical_damage/functions/fnc_getTypeOfDamage.sqf b/addons/medical_damage/functions/fnc_getTypeOfDamage.sqf index 80542359f6a..e2032b99a75 100644 --- a/addons/medical_damage/functions/fnc_getTypeOfDamage.sqf +++ b/addons/medical_damage/functions/fnc_getTypeOfDamage.sqf @@ -10,31 +10,29 @@ * Type of damage * * Example: - * ["bullet"] call ace_medical_damage_fnc_getTypeOfDamage + * "bullet" call ace_medical_damage_fnc_getTypeOfDamage * * Public: No */ params ["_typeOfProjectile"]; -private _damageType = GVAR(damageTypeCache) get _typeOfProjectile; +GVAR(damageTypeCache) getOrDefaultCall [_typeOfProjectile, { + private _projectileConfig = configFile >> "CfgAmmo" >> _typeOfProjectile >> "ACE_damageType"; -if (isNil "_damageType") then { - if (isText (configFile >> "CfgAmmo" >> _typeOfProjectile >> "ACE_damageType")) then { - _damageType = getText (configFile >> "CfgAmmo" >> _typeOfProjectile >> "ACE_damageType"); - } else { - WARNING_1("Ammo type [%1] has no ACE_damageType",_typeOfProjectile); - _damageType = "unknown"; - }; + switch (false) do { + case (isText _projectileConfig): { // no property or wrong type + WARNING_1("Ammo type [%1] has no ACE_damageType",_typeOfProjectile); + "unknown" // return + }; - // config may define an invalid damage type - if !(_damageType in GVAR(damageTypeDetails)) then { - WARNING_2("Damage type [%1] for ammo [%2] not found",_damageType,_typeOfProjectile); - _damageType = "unknown"; + private _damageType = getText _projectileConfig; + case (_damageType in GVAR(damageTypeDetails)): { // config may define an invalid damage type + WARNING_2("Damage type [%1] for ammo [%2] not found",_damageType,_typeOfProjectile); + "unknown" // return + }; + default { + _damageType // return + }; }; - - TRACE_2("getTypeOfDamage caching",_typeOfProjectile,_damageType); - GVAR(damageTypeCache) set [_typeOfProjectile, _damageType]; -}; - -_damageType // return +}, true]