From 056c35bec250fd202875d0a566a52560b32a83e0 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 9 Jul 2024 20:54:34 +0200 Subject: [PATCH 1/2] Getting ready for ACE 3.18.0 --- README.md | 2 + README_steam.md | 2 + addons/main/CfgVersioning.hpp | 12 ++ addons/main/config.cpp | 1 + addons/main/functions/fnc_handleDamage.sqf | 157 +++++++++++---------- 5 files changed, 96 insertions(+), 78 deletions(-) create mode 100644 addons/main/CfgVersioning.hpp diff --git a/README.md b/README.md index 05bbf79..a5cb0d5 100644 --- a/README.md +++ b/README.md @@ -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. +

Examples

* 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. diff --git a/README_steam.md b/README_steam.md index 24d0cf2..4c43664 100644 --- a/README_steam.md +++ b/README_steam.md @@ -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. diff --git a/addons/main/CfgVersioning.hpp b/addons/main/CfgVersioning.hpp new file mode 100644 index 0000000..b8af963 --- /dev/null +++ b/addons/main/CfgVersioning.hpp @@ -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"}; + }; + }; + }; + }; +}; diff --git a/addons/main/config.cpp b/addons/main/config.cpp index 4a17b1a..5a887c2 100644 --- a/addons/main/config.cpp +++ b/addons/main/config.cpp @@ -20,3 +20,4 @@ class CfgPatches { }; #include "CfgEventHandlers.hpp" +#include "CfgVersioning.hpp" diff --git a/addons/main/functions/fnc_handleDamage.sqf b/addons/main/functions/fnc_handleDamage.sqf index 737488e..5cb80bb 100644 --- a/addons/main/functions/fnc_handleDamage.sqf +++ b/addons/main/functions/fnc_handleDamage.sqf @@ -19,13 +19,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"; @@ -38,26 +39,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 { @@ -67,14 +72,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 { @@ -85,19 +92,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); + TRACE_5("Vehicle hit",_unit,_shooter,_instigator,_damage,_newDamage); _unit setVariable ["ace_medical_lastDamageSource", _shooter]; _unit setVariable ["ace_medical_lastInstigator", _instigator]; @@ -107,9 +111,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]; @@ -161,7 +215,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 { @@ -203,62 +257,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"]) From 4e332ec58759684d9d72dec2222a41fddfbcb254 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 28 Sep 2024 10:06:30 +0200 Subject: [PATCH 2/2] 1.0.3.0 --- CHANGELOG.md | 5 + addons/main/XEH_PREP.hpp | 6 +- addons/main/addon.toml | 6 - addons/main/config.cpp | 4 +- addons/main/functions/fnc_handleDamage.sqf | 5 +- addons/main/functions/fnc_handleDamageOld.sqf | 263 ++++++++++++++++++ addons/main/script_macros.hpp | 8 +- addons/main/script_mod.hpp | 2 +- addons/main/script_version.hpp | 2 +- 9 files changed, 282 insertions(+), 19 deletions(-) create mode 100644 addons/main/functions/fnc_handleDamageOld.sqf diff --git a/CHANGELOG.md b/CHANGELOG.md index 47f9cbc..ecbf7a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/addons/main/XEH_PREP.hpp b/addons/main/XEH_PREP.hpp index 3b2bf28..b8c1b8b 100644 --- a/addons/main/XEH_PREP.hpp +++ b/addons/main/XEH_PREP.hpp @@ -1 +1,5 @@ -PREP(handleDamage); +if (getNumber (configFile >> "CfgPatches" >> "ace_main" >> "version") >= 3.18) then { + PREP(handleDamage,handleDamage); +} else { + PREP(handleDamage,handleDamageOld); +}; diff --git a/addons/main/addon.toml b/addons/main/addon.toml index 3a886f6..5422b8b 100644 --- a/addons/main/addon.toml +++ b/addons/main/addon.toml @@ -1,8 +1,2 @@ [rapify] enabled = true - -[binarize] -enabled = true - -[asc] -enabled = true diff --git a/addons/main/config.cpp b/addons/main/config.cpp index 5a887c2..351d419 100644 --- a/addons/main/config.cpp +++ b/addons/main/config.cpp @@ -20,4 +20,6 @@ class CfgPatches { }; #include "CfgEventHandlers.hpp" -#include "CfgVersioning.hpp" + +// Don't force ACE version until 3.18.0 has been out for a while +// #include "CfgVersioning.hpp" diff --git a/addons/main/functions/fnc_handleDamage.sqf b/addons/main/functions/fnc_handleDamage.sqf index 5cb80bb..ab1ebfd 100644 --- a/addons/main/functions/fnc_handleDamage.sqf +++ b/addons/main/functions/fnc_handleDamage.sqf @@ -1,5 +1,4 @@ #include "..\script_component.hpp" - /* * Author: commy2, kymckay, modified by johnb43 * Original: @@ -7,7 +6,7 @@ * 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 @@ -100,7 +99,7 @@ if ( GET_NUMBER(_ammoCfg >> "explosive",0) > 0 || {GET_NUMBER(_ammoCfg >> "indirectHit",0) > 0} } -) exitwith { +) exitWith { TRACE_5("Vehicle hit",_unit,_shooter,_instigator,_damage,_newDamage); _unit setVariable ["ace_medical_lastDamageSource", _shooter]; diff --git a/addons/main/functions/fnc_handleDamageOld.sqf b/addons/main/functions/fnc_handleDamageOld.sqf new file mode 100644 index 0000000..e8ad79a --- /dev/null +++ b/addons/main/functions/fnc_handleDamageOld.sqf @@ -0,0 +1,263 @@ +#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. For ACE 3.17.1 and prior. + * + * Arguments: + * Handle damage EH + * + * Return Value: + * Damage to be inflicted + * + * Public: No + */ + +params ["_args", ["_ignoreAllowDamageACE", false]]; +_args params ["_unit", "_selection", "_damage", "_shooter", "_ammo", "_hitPointIndex", "_instigator", "_hitpoint", "_directHit"]; + +// HD sometimes triggers for remote units - ignore. +if !(local _unit) exitWith {nil}; + +// Get missing meta info +private _oldDamage = 0; + +if (_hitPoint isEqualTo "") then { + _hitPoint = "#structural"; + _oldDamage = damage _unit; +} else { + _oldDamage = _unit getHitIndex _hitPointIndex; +}; + +// Damage can be disabled with old variable or via sqf command allowDamage +if !(isDamageAllowed _unit && {_unit getVariable ["ace_medical_allowDamage", true] || _ignoreAllowDamageACE}) exitWith {_oldDamage}; + +private _newDamage = _damage - _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; + private _damageCoef = linearConversion [0, 1, ace_medical_engine_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 +// Damage occurs in consistent increments +if ( + _hitPoint isEqualTo "#structural" && + {getOxygenRemaining _unit <= 0.5} && + {_damage isEqualTo (_oldDamage + 0.005)} +) exitWith { + TRACE_5("Drowning",_unit,_shooter,_instigator,_damage,_newDamage); + ["ace_medical_woundReceived", [_unit, [[_newDamage, "Body", _newDamage]], _unit, "drowning"]] call CBA_fnc_localEvent; + + 0 +}; + +// 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} && + {vectorMagnitude (velocity _vehicle) > 5} + // todo: no way to detect if stationary and another vehicle hits you +) exitWith { + TRACE_5("Crash",_unit,_shooter,_instigator,_damage,_newDamage); + ["ace_medical_woundReceived", [_unit, [[_newDamage, _hitPoint, _newDamage]], _unit, "vehiclecrash"]] call CBA_fnc_localEvent; + + 0 +}; + +// 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 +if ( + _hitPoint isEqualTo "#structural" && + {!isNull _vehicle} && + {_ammo isNotEqualTo ""} && + { + 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); + + _unit setVariable ["ace_medical_lastDamageSource", _shooter]; + _unit setVariable ["ace_medical_lastInstigator", _instigator]; + + ["ace_medical_woundReceived", [_unit, [[_newDamage, _hitPoint, _newDamage]], _shooter, "vehiclehit"]] call CBA_fnc_localEvent; + + 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 { + _unit setVariable ["ace_medical_lastDamageSource", _shooter]; + _unit setVariable ["ace_medical_lastInstigator", _instigator]; + + private _damageStructural = _unit getVariable ["ace_medical_engine_$#structural", [0,0,0,0]]; + + // --- Head + private _damageHead = [ + _unit getVariable ["ace_medical_engine_$HitFace", [0,0,0,0]], + _unit getVariable ["ace_medical_engine_$HitNeck", [0,0,0,0]], + _unit getVariable ["ace_medical_engine_$HitHead", [0,0,0,0]] + ]; + _damageHead sort false; + _damageHead = _damageHead select 0; + + // --- Body + private _damageBody = [ + _unit getVariable ["ace_medical_engine_$HitPelvis", [0,0,0,0]], + _unit getVariable ["ace_medical_engine_$HitAbdomen", [0,0,0,0]], + _unit getVariable ["ace_medical_engine_$HitDiaphragm", [0,0,0,0]], + _unit getVariable ["ace_medical_engine_$HitChest", [0,0,0,0]] + // HitBody removed as it's a placeholder hitpoint and the high armor value (1000) throws the calculations off + ]; + _damageBody sort false; + _damageBody = _damageBody select 0; + + // --- Arms and Legs + private _damageLeftArm = _unit getVariable ["ace_medical_engine_$HitLeftArm", [0,0,0,0]]; + private _damageRightArm = _unit getVariable ["ace_medical_engine_$HitRightArm", [0,0,0,0]]; + private _damageLeftLeg = _unit getVariable ["ace_medical_engine_$HitLeftLeg", [0,0,0,0]]; + private _damageRightLeg = _unit getVariable ["ace_medical_engine_$HitRightLeg", [0,0,0,0]]; + + // Find hit point that received the maxium damage + // Priority used for sorting if incoming damage is equal + private _allDamages = [ + // Real damage (ignoring armor), Actual damage (with armor), Real damage modified (ignoring armor), Modified damage (with armor) + [_damageHead select 0, PRIORITY_HEAD, _damageHead select 1, "Head", _damageHead param [2, _damageHead select 0], _damageHead param [3, _damageHead select 1]], + [_damageBody select 0, PRIORITY_BODY, _damageBody select 1, "Body", _damageBody param [2, _damageBody select 0], _damageBody param [3, _damageBody select 1]], + [_damageLeftArm select 0, PRIORITY_LEFT_ARM, _damageLeftArm select 1, "LeftArm", _damageLeftArm param [2, _damageLeftArm select 0], _damageLeftArm param [3, _damageLeftArm select 1]], + [_damageRightArm select 0, PRIORITY_RIGHT_ARM, _damageRightArm select 1, "RightArm", _damageRightArm param [2, _damageRightArm select 0], _damageRightArm param [3, _damageRightArm select 1]], + [_damageLeftLeg select 0, PRIORITY_LEFT_LEG, _damageLeftLeg select 1, "LeftLeg", _damageLeftLeg param [2, _damageLeftLeg select 0], _damageLeftLeg param [3, _damageLeftLeg select 1]], + [_damageRightLeg select 0, PRIORITY_RIGHT_LEG, _damageRightLeg select 1, "RightLeg", _damageRightLeg param [2, _damageRightLeg select 0], _damageRightLeg param [3, _damageRightLeg select 1]], + [_damageStructural select 0, PRIORITY_STRUCTURAL, _damageStructural select 1, "#structural", _damageStructural param [2, _damageStructural select 0], _damageStructural param [3, _damageStructural select 1]] + ]; + TRACE_2("incoming",_allDamages,_damageStructural); + + _allDamages sort false; + // Use modified damages instead of initial ones + _allDamages = _allDamages apply {[_x select 5, _x select 3, _x select 4]}; + + // Environmental damage sources all have empty ammo string + // No explicit source given, we infer from differences between them + if (_ammo isEqualTo "") then { + // Any collision with terrain/vehicle/object has a shooter + // Check this first because burning can happen at any velocity + if !(isNull _shooter) then { + /* + If shooter != unit then they hit unit, otherwise it could be: + - Unit hitting anything at speed + - An empty vehicle hitting unit + - A physX object hitting unit + Assume fall damage for downward velocity because it's most common + */ + if (_shooter == _unit && {(velocity _unit select 2) < -2}) then { + _ammo = "falling"; + TRACE_5("Fall",_unit,_shooter,_instigator,_damage,_allDamages); + } else { + _ammo = "collision"; + TRACE_5("Collision",_unit,_shooter,_instigator,_damage,_allDamages); + }; + } else { + // Anything else is almost guaranteed to be fire damage + _ammo = "fire"; + TRACE_5("Fire Damage",_unit,_shooter,_instigator,_damage,_allDamages); + }; + }; + + // No wounds for minor damage + // TODO check if this needs to be changed for burning damage (occurs as lots of small events that we add together) + if ((_allDamages select 0 select 0) > 1E-3) then { + TRACE_1("received",_allDamages); + ["ace_medical_woundReceived", [_unit, _allDamages, _shooter, _ammo]] call CBA_fnc_localEvent; + }; + + // Clear stored damages otherwise they will influence future damage events + // (aka wounds will pile onto the historically most damaged hitpoint) + { + _unit setVariable [_x, nil]; + } forEach [ + "ace_medical_engine_$HitFace","ace_medical_engine_$HitNeck","ace_medical_engine_$HitHead", + "ace_medical_engine_$HitPelvis","ace_medical_engine_$HitAbdomen","ace_medical_engine_$HitDiaphragm","ace_medical_engine_$HitChest","ace_medical_engine_$HitBody", + "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 diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index 91fd239..102bf43 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -1,9 +1,5 @@ #include "\x\cba\addons\main\script_macros_common.hpp" -// This part includes parts of the CBA and ACE3 macro libraries -#define GETMVAR(var1,var2) (missionNamespace getVariable [ARR_2(var1,var2)]) -#define SETMVAR(var1,var2,var3) (missionNamespace setVariable [ARR_3(var1,var2,var3)]) - #define DEFAULT_SETTINGS [ARR_3(1,0,0)] #define MINIMUM_SETTINGS [ARR_3(0.001,0,0)] @@ -11,10 +7,10 @@ #ifdef DISABLE_COMPILE_CACHE #undef PREP - #define PREP(fncName) DFUNC(fncName) = compile preprocessFileLineNumbers QPATHTOF(functions\DOUBLES(fnc,fncName).sqf) + #define PREP(fncName,filename) DFUNC(fncName) = compile preprocessFileLineNumbers QPATHTOF(functions\DOUBLES(fnc,filename).sqf) #else #undef PREP - #define PREP(fncName) [QPATHTOF(functions\DOUBLES(fnc,fncName).sqf), QFUNC(fncName)] call CBA_fnc_compileFunction + #define PREP(fncName,filename) [QPATHTOF(functions\DOUBLES(fnc,filename).sqf), QFUNC(fncName)] call CBA_fnc_compileFunction #endif // #include "\z\ace\addons\medical_engine\script_component.hpp" diff --git a/addons/main/script_mod.hpp b/addons/main/script_mod.hpp index a850aa8..719db23 100644 --- a/addons/main/script_mod.hpp +++ b/addons/main/script_mod.hpp @@ -8,6 +8,6 @@ #define VERSION_AR MAJOR,MINOR,PATCHLVL,BUILD // MINIMAL required version for the Mod. Components can specify others.. -#define REQUIRED_VERSION 2.14 +#define REQUIRED_VERSION 2.16 #define COMPONENT_NAME QUOTE(Armor Modifier - ACE) diff --git a/addons/main/script_version.hpp b/addons/main/script_version.hpp index 62b1e56..9636dec 100644 --- a/addons/main/script_version.hpp +++ b/addons/main/script_version.hpp @@ -1,4 +1,4 @@ #define MAJOR 1 #define MINOR 0 -#define PATCHLVL 2 +#define PATCHLVL 3 #define BUILD 0