mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Medical Engine - Remove ACE_HDBracket hitpoint (#9732)
* Medical Engine - Remove ACE_HDBracket hitpoint * skip context 4 * move checks to vars * skip uav/logic entities * add check for arm/leg hitpoints * Update addons/medical_engine/functions/fnc_handleDamage.sqf Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com> * don't skip context 2 * clearer custom hitpoint array name * reenable compile cache * remove debug mode * lazy eval * whitespace * update comment * Update fnc_handleDamage.sqf header * Update addons/medical_engine/functions/fnc_handleDamage.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/medical_engine/XEH_postInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * update hitpoint test * missing " * Update addons/medical/dev/test_hitpointConfigs.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com>
This commit is contained in:
parent
c862c47617
commit
a85074a797
@ -21,23 +21,16 @@ INFO_1("Checking uniforms for correct medical hitpoints [%1 units]",count _units
|
|||||||
private _testPass = true;
|
private _testPass = true;
|
||||||
{
|
{
|
||||||
private _typeOf = configName _x;
|
private _typeOf = configName _x;
|
||||||
private _hitpoints = (configProperties [_x >> "HitPoints", "isClass _x", true]) apply {configName _x};
|
private _hitpoints = (configProperties [_x >> "HitPoints", "isClass _x", true]) apply {toLowerANSI configName _x};
|
||||||
|
private _expectedHitPoints = ["hitleftarm","hitrightarm","hitleftleg","hitrightleg","hithead","hitbody"];
|
||||||
|
private _missingHitPoints = _expectedHitPoints select {!(_x in _hitpoints)};
|
||||||
|
if (_missingHitPoints isNotEqualTo []) then {
|
||||||
|
WARNING_3("%1 missing ace hitpoints: %2 - class hitpoints: %3",_typeOf,_missingHitPoints,_hitpoints);
|
||||||
|
_testPass = false;
|
||||||
|
};
|
||||||
|
|
||||||
// _typeOf createUnit [position player, group player, "z = this"];
|
// _typeOf createUnit [position player, group player, "z = this"];
|
||||||
// deleteVehicle z;
|
// deleteVehicle z;
|
||||||
|
|
||||||
private _lastHitpoint = (_hitpoints param [(count _hitpoints) - 1, "#array"]);
|
|
||||||
if (_lastHitpoint != "ACE_HDBracket") then {
|
|
||||||
WARNING_2("%1 has bad last hitpoint: %2",_typeOf,_hitpoints);
|
|
||||||
_testPass = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (((_hitpoints findIf {_x == "HitLeftArm"}) == -1) || {(_hitpoints findIf {_x == "HitRightArm"}) == -1}
|
|
||||||
|| {(_hitpoints findIf {_x == "HitLeftLeg"}) == -1} || {(_hitpoints findIf {_x == "HitRightLeg"}) == -1}
|
|
||||||
|| {(_hitpoints findIf {_x == "HitHead"}) == -1} || {(_hitpoints findIf {_x == "HitBody"}) == -1}) then {
|
|
||||||
WARNING_2("%1 missing ace hitpoints: %2",_typeOf,_hitpoints);
|
|
||||||
_testPass = false;
|
|
||||||
};
|
|
||||||
} forEach _units;
|
} forEach _units;
|
||||||
|
|
||||||
_testPass
|
_testPass
|
||||||
|
@ -6,27 +6,23 @@
|
|||||||
[_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture)
|
[_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture)
|
||||||
}, true] call CBA_fnc_addPlayerEventHandler;
|
}, true] call CBA_fnc_addPlayerEventHandler;
|
||||||
|
|
||||||
|
|
||||||
["CAManBase", "init", {
|
["CAManBase", "init", {
|
||||||
params ["_unit"];
|
params ["_unit"];
|
||||||
|
|
||||||
// Check if last hit point is our dummy.
|
if (unitIsUAV _unit) exitWith {TRACE_1("ignore UAV AI",typeOf _unit);};
|
||||||
private _allHitPoints = getAllHitPointsDamage _unit param [0, []];
|
if (getNumber (configOf _unit >> "isPlayableLogic") == 1) exitWith {TRACE_1("ignore logic unit",typeOf _unit);};
|
||||||
reverse _allHitPoints;
|
|
||||||
while {(_allHitPoints param [0, ""]) select [0,1] == "#"} do { WARNING_1("Ignoring Reflector hitpoint %1",_allHitPoints deleteAt 0); };
|
|
||||||
|
|
||||||
if (_allHitPoints param [0, ""] != "ACE_HDBracket") then {
|
private _allHitPoints = getAllHitPointsDamage _unit param [0, []];
|
||||||
if (unitIsUAV _unit) exitWith {TRACE_1("ignore UAV AI",typeOf _unit);};
|
if ((GVAR(customHitpoints) arrayIntersect _allHitPoints) isNotEqualTo GVAR(customHitpoints)) exitWith {
|
||||||
if (getNumber ((configOf _unit) >> "isPlayableLogic") == 1) exitWith {TRACE_1("ignore logic unit",typeOf _unit)};
|
|
||||||
ERROR_1("Bad hitpoints for unit type ""%1""",typeOf _unit);
|
ERROR_1("Bad hitpoints for unit type ""%1""",typeOf _unit);
|
||||||
} else {
|
|
||||||
// Calling this function inside curly brackets allows the usage of
|
|
||||||
// "exitWith", which would be broken with "HandleDamage" otherwise.
|
|
||||||
_unit setVariable [
|
|
||||||
QEGVAR(medical,HandleDamageEHID),
|
|
||||||
_unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}]
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Calling this function inside curly brackets allows the usage of
|
||||||
|
// "exitWith", which would be broken with "HandleDamage" otherwise.
|
||||||
|
_unit setVariable [
|
||||||
|
QEGVAR(medical,HandleDamageEHID),
|
||||||
|
_unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}]
|
||||||
|
];
|
||||||
}, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler;
|
}, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler;
|
||||||
|
|
||||||
#ifdef DEBUG_MODE_FULL
|
#ifdef DEBUG_MODE_FULL
|
||||||
@ -88,7 +84,7 @@
|
|||||||
};
|
};
|
||||||
}] call CBA_fnc_addEventHandler;
|
}] call CBA_fnc_addEventHandler;
|
||||||
|
|
||||||
["CAManBase", "deleted", {
|
["CAManBase", "Deleted", {
|
||||||
params ["_unit"];
|
params ["_unit"];
|
||||||
TRACE_3("unit deleted",_unit,objectParent _unit,local _unit);
|
TRACE_3("unit deleted",_unit,objectParent _unit,local _unit);
|
||||||
if ((!isNull objectParent _unit) && {local objectParent _unit}) then {
|
if ((!isNull objectParent _unit) && {local objectParent _unit}) then {
|
||||||
|
@ -46,6 +46,8 @@ GVAR(animations) setVariable [QUNCON_ANIM(faceDown), [QUNCON_ANIM(1),QUNCON_ANIM
|
|||||||
GVAR(animations) setVariable [QUNCON_ANIM(faceLeft), [QUNCON_ANIM(7),QUNCON_ANIM(8),QUNCON_ANIM(1_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1)]];
|
GVAR(animations) setVariable [QUNCON_ANIM(faceLeft), [QUNCON_ANIM(7),QUNCON_ANIM(8),QUNCON_ANIM(1_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1)]];
|
||||||
GVAR(animations) setVariable [QUNCON_ANIM(faceRight), [QUNCON_ANIM(5),QUNCON_ANIM(6),QUNCON_ANIM(10),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]];
|
GVAR(animations) setVariable [QUNCON_ANIM(faceRight), [QUNCON_ANIM(5),QUNCON_ANIM(6),QUNCON_ANIM(10),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]];
|
||||||
|
|
||||||
|
GVAR(customHitpoints) = ["hitleftarm", "hitrightarm", "hitleftleg", "hitrightleg"];
|
||||||
|
|
||||||
private _fnc_fixStatic = {
|
private _fnc_fixStatic = {
|
||||||
params ["_vehicle"];
|
params ["_vehicle"];
|
||||||
private _type = typeOf _vehicle;
|
private _type = typeOf _vehicle;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include "..\script_component.hpp"
|
#include "..\script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: commy2, kymckay
|
* Author: commy2, kymckay, LinkIsGrim
|
||||||
* HandleDamage EH where wound events are raised based on incoming damage.
|
* 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).
|
* 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".
|
* We store these incoming damages and compare them on last iteration of the event (_context == 2).
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Handle damage EH
|
* Handle damage EH
|
||||||
@ -13,15 +13,16 @@
|
|||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
params ["_unit", "_selection", "_damage", "_shooter", "_ammo", "_hitPointIndex", "_instigator", "_hitpoint"];
|
params ["_unit", "_selection", "_damage", "_shooter", "_ammo", "_hitPointIndex", "_instigator", "_hitpoint", "_directHit", "_context"];
|
||||||
|
|
||||||
// HD sometimes triggers for remote units - ignore.
|
// HD sometimes triggers for remote units - ignore.
|
||||||
if !(local _unit) exitWith {nil};
|
if !(local _unit) exitWith {nil};
|
||||||
|
|
||||||
// Get missing meta info
|
// Get missing meta info
|
||||||
private _oldDamage = 0;
|
private _oldDamage = 0;
|
||||||
|
private _structuralDamage = _context == 0;
|
||||||
|
|
||||||
if (_hitPoint isEqualTo "") then {
|
if (_structuralDamage) then {
|
||||||
_hitPoint = "#structural";
|
_hitPoint = "#structural";
|
||||||
_oldDamage = damage _unit;
|
_oldDamage = damage _unit;
|
||||||
} else {
|
} else {
|
||||||
@ -33,26 +34,29 @@ if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), t
|
|||||||
|
|
||||||
private _newDamage = _damage - _oldDamage;
|
private _newDamage = _damage - _oldDamage;
|
||||||
|
|
||||||
// Happens occasionally for vehiclehit events (see line 80 onwards)
|
// _newDamage == 0 happens occasionally for vehiclehit events (see line 80 onwards), just exit early to save some frametime
|
||||||
// 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 (_newDamage == 0 && {_hitpoint isNotEqualTo "ace_hdbracket"}) exitWith {_oldDamage};
|
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
|
// Get scaled armor value of hitpoint and calculate damage before armor
|
||||||
// We scale using passThrough to handle explosive-resistant armor properly (#9063)
|
// We scale using passThrough to handle explosive-resistant armor properly (#9063)
|
||||||
// We need realDamage to determine which limb was hit correctly
|
// We need realDamage to determine which limb was hit correctly
|
||||||
[_unit, _hitpoint] call FUNC(getHitpointArmor) params ["_armor", "_armorScaled"];
|
[_unit, _hitpoint] call FUNC(getHitpointArmor) params ["_armor", "_armorScaled"];
|
||||||
private _realDamage = _newDamage * _armor;
|
private _realDamage = _newDamage * _armor;
|
||||||
if (_hitPoint isNotEqualTo "#structural") then {
|
if (!_structuralDamage) then {
|
||||||
private _armorCoef = _armor/_armorScaled;
|
private _armorCoef = _armor/_armorScaled;
|
||||||
private _damageCoef = linearConversion [0, 1, GVAR(damagePassThroughEffect), 1, _armorCoef];
|
private _damageCoef = linearConversion [0, 1, GVAR(damagePassThroughEffect), 1, _armorCoef];
|
||||||
_newDamage = _newDamage * _damageCoef;
|
_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
|
// Drowning doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs
|
||||||
// Damage occurs in consistent increments
|
// Damage occurs in consistent increments
|
||||||
if (
|
if (
|
||||||
_hitPoint isEqualTo "#structural" &&
|
_structuralDamage &&
|
||||||
{getOxygenRemaining _unit <= 0.5} &&
|
{getOxygenRemaining _unit <= 0.5} &&
|
||||||
{_damage isEqualTo (_oldDamage + 0.005)}
|
{_damage isEqualTo (_oldDamage + 0.005)}
|
||||||
) exitWith {
|
) exitWith {
|
||||||
@ -64,14 +68,14 @@ if (
|
|||||||
|
|
||||||
// Faster than (vehicle _unit), also handles dead units
|
// Faster than (vehicle _unit), also handles dead units
|
||||||
private _vehicle = objectParent _unit;
|
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
|
// 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
|
// It does fire the EH multiple times, but this seems to scale with the intensity of the crash
|
||||||
if (
|
if (
|
||||||
EGVAR(medical,enableVehicleCrashes) &&
|
EGVAR(medical,enableVehicleCrashes) &&
|
||||||
{_hitPoint isEqualTo "#structural"} &&
|
{_environmentDamage && _inVehicle && _structuralDamage} &&
|
||||||
{_ammo isEqualTo ""} &&
|
|
||||||
{!isNull _vehicle} &&
|
|
||||||
{vectorMagnitude (velocity _vehicle) > 5}
|
{vectorMagnitude (velocity _vehicle) > 5}
|
||||||
// todo: no way to detect if stationary and another vehicle hits you
|
// todo: no way to detect if stationary and another vehicle hits you
|
||||||
) exitWith {
|
) exitWith {
|
||||||
@ -83,11 +87,8 @@ if (
|
|||||||
|
|
||||||
// Receiving explosive damage inside a vehicle doesn't trigger for each hitpoint
|
// Receiving explosive damage inside a vehicle doesn't trigger for each hitpoint
|
||||||
// This is the case for mines, explosives, artillery, and catasthrophic vehicle explosions
|
// This is the case for mines, explosives, artillery, and catasthrophic vehicle explosions
|
||||||
// Triggers twice, but that doesn't matter as damage is low
|
|
||||||
if (
|
if (
|
||||||
_hitPoint isEqualTo "#structural" &&
|
(!_environmentDamage && _inVehicle && _structuralDamage) &&
|
||||||
{!isNull _vehicle} &&
|
|
||||||
{_ammo isNotEqualTo ""} &&
|
|
||||||
{
|
{
|
||||||
private _ammoCfg = configFile >> "CfgAmmo" >> _ammo;
|
private _ammoCfg = configFile >> "CfgAmmo" >> _ammo;
|
||||||
GET_NUMBER(_ammoCfg >> "explosive",0) > 0 ||
|
GET_NUMBER(_ammoCfg >> "explosive",0) > 0 ||
|
||||||
@ -104,9 +105,13 @@ if (
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
// This hitpoint is set to trigger last, evaluate all the stored damage values
|
// Damages are stored for last iteration of the HandleDamage event (_context == 2)
|
||||||
// to determine where wounds are applied
|
_unit setVariable [format [QGVAR($%1), _hitPoint], [_realDamage, _newDamage]];
|
||||||
if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
|
|
||||||
|
// 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 [QEGVAR(medical,lastDamageSource), _shooter];
|
_unit setVariable [QEGVAR(medical,lastDamageSource), _shooter];
|
||||||
_unit setVariable [QEGVAR(medical,lastInstigator), _instigator];
|
_unit setVariable [QEGVAR(medical,lastInstigator), _instigator];
|
||||||
|
|
||||||
@ -157,7 +162,7 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
|
|||||||
|
|
||||||
// Environmental damage sources all have empty ammo string
|
// Environmental damage sources all have empty ammo string
|
||||||
// No explicit source given, we infer from differences between them
|
// 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
|
// Any collision with terrain/vehicle/object has a shooter
|
||||||
// Check this first because burning can happen at any velocity
|
// Check this first because burning can happen at any velocity
|
||||||
if !(isNull _shooter) then {
|
if !(isNull _shooter) then {
|
||||||
@ -199,16 +204,9 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
|
|||||||
QGVAR($HitLeftArm),QGVAR($HitRightArm),QGVAR($HitLeftLeg),QGVAR($HitRightLeg),
|
QGVAR($HitLeftArm),QGVAR($HitRightArm),QGVAR($HitLeftLeg),QGVAR($HitRightLeg),
|
||||||
QGVAR($#structural)
|
QGVAR($#structural)
|
||||||
];
|
];
|
||||||
|
|
||||||
0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Damages are stored for "ace_hdbracket" event triggered last
|
|
||||||
_unit setVariable [format [QGVAR($%1), _hitPoint], [_realDamage, _newDamage]];
|
|
||||||
|
|
||||||
// Engine damage to these hitpoints controls blood visuals, limping, weapon sway
|
// Engine damage to these hitpoints controls blood visuals, limping, weapon sway
|
||||||
// Handled in fnc_damageBodyPart, persist here
|
// Handled in fnc_damageBodyPart, persist here
|
||||||
if (_hitPoint in ["hithead", "hitbody", "hithands", "hitlegs"]) exitWith {_oldDamage};
|
// For all other hitpoints, we store our own damage values, so engine damage is unnecessary
|
||||||
|
[0, _oldDamage] select (_hitPoint in ["hithead", "hitbody", "hithands", "hitlegs"])
|
||||||
// We store our own damage values so engine damage is unnecessary
|
|
||||||
0
|
|
||||||
|
@ -47,15 +47,4 @@
|
|||||||
};\
|
};\
|
||||||
class HitRightLeg: HitLeftLeg {\
|
class HitRightLeg: HitLeftLeg {\
|
||||||
name = "leg_r";\
|
name = "leg_r";\
|
||||||
};\
|
|
||||||
class ACE_HDBracket {\
|
|
||||||
armor = 1;\
|
|
||||||
material = -1;\
|
|
||||||
name = "head";\
|
|
||||||
passThrough = 0;\
|
|
||||||
radius = 1;\
|
|
||||||
explosionShielding = 1;\
|
|
||||||
visual = "";\
|
|
||||||
minimalHit = 0;\
|
|
||||||
depends = "HitHead";\
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user