Skip to content

Commit

Permalink
Medical Engine - Improve damage calculation for explosive-resistant a…
Browse files Browse the repository at this point in the history
…rmor (#9216)

* scale armor damage using passthrough

* add - to comment

Co-authored-by: Jouni Järvinen <[email protected]>

* improve condition

Co-authored-by: Jouni Järvinen <[email protected]>

* remove extra brackets

Co-authored-by: Jouni Järvinen <[email protected]>

* remove extra brackets

* fix damage sorting

* whitespace

* comment

* fix function header

* fix infinite armor when no item equipped

* cleanup

* more cleanup

* name

* don't scale structural damage

* add setting

* fix key name

* add cap to passThrough

* fix script error in setting

---------

Co-authored-by: GhostIsSpooky <[email protected]>
Co-authored-by: Jouni Järvinen <[email protected]>
  • Loading branch information
3 people authored Sep 23, 2023
1 parent ec96cdf commit da60a1b
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 20 deletions.
15 changes: 9 additions & 6 deletions addons/medical_engine/functions/fnc_getHitpointArmor.sqf
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#include "..\script_component.hpp"
/*
* Author: Pterolatypus
* Author: Pterolatypus, LinkIsGrim
* Checks a unit's equipment to calculate the total armor on a hitpoint.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Hitpoint <STRING>
*
* Return Value:
* Total armor for the given hitpoint <NUMBER>
* Total armor and scaled armor for the given hitpoint <ARRAY of NUMBER>
*
* Example:
* [player, "HitChest"] call ace_medical_engine_fnc_getHitpointArmor
Expand All @@ -32,16 +32,19 @@ private _gear = [

private _rags = _gear joinString "$";
private _var = format [QGVAR(armorCache$%1), _hitpoint];
_unit getVariable [_var, [""]] params ["_prevRags", "_armor"];
_unit getVariable [_var, ["", 0, 0]] params ["_prevRags", "_armor", "_armorScaled"];

if (_rags != _prevRags) then {
_armor = 0;
_armorScaled = 0;

{
_armor = _armor + ([_x, _hitpoint] call FUNC(getItemArmor));
([_x, _hitpoint] call FUNC(getItemArmor)) params ["_itemArmor", "_itemArmorScaled"];
_armor = _armor + _itemArmor;
_armorScaled = _armorScaled + _itemArmorScaled;
} forEach _gear;

_unit setVariable [_var, [_rags, _armor]];
_unit setVariable [_var, [_rags, _armor, _armorScaled]];
};

_armor // return
[_armor, _armorScaled] // return
34 changes: 23 additions & 11 deletions addons/medical_engine/functions/fnc_getItemArmor.sqf
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#include "..\script_component.hpp"
/*
* Author: Pterolatypus
* Returns the armor value the given item provides to a particular hitpoint, either from a cache or by reading the item config.
* Author: Pterolatypus, LinkIsGrim
* Returns the regular and scaled armor values the given item provides to a particular hitpoint, either from a cache or by reading the item config.
*
* Arguments:
* 0: Item Class <STRING>
* 1: Hitpoint <STRING>
*
* Return Value:
* Item armor for the given hitpoint <NUMBER>
* Regular and scaled item armor for the given hitpoint <ARRAY of NUMBER>
*
* Example:
* ["V_PlateCarrier_rgr", "HitChest"] call ace_medical_engine_fnc_getItemArmor
Expand All @@ -19,13 +19,16 @@
params ["_item", "_hitpoint"];

private _key = format ["%1$%2", _item, _hitpoint];
private _armor = GVAR(armorCache) get _key;
private _return = GVAR(armorCache) get _key;

if (isNil "_armor") then {
if (isNil "_return") then {
private _armor = 0;
private _armorScaled = 0;
private _passThrough = 1;
TRACE_2("Cache miss",_item,_hitpoint);
if ("" in [_item, _hitpoint]) exitWith {
_armor = 0;
GVAR(armorCache) set [_key, _armor];
_return = [_armor, _armorScaled];
GVAR(armorCache) set [_key, _return];
};

private _itemInfo = configFile >> "CfgWeapons" >> _item >> "ItemInfo";
Expand All @@ -38,15 +41,24 @@ if (isNil "_armor") then {
} else {
private _entry = _unitCfg >> "HitPoints" >> _hitpoint;
_armor = getNumber (_unitCfg >> "armor") * (1 max getNumber (_entry >> "armor"));
_passThrough = 0.1 max getNumber (_entry >> "passThrough") min 1; // prevent dividing by 0
};
} else {
private _condition = format ["getText (_x >> 'hitpointName') == '%1'", _hitpoint];
private _entry = configProperties [_itemInfo >> "HitpointsProtectionInfo", _condition] param [0, configNull];

_armor = getNumber (_entry >> "armor");
if (!isNull _entry) then {
_armor = getNumber (_entry >> "armor");
_passThrough = 0.1 max getNumber (_entry >> "passThrough") min 1;
};
};

GVAR(armorCache) set [_key, _armor];
// Scale armor using passthrough to fix explosive-resistant armor (#9063)
// Skip scaling for items that don't cover the hitpoint to prevent infinite armor
if (_armor isNotEqualTo 0) then {
_armorScaled = (log (_armor / _passThrough)) * 10;
};
_return = [_armor, _armorScaled];
GVAR(armorCache) set [_key, _return];
};

_armor // return
_return // return
14 changes: 11 additions & 3 deletions addons/medical_engine/functions/fnc_handleDamage.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,16 @@ if (_hitPoint isEqualTo "") then {
if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) exitWith {_oldDamage};

private _newDamage = _damage - _oldDamage;
// Get armor value of hitpoint and calculate damage before armor
private _armor = [_unit, _hitpoint] call FUNC(getHitpointArmor);
// Get scaled armor value of hitpoint and calculate damage before armor
// We scale using passThrough to handle explosive-resistant armor properly (#9063)
// We need realDamage to determine which limb was hit correctly
[_unit, _hitpoint] call FUNC(getHitpointArmor) params ["_armor", "_armorScaled"];
private _realDamage = _newDamage * _armor;
if (_hitPoint isNotEqualTo "#structural") then {
private _armorCoef = _armor/_armorScaled;
private _damageCoef = linearConversion [0, 1, GVAR(damagePassThroughEffect), 1, _armorCoef];
_newDamage = _newDamage * _damageCoef;
};
TRACE_4("Received hit",_hitpoint,_ammo,_newDamage,_realDamage);

// Drowning doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs
Expand Down Expand Up @@ -101,8 +108,9 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
private _damageLeftLeg = _unit getVariable [QGVAR($HitLeftLeg), [0,0]];
private _damageRightLeg = _unit getVariable [QGVAR($HitRightLeg), [0,0]];

// Find hit point that received the maxium damage
// Find hit point that received the maximum damage
// Priority used for sorting if incoming damage is equal
// _realDamage, priority, _newDamage, body part name
private _allDamages = [
[_damageHead select 0, PRIORITY_HEAD, _damageHead select 1, "Head"],
[_damageBody select 0, PRIORITY_BODY, _damageBody select 1, "Body"],
Expand Down
9 changes: 9 additions & 0 deletions addons/medical_engine/initSettings.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@
true,
true
] call CBA_fnc_addSetting;

[
QGVAR(damagePassThroughEffect),
"SLIDER",
[LSTRING(damagePassThroughEffect_displayName), LSTRING(damagePassThroughEffect_description)],
ELSTRING(medical,Category),
[0, 1, 1, 2, true],
true
] call CBA_fnc_addSetting;
6 changes: 6 additions & 0 deletions addons/medical_engine/stringtable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,11 @@
<Chinesesimp>控制乘员是否受到车辆碰撞的伤害。</Chinesesimp>
<Korean>차량 충돌로 인해 탑승인원들이 피해를 받을 지 결정합니다.</Korean>
</Key>
<Key ID="STR_ACE_Medical_Engine_damagePassThroughEffect_displayName">
<English>Armor PassThrough Effect</English>
</Key>
<Key ID="STR_ACE_Medical_Engine_damagePassThroughEffect_description">
<English>Controls effect of armor 'passThrough' on final damage. Makes high armor values, like ones used in GL rigs, less effective.\nUse 0% for pre 3.16.0 armor behavior.\nOnly touch this if you know what you're doing!</English>
</Key>
</Package>
</Project>

0 comments on commit da60a1b

Please sign in to comment.