diff --git a/addons/medical/ACE_Settings.hpp b/addons/medical/ACE_Settings.hpp index ef4a4f0162..a3e6c60167 100644 --- a/addons/medical/ACE_Settings.hpp +++ b/addons/medical/ACE_Settings.hpp @@ -22,6 +22,10 @@ class ACE_Settings { typeName = "SCALAR"; value = 1; }; + class GVAR(painCoefficient) { + typeName = "SCALAR"; + value = 1; + }; class GVAR(enableAirway) { typeName = "BOOL"; value = false; @@ -50,10 +54,10 @@ class ACE_Settings { typeName = "SCALAR"; value = 1; }; - class GVAR(enableUnsconsiousnessAI) { + class GVAR(enableUnconsiousnessAI) { value = 1; typeName = "SCALAR"; - values[] = {"Disabled", "Enabled", "50/50"}; + values[] = {"Disabled", "50/50", "Enabled"}; }; class GVAR(preventInstaDeath) { typeName = "BOOL"; diff --git a/addons/medical/CfgVehicles.hpp b/addons/medical/CfgVehicles.hpp index 6149c57afd..234947c0b6 100644 --- a/addons/medical/CfgVehicles.hpp +++ b/addons/medical/CfgVehicles.hpp @@ -87,7 +87,7 @@ class CfgVehicles { typeName = "NUMBER"; defaultValue = 1; }; - class enableUnsconsiousnessAI { + class enableUnconsiousnessAI { displayName = "AI Unconsciousness"; description = "Allow AI to go unconscious"; typeName = "NUMBER"; @@ -97,12 +97,12 @@ class CfgVehicles { value = 0; }; class normal { - name = "Enabled"; + name = "50/50"; value = 1; default = 1; }; - class full { - name = "50/50"; + class full { + name = "Enabled"; value = 2; }; }; @@ -119,6 +119,12 @@ class CfgVehicles { typeName = "NUMBER"; defaultValue = 1; }; + class painCoefficient { + displayName = "Pain coefficient"; + description = "Coefficient to modify the pain intensity"; + typeName = "NUMBER"; + defaultValue = 1; + }; class keepLocalSettingsSynced { displayName = "Sync status"; description = "Keep unit status synced. Recommended on."; diff --git a/addons/medical/XEH_postInit.sqf b/addons/medical/XEH_postInit.sqf index 386eb4de93..1bb0e744bc 100644 --- a/addons/medical/XEH_postInit.sqf +++ b/addons/medical/XEH_postInit.sqf @@ -133,7 +133,7 @@ GVAR(effectTimeBlood) = time; }; }; - _bleeding = ACE_player call FUNC(getBloodLoss); + _bleeding = [ACE_player] call FUNC(getBloodLoss); // Bleeding Indicator if (_bleeding > 0 and GVAR(effectTimeBlood) + 3.5 < time) then { GVAR(effectTimeBlood) = time; @@ -169,7 +169,7 @@ GVAR(lastHeartBeatSound) = time; // Pain effect _strength = ACE_player getVariable [QGVAR(pain), 0]; - // _strength = _strength * (ACE_player getVariable [QGVAR(coefPain), GVAR(coefPain)]); @todo + _strength = _strength * (ACE_player getVariable [QGVAR(painCoefficient), GVAR(painCoefficient)]); if (GVAR(painEffectType) == 1) then { GVAR(effectPainCC) ppEffectEnable false; if ((ACE_player getVariable [QGVAR(pain), 0]) > 0 && {alive ACE_player}) then { @@ -253,7 +253,7 @@ if (USE_WOUND_EVENT_SYNC) then { [ {(((_this select 0) getvariable [QGVAR(bloodVolume), 100]) < 65)}, {(((_this select 0) getvariable [QGVAR(pain), 0]) > 0.9)}, - {(((_this select 0) call FUNC(getBloodLoss)) > 0.25)}, + {(([_this select 0] call FUNC(getBloodLoss)) > 0.25)}, {((_this select 0) getvariable [QGVAR(inReviveState), false])}, {((_this select 0) getvariable [QGVAR(inCardiacArrest), false])}, {((_this select 0) getvariable ["ACE_isDead", false])}, diff --git a/addons/medical/XEH_respawn.sqf b/addons/medical/XEH_respawn.sqf index ac6cc2d6ef..0a95e064fd 100644 --- a/addons/medical/XEH_respawn.sqf +++ b/addons/medical/XEH_respawn.sqf @@ -8,7 +8,13 @@ if !(local _unit) exitWith {}; [_unit] call FUNC(init); -//Reset captive status for respawning unit +// Reset captive status for respawning unit if (!(_unit getVariable ["ACE_isUnconscious", false])) then { [_unit, QGVAR(unconscious), false] call EFUNC(common,setCaptivityStatus); }; + +// Remove maximum unconsciousness time handler +_maxUnconHandle = _unit getVariable [QGVAR(maxUnconTimeHandle), -1]; +if (_maxUnconHandle > 0) then { + [_maxUnconHandle] call CBA_fnc_removePerFrameHandler; +}; diff --git a/addons/medical/functions/fnc_getBloodLoss.sqf b/addons/medical/functions/fnc_getBloodLoss.sqf index 414b3a47c7..1881643d97 100644 --- a/addons/medical/functions/fnc_getBloodLoss.sqf +++ b/addons/medical/functions/fnc_getBloodLoss.sqf @@ -15,15 +15,17 @@ #define BLOODLOSSRATE_BASIC 0.2 -private ["_totalBloodLoss","_tourniquets","_openWounds", "_cardiacOutput", "_internalWounds"]; +private ["_unit", "_totalBloodLoss","_tourniquets","_openWounds", "_cardiacOutput", "_internalWounds"]; // TODO Only use this calculation if medium or higher, otherwise use vanilla calculations (for basic medical). + +_unit = _this select 0; _totalBloodLoss = 0; // Advanced medical bloodloss handling if (GVAR(level) >= 2) then { - _tourniquets = _this getvariable [QGVAR(tourniquets), [0,0,0,0,0,0]]; - _openWounds = _this getvariable [QGVAR(openWounds), []]; - //_cardiacOutput = [_this] call FUNC(getCardiacOutput); + _tourniquets = _unit getvariable [QGVAR(tourniquets), [0,0,0,0,0,0]]; + _openWounds = _unit getvariable [QGVAR(openWounds), []]; + //_cardiacOutput = [_unit] call FUNC(getCardiacOutput); { if ((_tourniquets select (_x select 2)) == 0) then { @@ -34,7 +36,7 @@ if (GVAR(level) >= 2) then { }; }foreach _openWounds; - _internalWounds = _this getvariable [QGVAR(internalWounds), []]; + _internalWounds = _unit getvariable [QGVAR(internalWounds), []]; { _totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3)); }foreach _internalWounds; @@ -42,6 +44,6 @@ if (GVAR(level) >= 2) then { // cap the blood loss to be no greater as the current cardiac output //(_totalBloodLoss min _cardiacOutput); } else { - _totalBloodLoss = BLOODLOSSRATE_BASIC * (damage _this); + _totalBloodLoss = BLOODLOSSRATE_BASIC * (damage _unit); }; -_totalBloodLoss * (GVAR(bleedingCoefficient) max 0); +_totalBloodLoss * ((_unit getVariable [QGVAR(bleedingCoefficient), GVAR(bleedingCoefficient)]) max 0); diff --git a/addons/medical/functions/fnc_getBloodVolumeChange.sqf b/addons/medical/functions/fnc_getBloodVolumeChange.sqf index f94c5d5b7b..23eba4a0c7 100644 --- a/addons/medical/functions/fnc_getBloodVolumeChange.sqf +++ b/addons/medical/functions/fnc_getBloodVolumeChange.sqf @@ -34,7 +34,7 @@ private ["_unit","_bloodVolume","_bloodVolumeChange", "_ivVolume"]; _unit = _this select 0; _bloodVolume = _unit getvariable [QGVAR(bloodVolume), 100]; -_bloodVolumeChange = -(_unit call FUNC(getBloodLoss)); +_bloodVolumeChange = -([_unit] call FUNC(getBloodLoss)); if (_bloodVolume < 100.0) then { { diff --git a/addons/medical/functions/fnc_getHeartRateChange.sqf b/addons/medical/functions/fnc_getHeartRateChange.sqf index 7429d6dd43..92a2053737 100644 --- a/addons/medical/functions/fnc_getHeartRateChange.sqf +++ b/addons/medical/functions/fnc_getHeartRateChange.sqf @@ -20,7 +20,7 @@ _unit = _this select 0; _hrIncrease = 0; if (!(_unit getvariable [QGVAR(inCardiacArrest),false])) then { _heartRate = _unit getvariable [QGVAR(heartRate), 80]; - _bloodLoss = _unit call FUNC(getBloodLoss); + _bloodLoss = [_unit] call FUNC(getBloodLoss); _adjustment = _unit getvariable [QGVAR(heartRateAdjustments), []]; { @@ -83,4 +83,4 @@ if (!(_unit getvariable [QGVAR(inCardiacArrest),false])) then { _hrIncrease = _hrIncrease - HEART_RATE_MODIFIER; }; }; -_hrIncrease \ No newline at end of file +_hrIncrease diff --git a/addons/medical/functions/fnc_handleDamage.sqf b/addons/medical/functions/fnc_handleDamage.sqf index d457762321..1d8c821d1f 100644 --- a/addons/medical/functions/fnc_handleDamage.sqf +++ b/addons/medical/functions/fnc_handleDamage.sqf @@ -17,12 +17,12 @@ #include "script_component.hpp" -private ["_unit", "_selection", "_damage", "_shooter", "_projectile", "_damageReturn", "_typeOfDamage", "_minLethalDamage", "_newDamage", "_typeIndex"]; -_unit = _this select 0; -_selection = _this select 1; -_damage = _this select 2; -_shooter = _this select 3; -_projectile = _this select 4; +private ["_unit", "_selection", "_damage", "_shooter", "_projectile", "_damageReturn", "_typeOfDamage", "_minLethalDamage", "_newDamage", "_typeIndex", "_preventDeath"]; +_unit = _this select 0; +_selection = _this select 1; +_damage = _this select 2; +_shooter = _this select 3; +_projectile = _this select 4; if !(local _unit) exitWith {nil}; @@ -34,6 +34,30 @@ if (typeName _projectile == "OBJECT") then { // If the damage is being weird, we just tell it to fuck off. if !(_selection in (GVAR(SELECTIONS) + [""])) exitWith {0}; +// Exit if we disable damage temporarily +_damageOld = damage _unit; +if (_selection in GVAR(SELECTIONS)) then { + _damageOld = _unit getHit _selection; +}; +if !(_unit getVariable [QGVAR(allowDamage), true]) exitWith {_damageOld}; + +// Figure out whether to prevent death before handling damage +if (diag_frameno > (_unit getVariable [QGVAR(frameNo), -3]) + 2) then { + _unit setVariable [QGVAR(frameNo), diag_frameno]; + _unit setVariable [QGVAR(wasUnconscious), _unit getVariable ["ACE_isUnconscious", false]]; + + _preventDeath = _unit getVariable [QGVAR(preventInstaDeath), GVAR(preventInstaDeath)]; + if (_unit getVariable ["ACE_isUnconscious", false]) then { + _preventDeath = _unit getVariable [QGVAR(enableRevive), GVAR(enableRevive)]; + if !([_unit] call EFUNC(common,isPlayer)) then { + _preventDeath = _preventDeath - 1; + }; + _preventDeath = _preventDeath > 0; + }; + _unit setVariable [QGVAR(preventDeath), _preventDeath]; +}; + +// Get return damage _damageReturn = _damage; if (GVAR(level) < 2) then { _damageReturn = _this call FUNC(handleDamage_basic); @@ -73,26 +97,30 @@ if (GVAR(level) < 2) then { }; [_unit] call FUNC(addToInjuredCollection); -if (_unit getVariable [QGVAR(preventInstaDeath), GVAR(preventInstaDeath)]) exitWith { - if (_damageReturn >= 0.9 && {_selection in ["", "head", "body"]}) exitWith { - if (_unit getvariable ["ACE_isUnconscious", false]) exitwith { +// Prevent death if necessary +if (_unit getVariable QGVAR(preventDeath)) then { + if (_selection in ["", "head", "body"]) then { + _damageReturn = _damageReturn min 0.89; + }; + + // Move the unit out of the vehicle if necessary + if (vehicle _unit != _unit and damage (vehicle _unit) == 1) then { + [_unit] call EFUNC(common,unloadPerson); + if (_unit getVariable QGVAR(wasUnconscious)) then { [_unit] call FUNC(setDead); - 0.89 + } else { + [_unit, true] call FUNC(setUnconscious); }; - [{ [_this select 0, true] call FUNC(setUnconscious); }, [_unit]] call EFUNC(common,execNextFrame); - 0.89 }; - _damageReturn min 0.89; -}; -if (((_unit getVariable [QGVAR(enableRevive), GVAR(enableRevive)]) > 0) && {_damageReturn >= 0.9} && {_selection in ["", "head", "body"]}) exitWith { - if (vehicle _unit != _unit and {damage (vehicle _unit) >= 1}) then { - // @todo - // [_unit] call FUNC(unload); + // Temporarily disable all damage to prevent stuff like + // being killed during the animation etc. + if (!_wasUnconscious and (_unit getVariable ["ACE_isUnconscious", false])) then { + _unit setVariable [QGVAR(allowDamage), false]; + [{ + _this setVariable [QGVAR(allowDamage), true]; + }, _unit, 0.7, 0] call EFUNC(common,waitAndExecute); }; - [_unit] call FUNC(setDead); - - 0.89 }; _damageReturn diff --git a/addons/medical/functions/fnc_handleDamage_basic.sqf b/addons/medical/functions/fnc_handleDamage_basic.sqf index 1647cc8442..7b308ad188 100644 --- a/addons/medical/functions/fnc_handleDamage_basic.sqf +++ b/addons/medical/functions/fnc_handleDamage_basic.sqf @@ -26,22 +26,28 @@ private ["_unit", "_selectionName", "_damage", "_shooter", "_projectile", "_damage", "_armdamage", "_hitPoint", "_index", "_legdamage", "_newDamage", "_otherDamage", "_pain", "_restore"]; -_unit = _this select 0; -_selectionName = _this select 1; -_damage = _this select 2; -_shooter = _this select 3; -_projectile = _this select 4; +_unit = _this select 0; +_selectionName = _this select 1; +_damage = _this select 2; +_shooter = _this select 3; +_projectile = _this select 4; + +// Apply damage treshold / coefficient +_threshold = [ + _unit getVariable [QGVAR(damageThreshold), GVAR(AIDamageThreshold)], + _unit getVariable [QGVAR(damageThreshold), GVAR(playerDamageThreshold)] +] select ([_unit] call EFUNC(common,isPlayer)); +_damage = _damage * (1 / _threshold); // This is a new hit, reset variables. // Note: sometimes handleDamage spans over 2 or even 3 frames. -if (diag_frameno > (_unit getVariable [QGVAR(frameNo), -3]) + 2) then { - _unit setVariable [QGVAR(frameNo), diag_frameno]; +if (diag_frameno > (_unit getVariable [QGVAR(basic_frameNo), -3]) + 2) then { + _unit setVariable [QGVAR(basic_frameNo), diag_frameno]; _unit setVariable [QGVAR(isFalling), false]; _unit setVariable [QGVAR(projectiles), []]; _unit setVariable [QGVAR(hitPoints), []]; _unit setVariable [QGVAR(damages), []]; _unit setVariable [QGVAR(structDamage), 0]; - _unit setVariable [QGVAR(preventDeath), false]; // Assign orphan structural damage to torso [{ private ["_unit", "_damagesum"]; @@ -172,11 +178,7 @@ if (_selectionName == "" and _damage < 1 and !(_unit getVariable ["ACE_isUnconscious", False] )) then { - if (_unit getVariable [QGVAR(allowUnconscious), ([_unit] call EFUNC(common,isPlayer)) or random 1 > 0.3]) then { - [_unit, true] call FUNC(setUnconscious); - } else { - _damage = 1; - }; + [_unit, true] call FUNC(setUnconscious); }; _damage diff --git a/addons/medical/functions/fnc_handleUnitVitals.sqf b/addons/medical/functions/fnc_handleUnitVitals.sqf index aff3b48945..ebfb8be746 100644 --- a/addons/medical/functions/fnc_handleUnitVitals.sqf +++ b/addons/medical/functions/fnc_handleUnitVitals.sqf @@ -49,7 +49,7 @@ if (_bloodVolume < 100) then { }; }; -if ((_unit call FUNC(getBloodLoss)) > 0) then { +if (([_unit] call FUNC(getBloodLoss)) > 0) then { if !(_unit getvariable [QGVAR(isBleeding), false]) then { _unit setvariable [QGVAR(isBleeding), true, true]; }; diff --git a/addons/medical/functions/fnc_moduleMedicalSettings.sqf b/addons/medical/functions/fnc_moduleMedicalSettings.sqf index 0d514aee27..ad8fbba18a 100644 --- a/addons/medical/functions/fnc_moduleMedicalSettings.sqf +++ b/addons/medical/functions/fnc_moduleMedicalSettings.sqf @@ -29,7 +29,8 @@ if !(_activated) exitWith {}; [_logic, QGVAR(enableScreams), "enableScreams"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(playerDamageThreshold), "playerDamageThreshold"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(AIDamageThreshold), "AIDamageThreshold"] call EFUNC(common,readSettingFromModule); -[_logic, QGVAR(enableUnsconsiousnessAI), "enableUnsconsiousnessAI"] call EFUNC(common,readSettingFromModule); +[_logic, QGVAR(enableUnconsiousnessAI), "enableUnconsiousnessAI"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(preventInstaDeath), "preventInstaDeath"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(bleedingCoefficient), "bleedingCoefficient"] call EFUNC(common,readSettingFromModule); +[_logic, QGVAR(painCoefficient), "painCoefficient"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(keepLocalSettingsSynced), "keepLocalSettingsSynced"] call EFUNC(common,readSettingFromModule); diff --git a/addons/medical/functions/fnc_setUnconscious.sqf b/addons/medical/functions/fnc_setUnconscious.sqf index 82e93eb1fb..0e0e6cf67e 100644 --- a/addons/medical/functions/fnc_setUnconscious.sqf +++ b/addons/medical/functions/fnc_setUnconscious.sqf @@ -22,6 +22,9 @@ _unit = _this select 0; _set = if (count _this > 1) then {_this select 1} else {true}; _minWaitingTime = if (count _this > 2) then {_this select 2} else {DEFAULT_DELAY}; +// No change, fuck off. (why is there no xor?) +if (_set isEqualTo (_unit getVariable ["ACE_isUnconscious", false])) exitWith {}; + if !(_set) exitwith { _unit setvariable ["ACE_isUnconscious", false, true]; }; @@ -43,16 +46,17 @@ if (_unit == ACE_player) then { }; // if we have unconsciousness for AI disabled, we will kill the unit instead -if (!([_unit] call EFUNC(common,IsPlayer)) && (GVAR(enableUnsconsiousnessAI) == 0 || (GVAR(enableUnsconsiousnessAI) == 2 && random(1) <= 0.5))) exitwith { - [_unit, true] call FUNC(setDead); // force, to avoid getting into a loop in case revive is enabled. +if !([_unit] call EFUNC(common,isPlayer)) then { + _enableUncon = _unit getVariable [QGVAR(enableUnconsciousnessAI), GVAR(enableUnconsciousnessAI)]; + if (_enableUncon == 0 or {_enableUncon == 1 and (random 1) < 0.5}) exitWith { + [_unit, true] call FUNC(setDead); + }; }; // If a unit has the launcher out, it will sometimes start selecting the primairy weapon while unconscious, // therefor we force it to select the primairy weapon before going unconscious if ((vehicle _unit) isKindOf "StaticWeapon") then { - moveOut _unit; - unassignVehicle _unit; - //_unit action ["eject", vehicle _unit]; + [_unit] call EFUNC(common,unloadPerson); }; if (animationState _unit in ["ladderriflestatic","laddercivilstatic"]) then { _unit action ["ladderOff", (nearestBuilding _unit)]; @@ -62,8 +66,6 @@ if (vehicle _unit == _unit) then { _unit addWeapon "ACE_FakePrimaryWeapon"; }; _unit selectWeapon (primaryWeapon _unit); - _unit switchMove ""; - _unit playmoveNow ""; }; // We are storing the current animation, so we can use it later on when waking the unit up inside a vehicle @@ -80,7 +82,15 @@ if (GVAR(moveUnitsFromGroupOnUnconscious)) then { }; [_unit, QGVAR(unconscious), true] call EFUNC(common,setCaptivityStatus); -[_unit, [_unit] call EFUNC(common,getDeathAnim), 1, true] call EFUNC(common,doAnimation); +_anim = [_unit] call EFUNC(common,getDeathAnim); +[_unit, _anim, 1, true] call EFUNC(common,doAnimation); +[{ + _unit = _this select 0; + _anim = _this select 1; + if ((_unit getVariable "ACE_isUnconscious") and (animationState _unit != _anim)) then { + [_unit, _anim, 2, true] call EFUNC(common,doAnimation); + }; +}, [_unit, _anim], 0.5, 0] call EFUNC(common,waitAndExecute); _startingTime = time;