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] 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 c31cf5b3789..f5998253bf4 100644 --- a/addons/medical_damage/functions/fnc_woundReceived.sqf +++ b/addons/medical_damage/functions/fnc_woundReceived.sqf @@ -22,18 +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"]; +if !(_typeOfDamage in GVAR(damageTypeDetails)) exitWith {}; - private _damageData = [_unit, _allDamages, _typeOfDamage]; +(GVAR(damageTypeDetails) get _typeOfDamage) params ["", "", "_woundHandlers"]; - { - _damageData = _damageData call _x; - TRACE_1("Wound handler returned",_damageData); +private _damageData = [_unit, _allDamages, _typeOfDamage, _ammo]; +private _originalCount = count _damageData; - // If invalid return, exit - if (isNil "_damageData" || {!(_damageData isEqualType [])} || {(count _damageData) < 3}) exitWith { - TRACE_1("Return invalid, skipping wound handling",_damageData); - }; - } forEach _woundHandlers; -}; +{ + _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; diff --git a/docs/wiki/framework/medical-framework.md b/docs/wiki/framework/medical-framework.md index c0e94b5f9ee..c3ec6d31de4 100644 --- a/docs/wiki/framework/medical-framework.md +++ b/docs/wiki/framework/medical-framework.md @@ -224,18 +224,24 @@ 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 | 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` 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_. +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"] 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"` | 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).