diff --git a/addons/medical_engine/functions/fnc_getHitpointArmor.sqf b/addons/medical_engine/functions/fnc_getHitpointArmor.sqf index 8214ba0079..5f51cc2cad 100644 --- a/addons/medical_engine/functions/fnc_getHitpointArmor.sqf +++ b/addons/medical_engine/functions/fnc_getHitpointArmor.sqf @@ -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 * * Return Value: - * Total armor for the given hitpoint + * Total armor and scaled armor for the given hitpoint * * 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 diff --git a/addons/medical_engine/functions/fnc_getItemArmor.sqf b/addons/medical_engine/functions/fnc_getItemArmor.sqf index fa66762a06..c201cbee42 100644 --- a/addons/medical_engine/functions/fnc_getItemArmor.sqf +++ b/addons/medical_engine/functions/fnc_getItemArmor.sqf @@ -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 * 1: Hitpoint * * Return Value: - * Item armor for the given hitpoint + * Regular and scaled item armor for the given hitpoint * * 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]; - - _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 diff --git a/addons/medical_engine/functions/fnc_handleDamage.sqf b/addons/medical_engine/functions/fnc_handleDamage.sqf index 3c042f5532..b38b3426cf 100644 --- a/addons/medical_engine/functions/fnc_handleDamage.sqf +++ b/addons/medical_engine/functions/fnc_handleDamage.sqf @@ -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"], diff --git a/addons/medical_engine/initSettings.sqf b/addons/medical_engine/initSettings.sqf index 9fe80afcb0..062e2a0822 100644 --- a/addons/medical_engine/initSettings.sqf +++ b/addons/medical_engine/initSettings.sqf @@ -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; diff --git a/addons/medical_engine/stringtable.xml b/addons/medical_engine/stringtable.xml index 81e2ae8450..aa6c3556c9 100644 --- a/addons/medical_engine/stringtable.xml +++ b/addons/medical_engine/stringtable.xml @@ -23,5 +23,11 @@ 控制乘员是否受到车辆碰撞的伤害。 차량 충돌로 인해 탑승인원들이 피해를 받을 지 결정합니다. + + Armor PassThrough Effect + + + 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! +