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" #include "..\script_component.hpp"
/* /*
* Author: Pterolatypus * Author: Pterolatypus, LinkIsGrim
* Checks a unit's equipment to calculate the total armor on a hitpoint. * Checks a unit's equipment to calculate the total armor on a hitpoint.
* *
* Arguments: * Arguments:
@ -8,7 +8,7 @@
* 1: Hitpoint <STRING> * 1: Hitpoint <STRING>
* *
* Return Value: * Return Value:
* Total armor for the given hitpoint <NUMBER> * Total armor and scaled armor for the given hitpoint <ARRAY of NUMBER>
* *
* Example: * Example:
* [player, "HitChest"] call ace_medical_engine_fnc_getHitpointArmor * [player, "HitChest"] call ace_medical_engine_fnc_getHitpointArmor
@ -32,16 +32,19 @@ private _gear = [
private _rags = _gear joinString "$"; private _rags = _gear joinString "$";
private _var = format [QGVAR(armorCache$%1), _hitpoint]; 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 { if (_rags != _prevRags) then {
_armor = 0; _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; } 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" #include "..\script_component.hpp"
/* /*
* Author: Pterolatypus * Author: Pterolatypus, LinkIsGrim
* Returns the armor value the given item provides to a particular hitpoint, either from a cache or by reading the item config. * 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: * Arguments:
* 0: Item Class <STRING> * 0: Item Class <STRING>
* 1: Hitpoint <STRING> * 1: Hitpoint <STRING>
* *
* Return Value: * Return Value:
* Item armor for the given hitpoint <NUMBER> * Regular and scaled item armor for the given hitpoint <ARRAY of NUMBER>
* *
* Example: * Example:
* ["V_PlateCarrier_rgr", "HitChest"] call ace_medical_engine_fnc_getItemArmor * ["V_PlateCarrier_rgr", "HitChest"] call ace_medical_engine_fnc_getItemArmor
@ -19,13 +19,16 @@
params ["_item", "_hitpoint"]; params ["_item", "_hitpoint"];
private _key = format ["%1$%2", _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); TRACE_2("Cache miss",_item,_hitpoint);
if ("" in [_item, _hitpoint]) exitWith { if ("" in [_item, _hitpoint]) exitWith {
_armor = 0; _return = [_armor, _armorScaled];
GVAR(armorCache) set [_key, _armor]; GVAR(armorCache) set [_key, _return];
}; };
private _itemInfo = configFile >> "CfgWeapons" >> _item >> "ItemInfo"; private _itemInfo = configFile >> "CfgWeapons" >> _item >> "ItemInfo";
@ -38,15 +41,24 @@ if (isNil "_armor") then {
} else { } else {
private _entry = _unitCfg >> "HitPoints" >> _hitpoint; private _entry = _unitCfg >> "HitPoints" >> _hitpoint;
_armor = getNumber (_unitCfg >> "armor") * (1 max getNumber (_entry >> "armor")); _armor = getNumber (_unitCfg >> "armor") * (1 max getNumber (_entry >> "armor"));
_passThrough = 0.1 max getNumber (_entry >> "passThrough") min 1; // prevent dividing by 0
}; };
} else { } else {
private _condition = format ["getText (_x >> 'hitpointName') == '%1'", _hitpoint]; private _condition = format ["getText (_x >> 'hitpointName') == '%1'", _hitpoint];
private _entry = configProperties [_itemInfo >> "HitpointsProtectionInfo", _condition] param [0, configNull]; private _entry = configProperties [_itemInfo >> "HitpointsProtectionInfo", _condition] param [0, configNull];
if (!isNull _entry) then {
_armor = getNumber (_entry >> "armor"); _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}; if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) exitWith {_oldDamage};
private _newDamage = _damage - _oldDamage; private _newDamage = _damage - _oldDamage;
// Get armor value of hitpoint and calculate damage before armor // Get scaled armor value of hitpoint and calculate damage before armor
private _armor = [_unit, _hitpoint] call FUNC(getHitpointArmor); // 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; 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); TRACE_4("Received hit",_hitpoint,_ammo,_newDamage,_realDamage);
// Drowning doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs // 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 _damageLeftLeg = _unit getVariable [QGVAR($HitLeftLeg), [0,0]];
private _damageRightLeg = _unit getVariable [QGVAR($HitRightLeg), [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 // Priority used for sorting if incoming damage is equal
// _realDamage, priority, _newDamage, body part name
private _allDamages = [ private _allDamages = [
[_damageHead select 0, PRIORITY_HEAD, _damageHead select 1, "Head"], [_damageHead select 0, PRIORITY_HEAD, _damageHead select 1, "Head"],
[_damageBody select 0, PRIORITY_BODY, _damageBody select 1, "Body"], [_damageBody select 0, PRIORITY_BODY, _damageBody select 1, "Body"],

View File

@ -6,3 +6,12 @@
true, true,
true true
] call CBA_fnc_addSetting; ] 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> <Chinesesimp>控制乘员是否受到车辆碰撞的伤害。</Chinesesimp>
<Korean>차량 충돌로 인해 탑승인원들이 피해를 받을 지 결정합니다.</Korean> <Korean>차량 충돌로 인해 탑승인원들이 피해를 받을 지 결정합니다.</Korean>
</Key> </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> </Package>
</Project> </Project>