From 573279bd30fdec83f7bf696f385a836cc5c12e3a Mon Sep 17 00:00:00 2001 From: commy2 Date: Fri, 2 Oct 2015 23:19:14 +0200 Subject: [PATCH] add selection, collision, fall and drowning damage events --- addons/medical/XEH_init.sqf | 3 +- addons/medical/XEH_postInit.sqf | 5 + addons/medical/XEH_preInit.sqf | 5 + .../functions/fnc_handleCollisionDamage.sqf | 14 ++ .../medical/functions/fnc_handleDamageNew.sqf | 167 ++++++++++++++++++ .../functions/fnc_handleDrowningDamage.sqf | 14 ++ .../functions/fnc_handleFallDamage.sqf | 14 ++ .../functions/fnc_handleSelectionDamage.sqf | 11 ++ 8 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 addons/medical/functions/fnc_handleCollisionDamage.sqf create mode 100644 addons/medical/functions/fnc_handleDamageNew.sqf create mode 100644 addons/medical/functions/fnc_handleDrowningDamage.sqf create mode 100644 addons/medical/functions/fnc_handleFallDamage.sqf create mode 100644 addons/medical/functions/fnc_handleSelectionDamage.sqf diff --git a/addons/medical/XEH_init.sqf b/addons/medical/XEH_init.sqf index acdd50ce82..8b2b0ae1cd 100644 --- a/addons/medical/XEH_init.sqf +++ b/addons/medical/XEH_init.sqf @@ -2,7 +2,8 @@ params ["_unit"]; -_unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}]; +//_unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}]; +_unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamageNew)}]; if (local _unit) then { if (!EGVAR(common,settingsInitFinished)) exitWith { diff --git a/addons/medical/XEH_postInit.sqf b/addons/medical/XEH_postInit.sqf index 064f78682f..b893c0349c 100644 --- a/addons/medical/XEH_postInit.sqf +++ b/addons/medical/XEH_postInit.sqf @@ -2,6 +2,11 @@ #include "script_component.hpp" +["medical_selectionDamage", {_this call FUNC(handleSelectionDamage)}] call EFUNC(common,addEventhandler); +["medical_fallDamage", {_this call FUNC(handleFallDamage)}] call EFUNC(common,addEventhandler); +["medical_drowningDamage", {_this call FUNC(handleDrowningDamage)}] call EFUNC(common,addEventhandler); +["medical_collisionDamage", {_this call FUNC(handleCollisionDamage)}] call EFUNC(common,addEventhandler); + GVAR(heartBeatSounds_Fast) = ["ACE_heartbeat_fast_1", "ACE_heartbeat_fast_2", "ACE_heartbeat_fast_3"]; GVAR(heartBeatSounds_Normal) = ["ACE_heartbeat_norm_1", "ACE_heartbeat_norm_2"]; GVAR(heartBeatSounds_Slow) = ["ACE_heartbeat_slow_1", "ACE_heartbeat_slow_2"]; diff --git a/addons/medical/XEH_preInit.sqf b/addons/medical/XEH_preInit.sqf index 2625bf4b8a..94590c5077 100644 --- a/addons/medical/XEH_preInit.sqf +++ b/addons/medical/XEH_preInit.sqf @@ -41,6 +41,11 @@ PREP(handleDamage_fractures); PREP(handleDamage_internalInjuries); PREP(handleDamage_wounds); PREP(handleDamage_woundsOld); +PREP(handleDamageNew); +PREP(handleSelectionDamage); +PREP(handleFallDamage); +PREP(handleCollisionDamage); +PREP(handleDrowningDamage); PREP(handleUnitVitals); PREP(handleKilled); PREP(handleLocal); diff --git a/addons/medical/functions/fnc_handleCollisionDamage.sqf b/addons/medical/functions/fnc_handleCollisionDamage.sqf new file mode 100644 index 0000000000..191a91cb6a --- /dev/null +++ b/addons/medical/functions/fnc_handleCollisionDamage.sqf @@ -0,0 +1,14 @@ +// by commy2 +#include "script_component.hpp" + +params ["_unit", "_newDamage"]; + +private ["_selection", "_totalDamage"]; + +_selection = "body"; + +_totalDamage = (_unit getHit _selection) + _newDamage; + +_unit setHit [_selection, _totalDamage]; + +systemChat format ["collision: %1", _this]; diff --git a/addons/medical/functions/fnc_handleDamageNew.sqf b/addons/medical/functions/fnc_handleDamageNew.sqf new file mode 100644 index 0000000000..143c70dddb --- /dev/null +++ b/addons/medical/functions/fnc_handleDamageNew.sqf @@ -0,0 +1,167 @@ +/* + * Author: KoffeinFlummi, Glowbal, commy2 + * Main HandleDamage EH function. + * + * Arguments: + * 0: Unit That Was Hit + * 1: Name Of Hit Selection + * 2: Amount Of Damage + * 3: Shooter + * 4: Projectile + * + * Return Value: + * Damage To Be Inflicted + * + * Public: No + */ +#include "script_component.hpp" + +params ["_unit", "_selection", "_damage", "_shooter", "_projectile"]; +TRACE_5("ACE_DEBUG: HandleDamage Called",_unit,_selection,_damage,_shooter,_projectile); + +// bug, apparently can fire for remote units in special cases +if !(local _unit) exitWith { + TRACE_2("ACE_DEBUG: HandleDamage on remote unit!",_unit,isServer); + nil +}; + +// bug, assumed fixed, @todo excessive testing, if nothing happens remove +if (typeName _projectile == "OBJECT") then { + TRACE_3("ACE_DEBUG: HandleDamage found projectile instead of classname of ammo!",_unit,_projectile,typeOf _projectile); + _projectile = typeOf _projectile; + _this set [4, _projectile]; +}; + +// Exit now we disable damage, replaces "allowDamage false" +if !(_unit getVariable [QGVAR(allowDamage), true]) exitWith { + TRACE_2("ACE_DEBUG: HandleDamage damage disabled.",_selection,_unit); + if (_selection == "") then { + damage _unit + } else { + _unit getHit _selection + }; +}; + + +diag_log text str _selection; +diag_log text str _damage; + + +private ["_damageReturn", "_newDamage", "_index"]; + +// apply damage scripted +if (_selection == "") then { + _damageReturn = _damage; + _newDamage = _damage - damage _unit; + + _index = -1; + + private "_cachedStructuralDamage"; + _cachedStructuralDamage = _unit getVariable [QGVAR(cachedStructuralDamageNew), 0]; + + // handle damage always tries to start and end with the same structural damage call. Use that to find and set the final damage. discard everything the game discards too. + // this correctly handles: bullets, explosions, fire + if (_damage == _cachedStructuralDamage) then { + private "_cachedNewHitpointDamages"; + _cachedNewHitpointDamages = _unit getVariable [QGVAR(cachedNewHitpointDamages), [0,0,0,0,0,0]]; + + // this is the only point damage actually counts. all additional vitality functions should use these values. + { + if (_x > 0) then { + ["medical_selectionDamage", [_unit, GVAR(Selections) select _forEachIndex, _x, _projectile]] call EFUNC(common,localEvent); + }; + } forEach _cachedNewHitpointDamages; + } else { + scopeName "findDamageSource"; + + // check for fall damage. this triggers twice, but seems to happen on the same frame. shouldn't fall twice in a few frames anyway. tested at 7FPS on local host MP + if (animationState _unit select [0,4] == "afal") then { + private "_cachedLastFallDamageFrame"; + _cachedLastFallDamageFrame = _unit getVariable [QGVAR(cachedLastFallDamageFrame), -1]; + + if (diag_frameno != _cachedLastFallDamageFrame) then { + ["medical_fallDamage", [_unit, _newDamage]] call EFUNC(common,localEvent); + _unit setVariable [QGVAR(cachedLastFallDamageFrame), diag_frameno]; + }; + + _damageReturn = damage _unit; + breakOut "findDamageSource"; + }; + + // check for drowning damage. Pretty relyable damage output. triggers only once. + if (getOxygenRemaining _unit < 0.5) then { + // typical drowning damage + if (_newDamage == 0.005) then { + ["medical_drowningDamage", [_unit, _newDamage]] call EFUNC(common,localEvent); + _damageReturn = damage _unit - 0.005; // engine applies damage before hd call. subtract again here. + breakOut "findDamageSource"; + }; + + // suffocated under water might use atypical new damage (mostly 1.005) + if (getOxygenRemaining _unit == 0) then { + ["medical_drowningDamage", [_unit, _newDamage min 1]] call EFUNC(common,localEvent); + _damageReturn = damage _unit; // you will die regardless of hd return value + breakOut "findDamageSource"; + }; + }; + + // check for misc. damage. Probably collision. + if (_projectile == "" && _newDamage > 0) then { + private "_cachedLastCollisionDamageFrame"; + _cachedLastCollisionDamageFrame = _unit getVariable [QGVAR(cachedLastFallDamageFrame), -1]; + + // collision only happens once. engine ignores all further calls on that frame as well + if (_cachedLastCollisionDamageFrame != diag_frameno) then { + _unit setVariable [QGVAR(cachedLastFallDamageFrame), diag_frameno]; + _unit setVariable [QGVAR(cachedLastCollisionDamage), 0]; + + ["medical_collisionDamage", [_unit, _newDamage max (_unit getVariable [QGVAR(cachedLastCollisionDamage), 0])]] call EFUNC(common,localEvent); + + _damageReturn = damage _unit - _newDamage; + breakOut "findDamageSource"; + }; + _damageReturn = damage _unit; + }; + }; + + // reset everything, get ready for the next bullet + _unit setVariable [QGVAR(cachedNewHitpointDamages), [0,0,0,0,0,0]]; + _unit setVariable [QGVAR(cachedStructuralDamageNew), _damage]; + +} else { + // selections are done scripted. return same value to change nothing. + _damageReturn = _unit getHit _selection; + _newDamage = _damage - _damageReturn; // _damageReturn because it saves one getHit call + + _index = GVAR(SELECTIONS) find _selection; + + // a selection we care for was hit. now save the new damage to apply it by a later structural damage call + if (_index != -1) then { + private "_cachedNewHitpointDamages"; + _cachedNewHitpointDamages = _unit getVariable [QGVAR(cachedNewHitpointDamages), [0,0,0,0,0,0]]; + + // prevents multiple selections from being hit by one bullet due to hitpoint radius system + { + // ignore this damage if it's a secondary selection (minor damage) + if (_x > _newDamage) exitWith { + _newDamage = 0; + }; + + // overwrite minor damage in secondary selections + if (_x > 0) then { + _cachedNewHitpointDamages set [_forEachIndex, 0]; + }; + } forEach _cachedNewHitpointDamages; + + // apply these by the next matching hd call with selection "". If that one is not matching, this gets discarded + _cachedNewHitpointDamages set [_index, _newDamage]; + _unit setVariable [QGVAR(cachedNewHitpointDamages), _cachedNewHitpointDamages]; + }; + + // use this to detect collision damage. + if (_projectile == "") then { + _unit setVariable [QGVAR(cachedLastCollisionDamage), _newDamage max (_unit getVariable [QGVAR(cachedLastCollisionDamage), 0])]; + }; +}; + +_damageReturn diff --git a/addons/medical/functions/fnc_handleDrowningDamage.sqf b/addons/medical/functions/fnc_handleDrowningDamage.sqf new file mode 100644 index 0000000000..2dc538aac9 --- /dev/null +++ b/addons/medical/functions/fnc_handleDrowningDamage.sqf @@ -0,0 +1,14 @@ +// by commy2 +#include "script_component.hpp" + +params ["_unit", "_newDamage"]; + +private ["_selection", "_totalDamage"]; + +_selection = "head"; + +_totalDamage = (_unit getHit _selection) + _newDamage; + +_unit setHit [_selection, _totalDamage]; + +systemChat format ["drowning: %1", _this]; diff --git a/addons/medical/functions/fnc_handleFallDamage.sqf b/addons/medical/functions/fnc_handleFallDamage.sqf new file mode 100644 index 0000000000..cea73b16bf --- /dev/null +++ b/addons/medical/functions/fnc_handleFallDamage.sqf @@ -0,0 +1,14 @@ +// by commy2 +#include "script_component.hpp" + +params ["_unit", "_newDamage"]; + +private ["_totalDamageL", "_totalDamageR"]; + +_totalDamageL = (_unit getHitPointDamage "HitLeftLeg") + _newDamage; +_totalDamageR = (_unit getHitPointDamage "HitRightLeg") + _newDamage; + +_unit setHitPointDamage ["HitLeftLeg", _totalDamageL]; +_unit setHitPointDamage ["HitRightLeg", _totalDamageR]; + +systemChat format ["falling: %1", _this]; diff --git a/addons/medical/functions/fnc_handleSelectionDamage.sqf b/addons/medical/functions/fnc_handleSelectionDamage.sqf new file mode 100644 index 0000000000..27c8debe63 --- /dev/null +++ b/addons/medical/functions/fnc_handleSelectionDamage.sqf @@ -0,0 +1,11 @@ +// by commy2 +#include "script_component.hpp" + +params ["_unit", "_selection", "_newDamage", "_projectile"]; + +private "_totalDamage"; +_totalDamage = (_unit getHit _selection) + _newDamage; + +_unit setHit [_selection, _totalDamage]; + +systemChat format ["selection: %1", _this];