diff --git a/addons/medical/CfgVehicles.hpp b/addons/medical/CfgVehicles.hpp index 8f570147d5..ba7d413364 100644 --- a/addons/medical/CfgVehicles.hpp +++ b/addons/medical/CfgVehicles.hpp @@ -429,9 +429,9 @@ class CfgVehicles { }; }; - #define ARM_LEG_ARMOR_DEFAULT 3 - #define ARM_LEG_ARMOR_BETTER 5 - #define ARM_LEG_ARMOR_CSAT 4 + #define ARM_LEG_ARMOR_DEFAULT 1 + #define ARM_LEG_ARMOR_BETTER 1 + #define ARM_LEG_ARMOR_CSAT 1 #define ADD_ACE_HITPOINTS(ARM_ARMOR,LEG_ARMOR) \ class HitLeftArm { \ diff --git a/addons/medical/XEH_preInit.sqf b/addons/medical/XEH_preInit.sqf index 9563752d92..5deaf77ceb 100644 --- a/addons/medical/XEH_preInit.sqf +++ b/addons/medical/XEH_preInit.sqf @@ -12,6 +12,7 @@ PREP(actionPlaceInBodyBag); PREP(actionRemoveTourniquet); PREP(actionLoadUnit); PREP(actionUnloadUnit); +PREP(addDamageToUnit); PREP(addHeartRateAdjustment); PREP(addToInjuredCollection); PREP(addToLog); diff --git a/addons/medical/functions/fnc_addDamageToUnit.sqf b/addons/medical/functions/fnc_addDamageToUnit.sqf new file mode 100644 index 0000000000..78d81821e4 --- /dev/null +++ b/addons/medical/functions/fnc_addDamageToUnit.sqf @@ -0,0 +1,63 @@ +/* + * Author: PabstMirror + * Manually Apply Damage to a unit (can cause lethal damage) + * NOTE: because of caching, this will not have instant effects (~3 frame delay) + * + * Arguments: + * 0: The Unit + * 1: Damage to Add + * 2: Selection ("head", "body", "hand_l", "hand_r", "leg_l", "leg_r") + * 3: Projectile Type + * + * Return Value: + * HandleDamage's return + * + * Example: + * [player, 0.8, "leg_r", "bullet"] call ace_medical_fnc_addDamageToUnit + * [cursorTarget, 1, "body", "stab"] call ace_medical_fnc_addDamageToUnit + * + * Public: Yes + */ +#define DEBUG_MODE_FULL +#define DEBUG_TESTRESULTS +#include "script_component.hpp" + +params [["_unit", objNull, [objNull]], ["_damageToAdd", -1, [0]], ["_selection", "", [""]], ["_typeOfDamage", "", [""]]]; +TRACE_4("params",_unit,_damageToAdd,_selection,_typeOfDamage); + +_selection = toLower _selection; +if ((isNull _unit) || {!local _unit} || {!alive _unit}) exitWith {ACE_LOGERROR_1("addDamageToUnit - badUnit %1", _this); -1}; +if (_damageToAdd < 0) exitWith {ACE_LOGERROR_1("addDamageToUnit - bad damage %1", _this); -1}; +if (!(_selection in GVAR(SELECTIONS))) exitWith {ACE_LOGERROR_1("addDamageToUnit - bad selection %1", _this); -1}; + +//Get the hitpoint and the index +private _hitpoint = [_unit, _selection, true] call ace_medical_fnc_translateSelections; +(getAllHitPointsDamage _unit) params [["_allHitPoints", []]]; +private _hitpointIndex = -1; +{ //case insensitive find + if (_x == _hitpoint) exitWith {_hitpointIndex = _forEachIndex;}; +} forEach _allHitPoints; +if (_hitpointIndex < 0) exitWith {ACE_LOGERROR_1("addDamageToUnit - bad hitpointIndex %1", _this); -1}; + +private _currentDamage = _unit getHitIndex _hitpointIndex; + +#ifdef DEBUG_TESTRESULTS +private _checkAtFrame = diag_frameno + 5; +private _partNumber = [_selection] call FUNC(selectionNameToNumber); +private _startDmg = (_unit getVariable [QGVAR(bodyPartStatus), [0,0,0,0,0,0]]) select _partNumber; +private _debugCode = { + params ["", "_unit", "_startDmg", "_damageToAdd", "_partNumber"]; + private _endDmg = (_unit getVariable [QGVAR(bodyPartStatus), [0,0,0,0,0,0]]) select _partNumber; + if ((!alive _unit) || {_endDmg > _startDmg}) then { + ACE_LOGINFO_6("addDamageToUnit - PASSED - [unit:%1, partNo:%2, addDmg:%3] results:[alive:%4 old:%5 new:%6]", _unit, _partNumber, _damageToAdd, alive _unit, _startDmg, _endDmg); + } else { + ACE_LOGERROR_6("addDamageToUnit - FAILED - [unit:%1, partNo:%2, addDmg:%3] results:[alive:%4 old:%5 new:%6]", _unit, _partNumber, _damageToAdd, alive _unit, _startDmg, _endDmg); + }; +}; +[{diag_frameno > (_this select 0)}, _debugCode, [_checkAtFrame, _unit, _startDmg, _damageToAdd, _partNumber]] call EFUNC(common,waitUntilAndExecute); +#endif + +private _return = [_unit, _selection, (_currentDamage + _damageToAdd), _unit, _typeOfDamage, _hitpointIndex] call FUNC(handleDamage); +TRACE_1("handleDamage called",_return); + +_return diff --git a/addons/medical/functions/fnc_displayPatientInformation.sqf b/addons/medical/functions/fnc_displayPatientInformation.sqf index cd77a8d371..734479914d 100644 --- a/addons/medical/functions/fnc_displayPatientInformation.sqf +++ b/addons/medical/functions/fnc_displayPatientInformation.sqf @@ -133,10 +133,10 @@ if (_show) then { } else { _damaged = [true, true, true, true, true, true]; { - _selectionBloodLoss set [_forEachIndex, _target getHitPointDamage _x]; - - if (_target getHitPointDamage _x > 0 && {_forEachIndex == _selectionN}) then { - _pointDamage = _target getHitPointDamage _x; + private _hitPoint = [_target, _x, true] call FUNC(translateSelections); + _selectionBloodLoss set [_forEachIndex, _target getHitPointDamage _hitPoint]; + if (_target getHitPointDamage _hitPoint > 0 && {_forEachIndex == _selectionN}) then { + _pointDamage = _target getHitPointDamage _hitPoint; _severity = switch (true) do { case (_pointDamage > 0.5): {localize LSTRING(HeavilyWounded)}; case (_pointDamage > 0.1): {localize LSTRING(LightlyWounded)}; @@ -152,7 +152,7 @@ if (_show) then { ] select _forEachIndex); _allInjuryTexts pushBack [format ["%1 %2", _severity, toLower _part], [1,1,1,1]]; }; - } forEach ["HitHead", "HitBody", "HitLeftArm", "HitRightArm", "HitLeftLeg", "HitRightLeg"]; + } forEach GVAR(SELECTIONS); }; // Handle the body image coloring diff --git a/addons/medical/functions/fnc_handleDamage.sqf b/addons/medical/functions/fnc_handleDamage.sqf index 1af77c8483..83d5c9d2f2 100644 --- a/addons/medical/functions/fnc_handleDamage.sqf +++ b/addons/medical/functions/fnc_handleDamage.sqf @@ -8,6 +8,7 @@ * 2: Amount Of Damage * 3: Shooter * 4: Projectile + * 5: HitPointIndex (-1 for structural) * * Return Value: * Damage To Be Inflicted @@ -38,6 +39,7 @@ TRACE_3("ACE_DEBUG: HandleDamage",_selection,_damage,_unit); // If damage is in dummy hitpoints, "hands" and "legs", don't change anything if (_selection == "hands") exitWith {_unit getHit "hands"}; if (_selection == "legs") exitWith {_unit getHit "legs"}; +if (_selection == "arms") exitWith {_unit getHit "arms"}; // Deal with the new hitpoint and selection names introduced with Arma v1.50 and later. // This will convert new selection names into selection names that the medical system understands @@ -46,8 +48,8 @@ if (_selection == "legs") exitWith {_unit getHit "legs"}; _selection = [_unit, _selection, _hitPointIndex] call FUNC(translateSelections); _this set [1, _selection]; // ensure that the parameters are set correctly -// If the damage is being weird, we just tell it to fuck off. Ignore: "hands", "legs", "?" -if (_selection != "" && {!(_selection in GVAR(SELECTIONS))}) exitWith {0}; //@todo "neck", "pelvis", "spine1", "spine2", "spine3" +// If the damage is being weird, we just tell it to fuck off. Ignore: "hands", "legs", "arms" +if (_selection != "" && {!(_selection in GVAR(SELECTIONS))}) exitWith {0}; // Exit if we disable damage temporarily if !(_unit getVariable [QGVAR(allowDamage), true]) exitWith { @@ -85,7 +87,7 @@ if ((_minLethalDamage <= _newDamage) && {[_unit, [_selection] call FUNC(selectio if ((_unit getVariable [QGVAR(preventInstaDeath), GVAR(preventInstaDeath)])) exitwith { _damageReturn = 0.9; }; - if ([_unit] call FUNC(setDead)) then { + if ([_unit, false, true] call FUNC(setDead)) then { _damageReturn = 1; } else { _damageReturn = _damageReturn min 0.89; @@ -110,7 +112,7 @@ if (_unit getVariable [QGVAR(preventInstaDeath), GVAR(preventInstaDeath)]) exitW if (_damageReturn >= 0.9 && {_selection in ["", "head", "body"]}) exitWith { if (_unit getvariable ["ACE_isUnconscious", false]) exitwith { - [_unit] call FUNC(setDead); + [_unit, false, true] call FUNC(setDead); 0.89; }; if (_delayedUnconsicous) then { @@ -131,7 +133,7 @@ if (((_unit getVariable [QGVAR(enableRevive), GVAR(enableRevive)]) > 0) && {_dam if (vehicle _unit != _unit and {damage (vehicle _unit) >= 1}) then { [_unit] call EFUNC(common,unloadPerson); }; - [_unit] call FUNC(setDead); + [_unit, false, true] call FUNC(setDead); 0.89; }; diff --git a/addons/medical/functions/fnc_handleDamage_basic.sqf b/addons/medical/functions/fnc_handleDamage_basic.sqf index 92fc97c717..228c503ce0 100644 --- a/addons/medical/functions/fnc_handleDamage_basic.sqf +++ b/addons/medical/functions/fnc_handleDamage_basic.sqf @@ -24,6 +24,7 @@ TRACE_4("ACE_DEBUG: HandleDamage BASIC",_unit, _damageBodyParts,_cache_params,_c { _x params ["_unit","_selectionName","_amountOfDamage","_sourceOfDamage","_typeOfProjectile","_typeOfDamage"]; + TRACE_6("_x",_unit,_selectionName,_amountOfDamage,_sourceOfDamage,_typeOfProjectile,_typeOfDamage); if !(isNull _sourceOfDamage && {_typeOfProjectile == ""} && {vehicle _unit == _unit} && {(_selectionName == "head" || isBurning _unit)}) then { _part = [_selectionName] call FUNC(selectionNameToNumber); if (_part < 0) exitwith {}; @@ -56,5 +57,6 @@ _target setHitPointDamage ["hitHands", (_handsDamageR + _handsDamageL) min 0.95] _target setHitPointDamage ["hitLegs", (_legsDamageR + _legsDamageL) min 0.95]; { - _target setHitPointDamage [_x, (_damageBodyParts select _foreachIndex) min 0.95]; -}foreach GVAR(HITPOINTS); + private _hitPointName = [_target, _x, true] call FUNC(translateSelections); + _target setHitPointDamage [_hitPointName, (_damageBodyParts select _foreachIndex) min 0.95]; +}foreach GVAR(SELECTIONS); diff --git a/addons/medical/functions/fnc_handleDamage_caching.sqf b/addons/medical/functions/fnc_handleDamage_caching.sqf index 910221a850..63e386bd58 100644 --- a/addons/medical/functions/fnc_handleDamage_caching.sqf +++ b/addons/medical/functions/fnc_handleDamage_caching.sqf @@ -8,29 +8,25 @@ * 2: Amount Of Damage * 3: Shooter * 4: Projectile - * 5: Current damage to be returned + * 5: HitPointIndex (-1 for structural) * * Return Value: * * * Public: No */ - #include "script_component.hpp" private ["_hitSelections", "_hitPoints", "_impactVelocity", "_newDamage", "_cache_hitpoints", "_cache_projectiles", "_cache_params", "_cache_damages"]; -params ["_unit", "_selectionName", "_damage", "_source", "_projectile"]; -TRACE_8("ACE_DEBUG: HandleDamage_Caching Called",_unit, _selectionName, _damage, _source, _projectile,GVAR(SELECTIONS),GVAR(HITPOINTS),damage _unit); +params ["_unit", "_selectionName", "_damage", "_source", "_projectile", "_hitPointIndex"]; + _hitSelections = GVAR(SELECTIONS); -_hitPoints = GVAR(HITPOINTS); -// Calculate change in damage. +// Calculate change in damage - use getHitIndex because selection is translated (hitdiaphragm->body) _newDamage = _damage - (damage _unit); -if (_selectionName in _hitSelections) then { - _newDamage = _damage - (_unit getHitPointDamage (_hitPoints select (_hitSelections find _selectionName))); -}; +if (_hitPointIndex >= 0) then {_newDamage = _damage - (_unit getHitIndex _hitPointIndex)}; -//_damage = _damage + _newDamage; +TRACE_7("ACE_DEBUG: HandleDamage_Caching Called",_unit, _selectionName, _damage, _source, _projectile,_hitPointIndex,_newDamage); // Check for vehicle crash if (vehicle _unit != _unit && {!(vehicle _unit isKindOf "StaticWeapon")} && {isNull _source} && {_projectile == ""} && {_selectionName == ""}) then { @@ -45,8 +41,14 @@ if (vehicle _unit != _unit && {!(vehicle _unit isKindOf "StaticWeapon")} && {isN // Handle falling damage _impactVelocity = (velocity _unit) select 2; if (_impactVelocity < -5 && {vehicle _unit == _unit}) then { + TRACE_1("Starting isFalling", time); _unit setVariable [QGVAR(isFalling), true]; _unit setVariable [QGVAR(impactVelocity), _impactVelocity]; +} else { + if ((_unit getVariable [QGVAR(isFalling), false]) && {diag_frameno > (_unit getVariable [QGVAR(frameNo_damageCaching), -3]) + 2}) then { + TRACE_1("Ending isFalling", time); + _unit setVariable [QGVAR(isFalling), false]; + }; }; if (_unit getVariable [QGVAR(isFalling), false]) then { if !(_selectionName in ["", "leg_l", "leg_r"]) then { @@ -119,10 +121,10 @@ if (_selectionName != "") then { private ["_hitPoint", "_restore"]; // Restore the damage before the previous damage was processed _hitPoint = _cache_hitpoints select _index; - _restore = ((_unit getHitPointDamage _hitPoint) - _otherDamage) max 0; - _unit setHitPointDamage [_hitPoint, _restore]; + _restore = ((_unit getHitIndex _hitPoint) - _otherDamage) max 0; + _unit setHitIndex [_hitPoint, _restore]; - _cache_hitpoints set [_index, (_hitPoints select (_hitSelections find _selectionName))]; + _cache_hitpoints set [_index, _hitPointIndex]; _cache_damages set [_index, _newDamage]; _cache_params set[_index, _this]; @@ -139,7 +141,7 @@ if (_selectionName != "") then { // This is an unhandled projectile _cache_projectiles pushBack _projectile; - _cache_hitpoints pushBack (_hitPoints select (_hitSelections find _selectionName)); + _cache_hitpoints pushBack _hitPointIndex; _cache_damages pushBack _newDamage; _cache_params pushBack _this; diff --git a/addons/medical/functions/fnc_setDead.sqf b/addons/medical/functions/fnc_setDead.sqf index c8c81a699e..f00621df02 100644 --- a/addons/medical/functions/fnc_setDead.sqf +++ b/addons/medical/functions/fnc_setDead.sqf @@ -4,19 +4,21 @@ * * Arguments: * 0: The unit that will be killed + * 1: Force Dead (ignore revive setting) + * 1: Delay setDamage for a frame * * ReturnValue: - * None + * Did he died? * * Public: yes */ #include "script_component.hpp" -private ["_unit", "_force", "_reviveVal", "_lifesLeft"]; -params ["_unit", ["_force", false]]; +private ["_reviveVal", "_lifesLeft"]; +params ["_unit", ["_force", false], ["_delaySetDamage", false]]; -if (!alive _unit) exitwith{true}; +if ((!alive _unit) || {_unit getVariable ["ACE_isDead", false]}) exitWith {true}; if (!local _unit) exitwith { [[_unit, _force], QUOTE(DFUNC(setDead)), _unit, false] call EFUNC(common,execRemoteFnc); /* TODO Replace by event system */ false; @@ -78,5 +80,13 @@ if (isPLayer _unit) then { ["medical_onSetDead", [_unit]] call EFUNC(common,localEvent); -[_unit, 1] call FUNC(setStructuralDamage); +//Delay a frame before killing the unit via scripted damage +//to avoid triggering the "Killed" Event twice (and having the wrong killer) + +if (!_delaySetDamage) then { + [_unit, 1] call FUNC(setStructuralDamage); +} else { + [FUNC(setStructuralDamage), [_unit, 1]] call EFUNC(common,execNextFrame); +}; + true; diff --git a/addons/medical/functions/fnc_translateSelections.sqf b/addons/medical/functions/fnc_translateSelections.sqf index f2fe4c1de9..95773acdab 100644 --- a/addons/medical/functions/fnc_translateSelections.sqf +++ b/addons/medical/functions/fnc_translateSelections.sqf @@ -6,15 +6,18 @@ * Arguments: * 0: Unit * 1: selection name - * 2: HitPoint Index + * 2: HitPoint Index/True to get hitpoint * * Return Value: - * translated selection name + * translated selection/hitpoint name * * Example: * [bob, "pelvis", 4] call ace_medical_fnc_translateSelections * Returns "body" * + * [bob, "body", true] call ace_medical_fnc_translateSelections + * Returns "HitBody" + * * Public: No */ #include "script_component.hpp" @@ -35,6 +38,36 @@ params ["_unit", "_selection", "_hitPointIndex"]; if (_selection == "") exitWith {""}; + +//Get Selection from standard selection ["head","body","hand_l","hand_r","leg_l","leg_r"] +if (_hitPointIndex isEqualTo true) exitWith { + private _returnHitPoint = GVAR(HITPOINTS) select (GVAR(SELECTIONS) find _selection); + //If the selection is a valid hitpoint just return it: + if (!isNil {_unit getHitPointDamage _returnHitPoint}) exitWith { + _returnHitPoint; + }; + + //Those VR fuckers have weird limb hitpoints + private _hitPoints = switch (_selection) do { + case ("hand_l"): {L_ARM_HITPOINTS}; + case ("hand_r"): {R_ARM_HITPOINTS}; + case ("leg_l"): {L_LEG_HITPOINTS}; + case ("leg_r"): {R_LEG_HITPOINTS}; + case ("head"): {HEAD_HITPOINTS}; + case ("body"): {TORSO_HITPOINTS}; + default {[]}; + }; + { + if (!isNil {_unit getHitPointDamage _x}) exitWith { + _returnHitPoint = _x; + }; + } forEach _hitPoints; + _returnHitPoint +}; + + +//Get Selection from Selection/HitIndex: + if (_selection in HEAD_SELECTIONS) exitWith {"head"}; if (_selection in TORSO_SELECTIONS) exitWith {"body"}; diff --git a/addons/medical/functions/fnc_treatmentBasic_bandageLocal.sqf b/addons/medical/functions/fnc_treatmentBasic_bandageLocal.sqf index ee04decfbd..b34f0f1cd0 100644 --- a/addons/medical/functions/fnc_treatmentBasic_bandageLocal.sqf +++ b/addons/medical/functions/fnc_treatmentBasic_bandageLocal.sqf @@ -44,7 +44,8 @@ _target setHitPointDamage ["hitHands", (_handsDamageR + _handsDamageL) min 0.95] _target setHitPointDamage ["hitLegs", (_legsDamageR + _legsDamageL) min 0.95]; { - _target setHitPointDamage [_x, (_damageBodyParts select _foreachIndex) min 0.95]; -}foreach GVAR(HITPOINTS); + private _hitPointName = [_target, _x, true] call FUNC(translateSelections); + _target setHitPointDamage [_hitPointName, (_damageBodyParts select _foreachIndex) min 0.95]; +}foreach GVAR(SELECTIONS); true; diff --git a/addons/medical/functions/fnc_treatment_success.sqf b/addons/medical/functions/fnc_treatment_success.sqf index c2347c59ee..559a83885f 100644 --- a/addons/medical/functions/fnc_treatment_success.sqf +++ b/addons/medical/functions/fnc_treatment_success.sqf @@ -66,14 +66,10 @@ if (isNil _callback) then { }; //Get current damage before treatment (for litter) -_previousDamage = switch (toLower _selectionName) do { - case ("head"): {_target getHitPointDamage "HitHead"}; - case ("body"): {_target getHitPointDamage "HitBody"}; - case ("hand_l"): {_target getHitPointDamage "HitLeftArm"}; - case ("hand_r"): {_target getHitPointDamage "HitRightArm"}; - case ("leg_l"): {_target getHitPointDamage "HitLeftLeg"}; - case ("leg_r"): {_target getHitPointDamage "HitRightLeg"}; - default {damage _target}; +_previousDamage = if (_selectionName in GVAR(SELECTIONS)) then { + _target getHitPointDamage ([_target, _selectionName, true] call FUNC(translateSelections)); +} else { + damage _target; }; _args call _callback; diff --git a/addons/overpressure/functions/fnc_fireLauncherBackblast.sqf b/addons/overpressure/functions/fnc_fireLauncherBackblast.sqf index e457e023c6..02da9e9564 100644 --- a/addons/overpressure/functions/fnc_fireLauncherBackblast.sqf +++ b/addons/overpressure/functions/fnc_fireLauncherBackblast.sqf @@ -62,7 +62,7 @@ if (_distance < _backblastRange) then { [_damage * 100] call BIS_fnc_bloodEffect; if (isClass (configFile >> "CfgPatches" >> "ACE_Medical") && {([_firer] call EFUNC(medical,hasMedicalEnabled))}) then { - [_firer, "body", ((_firer getvariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0]]) select 1) + _damage, _firer, "backblast", 0] call EFUNC(medical,handleDamage); + [_firer, _damage, "body", "backblast"] call EFUNC(medical,addDamageToUnit); } else { _firer setDamage (damage _firer + _damage); }; diff --git a/addons/overpressure/functions/fnc_overpressureDamage.sqf b/addons/overpressure/functions/fnc_overpressureDamage.sqf index f9c58050e0..b1c8a5c574 100644 --- a/addons/overpressure/functions/fnc_overpressureDamage.sqf +++ b/addons/overpressure/functions/fnc_overpressureDamage.sqf @@ -56,7 +56,7 @@ TRACE_4("Parameters:",_overpressureAngle,_overpressureRange,_overpressureDamage, if (_x == ACE_player) then {[_damage * 100] call BIS_fnc_bloodEffect}; if (isClass (configFile >> "CfgPatches" >> "ACE_Medical") && {([_x] call EFUNC(medical,hasMedicalEnabled))}) then { - [_x, "body", ((_x getvariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0]]) select 1) + _damage, _firer, "backblast", 0] call EFUNC(medical,handleDamage); + [_x, _damage, "body", "backblast"] call EFUNC(medical,addDamageToUnit); } else { _x setDamage (damage _x + _damage); };