ACE3/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf
Thomas Kooi 36f2c5fcc9 Minor code clean up (#6474)
* Minor code clean up
* refactor(medical): shorten some code
* refactor(medical): use macros for tourniquets
* refactor(medical): pull cache expiry values into script_macros_medical
2018-07-29 22:43:14 +01:00

148 lines
5.8 KiB
Plaintext

/*
* Author: Glowbal
* Updates the vitals. Called from the statemachine's onState functions.
*
* Arguments:
* 0: The Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* [player] call ace_medical_vitals_fnc_handleUnitVitals
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
params ["_unit"];
private _lastTimeUpdated = _unit getVariable [QGVAR(lastTimeUpdated), 0];
private _deltaT = (CBA_missionTime - _lastTimeUpdated) min 10;
if (_deltaT < 1) exitWith {}; // state machines could be calling this very rapidly depending on number of local units
BEGIN_COUNTER(Vitals);
_unit setVariable [QGVAR(lastTimeUpdated), CBA_missionTime];
private _lastTimeValuesSynced = _unit getVariable [QGVAR(lastMomentValuesSynced), 0];
private _syncValues = (CBA_missionTime - _lastTimeValuesSynced) >= (10 + floor(random 10));
if (_syncValues) then {
_unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime];
};
private _bloodVolume = GET_BLOOD_VOLUME(_unit) + ([_unit, _deltaT, _syncValues] call EFUNC(medical_status,getBloodVolumeChange));
_bloodVolume = 0 max _bloodVolume min DEFAULT_BLOOD_VOLUME;
// @todo: replace this and the rest of the setVariable with EFUNC(common,setApproximateVariablePublic)
_unit setVariable [VAR_BLOOD_VOL, _bloodVolume, _syncValues];
// Set variables for synchronizing information across the net
private _hemorrhage = switch (true) do {
case (_bloodVolume < BLOOD_VOLUME_CLASS_4_HEMORRHAGE): { 4 };
case (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE): { 3 };
case (_bloodVolume < BLOOD_VOLUME_CLASS_2_HEMORRHAGE): { 2 };
case (_bloodVolume < BLOOD_VOLUME_CLASS_1_HEMORRHAGE): { 1 };
default {0};
};
if (_hemorrhage != GET_HEMORRHAGE(_unit)) then {
_unit setVariable [VAR_HEMORRHAGE, _hemorrhage, true];
};
private _bloodLoss = GET_BLOOD_LOSS(_unit);
if (_bloodLoss > 0) then {
_unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues];
if !IS_BLEEDING(_unit) then {
_unit setVariable [VAR_IS_BLEEDING, true, true];
};
} else {
if IS_BLEEDING(_unit) then {
_unit setVariable [VAR_IS_BLEEDING, false, true];
};
};
private _inPain = GET_PAIN_PERCEIVED(_unit) > 0;
if !(_inPain isEqualTo IS_IN_PAIN(_unit)) then {
_unit setVariable [VAR_IN_PAIN, _inPain, true];
};
// Handle pain due tourniquets, that have been applied more than 120 s ago
private _tourniquetPain = 0;
private _tourniquets = GET_TOURNIQUETS(_unit);
{
if (_x > 0 && {CBA_missionTime - _x > 120}) then {
_tourniquetPain = _tourniquetPain max (CBA_missionTime - _x - 120) * 0.001;
};
} forEach _tourniquets;
[_unit, _tourniquetPain] call EFUNC(medical,adjustPainLevel);
private _heartRate = [_unit, _deltaT, _syncValues] call FUNC(updateHeartRate);
[_unit, _deltaT, _syncValues] call FUNC(updatePainSuppress);
[_unit, _deltaT, _syncValues] call FUNC(updatePeripheralResistance);
private _bloodPressure = GET_BLOOD_PRESSURE(_unit);
_unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues];
_bloodPressure params ["_bloodPressureL", "_bloodPressureH"];
private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput);
// Statements are ordered by most lethal first.
switch (true) do {
case (_bloodVolume < BLOOD_VOLUME_FATAL): {
TRACE_3("BloodVolume Fatal",_unit,BLOOD_VOLUME_FATAL,_bloodVolume);
[QEGVAR(medical,Bleedout), _unit] call CBA_fnc_localEvent;
};
case (_hemorrhage == 4): {
TRACE_3("Class IV Hemorrhage",_unit,_hemorrhage,_bloodVolume);
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
};
case (_heartRate < 20 || {_heartRate > 220}): {
TRACE_2("heartRate Fatal",_unit,_heartRate);
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
};
case (_bloodPressureH < 50 && {_bloodPressureL < 40} && {_heartRate < 40}): {
TRACE_4("bloodPressure (H & L) + heartRate Fatal",_unit,_bloodPressureH,_bloodPressureL,_heartRate);
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
};
case (_bloodPressureL >= 190): {
TRACE_2("bloodPressure L above limits",_unit,_bloodPressureL);
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
};
case (_heartRate < 30): { // With a heart rate below 30 but bigger than 20 there is a chance to enter the cardiac arrest state
private _nextCheck = _unit getVariable [QGVAR(lastCheckCriticalHeartRate), CBA_missionTime];
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.
_unit setVariable [QGVAR(lastCheckCriticalHeartRate), CBA_missionTime + 5];
};
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;
};
};
case (_bloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD * _cardiacOutput): {
[QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent;
};
case (_bloodLoss > 0): {
[QEGVAR(medical,Injury), _unit] call CBA_fnc_localEvent;
};
case (_inPain): {
[QEGVAR(medical,Injury), _unit] call CBA_fnc_localEvent;
};
};
#ifdef DEBUG_MODE_FULL
if (!isPlayer _unit) then {
private _painLevel = _unit getVariable [VAR_PAIN, 0];
hintSilent format["blood volume: %1, blood loss: [%2, %3]\nhr: %4, bp: %5, pain: %6", round(_bloodVolume * 100) / 100, round(_bloodLoss * 1000) / 1000, round((_bloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100];
};
#endif
END_COUNTER(Vitals);