Medical Engine - Improve damage calculation for explosive-resistant armor (#9216)

* scale armor damage using passthrough

* add - to comment

Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>

* improve condition

Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>

* remove extra brackets

Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>

* 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 <69561145+Salluci@users.noreply.github.com>
Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>
This commit is contained in:
Grim 2023-09-23 13:07:06 -04:00 committed by GitHub
parent ec96cdf12c
commit da60a1b39d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 20 deletions

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp"
/*
* Author: Pterolatypus
* Author: Pterolatypus, LinkIsGrim
* Checks a unit's equipment to calculate the total armor on a hitpoint.
*
* Arguments:
@ -8,7 +8,7 @@
* 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
@ -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

View File

@ -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
@ -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";
@ -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];
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

View File

@ -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
@ -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"],

View File

@ -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;

View File

@ -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>