diff --git a/addons/medical/XEH_preInit.sqf b/addons/medical/XEH_preInit.sqf index b479383468..6ae9dbb866 100644 --- a/addons/medical/XEH_preInit.sqf +++ b/addons/medical/XEH_preInit.sqf @@ -2,6 +2,8 @@ ADDON = false; +PREP(handleDamage_basic2); + PREP(actionCheckBloodPressure); PREP(actionCheckBloodPressureLocal); PREP(actionCheckPulse); diff --git a/addons/medical/functions/fnc_handleDamage.sqf b/addons/medical/functions/fnc_handleDamage.sqf index a4e5525276..47234d09fd 100644 --- a/addons/medical/functions/fnc_handleDamage.sqf +++ b/addons/medical/functions/fnc_handleDamage.sqf @@ -44,7 +44,34 @@ if !(_unit getVariable [QGVAR(allowDamage), true]) exitWith {_damageOld}; // Get return damage _damageReturn = _damage; if (GVAR(level) < 2) then { - _damageReturn = _this call FUNC(handleDamage_basic); + _newDamage = _this call FUNC(handleDamage_basic2); + _projectile = _this select 4; + _typeOfDamage = [_projectile] call FUNC(getTypeOfDamage); + + _typeIndex = (GVAR(allAvailableDamageTypes) find _typeOfDamage); + _minLethalDamage = 0.01; + if (_typeIndex >= 0) then { + _minLethalDamage = GVAR(minLethalDamages) select _typeIndex; + }; + + if (vehicle _unit != _unit && {!(vehicle _unit isKindOf "StaticWeapon")} && {isNull _shooter} && {_projectile == ""} && {_selection == ""}) then { + if (GVAR(enableVehicleCrashes)) then { + _selection = GVAR(SELECTIONS) select (floor(random(count GVAR(SELECTIONS)))); + }; + }; + + if ((_minLethalDamage <= _newDamage) && {[_unit, [_selection] call FUNC(selectionNameToNumber), _newDamage] call FUNC(determineIfFatal)}) then { + if ((_unit getVariable [QGVAR(preventInstaDeath), GVAR(preventInstaDeath)])) exitwith { + _damageReturn = 0.9; + }; + if ([_unit] call FUNC(setDead)) then { + _damageReturn = 1; + } else { + _damageReturn = _damageReturn min 0.89; + }; + } else { + _damageReturn = _damageReturn min 0.89; + }; } else { if !([_unit] call FUNC(hasMedicalEnabled)) exitwith { // Because of the config changes, we cannot properly disable the medical system for a unit. diff --git a/addons/medical/functions/fnc_handleDamage_basic.sqf b/addons/medical/functions/fnc_handleDamage_basic.sqf index 04049cfa7c..9b48a5d5c7 100644 --- a/addons/medical/functions/fnc_handleDamage_basic.sqf +++ b/addons/medical/functions/fnc_handleDamage_basic.sqf @@ -37,6 +37,8 @@ _threshold = [ _unit getVariable [QGVAR(damageThreshold), GVAR(AIDamageThreshold)], _unit getVariable [QGVAR(damageThreshold), GVAR(playerDamageThreshold)] ] select ([_unit] call EFUNC(common,isPlayer)); +if (_selectionName in ["leg_l", "leg_r", "hand_l", "hand_r"]) then {_threshold = _threshold * 1.7}; + _damage = _damage * (1 / _threshold); // This is a new hit, reset variables. @@ -63,7 +65,7 @@ if (diag_frameno > (_unit getVariable [QGVAR(basic_frameNo), -3]) + 2) then { (_unit getHitPointDamage "HitLeftLeg") + (_unit getHitPointDamage "HitRightLeg"); if (_damagesum < 0.06 and damage _unit > 0.06 and alive _unit) then { - _unit setHitPointDamage ["HitBody", damage _unit]; + // _unit setHitPointDamage ["HitBody", damage _unit]; }; [(_this select 1)] call cba_fnc_removePerFrameHandler; }; diff --git a/addons/medical/functions/fnc_handleDamage_basic2.sqf b/addons/medical/functions/fnc_handleDamage_basic2.sqf new file mode 100644 index 0000000000..9da6fd405d --- /dev/null +++ b/addons/medical/functions/fnc_handleDamage_basic2.sqf @@ -0,0 +1,168 @@ +/* + * Author: KoffeinFlummi, Glowbal + * Cache a handleDamage call to execute it 3 frames later + * + * Arguments: + * 0: Unit That Was Hit + * 1: Name Of Hit Selection + * 2: Amount Of Damage + * 3: Shooter + * 4: Projectile + * 5: Current damage to be returned + * + * Return Value: + * + * + * Public: No + */ + +#include "script_component.hpp" + +private ["_unit", "_selectionName", "_damage", "_source", "_projectile", "_hitSelections", "_hitPoints", "_impactVelocity", "_newDamage", "_cache_hitpoints", "_cache_projectiles", "_cache_params", "_cache_damages"]; +_unit = _this select 0; +_selectionName = _this select 1; +_damage = _this select 2; +_source = _this select 3; +_projectile = _this select 4; + +_hitSelections = GVAR(SELECTIONS); +_hitPoints = GVAR(HITPOINTS); + +// Calculate change in damage. +_newDamage = _damage - (damage _unit); +if (_selectionName in _hitSelections) then { + _newDamage = _damage - (_unit getHitPointDamage (_hitPoints select (_hitSelections find _selectionName))); +}; + +//_damage = _damage + _newDamage; + +// Check for vehicle crash +if (vehicle _unit != _unit && {!(vehicle _unit isKindOf "StaticWeapon")} && {isNull _source} && {_projectile == ""} && {_selectionName == ""}) then { + if (GVAR(enableVehicleCrashes)) then { + _selectionName = _hitSelections select (floor(random(count _hitSelections))); + _projectile = "vehiclecrash"; + _this set [1, _selectionName]; + _this set [4, _projectile]; + }; +}; + +// Handle falling damage +_impactVelocity = (velocity _unit) select 2; +if (_impactVelocity < -5 && {vehicle _unit == _unit}) then { + _unit setVariable [QGVAR(isFalling), true]; + _unit setVariable [QGVAR(impactVelocity), _impactVelocity]; +}; +if (_unit getVariable [QGVAR(isFalling), false]) then { + if !(_selectionName in ["", "leg_l", "leg_r"]) then { + if (_selectionName == "body") then { + _newDamage = _newDamage * abs(_unit getVariable [QGVAR(impactVelocity), _impactVelocity]) / 50; + } else { + _newDamage = _newDamage * 0.5; + }; + } else { + if (_selectionName == "") then { + _selectionName = ["leg_l", "leg_r"] select (floor(random 2)); + _this set [1, _selectionName]; + }; + _newDamage = _newDamage * 0.7; + }; + _projectile = "falling"; + _this set [4, "falling"]; +}; + +// Finished with the current frame, reset variables +// Note: sometimes handleDamage spans over 2 or even 3 frames. +if (diag_frameno > (_unit getVariable [QGVAR(frameNo_damageCaching), -3]) + 2) then { + _unit setVariable [QGVAR(frameNo_damageCaching), diag_frameno]; + + // handle the cached damages 3 frames later + [{ + params ["_args", "_id"]; + _args params ["_target", "_frameNo"]; + + if (diag_frameno > _frameNo + 2) then { + _target setDamage 0; + + _cache_params = _target getVariable [QGVAR(cachedHandleDamageParams), []]; + _cache_damages = _target getVariable QGVAR(cachedDamages); + _damageBodyParts = _target getvariable [QGVAR(bodyPartStatus), [0,0,0,0,0,0]]; + { + _x params ["_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 {}; + _damageBodyParts set [_part, (_damageBodyParts select _part) + (_cache_damages select _foreachIndex)]; + }; + }foreach _cache_params; + _unit setvariable [QGVAR(bodyPartStatus), _damageBodyParts, true]; + + EXPLODE_6_PVT(_damageBodyParts,_headDamage,_torsoDamage,_handsDamageR,_handsDamageL,_legsDamageR,_legsDamageL); + _target setHitPointDamage ["hitHead", _headDamage min 0.95]; + _target setHitPointDamage ["hitBody", _torsoDamage min 0.95]; + _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); + [_id] call cba_fnc_removePerFrameHandler; + }; + }, 0, [_unit, diag_frameno] ] call CBA_fnc_addPerFrameHandler; + + _unit setVariable [QGVAR(cachedProjectiles), []]; + _unit setVariable [QGVAR(cachedHitPoints), []]; + _unit setVariable [QGVAR(cachedDamages), []]; + _unit setVariable [QGVAR(cachedHandleDamageParams), []]; +}; + +// Caching of the damage events +if (_selectionName != "") then { + _cache_projectiles = _unit getVariable QGVAR(cachedProjectiles); + private ["_index","_otherDamage"]; + _index = _cache_projectiles find _projectile; + // Check if the current projectile has already been handled once + if (_index >= 0 && {_projectile != "falling"}) exitwith { + _cache_damages = _unit getVariable QGVAR(cachedDamages); + // Find the previous damage this projectile has done + _otherDamage = (_cache_damages select _index); + + // Take the highest damage of the two + if (_newDamage > _otherDamage) then { + _cache_params = _unit getVariable QGVAR(cachedHandleDamageParams); + _cache_hitpoints = _unit getVariable QGVAR(cachedHitPoints); + + 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]; + + _cache_hitpoints set [_index, (_hitPoints select (_hitSelections find _selectionName))]; + _cache_damages set [_index, _newDamage]; + _cache_params set[_index, _this]; + + _unit setVariable [QGVAR(cachedProjectiles), _cache_projectiles]; + _unit setVariable [QGVAR(cachedHitPoints), _cache_hitpoints]; + _unit setVariable [QGVAR(cachedDamages), _cache_damages]; + _unit setVariable [QGVAR(cachedHandleDamageParams), _cache_params]; + }; + }; + + _cache_hitpoints = _unit getVariable QGVAR(cachedHitPoints); + _cache_damages = _unit getVariable QGVAR(cachedDamages); + _cache_params = _unit getVariable QGVAR(cachedHandleDamageParams); + + // This is an unhandled projectile + _cache_projectiles pushBack _projectile; + _cache_hitpoints pushBack (_hitPoints select (_hitSelections find _selectionName)); + _cache_damages pushBack _newDamage; + _cache_params pushBack _this; + + // Store the new cached values + _unit setVariable [QGVAR(cachedProjectiles), _cache_projectiles]; + _unit setVariable [QGVAR(cachedHitPoints), _cache_hitpoints]; + _unit setVariable [QGVAR(cachedDamages), _cache_damages]; + _unit setVariable [QGVAR(cachedHandleDamageParams), _cache_params]; +}; + +_newDamage;