mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
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:
parent
ec96cdf12c
commit
da60a1b39d
@ -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
|
||||
|
@ -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];
|
||||
|
||||
_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
|
||||
|
@ -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"],
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user