Skip to content

Commit

Permalink
Merge pull request #1 from johnb432/dev
Browse files Browse the repository at this point in the history
1.0.3.0
  • Loading branch information
johnb432 authored Sep 28, 2024
2 parents 2101086 + 4e332ec commit 475ac68
Show file tree
Hide file tree
Showing 12 changed files with 377 additions and 96 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Changelog for Armor Modifier - ACE 28.9.2024

1.0.3.0
- Updated to work with ACE 3.18.0. Remains backwards compatible with ACE 3.17.1.

# Changelog for Armor Modifier - ACE 26.3.2024

1.0.2.0
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ _unit setVariable ["armor_modifier_ace_main_hitPointMultiplier_chest", [armorMul
_unit setVariable ["armor_modifier_ace_main_hitPointMultiplier_limb", [armorMultiplier, minimumArmor, maximumArmor], true];
```

2 is usually the minimum hitpoint armor a unit has without any equipment on.

<h2>Examples</h2>

* If **Player hitpoint damage reduction - chest** is set to `[10, 0, 0]`, it means that you take a 10th of the damage to the chest.
Expand Down
2 changes: 2 additions & 0 deletions README_steam.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ _unit setVariable ["armor_modifier_ace_main_hitPointMultiplier_chest", [armorMul
_unit setVariable ["armor_modifier_ace_main_hitPointMultiplier_limb", [armorMultiplier, minimumArmor, maximumArmor], true];
[/code]

2 is usually the minimum hitpoint armor a unit has without any equipment on.

[h2]Examples[/h2]
[list]
[*] If [b]Player hitpoint damage reduction - chest[/b] is set to '[10, 0, 0]', it means that you take a 10th of the damage to the chest.
Expand Down
12 changes: 12 additions & 0 deletions addons/main/CfgVersioning.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CfgSettings {
class CBA {
class Versioning {
class PREFIX {
class Dependencies {
ACE[] = {"ace_main", {3, 18, 0}, "true"};
CBA[] = {"cba_main", {3, 16, 0}, "true"};
};
};
};
};
};
6 changes: 5 additions & 1 deletion addons/main/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
PREP(handleDamage);
if (getNumber (configFile >> "CfgPatches" >> "ace_main" >> "version") >= 3.18) then {
PREP(handleDamage,handleDamage);
} else {
PREP(handleDamage,handleDamageOld);
};
6 changes: 0 additions & 6 deletions addons/main/addon.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
[rapify]
enabled = true

[binarize]
enabled = true

[asc]
enabled = true
3 changes: 3 additions & 0 deletions addons/main/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ class CfgPatches {
};

#include "CfgEventHandlers.hpp"

// Don't force ACE version until 3.18.0 has been out for a while
// #include "CfgVersioning.hpp"
162 changes: 81 additions & 81 deletions addons/main/functions/fnc_handleDamage.sqf
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#include "..\script_component.hpp"

/*
* Author: commy2, kymckay, modified by johnb43
* Original:
* HandleDamage EH where wound events are raised based on incoming damage.
* Be aware that for each source of damage, the EH can fire multiple times (once for each hitpoint).
* We store these incoming damages and compare them on our final hitpoint: "ace_hdbracket".
* Added:
* Handling of damage to allow armor modifcation.
* Handling of damage to allow armor modifcation. For ACE 3.18.0 and later.
*
* Arguments:
* Handle damage EH
Expand All @@ -19,13 +18,14 @@
*/

params ["_args", ["_ignoreAllowDamageACE", false]];
_args params ["_unit", "_selection", "_damage", "_shooter", "_ammo", "_hitPointIndex", "_instigator", "_hitpoint", "_directHit"];
_args params ["_unit", "_selection", "_damage", "_shooter", "_ammo", "_hitPointIndex", "_instigator", "_hitpoint", "_directHit", "_context"];

// HD sometimes triggers for remote units - ignore.
if !(local _unit) exitWith {nil};

// Get missing meta info
private _oldDamage = 0;
private _structuralDamage = _context == 0;

if (_hitPoint isEqualTo "") then {
_hitPoint = "#structural";
Expand All @@ -38,26 +38,30 @@ if (_hitPoint isEqualTo "") then {
if !(isDamageAllowed _unit && {_unit getVariable ["ace_medical_allowDamage", true] || _ignoreAllowDamageACE}) exitWith {_oldDamage};

private _newDamage = _damage - _oldDamage;

// _newDamage == 0 happens occasionally for vehiclehit events (see line 80 onwards), just exit early to save some frametime
// context 4 is engine "bleeding". For us, it's just a duplicate event for #structural which we can ignore without any issues
if (_context != 2 && {_context == 4 || _newDamage == 0}) exitWith {
TRACE_4("Skipping engine bleeding or zero damage",_ammo,_newDamage,_directHit,_context);
_oldDamage
};

// 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 ace_medical_engine_fnc_getHitpointArmor params ["_armor", "_armorScaled"];

private _realDamage = _newDamage * _armor;

// ACE <3.16.0 does not return "_armorScaled"
if (_hitPoint isNotEqualTo "#structural" && {!isNil "_armorScaled"}) then {
private _armorCoef = _armor / _armorScaled;
if (!_structuralDamage) then {
private _armorCoef = _armor/_armorScaled;
private _damageCoef = linearConversion [0, 1, ace_medical_engine_damagePassThroughEffect, 1, _armorCoef];
_newDamage = _newDamage * _damageCoef;
};

TRACE_4("Received hit",_hitpoint,_ammo,_newDamage,_realDamage);
TRACE_6("Received hit",_hitpoint,_ammo,_newDamage,_realDamage,_directHit,_context);

// Drowning doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs
// Damage occurs in consistent increments
if (
_hitPoint isEqualTo "#structural" &&
_structuralDamage &&
{getOxygenRemaining _unit <= 0.5} &&
{_damage isEqualTo (_oldDamage + 0.005)}
) exitWith {
Expand All @@ -67,14 +71,16 @@ if (
0
};

// Faster than (vehicle _unit), also handles dead units
private _vehicle = objectParent _unit;
private _inVehicle = !isNull _vehicle;
private _environmentDamage = _ammo == "";

// Crashing a vehicle doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs
// It does fire the EH multiple times, but this seems to scale with the intensity of the crash
private _vehicle = vehicle _unit;
if (
ace_medical_enableVehicleCrashes &&
{_hitPoint isEqualTo "#structural"} &&
{_ammo isEqualTo ""} &&
{!isNull _vehicle} &&
{_environmentDamage && _inVehicle && _structuralDamage} &&
{vectorMagnitude (velocity _vehicle) > 5}
// todo: no way to detect if stationary and another vehicle hits you
) exitWith {
Expand All @@ -85,19 +91,16 @@ if (
};

// Receiving explosive damage inside a vehicle doesn't trigger for each hitpoint
// This is the case for mines, explosives, artillery, and catastrophic vehicle explosions
// Triggers twice, but that doesn't matter as damage is low
// This is the case for mines, explosives, artillery, and catasthrophic vehicle explosions
if (
_hitPoint isEqualTo "#structural" &&
{!isNull _vehicle} &&
{_ammo isNotEqualTo ""} &&
(!_environmentDamage && _inVehicle && _structuralDamage) &&
{
private _ammoCfg = configFile >> "CfgAmmo" >> _ammo;
GET_NUMBER(_ammoCfg >> "explosive",0) > 0 ||
{GET_NUMBER(_ammoCfg >> "indirectHit",0) > 0}
}
) exitwith {
TRACE_6("Vehicle hit",_unit,_shooter,_instigator,_damage,_newDamage,_damages);
) exitWith {
TRACE_5("Vehicle hit",_unit,_shooter,_instigator,_damage,_newDamage);

_unit setVariable ["ace_medical_lastDamageSource", _shooter];
_unit setVariable ["ace_medical_lastInstigator", _instigator];
Expand All @@ -107,9 +110,59 @@ if (
0
};

// This hitpoint is set to trigger last, evaluate all the stored damage values
// to determine where wounds are applied
if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
// Get setting for particular unit
private _multiplierArray = switch (true) do {
case (_hitPoint in ["hitface", "hitneck", "hithead"]): {
_unit getVariable [QGVAR(hitPointMultiplier_head), [GVAR(hitPointMultiplier_ai_head), GVAR(hitPointMultiplier_player_head)] select (isPlayer _unit)]
};
case (_hitPoint in ["hitpelvis" ,"hitabdomen", "hitdiaphragm", "hitchest"]): {
_unit getVariable [QGVAR(hitPointMultiplier_chest), [GVAR(hitPointMultiplier_ai_chest), GVAR(hitPointMultiplier_player_chest)] select (isPlayer _unit)]
};
case (_hitPoint in ["hitleftarm", "hitrightarm", "hitleftleg", "hitrightleg"]): {
_unit getVariable [QGVAR(hitPointMultiplier_limb), [GVAR(hitPointMultiplier_ai_limb), GVAR(hitPointMultiplier_player_limb)] select (isPlayer _unit)]
};
default {
DEFAULT_SETTINGS
};
};

private _modifiedNewDamage = _newDamage;
private _modifiedRealDamage = _realDamage;

// If default settings, we don't need to change anything, so skip calculcations and let ace handle damage
if (_multiplierArray isNotEqualTo DEFAULT_SETTINGS) then {
_multiplierArray params ["_hitPointMultiplier", "_armorMin", "_armorMax"];

switch (true) do {
case (_armorMin >= 1 && {_armor < _armorMin}): {
// This will decrease damage
_modifiedNewDamage = _newDamage * _armor / _armorMin;
_modifiedRealDamage = _realDamage * _armor / _armorMin;

TRACE_6("Under min armor",_armor,_armorMin,_newDamage,_modifiedNewDamage,_realDamage,_modifiedRealDamage);
};
case (_armorMax >= 1 && {_armor > _armorMax}): {
// This will increase damage
_modifiedNewDamage = _newDamage * _armor / _armorMax;
_modifiedRealDamage = _realDamage * _armor / _armorMax;

TRACE_6("Over max armor",_armor,_armorMax,_newDamage,_modifiedNewDamage,_realDamage,_modifiedRealDamage);
};
};

_modifiedNewDamage = _modifiedNewDamage / _hitPointMultiplier;
_modifiedRealDamage = _modifiedRealDamage / _hitPointMultiplier;

TRACE_5("Hitpoint damage multiplied",_armor,_newDamage,_modifiedNewDamage,_realDamage,_modifiedRealDamage);
};

// Damages are stored for last iteration of the HandleDamage event (_context == 2)
_unit setVariable [format ["ace_medical_engine_$%1", _hitPoint], [_realDamage, _newDamage, _modifiedRealDamage, _modifiedNewDamage]];

// Ref https://community.bistudio.com/wiki/Arma_3:_Event_Handlers#HandleDamage
// Context 2 means this is the last iteration of HandleDamage, so figure out which hitpoint took the most real damage and send wound event
// Don't exit, as the last iteration can be one of the hitpoints that we need to keep _oldDamage for
if (_context == 2) then {
_unit setVariable ["ace_medical_lastDamageSource", _shooter];
_unit setVariable ["ace_medical_lastInstigator", _instigator];

Expand Down Expand Up @@ -161,7 +214,7 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith {

// Environmental damage sources all have empty ammo string
// No explicit source given, we infer from differences between them
if (_ammo isEqualTo "") then {
if (_environmentDamage) then {
// Any collision with terrain/vehicle/object has a shooter
// Check this first because burning can happen at any velocity
if !(isNull _shooter) then {
Expand Down Expand Up @@ -203,62 +256,9 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
"ace_medical_engine_$HitLeftArm","ace_medical_engine_$HitRightArm","ace_medical_engine_$HitLeftLeg","ace_medical_engine_$HitRightLeg",
"ace_medical_engine_$#structural"
];

0
};

// Get setting for particular unit
private _multiplierArray = switch (true) do {
case (_hitPoint in ["hitface", "hitneck", "hithead"]): {
_unit getVariable [QGVAR(hitPointMultiplier_head), [GVAR(hitPointMultiplier_ai_head), GVAR(hitPointMultiplier_player_head)] select (isPlayer _unit)]
};
case (_hitPoint in ["hitpelvis" ,"hitabdomen", "hitdiaphragm", "hitchest"]): {
_unit getVariable [QGVAR(hitPointMultiplier_chest), [GVAR(hitPointMultiplier_ai_chest), GVAR(hitPointMultiplier_player_chest)] select (isPlayer _unit)]
};
case (_hitPoint in ["hitleftarm", "hitrightarm", "hitleftleg", "hitrightleg"]): {
_unit getVariable [QGVAR(hitPointMultiplier_limb), [GVAR(hitPointMultiplier_ai_limb), GVAR(hitPointMultiplier_player_limb)] select (isPlayer _unit)]
};
default {
DEFAULT_SETTINGS
};
};

private _modifiedNewDamage = _newDamage;
private _modifiedRealDamage = _realDamage;

// If default settings, we don't need to change anything, so skip calculcations and let ace handle damage
if (_multiplierArray isNotEqualTo DEFAULT_SETTINGS) then {
_multiplierArray params ["_hitPointMultiplier", "_armorMin", "_armorMax"];

switch (true) do {
case (_armorMin >= 1 && {_armor < _armorMin}): {
// This will decrease damage
_modifiedNewDamage = _newDamage * _armor / _armorMin;
_modifiedRealDamage = _realDamage * _armor / _armorMin;

TRACE_6("Under min armor",_armor,_armorMin,_newDamage,_modifiedNewDamage,_realDamage,_modifiedRealDamage);
};
case (_armorMax >= 1 && {_armor > _armorMax}): {
// This will increase damage
_modifiedNewDamage = _newDamage * _armor / _armorMax;
_modifiedRealDamage = _realDamage * _armor / _armorMax;

TRACE_6("Over max armor",_armor,_armorMax,_newDamage,_modifiedNewDamage,_realDamage,_modifiedRealDamage);
};
};

_modifiedNewDamage = _modifiedNewDamage / _hitPointMultiplier;
_modifiedRealDamage = _modifiedRealDamage / _hitPointMultiplier;

TRACE_5("Hitpoint damage multiplied",_armor,_newDamage,_modifiedNewDamage,_realDamage,_modifiedRealDamage);
};

// Damages are stored for "ace_hdbracket" event triggered last
_unit setVariable [format ["ace_medical_engine_$%1", _hitPoint], [_realDamage, _newDamage, _modifiedRealDamage, _modifiedNewDamage]];

// Engine damage to these hitpoints controls blood visuals, limping, weapon sway
// Handled in fnc_damageBodyPart, persist here
if (_hitPoint in ["hithead", "hitbody", "hithands", "hitlegs"]) exitWith {_oldDamage};

// We store our own damage values so engine damage is unnecessary
0
// For all other hitpoints, we store our own damage values, so engine damage is unnecessary
[0, _oldDamage] select (_hitPoint in ["hithead", "hitbody", "hithands", "hitlegs"])
Loading

0 comments on commit 475ac68

Please sign in to comment.