-
Notifications
You must be signed in to change notification settings - Fork 738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Medical Damage - Add alternate armor penetration #9217
base: master
Are you sure you want to change the base?
Changes from all commits
75f1cec
386eda6
510e6aa
f290e28
9ad380d
0c82347
27ef26f
0098ecb
816c5e7
c232f7f
92d636d
33c3e9e
628c0c8
7ad1d05
6991e8c
2d36e66
56ef3a3
cdf6520
1d1edbb
73119fd
8ef0af1
6035088
434d5d5
dc39995
34a4b24
2b32870
aafef61
260e1c3
e19bed4
2ed1058
7b437b2
82f1e41
60f0d77
6547fa0
0567367
b77eca6
255ec5d
6f706fe
e4e9345
ed9d6d6
46e21e9
bb53055
d27f6f7
97cdaf9
383dda1
f1d5b80
785502b
300d5fe
d227414
7e1821a
540e479
84934a8
6a449ca
5c09916
5eba4c9
d259ad1
d6cc11b
a7eca55
e29afd9
318f4b1
ef8d10d
26b3759
54c9cb9
18dc75d
2009431
ef0cdf7
3fe5924
d566238
261c0a6
7317266
a503f54
833578e
b9055e8
298237b
2f45079
a833865
505f524
b510e95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#include "..\script_component.hpp" | ||
/* | ||
* Author: LinkIsGrim | ||
* Returns base damage value, penetration factor, and expected muzzle velocity of a given round, either from a cache or by reading the ammo config. | ||
* | ||
* Arguments: | ||
* 0: Ammo <STRING> | ||
* | ||
* Return Value: | ||
* Base damage value, penetration factor, muzzle velocity <ARRAY of NUMBER> | ||
* | ||
* Example: | ||
* "B_556x45_Ball" call ace_medical_engine_fnc_getAmmoData | ||
* | ||
* Public: No | ||
*/ | ||
|
||
// Baseline penetrability used for armor penetration calculation, see (https://community.bistudio.com/wiki/CfgAmmo_Config_Reference#caliber) | ||
#define ARMOR_PENETRABILITY 0.015 | ||
|
||
params ["_ammo"]; | ||
|
||
GVAR(ammoCache) getOrDefaultCall [toLowerANSI _ammo, { | ||
TRACE_1("Cache miss",_ammo); | ||
private _ammoConfig = configFile >> "CfgAmmo" >> _ammo; | ||
|
||
if (isNull _ammoConfig) then { | ||
[0, 0, 0] // return | ||
} else { | ||
private _hit = getNumber (_ammoConfig >> "hit"); | ||
private _caliber = (getNumber (_ammoConfig >> "caliber")); | ||
private _typicalSpeed = getNumber (_ammoConfig >> "typicalSpeed"); | ||
private _penFactor = _caliber * ARMOR_PENETRABILITY; | ||
[_hit, _penFactor, _typicalSpeed] // return | ||
}; | ||
}, true] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#include "..\script_component.hpp" | ||
/* | ||
* Author: LinkIsGrim | ||
* Custom wounds handler for armor penetration. Calculates damage based on round material penetration and unit armor | ||
* | ||
* Arguments: | ||
* 0: Unit that was hit <OBJECT> | ||
* 1: Damage done to each body part <ARRAY> | ||
* 0: Engine damage <NUMBER> | ||
* 1: Body part <STRING> | ||
* 2: Real damage <NUMBER> | ||
* 2: Type of the damage done <STRING> | ||
* 3: Ammo <STRING> | ||
* | ||
* Return Value: | ||
* None | ||
* | ||
* Example: | ||
* [player, [[0.5, "Body", 1]], "bullet"] call ace_medical_damage_fnc_woundsHandlerArmorPenetration | ||
* | ||
* Public: No | ||
*/ | ||
|
||
// This gets close to vanilla values on FMJ ammo | ||
#define DAMAGE_SCALING_FACTOR 10 | ||
|
||
params ["_unit", "_allDamages", "_typeOfDamage", "_ammo"]; | ||
TRACE_4("woundsHandlerArmorPenetration",_unit,_allDamages,_typeOfDamage,_ammo); | ||
|
||
if (!EGVAR(medical,alternateArmorPenetration)) exitWith {_this}; | ||
|
||
private _damageData = (_allDamages select 0); // selection specific | ||
_damageData params ["_engineDamage", "_bodyPart", "_realDamage"]; | ||
|
||
private _ammoData = _ammo call FUNC(getAmmoData); | ||
|
||
// See (https://community.bistudio.com/wiki/CfgAmmo_Config_Reference#caliber), | ||
// _penFactor is ammo "caliber" * RHA penetrability, armor plates according to BI are just made of RHAe material | ||
_ammoData params ["_hit", "_penFactor", "_typicalSpeed"]; | ||
|
||
// Skip bad ammo | ||
if (_hit <= 0) exitWith {_this}; | ||
|
||
private _armorLevelStep = [2, 4] select (_bodyPart == "body"); | ||
private _armor = (_realDamage/_engineDamage) - 2; // remove base armor | ||
|
||
// There's no need to calculate penetration if there is no armor to begin with, base damage handling is good enough in this case | ||
if (_armor <= _armorLevelStep) exitWith { | ||
TRACE_3("skipping no armor",_armor,_bodyPart,_armorLevelStep); | ||
_this // return | ||
}; | ||
|
||
// Cap at Armor Level V | ||
// Jumping from no armor to armor level 1 is 2 steps | ||
private _armorLevel = 0 max (round ((_armor - (_armorLevelStep * 2)) / _armorLevelStep)) min 4; | ||
TRACE_3("gotArmorLevel",_armorLevel,_armor,_armorLevelStep); | ||
|
||
// Armor RHA equivalent, non-linear, ref \a3\Data_F\Penetration\armour_plate/thin/medium/heavy.bisurf | ||
// Divided by 2 to keep inline with vanilla caliber values | ||
private _armorThickness = [ | ||
6, | ||
15, | ||
21, | ||
40, | ||
55 | ||
] select _armorLevel; | ||
TRACE_1("gotArmorThickness",_armorThickness); | ||
|
||
// Impact damage is hit * (impactSpeed / typicalSpeed): https://community.bistudio.com/wiki/CfgAmmo_Config_Reference#typicalSpeed | ||
// Impact damage is already lowered by engine based on hit angle, so speed and therefore penetration are also naturally lowered | ||
// Assume typicalSpeed < 1 means no damage dropoff | ||
private _impactSpeed = (_realDamage/_hit) * (_typicalSpeed max 1); | ||
|
||
private _penDepth = _penFactor * _impactSpeed; | ||
|
||
// Max damage is the config value, go down from there based on armor penetration | ||
private _finalDamage = (_hit * ((_penDepth/_armorThickness) min 1)) / DAMAGE_SCALING_FACTOR; | ||
_damageData set [0, _finalDamage]; | ||
|
||
TRACE_3("Armor penetration handled, passing damage",_finalDamage,_damageData,_allDamages); | ||
|
||
_this // return |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,14 @@ | ||
#include "..\script_component.hpp" | ||
/* | ||
* 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. | ||
* Returns the armor value provided by an item to a hitpoint. Armor may be scaled back if over the cap. | ||
* | ||
* Arguments: | ||
* 0: Item Class <STRING> | ||
* 1: Hitpoint <STRING> | ||
* | ||
* Return Value: | ||
* Regular and scaled item armor for the given hitpoint <ARRAY of NUMBER> | ||
* Item armor for the given hitpoint, may be scaled. <NUMBER> | ||
* | ||
* Example: | ||
* ["V_PlateCarrier_rgr", "HitChest"] call ace_medical_engine_fnc_getItemArmor | ||
|
@@ -18,53 +18,42 @@ | |
|
||
params ["_item", "_hitpoint"]; | ||
|
||
private _key = format ["%1$%2", _item, _hitpoint]; | ||
private _return = GVAR(armorCache) get _key; | ||
|
||
if (isNil "_return") then { | ||
GVAR(armorCache) getOrDefaultCall [_this joinString "$", { | ||
TRACE_2("Cache miss",_item,_hitpoint); | ||
private _armor = 0; | ||
private _armorScaled = 0; | ||
private _passThrough = 1; | ||
TRACE_2("Cache miss",_item,_hitpoint); | ||
if ("" in [_item, _hitpoint]) exitWith { | ||
_return = [_armor, _armorScaled]; | ||
GVAR(armorCache) set [_key, _return]; | ||
}; | ||
|
||
private _itemInfo = configFile >> "CfgWeapons" >> _item >> "ItemInfo"; | ||
private _itemType = getNumber (_itemInfo >> "type"); | ||
private _passThroughEffect = [1, 0.6] select (_itemType == TYPE_VEST); | ||
if !("" in [_item, _hitpoint]) then { | ||
private _itemInfo = configFile >> "CfgWeapons" >> _item >> "ItemInfo"; | ||
private _itemType = getNumber (_itemInfo >> "type"); | ||
|
||
if (_itemType == TYPE_UNIFORM) then { | ||
private _unitCfg = configFile >> "CfgVehicles" >> getText (_itemInfo >> "uniformClass"); | ||
if (_hitpoint == "#structural") then { | ||
// TODO: I'm not sure if this should be multiplied by the base armor value or not | ||
_armor = getNumber (_unitCfg >> "armorStructural"); | ||
if (_itemType == TYPE_UNIFORM) then { | ||
private _unitCfg = configFile >> "CfgVehicles" >> getText (_itemInfo >> "uniformClass"); | ||
if (_hitpoint == "#structural") then { | ||
// TODO: I'm not sure if this should be multiplied by the base armor value or not | ||
_armor = getNumber (_unitCfg >> "armorStructural"); | ||
} 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 _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 | ||
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; | ||
}; | ||
}; | ||
} 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; | ||
}; | ||
}; | ||
|
||
// Scale armor using passthrough to fix explosive-resistant armor (#9063) | ||
// Skip scaling for uniforms and items that don't cover the hitpoint to prevent infinite armor | ||
if (_armor > 0) then { | ||
if (_itemType == TYPE_UNIFORM) then { | ||
_armorScaled = _armor; | ||
} else { | ||
_armorScaled = (log (_armor / (_passThrough ^ _passThroughEffect))) * 10; | ||
// Scale armor using passthrough to fix explosive-resistant & stupid armor (#9063) | ||
// Skip scaling for uniforms and items that don't cover the hitpoint to prevent infinite armor | ||
private _armorLevelStep = [4, 2] select (_itemType == TYPE_HEADGEAR); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this change the balance compared to before? I haven't looked at it in detail, so forgive me if I'm wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Changed back to vanilla levels except for stupid armor which gets capped. Works well enough IMO. |
||
if (_itemType != TYPE_UNIFORM && (_armor > _armorLevelStep * 6)) then { | ||
LinkIsGrim marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private _passThroughEffect = [1, 0.6] select (_itemType == TYPE_VEST); | ||
_armor = (log (_armor / (_passThrough ^ _passThroughEffect))) * 10; | ||
}; | ||
}; | ||
_return = [_armor, _armorScaled]; | ||
GVAR(armorCache) set [_key, _return]; | ||
}; | ||
|
||
_return // return | ||
_armor // return | ||
}, true] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be a setting? /shrug.