diff --git a/addons/gforces/functions/fnc_pfhUpdateGForces.sqf b/addons/gforces/functions/fnc_pfhUpdateGForces.sqf index f4f7c4becd..89e49fe7e5 100644 --- a/addons/gforces/functions/fnc_pfhUpdateGForces.sqf +++ b/addons/gforces/functions/fnc_pfhUpdateGForces.sqf @@ -69,7 +69,7 @@ private _gBlackOut = MAXVIRTUALG / _classCoef + MAXVIRTUALG / _suitCoef - MAXVIR // Unconsciousness if ((_average > _gBlackOut) and {isClass (configFile >> "CfgPatches" >> "ACE_Medical") and {!(ACE_player getVariable ["ACE_isUnconscious", false])}}) then { - [ACE_player, true, (10 + floor(random 5))] call EFUNC(medical,setUnconscious); + [ACE_player, true, (10 + floor(random 5)), true] call EFUNC(medical,setUnconscious); }; GVAR(GForces_CC) ppEffectAdjust [1,1,0,[0,0,0,1],[0,0,0,0],[1,1,1,1],[10,10,0,0,0,0.1,0.5]]; diff --git a/addons/medical/ACE_Medical_StateMachine.hpp b/addons/medical/ACE_Medical_StateMachine.hpp index 6d551aad0f..3e9848ef6f 100644 --- a/addons/medical/ACE_Medical_StateMachine.hpp +++ b/addons/medical/ACE_Medical_StateMachine.hpp @@ -10,7 +10,11 @@ class ACE_Medical_StateMachine { }; class CriticalInjuryOrVitals { targetState = "Unconscious"; - events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals)}; + events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals), QGVAR(knockOut)}; + }; + class FatalVitals { + targetState = "CardiacArrest"; + events[] = {QGVAR(FatalVitals)}; }; class FatalInjury { targetState = "FatalInjury"; @@ -25,7 +29,7 @@ class ACE_Medical_StateMachine { }; class CriticalInjuryOrVitals { targetState = "Unconscious"; - events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals)}; + events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals), QGVAR(knockOut)}; }; class FatalVitals { targetState = "CardiacArrest"; @@ -38,12 +42,12 @@ class ACE_Medical_StateMachine { }; class Unconscious { onState = QUOTE(DFUNC(handleStateUnconscious)); - onStateEntered = QUOTE([ARR_2(_this,(true))] call FUNC(setUnconscious)); + onStateEntered = QUOTE([ARR_2(_this,(true))] call FUNC(setUnconsciousStatemachine)); class WakeUp { targetState = "Injured"; condition = QUOTE(_this call FUNC(hasStableVitals)); events[] = {QGVAR(WakeUp)}; - onTransition = QUOTE([ARR_2(_this,(false))] call FUNC(setUnconscious)); + onTransition = QUOTE([ARR_2(_this,(false))] call FUNC(setUnconsciousStatemachine)); }; class FatalTransitions { targetState = "CardiacArrest"; diff --git a/addons/medical/ACE_Settings.hpp b/addons/medical/ACE_Settings.hpp index b5c1c80d1a..d9ff8fe073 100644 --- a/addons/medical/ACE_Settings.hpp +++ b/addons/medical/ACE_Settings.hpp @@ -251,4 +251,11 @@ class ACE_Settings { value = 0; values[] = {"No", "Yes"}; }; + class GVAR(spontaneousWakeUpChance) { + category = CSTRING(Category_Medical); + displayName = CSTRING(MedicalSettings_spontaneousWakeUpChance_DisplayName); + description = CSTRING(MedicalSettings_spontaneousWakeUpChance_Description); + typeName = "SCALAR"; + value = 0; + }; }; diff --git a/addons/medical/CfgVehicles.hpp b/addons/medical/CfgVehicles.hpp index dbf1e2114e..c5a2e54f57 100644 --- a/addons/medical/CfgVehicles.hpp +++ b/addons/medical/CfgVehicles.hpp @@ -452,6 +452,12 @@ class CfgVehicles { }; }; }; + class spontaneousWakeUpChance { + displayName = CSTRING(MedicalSettings_spontaneousWakeUpChance_DisplayName); + description = CSTRING(MedicalSettings_spontaneousWakeUpChance_Description); + typeName = "SCALAR"; + defaultValue = 0; + }; }; }; class MapBoard_altis_F; diff --git a/addons/medical/XEH_PREP.hpp b/addons/medical/XEH_PREP.hpp index 5d2f0aa195..9c40ee1b2b 100644 --- a/addons/medical/XEH_PREP.hpp +++ b/addons/medical/XEH_PREP.hpp @@ -41,6 +41,7 @@ PREP(serverRemoveBody); PREP(setCardiacArrest); PREP(setDead); PREP(setUnconscious); +PREP(setUnconsciousStatemachine); PREP(transitionSecondChance); PREP(updateHeartRate); PREP(updatePainSuppress); diff --git a/addons/medical/functions/fnc_handleStateUnconscious.sqf b/addons/medical/functions/fnc_handleStateUnconscious.sqf index b22fac1ee3..123f8f9f1f 100644 --- a/addons/medical/functions/fnc_handleStateUnconscious.sqf +++ b/addons/medical/functions/fnc_handleStateUnconscious.sqf @@ -1,4 +1,5 @@ +#define DEBUG_MODE_FULL #include "script_component.hpp" params ["_unit", "_stateName"]; @@ -21,16 +22,19 @@ if (_painLevel > 0) then { }; // Handle spontaneous wakeup from unconsciousness -if (_unit call FUNC(hasStableVitals)) then { - private _lastWakeUpCheck = _unit getVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; - if (CBA_missionTime - _lastWakeUpCheck > SPONTANEOUS_WAKE_UP_INTERVAL) then { - _unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; - if ((random 1) < SPONTANEOUS_WAKE_UP_CHANCE) then { - TRACE_1("spontaneous wake up",_unit); - [QGVAR(WakeUp), _unit] call CBA_fnc_localEvent; +if (GVAR(spontaneousWakeUpChance) > 0) then { + if (_unit call FUNC(hasStableVitals)) then { + private _lastWakeUpCheck = _unit getVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; + if (CBA_missionTime - _lastWakeUpCheck > SPONTANEOUS_WAKE_UP_INTERVAL) then { + TRACE_2("Checking for wake up",_unit,GVAR(spontaneousWakeUpChance)); + _unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; + if ((random 1) < GVAR(spontaneousWakeUpChance)) then { + TRACE_1("Spontaneous wake up!",_unit); + [QGVAR(WakeUp), _unit] call CBA_fnc_localEvent; + }; }; + } else { + // Unstable vitals, procrastinate the next wakeup check + _unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; }; -} else { - // Unstable vitals, procrastinate the next wakeup check - _unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; }; diff --git a/addons/medical/functions/fnc_moduleMedicalSettings.sqf b/addons/medical/functions/fnc_moduleMedicalSettings.sqf index 8c518ac37d..c684515147 100644 --- a/addons/medical/functions/fnc_moduleMedicalSettings.sqf +++ b/addons/medical/functions/fnc_moduleMedicalSettings.sqf @@ -54,6 +54,8 @@ if !(_activated) exitWith {}; [_logic, QGVAR(ivFlowRate), "ivFlowRate"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(allowSelfIV), "allowSelfIV"] call EFUNC(common,readSettingFromModule); +[_logic, QGVAR(spontaneousWakeUpChance), "spontaneousWakeUpChance"] call EFUNC(common,readSettingFromModule); + //[_logic, QGVAR(allowLitterCreation), "allowLitterCreation"] call EFUNC(common,readSettingFromModule); //[_logic, QGVAR(litterCleanUpDelay), "litterCleanUpDelay"] call EFUNC(common,readSettingFromModule); diff --git a/addons/medical/functions/fnc_setCardiacArrest.sqf b/addons/medical/functions/fnc_setCardiacArrest.sqf index 9354784662..5bcae1a680 100644 --- a/addons/medical/functions/fnc_setCardiacArrest.sqf +++ b/addons/medical/functions/fnc_setCardiacArrest.sqf @@ -23,8 +23,8 @@ _unit setVariable [QGVAR(heartRate), 0, true]; ["ace_cardiacArrestEntered", [_unit]] call CBA_fnc_localEvent; -[_unit, true] call FUNC(setUnconscious); -[QEGVAR(medical,InjuryCritical), _unit] call CBA_fnc_localEvent; +[_unit, true] call FUNC(setUnconsciousStatemachine); + private _timeInCardiacArrest = 120 + round(random(600)); [{ diff --git a/addons/medical/functions/fnc_setUnconscious.sqf b/addons/medical/functions/fnc_setUnconscious.sqf index a4b4ed8f5d..8d9fd5b39f 100644 --- a/addons/medical/functions/fnc_setUnconscious.sqf +++ b/addons/medical/functions/fnc_setUnconscious.sqf @@ -1,19 +1,24 @@ /* * Author: Glowbal * Sets a unit in the unconscious state. + * For Public Use * * Arguments: * 0: The unit that will be put in an unconscious state * 1: Set unconsciouns (default: true) + * 2: Minimum unconscious time (set to 0 to ignore) (default: 0) + * 3: Force wakeup at given time if vitals are stable (default: false) * * ReturnValue: * Success? * * Example: * [bob, true] call ace_medical_fnc_setUnconscious; + * [player, true, 5, true] call ace_medical_fnc_setUnconscious; * * Public: yes */ +#define DEBUG_MODE_FULL #include "script_component.hpp" // only run this after the settings are initialized @@ -21,41 +26,50 @@ if !(EGVAR(common,settingsInitFinished)) exitWith { EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this]; }; -params ["_unit", ["_knockOut", true]]; - -if (isNull _unit || {!(_unit isKindOf "CAManBase")}) exitWith {false}; +params ["_unit", ["_knockOut", true, [false]], ["_minWaitingTime", 0, [0]], ["_forcedWakup", false, [false]]]; +TRACE_4("setUnconscious",_unit,_knockOut,_minWaitingTime,_forcedWakup); +if ((isNull _unit) || {!alive _unit} || {!(_unit isKindOf "CAManBase")}) exitWith { + ERROR_3("Bad Unit %1 [Type: %2] [Alive: %3]",_unit,typeOf _unit,alive _unit); + false +}; if (!local _unit) exitWith { [QGVAR(setUnconscious), [_unit, _knockOut], _unit] call CBA_fnc_targetEvent; true }; - -if (_knockOut isEqualTo (_unit getVariable [QGVAR(isUnconscious), false])) exitWith {false}; - -// --- wake up -if !(_knockOut) exitWith { - _unit setVariable [QGVAR(isUnconscious), false, true]; - - [_unit, false] call EFUNC(medical_engine,setUnconsciousAnim); - ["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent; - - true +if (_knockOut isEqualTo (_unit getVariable [QGVAR(isUnconscious), false])) exitWith { + WARNING_2("setUnconscious called with no change [Unit %1] [State [%2]", _unit, _knockOut); + false }; -// --- knock out -_unit setVariable [QGVAR(isUnconscious), true, true]; -_unit setVariable [QGVAR(lastWakeUpCheck), CBA_missiontime]; +private _beforeState = [_unit, GVAR(STATE_MACHINE)] call CBA_statemachine_fnc_getCurrentState; -if (_unit == ACE_player) then { - if (visibleMap) then {openMap false}; - while {dialog} do { - closeDialog 0; +if (_knockOut) then { + if (_minWaitingTime > 0) then { + if (_forcedWakup) then { + // If unit still has stable vitals at min waiting time, then force wake up + [{ + params [["_unit", objNull]]; + if ((alive _unit) && {_unit call FUNC(hasStableVitals)}) then { + TRACE_1("Doing delay wakeup",_unit); + [QGVAR(WakeUp), _unit] call CBA_fnc_localEvent; + } else { + TRACE_1("Skipping delay wakeup",_unit); + }; + }, [_unit], _minWaitingTime] call CBA_fnc_waitAndExecute; + }; + if (GVAR(spontaneousWakeUpChance) > 0) then { + _unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime + _minWaitingTime - SPONTANEOUS_WAKE_UP_INTERVAL]; + }; }; + + [QGVAR(knockOut), _unit] call CBA_fnc_localEvent; +} else { + [QGVAR(WakeUp), _unit] call CBA_fnc_localEvent; }; -[_unit, true] call EFUNC(medical_engine,setUnconsciousAnim); -[QGVAR(Unconscious), _unit] call CBA_fnc_localEvent; -["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent; +private _afterState = [_unit, GVAR(STATE_MACHINE)] call CBA_statemachine_fnc_getCurrentState; +TRACE_2("state change",_beforeState,_afterState); true diff --git a/addons/medical/functions/fnc_setUnconsciousStatemachine.sqf b/addons/medical/functions/fnc_setUnconsciousStatemachine.sqf new file mode 100644 index 0000000000..cb21188466 --- /dev/null +++ b/addons/medical/functions/fnc_setUnconsciousStatemachine.sqf @@ -0,0 +1,50 @@ +/* + * Author: Glowbal + * Sets a unit in the unconscious state. + * For Internal Use: Called from the state machine. + * + * Arguments: + * 0: The unit that will be put in an unconscious state + * 1: Set unconsciouns + * + * ReturnValue: + * Success? + * + * Example: + * [bob, true] call ace_medical_fnc_setUnconsciousStatemachine + * + * Public: No + */ +#define DEBUG_MODE_FULL +#include "script_component.hpp" + +params ["_unit", "_knockOut"]; +TRACE_2("setUnconsciousStatemachine",_unit,_knockOut); + +if (_knockOut isEqualTo (_unit getVariable [QGVAR(isUnconscious), false])) exitWith {TRACE_1("No Change - Exiting",_knockOut);}; + +_unit setVariable [QGVAR(isUnconscious), _knockOut, true]; +["ace_unconscious", [_unit, _knockOut]] call CBA_fnc_globalEvent; +[_unit, _knockOut] call EFUNC(medical_engine,setUnconsciousAnim); + + +if (_knockOut) then { + // --- knock out + if (GVAR(spontaneousWakeUpChance) > 0) then { // Don't bother setting this if not used + private _lastWakeUpCheck = CBA_missiontime max (_unit getVariable [QGVAR(lastWakeUpCheck), 0]); + TRACE_2("setting lastWakeUpCheck",_lastWakeUpCheck,(_lastWakeUpCheck - CBA_missiontime)); + _unit setVariable [QGVAR(lastWakeUpCheck), _lastWakeUpCheck]; + }; + + if (_unit == ACE_player) then { + if (visibleMap) then {openMap false}; + + while {dialog} do { + closeDialog 0; + }; + }; + [QGVAR(Unconscious), _unit] call CBA_fnc_localEvent; +} else { + // --- wake up + _unit setVariable [QGVAR(lastWakeUpCheck), nil]; // clear this now (min wait time could be set to a very high value) +}; diff --git a/addons/medical/script_macros_medical.hpp b/addons/medical/script_macros_medical.hpp index a22f7fafc8..84b94f647b 100644 --- a/addons/medical/script_macros_medical.hpp +++ b/addons/medical/script_macros_medical.hpp @@ -45,7 +45,6 @@ #define PAIN_SUPPRESSION_FADE_TIME 1800 // Chance to wake up when vitals are stable (checked once every SPONTANEOUS_WAKE_UP_INTERVAL seconds) -#define SPONTANEOUS_WAKE_UP_CHANCE 0.2 #define SPONTANEOUS_WAKE_UP_INTERVAL 15 #define LETHAL_HEAD_DAMAGE_THRESHOLD 1.0 diff --git a/addons/medical/stringtable.xml b/addons/medical/stringtable.xml index 3fbe015919..961daf8d29 100644 --- a/addons/medical/stringtable.xml +++ b/addons/medical/stringtable.xml @@ -4055,5 +4055,11 @@ Allow Unconscious Animation on Treatment. + + Unconscious Wake Up Chance + + + Probablity that a unit with stable vitals will wake up from unconscious [Checked every 15 sec] + diff --git a/addons/zeus/functions/fnc_moduleUnconscious.sqf b/addons/zeus/functions/fnc_moduleUnconscious.sqf index 0cf0fffda6..35b300e989 100644 --- a/addons/zeus/functions/fnc_moduleUnconscious.sqf +++ b/addons/zeus/functions/fnc_moduleUnconscious.sqf @@ -38,7 +38,7 @@ if (isNil QEFUNC(medical,setUnconscious)) then { } else { _conscious = GETVAR(_unit,ACE_isUnconscious,false); // Function handles locality for me - [_unit, !_conscious, 10e10, true] call EFUNC(medical,setUnconscious); + [_unit, !_conscious, 10e10] call EFUNC(medical,setUnconscious); }; }; };