Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Medical Vitals - Add SPO2 #9360

Merged
merged 29 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d451da6
spo2 initial
BrettMayson Sep 4, 2023
d7e1a43
Merge branch 'master' into spo2
BrettMayson Sep 4, 2023
93b3f9a
remove missed systemChat
BrettMayson Sep 4, 2023
1f4a0ad
some minor cleanup
BrettMayson Sep 4, 2023
c064ae0
review suggestions, effectiveness changes
BrettMayson Sep 8, 2023
3bb589e
cleanup
BrettMayson Sep 8, 2023
83054a3
fatigue compatibility with RC units
LinkIsGrim Oct 26, 2023
e79e6b3
Rename CfgVehicles.hpp to CfgWeapons.hpp
LinkIsGrim Oct 26, 2023
c901cab
CfgWeapons
LinkIsGrim Oct 26, 2023
9a8315b
Merge remote-tracking branch 'upstream/master' into spo2
LinkIsGrim Oct 26, 2023
f898a0c
fix script_component
LinkIsGrim Oct 26, 2023
4658059
switch to weather enabled setting
LinkIsGrim Oct 26, 2023
db8d2cc
move condition cache to preStart, add vest support
LinkIsGrim Oct 26, 2023
0ab9abc
add setting to disable
LinkIsGrim Oct 26, 2023
f4802ae
Update addons/medical_vitals/initSettings.sqf
BrettMayson Nov 21, 2023
5fedf37
Update addons/medical_vitals/functions/fnc_updateOxygen.sqf
BrettMayson Dec 28, 2023
328f8af
move default value reset to setting change
LinkIsGrim Jan 2, 2024
daee82b
Merge remote-tracking branch 'upstream/master' into spo2
LinkIsGrim Jan 2, 2024
570ac7a
fix setting
LinkIsGrim Jan 2, 2024
22a4c91
Update addons/medical_vitals/functions/fnc_updateOxygen.sqf
BrettMayson Jan 2, 2024
5dc1898
Merge remote-tracking branch 'upstream/master' into spo2
LinkIsGrim Jan 16, 2024
ff6f63c
fix respawn, full heal
LinkIsGrim Jan 16, 2024
80da6f6
edit macro name
LinkIsGrim Jan 16, 2024
f0d8fc4
OCD extra whitespace
LinkIsGrim Jan 16, 2024
c76e2b4
reduce aerobic fatigue effect (max oxygen demand from fatigue is now …
LinkIsGrim Jan 16, 2024
75a6edf
Update addons/medical_vitals/functions/fnc_updateOxygen.sqf
BrettMayson Jan 26, 2024
8e5ca92
Merge remote-tracking branch 'upstream/master' into spo2
LinkIsGrim Feb 5, 2024
f6a0baa
use AF's o2sat value if SPO2 simulation is disabled
LinkIsGrim Feb 5, 2024
4bdc410
Update addons/weather/functions/fnc_calculateOxygenDensity.sqf
LinkIsGrim Feb 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions addons/advanced_fatigue/functions/fnc_mainLoop.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ if (!alive ACE_player) exitWith {
_staminaBarContainer ctrlCommit 1;
};

private _oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 90]) / 100;
johnb432 marked this conversation as resolved.
Show resolved Hide resolved

private _currentWork = REE;
private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6;

Expand All @@ -42,8 +44,8 @@ GVAR(muscleDamage) = (GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.
private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage));

// Calculate available power
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * OXYGEN * _muscleIntegritySqrt;
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * OXYGEN * _muscleIntegritySqrt;
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;

// Calculate how much power is consumed from each reserve
private _ae1Power = _currentWork min _ae1PathwayPowerFatigued;
Expand All @@ -58,8 +60,8 @@ GVAR(anReserve) = GVAR(anReserve) - _anPower / WATTSPERATP;
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 1.1;

// Aerobic ATP reserve recovery
GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + OXYGEN * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0;
GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + OXYGEN * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0;
GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + _oxygen * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0;
GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + _oxygen * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0;

// Anaerobic ATP reserver and fatigue recovery
GVAR(anReserve) = ((GVAR(anReserve)
Expand All @@ -70,9 +72,9 @@ GVAR(anFatigue) = ((GVAR(anFatigue)
- (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
) min 1) max 0;

private _aeReservePercentage = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2;
private _anReservePercentage = GVAR(anReserve) / AN_MAXRESERVE;
private _perceivedFatigue = 1 - (_anReservePercentage min _aeReservePercentage);
GVAR(aeReservePercentage) = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2;
GVAR(anReservePercentage) = GVAR(anReserve) / AN_MAXRESERVE;
private _perceivedFatigue = 1 - (GVAR(anReservePercentage) min GVAR(aeReservePercentage));

[ACE_player, _perceivedFatigue, _currentSpeed, GVAR(anReserve) == 0] call FUNC(handleEffects);

Expand Down
3 changes: 3 additions & 0 deletions addons/medical_engine/script_macros_medical.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#define GET_ARRAY(config,default) (if (isArray (config)) then {getArray (config)} else {default})

#define DEFAULT_HEART_RATE 80
#define DEFAULT_SPO2 97
#define DEFAULT_PERIPH_RES 100

// --- blood
Expand Down Expand Up @@ -141,6 +142,7 @@
#define VAR_WOUND_BLEEDING QEGVAR(medical,woundBleeding)
#define VAR_CRDC_ARRST QEGVAR(medical,inCardiacArrest)
#define VAR_HEART_RATE QEGVAR(medical,heartRate)
#define VAR_SPO2 QEGVAR(medical,spo2)
#define VAR_PAIN QEGVAR(medical,pain)
#define VAR_PAIN_SUPP QEGVAR(medical,painSuppress)
#define VAR_PERIPH_RES QEGVAR(medical,peripheralResistance)
Expand All @@ -163,6 +165,7 @@
#define GET_BLOOD_VOLUME(unit) (unit getVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME])
#define GET_WOUND_BLEEDING(unit) (unit getVariable [VAR_WOUND_BLEEDING, 0])
#define GET_HEART_RATE(unit) (unit getVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE])
#define GET_SPO2(unit) (unit getVariable [VAR_SPO2, DEFAULT_SPO2])
johnb432 marked this conversation as resolved.
Show resolved Hide resolved
#define GET_HEMORRHAGE(unit) (unit getVariable [VAR_HEMORRHAGE, 0])
#define GET_PAIN(unit) (unit getVariable [VAR_PAIN, 0])
#define GET_PAIN_SUPPRESS(unit) (unit getVariable [VAR_PAIN_SUPP, 0])
Expand Down
6 changes: 6 additions & 0 deletions addons/medical_vitals/CfgVehicles.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class CfgWeapons {
class H_HelmetB;
class H_PilotHelmetFighter_B: H_HelmetB {
GVAR(oxygenSupply) = QUOTE(vehicle _this isKindOf 'Plane' || vehicle _this isKindOf 'Helicopter');
};
};
1 change: 1 addition & 0 deletions addons/medical_vitals/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
PREP(handleUnitVitals);
PREP(updateHeartRate);
PREP(updateOxygen);
PREP(updatePainSuppress);
PREP(updatePeripheralResistance);
1 change: 1 addition & 0 deletions addons/medical_vitals/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ class CfgPatches {
};

#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved

#endif
3 changes: 3 additions & 0 deletions addons/medical_vitals/functions/fnc_handleUnitVitals.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ if (_syncValues) then {
_unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime];
};

// 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;

Expand Down
6 changes: 5 additions & 1 deletion addons/medical_vitals/functions/fnc_updateHeartRate.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ if IN_CRDC_ARRST(_unit) then {
if (_bloodVolume > BLOOD_VOLUME_CLASS_4_HEMORRHAGE) then {
GET_BLOOD_PRESSURE(_unit) params ["_bloodPressureL", "_bloodPressureH"];
private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL;
private _spo2 = GET_SPO2(_unit);
private _painLevel = GET_PAIN_PERCEIVED(_unit);

private _targetBP = 107;
Expand All @@ -51,8 +52,11 @@ if IN_CRDC_ARRST(_unit) then {
if (_painLevel > 0.2) then {
_targetHR = _targetHR max (80 + 50 * _painLevel);
};
// Increase HR to compensate for low blood oxygen
// Increase HR to compensate for higher oxygen demand (e.g. running, recovering from sprint)
private _oxygenDemand = _unit getVariable [QGVAR(oxygenDemand), 0];
_targetHR = _targetHR + ((97 - _spo2) * 2) + (_oxygenDemand * -1000);
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
_targetHR = (_targetHR + _hrTargetAdjustment) max 0;

_hrChange = round(_targetHR - _heartRate) / 2;
} else {
_hrChange = -round(_heartRate / 10);
Expand Down
81 changes: 81 additions & 0 deletions addons/medical_vitals/functions/fnc_updateOxygen.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "script_component.hpp"
/*
* Author: Brett Mayson
* Update the oxygen levels
*
* Arguments:
* 0: The Unit <OBJECT>
jonpas marked this conversation as resolved.
Show resolved Hide resolved
* 1: Time since last update <NUMBER>
* 2: Sync value? <BOOL>
BrettMayson marked this conversation as resolved.
Show resolved Hide resolved
*
* ReturnValue:
* Current SPO2 <NUMBER>
*
* Example:
* [player, 1, false] call ace_medical_vitals_fnc_updateOxygen
*
* Public: No
*/

params ["_unit", "_deltaT", "_syncValue"];

#define IDEAL_PPO2 0.255

private _current = GET_SPO2(_unit);
private _heartRate = GET_HEART_RATE(_unit);

private _altitude = EGVAR(common,mapAltitude) + ((getPosASL _unit) select 2);
private _po2 = if (missionNamespace getVariable ["ace_weather", false]) then {
private _temperature = _altitude call EFUNC(weather,calculateTemperatureAtHeight);
private _pressure = _altitude call EFUNC(weather,calculateBarometricPressure);
[_temperature, _pressure, EGVAR(weather,currentHumidity)] call EFUNC(weather,calculateOxygenDensity)
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
} else {
// Rough approximation of the partial pressure of oxygen in the air
0.25725 * (_altitude / 1000 + 1)
};

private _oxygenSaturation = (IDEAL_PPO2 min _po2) / IDEAL_PPO2;

// Check gear for oxygen supply
[goggles _unit, headgear _unit] findIf {
if (_x != "") then {
if (isNil QGVAR(oxygenSupplyConditionCache)) then {
GVAR(oxygenSupplyConditionCache) = createHashmap;
};
private _condition = GVAR(oxygenSupplyConditionCache) getOrDefaultCall [_x, {
compile getText (configFile >> "CfgWeapons" >> _x >> QGVAR(oxygenSupply))
}, true];
if (_condition isNotEqualTo {} && {ACE_player call _condition}) then {
_oxygenSaturation = 1;
_po2 = IDEAL_PPO2;
true
} else {
false
}
} else {
false
}
};
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved

// Base oxygen consumption rate
private _negativeChange = BASE_OXYGEN_USE;

// Fatigue will demand more oxygen
if (_unit == player && {missionNamespace getVariable [QEGVAR(advanced_fatigue,enabled), false]}) then {
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
_negativeChange = _negativeChange - ((1 - EGVAR(advanced_fatigue,aeReservePercentage)) * 0.5);
BrettMayson marked this conversation as resolved.
Show resolved Hide resolved
};

// Effectiveness of capturing oxygen
// increases slightly as po2 starts lowering
// but falls off quickly as po2 drops further
private _capture = 1 max ((_po2 / IDEAL_PPO2) ^ (-_po2 * 3));
BrettMayson marked this conversation as resolved.
Show resolved Hide resolved
private _positiveChange = _heartRate * 0.00368 * _oxygenSaturation * _capture;

private _breathingEffectiveness = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume more factors will be come into play here later.


private _rateOfChange = _negativeChange + (_positiveChange * _breathingEffectiveness);

private _spo2 = (_current + (_rateOfChange * _deltaT)) max 0 min 100;

_unit setVariable [QGVAR(oxygenDemand), _negativeChange - BASE_OXYGEN_USE];
_unit setVariable [VAR_SPO2, _spo2, _syncValue];
2 changes: 2 additions & 0 deletions addons/medical_vitals/script_component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@

#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"

#define BASE_OXYGEN_USE -0.25
2 changes: 1 addition & 1 deletion addons/weather/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

PREP(calculateAirDensity);
PREP(calculateBarometricPressure);
PREP(calculateDensityAltitude);
PREP(calculateDewPoint);
PREP(calculateHeatIndex);
PREP(calculateOxygenDensity);
PREP(calculateRoughnessLength);
PREP(calculateSpeedOfSound);
PREP(calculateTemperatureAtHeight);
Expand Down
20 changes: 20 additions & 0 deletions addons/weather/functions/fnc_calculateOxygenDensity.sqf
johnb432 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "script_component.hpp"
/*
* Author: Brett Mayson
* Calculates the oxygen density
*
* Arguments:
* 0: temperature - degrees celsius <NUMBER>
* 1: pressure - hPa <NUMBER>
* 2: relativeHumidity - value between 0.0 and 1.0 <NUMBER>
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
*
* Return Value:
* density of oxygen - kg * m^(-3) <NUMBER>
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
*
* Example:
* [0, 1020] call ace_weather_fnc_calculateOxygenDensity
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved
*
* Public: No
*/

(_this call FUNC(calculateAirDensity)) * 0.21
LinkIsGrim marked this conversation as resolved.
Show resolved Hide resolved