diff --git a/addons/medical_engine/script_macros_medical.hpp b/addons/medical_engine/script_macros_medical.hpp index 20a9a689209..1f7c2aee6bd 100644 --- a/addons/medical_engine/script_macros_medical.hpp +++ b/addons/medical_engine/script_macros_medical.hpp @@ -132,6 +132,12 @@ #define DEFAULT_TOURNIQUET_VALUES [0,0,0,0,0,0] +// Time until a tourniquet starts causing pain +#define TOURNIQUET_MIN_TIME_FOR_PAIN 120 + +// How much pain a tourniquet will cause per second after TOURNIQUET_MIN_TIME_FOR_PAIN +#define TOURNIQUET_PAIN_PER_SECOND 0.001 + #define DEFAULT_FRACTURE_VALUES [0,0,0,0,0,0] #define DEFAULT_BODYPART_DAMAGE_VALUES [0,0,0,0,0,0] diff --git a/addons/medical_status/XEH_PREP.hpp b/addons/medical_status/XEH_PREP.hpp index 7bfd270f8de..37e5bf644ad 100644 --- a/addons/medical_status/XEH_PREP.hpp +++ b/addons/medical_status/XEH_PREP.hpp @@ -4,7 +4,6 @@ PREP(adjustPainLevel); PREP(getAllMedicationCount); PREP(getBloodLoss); PREP(getBloodPressure); -PREP(getBloodVolumeChange); PREP(getCardiacOutput); PREP(getMedicationCount); PREP(handleKilled); diff --git a/addons/medical_status/functions/fnc_getBloodVolumeChange.sqf b/addons/medical_status/functions/fnc_getBloodVolumeChange.sqf deleted file mode 100644 index 3430de7e83a..00000000000 --- a/addons/medical_status/functions/fnc_getBloodVolumeChange.sqf +++ /dev/null @@ -1,53 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: Glowbal - * Calculates the blood volume change and decreases the IVs given to the unit. - * - * Arguments: - * 0: The Unit - * 1: Time since last update - * 2: Global Sync Values (bloodbags) - * - * Return Value: - * Blood volume change (liters per second) - * - * Example: - * [player, 1, true] call ace_medical_status_fnc_getBloodVolumeChange - * - * Public: No - */ - -params ["_unit", "_deltaT", "_syncValues"]; - -private _bloodVolumeChange = -_deltaT * GET_BLOOD_LOSS(_unit); - -if (!isNil {_unit getVariable QEGVAR(medical,ivBags)}) then { - private _bloodBags = _unit getVariable [QEGVAR(medical,ivBags), []]; - private _tourniquets = GET_TOURNIQUETS(_unit); - - _bloodBags = _bloodBags apply { - _x params ["_bagVolumeRemaining", "_type", "_bodyPart", "_treatment", "_rateCoef", "_item"]; - - if (_tourniquets select _bodyPart == 0) then { - private _bagChange = (_deltaT * EGVAR(medical,ivFlowRate) * IV_CHANGE_PER_SECOND * _rateCoef) min _bagVolumeRemaining; // absolute value of the change in miliLiters - _bagVolumeRemaining = _bagVolumeRemaining - _bagChange; - _bloodVolumeChange = _bloodVolumeChange + (_bagChange / 1000); - }; - - if (_bagVolumeRemaining < 0.01) then { - [] - } else { - [_bagVolumeRemaining, _type, _bodyPart, _treatment, _rateCoef, _item] - }; - }; - - _bloodBags = _bloodBags - [[]]; // remove empty bags - - if (_bloodBags isEqualTo []) then { - _unit setVariable [QEGVAR(medical,ivBags), nil, true]; // no bags left - clear variable (always globaly sync this) - } else { - _unit setVariable [QEGVAR(medical,ivBags), _bloodBags, _syncValues]; - }; -}; - -_bloodVolumeChange diff --git a/addons/medical_status/functions/fnc_updateWoundBloodLoss.sqf b/addons/medical_status/functions/fnc_updateWoundBloodLoss.sqf index 86963496422..e5b140bce68 100644 --- a/addons/medical_status/functions/fnc_updateWoundBloodLoss.sqf +++ b/addons/medical_status/functions/fnc_updateWoundBloodLoss.sqf @@ -23,24 +23,26 @@ private _bodyPartBleeding = [0,0,0,0,0,0]; { private _partIndex = ALL_BODY_PARTS find _x; if (_tourniquets select _partIndex == 0) then { + private _partBleeding = 0; { _x params ["", "_amountOf", "_bleeeding"]; - _bodyPartBleeding set [_partIndex, (_bodyPartBleeding select _partIndex) + (_amountOf * _bleeeding)]; + _partBleeding = _partBleeding + (_amountOf * _bleeding); } forEach _y; + _bodyPartBleeding set [_partIndex, _partBleeding]; }; } forEach GET_OPEN_WOUNDS(_unit); -if (_bodyPartBleeding isEqualTo [0,0,0,0,0,0]) then { +if (selectMax _bodyPartBleeding == 0) exitWith { TRACE_1("updateWoundBloodLoss-none",_unit); _unit setVariable [VAR_WOUND_BLEEDING, 0, true]; -} else { - _bodyPartBleeding params ["_headBleeding", "_bodyBleeding", "_leftArmBleeding", "_rightArmBleeding", "_leftLegBleeding", "_rightLegBleeding"]; - private _bodyBleedingRate = ((_headBleeding min 0.9) + (_bodyBleeding min 1.0)) min 1.0; - private _limbBleedingRate = ((_leftArmBleeding min 0.3) + (_rightArmBleeding min 0.3) + (_leftLegBleeding min 0.5) + (_rightLegBleeding min 0.5)) min 1.0; +}; - // limb bleeding is scaled down based on the amount of body bleeding - _limbBleedingRate = _limbBleedingRate * (1 - _bodyBleedingRate); +_bodyPartBleeding params ["_headBleeding", "_bodyBleeding", "_leftArmBleeding", "_rightArmBleeding", "_leftLegBleeding", "_rightLegBleeding"]; +private _bodyBleedingRate = ((_headBleeding min 0.9) + (_bodyBleeding min 1.0)) min 1.0; +private _limbBleedingRate = ((_leftArmBleeding min 0.3) + (_rightArmBleeding min 0.3) + (_leftLegBleeding min 0.5) + (_rightLegBleeding min 0.5)) min 1.0; - TRACE_3("updateWoundBloodLoss-bleeding",_unit,_bodyBleedingRate,_limbBleedingRate); - _unit setVariable [VAR_WOUND_BLEEDING, _bodyBleedingRate + _limbBleedingRate, true]; -}; +// limb bleeding is scaled down based on the amount of body bleeding +_limbBleedingRate = _limbBleedingRate * (1 - _bodyBleedingRate); + +TRACE_3("updateWoundBloodLoss-bleeding",_unit,_bodyBleedingRate,_limbBleedingRate); +_unit setVariable [VAR_WOUND_BLEEDING, _bodyBleedingRate + _limbBleedingRate, true]; diff --git a/addons/medical_vitals/XEH_PREP.hpp b/addons/medical_vitals/XEH_PREP.hpp index 02f1cc5f899..944b3ac881d 100644 --- a/addons/medical_vitals/XEH_PREP.hpp +++ b/addons/medical_vitals/XEH_PREP.hpp @@ -1,6 +1,12 @@ +PREP(consumeIVs); +PREP(consumeMedications); PREP(handleUnitVitals); PREP(scanConfig); +PREP(updateBloodPressure); +PREP(updateBloodVolume); PREP(updateHeartRate); PREP(updateOxygen); +PREP(updatePain); PREP(updatePainSuppress); PREP(updatePeripheralResistance); +PREP(updateState); diff --git a/addons/medical_vitals/functions/fnc_consumeIVs.sqf b/addons/medical_vitals/functions/fnc_consumeIVs.sqf new file mode 100644 index 00000000000..853d16f5ba9 --- /dev/null +++ b/addons/medical_vitals/functions/fnc_consumeIVs.sqf @@ -0,0 +1,60 @@ +#include "..\script_component.hpp" +/* + * Author: Glowbal, LinkIsGrim + * Calculates fluid intake and consumes unit's IVs. + * + * Arguments: + * 0: The Unit + * 1: Time since last update + * 2: Global Sync Values (IVs) + * + * Return Value: + * Blood volume change (liters per second) + * + * Example: + * [player, 1, true] call ace_medical_vitals_fnc_consumeIVs + * + * Public: No + */ + +params ["_unit", "_deltaT", "_syncValues"]; + +private _ivBags = _unit getVariable [QEGVAR(medical,ivBags), []]; + +if (_ivBags isEqualTo []) exitWith {0}; + +private _tourniquets = GET_TOURNIQUETS(_unit); +private _bloodVolumeChange = 0; +private _consumedIVs = []; + +{ + _x params ["_bagVolumeRemaining", "_type", "_bodyPartIndex", "_treatment", "_rateCoef", "_item"]; + + if (_tourniquets select _bodyPartIndex > 0) then { + continue + }; + + private _bagChange = (_deltaT * EGVAR(medical,ivFlowRate) * IV_CHANGE_PER_SECOND * _rateCoef) min _bagVolumeRemaining; // absolute value of the change in milliliters + _bagVolumeRemaining = _bagVolumeRemaining - _bagChange; + _consumedIVs pushBack [_type, _treatment, _bagChange]; + + if (_type in ["Blood", "Plasma", "Saline"]) then { + _bloodVolumeChange = _bloodVolumeChange + (_bagChange / 1000); + }; + + if (_bagVolumeRemaining >= 0.01) then { + _x set [0, _bagVolumeRemaining]; + } else { + _ivBags deleteAt _forEachIndex; + }; +} forEachReversed _ivBags; + +[QEGVAR(medical,consumedIVs), [_unit, _consumedIVs]] call CBA_fnc_localEvent; + +if (_ivBags isEqualTo []) then { + _unit setVariable [QEGVAR(medical,ivBags), nil, true]; +} else { + _unit setVariable [QEGVAR(medical,ivBags), _ivBags, _syncValues]; +}; + +_bloodVolumeChange // return diff --git a/addons/medical_vitals/functions/fnc_consumeMedications.sqf b/addons/medical_vitals/functions/fnc_consumeMedications.sqf new file mode 100644 index 00000000000..7ecce7ad889 --- /dev/null +++ b/addons/medical_vitals/functions/fnc_consumeMedications.sqf @@ -0,0 +1,61 @@ +#include "..\script_component.hpp" +/* + * Author: Glowbal, LinkIsGrim + * Consumes unit's medications and update relevant vitals + * + * Arguments: + * 0: The Unit + * 1: Time since last update + * 2: Global Sync Values (medications) + * + * Return Value: + * Values should be synced + * + * Example: + * [player, 1, true] call ace_medical_vitals_fnc_consumeMedications + * + * Public: No + */ + +params ["_unit", "_deltaT", "_syncValues"]; + +private _medications = _unit getVariable [VAR_MEDICATIONS, []]; + +if (_medications isEqualTo []) exitWith { + false // return +}; + +private _hrTargetAdjustment = 0; +private _painSupressAdjustment = 0; +private _peripheralResistanceAdjustment = 0; +private _consumedMedications = []; + +{ + _x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"]; + + private _timeInSystem = CBA_missionTime - _timeAdded; + if (_timeInSystem >= _maxTimeInSystem) then { + _syncValues = true; + _medications deleteAt _forEachIndex; + } else { + private _effectRatio = (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; + + _consumedMedications pushBack [_medication, _effectRatio]; + + if (_hrAdjust != 0) then { _hrTargetAdjustment = _hrTargetAdjustment + _hrAdjust * _effectRatio; }; + if (_painAdjust != 0) then { _painSupressAdjustment = _painSupressAdjustment + _painAdjust * _effectRatio; }; + if (_flowAdjust != 0) then { _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; }; + }; +} forEachReversed _medications; + +[QEGVAR(medical,consumeMedications), [_unit, _consumedMedications]] call CBA_fnc_localEvent; + +if (_syncValues) then { + _unit setVariable [VAR_MEDICATIONS, _medications, true] +}; + +[_unit, _hrTargetAdjustment, _deltaT, _syncValues] call FUNC(updateHeartRate); +[_unit, _painSupressAdjustment, _deltaT, _syncValues] call FUNC(updatePainSuppress); +[_unit, _peripheralResistanceAdjustment, _deltaT, _syncValues] call FUNC(updatePeripheralResistance); + +_syncValues // return diff --git a/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf b/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf index 77aec7fd621..a3b47068ebb 100644 --- a/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf +++ b/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf @@ -34,141 +34,25 @@ if (_syncValues) then { // Update SPO2 intake and usage since last update [_unit, _deltaT, _syncValues] call FUNC(updateOxygen); -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}; -}; +// Update blood volume +[_unit, _deltaT, _syncValues] call FUNC(updateBloodVolume); -if (_hemorrhage != GET_HEMORRHAGE(_unit)) then { - _unit setVariable [VAR_HEMORRHAGE, _hemorrhage, true]; -}; +// Update pain (currently only tourniquets) +[_unit, _syncValues] call FUNC(updatePain); -private _woundBloodLoss = GET_WOUND_BLEEDING(_unit); +// Consume medications +_syncValues = [_unit, _deltaT, _syncValues] call FUNC(consumeMedications); -private _inPain = GET_PAIN_PERCEIVED(_unit) > 0; -if (_inPain isNotEqualTo 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; -if (_tourniquetPain > 0) then { - [_unit, _tourniquetPain] call EFUNC(medical_status,adjustPainLevel); -}; +// Update blood presure +[_unit, _syncValues] call FUNC(updateBloodPressure); -// Get Medication Adjustments: -private _hrTargetAdjustment = 0; -private _painSupressAdjustment = 0; -private _peripheralResistanceAdjustment = 0; -private _adjustments = _unit getVariable [VAR_MEDICATIONS,[]]; - -if (_adjustments isNotEqualTo []) 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 deleteAt _forEachIndex; - } 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; }; - if (_flowAdjust != 0) then { _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; }; - }; - } forEachReversed _adjustments; - - if (_deleted) then { - _unit setVariable [VAR_MEDICATIONS, _adjustments, true]; - _syncValues = true; - }; -}; +// Update statemachine and status variables +[_unit, _syncValues] call FUNC(updateState); -private _heartRate = [_unit, _hrTargetAdjustment, _deltaT, _syncValues] call FUNC(updateHeartRate); -[_unit, _painSupressAdjustment, _deltaT, _syncValues] call FUNC(updatePainSuppress); -[_unit, _peripheralResistanceAdjustment, _deltaT, _syncValues] call FUNC(updatePeripheralResistance); - -private _bloodPressure = GET_BLOOD_PRESSURE(_unit); -_unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues]; - -_bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; - -// 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 (IN_CRDC_ARRST(_unit)): {}; // if in cardiac arrest just break now to avoid throwing unneeded events - 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(nextCheckCriticalHeartRate), 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(nextCheckCriticalHeartRate), 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 (_woundBloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD): { - [QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; - }; - case (_woundBloodLoss > 0): { - [QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent; - }; - case (_inPain): { - [QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent; - }; -}; +END_COUNTER(Vitals); -#ifdef DEBUG_MODE_FULL -private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput); -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(_woundBloodLoss * 1000) / 1000, round((_woundBloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100]; -}; -#endif -END_COUNTER(Vitals); -//placed outside the counter as 3rd-party code may be called from this event [QEGVAR(medical,handleUnitVitals), [_unit, _deltaT]] call CBA_fnc_localEvent; true diff --git a/addons/medical_vitals/functions/fnc_updateBloodPressure.sqf b/addons/medical_vitals/functions/fnc_updateBloodPressure.sqf new file mode 100644 index 00000000000..7df1cdf4173 --- /dev/null +++ b/addons/medical_vitals/functions/fnc_updateBloodPressure.sqf @@ -0,0 +1,22 @@ +#include "..\script_component.hpp" +/* + * Author: LinkIsGrim + * Update unit blood pressure + * + * Arguments: + * 0: The Unit + * 1: Sync value? + * + * Return Value: + * None + * + * Example: + * [player, false] call ace_medical_vitals_fnc_updateBloodPressure + * + * Public: No + */ + +params ["_unit", "_syncValues"]; + +private _bloodPressure = GET_BLOOD_PRESSURE(_unit); +_unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues]; diff --git a/addons/medical_vitals/functions/fnc_updateBloodVolume.sqf b/addons/medical_vitals/functions/fnc_updateBloodVolume.sqf new file mode 100644 index 00000000000..071aef140bd --- /dev/null +++ b/addons/medical_vitals/functions/fnc_updateBloodVolume.sqf @@ -0,0 +1,29 @@ +#include "..\script_component.hpp" +/* + * Author: LinkIsGrim + * Update unit blood volume + * + * Arguments: + * 0: The Unit + * 1: Time since last update + * 2: Sync value? + * + * Return Value: + * None + * + * Example: + * [player, 5, false] call ace_medical_vitals_fnc_updateBloodVolume + * + * Public: No + */ + +params ["_unit", "_deltaT", "_syncValues"]; + +private _bleeding = -_deltaT * GET_BLOOD_LOSS(_unit); +private _ivChange = [_unit, _deltaT, _syncValues] call FUNC(consumeIVs); + +private _bloodVolume = GET_BLOOD_VOLUME(_unit) + _bleeding + _ivChange; +_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]; diff --git a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf index 0390a9ad076..888e5fea797 100644 --- a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf +++ b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Update the heart rate + * Update unit's heart rate * * Arguments: * 0: The Unit @@ -9,8 +9,8 @@ * 2: Time since last update * 3: Sync value? * - * ReturnValue: - * Current Heart Rate + * Return Value: + * None * * Example: * [player, 0, 1, false] call ace_medical_vitals_fnc_updateHeartRate @@ -65,5 +65,3 @@ if IN_CRDC_ARRST(_unit) then { }; _unit setVariable [VAR_HEART_RATE, _heartRate, _syncValue]; - -_heartRate diff --git a/addons/medical_vitals/functions/fnc_updatePain.sqf b/addons/medical_vitals/functions/fnc_updatePain.sqf new file mode 100644 index 00000000000..bd977ba1097 --- /dev/null +++ b/addons/medical_vitals/functions/fnc_updatePain.sqf @@ -0,0 +1,29 @@ +#include "..\script_component.hpp" +/* + * Author: LinkIsGrim + * Update unit pain + * + * Arguments: + * 0: The Unit + * 1: Sync value? + * + * Return Value: + * None + * + * Example: + * [player, false] call ace_medical_vitals_fnc_updatePain + * + * Public: No + */ + +params ["_unit", "_syncValues"]; + +// Handle pain due to tourniquets, that have been applied more than 120 s ago +private _activeTourniquets = GET_TOURNIQUETS(_unit) - [0]; +if (_activeTourniquets isEqualTo []) exitWith {}; + +private _oldestTourniquetTime = selectMin _activeTourniquets; +private _tourniquetPainSeconds = CBA_missionTime - _oldestTourniquetTime - TOURNIQUET_MIN_TIME_FOR_PAIN; +if (_tourniquetPainSeconds <= 0) exitWith {}; + +[_unit, _tourniquetPainSeconds * TOURNIQUET_PAIN_PER_SECOND] call EFUNC(medical_status,adjustPainLevel); diff --git a/addons/medical_vitals/functions/fnc_updateState.sqf b/addons/medical_vitals/functions/fnc_updateState.sqf new file mode 100644 index 00000000000..063b9d77617 --- /dev/null +++ b/addons/medical_vitals/functions/fnc_updateState.sqf @@ -0,0 +1,94 @@ +#include "..\script_component.hpp" +/* + * Author: LinkIsGrim + * Update unit state and status variables + * + * Arguments: + * 0: The Unit + * 1: Sync value? + * + * Return Value: + * None + * + * Example: + * [player, false] call ace_medical_vitals_fnc_updateState + * + * Public: No + */ + +params ["_unit", "_syncValues"]; + +private _bloodVolume = GET_BLOOD_VOLUME(_unit); +// 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 _inPain = GET_PAIN_PERCEIVED(_unit) > 0; +if (_inPain isNotEqualTo IS_IN_PAIN(_unit)) then { + _unit setVariable [VAR_IN_PAIN, _inPain, true]; +}; + +private _heartRate = GET_HEART_RATE(_unit); +private _woundBloodLoss = GET_WOUND_BLEEDING(_unit); +private _bloodPressure = _unit getVariable [VAR_BLOOD_PRESS, [80, 120]]; + +_bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; + +// 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 (IN_CRDC_ARRST(_unit)): {}; // if in cardiac arrest just break now to avoid throwing unneeded events + 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(nextCheckCriticalHeartRate), 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(nextCheckCriticalHeartRate), 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 (_woundBloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD): { + [QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_woundBloodLoss > 0): { + [QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent; + }; + case (_inPain): { + [QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent; + }; +};