2018-08-02 14:02:10 +00:00
|
|
|
#include "script_component.hpp"
|
2015-02-08 09:01:32 +00:00
|
|
|
/*
|
|
|
|
* Author: Glowbal
|
2017-04-22 15:57:32 +00:00
|
|
|
* Updates the vitals. Called from the statemachine's onState functions.
|
2015-02-07 22:55:48 +00:00
|
|
|
*
|
2015-02-08 09:01:32 +00:00
|
|
|
* Arguments:
|
|
|
|
* 0: The Unit <OBJECT>
|
|
|
|
*
|
2017-06-08 13:31:51 +00:00
|
|
|
* Return Value:
|
2019-12-17 17:17:49 +00:00
|
|
|
* Update Ran (at least 1 second between runs) <BOOL>
|
2017-06-08 13:31:51 +00:00
|
|
|
*
|
|
|
|
* Example:
|
2018-05-08 08:17:47 +00:00
|
|
|
* [player] call ace_medical_vitals_fnc_handleUnitVitals
|
2017-04-22 15:57:32 +00:00
|
|
|
*
|
2015-02-08 09:01:32 +00:00
|
|
|
* Public: No
|
2015-02-07 22:55:48 +00:00
|
|
|
*/
|
|
|
|
|
2016-12-05 20:34:20 +00:00
|
|
|
params ["_unit"];
|
2016-10-12 19:59:32 +00:00
|
|
|
|
2017-04-22 15:57:32 +00:00
|
|
|
private _lastTimeUpdated = _unit getVariable [QGVAR(lastTimeUpdated), 0];
|
|
|
|
private _deltaT = (CBA_missionTime - _lastTimeUpdated) min 10;
|
2019-12-17 17:17:49 +00:00
|
|
|
if (_deltaT < 1) exitWith { false }; // state machines could be calling this very rapidly depending on number of local units
|
2016-12-05 20:34:20 +00:00
|
|
|
|
2017-04-26 15:16:09 +00:00
|
|
|
BEGIN_COUNTER(Vitals);
|
|
|
|
|
|
|
|
_unit setVariable [QGVAR(lastTimeUpdated), CBA_missionTime];
|
2016-06-13 00:11:21 +00:00
|
|
|
private _lastTimeValuesSynced = _unit getVariable [QGVAR(lastMomentValuesSynced), 0];
|
2018-05-11 14:28:25 +00:00
|
|
|
private _syncValues = (CBA_missionTime - _lastTimeValuesSynced) >= (10 + floor(random 10));
|
2016-10-12 19:59:32 +00:00
|
|
|
|
2015-03-08 12:56:24 +00:00
|
|
|
if (_syncValues) then {
|
2016-03-02 10:01:39 +00:00
|
|
|
_unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime];
|
2015-03-08 12:56:24 +00:00
|
|
|
};
|
|
|
|
|
2018-05-10 16:44:02 +00:00
|
|
|
private _bloodVolume = GET_BLOOD_VOLUME(_unit) + ([_unit, _deltaT, _syncValues] call EFUNC(medical_status,getBloodVolumeChange));
|
2018-05-11 14:28:25 +00:00
|
|
|
_bloodVolume = 0 max _bloodVolume min DEFAULT_BLOOD_VOLUME;
|
2015-04-14 18:40:38 +00:00
|
|
|
|
2016-12-05 20:34:20 +00:00
|
|
|
// @todo: replace this and the rest of the setVariable with EFUNC(common,setApproximateVariablePublic)
|
2018-05-11 14:28:25 +00:00
|
|
|
_unit setVariable [VAR_BLOOD_VOL, _bloodVolume, _syncValues];
|
2015-02-07 22:55:48 +00:00
|
|
|
|
|
|
|
// Set variables for synchronizing information across the net
|
2018-07-18 19:38:00 +00:00
|
|
|
private _hemorrhage = switch (true) do {
|
2018-07-25 10:40:37 +00:00
|
|
|
case (_bloodVolume < BLOOD_VOLUME_CLASS_4_HEMORRHAGE): { 4 };
|
|
|
|
case (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE): { 3 };
|
|
|
|
case (_bloodVolume < BLOOD_VOLUME_CLASS_2_HEMORRHAGE): { 2 };
|
2018-07-18 19:38:00 +00:00
|
|
|
case (_bloodVolume < BLOOD_VOLUME_CLASS_1_HEMORRHAGE): { 1 };
|
|
|
|
default {0};
|
|
|
|
};
|
2018-05-22 17:25:07 +00:00
|
|
|
|
|
|
|
if (_hemorrhage != GET_HEMORRHAGE(_unit)) then {
|
2018-07-18 19:38:00 +00:00
|
|
|
_unit setVariable [VAR_HEMORRHAGE, _hemorrhage, true];
|
2015-02-07 22:55:48 +00:00
|
|
|
};
|
|
|
|
|
2019-04-27 19:12:11 +00:00
|
|
|
private _woundBloodLoss = GET_WOUND_BLEEDING(_unit);
|
2015-02-07 22:55:48 +00:00
|
|
|
|
2018-05-22 17:06:28 +00:00
|
|
|
private _inPain = GET_PAIN_PERCEIVED(_unit) > 0;
|
|
|
|
if !(_inPain isEqualTo IS_IN_PAIN(_unit)) then {
|
|
|
|
_unit setVariable [VAR_IN_PAIN, _inPain, true];
|
2015-02-07 22:55:48 +00:00
|
|
|
};
|
|
|
|
|
2016-12-05 20:34:20 +00:00
|
|
|
// Handle pain due tourniquets, that have been applied more than 120 s ago
|
2016-12-09 16:48:27 +00:00
|
|
|
private _tourniquetPain = 0;
|
2018-07-29 21:43:14 +00:00
|
|
|
private _tourniquets = GET_TOURNIQUETS(_unit);
|
2016-12-09 16:48:27 +00:00
|
|
|
{
|
|
|
|
if (_x > 0 && {CBA_missionTime - _x > 120}) then {
|
|
|
|
_tourniquetPain = _tourniquetPain max (CBA_missionTime - _x - 120) * 0.001;
|
|
|
|
};
|
|
|
|
} forEach _tourniquets;
|
2019-04-03 13:17:17 +00:00
|
|
|
if (_tourniquetPain > 0) then {
|
|
|
|
[_unit, _tourniquetPain] call EFUNC(medical_status,adjustPainLevel);
|
|
|
|
};
|
2016-12-09 16:48:27 +00:00
|
|
|
|
2019-04-27 19:12:11 +00:00
|
|
|
// Get Medication Adjustments:
|
|
|
|
private _hrTargetAdjustment = 0;
|
|
|
|
private _painSupressAdjustment = 0;
|
|
|
|
private _peripheralResistanceAdjustment = 0;
|
|
|
|
private _adjustments = _unit getVariable [VAR_MEDICATIONS,[]];
|
|
|
|
|
|
|
|
if !(_adjustments isEqualTo []) then {
|
|
|
|
private _deleted = false;
|
|
|
|
{
|
|
|
|
_x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"];
|
|
|
|
private _timeInSystem = CBA_missionTime - _timeAdded;
|
|
|
|
if (_timeInSystem >= _maxTimeInSystem) then {
|
|
|
|
_deleted = true;
|
|
|
|
_adjustments set [_forEachIndex, objNull];
|
|
|
|
} else {
|
|
|
|
private _effectRatio = (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem;
|
|
|
|
if (_hrAdjust != 0) then { _hrTargetAdjustment = _hrTargetAdjustment + _hrAdjust * _effectRatio; };
|
|
|
|
if (_painAdjust != 0) then { _painSupressAdjustment = _painSupressAdjustment + _painAdjust * _effectRatio; };
|
2020-06-15 14:53:25 +00:00
|
|
|
if (_flowAdjust != 0) then { _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; };
|
2019-04-27 19:12:11 +00:00
|
|
|
};
|
|
|
|
} forEach _adjustments;
|
|
|
|
|
|
|
|
if (_deleted) then {
|
|
|
|
_unit setVariable [VAR_MEDICATIONS, _adjustments - [objNull], true];
|
|
|
|
_syncValues = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
private _heartRate = [_unit, _hrTargetAdjustment, _deltaT, _syncValues] call FUNC(updateHeartRate);
|
|
|
|
[_unit, _painSupressAdjustment, _deltaT, _syncValues] call FUNC(updatePainSuppress);
|
|
|
|
[_unit, _peripheralResistanceAdjustment, _deltaT, _syncValues] call FUNC(updatePeripheralResistance);
|
2016-12-06 19:42:10 +00:00
|
|
|
|
2018-05-08 08:28:16 +00:00
|
|
|
private _bloodPressure = GET_BLOOD_PRESSURE(_unit);
|
2018-05-11 14:28:25 +00:00
|
|
|
_unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues];
|
2016-02-28 23:50:28 +00:00
|
|
|
|
2018-07-18 10:09:09 +00:00
|
|
|
_bloodPressure params ["_bloodPressureL", "_bloodPressureH"];
|
|
|
|
|
2018-07-29 21:43:14 +00:00
|
|
|
// Statements are ordered by most lethal first.
|
2018-07-18 10:09:09 +00:00
|
|
|
switch (true) do {
|
|
|
|
case (_bloodVolume < BLOOD_VOLUME_FATAL): {
|
|
|
|
TRACE_3("BloodVolume Fatal",_unit,BLOOD_VOLUME_FATAL,_bloodVolume);
|
2018-07-25 10:40:37 +00:00
|
|
|
[QEGVAR(medical,Bleedout), _unit] call CBA_fnc_localEvent;
|
|
|
|
};
|
2019-06-28 00:01:20 +00:00
|
|
|
case (IN_CRDC_ARRST(_unit)): {}; // if in cardiac arrest just break now to avoid throwing unneeded events
|
2018-07-25 10:40:37 +00:00
|
|
|
case (_hemorrhage == 4): {
|
|
|
|
TRACE_3("Class IV Hemorrhage",_unit,_hemorrhage,_bloodVolume);
|
2018-07-18 10:09:09 +00:00
|
|
|
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
|
|
|
|
};
|
2018-07-18 19:53:54 +00:00
|
|
|
case (_heartRate < 20 || {_heartRate > 220}): {
|
2018-07-18 10:09:09 +00:00
|
|
|
TRACE_2("heartRate Fatal",_unit,_heartRate);
|
|
|
|
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
|
|
|
|
};
|
2018-07-20 20:49:55 +00:00
|
|
|
case (_bloodPressureH < 50 && {_bloodPressureL < 40} && {_heartRate < 40}): {
|
|
|
|
TRACE_4("bloodPressure (H & L) + heartRate Fatal",_unit,_bloodPressureH,_bloodPressureL,_heartRate);
|
2018-07-18 10:09:09 +00:00
|
|
|
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
|
|
|
|
};
|
2018-07-29 21:16:06 +00:00
|
|
|
case (_bloodPressureL >= 190): {
|
2018-07-20 20:49:55 +00:00
|
|
|
TRACE_2("bloodPressure L above limits",_unit,_bloodPressureL);
|
|
|
|
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
|
2018-07-18 10:09:09 +00:00
|
|
|
};
|
2018-07-20 20:49:55 +00:00
|
|
|
case (_heartRate < 30): { // With a heart rate below 30 but bigger than 20 there is a chance to enter the cardiac arrest state
|
2019-04-27 19:12:11 +00:00
|
|
|
private _nextCheck = _unit getVariable [QGVAR(nextCheckCriticalHeartRate), CBA_missionTime];
|
2018-07-20 20:49:55 +00:00
|
|
|
private _enterCardiacArrest = false;
|
|
|
|
if (CBA_missionTime >= _nextCheck) then {
|
|
|
|
_enterCardiacArrest = random 1 < (0.4 + 0.6*(30 - _heartRate)/10); // Variable chance of getting into cardiac arrest.
|
2019-04-27 19:12:11 +00:00
|
|
|
_unit setVariable [QGVAR(nextCheckCriticalHeartRate), CBA_missionTime + 5];
|
2018-07-20 20:49:55 +00:00
|
|
|
};
|
|
|
|
if (_enterCardiacArrest) then {
|
|
|
|
TRACE_2("Heart rate critical. Cardiac arrest",_unit,_heartRate);
|
|
|
|
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
|
|
|
|
} else {
|
|
|
|
TRACE_2("Heart rate critical. Critical vitals",_unit,_heartRate);
|
|
|
|
[QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent;
|
|
|
|
};
|
2018-07-18 10:09:09 +00:00
|
|
|
};
|
2019-04-27 19:12:11 +00:00
|
|
|
case (_woundBloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD): {
|
2018-07-18 10:09:09 +00:00
|
|
|
[QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent;
|
|
|
|
};
|
2019-04-27 19:12:11 +00:00
|
|
|
case (_woundBloodLoss > 0): {
|
2018-08-11 10:40:06 +00:00
|
|
|
[QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent;
|
2018-07-18 10:09:09 +00:00
|
|
|
};
|
|
|
|
case (_inPain): {
|
2018-08-11 10:40:06 +00:00
|
|
|
[QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent;
|
2018-07-18 10:09:09 +00:00
|
|
|
};
|
2016-12-05 20:34:20 +00:00
|
|
|
};
|
2016-02-29 01:08:59 +00:00
|
|
|
|
2016-12-05 20:34:20 +00:00
|
|
|
#ifdef DEBUG_MODE_FULL
|
2019-04-27 19:12:11 +00:00
|
|
|
private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput);
|
2016-12-09 17:43:32 +00:00
|
|
|
if (!isPlayer _unit) then {
|
2018-07-18 19:38:00 +00:00
|
|
|
private _painLevel = _unit getVariable [VAR_PAIN, 0];
|
2019-04-27 19:12:11 +00:00
|
|
|
hintSilent format["blood volume: %1, blood loss: [%2, %3]\nhr: %4, bp: %5, pain: %6", round(_bloodVolume * 100) / 100, round(_woundBloodLoss * 1000) / 1000, round((_woundBloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100];
|
2016-12-05 20:34:20 +00:00
|
|
|
};
|
|
|
|
#endif
|
2015-02-07 22:55:48 +00:00
|
|
|
|
2017-04-26 15:16:09 +00:00
|
|
|
END_COUNTER(Vitals);
|
2019-12-17 17:17:49 +00:00
|
|
|
|
|
|
|
true
|