Skip to content

Commit

Permalink
Medical Damage - Pass ammo to wound handlers (#10573)
Browse files Browse the repository at this point in the history
Co-authored-by: johnb432 <[email protected]>
  • Loading branch information
LinkIsGrim and johnb432 authored Feb 8, 2025
1 parent 628683a commit a6befd7
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 35 deletions.
36 changes: 17 additions & 19 deletions addons/medical_damage/functions/fnc_getTypeOfDamage.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,29 @@
* Type of damage <STRING>
*
* 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]
7 changes: 4 additions & 3 deletions addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ private _entries = [];

{
private _entryResult = getText _x;
private _entryName = configName _x;

if (_entryResult != "") then {
if (ADDON) then {
Expand All @@ -30,15 +31,15 @@ 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 {
// Runs in preInit
// In case function doesn't exist yet, wrap in extra layer
_entries pushBack (compile format ["call %1", _entryResult]);
_entries pushBack [_entryName, (compile format ["call %1", _entryResult])];
};
};
} forEach configProperties [_config, "isText _x", false];
Expand Down
32 changes: 20 additions & 12 deletions addons/medical_damage/functions/fnc_woundReceived.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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;
8 changes: 7 additions & 1 deletion docs/wiki/framework/medical-framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down

0 comments on commit a6befd7

Please sign in to comment.