diff --git a/addons/airway/XEH_postInit.sqf b/addons/airway/XEH_postInit.sqf index 9b2d9b8e3..cd443c7d2 100644 --- a/addons/airway/XEH_postInit.sqf +++ b/addons/airway/XEH_postInit.sqf @@ -29,9 +29,6 @@ if !(GVAR(enable)) exitWith {}; private _alive = alive _unit; if ((!_alive) || (_unit getVariable [GVAR(string_exit), ""] isEqualTo "keko_wasPunched") || KAT_forceWakeup) exitWith {}; - if (EGVAR(breathing,enable)) then { - [QEGVAR(breathing,handleBreathing), [_unit, CBA_missionTime], _unit] call CBA_fnc_targetEvent; - }; [_unit] call FUNC(handleAirway); [_unit] call FUNC(handlePuking); }] call CBA_fnc_addEventHandler; diff --git a/addons/breathing/XEH_PREP.hpp b/addons/breathing/XEH_PREP.hpp index a419a4ca1..305208eb1 100644 --- a/addons/breathing/XEH_PREP.hpp +++ b/addons/breathing/XEH_PREP.hpp @@ -1,8 +1,6 @@ PREP(canUseBVM); PREP(checkBreathing); PREP(checkPulseOximeter); -PREP(getETCo2); -PREP(getRespiratoryRate); PREP(fullHealLocal); PREP(gui_updateBodyImage); PREP(gui_updateInjuryListPart); diff --git a/addons/breathing/functions/fnc_checkBreathing.sqf b/addons/breathing/functions/fnc_checkBreathing.sqf index b4d5323e4..8cc5e4de0 100644 --- a/addons/breathing/functions/fnc_checkBreathing.sqf +++ b/addons/breathing/functions/fnc_checkBreathing.sqf @@ -19,7 +19,7 @@ params ["_medic", "_patient"]; -private _ph = _patient getVariable [QEGVAR(pharma,pH), 1500]; +private _ph = GET_PH(_patient); private _hr = GET_HEART_RATE(_patient); private _output = ""; private _output_log = ""; @@ -33,10 +33,10 @@ if (_patient getVariable [QGVAR(pneumothorax), 0] > 0) then { _breathing_log = LLSTRING(breathing_shallow); }; -if (_ph < 750) then { +if (_ph < 7.2) then { _breath = LLSTRING(breath_mild); - if (_ph < 250) then { + if (_ph < 6.9) then { _breath = LLSTRING(breath_stink); }; }; diff --git a/addons/breathing/functions/fnc_fullHealLocal.sqf b/addons/breathing/functions/fnc_fullHealLocal.sqf index d6d563167..9791dd752 100644 --- a/addons/breathing/functions/fnc_fullHealLocal.sqf +++ b/addons/breathing/functions/fnc_fullHealLocal.sqf @@ -25,7 +25,6 @@ _patient setVariable [QGVAR(tensionpneumothorax), false, true]; _patient setVariable [QGVAR(activeChestSeal), false, true]; _patient setVariable [QGVAR(deepPenetratingInjury), false, true]; _patient setVariable [QGVAR(etco2Monitor), [], true]; -_patient setVariable [QGVAR(etco2Level), 40, true]; _patient setVariable [QGVAR(breathRate), 15, true]; _patient setVariable [QGVAR(nasalCannula), false, true]; diff --git a/addons/breathing/functions/fnc_getETCo2.sqf b/addons/breathing/functions/fnc_getETCo2.sqf deleted file mode 100644 index 9660de356..000000000 --- a/addons/breathing/functions/fnc_getETCo2.sqf +++ /dev/null @@ -1,78 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: apo_tle - * Calculate patient's ETCo2 level based on status of their vitals. - * - * Arguments: - * 0: Patient - * - * Return Value: - * ETCo2 level and units : "40 mmHg" - * - * Example: - * [player] call kat_breathing_fnc_getETCo2; - * - * Public: No - */ - -params ["_patient"]; - -if !(alive _patient) exitWith {0}; - -private _pr = GET_HEART_RATE(_patient); -private _bloodVolume = GET_BLOOD_VOLUME(_patient); -private _lostBlood = 6.0 - _bloodVolume; -private _pH = _patient getVariable [QEGVAR(pharma,pH),1500]; -private _phDiff = 1500 - _pH; - -private _ptxTarget = _patient getVariable [QGVAR(pneumothorax), 0]; // more deteriorated closer to 4, at 4 likely to become advanced -private _hasHtx = _patient getVariable [QGVAR(hemopneumothorax), false]; -private _hasTptx = _patient getVariable [QGVAR(tensopneumothorax), false]; - -private _airwayObstructed = _patient getVariable [QEGVAR(airway,obstruction), false] && !(_patient getVariable [QEGVAR(airway,overstretch), false]); -private _airwayOccluded = _patient getVariable [QEGVAR(airway,occluded), false]; - -private _phOffset = [0,(floor (_phDiff / 250))] select (missionNamespace getVariable [QEGVAR(pharma,kidneyAction),false]); // increase etco2 by 1 per 250 points of pH lost -private _randomOffset = selectRandom [-2,-1,0,1,2]; -private _newEtco2 = switch (true) do { - //cpr being performed and patient has no pulse - case ((_patient getVariable [QACEGVAR(medical,CPR_provider), objNull] isNotEqualTo objNull) && (_pr == 0)): { - private _newEtco2 = 11; - private _cardiacType = _patient getVariable [QEGVAR(circulation,cardiacArrestType), 0]; - private _offset = (_cardiacType); - private _bloodOffset = [((floor (_lostBlood / 0.8)) * 2),0] select (_lostBlood > 2); // reduce ETCo2 by 2mmhg for each 800ml of blood lost above 2L threshold (initial 2L incl.) - _newEtco2 = _newEtco2 + _offset - _bloodOffset; - _newEtco2 + _randomOffset; - }; - - //cardiac arrest without cpr being performed - case (IN_CRDC_ARRST(_patient)): {0}; - - //airways blocked - case (_airwayObstructed || _airwayOccluded): {50+_randomOffset+_phOffset}; - - //lost a lot of blood - case (_lostBlood >= 1): { - private _newEtco2 = 37; - _newEtco2 = _newEtco2 - ((floor (_lostBlood / 0.5)) * 4); - (14 max _newEtco2 min 99) + _randomOffset+_phOffset; //subtract 4mmhg of ETCo2 for each 500ml lost, clamped at minimum 14 - }; - - //tptx/hpx - case (_hasHtx || _hasTptx): {22+_randomOffset+_phOffset}; - - // base ptx. ETCo2 decreases as ptx deteriorates - case (_ptxTarget > 0): { - private _newEtco2 = 37 - (_ptxTarget * 3); - _newEtco2 + _randomOffset + _phOffset; - }; - - //no problems - default {40+_randomOffset+_phOffset}; -}; - -if (GVAR(Etco2_Units) == 0) then { - (str _newEtco2) + "mmHg"; -} else { - ((_newEtco2/7.501) toFixed 2)+ "kPa"; -}; \ No newline at end of file diff --git a/addons/breathing/functions/fnc_getRespiratoryRate.sqf b/addons/breathing/functions/fnc_getRespiratoryRate.sqf deleted file mode 100644 index 4e3b86a53..000000000 --- a/addons/breathing/functions/fnc_getRespiratoryRate.sqf +++ /dev/null @@ -1,62 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: apo_tle - * Calculate patient's Respiratory Rate based on status of their vitals. - * - * Arguments: - * 0: Patient - * - * Return Value: - * Respiratory Rate - * - * Example: - * [player] call kat_breathing_fnc_getRespiratoryRate; - * - * Public: No - */ - -params ["_patient"]; - -if !(alive _patient) exitWith {0}; - -private _bloodVolume = GET_BLOOD_VOLUME(_patient); -private _lostBlood = 6.0 - _bloodVolume; -private _pH = _patient getVariable [QEGVAR(pharma,pH),1500]; -private _phDiff = 1500 - _pH; - -private _ptxTarget = _patient getVariable [QGVAR(pneumothorax), 0]; // more deteriorated closer to 4, at 4 likely to become advanced -private _hasHtx = _patient getVariable [QGVAR(hemopneumothorax), false]; -private _hasTptx = _patient getVariable [QGVAR(tensopneumothorax), false]; - -private _airwayObstructed = _patient getVariable [QEGVAR(airway,obstruction), false] && !(_patient getVariable [QEGVAR(airway,overstretch), false]); -private _airwayOccluded = _patient getVariable [QEGVAR(airway,occluded), false]; - -private _phOffset = [0,((floor (_phDiff / 250)))] select (EGVAR(pharma,kidneyAction)); // increase RR by 1 per 250 points of pH lost -private _randomOffset = selectRandom [-1,0,1]; -private _respiratoryRate = 16 + _randomOffset + _phOffset; - -// calculate respiratoryrate for blood loss -if (_lostBlood >= 0.2) then { - _respiratoryRate = (_respiratoryRate + (floor (_lostBlood / 0.2))); // increase breath rate by 1 per 200ml lost -}; -// calculate respiratoryrate for ptxs -if (_ptxTarget > 0) then { - _respiratoryRate = [_respiratoryRate + 9, _respiratoryRate + (_ptxTarget * 2)] select (_hasHtx || _hasTptx); -}; - -switch (true) do { - //cpr being performed and patient has no pulse - case ((_patient getVariable [QACEGVAR(medical,CPR_provider), objNull] isNotEqualTo objNull) && (_pr == 0)): {10}; - - //bvm being used - case (_patient getVariable [QGVAR(BVMInUse), false]): {10}; - - //cardiac arrest - case (IN_CRDC_ARRST(_patient)): {0}; - - //airways blocked - case (_airwayObstructed || _airwayOccluded): {0}; - - //able to breathe - default {_respiratoryRate}; -}; \ No newline at end of file diff --git a/addons/breathing/functions/fnc_handlePulmoHit.sqf b/addons/breathing/functions/fnc_handlePulmoHit.sqf index 6f8a6d8fa..3e835cc9b 100644 --- a/addons/breathing/functions/fnc_handlePulmoHit.sqf +++ b/addons/breathing/functions/fnc_handlePulmoHit.sqf @@ -36,7 +36,6 @@ if (floor (random 100) < (GVAR(pneumothoraxChance) + _chanceIncrease)) then { if (_unit getVariable [QGVAR(pneumothorax), 0] isEqualto 0 && !(_unit getVariable [QGVAR(tensionpneumothorax), false])) then { // Initial pneumothorax // add breathing sound [_unit, 0.2] call ACEFUNC(medical_status,adjustPainLevel); - [_unit] call FUNC(handleBreathing); _unit setVariable [QGVAR(pneumothorax), 1, true]; _unit setVariable [QGVAR(deepPenetratingInjury), true, true]; _unit setVariable [QGVAR(activeChestSeal), false, true]; diff --git a/addons/breathing/functions/fnc_treatmentAdvanced_pulseoximeterLocal.sqf b/addons/breathing/functions/fnc_treatmentAdvanced_pulseoximeterLocal.sqf index 1b369b761..203156c3a 100644 --- a/addons/breathing/functions/fnc_treatmentAdvanced_pulseoximeterLocal.sqf +++ b/addons/breathing/functions/fnc_treatmentAdvanced_pulseoximeterLocal.sqf @@ -40,7 +40,7 @@ _patient setVariable [QGVAR(PulseOximeter_Attached), _attachedPulseOximeter, tru }; private _HR = GET_HEART_RATE(_patient); - private _SpO2 = _patient getVariable [QGVAR(airwayStatus), 100]; + private _SpO2 = GET_SPO2(_patient); if (([_patient,_bodyPart] call ACEFUNC(medical_treatment,hasTourniquetAppliedTo))) then { _HR = 0; @@ -58,7 +58,7 @@ _patient setVariable [QGVAR(PulseOximeter_Attached), _attachedPulseOximeter, tru [_idPFH] call CBA_fnc_removePerFrameHandler; }; - private _SpO2 = _patient getVariable [QGVAR(airwayStatus), 100]; + private _SpO2 = GET_SPO2(_patient); if (([_patient,_bodyPart] call ACEFUNC(medical_treatment,hasTourniquetAppliedTo))) then { _SpO2 = 0; diff --git a/addons/chemical/functions/fnc_afterWait.sqf b/addons/chemical/functions/fnc_afterWait.sqf index f807a46f7..34d5d8988 100644 --- a/addons/chemical/functions/fnc_afterWait.sqf +++ b/addons/chemical/functions/fnc_afterWait.sqf @@ -54,7 +54,6 @@ if ((goggles _unit) in (missionNamespace getVariable [QGVAR(availGasmaskList), [ _unit setVariable [QGVAR(airPoisoning), true, true]; }; }; - [_unit] call EFUNC(breathing,handleBreathing); _isinGas = false; }; @@ -69,7 +68,6 @@ if ((goggles _unit) in (missionNamespace getVariable [QGVAR(availGasmaskList), [ _unit setVariable [QGVAR(airPoisoning), true, true]; }; }; - [_unit] call EFUNC(breathing,handleBreathing); _isinGas = false; }; @@ -93,6 +91,5 @@ if ((goggles _unit) in (missionNamespace getVariable [QGVAR(availGasmaskList), [ _unit setVariable [QGVAR(airPoisoning), true, true]; }; }; - [_unit] call EFUNC(breathing,handleBreathing); }; }; diff --git a/addons/chemical/functions/fnc_breathing.sqf b/addons/chemical/functions/fnc_breathing.sqf index f98f37013..f4ab4b46d 100644 --- a/addons/chemical/functions/fnc_breathing.sqf +++ b/addons/chemical/functions/fnc_breathing.sqf @@ -32,7 +32,7 @@ params ["_unit"]; [_handler] call CBA_fnc_removePerFrameHandler; [_unit] call FUNC(breathing); } else { - if (GET_PAIN_PERCEIVED(_unit) >= 0.4 || {_unit getVariable[QACEGVAR(medical,heartrate), 80] >= 105}) then { + if (GET_PAIN_PERCEIVED(_unit) >= 0.4) || (_unit getVariable[QACEGVAR(medical,heartrate), 80] >= 105) then { _unit say3D QGVAR(mask_breath_heavy); } else { private _random = selectRandom[QGVAR(mask_breath_1), QGVAR(mask_breath_2)]; diff --git a/addons/circulation/ACE_Medical_Treatment_Actions.hpp b/addons/circulation/ACE_Medical_Treatment_Actions.hpp index 17f4d5e2f..5c88d80e1 100644 --- a/addons/circulation/ACE_Medical_Treatment_Actions.hpp +++ b/addons/circulation/ACE_Medical_Treatment_Actions.hpp @@ -38,7 +38,7 @@ class ACE_Medical_Treatment_Actions { allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; allowSelfTreatment = QGVAR(enable_selfBloodDraw); category = "advanced"; - medicRequired = 0; + medicRequired = 1; consumeItem = 1; callbackSuccess = QUOTE([ARR_3(_medic,_patient,500)] call FUNC(drawBlood)); condition = QUOTE([ARR_3(_medic,_patient,500)] call FUNC(canDraw) && (!(EGVAR(pharma,RequireInsIVBloodDraw)) || EFUNC(pharma,removeIV))); @@ -54,7 +54,7 @@ class ACE_Medical_Treatment_Actions { allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; allowSelfTreatment = QGVAR(enable_selfBloodDraw); category = "advanced"; - medicRequired = 0; + medicRequired = 1; consumeItem = 1; callbackSuccess = QUOTE([ARR_3(_medic,_patient,250)] call FUNC(drawBlood)); condition = QUOTE([ARR_3(_medic,_patient,250)] call FUNC(canDraw) && (!(EGVAR(pharma,RequireInsIVBloodDraw)) || EFUNC(pharma,removeIV))); @@ -63,6 +63,14 @@ class ACE_Medical_Treatment_Actions { animationPatientUnconscious = "AinjPpneMstpSnonWrflDnon_rolltoback"; animationPatientUnconsciousExcludeOn[] = {"ainjppnemstpsnonwrfldnon", "kat_recoveryposition"}; }; + class DrawArterial: KAT_DrawBlood250 { + displayName = CSTRING(DrawArterial_Action_Use); + displayNameProgress = CSTRING(DrawBlood_Action_Progress); + treatmentTime = 10; + callbackSuccess = QFUNC(drawArterial); + condition = "true"; + items[] = {"kat_IV_16"}; + }; #include "Blood_Medical.hpp" diff --git a/addons/circulation/CfgVehicles.hpp b/addons/circulation/CfgVehicles.hpp index 61372a570..932e1a86a 100644 --- a/addons/circulation/CfgVehicles.hpp +++ b/addons/circulation/CfgVehicles.hpp @@ -233,9 +233,134 @@ class CfgVehicles { }; }; + class LandVehicle; + class Car: LandVehicle { + class ACE_Actions { + class ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + + class Car_F: Car {}; + class Quadbike_01_base_F: Car_F { + class ACE_Actions: ACE_Actions { + class ACE_MainActions: ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + + class Kart_01_Base_F: Car_F { + class ACE_Actions: ACE_Actions { + class ACE_MainActions: ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + + class Tank: LandVehicle { + class ACE_Actions { + class ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + + class Motorcycle: LandVehicle { + class ACE_Actions { + class ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + + class Air; + class Helicopter: Air { + class ACE_Actions { + class ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + + class Plane: Air { + class ACE_Actions { + class ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + + class Ship; + class Ship_F: Ship { + class ACE_Actions { + class ACE_MainActions { + class KAT_ArterialTest { + displayName = CSTRING(Arterial_Test_Action); + condition = QUOTE(_target call ACEFUNC(medical_treatment,isMedicalVehicle)); + statement = ""; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialTestActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; + class Man; class CAManBase: Man { class ACE_Actions { + class ACE_MainActions { + class KAT_ApplyBloodTest { + displayName = CSTRING(Arterial_Test); + condition = "true"; + statement = "true"; + insertChildren = QUOTE([ARR_2(_target,_player)] call FUNC(addArterialApplyActions)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; class ACE_Head { class CheckBloodPressure {}; // Remove the ability to check blood pressure at the head }; diff --git a/addons/circulation/CfgWeapons.hpp b/addons/circulation/CfgWeapons.hpp index 7b371ed29..226b72b69 100644 --- a/addons/circulation/CfgWeapons.hpp +++ b/addons/circulation/CfgWeapons.hpp @@ -1,3 +1,19 @@ +#define KAT_bloodSample_ITEM(SAMPLEBASE,SAMPLEID) \ + class SAMPLEBASE##_##SAMPLEID: SAMPLEBASE { \ + scope = 1; \ + scopeArsenal = 0; \ + scopeCurator = 0; \ + nameID = SAMPLEID; \ + } + +#define KAT_bloodResult_ITEM(RESULTBASE,RESULTID) \ + class RESULTBASE##_##RESULTID: RESULTBASE { \ + scope = 1; \ + scopeArsenal = 0; \ + scopeCurator = 0; \ + testID = RESULTID; \ + } + class CfgWeapons { class ACE_ItemCore; class CBA_MiscItem_ItemInfo; @@ -139,4 +155,64 @@ class CfgWeapons { mass = 0.1; }; }; + class KAT_bloodSample: ACE_ItemCore { + author = "Mazinski"; + scope = 0; + displayName = CSTRING(sampleItemName); + model = "\A3\Structures_F_EPA\Items\Medical\Defibrillator_F.p3d"; + picture = QPATHTOF(ui\bloodIV_empty_ca.paa); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 0; + }; + }; + class KAT_bloodResult: ACE_ItemCore { + author = "Mazinski"; + scope = 0; + displayName = CSTRING(resultItemName); + model = "\A3\Structures_F_EPA\Items\Medical\Defibrillator_F.p3d"; + picture = QPATHTOF(ui\bloodIV_empty_ca.paa); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 0; + }; + }; + KAT_bloodSample_ITEM(KAT_bloodSample,1); + KAT_bloodSample_ITEM(KAT_bloodSample,2); + KAT_bloodSample_ITEM(KAT_bloodSample,3); + KAT_bloodSample_ITEM(KAT_bloodSample,4); + KAT_bloodSample_ITEM(KAT_bloodSample,5); + KAT_bloodSample_ITEM(KAT_bloodSample,6); + KAT_bloodSample_ITEM(KAT_bloodSample,7); + KAT_bloodSample_ITEM(KAT_bloodSample,8); + KAT_bloodSample_ITEM(KAT_bloodSample,9); + KAT_bloodSample_ITEM(KAT_bloodSample,10); + KAT_bloodSample_ITEM(KAT_bloodSample,11); + KAT_bloodSample_ITEM(KAT_bloodSample,12); + KAT_bloodSample_ITEM(KAT_bloodSample,13); + KAT_bloodSample_ITEM(KAT_bloodSample,14); + KAT_bloodSample_ITEM(KAT_bloodSample,15); + KAT_bloodSample_ITEM(KAT_bloodSample,16); + KAT_bloodSample_ITEM(KAT_bloodSample,17); + KAT_bloodSample_ITEM(KAT_bloodSample,18); + KAT_bloodSample_ITEM(KAT_bloodSample,19); + KAT_bloodSample_ITEM(KAT_bloodSample,20); + KAT_bloodResult_ITEM(KAT_bloodResult,1); + KAT_bloodResult_ITEM(KAT_bloodResult,2); + KAT_bloodResult_ITEM(KAT_bloodResult,3); + KAT_bloodResult_ITEM(KAT_bloodResult,4); + KAT_bloodResult_ITEM(KAT_bloodResult,5); + KAT_bloodResult_ITEM(KAT_bloodResult,6); + KAT_bloodResult_ITEM(KAT_bloodResult,7); + KAT_bloodResult_ITEM(KAT_bloodResult,8); + KAT_bloodResult_ITEM(KAT_bloodResult,9); + KAT_bloodResult_ITEM(KAT_bloodResult,10); + KAT_bloodResult_ITEM(KAT_bloodResult,11); + KAT_bloodResult_ITEM(KAT_bloodResult,12); + KAT_bloodResult_ITEM(KAT_bloodResult,13); + KAT_bloodResult_ITEM(KAT_bloodResult,14); + KAT_bloodResult_ITEM(KAT_bloodResult,15); + KAT_bloodResult_ITEM(KAT_bloodResult,16); + KAT_bloodResult_ITEM(KAT_bloodResult,17); + KAT_bloodResult_ITEM(KAT_bloodResult,18); + KAT_bloodResult_ITEM(KAT_bloodResult,19); + KAT_bloodResult_ITEM(KAT_bloodResult,20); }; diff --git a/addons/circulation/XEH_PREP.hpp b/addons/circulation/XEH_PREP.hpp index 530966fc7..a207e6fc7 100644 --- a/addons/circulation/XEH_PREP.hpp +++ b/addons/circulation/XEH_PREP.hpp @@ -1,3 +1,5 @@ +PREP(addArterialApplyActions); +PREP(addArterialTestActions); PREP(addDefibrillatorActions); PREP(AED_Analyze); PREP(AED_Charge); @@ -11,6 +13,7 @@ PREP(AEDX_ViewMonitor); PREP(AEDX_VitalsMonitor_CheckCondition); PREP(AEDX_VitalsMonitor); PREP(AEDXPlaced_VitalsMonitor_SetVolume); +PREP(attachBloodGas); PREP(bloodType); PREP(bloodTypeLog); PREP(canDraw); @@ -25,6 +28,7 @@ PREP(Defibrillator_Pads_CheckCondition); PREP(Defibrillator_RemovePads); PREP(DefibrillatorPlaced_CheckCondition); PREP(drawBlood); +PREP(drawArterial); PREP(fullHealLocal); PREP(generateBloodType); PREP(getBloodPressure); @@ -39,6 +43,7 @@ PREP(onCloseDialog); PREP(placeAED_PickUpAction); PREP(placeAED); PREP(removeLog); +PREP(showBloodGas); PREP(treatmentAdvanced_IV); PREP(updateBloodPressureChange); PREP(updateHeartRate); diff --git a/addons/circulation/XEH_preInit.sqf b/addons/circulation/XEH_preInit.sqf index 0f5bf2ebe..c03019dda 100644 --- a/addons/circulation/XEH_preInit.sqf +++ b/addons/circulation/XEH_preInit.sqf @@ -6,6 +6,14 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +if (isServer) then { + GVAR(bloodSampleMap) = createHashMap; + GVAR(sampleCounter) = 0; + + GVAR(resultSampleMap) = createHashMap; + GVAR(resultCounter) = 0; +}; + #define CBA_SETTINGS_CAT "KAT - ADV Medical: Circulation" [ diff --git a/addons/circulation/functions/fnc_AEDX_ViewMonitor.sqf b/addons/circulation/functions/fnc_AEDX_ViewMonitor.sqf index fb6aaa380..620cf416c 100644 --- a/addons/circulation/functions/fnc_AEDX_ViewMonitor.sqf +++ b/addons/circulation/functions/fnc_AEDX_ViewMonitor.sqf @@ -277,7 +277,7 @@ GVAR(PulseRateReady) = true; if (HAS_TOURNIQUET_APPLIED_ON(GVAR(AEDX_MonitorTarget),_partIndex)) then { _bp = [0,0]; } else { - _spO2 = GVAR(AEDX_MonitorTarget) getVariable [QEGVAR(breathing,airwayStatus), 100]; + _spO2 = GET_SPO2(GVAR(AEDX_MonitorTarget)); _pr = GVAR(AEDX_MonitorTarget) getVariable [QACEGVAR(medical,heartRate), 0]; }; diff --git a/addons/circulation/functions/fnc_AEDX_VitalsMonitor.sqf b/addons/circulation/functions/fnc_AEDX_VitalsMonitor.sqf index c0386abf5..f8812ae97 100644 --- a/addons/circulation/functions/fnc_AEDX_VitalsMonitor.sqf +++ b/addons/circulation/functions/fnc_AEDX_VitalsMonitor.sqf @@ -92,10 +92,10 @@ if (_patient getVariable ["kat_AEDXPatient_PFH", -1] isEqualTo -1) then { _bp = [0,0]; _pr = 0; } else { - _spO2 = _patient getVariable [QEGVAR(breathing,airwayStatus), 100]; + _spO2 = GET_SPO2(_patient); - _etco2 = _patient call EFUNC(breathing,getETCo2); - _breathrate = _patient call EFUNC(breathing,getRespiratoryRate); + _etco2 = GET_ETCO2(_patient); + _breathrate = GET_BREATHING_RATE(_patient); }; // List vitals depending on if AED pads and vitals monitoring (pressure cuff + pulse oximeter) is connected @@ -104,9 +104,9 @@ if (_patient getVariable ["kat_AEDXPatient_PFH", -1] isEqualTo -1) then { [_patient, "quick_view", LSTRING(VitalsMonitor_StatusLog)+_hasEtco2Monitor, [round(_hr), round(_bp select 1), round(_bp select 0), round(_spO2), _etco2, round(_breathrate)]] call ACEFUNC(medical_treatment,addToLog); } else { if (_patient getVariable [QGVAR(DefibrillatorPads_Connected), false]) then { - [_patient, "quick_view", LSTRING(VitalsMonitor_VMInactive_StatusLog)+_hasEtco2Monitor, [round(_hr), _etco2, round(_breathrate)]] call ACEFUNC(medical_treatment,addToLog); + [_patient, "quick_view", LSTRING(VitalsMonitor_VMInactive_StatusLog)+_hasEtco2Monitor, [round(_hr), round(_etco2), round(_breathrate)]] call ACEFUNC(medical_treatment,addToLog); } else { - [_patient, "quick_view", LSTRING(VitalsMonitor_VMActive_StatusLog)+_hasEtco2Monitor, [round(_pr), round(_bp select 1), round(_bp select 0), round(_spO2), _etco2, round(_breathrate)]] call ACEFUNC(medical_treatment,addToLog); + [_patient, "quick_view", LSTRING(VitalsMonitor_VMActive_StatusLog)+_hasEtco2Monitor, [round(_pr), round(_bp select 1), round(_bp select 0), round(_spO2), round(_etco2), round(_breathrate)]] call ACEFUNC(medical_treatment,addToLog); }; }; @@ -291,7 +291,7 @@ if (_patient getVariable [QGVAR(AED_X_VitalsMonitor_Connected), false] && {(_pat if (_patient getVariable [QGVAR(DefibrillatorInUse), false] || !(_patient getVariable [QGVAR(AED_X_VitalsMonitor_VolumePatient), false])) then { } else { private _hr = _patient getVariable [QACEGVAR(medical,heartRate), 80]; - private _spO2 = _patient getVariable [QEGVAR(breathing,airwayStatus), 100]; + private _spO2 = GET_SPO2(_patient); if (_spO2 < GVAR(AED_X_Monitor_SpO2Warning) || _tourniquetApplied) then { playSound3D [QPATHTOF_SOUND(sounds\spo2warning.wav), _soundSource, false, getPosASL _soundSource, 5, 1, 15]; }; diff --git a/addons/circulation/functions/fnc_addArterialApplyActions.sqf b/addons/circulation/functions/fnc_addArterialApplyActions.sqf new file mode 100644 index 000000000..b23bdfb62 --- /dev/null +++ b/addons/circulation/functions/fnc_addArterialApplyActions.sqf @@ -0,0 +1,55 @@ +#include "..\script_component.hpp" +/* + * Author: SzwedzikPL, mharis001 + * Modified: Mazinski + * Apply arterial blood gas test to patient. + * + * Arguments: + * 0: Patient + * 1: Medic + * + * Return Value: + * Ace actions + * + * Example: + * [patient, medic] call kat_circulation_fnc_addArterialApplyActions; + * + * Public: No + */ + +params ["_target", "_player"]; + +private _fnc_getActions = { + private _actions = []; + private _cfgWeapons = configFile >> "CfgWeapons"; + private _idNumber = 0; + + { + private _config = _cfgWeapons >> _x; + _idNumber = getNumber (_config >> "testID"); + + if (_idNumber > 0) then { + private _bloodTestArray = GVAR(resultSampleMap) get _idNumber; + private _patient = _bloodTestArray select 0; + + _actions pushBack [ + [ + _x, + format [LLSTRING(Apply_Arterial_Test), _patient], + "", + {_this call FUNC(attachBloodGas)}, + {true}, + {}, + [] + ] call ACEFUNC(interact_menu,createAction), + [], + [_bloodTestArray, _target, _idNumber, _player] + ]; + }; + } forEach ([_player, 0] call ACEFUNC(common,uniqueItems)); + + _actions +}; + + +[[], _fnc_getActions, _player, QGVAR(actionsCache), 9999, "cba_events_loadoutEvent"] call ACEFUNC(common,cachedCall); \ No newline at end of file diff --git a/addons/circulation/functions/fnc_addArterialTestActions.sqf b/addons/circulation/functions/fnc_addArterialTestActions.sqf new file mode 100644 index 000000000..934fa14b5 --- /dev/null +++ b/addons/circulation/functions/fnc_addArterialTestActions.sqf @@ -0,0 +1,58 @@ +#include "..\script_component.hpp" +/* + * Author: SzwedzikPL, mharis001 + * Modified: Mazinski + * Add arterial blood gas test action to vehicle. + * + * Arguments: + * 0: Vehicle + * 1: Medic + * + * Return Value: + * Ace actions + * + * Example: + * [vehicle, medic] call kat_circulation_fnc_addArterialTestActions; + * + * Public: No + */ + +params ["_vehicle", "_player"]; + +private _fnc_getActions = { + private _actions = []; + private _cfgWeapons = configFile >> "CfgWeapons"; + private _idNumber = 0; + + { + private _config = _cfgWeapons >> _x; + _idNumber = getNumber (_config >> "nameID"); + + if (_idNumber > 0) then { + private _bloodSampleArray = GVAR(bloodSampleMap) get _idNumber; + private _patient = _bloodSampleArray select 0; + + _actions pushBack [ + [ + _x, + format [LLSTRING(Blood_Sample_String), _patient], + "", + {_this call FUNC(showBloodGas)}, + {true}, + {}, + [], + {[0, 0, 0]}, + 2, + [false,false,false,false,false] + ] call ACEFUNC(interact_menu,createAction), + [], + [_bloodSampleArray, _player, _idNumber, _vehicle] + ]; + }; + } forEach ([_vehicle, 0] call ACEFUNC(common,uniqueItems)); + + _actions +}; + + +[[], _fnc_getActions, _player, QGVAR(actionsCache), 9999, "cba_events_loadoutEvent"] call ACEFUNC(common,cachedCall); \ No newline at end of file diff --git a/addons/circulation/functions/fnc_attachBloodGas.sqf b/addons/circulation/functions/fnc_attachBloodGas.sqf new file mode 100644 index 000000000..cb974d473 --- /dev/null +++ b/addons/circulation/functions/fnc_attachBloodGas.sqf @@ -0,0 +1,23 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Attaches ABG test to patient + * + * Arguments: + * 0: Array + * + * Return Value: + * None + * + * Example: + * [[[40,90,0.96,24,7.4,37], "Patient"], patient] call kat_circulation_fnc_attachBloodGas; + * + * Public: No + */ +params ["_entries"]; +_entries params ["_bloodGas", "_patient", "_idNumber", "_player"]; +_bloodGas params ["_patientName", "_bloodGasArray"]; + +_patient setVariable [QGVAR(testedBloodGas), _bloodGasArray, true]; + +_player removeItem (format ["KAT_bloodResult_%1",_idNumber]); \ No newline at end of file diff --git a/addons/circulation/functions/fnc_canDraw.sqf b/addons/circulation/functions/fnc_canDraw.sqf index 48c74987c..be156c753 100644 --- a/addons/circulation/functions/fnc_canDraw.sqf +++ b/addons/circulation/functions/fnc_canDraw.sqf @@ -20,7 +20,7 @@ params ["_medic", "_patient", "_volume"]; private _bagItem = format ["ACE_bloodIV_%1", _volume]; -private _bloodVolume = (_patient getVariable [QACEGVAR(medical,bloodVolume), 6.0]); -private _volumeChange = _volume/1000; +private _bloodVolume = GET_BLOOD_VOLUME_LITERS(_patient); +private _volumeChange = _volume/ML_TO_LITERS; if (((_bloodVolume - _volumeChange) > GVAR(blood_draw_limit))) exitWith {true}; false diff --git a/addons/circulation/functions/fnc_cprLocal.sqf b/addons/circulation/functions/fnc_cprLocal.sqf index 4a0a2ab02..f338990dd 100644 --- a/addons/circulation/functions/fnc_cprLocal.sqf +++ b/addons/circulation/functions/fnc_cprLocal.sqf @@ -91,24 +91,24 @@ switch (_reviveObject) do { if (GVAR(enable_CPR_Chances)) then { switch (_medic getVariable [QACEGVAR(medical,medicClass),0]) do { case 0: { - _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME(_patient), GVAR(CPR_MinChance_Default), GVAR(CPR_MaxChance_Default), true]; + _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME_LITERS(_patient), GVAR(CPR_MinChance_Default), GVAR(CPR_MaxChance_Default), true]; }; case 1: { - _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME(_patient), GVAR(CPR_MinChance_RegularMedic), GVAR(CPR_MaxChance_RegularMedic), true]; + _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME_LITERS(_patient), GVAR(CPR_MinChance_RegularMedic), GVAR(CPR_MaxChance_RegularMedic), true]; }; case 2: { - _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME(_patient), GVAR(CPR_MinChance_Doctor), GVAR(CPR_MaxChance_Doctor), true]; + _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME_LITERS(_patient), GVAR(CPR_MinChance_Doctor), GVAR(CPR_MaxChance_Doctor), true]; }; }; }; }; case "AED": { [_patient, "activity", LSTRING(Activity_Shock), [[_medic, false, true] call ACEFUNC(common,getName), "AED"]] call ACEFUNC(medical_treatment,addToLog); - _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME(_patient), GVAR(AED_MinChance), GVAR(AED_MaxChance), true]; + _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME_LITERS(_patient), GVAR(AED_MinChance), GVAR(AED_MaxChance), true]; }; case "AEDX": { [_patient, "activity", LSTRING(Activity_Shock), [[_medic, false, true] call ACEFUNC(common,getName), "AED-X"]] call ACEFUNC(medical_treatment,addToLog); - _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME(_patient), GVAR(AED_X_MinChance), GVAR(AED_X_MaxChance), true]; + _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME_LITERS(_patient), GVAR(AED_X_MinChance), GVAR(AED_X_MaxChance), true]; }; }; @@ -138,7 +138,7 @@ if (_reviveObject in ["AED", "AEDX"]) exitWith { if !(GVAR(enable_CPR_Chances)) then { private _min = ACEGVAR(medical_treatment,cprSuccessChanceMin); private _max = ACEGVAR(medical_treatment,cprSuccessChanceMax); - _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME(_patient), _min, _max, true]; + _chance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, GET_BLOOD_VOLUME_LITERS(_patient), _min, _max, true]; // ACE Medical settings are percentages (decimals, 0 <= x <= 1) instead of integers if ((random 1) <= _chance) then { diff --git a/addons/circulation/functions/fnc_drawArterial.sqf b/addons/circulation/functions/fnc_drawArterial.sqf new file mode 100644 index 000000000..893014288 --- /dev/null +++ b/addons/circulation/functions/fnc_drawArterial.sqf @@ -0,0 +1,29 @@ +#include "..\script_component.hpp" +/* + * Author: Battlekeeper, modified by YetheSamartaka, Mazinski + * Refactored by Slatery + * Handles drawing of arterial blood + * + * Arguments: + * 0: Medic + * 1: Patient + * + * Return Value: + * None + * + * Example: + * [medic, patient] call kat_circulation_fnc_drawArterial; + * + * Public: No + */ + +params ["_medic", "_patient"]; + +private _bloodGas = GET_BLOOD_GAS(_patient); + +GVAR(sampleCounter) = [GVAR(sampleCounter) +1, 1] select (GVAR(sampleCounter) == 20); +GVAR(bloodSampleMap) set [GVAR(sampleCounter), [name(_patient), _bloodGas]]; + +private _itemStr = format ["KAT_bloodSample_%1", GVAR(sampleCounter)]; + +[_medic, _itemStr, true] call CBA_fnc_addItem; \ No newline at end of file diff --git a/addons/circulation/functions/fnc_drawBlood.sqf b/addons/circulation/functions/fnc_drawBlood.sqf index 2c2e2c66a..1be0c6940 100644 --- a/addons/circulation/functions/fnc_drawBlood.sqf +++ b/addons/circulation/functions/fnc_drawBlood.sqf @@ -23,8 +23,7 @@ params ["_medic", "_patient", "_volume"]; private _modStr = "ACE_"; private _bloodtypeStr = ""; private _bagVolumeStr = format ["_%1",_volume]; -private _volumeChange = _volume/1000; -private _bloodVolume = (_patient getVariable [QACEGVAR(medical,bloodVolume), 6.0]); + if (GVAR(bloodGroups)) then { _modStr = "kat_"; _bloodtype = [_patient] call FUNC(bloodType); @@ -32,4 +31,5 @@ if (GVAR(bloodGroups)) then { }; private _itemStr = format ["%1bloodIV%2%3",_modStr,_bloodtypeStr,_bagVolumeStr]; [_medic, _itemStr] call ACEFUNC(common,addToInventory); -_patient setVariable [QACEGVAR(medical,bloodVolume), _bloodVolume - _volumeChange,true]; + +REDUCE_TOTAL_BLOOD_VOLUME(_patient,_volume); \ No newline at end of file diff --git a/addons/circulation/functions/fnc_fullHealLocal.sqf b/addons/circulation/functions/fnc_fullHealLocal.sqf index cc1efb5b4..b0a87f39c 100644 --- a/addons/circulation/functions/fnc_fullHealLocal.sqf +++ b/addons/circulation/functions/fnc_fullHealLocal.sqf @@ -24,10 +24,19 @@ _patient setVariable [QGVAR(cardiacArrestType), 0, true]; _patient setVariable [VAR_BLOODPRESSURE_CHANGE, nil, true]; +_patient setVariable [QGVAR(bodyFluid), DEFAULT_BODY_FLUID]; + _patient setVariable [QGVAR(isPerformingCPR), false, true]; _patient setVariable [QGVAR(OxygenationPeriod), 0, true]; +_patient setVariable [QGVAR(tourniquetTime), [0,0,0,0,0,0]]; + +// PaCO2, PaO2, O2 Sat, HCO3, pH, ETCO2 +_patient setVariable [QGVAR(bloodGas), DEFAULT_BLOOD_GAS, true]; +_patient setVariable [QGVAR(testedBloodGas), [0,0,0,0,0,0], true]; + _patient setVariable [QGVAR(ht), [], true]; _patient setVariable [QGVAR(effusion), 0, true]; [_patient, true] call FUNC(updateInternalBleeding); + diff --git a/addons/circulation/functions/fnc_handleCardiacArrest.sqf b/addons/circulation/functions/fnc_handleCardiacArrest.sqf index 92b4c38c6..307b12e01 100644 --- a/addons/circulation/functions/fnc_handleCardiacArrest.sqf +++ b/addons/circulation/functions/fnc_handleCardiacArrest.sqf @@ -39,7 +39,7 @@ if ((_unit getVariable [QGVAR(cardiacArrestType), 0] != 0) && _initial) then { if (_initial) then { if !(_active) exitWith {}; - if (_unit getVariable [QACEGVAR(medical,bloodVolume), 6.0] < GVAR(AdvRhythm_asystoleBloodlossThreshold)) then { + if (GET_BLOOD_VOLUME_LITERS(_unit) < GVAR(AdvRhythm_asystoleBloodlossThreshold)) then { if (floor (random 100) < GVAR(AdvRhythm_PEAChance)) then { _cardiacArrestType = 2; } else { @@ -76,7 +76,7 @@ if (GVAR(AdvRhythm_canDeteriorate)) then { [{ params ["_unit"]; - _unit getVariable [QACEGVAR(medical,bloodVolume), 6.0] < GVAR(AdvRhythm_asystoleBloodlossThreshold) && _unit getVariable [QGVAR(cardiacArrestType), 0] > 2 + GET_BLOOD_VOLUME_LITERS(_unit) < GVAR(AdvRhythm_asystoleBloodlossThreshold) && _unit getVariable [QGVAR(cardiacArrestType), 0] > 2 }, { params ["_unit"]; @@ -115,7 +115,7 @@ if (GVAR(AdvRhythm_canDeteriorate)) then { [{ params ["_unit"]; - _unit getVariable [QACEGVAR(medical,bloodVolume), 6.0] < GVAR(AdvRhythm_asystoleBloodlossThreshold) && _unit getVariable [QGVAR(cardiacArrestType), 0] > 2 + GET_BLOOD_VOLUME_LITERS(_unit) < GVAR(AdvRhythm_asystoleBloodlossThreshold) && _unit getVariable [QGVAR(cardiacArrestType), 0] > 2 }, { // If past asystole bloodloss threshold params ["_unit"]; diff --git a/addons/circulation/functions/fnc_showBloodGas.sqf b/addons/circulation/functions/fnc_showBloodGas.sqf new file mode 100644 index 000000000..5954c20b4 --- /dev/null +++ b/addons/circulation/functions/fnc_showBloodGas.sqf @@ -0,0 +1,31 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Checks patient temperature + * + * Arguments: + * 0: Array + * + * Return Value: + * None + * + * Example: + * [[[40,90,0.96,24,7.4,37], "Patient"], patient] call kat_circulation_fnc_showBloodGas; + * + * Public: No + */ +params ["_entries"]; +_entries params ["_bloodGas", "_player", "_idNumber", "_vehicle"]; +_bloodGas params ["_patientName", "_bloodGasArray"]; +_bloodGasArray params ["_paCO2", "_paO2", "_spO2", "_hCO2", "_pH", "_etCO2"]; + +private _output = format ["Patient: %1, PaCO2: %2, PaO2: %3, SpO2: %4, HCO2: %5, pH: %6", _patientName, _paCO2 toFixed 2, _paO2 toFixed 2, _spO2 toFixed 2, _hCO2 toFixed 2, _pH toFixed 2]; +[_output, 3, _player] call ACEFUNC(common,displayTextStructured); + +GVAR(resultCounter) = if (GVAR(resultCounter) == 20) then { 1 } else { GVAR(resultCounter) + 1 }; +GVAR(resultSampleMap) set [GVAR(resultCounter), [_patientName, _bloodGasArray]]; + +private _itemStr = format ["KAT_bloodResult_%1",GVAR(resultCounter)]; + +[_vehicle, (format ["KAT_bloodSample_%1",_idNumber])] call CBA_fnc_removeItemCargo; +[_player, _itemStr, true] call CBA_fnc_addItem; \ No newline at end of file diff --git a/addons/circulation/functions/fnc_updateHeartRate.sqf b/addons/circulation/functions/fnc_updateHeartRate.sqf index d41f8399a..6a8a75579 100644 --- a/addons/circulation/functions/fnc_updateHeartRate.sqf +++ b/addons/circulation/functions/fnc_updateHeartRate.sqf @@ -33,7 +33,7 @@ if IN_CRDC_ARRST(_unit) then { } else { private _hrChange = 0; private _targetHR = 0; - private _bloodVolume = GET_BLOOD_VOLUME(_unit); + private _bloodVolume = GET_BLOOD_VOLUME_LITERS(_unit); if (_bloodVolume > BLOOD_VOLUME_CLASS_4_HEMORRHAGE) then { GET_BLOOD_PRESSURE(_unit) params ["_bloodPressureL", "_bloodPressureH"]; private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL; diff --git a/addons/circulation/stringtable.xml b/addons/circulation/stringtable.xml index 6dbfcc5c8..09da92a68 100644 --- a/addons/circulation/stringtable.xml +++ b/addons/circulation/stringtable.xml @@ -18,6 +18,9 @@ ACE - Circulação ativada? ACE-Kierto aktivoitu? + + AI Simple Medical activated? + Advanced Rhythms activated? Fortgeschrittenen Rhythmus aktivieren? @@ -1561,6 +1564,18 @@ PR Ритм (PR) + + %1 Blood Sample + + + Run ABG Test + + + ABG Test + + + Apply %1 Test + Blood groups cheat sheet Blutgruppentabelle @@ -2410,6 +2425,15 @@ Extrair sangue (250ml) Ottaa verta (250ml) + + Draw Arterial Sample + + + Blood Sample + + + ABG Result + Drawing Blood Pobieranie krwi diff --git a/addons/gui/CfgFunctions.hpp b/addons/gui/CfgFunctions.hpp index 751d0352a..a9e6c4cd1 100644 --- a/addons/gui/CfgFunctions.hpp +++ b/addons/gui/CfgFunctions.hpp @@ -2,6 +2,9 @@ class CfgFunctions { class overwrite_medical_gui { tag = "ace_medical_gui"; class ace_medical_gui { + class menuPFH { + file = QPATHTOF(functions\fnc_menuPFH.sqf); + }; class onMenuClose { file = QPATHTOF(functions\fnc_onMenuClose.sqf); }; diff --git a/addons/gui/XEH_PREP.hpp b/addons/gui/XEH_PREP.hpp index 4c42ae836..692458635 100644 --- a/addons/gui/XEH_PREP.hpp +++ b/addons/gui/XEH_PREP.hpp @@ -1,6 +1,11 @@ +PREP(dumpBloodGas); +PREP(handleIVAdjust); PREP(logListAppended); +PREP(menuPFH); PREP(onMenuClose); PREP(onMenuOpen); PREP(updateCategories); PREP(updateInjuryList); -PREP(updateBodyImage); \ No newline at end of file +PREP(updateBodyImage); +PREP(updateIVStatus); +PREP(updateABGStatus); \ No newline at end of file diff --git a/addons/gui/functions/fnc_dumpBloodGas.sqf b/addons/gui/functions/fnc_dumpBloodGas.sqf new file mode 100644 index 000000000..a0250af6b --- /dev/null +++ b/addons/gui/functions/fnc_dumpBloodGas.sqf @@ -0,0 +1,20 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinksi + * Removes blood gas testing values + * + * Arguments: + * 0: Target + * + * Return Value: + * None + * + * Example: + * [_target] call kat_medical_gui_fnc_dumpBloodGas; + * + * Public: No + */ + +params ["_target"]; + + _target setVariable [QEGVAR(circulation,testedBloodGas), [0,0,0,0,0,0], true]; \ No newline at end of file diff --git a/addons/gui/functions/fnc_handleIVAdjust.sqf b/addons/gui/functions/fnc_handleIVAdjust.sqf new file mode 100644 index 000000000..5bc50112c --- /dev/null +++ b/addons/gui/functions/fnc_handleIVAdjust.sqf @@ -0,0 +1,25 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinksi + * Adjusts IV flow rates from GUI + * + * Arguments: + * 0: Target + * 1: Body Part + * 2: Adjust Value + * + * Return Value: + * None + * + * Example: + * [_target, 2, 0.5] call kat_medical_gui_fnc_handleIVAdjust; + * + * Public: No + */ + +params ["_target", "_bodyPartN", "_adjust"]; + +private _ivFlow = _target getVariable [QEGVAR(pharma,IVFlow),[0,0,0,0,0,0]]; + +_ivFlow set [_bodyPartN, ((((_ivFlow select _bodyPartN) + _adjust) max 0) min 1.5)]; +_target setVariable [QEGVAR(pharma,IVFlow), _ivFlow, true]; \ No newline at end of file diff --git a/addons/gui/functions/fnc_menuPFH.sqf b/addons/gui/functions/fnc_menuPFH.sqf new file mode 100644 index 000000000..e469fa9fe --- /dev/null +++ b/addons/gui/functions/fnc_menuPFH.sqf @@ -0,0 +1,65 @@ +#include "..\script_component.hpp" +/* + * Author: mharis001 + * Modified: Mazinski + * Handles updating the Medical Menu UI for the current target. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_medical_gui_fnc_menuPFH + * + * Public: No + */ + +// Check if menu should stay open for target +if !( + ([ACE_player, ACEGVAR(medical_gui,target), ["isNotInside", "isNotSwimming"]] call ACEFUNC(common,canInteractWith) || {!isNull findDisplay 312}) && // Allow player to look at himself when unconsious and in Zeus + {[ACE_player, ACEGVAR(medical_gui,target)] call ACEFUNC(medical_gui,canOpenMenu)} +) then { + closeDialog 0; + // Show hint if distance condition failed + if ((ACE_player distance ACEGVAR(medical_gui,target) > ACEGVAR(medical_gui,maxDistance)) && {vehicle ACE_player != vehicle ACEGVAR(medical_gui,target)}) then { + [[ACELSTRING(medical,DistanceToFar), ACEGVAR(medical_gui,target) call ACEFUNC(common,getName)], 2] call ACEFUNC(common,displayTextStructured); + }; +}; + +// Get the Medical Menu display +private _display = uiNamespace getVariable [QACEGVAR(medical_gui,menuDisplay), displayNull]; +if (isNull _display) exitWith {}; + +// Update treatment category buttons +[_display] call ACEFUNC(medical_gui,updateCategories); + +// Update treatment actions for current category +[_display] call ACEFUNC(medical_gui,updateActions); + +// Update IV Status +[ACEGVAR(medical_gui,target)] call FUNC(updateIVStatus); + +// Update Blood Gas +[ACEGVAR(medical_gui,target)] call FUNC(updateABGStatus); + +// Update injury list +private _ctrlInjuries = _display displayCtrl IDC_INJURIES; +[_ctrlInjuries, ACEGVAR(medical_gui,target), ACEGVAR(medical_gui,selectedBodyPart)] call ACEFUNC(medical_gui,updateInjuryList); + +// Update body image +private _ctrlBodyImage = _display displayCtrl IDC_BODY_GROUP; +[_ctrlBodyImage, ACEGVAR(medical_gui,target), ACEGVAR(medical_gui,selectedBodyPart)] call ACEFUNC(medical_gui,updateBodyImage); + +// Update activity and quick view logs +private _ctrlActivityLog = _display displayCtrl IDC_ACTIVITY; +private _activityLog = ACEGVAR(medical_gui,target) getVariable [MED_LOG_VARNAME("activity"), []]; +[_ctrlActivityLog, _activityLog] call ACEFUNC(medical_gui,updateLogList); + +private _ctrlQuickView = _display displayCtrl IDC_QUICKVIEW; +private _quickView = ACEGVAR(medical_gui,target) getVariable [MED_LOG_VARNAME("quick_view"), []]; +[_ctrlQuickView, _quickView] call ACEFUNC(medical_gui,updateLogList); + +// Update triage status +[_display, ACEGVAR(medical_gui,target)] call ACEFUNC(medical_gui,updateTriageStatus); \ No newline at end of file diff --git a/addons/gui/functions/fnc_updateABGStatus.sqf b/addons/gui/functions/fnc_updateABGStatus.sqf new file mode 100644 index 000000000..e81b03228 --- /dev/null +++ b/addons/gui/functions/fnc_updateABGStatus.sqf @@ -0,0 +1,34 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinksi + * Updates ABG status GUI + * + * Arguments: + * 0: Target + * + * Return Value: + * None + * + * Example: + * [_target] call kat_medical_gui_fnc_updateABGStatus; + * + * Public: No + */ + +params ["_target"]; + +// Get tourniquets, damage, and blood loss for target +private _bloodGasTest = _target getVariable [QEGVAR(circulation,testedBloodGas), [0,0,0,0,0,0]]; +private _activeBlood = 0; + +{ + _x params ["_watchIDC"]; + + _activeBlood = _bloodGasTest select _forEachIndex; + + if (_activeBlood != 0) then { + ctrlSetText [_watchIDC, (_activeBlood toFixed 2)]; + } else { + ctrlSetText [_watchIDC, "--.-"]; + }; +} forEach [IDC_TEST_PACO2, IDC_TEST_PAO2, IDC_TEST_SPO2, IDC_TEST_HCO3, IDC_TEST_PH]; \ No newline at end of file diff --git a/addons/gui/functions/fnc_updateIVStatus.sqf b/addons/gui/functions/fnc_updateIVStatus.sqf new file mode 100644 index 000000000..f1773ff1f --- /dev/null +++ b/addons/gui/functions/fnc_updateIVStatus.sqf @@ -0,0 +1,69 @@ +#include "..\script_component.hpp" +/* + * Author: Glowbal, kymckay, mharis001 + * Updates the body image for given target. + * + * Arguments: + * 0: Body image controls group + * 1: Target + * 2: Body part + * + * Return Value: + * None + * + * Example: + * [CONTROL, _target, 0] call ace_medical_gui_fnc_updateBodyImage + * + * Public: No + */ + +params ["_target"]; + +// Get tourniquets, damage, and blood loss for target +private _IV = _target getVariable [QEGVAR(pharma,IV), [0,0,0,0,0,0]]; +private _ivFlow = _target getVariable [QEGVAR(pharma,IVflow), [0,0,0,0,0,0]]; + +{ + _x params ["_coverIDC", "_titleIDC", "_typeIDC", "_valueIDC", "_buttonIDCArray", "_bodyPartN"]; + + private _activeIV = _IV select _bodyPartN; + private _activeFlow = _ivFlow select _bodyPartN; + + switch (true) do { + case (_activeIV == 0): { + ctrlShow [_coverIDC, true]; + ctrlShow [_titleIDC, false]; + ctrlShow [_typeIDC, false]; + ctrlShow [_valueIDC, false]; + _buttonIDCArray apply {ctrlShow [_x, false]}; + _buttonIDCArray apply {ctrlEnable [_x, false]}; + }; + case (_activeIV == 1): { + ctrlShow [_coverIDC, false]; + ctrlShow [_titleIDC, true]; + ctrlShow [_typeIDC, true]; + ctrlShow [_valueIDC, true]; + _buttonIDCArray apply {ctrlShow [_x, true]}; + _buttonIDCArray apply {ctrlEnable [_x, true]}; + ctrlSetText [_typeIDC, "IO"]; + ctrlSetText [_valueIDC, (_activeFlow toFixed 1)]; + }; + case (_activeIV > 1): { + ctrlShow [_coverIDC, false]; + ctrlShow [_titleIDC, true]; + ctrlShow [_typeIDC, true]; + ctrlShow [_valueIDC, true]; + _buttonIDCArray apply {ctrlShow [_x, true]}; + _buttonIDCArray apply {ctrlEnable [_x, true]}; + ctrlSetText [_typeIDC, "IV"]; + ctrlSetText [_valueIDC, (_activeFlow toFixed 1)]; + }; + }; +} forEach [ + [IDC_IV_FLOW_HEADCOVER, IDC_IV_FLOW_HEADTITLE, IDC_IV_FLOW_HEADTYPE, IDC_IV_FLOW_HEADIV_VALUE, [IDC_IV_FLOW_HEADSUBTRACTFULL, IDC_IV_FLOW_HEADSUBTRACT, IDC_IV_FLOW_HEADADD, IDC_IV_FLOW_HEADADDFULL], 0], + [IDC_IV_FLOW_CHESTCOVER, IDC_IV_FLOW_CHESTTITLE, IDC_IV_FLOW_CHESTTYPE, IDC_IV_FLOW_CHESTTEST, [IDC_IV_FLOW_CHESTSUBTRACTFULL, IDC_IV_FLOW_CHESTSUBTRACT, IDC_IV_FLOW_CHESTADD, IDC_IV_FLOW_CHESTADDFULL], 1], + [IDC_IV_FLOW_LARMCOVER, IDC_IV_FLOW_LARMTITLE, IDC_IV_FLOW_LARMTYPE, IDC_IV_FLOW_LARMIVVALUE, [IDC_IV_FLOW_LARMSUBTRACTFULL, IDC_IV_FLOW_LARMSUBTRACT, IDC_IV_FLOW_LARMADD, IDC_IV_FLOW_LARMADDFULL], 2], + [IDC_IV_FLOW_RARMCOVER, IDC_IV_FLOW_RARMTITLE, IDC_IV_FLOW_RARMTYPE, IDC_IV_FLOW_RARMIVVALUE, [IDC_IV_FLOW_RARMSUBTRACTFULL, IDC_IV_FLOW_RARMSUBTRACT, IDC_IV_FLOW_RARMADD, IDC_IV_FLOW_RARMADDFULL], 3], + [IDC_IV_FLOW_LLEGCOVER, IDC_IV_FLOW_LLEGTITLE, IDC_IV_FLOW_LLEGTYPE, IDC_IV_FLOW_LLEGIVVALUE, [IDC_IV_FLOW_LLEGSUBTRACTFULL, IDC_IV_FLOW_LLEGSUBTRACT, IDC_IV_FLOW_LLEGADD, IDC_IV_FLOW_LLEGADDFULL], 4], + [IDC_IV_FLOW_RLEGCOVER, IDC_IV_FLOW_RLEGTITLE, IDC_IV_FLOW_RLEGTYPE, IDC_IV_FLOW_RLEGIVVALUE, [IDC_IV_FLOW_RLEGSUBTRACTFULL, IDC_IV_FLOW_RLEGSUBTRACT, IDC_IV_FLOW_RLEGADD, IDC_IV_FLOW_RLEGADDFULL], 5] +]; \ No newline at end of file diff --git a/addons/gui/functions/fnc_updateInjuryList.sqf b/addons/gui/functions/fnc_updateInjuryList.sqf index 64e029206..55511183e 100644 --- a/addons/gui/functions/fnc_updateInjuryList.sqf +++ b/addons/gui/functions/fnc_updateInjuryList.sqf @@ -199,7 +199,13 @@ if (ACEGVAR(medical_gui,showDamageEntry)) then { // Indicate if a tourniquet is applied if (HAS_TOURNIQUET_ACTUAL(_target,_selectionN)) then { - _entries pushBack [localize ACELSTRING(medical_gui,Status_Tourniquet_Applied), [0.77, 0.51, 0.08, 1]]; + _entries pushBack [format ["%1 [%2]", localize ACELSTRING(medical_gui,Status_Tourniquet_Applied), _target getVariable [QEGVAR(circulation,tourniquetTime), [0,0,0,0,0,0]] select _selectionN], [0.77, 0.51, 0.08, 1]]; +}; + +private _warmerPlaced = _target getVariable [QEGVAR(hypothermia,fluidWarmer), [0,0,0,0,0,0]]; + +if (_warmerPlaced select _selectionN == 1) then { + _entries pushBack [LELSTRING(hypothermia,LineWarmer), [1, 0.75, 0.18, 1]]; }; // Indicate current body part fracture status diff --git a/addons/gui/gui.hpp b/addons/gui/gui.hpp index 47d2e2751..9514c98f1 100644 --- a/addons/gui/gui.hpp +++ b/addons/gui/gui.hpp @@ -1,4 +1,5 @@ class RscText; +class RscStructuredText; class RscButton; class RscPicture; class RscListBox; @@ -105,7 +106,460 @@ class ACEGVAR(medical_gui,BodyImage): RscControlsGroupNoScrollbars { }; class ACE_Medical_Menu { - class Controls { + class controlsBackground { + class IVFlowBackground: RscText { + idc = IDC_IV_FLOW_BACKGROUND; // LOOK HERE + x = QUOTE(POS_X(-8.5)); + y = QUOTE(POS_Y(1.1)); + w = QUOTE(POS_W(9)); + h = QUOTE(POS_H(16.3)); + colorBackground[] = {0, 0, 0, 0.7}; + }; + class IVFlowTitle: RscText { + idc = IDC_IV_FLOW_TITLE; // LOOK HERE + text = CSTRING(IVFlowTitle); + x = QUOTE(POS_X(-8.5)); + y = QUOTE(POS_Y(0)); + w = QUOTE(POS_W(9)); + h = QUOTE(POS_H(1)); + colorBackground[] = GUI_BCG_COLOR; // LOOK HERE + show = 1; + class Attributes { + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "true"; + }; + }; + class ABGBackground: IVFlowBackground { + idc = IDC_ABG_BACKGROUND; // LOOK HERE + x = QUOTE(POS_X(39.6)); + y = QUOTE(POS_Y(1.1)); + w = QUOTE(POS_W(9)); + h = QUOTE(POS_H(3.3)); + }; + class ABGTitle: IVFlowTitle { + idc = IDC_ABG_TITLE; // LOOK HERE + text = CSTRING(ABGTitle); + x = QUOTE(POS_X(39.6)); + y = QUOTE(POS_Y(0)); + w = QUOTE(POS_W(9)); + h = QUOTE(POS_H(1)); + show = 1; + class Attributes { + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "true"; + }; + }; + }; + class controls { + class HeadCover: RscStructuredText { + idc = IDC_IV_FLOW_HEADCOVER; // LOOK HERE + text = CSTRING(HeadCover); + x = QUOTE(POS_X(-8)); + y = QUOTE(POS_Y(2.3)); + w = QUOTE(POS_W(8)); + h = QUOTE(POS_H(1.3)); + colorBackground[] = {0, 0, 0, 0.5}; + show = 1; + class Attributes { + align = "center"; + valign = "bottom"; + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + }; + }; + class HeadTitle: RscStructuredText { + idc = IDC_IV_FLOW_HEADTITLE; // LOOK HERE + text = CSTRING(HeadTitle); + x = QUOTE(POS_X(-6.6)); + y = QUOTE(POS_Y(1.5)); + w = QUOTE(POS_W(2.2)); + h = QUOTE(POS_H(0.8)); + colorBackground[] = {0, 0, 0, 0}; + show = 0; + class Attributes { + align = "center"; + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + size = 0.9; + }; + }; + class HeadType: RscStructuredText { + idc = IDC_IV_FLOW_HEADTYPE; // LOOK HERE + x = QUOTE(POS_X(-3.6)); + y = QUOTE(POS_Y(1.5)); + w = QUOTE(POS_W(2)); + h = QUOTE(POS_H(0.8)); + colorBackground[] = {0, 0, 0, 0}; + show = 0; + class Attributes { + align = "center"; + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + size = 0.9; + }; + }; + class HeadSubtractFull: RscButton { + idc = IDC_IV_FLOW_HEADSUBTRACTFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),0,-0.5)] call FUNC(handleIVAdjust)); + text = "<<"; + x = QUOTE(POS_X(-7.5)); + y = QUOTE(POS_Y(2.5)); + w = QUOTE(POS_W(1)); + h = QUOTE(POS_H(1)); + show = 0; + colorBackground[] = {0, 0, 0, 0.7}; + colorBackgroundActive[] = {1, 1, 1, 1}; + colorBackgroundDisabled[] = {0, 0, 0, 0.7}; + colorBorder[] = {0,0,0,0}; + class Attributes { + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + }; + }; + class HeadSubtract: RscButton { + idc = IDC_IV_FLOW_HEADSUBTRACT; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),0,-0.1)] call FUNC(handleIVAdjust)); + text = "<"; + x = QUOTE(POS_X(-6)); + y = QUOTE(POS_Y(2.5)); + w = QUOTE(POS_W(1)); + h = QUOTE(POS_H(1)); + show = 0; + colorBackground[] = {0, 0, 0, 0.7}; + colorBackgroundActive[] = {1, 1, 1, 1}; + colorBackgroundDisabled[] = {0, 0, 0, 0.7}; + colorBorder[] = {0,0,0,0}; + class Attributes { + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + }; + }; + class HeadIVValue: RscStructuredText { + idc = IDC_IV_FLOW_HEADIV_VALUE; // LOOK HERE + text = CSTRING(IVValue); + x = QUOTE(POS_X(-5)); + y = QUOTE(POS_Y(2.5)); + w = QUOTE(POS_W(2)); + h = QUOTE(POS_H(1)); + colorBackground[] = {0, 0, 0, 0.2}; + show = 0; + class Attributes { + align = "center"; + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + size = 1; + }; + }; + class HeadAdd: RscButton { + idc = IDC_IV_FLOW_HEADADD; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),0,0.1)] call FUNC(handleIVAdjust)); + text = ">"; + x = QUOTE(POS_X(-3)); + y = QUOTE(POS_Y(2.5)); + w = QUOTE(POS_W(1)); + h = QUOTE(POS_H(1)); + show = 0; + colorBackground[] = {0, 0, 0, 0.7}; + colorBackgroundActive[] = {1, 1, 1, 1}; + colorBackgroundDisabled[] = {0, 0, 0, 0.7}; + colorBorder[] = {0,0,0,0}; + class Attributes { + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + }; + }; + class HeadAddFull: RscButton { + idc = IDC_IV_FLOW_HEADADDFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),0,0.5)] call FUNC(handleIVAdjust)); + text = ">>"; + x = QUOTE(POS_X(-1.5)); + y = QUOTE(POS_Y(2.5)); + w = QUOTE(POS_W(1)); + h = QUOTE(POS_H(1)); + show = 0; + colorBackground[] = {0, 0, 0, 0.7}; + colorBackgroundActive[] = {1, 1, 1, 1}; + colorBackgroundDisabled[] = {0, 0, 0, 0.7}; + colorBorder[] = {0,0,0,0}; + class Attributes { + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + }; + }; + + class ChestCover: HeadCover { + idc = IDC_IV_FLOW_CHESTCOVER; + text = CSTRING(ChestCover); // LOOK HERE + y = QUOTE(POS_Y(4.8)); + }; + class ChestTitle: HeadTitle { + idc = IDC_IV_FLOW_CHESTTITLE; // LOOK HERE + text = CSTRING(ChestTitle); + y = QUOTE(POS_Y(4.1)); + }; + class ChestType: HeadType { + idc = IDC_IV_FLOW_CHESTTYPE; // LOOK HERE + y = QUOTE(POS_Y(4.1)); + }; + class ChestSubtractFull: HeadSubtractFull { + idc = IDC_IV_FLOW_CHESTSUBTRACTFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),1,-0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(5)); + }; + class ChestSubtract: HeadSubtract { + idc = IDC_IV_FLOW_CHESTSUBTRACT; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),1,-0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(5)); + }; + class ChestIVValue: HeadIVValue { + idc = IDC_IV_FLOW_CHESTTEST; // LOOK HERE + y = QUOTE(POS_Y(5)); + }; + class ChestAdd: HeadAdd { + idc = IDC_IV_FLOW_CHESTADD; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),1,0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(5)); + }; + class ChestAddFull: HeadAddFull { + idc = IDC_IV_FLOW_CHESTADDFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),1,0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(5)); + }; + + class LArmCover: HeadCover { + idc = IDC_IV_FLOW_LARMCOVER; // LOOK HERE + text = CSTRING(LArmCover); + y = QUOTE(POS_Y(7.4)); + }; + class LArmTitle: HeadTitle { + idc = IDC_IV_FLOW_LARMTITLE; // LOOK HERE + text = CSTRING(LArmTitle); + y = QUOTE(POS_Y(6.6)); + }; + class LArmType: HeadType { + idc = IDC_IV_FLOW_LARMTYPE; // LOOK HERE + y = QUOTE(POS_Y(6.6)); + }; + class LArmSubtractFull: HeadSubtractFull { + idc = IDC_IV_FLOW_LARMSUBTRACTFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),2,-0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(7.6)); + }; + class LArmSubtract: HeadSubtract { + idc = IDC_IV_FLOW_LARMSUBTRACT; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),2,-0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(7.6)); + }; + class LArmIVValue: HeadIVValue { + idc = IDC_IV_FLOW_LARMIVVALUE; // LOOK HERE + y = QUOTE(POS_Y(7.6)); + }; + class LArmAdd: HeadAdd { + idc = IDC_IV_FLOW_LARMADD; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),2,0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(7.6)); + }; + class LArmAddFull: HeadAddFull { + idc = IDC_IV_FLOW_LARMADDFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),2,0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(7.6)); + }; + + class RArmCover: HeadCover { + idc = IDC_IV_FLOW_RARMCOVER; // LOOK HERE + text = CSTRING(RArmCover); + y = QUOTE(POS_Y(10.1)); + }; + class RArmTitle: HeadTitle { + idc = IDC_IV_FLOW_RARMTITLE; // LOOK HERE + text = CSTRING(RArmTitle); + y = QUOTE(POS_Y(9.3)); + }; + class RArmType: HeadType { + idc = IDC_IV_FLOW_RARMTYPE; // LOOK HERE + y = QUOTE(POS_Y(9.3)); + }; + class RArmSubtractFull: HeadSubtractFull { + idc = IDC_IV_FLOW_RARMSUBTRACTFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),3,-0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(10.3)); + }; + class RArmSubtract: HeadSubtract { + idc = IDC_IV_FLOW_RARMSUBTRACT; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),3,-0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(10.3)); + }; + class RArmIVValue: HeadIVValue { + idc = IDC_IV_FLOW_RARMIVVALUE; // LOOK HERE + y = QUOTE(POS_Y(10.3)); + }; + class RArmAdd: HeadAdd { + idc = IDC_IV_FLOW_RARMADD; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),3,0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(10.3)); + }; + class RArmAddFull: HeadAddFull { + idc = IDC_IV_FLOW_RARMADDFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),3,0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(10.3)); + }; + + class LLegCover: HeadCover { + idc = IDC_IV_FLOW_LLEGCOVER; // LOOK HERE + text = CSTRING(LLegCover); + y = QUOTE(POS_Y(12.8)); + }; + class LLegTitle: HeadTitle { + idc = IDC_IV_FLOW_LLEGTITLE; // LOOK HERE + text = CSTRING(LLegTitle); + y = QUOTE(POS_Y(12)); + }; + class LLegType: HeadType { + idc = IDC_IV_FLOW_LLEGTYPE; // LOOK HERE + y = QUOTE(POS_Y(12)); + }; + class LLegSubtractFull: HeadSubtractFull { + idc = IDC_IV_FLOW_LLEGSUBTRACTFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),4,-0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(12.9)); + }; + class LLegSubtract: HeadSubtract { + idc = IDC_IV_FLOW_LLEGSUBTRACT; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),4,-0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(12.9)); + }; + class LLegIVValue: HeadIVValue { + idc = IDC_IV_FLOW_LLEGIVVALUE; // LOOK HERE + y = QUOTE(POS_Y(12.9)); + }; + class LLegAdd: HeadAdd { + idc = IDC_IV_FLOW_LLEGADD; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),4,0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(12.9)); + }; + class LLegAddFull: HeadAddFull { + idc = IDC_IV_FLOW_LLEGADDFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),4,0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(12.9)); + }; + + class RLegCover: HeadCover { + idc = IDC_IV_FLOW_RLEGCOVER; // LOOK HERE + text = CSTRING(RLegCover); + y = QUOTE(POS_Y(15.4)); + }; + class RLegTitle: HeadTitle { + idc = IDC_IV_FLOW_RLEGTITLE; // LOOK HERE + text = CSTRING(RLegTitle); + y = QUOTE(POS_Y(14.6)); + }; + class RLegType: HeadType { + idc = IDC_IV_FLOW_RLEGTYPE; // LOOK HERE + y = QUOTE(POS_Y(14.6)); + }; + class RLegSubtractFull: HeadSubtractFull { + idc = IDC_IV_FLOW_RLEGSUBTRACTFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),5,-0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(15.5)); + }; + class RLegSubtract: HeadSubtract { + idc = IDC_IV_FLOW_RLEGSUBTRACT; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),5,-0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(15.5)); + }; + class RLegIVValue: HeadIVValue { + idc = IDC_IV_FLOW_RLEGIVVALUE; // LOOK HERE + y = QUOTE(POS_Y(15.5)); + }; + class RLegAdd: HeadAdd { + idc = IDC_IV_FLOW_RLEGADD; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),5,0.1)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(15.5)); + }; + class RLegAddFull: HeadAddFull { + idc = IDC_IV_FLOW_RLEGADDFULL; // LOOK HERE + onButtonClick = QUOTE([ARR_3(ACEGVAR(medical_gui,target),5,0.5)] call FUNC(handleIVAdjust)); + y = QUOTE(POS_Y(15.5)); + }; + + class PaCO2_Output: RscStructuredText { + idc = IDC_TEST_PACO2; // LOOK HERE + text = CSTRING(BGBlank); + x = QUOTE(POS_X(40)); + y = QUOTE(POS_Y(1.5)); + w = QUOTE(POS_W(2.2)); + h = QUOTE(POS_H(1)); + colorBackground[] = {0, 0, 0, 0.5}; + show = 1; + class Attributes { + align = "center"; + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + size = 1; + }; + }; + class PaO2_Output: PaCO2_Output { + idc = IDC_TEST_PAO2; // LOOK HERE + x = QUOTE(POS_X(43)); + }; + class SpO2_Output: PaCO2_Output { + idc = IDC_TEST_SPO2; // LOOK HERE + x = QUOTE(POS_X(46)); + }; + class HCO3_Output: RscStructuredText { + idc = IDC_TEST_HCO3; // LOOK HERE + text = CSTRING(BGBlank); + x = QUOTE(POS_X(40)); + y = QUOTE(POS_Y(3)); + w = QUOTE(POS_W(2.2)); + h = QUOTE(POS_H(1)); + colorBackground[] = {0, 0, 0, 0.5}; + show = 1; + class Attributes { + align = "center"; + color = "#E5E5E5"; + font = "RobotoCondensed"; + shadow = "false"; + size = 1; + }; + }; + class PH_Output: HCO3_Output { + idc = IDC_TEST_PH; // LOOK HERE + x = QUOTE(POS_X(43)); + }; + class Test_Reset: RscButton { + idc = IDC_TEST_RESET; // LOOK HERE + onButtonClick = QUOTE([ACEGVAR(medical_gui,target)] call FUNC(dumpBloodGas)); + text = CSTRING(TestReset); + x = QUOTE(POS_X(46)); + y = QUOTE(POS_Y(3)); + w = QUOTE(POS_W(2.1)); + h = QUOTE(POS_H(1)); + colorText[] = {1, 1, 1, 0.9}; + colorActive[] = {0, 0, 0, 0.7}; + colorBackground[] = {0, 0, 0, 0.7}; + colorBackgroundActive[] = {1, 1, 1, 1}; + colorBorder[] = {0,0,0,0}; + show = 1; + class Attributes { + align = "center"; + font = "RobotoCondensed"; + shadow = "false"; + }; + }; + + class Triage: RscActivePicture {}; class Surgery: Triage { idc = IDC_SURGERY; diff --git a/addons/gui/gui_defines.hpp b/addons/gui/gui_defines.hpp index d0185fecb..c37eedfeb 100644 --- a/addons/gui/gui_defines.hpp +++ b/addons/gui/gui_defines.hpp @@ -71,3 +71,70 @@ #define IDC_BODY_RIGHTLEG_IV 70141 #define IDC_BODY_LEFTLEG_IV 70142 + +#define IDC_IV_FLOW_TITLE 71101 +#define IDC_IV_FLOW_HEADCOVER 71102 +#define IDC_IV_FLOW_HEADTITLE 71103 +#define IDC_IV_FLOW_HEADTYPE 71104 +#define IDC_IV_FLOW_HEADSUBTRACT 71105 +#define IDC_IV_FLOW_HEADIV_VALUE 71106 +#define IDC_IV_FLOW_HEADADD 71107 +#define IDC_IV_FLOW_HEADSUBTRACTFULL 71108 +#define IDC_IV_FLOW_HEADADDFULL 71109 + +#define IDC_IV_FLOW_CHESTCOVER 71110 +#define IDC_IV_FLOW_CHESTTITLE 71111 +#define IDC_IV_FLOW_CHESTTYPE 71112 +#define IDC_IV_FLOW_CHESTSUBTRACT 71113 +#define IDC_IV_FLOW_CHESTTEST 71114 +#define IDC_IV_FLOW_CHESTADD 71115 +#define IDC_IV_FLOW_CHESTSUBTRACTFULL 71116 +#define IDC_IV_FLOW_CHESTADDFULL 71117 + +#define IDC_IV_FLOW_LARMCOVER 71118 +#define IDC_IV_FLOW_LARMTITLE 71119 +#define IDC_IV_FLOW_LARMTYPE 71120 +#define IDC_IV_FLOW_LARMSUBTRACT 71121 +#define IDC_IV_FLOW_LARMIVVALUE 71122 +#define IDC_IV_FLOW_LARMADD 71123 +#define IDC_IV_FLOW_LARMSUBTRACTFULL 71124 +#define IDC_IV_FLOW_LARMADDFULL 71125 + +#define IDC_IV_FLOW_LLEGCOVER 71126 +#define IDC_IV_FLOW_LLEGTITLE 71127 +#define IDC_IV_FLOW_LLEGTYPE 71128 +#define IDC_IV_FLOW_LLEGSUBTRACT 71129 +#define IDC_IV_FLOW_LLEGIVVALUE 71130 +#define IDC_IV_FLOW_LLEGADD 71131 +#define IDC_IV_FLOW_LLEGSUBTRACTFULL 71132 +#define IDC_IV_FLOW_LLEGADDFULL 71133 + +#define IDC_IV_FLOW_RLEGCOVER 71134 +#define IDC_IV_FLOW_RLEGTITLE 71135 +#define IDC_IV_FLOW_RLEGTYPE 71136 +#define IDC_IV_FLOW_RLEGSUBTRACT 71137 +#define IDC_IV_FLOW_RLEGIVVALUE 71138 +#define IDC_IV_FLOW_RLEGADD 71139 +#define IDC_IV_FLOW_RLEGSUBTRACTFULL 71140 +#define IDC_IV_FLOW_RLEGADDFULL 71141 + +#define IDC_IV_FLOW_RARMCOVER 71142 +#define IDC_IV_FLOW_RARMTITLE 71143 +#define IDC_IV_FLOW_RARMTYPE 71144 +#define IDC_IV_FLOW_RARMSUBTRACT 71145 +#define IDC_IV_FLOW_RARMIVVALUE 71146 +#define IDC_IV_FLOW_RARMADD 71147 +#define IDC_IV_FLOW_RARMSUBTRACTFULL 71148 +#define IDC_IV_FLOW_RARMADDFULL 71149 + +#define IDC_IV_FLOW_BACKGROUND 71199 + +#define IDC_ABG_TITLE 71201 +#define IDC_TEST_PACO2 71202 +#define IDC_TEST_PAO2 71203 +#define IDC_TEST_SPO2 71204 +#define IDC_TEST_HCO3 71205 +#define IDC_TEST_PH 71206 +#define IDC_TEST_RESET 71207 + +#define IDC_ABG_BACKGROUND 71299 diff --git a/addons/gui/stringtable.xml b/addons/gui/stringtable.xml index 3a0e8a762..c409f1c66 100644 --- a/addons/gui/stringtable.xml +++ b/addons/gui/stringtable.xml @@ -83,5 +83,74 @@ Merkitse potilaan sivut Маркировка сторон пациента + + HEAD - NO LINE + + + CHEST - NO LINE + + + RIGHT ARM - NO LINE + + + LEFT ARM - NO LINE + + + RIGHT LEG - NO LINE + + + LEFT LEG - NO LINE + + + IV Flow Control + + + ABG Results + + + 0.0 + + + Head + + + IV + + + Chest + + + IV + + + LA + + + IV + + + RA + + + IV + + + LL + + + IV + + + RL + + + IV + + + --.- + + + Reset + diff --git a/addons/hypothermia/$PBOPREFIX$ b/addons/hypothermia/$PBOPREFIX$ new file mode 100644 index 000000000..db7fe72be --- /dev/null +++ b/addons/hypothermia/$PBOPREFIX$ @@ -0,0 +1 @@ +x\kat\addons\hypothermia \ No newline at end of file diff --git a/addons/hypothermia/ACE_Medical_Treatment_Actions.hpp b/addons/hypothermia/ACE_Medical_Treatment_Actions.hpp new file mode 100644 index 000000000..0cc85314e --- /dev/null +++ b/addons/hypothermia/ACE_Medical_Treatment_Actions.hpp @@ -0,0 +1,45 @@ +class ACE_Medical_Treatment_Actions { + class CheckPulse; + class BasicBandage; + class ApplyHandWarmers: BasicBandage { + displayName = CSTRING(Use_Handwarmer); + displayNameProgress = CSTRING(Using); + condition = "true"; + treatmentLocations = 0; + treatmentTime = 5; + allowedSelections[] = {"Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"}; + items[] = {"kat_handWarmer"}; + callbackSuccess = QFUNC(useHandWarmer); + }; + class ApplyFluidWarmer: BasicBandage { + displayName = CSTRING(Apply_Warmer); + displayNameProgress = CSTRING(perform); + category = "advanced"; + allowedSelections[] = {"Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"}; + medicRequired = QACEGVAR(medical_treatment,medicIV); + treatmentTime = 10; + items[] = {"kat_fluidWarmer"}; + condition = QUOTE(([ARR_3(_medic,_patient,_bodyPart)] call EFUNC(pharma,removeIV)) && !([ARR_2(_patient,_bodyPart)] call FUNC(removeWarmer))); + callbackSuccess = QFUNC(applyFluidWarmer); + }; + class RemoveFluidWarmer: BasicBandage { + displayName = CSTRING(Remove_Warmer); + displayNameProgress = CSTRING(perform); + category = "advanced"; + allowedSelections[] = {"Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"}; + medicRequired = QACEGVAR(medical_treatment,medicIV); + treatmentTime = 10; + items[] = {}; + condition = QUOTE([ARR_2(_patient,_bodyPart)] call FUNC(removeWarmer)); + callbackSuccess = QFUNC(removeFluidWarmer); + }; + class CheckTemperature: CheckPulse { + displayName = CSTRING(Check_Temperature); + displayNameProgress = CSTRING(Check_Temperature_Progress); + category = "examine"; + allowedSelections[] = {"Head"}; + treatmentTime = 3; + condition = "true"; + callbackSuccess = QFUNC(checkTemperature); + }; +}; diff --git a/addons/hypothermia/CfgEventHandlers.hpp b/addons/hypothermia/CfgEventHandlers.hpp new file mode 100644 index 000000000..4551ce282 --- /dev/null +++ b/addons/hypothermia/CfgEventHandlers.hpp @@ -0,0 +1,20 @@ +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + disableModuload = "true"; + }; +}; + +class Extended_Init_EventHandlers { + class CAManBase { + class ADDON { + init = QUOTE([ARR_2((_this select 0),false)] call FUNC(init)); + }; + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_postInit)); + }; +}; diff --git a/addons/hypothermia/CfgVehicles.hpp b/addons/hypothermia/CfgVehicles.hpp new file mode 100644 index 000000000..6ede5b41d --- /dev/null +++ b/addons/hypothermia/CfgVehicles.hpp @@ -0,0 +1,27 @@ +class CfgVehicles { + class Man; + + class CAManBase: Man { + class ACE_Actions { + class ACE_MainActions { + class KAT_CheckHandWarmers { + displayName = CSTRING(Check_Hand_Warmers); + condition = "true"; + statement = QUOTE([ARR_2(_player,_target)] call FUNC(checkHandWarmers)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + + class ACE_SelfActions { + class KAT_Equipment { + class KAT_CheckHandWarmersSelf { + displayName = CSTRING(Check_Hand_Warmers); + condition = "true"; + statement = QUOTE([ARR_2(_player,_player)] call FUNC(checkHandWarmers)); + icon = QACEPATHTOF(medical_gui,ui\cross.paa); + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/addons/hypothermia/CfgWeapons.hpp b/addons/hypothermia/CfgWeapons.hpp new file mode 100644 index 000000000..25bb1d750 --- /dev/null +++ b/addons/hypothermia/CfgWeapons.hpp @@ -0,0 +1,27 @@ +class CfgWeapons { + class ACE_ItemCore; + class CBA_MiscItem_ItemInfo; + + class kat_handWarmer: ACE_ItemCore { + scope = 2; + displayName = CSTRING(HandWarmer_displayName); + picture = QPATHTOF(ui\warmers.paa); + model = "\A3\Structures_F_EPA\Items\Medical\HeatPack_F.p3d"; + descriptionShort = CSTRING(HandWarmer_DescShort); + ACE_isMedicalItem = 1; + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 0.2; + }; + }; + class kat_fluidWarmer: ACE_ItemCore { + scope = 2; + displayName = CSTRING(FluidWarmer_displayName); + picture = QPATHTOF(ui\fluidWarmer.paa); + model = "\A3\Structures_F_EPA\Items\Tools\ButaneTorch_F.p3d"; + descriptionShort = CSTRING(FluidWarmer_DescShort); + ACE_isMedicalItem = 1; + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 1; + }; + }; +}; diff --git a/addons/hypothermia/XEH_PREP.hpp b/addons/hypothermia/XEH_PREP.hpp new file mode 100644 index 000000000..7469488a6 --- /dev/null +++ b/addons/hypothermia/XEH_PREP.hpp @@ -0,0 +1,12 @@ +PREP(applyFluidWarmer); +PREP(applyFluidWarmerLocal); +PREP(checkHandWarmers); +PREP(checkTemperature); +PREP(fullHealLocal); +PREP(handleRespawn); +PREP(init); +PREP(removeFluidWarmer); +PREP(removeFluidWarmerLocal); +PREP(removeWarmer); +PREP(useHandWarmer); +PREP(useHandWarmerLocal); \ No newline at end of file diff --git a/addons/hypothermia/XEH_postInit.sqf b/addons/hypothermia/XEH_postInit.sqf new file mode 100644 index 000000000..db2503afa --- /dev/null +++ b/addons/hypothermia/XEH_postInit.sqf @@ -0,0 +1,8 @@ +#include "script_component.hpp" + +[QGVAR(useHandWarmer), LINKFUNC(useHandWarmerLocal)] call CBA_fnc_addEventHandler; +[QGVAR(applyFluidWarmer), LINKFUNC(applyFluidWarmerLocal)] call CBA_fnc_addEventHandler; +[QGVAR(removeFluidWarmer), LINKFUNC(removeFluidWarmerLocal)] call CBA_fnc_addEventHandler; + +[QEGVAR(misc,handleRespawn), LINKFUNC(handleRespawn)] call CBA_fnc_addEventHandler; +[QACEGVAR(medical_treatment,fullHealLocalMod), LINKFUNC(fullHealLocal)] call CBA_fnc_addEventHandler; \ No newline at end of file diff --git a/addons/hypothermia/XEH_preInit.sqf b/addons/hypothermia/XEH_preInit.sqf new file mode 100644 index 000000000..29cf1d60f --- /dev/null +++ b/addons/hypothermia/XEH_preInit.sqf @@ -0,0 +1,28 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +if (isServer) then { + // Decrease of 0.7C for each degree of lattitude gained. Middle lattitudes between 20N and 20S have average temperatures of 27C, everything decreases from there. + private _mapPosition = if (count([worldName] call ACEFUNC(common,getMapData)) != 0) then { abs([worldName] call ACEFUNC(common,getMapData) select 0) } else { 25 }; + private _mapHighTemperature = if ((_mapPosition - 20) > 0) then { 27 + (-0.7 * (_mapPosition - 27)) } else { 27 }; + + GVAR(positionTemperature) = [_mapPosition, _mapHighTemperature]; +}; + +#define CBA_SETTINGS_CAT "KAT - ADV Medical: Hypothermia" + +[ + QGVAR(hypothermiaActive), + "CHECKBOX", + LLSTRING(ENABLE_HYPOTHERMIA), + [CBA_SETTINGS_CAT, LSTRING(SubCategory_Hypothermia)], + [true], + true +] call CBA_Settings_fnc_init; + +ADDON = true; diff --git a/addons/hypothermia/config.cpp b/addons/hypothermia/config.cpp new file mode 100644 index 000000000..861f2a6a3 --- /dev/null +++ b/addons/hypothermia/config.cpp @@ -0,0 +1,39 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + requiredVersion = REQUIRED_VERSION; + units[] = { + }; + weapons[] = { + "kat_handWarmer", + "kat_fluidWarmer" + }; + magazines[] = { }; + requiredAddons[] = { + "ace_medical", + "ace_medical_ai", + "ace_medical_blood", + "ace_medical_damage", + "ace_medical_engine", + "ace_medical_feedback", + "ace_medical_gui", + "ace_medical_statemachine", + "ace_medical_status", + "ace_medical_treatment", + "ace_medical_vitals", + "ace_dogtags", + "cba_settings" + }; + author = "Mazinski"; + authors[] = {"Mazinski"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgVehicles.hpp" +#include "CfgWeapons.hpp" +#include "ACE_Medical_Treatment_Actions.hpp" \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_applyFluidWarmer.sqf b/addons/hypothermia/functions/fnc_applyFluidWarmer.sqf new file mode 100644 index 000000000..0f1cfc863 --- /dev/null +++ b/addons/hypothermia/functions/fnc_applyFluidWarmer.sqf @@ -0,0 +1,26 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Begins Fluid Warmer Treatment + * + * Arguments: + * 0: Medic + * 1: Patient + * 2: Body Part + * 3: Treatment + * 4: Item User (not used) + * 5: Used Item + * + * Return Value: + * None + * + * Example: + * [player, cursorObject, "RightArm", "FluidWarmer", objNull, "kat_fluidWarmer"] call kat_hypothermia_fnc_applyFluidWarmer; + * + * Public: No + */ + +params ["_medic", "_patient", "_bodyPart", "_classname", "", "_usedItem"]; + +[QGVAR(applyFluidWarmer), [_patient, _bodyPart], _patient] call CBA_fnc_targetEvent; + diff --git a/addons/hypothermia/functions/fnc_applyFluidWarmerLocal.sqf b/addons/hypothermia/functions/fnc_applyFluidWarmerLocal.sqf new file mode 100644 index 000000000..42f58b8d6 --- /dev/null +++ b/addons/hypothermia/functions/fnc_applyFluidWarmerLocal.sqf @@ -0,0 +1,23 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Local call for applying fluid warmers + * + * Arguments: + * 0: Patient + * 1: Body Part + * + * Return Value: + * None + * + * Example: + * [cursorObject, "LeftLeg"] call kat_hypothermia_fnc_applyFluidWarmerLocal; + * + * Public: No + */ +params ["_patient", "_bodyPart"]; + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; +private _warmerArray = _patient getVariable [QGVAR(fluidWarmer), [0,0,0,0,0,0]]; +_warmerArray set [_partIndex, 1]; +_patient setVariable [QGVAR(fluidWarmer), _warmerArray]; \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_checkHandWarmers.sqf b/addons/hypothermia/functions/fnc_checkHandWarmers.sqf new file mode 100644 index 000000000..752fae962 --- /dev/null +++ b/addons/hypothermia/functions/fnc_checkHandWarmers.sqf @@ -0,0 +1,51 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Checks handwarmer status + * + * Arguments: + * 0: Patient + * + * Return Value: + * None + * + * Example: + * [patient] call kat_hypothermia_fnc_checkHandWarmers; + * + * Public: No + */ + +params ["_target"]; + +private _warmers = _target getVariable [QGVAR(handWarmers), [0,0,0,0,0,0]]; +_warmers params ["_head", "_body", "_larm", "_rarm", "_lleg", "_rleg"]; + +if (_player == _target) exitWith { + if (({_x == 0} count _warmers) == 6) exitWith { + [LLSTRING(HandWarmer_None), 1.5, _target] call ACEFUNC(common,displayTextStructured); + }; + + private _output = format [LSTRING(Self_Handwarmer_Output), + [(format [LLSTRING(HandWarmer_Body), (random[10, _body, 60]) toFixed 0]), LLSTRING(HandWarmer_Body_None)] select (_body < 10), + [(format [LLSTRING(HandWarmer_LArm), (random[10, _larm, 60]) toFixed 0]), LLSTRING(HandWarmer_LArm_None)] select (_larm < 10), + [(format [LLSTRING(HandWarmer_RArm), (random[10, _rarm, 60]) toFixed 0]), LLSTRING(HandWarmer_RArm_None)] select (_rarm < 10), + [(format [LLSTRING(HandWarmer_LLeg), (random[10, _lleg, 60]) toFixed 0]), LLSTRING(HandWarmer_LLeg_None)] select (_lleg < 10), + [(format [LLSTRING(HandWarmer_RLeg), (random[10, _rleg, 60]) toFixed 0]), LLSTRING(HandWarmer_RLeg_None)] select (_rleg < 10) + ]; + + [_output, 5, _target] call ACEFUNC(common,displayTextStructured); +}; + +if (({_x == 0} count _warmers) == 6) exitWith { + [LLSTRING(HandWarmer_None), 1.5, _target] call ACEFUNC(common,displayTextStructured); +}; + +private _output = format [LSTRING(Other_Handwarmer_Output), + [(format [LLSTRING(HandWarmer_Body), (random[10, _body, 60]) toFixed 0]), LLSTRING(HandWarmer_Body_None)] select (_body < 10), + [(format [LLSTRING(HandWarmer_LArm), (random[10, _larm, 60]) toFixed 0]), LLSTRING(HandWarmer_LArm_None)] select (_larm < 10), + [(format [LLSTRING(HandWarmer_RArm), (random[10, _rarm, 60]) toFixed 0]), LLSTRING(HandWarmer_RArm_None)] select (_rarm < 10), + [(format [LLSTRING(HandWarmer_LLeg), (random[10, _lleg, 60]) toFixed 0]), LLSTRING(HandWarmer_LLeg_None)] select (_lleg < 10), + [(format [LLSTRING(HandWarmer_RLeg), (random[10, _rleg, 60]) toFixed 0]), LLSTRING(HandWarmer_RLeg_None)] select (_rleg < 10) +]; + +[_output, 5, _player] call ACEFUNC(common,displayTextStructured); \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_checkTemperature.sqf b/addons/hypothermia/functions/fnc_checkTemperature.sqf new file mode 100644 index 000000000..7ecc90422 --- /dev/null +++ b/addons/hypothermia/functions/fnc_checkTemperature.sqf @@ -0,0 +1,28 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Checks patient temperature + * + * Arguments: + * 0: Medic + * 1: Patient + * + * Return Value: + * None + * + * Example: + * [player, cursorObject] call kat_hypothermia_fnc_checkTemperature; + * + * Public: No + */ +params ["_medic", "_patient"]; + +private _unitTemperature = _patient getVariable [QGVAR(unitTemperature), 37]; + +switch (true) do { + case (!(alive _patient)) : { [LLSTRING(temperature_dead), 1.5, _medic] call ACEFUNC(common,displayTextStructured); }; + case (_unitTemperature < 29) : { [LLSTRING(temperature_cold), 1.5, _medic] call ACEFUNC(common,displayTextStructured); }; + case (_unitTemperature < 32) : { [LLSTRING(temperature_cool), 1.5, _medic] call ACEFUNC(common,displayTextStructured); }; + case (_unitTemperature < 36) : { [LLSTRING(temperature_mild), 1.5, _medic] call ACEFUNC(common,displayTextStructured); }; + default {[LLSTRING(temperature_warm), 1.5, _medic] call ACEFUNC(common,displayTextStructured); }; +}; \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_fullHealLocal.sqf b/addons/hypothermia/functions/fnc_fullHealLocal.sqf new file mode 100644 index 000000000..f0570e08d --- /dev/null +++ b/addons/hypothermia/functions/fnc_fullHealLocal.sqf @@ -0,0 +1,24 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Local callback for fully healing a patient. + * + * Arguments: + * 0: Patient + * + * Return Value: + * None + * + * Example: + * [player] call kat_hypothermia_fnc_fullHealLocal + * + * Public: No + */ + +params ["_patient"]; +TRACE_1("fullHealLocal",_patient); + +_patient setVariable [QGVAR(unitTemperature), 37, true]; +_patient setVariable [QGVAR(warmingImpact), 0, true]; +_patient setVariable [QGVAR(handWarmers), [0,0,0,0,0,0], true]; +_patient setVariable [QGVAR(fluidWarmer), [0,0,0,0,0,0], true]; \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_handleRespawn.sqf b/addons/hypothermia/functions/fnc_handleRespawn.sqf new file mode 100644 index 000000000..453e4db2f --- /dev/null +++ b/addons/hypothermia/functions/fnc_handleRespawn.sqf @@ -0,0 +1,53 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Handles the player respawn for Hypothermia. + * + * Arguments: + * 0: Patient + * + * Return Value: + * None + * + * Example: + * [player] call kat_hypothermia_fnc_handleRespawn + * + * Public: No + */ + +params ["_patient"]; +TRACE_1("fullHealLocal",_patient); + +[_patient] call FUNC(fullHealLocal); + +if (GVAR(hypothermiaActive)) then { + [{ + params ["_args", "_idPFH"]; + _args params ["_patient"]; + + private _alive = alive _patient; + + if (!_alive) exitWith { + [_idPFH] call CBA_fnc_removePerFrameHandler; + }; + + private _handWarmers = _patient getVariable [QGVAR(handWarmers), [0,0,0,0,0,0]]; + + { + _x params ["_timeRemaining"]; + + if (_x > 0) then { + _handWarmers set [_forEachIndex, _timeRemaining - 1]; + }; + } forEach (_handWarmers); + + _patient setVariable [QGVAR(handWarmers), _handWarmers, true]; + + if (GET_BLOOD_VOLUME_LITERS(_patient) > 4) then { + private _impact = (_patient getVariable [QGVAR(warmingImpact), 0]); + [(_impact - 100) max 0, (_impact + 200) min 0] select (_impact < 0); + _patient setVariable [QGVAR(warmingImpact), _impact, true]; + }; + + }, 60, [_patient]] call CBA_fnc_addPerFrameHandler; +}; \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_init.sqf b/addons/hypothermia/functions/fnc_init.sqf new file mode 100644 index 000000000..7e6953ea8 --- /dev/null +++ b/addons/hypothermia/functions/fnc_init.sqf @@ -0,0 +1,56 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Initializes unit variables. + * + * Arguments: + * 0: Unit + * + * Return Value: + * None + * + * Example: + * [player] call kat_hypothermia_fnc_init; + * + * Public: No + */ + +params ["_unit", ["_isRespawn", true]]; + +if (!local _unit) exitWith {}; + +[_unit] call FUNC(fullHealLocal); + +if (GVAR(hypothermiaActive)) then { + [{ + params ["_args", "_idPFH"]; + _args params ["_unit"]; + + private _alive = alive _unit; + + if (!_alive) exitWith { + [_idPFH] call CBA_fnc_removePerFrameHandler; + }; + + private _handWarmers = _unit getVariable [QGVAR(handWarmers), [0,0,0,0,0,0]]; + + { + _x params ["_timeRemaining"]; + + if (_x > 0) exitWith { + _handWarmers set [_forEachIndex, _timeRemaining - 1]; + }; + + _handWarmers set [_forEachIndex, 0]; + } forEach (_handWarmers); + + _unit setVariable [QGVAR(handWarmers), _handWarmers, true]; + + if (GET_BLOOD_VOLUME_LITERS(_unit) > 4) then { + private _impact = (_unit getVariable [QGVAR(warmingImpact), 0]); + [(_impact - 100) max 0, (_impact + 200) min 0] select (_impact < 0); + _unit setVariable [QGVAR(warmingImpact), _impact, true]; + }; + + }, 60, [_unit]] call CBA_fnc_addPerFrameHandler; +}; \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_removeFluidWarmer.sqf b/addons/hypothermia/functions/fnc_removeFluidWarmer.sqf new file mode 100644 index 000000000..b8b92ec32 --- /dev/null +++ b/addons/hypothermia/functions/fnc_removeFluidWarmer.sqf @@ -0,0 +1,25 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski.H + * Begins Remove Fluid Warmer treatment + * + * Arguments: + * 0: Medic + * 1: Patient + * 2: Body Part + * 3: Treatment + * 4: Item User (not used) + * 5: Used Item + * + * Return Value: + * None + * + * Example: + * [player, cursorObject, "RightArm", "Fluid Warmer", objNull, "kat_FluidWarmer"] call kat_hypothermia_fnc_removeFluidWarmer; + * + * Public: No + */ + +params ["_medic", "_patient", "_bodyPart", "_classname", "", "_usedItem"]; + +[QGVAR(removeFluidWarmer), [_medic, _patient, _bodyPart], _patient] call CBA_fnc_targetEvent; diff --git a/addons/hypothermia/functions/fnc_removeFluidWarmerLocal.sqf b/addons/hypothermia/functions/fnc_removeFluidWarmerLocal.sqf new file mode 100644 index 000000000..359d55932 --- /dev/null +++ b/addons/hypothermia/functions/fnc_removeFluidWarmerLocal.sqf @@ -0,0 +1,26 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Local call for removing a fluid warmer + * + * Arguments: + * 0: Medic + * 1: Patient + * 2: Body Part + * + * Return Value: + * None + * + * Example: + * [player, cursorObject, "LeftLeg"] call kat_hypothermia_fnc_removeFluidWarmerLocal; + * + * Public: No + */ +params ["_medic", "_patient", "_bodyPart"]; + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; +private _warmerArray = _patient getVariable [QGVAR(fluidWarmer), [0,0,0,0,0,0]]; +_warmerArray set [_partIndex, 0]; +_patient setVariable [QGVAR(fluidWarmer), _warmerArray]; + +[_medic, "kat_fluidWarmer"] call ACEFUNC(common,addToInventory); \ No newline at end of file diff --git a/addons/hypothermia/functions/fnc_removeWarmer.sqf b/addons/hypothermia/functions/fnc_removeWarmer.sqf new file mode 100644 index 000000000..f9207ab6a --- /dev/null +++ b/addons/hypothermia/functions/fnc_removeWarmer.sqf @@ -0,0 +1,27 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Check for fluid warmers present + * + * Arguments: + * 0: Patient + * 1: Body Part + * + * Return Value: + * None + * + * Example: + * [player, cursorObject, "LeftLeg"] call kat_hypothermia_fnc_removeWarmer; + * + * Public: No + */ +params ["_patient", "_bodyPart"]; + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; +private _warmerArray = _patient getVariable [QGVAR(fluidWarmer), [0,0,0,0,0,0]]; + +if (_warmerArray select _partIndex == 0) exitWith { + false +}; + +true diff --git a/addons/hypothermia/functions/fnc_useHandWarmer.sqf b/addons/hypothermia/functions/fnc_useHandWarmer.sqf new file mode 100644 index 000000000..ee12251d6 --- /dev/null +++ b/addons/hypothermia/functions/fnc_useHandWarmer.sqf @@ -0,0 +1,27 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Begins Hand Warmer treatment + * + * Arguments: + * 0: Medic + * 1: Patient + * 2: Body Part + * 3: Treatment + * 4: Item User (not used) + * 5: Used Item + * + * Return Value: + * None + * + * Example: + * [player, cursorObject, "LeftLeg", "HandWarmer", objNull, "kat_handWarmer"] call kat_hypothermia_fnc_useHandWarmer; + * + * Public: No + */ +params ["_medic", "_patient", "_bodyPart", "_classname", "", "_usedItem"]; + +[_patient, _classname] call ACEFUNC(medical_treatment,addToTriageCard); +[_patient, "activity", ACELSTRING(medical_treatment,Activity_usedItem), [[_medic] call ACEFUNC(common,getName), _classname]] call ACEFUNC(medical_treatment,addToLog); + +[QGVAR(useHandWarmer), [_patient, _bodyPart], _patient] call CBA_fnc_targetEvent; diff --git a/addons/hypothermia/functions/fnc_useHandWarmerLocal.sqf b/addons/hypothermia/functions/fnc_useHandWarmerLocal.sqf new file mode 100644 index 000000000..e167c6c90 --- /dev/null +++ b/addons/hypothermia/functions/fnc_useHandWarmerLocal.sqf @@ -0,0 +1,24 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Local call for applying hand warmers + * + * Arguments: + * 0: Patient + * 1: Body Part + * + * Return Value: + * None + * + * Example: + * [cursorObject, "LeftLeg"] call kat_hypothermia_fnc_useHandWarmerLocal; + * + * Public: No + */ +params ["_patient", "_bodyPart"]; + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; +private _warmerArray = _patient getVariable [QGVAR(handWarmers), [0,0,0,0,0,0]]; +_warmerArray set [_partIndex, 60]; + +_patient setVariable [QGVAR(handWarmers), _warmerArray]; \ No newline at end of file diff --git a/addons/hypothermia/script_component.hpp b/addons/hypothermia/script_component.hpp new file mode 100644 index 000000000..4d2776626 --- /dev/null +++ b/addons/hypothermia/script_component.hpp @@ -0,0 +1,17 @@ +#define COMPONENT hypothermia +#define COMPONENT_BEAUTIFIED KAT - Hypothermia +#include "\x\kat\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_HYPOTHERMIA + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_HYPOTHERMIA + #define DEBUG_SETTINGS DEBUG_SETTINGS_Hypothermia +#endif + +#include "\x\kat\addons\main\script_macros.hpp" diff --git a/addons/hypothermia/stringtable.xml b/addons/hypothermia/stringtable.xml new file mode 100644 index 000000000..5f65e154c --- /dev/null +++ b/addons/hypothermia/stringtable.xml @@ -0,0 +1,136 @@ + + + + + Using + Verwenden + Używanie + Usando + 服用中 + 使用中 + Používám + 사용 중 + Utilisation + Kullanılıyor + Usando + 使用中 + Usando + Käytetään + С помощью + + + Enable Hypothermia + + + Hand Warmer Impact + + + Multipler for impact of hand warmers on heat gain + + + Fluid Warmer Impact + + + Multipler for impact of fluid warmer on heat gain + + + Warm Uniforms + + + List of clothing marked that reduces heat loss + + + Check Hand Warmers + + + Hand Warmer + + + Small hand warmers to provide warmth in colder climates + + + Use Hand Warmer + + + This is where you have handwarmers and how much longer you think they have in minutes: %1, %2, %3, %4, %5 + + + This patient has handwarmers and they will probably last this many more minutes at this locations: %1, %2, %3, %4, %5 + + + Fluid Line Warmer + + + Provides heating to IV fluids. Must be placed on an already existing line + + + Attach Fluid Warmer + + + Remove Fluid Warmer + + + Patient feels frigid + + + Patient feels remarkably cold + + + Patient feels moderately cold + + + Patient feels mildly cool + + + Patient feels warm + + + Check Temperature + + + Checking Temperature + + + Check Hand Warmers + + + Performing + + + Line Warmer Active + + + No Hand Warmers are active at this time + + + Body: %1 + + + Body: None + + + Left Arm: %1 + + + Left Arm: None + + + Right Arm: %1 + + + Right Arm: None + + + Left Leg: %1 + + + Left Leg: None + + + Right Leg: %1 + + + Right Leg: None + + + diff --git a/addons/hypothermia/ui/fluidWarmer.paa b/addons/hypothermia/ui/fluidWarmer.paa new file mode 100644 index 000000000..f5311b677 Binary files /dev/null and b/addons/hypothermia/ui/fluidWarmer.paa differ diff --git a/addons/hypothermia/ui/warmers.paa b/addons/hypothermia/ui/warmers.paa new file mode 100644 index 000000000..287f965bb Binary files /dev/null and b/addons/hypothermia/ui/warmers.paa differ diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index 02973388e..d4ce3212c 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -186,13 +186,14 @@ #undef GET_SM_STATE #define GET_SM_STATE(_unit) ([_unit, ACEGVAR(medical,STATE_MACHINE)] call CBA_statemachine_fnc_getCurrentState) +#undef GET_BLOOD_VOLUME + #define GET_OPIOID_FACTOR(unit) (unit getVariable [QEGVAR(pharma,opioidFactor), 1]) +#define GET_PAIN_PERCEIVED(unit) (0 max ((GET_PAIN(unit) - GET_PAIN_SUPPRESS(unit)) min 1)) #undef GET_DAMAGE_THRESHOLD #define GET_DAMAGE_THRESHOLD(unit) ((unit getVariable [QACEGVAR(medical,damageThreshold), [ACEGVAR(medical,AIDamageThreshold),ACEGVAR(medical,playerDamageThreshold)] select (isPlayer unit)]) * GET_OPIOID_FACTOR(unit)) -#define GET_PAIN_PERCEIVED(unit) (0 max (GET_PAIN(unit) - GET_PAIN_SUPPRESS(unit)) min 1) - #define DEFAULT_TOURNIQUET_VALUES [0,0,0,0,0,0] #define GET_TOURNIQUETS(unit) (unit getVariable [VAR_TOURNIQUET, DEFAULT_TOURNIQUET_VALUES]) #define GET_SURGICAL_TOURNIQUETS(unit) (unit getVariable [QEGVAR(surgery,surgicalBlock), DEFAULT_TOURNIQUET_VALUES]) @@ -272,18 +273,66 @@ #define ALL_BODY_PARTS_PRIORITY ["body", "head", "leftarm", "rightarm", "leftleg", "rightleg"] +#define DEFAULT_PACO2 40 +#define DEFAULT_PAO2 90 +#define DEFAULT_O2SAT 0.96 +#define DEFAULT_HCO3 24 +#define DEFAULT_PH 7.4 +#define DEFAULT_ETCO2 37 +#define DEFAULT_BLOOD_GAS [DEFAULT_PACO2, DEFAULT_PAO2, DEFAULT_O2SAT, DEFAULT_HCO3, DEFAULT_PH, DEFAULT_ETCO2] + +#define DEFAULT_ANEROBIC_EXCHANGE 0.8 +#define DEFAULT_TEMPERATURE 37 + +#define DEFAULT_ECB 2700 +#define DEFAULT_ECP 3300 +#define DEFAULT_SRBC 500 +#define DEFAULT_ISP 10000 +#define DEFAULT_BODY_FLUID [2700, 3300, 500, 10000, 6000] + +#define LITERS_TO_ML 1000 +#define ML_TO_LITERS 1000 + // Airway -#define VAR_SPO2 QEGVAR(breathing,airwayStatus) -#define GET_SPO2(unit) (unit getVariable [VAR_SPO2, 100]) +#define OXYGEN_PERCENTAGE_CRITICAL 85 +#define OXYGEN_PERCENTAGE_ARREST 80 +#define OXYGEN_PERCENTAGE_FATAL 75 + +// Breathing +#define VAR_SURFACE_AREA 400 +#define GET_KAT_SURFACE_AREA(unit) (VAR_SURFACE_AREA - (((unit getVariable [QEGVAR(breathing,pneumothorax), 0]) * 75))) + +#define VAR_BLOOD_GAS QEGVAR(circulation,bloodGas) +#define VAR_BREATHING_RATE QEGVAR(breathing,breathRate) + +#define GET_BLOOD_GAS(unit) (unit getVariable [VAR_BLOOD_GAS, DEFAULT_BLOOD_GAS]) +#define GET_PAO2(unit) ((unit getVariable [VAR_BLOOD_GAS, DEFAULT_BLOOD_GAS]) select 1) +#define GET_SPO2(unit) (((unit getVariable [VAR_BLOOD_GAS, DEFAULT_BLOOD_GAS]) select 2) * 100) +#define GET_PH(unit) ((unit getVariable [VAR_BLOOD_GAS, DEFAULT_BLOOD_GAS]) select 4) +#define GET_ETCO2(unit) ((unit getVariable [VAR_BLOOD_GAS, DEFAULT_BLOOD_GAS]) select 5) +#define GET_BREATHING_RATE(unit) (unit getVariable [VAR_BREATHING_RATE, 15]) // Circulation #define VAR_INTERNAL_BLEEDING QEGVAR(circulation,internalBleeding) #define GET_INTERNAL_BLEEDING(unit) (unit getVariable [VAR_INTERNAL_BLEEDING, 0]) +#define VAR_BODY_FLUID QEGVAR(circulation,bodyFluid) +#define GET_BODY_FLUID(unit) (unit getVariable [VAR_BODY_FLUID, DEFAULT_BODY_FLUID]) + +#define GET_BLOOD_VOLUME_LITERS(unit) ((GET_BODY_FLUID(unit) select 4) / 1000) +#define GET_BLOOD_VOLUME_ML(unit) (GET_BODY_FLUID(unit) select 4) +#define GET_SIMPLE_BLOOD_VOLUME(unit) (unit getVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME]) + +#define REDUCE_TOTAL_BLOOD_VOLUME(unit,volume) (unit setVariable [VAR_BODY_FLUID, [(GET_BODY_FLUID(unit) select 0) - (volume / 2), (GET_BODY_FLUID(unit) select 1) - (volume / 2), (GET_BODY_FLUID(unit) select 2), (GET_BODY_FLUID(unit) select 3), (GET_BODY_FLUID(unit) select 4) - volume], true]) + #undef GET_BLOOD_PRESSURE #define GET_BLOOD_PRESSURE(unit) ([unit] call EFUNC(circulation,getBloodPressure)) #define VAR_BLOODPRESSURE_CHANGE QEGVAR(circulation,bloodPressureChange) #define GET_BLOODPRESSURE_CHANGE(unit) (unit getVariable [VAR_BLOODPRESSURE_CHANGE, [0,0]]) +// Pharma +#define VAR_VASOCONSTRICTION QEGVAR(pharma,alphaAction) +#define GET_VASOCONSTRICTION(unit) (unit getVariable [VAR_VASOCONSTRICTION, 1]) + //Surgery #define STRING_BODY_PARTS ["head", "body", "left arm", "right arm", "left leg", "right leg"] diff --git a/addons/misc/CfgFunctions.hpp b/addons/misc/CfgFunctions.hpp index 3e014a03b..b1b6edfb4 100644 --- a/addons/misc/CfgFunctions.hpp +++ b/addons/misc/CfgFunctions.hpp @@ -40,14 +40,6 @@ class CfgFunctions { }; }; }; - class overwrite_ace_medical_status { - tag = "ace_medical_status"; - class ace_medical_status { - class hasStableVitals { - file = QPATHTOF(functions\fnc_hasStableVitals.sqf); - }; - }; - }; class overwrite_dogtags { tag = "ace_dogtags"; class ace_dogtags { diff --git a/addons/misc/XEH_PREP.hpp b/addons/misc/XEH_PREP.hpp index b59d9a0a8..e546e01c2 100644 --- a/addons/misc/XEH_PREP.hpp +++ b/addons/misc/XEH_PREP.hpp @@ -29,13 +29,14 @@ PREP(groupID); PREP(handleRespawn); PREP(handleTourniquetEffects); PREP(handleUnconscious); -PREP(hasStableVitals); PREP(heliAddActionDeploy); PREP(heliStretcherAttach); PREP(incompatibilityWarning); PREP(init); PREP(removeIVbag); PREP(setUnconscious); +PREP(setTourniquetTime); +PREP(removeTourniquetTime); PREP(slingArmband); PREP(stopCarryingPrompt); PREP(stretcher); diff --git a/addons/misc/XEH_postInit.sqf b/addons/misc/XEH_postInit.sqf index a0c9c7aa4..f3790d0fb 100644 --- a/addons/misc/XEH_postInit.sqf +++ b/addons/misc/XEH_postInit.sqf @@ -33,6 +33,9 @@ if (GVAR(incompatibilityWarning)) then { call FUNC(incompatibilityWarning); }; +[QACEGVAR(medical_treatment,tourniquetLocal), LINKFUNC(setTourniquetTime)] call CBA_fnc_addEventHandler; +[QACEGVAR(medical_treatment,tourniquetRemove), LINKFUNC(removeTourniquetTime)] call CBA_fnc_addEventHandler; + ["kat_Armband_Red_Cross_Item", "kat_Armband_Red_Cross_Goggles"] call ACEFUNC(common,registerItemReplacement); ["kat_Armband_Medic_Item", "kat_Armband_Medic_Goggles"] call ACEFUNC(common,registerItemReplacement); ["kat_Armband_Doctor_Item", "kat_Armband_Doctor_Goggles"] call ACEFUNC(common,registerItemReplacement); diff --git a/addons/misc/functions/fnc_BubbleWrap.sqf b/addons/misc/functions/fnc_BubbleWrap.sqf index bb1d69e35..8af4556d6 100644 --- a/addons/misc/functions/fnc_BubbleWrap.sqf +++ b/addons/misc/functions/fnc_BubbleWrap.sqf @@ -15,5 +15,6 @@ params ["_unit"]; [_unit, 'kat_Bubble_Wrap'] call ACEFUNC(common,adjustMagazineAmmo); + [QEGVAR(pharma,medicationLocal), [_unit, "Head", "BubbleWrap"], _unit] call CBA_fnc_targetEvent; playsound3D [selectRandom [QPATHTOF_SOUND(sounds\bubble_wrap_1.ogg),QPATHTOF_SOUND(sounds\bubble_wrap_2.ogg),QPATHTOF_SOUND(sounds\bubble_wrap_3.ogg),QPATHTOF_SOUND(sounds\bubble_wrap_4.ogg),QPATHTOF_SOUND(sounds\bubble_wrap_5.ogg)], _unit, false, getPosASL _unit, 30, 1, 10]; diff --git a/addons/misc/functions/fnc_removeTourniquetTime.sqf b/addons/misc/functions/fnc_removeTourniquetTime.sqf new file mode 100644 index 000000000..42071f0c8 --- /dev/null +++ b/addons/misc/functions/fnc_removeTourniquetTime.sqf @@ -0,0 +1,27 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Removes in game time when tourniquet was applied + * + * Arguments: + * 0: The Unit + * 1: Temperature Adjustments + * 2: Body Part + * + * ReturnValue: + * None + * + * Example: + * [player, cursorObject, "LeftLeg"] call kat_misc_fnc_removeTourniquetTime; + * + * Public: No + */ + +params ["_medic", "_patient", "_bodyPart"]; + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; +private _tourniquetsDisplay = _patient getVariable [QEGVAR(circulation,tourniquetTime), [0,0,0,0,0,0]]; + +_tourniquetsDisplay set [_partIndex, 0]; + +_patient setVariable [QEGVAR(circulation,tourniquetTime), _tourniquetsDisplay, true]; \ No newline at end of file diff --git a/addons/misc/functions/fnc_setTourniquetTime.sqf b/addons/misc/functions/fnc_setTourniquetTime.sqf new file mode 100644 index 000000000..ddf6def4b --- /dev/null +++ b/addons/misc/functions/fnc_setTourniquetTime.sqf @@ -0,0 +1,26 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Records in game time when tourniquet was applied + * + * Arguments: + * 0: The Unit + * 1: Body Part + * + * ReturnValue: + * None + * + * Example: + * [cursorObject, "LeftLeg"] call kat_misc_fnc_setTourniquetTime; + * + * Public: No + */ + +params ["_patient", "_bodyPart"]; + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; +private _tourniquetsDisplay = _patient getVariable [QEGVAR(circulation,tourniquetTime), [0,0,0,0,0,0]]; + +_tourniquetsDisplay set [_partIndex, ([dayTime, "HH:MM"] call BIS_fnc_timeToString)]; + +_patient setVariable [QEGVAR(circulation,tourniquetTime), _tourniquetsDisplay, true]; \ No newline at end of file diff --git a/addons/pharma/ACE_Medical_Treatment_Actions.hpp b/addons/pharma/ACE_Medical_Treatment_Actions.hpp index b9e8ebf31..66c4ee124 100644 --- a/addons/pharma/ACE_Medical_Treatment_Actions.hpp +++ b/addons/pharma/ACE_Medical_Treatment_Actions.hpp @@ -11,31 +11,31 @@ class ACE_Medical_Treatment_Actions { allowedSelections[] = {"Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"}; medicRequired = QUOTE(ace_medical_treatment_medicIV); condition = QUOTE(!(GVAR(RequireInsIV)) || FUNC(removeIV)); - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 800, 16] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -800, 16] call kat_pharma_fnc_fluid;"; }; class BloodIV_500: BloodIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 400, 8] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -400, 8] call kat_pharma_fnc_fluid;"; }; class BloodIV_250: BloodIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 200, 4] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -200, 4] call kat_pharma_fnc_fluid;"; }; class SalineIV: BloodIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -750, 0] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 750, 0] call kat_pharma_fnc_fluid;"; }; class SalineIV_500: SalineIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -350, 0] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 350, 0] call kat_pharma_fnc_fluid;"; }; class SalineIV_250: SalineIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -150, 0] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 150, 0] call kat_pharma_fnc_fluid;"; }; class PlasmaIV: BloodIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 500, 20] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -500, 20] call kat_pharma_fnc_fluid;"; }; class PlasmaIV_500: PlasmaIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 250, 10] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -250, 10] call kat_pharma_fnc_fluid;"; }; class PlasmaIV_250: PlasmaIV { - callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, 100, 5] call kat_pharma_fnc_fluid;"; + callbackSuccess = "[_medic, _patient, _bodyPart, _className, _itemUser, _usedItem] call ace_medical_treatment_fnc_ivBag; [_patient, -100, 5] call kat_pharma_fnc_fluid;"; }; class Epinephrine: Morphine { callbackSuccess = QFUNC(medication); diff --git a/addons/pharma/functions/fnc_clotWound.sqf b/addons/pharma/functions/fnc_clotWound.sqf index 5c0dc53e9..7f079c52f 100644 --- a/addons/pharma/functions/fnc_clotWound.sqf +++ b/addons/pharma/functions/fnc_clotWound.sqf @@ -119,7 +119,7 @@ private _fnc_clotWound = { if (_openWounds isEqualTo createHashmap) exitWith {}; // Exit when hashmap not initialized (Will not work when hashmap is set, cause ace only changes value of "woundCount" to 0) if (_coagulationFactor <= 0) exitWith {}; // Exit when no coagFactors left - if (_unit getVariable [QACEGVAR(medical,bloodVolume), 6.0] < GVAR(coagulation_requireBV)) exitWith {}; // Blood volume check + if (GET_BLOOD_VOLUME_LITERS(_unit) < GVAR(coagulation_requireBV)) exitWith {}; // Blood volume check if ((_pulse < 20) && GVAR(coagulation_requireHR)) exitWith {}; // Has pulse & require setting private _shuffledKeys = keys _openWounds call BIS_fnc_arrayShuffle; // Shuffel Keys to switch bodypart after each bandage for on_all_Bodyparts setting diff --git a/addons/pharma/functions/fnc_coagRegen.sqf b/addons/pharma/functions/fnc_coagRegen.sqf index a64bf46cd..c6ffeccaf 100644 --- a/addons/pharma/functions/fnc_coagRegen.sqf +++ b/addons/pharma/functions/fnc_coagRegen.sqf @@ -33,7 +33,7 @@ if !(GVAR(coagulation)) exitWith {}; [_idPFH] call CBA_fnc_removePerFrameHandler; }; - if (_unit getVariable [QACEGVAR(medical,bloodVolume), 6.0] < GVAR(coagulation_requireBV)) exitWith {}; // Blood volume check + if (GET_BLOOD_VOLUME_LITERS(_unit) < GVAR(coagulation_requireBV)) exitWith {}; // Blood volume check if ((_pulse < 20) && GVAR(coagulation_requireHR)) exitWith {}; // Has pulse & require setting private _currentCoagFactors = _unit getVariable [QGVAR(coagulationFactor), 30]; diff --git a/addons/pharma/functions/fnc_fluidLocal.sqf b/addons/pharma/functions/fnc_fluidLocal.sqf index 09151eaf4..e2609a96e 100644 --- a/addons/pharma/functions/fnc_fluidLocal.sqf +++ b/addons/pharma/functions/fnc_fluidLocal.sqf @@ -19,12 +19,10 @@ params ["_patient", "_ph", "_coagulation"]; -private _current = _patient getVariable [QGVAR(pH), 1500]; -private _final = (_current + _ph) max 0; -_final min 1500; -_patient setVariable [QGVAR(pH), (_final), true]; +private _current = _patient getVariable [QGVAR(externalPh), 0]; +_patient setVariable [QGVAR(externalPh), ((_current + _ph) max 0), true]; private _coagFactorMax = missionNamespace getVariable [QGVAR(coagulation_factor_limit), 60]; private _factor = _patient getVariable [QGVAR(coagulationFactor), 30]; private _final2 = (_factor + _coagulation) min _coagFactorMax; -_patient setVariable [QGVAR(coagulationFactor), (_final2), true]; +_patient setVariable [QGVAR(coagulationFactor), (_final2), true]; \ No newline at end of file diff --git a/addons/pharma/functions/fnc_fullHealLocal.sqf b/addons/pharma/functions/fnc_fullHealLocal.sqf index 7e3af217b..14befa1c7 100644 --- a/addons/pharma/functions/fnc_fullHealLocal.sqf +++ b/addons/pharma/functions/fnc_fullHealLocal.sqf @@ -29,10 +29,12 @@ TRACE_1("fullHealLocal",_patient); GVAR(cardiacArrestBleedRate) = ACEGVAR(medical,const_minCardiacOutput) * EGVAR(circulation,cardiacArrestBleedRate); _patient setVariable [QGVAR(alphaAction), 1, true]; _patient setVariable [QGVAR(IV), [0,0,0,0,0,0], true]; +_patient setVariable [QGVAR(IVflow), [0,0,0,0,0,0], true]; _patient setVariable [QGVAR(IVpfh), [0,0,0,0,0,0], true]; _patient setVariable [QGVAR(active), false, true]; _patient setVariable [QGVAR(IVPharma_PFH), nil, true]; -_patient setVariable [QGVAR(pH), 1500, true]; +_patient setVariable [QGVAR(externalPh), 0, true]; +_patient setVariable [QGVAR(pH), 0, true]; _patient setVariable [QGVAR(kidneyFail), false, true]; _patient setVariable [QGVAR(kidneyArrest), false, true]; _patient setVariable [QGVAR(kidneyPressure), false, true]; diff --git a/addons/pharma/functions/fnc_getBloodVolumeChange.sqf b/addons/pharma/functions/fnc_getBloodVolumeChange.sqf index 7e1aacb93..dc69318b5 100644 --- a/addons/pharma/functions/fnc_getBloodVolumeChange.sqf +++ b/addons/pharma/functions/fnc_getBloodVolumeChange.sqf @@ -12,7 +12,7 @@ * Blood volume change (liters per second) * * Example: - * [player, 1, true] call ace_medical_status_fnc_getBloodVolumeChange + * [player, 1, true] call kat_pharma_fnc_getBloodVolumeChange * * Public: No */ @@ -21,25 +21,58 @@ params ["_unit", "_deltaT", "_syncValues"]; private _bloodLoss = [_unit] call ACEFUNC(medical_status,getBloodLoss); private _internalBleeding = GET_INTERNAL_BLEEDING(_unit); -private _bloodVolumeChange = -_deltaT * (_bloodLoss + _internalBleeding); +private _lossVolumeChange = (-_deltaT * ((_bloodLoss + _internalBleeding * (GET_HEART_RATE(_unit) / DEFAULT_HEART_RATE)) / GET_VASOCONSTRICTION(_unit))); +private _fluidVolume = GET_BODY_FLUID(_unit); +private _SRBCChange = 0; +_fluidVolume params ["_ECP","_ECB","_SRBC","_ISP","_fullVolume"]; + +_ECP = _ECP + (_lossVolumeChange * LITERS_TO_ML) / 2; +_ECB = _ECB + (_lossVolumeChange * LITERS_TO_ML) / 2; + +_SRBCChange = if (_SRBC > 100 && _ECB < DEFAULT_ECB) then { ((DEFAULT_ECB - _ECB) min (abs ((_lossVolumeChange * LITERS_TO_ML)) / 2 + 1)) } else { 0 }; +_ECB = _ECB + _SRBCChange; if (!isNil {_unit getVariable [QACEGVAR(medical,ivBags),[]]}) then { private _bloodBags = _unit getVariable [QACEGVAR(medical,ivBags), []]; - private _tourniquets = GET_TOURNIQUETS(_unit); private _IVarray = _unit getVariable [QGVAR(IV), [0,0,0,0,0,0]]; - private _flowCalculation = ACEGVAR(medical,ivFlowRate) * (_unit getVariable [QGVAR(alphaAction), 1]) * _deltaT * 4.16; + private _flowCalculation = (ACEGVAR(medical,ivFlowRate) * _deltaT * 4.16); + private _hypothermia = missionNameSpace getVariable [QEGVAR(hypothermia,hypothermiaActive), false]; if (GET_HEART_RATE(_unit) < 20) then { _flowCalculation = _flowCalculation / 1.5; }; + if (_hypothermia) then { + private _incomingVolumeChange = [0,0,0,0,0,0]; + private _fluidWarmer = _unit getVariable [QEGVAR(hypothermia,fluidWarmer), [0,0,0,0,0,0]]; + private _fluidHeat = 0; + }; + _bloodBags = _bloodBags apply { _x params ["_bagVolumeRemaining", "_type", "_bodyPart"]; + private _tourniquets = GET_TOURNIQUETS(_unit); + if ((_tourniquets select _bodyPart isEqualTo 0) && (_IVarray select _bodyPart isNotEqualTo 3)) then { - private _bagChange = _flowCalculation min _bagVolumeRemaining; // absolute value of the change in miliLiters + private _IVflow = _unit getVariable [QGVAR(IVflow), [0,0,0,0,0,0]]; + private _bagChange = (_flowCalculation * (_IVflow select _bodyPart)) min _bagVolumeRemaining; // absolute value of the change in miliLiters _bagVolumeRemaining = _bagVolumeRemaining - _bagChange; - _bloodVolumeChange = _bloodVolumeChange + (_bagChange / 1000); + + if (_hypothermia) then { + // If fluid warmers are on the line, fluids are "warmed" and added to the warmer. If there is no fluid warmer on the line, the fluids stayed cooled + if (_fluidWarmer select _bodyPart == 1) then { + _incomingVolumeChange set [_bodyPart, ((_incomingVolumeChange select _bodyPart) + _bagChange)]; + } else { + _incomingVolumeChange set [_bodyPart, ((_incomingVolumeChange select _bodyPart) - _bagChange)]; + }; + }; + + // Plasma adds to ECP. Saline splits between the ECP and ISP. Blood adds to ECB + switch (true) do { + case(_type == "Plasma"): { _ECP = _ECP + _bagChange; _lossVolumeChange = _lossVolumeChange + (_bagChange / ML_TO_LITERS); }; + case(_type == "Saline"): { _ECP = _ECP + _bagChange / 2; _ISP = _ISP + _bagChange / 2; _lossVolumeChange = _lossVolumeChange + (_bagChange / 2000); }; + case(_type == "Blood"): { _ECB = _ECB + _bagChange; _lossVolumeChange = _lossVolumeChange + (_bagChange / ML_TO_LITERS); }; + }; }; if (_bagVolumeRemaining < 0.01) then { @@ -56,6 +89,41 @@ if (!isNil {_unit getVariable [QACEGVAR(medical,ivBags),[]]}) then { } else { _unit setVariable [QACEGVAR(medical,ivBags), _bloodBags, _syncValues]; }; + + // Incoming fluids impacting internal temperature + if (_hypothermia) then { + {_fluidHeat = _fluidHeat + _x} forEach _incomingVolumeChange; + + if (_fluidHeat > 0) then { + private _totalHeat = _unit getVariable [QEGVAR(hypothermia,warmingImpact), 0]; + _unit setVariable [QEGVAR(hypothermia,warmingImpact), _totalHeat + _fluidHeat, _syncValues]; + } else { + private _totalCooling = _unit getVariable [QEGVAR(hypothermia,warmingImpact), 0]; + _unit setVariable [QEGVAR(hypothermia,warmingImpact), _totalCooling + _fluidHeat, _syncValues]; + }; + }; }; -_bloodVolumeChange +// Movement and recovery of interstital fluid +private _shiftValue = 0; +switch (true) do { + case ((_ECB + _ECP) > (_ISP * 0.6)): { + _shiftValue = (5 min ((_ECP + _ECB) - (_ISP * 0.6))); + _ECP = _ECP - _shiftValue; + _ISP = _ISP + _shiftValue; + }; + case ((_ECB + _ECP) < (_ISP * 0.6)): { + _shiftValue = (5 min ((_ISP * 0.6) - (_ECP + _ECB))); + _ECP = _ECP + _shiftValue; + _ISP = _ISP - _shiftValue; + }; + default { + // If no shift is required, fluids begin returning to baseline in both ISP and SRBC volumes + _ISP = _ISP + ((DEFAULT_ISP - _ISP) min 2); + _SRBC = _SRBC + ((DEFAULT_SRBC - _SRBC) min 1); + }; +}; + +_unit setVariable [QEGVAR(circulation,bodyFluid), [_ECP, _ECB, (_SRBC - _SRBCChange), _ISP, (_ECP + _ECB)], _syncValues]; + +((_lossVolumeChange + GET_BLOOD_VOLUME_LITERS(_unit)) max 0.01) \ No newline at end of file diff --git a/addons/pharma/functions/fnc_handleRespawn.sqf b/addons/pharma/functions/fnc_handleRespawn.sqf index 8a2b99bd9..06c6c0561 100644 --- a/addons/pharma/functions/fnc_handleRespawn.sqf +++ b/addons/pharma/functions/fnc_handleRespawn.sqf @@ -57,37 +57,43 @@ if (GVAR(kidneyAction)) then { [_idPFH] call CBA_fnc_removePerFrameHandler; }; - private _ph = _unit getVariable [QGVAR(pH), 1500]; - if (_ph == 1500) exitWith {}; - + private _ph = _unit getVariable [QGVAR(externalPh), 0]; private _kidneyFail = _unit getVariable [QGVAR(kidneyFail), false]; private _kidneyArrest = _unit getVariable [QGVAR(kidneyArrest), false]; private _kidneyPressure = _unit getVariable [QGVAR(kidneyPressure), false]; - if (_ph <= 0) exitWith { - _unit setVariable [QGVAR(kidneyFail), true, true]; - - if !(_kidneyArrest) then { - private _random = random 1; - - if (_random >= 0.5) then { - [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + switch true do { + case(_ph == 3000): { + if (_ph == 3000) exitWith { + _unit setVariable [QGVAR(kidneyFail), true, true]; _unit setVariable [QGVAR(kidneyArrest), true, true]; }; }; - }; - - if (_ph < 750) exitWith { - _ph = (_ph + 25) min 1500; - _unit setVariable [QGVAR(pH), _ph, true]; - - if !(_kidneyPressure) then { - _unit setVariable [QGVAR(kidneyPressure), true, true]; - [_unit, "KIDNEY", 15, 1200, 30, 0, 15] call ACEFUNC(medical_status,addMedicationAdjustment); + case (_ph >= 2000): { + _unit setVariable [QGVAR(kidneyFail), true, true]; + + if !(_kidneyArrest) then { + private _random = random 1; + + if (_random >= 0.75) then { + [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + _unit setVariable [QGVAR(kidneyArrest), true, true]; + }; + }; + }; + case (_ph >= 1000): { + _ph = (_ph - 30) max 0; + _unit setVariable [QGVAR(externalPh), _ph, true]; + + if !(_kidneyPressure) then { + _unit setVariable [QGVAR(kidneyPressure), true, true]; + [_unit, "KIDNEY", 15, 1200, 30, 0, 15] call ACEFUNC(medical_status,addMedicationAdjustment); + }; + }; + default { + _ph = (_ph - 60) max 0; + _unit setVariable [QGVAR(externalPh), _ph, true]; }; }; - - _ph = (_ph + 50) min 1500; - _unit setVariable [QGVAR(pH), _ph, true]; }, 20, [_unit]] call CBA_fnc_addPerFrameHandler; }; diff --git a/addons/pharma/functions/fnc_init.sqf b/addons/pharma/functions/fnc_init.sqf index bfdd09d48..8afb3986e 100644 --- a/addons/pharma/functions/fnc_init.sqf +++ b/addons/pharma/functions/fnc_init.sqf @@ -71,42 +71,43 @@ if (GVAR(kidneyAction)) then { [_idPFH] call CBA_fnc_removePerFrameHandler; }; - private _ph = _unit getVariable [QGVAR(pH), 1500]; - if (_ph == 1500) exitWith { - _unit setVariable [QGVAR(kidneyArrest), false, true]; - _unit setVariable [QGVAR(kidneyPressure), false, true]; - _unit setVariable [QGVAR(kidneyFail), false, true]; - }; - + private _ph = _unit getVariable [QGVAR(externalPh), 0]; private _kidneyFail = _unit getVariable [QGVAR(kidneyFail), false]; private _kidneyArrest = _unit getVariable [QGVAR(kidneyArrest), false]; private _kidneyPressure = _unit getVariable [QGVAR(kidneyPressure), false]; - if (_ph <= 0) exitWith { - _unit setVariable [QGVAR(kidneyFail), true, true]; - _unit setVariable [QGVAR(pH), 0, true]; - - if !(_kidneyArrest) then { - private _random = random 1; - - if (_random >= 0.5) then { - [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + switch true do { + case(_ph == 3000): { + if (_ph == 3000) exitWith { + _unit setVariable [QGVAR(kidneyFail), true, true]; _unit setVariable [QGVAR(kidneyArrest), true, true]; }; }; - }; - - if (_ph < 750) exitWith { - _ph = (_ph + 25) min 1500; - _unit setVariable [QGVAR(pH), _ph, true]; - - if !(_kidneyPressure) then { - _unit setVariable [QGVAR(kidneyPressure), true, true]; - [_unit, "KIDNEY", 15, 1200, 30, 0, 15] call ACEFUNC(medical_status,addMedicationAdjustment); + case (_ph >= 2000): { + _unit setVariable [QGVAR(kidneyFail), true, true]; + + if !(_kidneyArrest) then { + private _random = random 1; + + if (_random >= 0.75) then { + [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + _unit setVariable [QGVAR(kidneyArrest), true, true]; + }; + }; + }; + case (_ph >= 1000): { + _ph = (_ph - 30) max 0; + _unit setVariable [QGVAR(externalPh), _ph, true]; + + if !(_kidneyPressure) then { + _unit setVariable [QGVAR(kidneyPressure), true, true]; + [_unit, "KIDNEY", 15, 1200, 30, 0, 15] call ACEFUNC(medical_status,addMedicationAdjustment); + }; + }; + default { + _ph = (_ph - 60) max 0; + _unit setVariable [QGVAR(externalPh), _ph, true]; }; }; - - _ph = (_ph + 50) min 1500; - _unit setVariable [QGVAR(pH), _ph, true]; }, 20, [_unit]] call CBA_fnc_addPerFrameHandler; }; diff --git a/addons/pharma/functions/fnc_treatmentAdvanced_DialysisLocal.sqf b/addons/pharma/functions/fnc_treatmentAdvanced_DialysisLocal.sqf index a817dd662..d3f69e4ef 100644 --- a/addons/pharma/functions/fnc_treatmentAdvanced_DialysisLocal.sqf +++ b/addons/pharma/functions/fnc_treatmentAdvanced_DialysisLocal.sqf @@ -19,7 +19,7 @@ params ["_medic", "_patient"]; _patient setVariable [QACEGVAR(medical,medications), [], true]; -_patient setVariable [QGVAR(pH), 1000, true]; +_patient setVariable [QGVAR(externalPh), 0, true]; _patient setVariable [QGVAR(kidneyFail), false, true]; _patient setVariable [QGVAR(kidneyArrest), false, true]; _patient setVariable [QGVAR(kidneyPressure), false, true]; diff --git a/addons/pharma/functions/fnc_treatmentAdvanced_EACALocal.sqf b/addons/pharma/functions/fnc_treatmentAdvanced_EACALocal.sqf index 502b608c9..2a815a6df 100644 --- a/addons/pharma/functions/fnc_treatmentAdvanced_EACALocal.sqf +++ b/addons/pharma/functions/fnc_treatmentAdvanced_EACALocal.sqf @@ -49,7 +49,6 @@ if (_IVactual > 1) then { if (!(GVAR(coagulation)) || GVAR(coagulation_allow_EACA_script)) then { if (_IVactual != 3) then { - if (_countEACA > 1 && !(_allowStack)) exitWith {}; [{ @@ -59,8 +58,8 @@ if (!(GVAR(coagulation)) || GVAR(coagulation_allow_EACA_script)) then { private _alive = alive _patient; private _exit = true; - private _random = random 750; - private _ph = (_patient getVariable [QGVAR(pH), 1500]) - 750; + private _random = random [6.4, 6.8, 7.2]; + private _ph = GET_PH(_patient); if !(_alive) exitWith { [_idPFH] call CBA_fnc_removePerFrameHandler; diff --git a/addons/pharma/functions/fnc_treatmentAdvanced_TXALocal.sqf b/addons/pharma/functions/fnc_treatmentAdvanced_TXALocal.sqf index 7f74eec37..c52d0a4be 100644 --- a/addons/pharma/functions/fnc_treatmentAdvanced_TXALocal.sqf +++ b/addons/pharma/functions/fnc_treatmentAdvanced_TXALocal.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: 2LT.Mazinski + * Author: Mazinski * Begins TXA bandaging process * * Arguments: @@ -58,18 +58,13 @@ if (!(GVAR(coagulation)) || GVAR(coagulation_allow_TXA_script)) then { private _alive = alive _patient; private _exit = true; + private _random = random [6.4, 6.8, 7.2]; + private _ph = GET_PH(_patient); if !(_alive) exitWith { [_idPFH] call CBA_fnc_removePerFrameHandler; }; - if !(GVAR(kidneyAction)) then { - _patient setVariable [QGVAR(pH), 1500, true]; - }; - - private _random = random 1000; - private _ph = (_patient getVariable [QGVAR(pH), 1500]) - 500; - if (_random <= _ph) then { { _x params ["_targetBodyPart"]; diff --git a/addons/pharma/stringtable.xml b/addons/pharma/stringtable.xml index 91e134670..98edb2851 100644 --- a/addons/pharma/stringtable.xml +++ b/addons/pharma/stringtable.xml @@ -3527,13 +3527,13 @@ Coletando amostra sanguínea, - slightly below normal INR + Slightly Below Normal INR 正常INRより少し低い ligeramente por debajo del INR normal INR ligeiramente abaixo do normal - sligtly above normal INR + Sligtly Above normal INR 正常INRより少し高い ligeramente por encima de INR normal INR ligeiramente acima do normal diff --git a/addons/surgery/ACE_Medical_Treatment_Actions.hpp b/addons/surgery/ACE_Medical_Treatment_Actions.hpp index 1115934d3..da72a3a70 100644 --- a/addons/surgery/ACE_Medical_Treatment_Actions.hpp +++ b/addons/surgery/ACE_Medical_Treatment_Actions.hpp @@ -45,7 +45,7 @@ class ACE_Medical_Treatment_Actions { items[] = {"kat_plate"}; consumeItem = 1; condition = QUOTE([ARR_4(_medic,_patient,_bodyPart,3.5)] call FUNC(openReductionCheck)); - callbackSuccess = QFUNC(openReduction); + callbackSuccess = QUOTE([ARR_4(_medic,_patient,_bodyPart,false)] call FUNC(openReduction)); }; class Expose: BasicBandage { displayName = CSTRING(Retractor_Use); @@ -101,6 +101,20 @@ class ACE_Medical_Treatment_Actions { condition = QUOTE([ARR_4(_medic,_patient,_bodyPart,2.3)] call FUNC(openReductionCheck)); callbackSuccess = QUOTE([ARR_4(_medic,_patient,_bodyPart,2.3)] call FUNC(openReductionProgress)); }; + class ResetSurgery: CheckFracture { + displayName = CSTRING(Reset_Surgery); + displayNameProgress = CSTRING(perform); + category = "surgery"; + treatmentLocations = QGVAR(surgicalLocation); + allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; + allowSelfTreatment = 0; + medicRequired = QGVAR(surgicalAction_MedLevel); + treatmentTime = QGVAR(openTime); + items[] = {"ACE_surgicalKit"}; + consumeItem = 1; + condition = QUOTE(([ARR_4(_medic,_patient,_bodyPart,2)] call FUNC(openReductionCheck)) && (GVAR(enable_fracture))); + callbackSuccess = QUOTE([ARR_4(_medic,_patient,_bodyPart,true)] call FUNC(openReduction)); + }; class NPWT: BasicBandage { displayName = CSTRING(Vacuum_Use); displayNameProgress = CSTRING(Vacuum_Action); diff --git a/addons/surgery/functions/fnc_openReduction.sqf b/addons/surgery/functions/fnc_openReduction.sqf index 90c6cc62e..b585e3562 100644 --- a/addons/surgery/functions/fnc_openReduction.sqf +++ b/addons/surgery/functions/fnc_openReduction.sqf @@ -17,6 +17,6 @@ * Public: No */ -params ["_medic", "_patient", "_bodyPart"]; +params ["_medic", "_patient", "_bodyPart", "_exit"]; -[QGVAR(openReduction), [_medic, _patient, _bodyPart], _patient] call CBA_fnc_targetEvent; +[QGVAR(openReduction), [_medic, _patient, _bodyPart, _exit], _patient] call CBA_fnc_targetEvent; diff --git a/addons/surgery/functions/fnc_openReductionLocal.sqf b/addons/surgery/functions/fnc_openReductionLocal.sqf index 2fd8a9c46..13f72e9f4 100644 --- a/addons/surgery/functions/fnc_openReductionLocal.sqf +++ b/addons/surgery/functions/fnc_openReductionLocal.sqf @@ -17,13 +17,27 @@ * Public: No */ -params ["_medic", "_patient", "_bodyPart"]; +params ["_medic", "_patient", "_bodyPart", "_exit"]; private _part = ALL_BODY_PARTS find toLower _bodyPart; private _activeFracture = GET_FRACTURES(_patient); private _fractureArray = _patient getVariable [QGVAR(fractures), [0,0,0,0,0,0]]; private _liveFracture = _fractureArray select _part; +if (_exit) exitWith { + if (_liveFracture < 2.5) then { + _liveFracture = 2; + } else { + _liveFracture = 3; + }; + + _fractureArray set [_part, _liveFracture]; + _patient setVariable [QGVAR(fractures), _fractureArray, true]; + + [_patient, true] call ACEFUNC(dragging,setCarryable); + [_patient, true] call ACEFUNC(dragging,setDraggable); +}; + if ((_liveFracture == 2.5) || (_liveFracture == 3.5)) exitWith { _liveFracture = 0; diff --git a/addons/surgery/stringtable.xml b/addons/surgery/stringtable.xml index 4ad7ae813..598caf4e8 100644 --- a/addons/surgery/stringtable.xml +++ b/addons/surgery/stringtable.xml @@ -491,6 +491,9 @@ Kastelu Промывание + + Close Incision + Bone Plate 骨板 diff --git a/addons/vitals/$PBOPREFIX$ b/addons/vitals/$PBOPREFIX$ new file mode 100644 index 000000000..49f81db89 --- /dev/null +++ b/addons/vitals/$PBOPREFIX$ @@ -0,0 +1 @@ +x\kat\addons\vitals \ No newline at end of file diff --git a/addons/vitals/CfgEventHandlers.hpp b/addons/vitals/CfgEventHandlers.hpp new file mode 100644 index 000000000..4551ce282 --- /dev/null +++ b/addons/vitals/CfgEventHandlers.hpp @@ -0,0 +1,20 @@ +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + disableModuload = "true"; + }; +}; + +class Extended_Init_EventHandlers { + class CAManBase { + class ADDON { + init = QUOTE([ARR_2((_this select 0),false)] call FUNC(init)); + }; + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_postInit)); + }; +}; diff --git a/addons/vitals/CfgFunctions.hpp b/addons/vitals/CfgFunctions.hpp new file mode 100644 index 000000000..0bb3d51b3 --- /dev/null +++ b/addons/vitals/CfgFunctions.hpp @@ -0,0 +1,18 @@ +class CfgFunctions { + class overwrite_ace_medical_status { + tag = "ace_medical_status"; + class ace_medical_status { + class hasStableVitals { + file = QPATHTOF(functions\fnc_hasStableVitals.sqf); + }; + }; + }; + class overwrite_ace_medical_vitals { + tag = "ace_medical_vitals"; + class ace_medical_vitals { + class handleUnitVitals { + file = QPATHTOF(functions\fnc_handleUnitVitals.sqf); + }; + }; + }; +}; diff --git a/addons/vitals/XEH_PREP.hpp b/addons/vitals/XEH_PREP.hpp new file mode 100644 index 000000000..d1eb1a60c --- /dev/null +++ b/addons/vitals/XEH_PREP.hpp @@ -0,0 +1,8 @@ +PREP(handleUnitVitals); +PREP(handleSimpleVitals); +PREP(handleCardiacFunction); +PREP(handleTemperatureFunction); +PREP(handleRespawn); +PREP(handleOxygenFunction); +PREP(hasStableVitals); +PREP(init); \ No newline at end of file diff --git a/addons/vitals/XEH_postInit.sqf b/addons/vitals/XEH_postInit.sqf new file mode 100644 index 000000000..b98c22217 --- /dev/null +++ b/addons/vitals/XEH_postInit.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +[QEGVAR(misc,handleRespawn), LINKFUNC(handleRespawn)] call CBA_fnc_addEventHandler; diff --git a/addons/vitals/XEH_preInit.sqf b/addons/vitals/XEH_preInit.sqf new file mode 100644 index 000000000..1f942547e --- /dev/null +++ b/addons/vitals/XEH_preInit.sqf @@ -0,0 +1,20 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +#define CBA_SETTINGS_CAT "KAT - ADV Medical: Vitals" + +[ + QGVAR(simpleMedical), + "CHECKBOX", + LLSTRING(SIMPLEMED_ENABLE), + [CBA_SETTINGS_CAT, ELSTRING(GUI,SubCategory_Basic)], + [false], + true +] call CBA_Settings_fnc_init; + +ADDON = true; diff --git a/addons/vitals/config.cpp b/addons/vitals/config.cpp new file mode 100644 index 000000000..87fc7dfe7 --- /dev/null +++ b/addons/vitals/config.cpp @@ -0,0 +1,33 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + requiredVersion = REQUIRED_VERSION; + units[] = {}; + weapons[] = {}; + magazines[] = {}; + requiredAddons[] = { + "ace_medical", + "ace_medical_ai", + "ace_medical_blood", + "ace_medical_damage", + "ace_medical_engine", + "ace_medical_feedback", + "ace_medical_gui", + "ace_medical_statemachine", + "ace_medical_status", + "ace_medical_treatment", + "ace_medical_vitals", + "ace_dogtags", + "cba_settings" + }; + author = "Mazinski"; + authors[] = {"Mazinski"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgFunctions.hpp" \ No newline at end of file diff --git a/addons/vitals/functions/fnc_handleCardiacFunction.sqf b/addons/vitals/functions/fnc_handleCardiacFunction.sqf new file mode 100644 index 000000000..c23341803 --- /dev/null +++ b/addons/vitals/functions/fnc_handleCardiacFunction.sqf @@ -0,0 +1,71 @@ +#include "..\script_component.hpp" +/* + * Author: Glowbal, Mazinski + * Update heart rate + + * Arguments: + * 0: The Unit + * 1: Heart Rate Adjustments + * 2: Heart Rate Target + * 3: Blood Volume + * 4: Time since last update + * 5: Sync value? + * + * ReturnValue: + * Current Heart Rate + * + * Example: + * [player, 0, 80, 6, 1, false] call kat_vitals_handleCardiacFunction; + * + * Public: No + */ + +params ["_unit", "_hrTargetAdjustment", "_hrTarget", "_bloodVolume", "_deltaT", "_syncValue"]; + +#define HEART_RATE_CO2_MULTIPLIER 60 +#define CO2_TO_DEMAND_DIVISOR 37894.7367424 +#define BLOOD_VOLUME_TO_STROKE_DIVISOR 3789.47371 +#define DEFAULT_STROKE_VOLUME 0.001583333323 + +private _actualHeartRate = _hrTarget; +private _actualReturn = 0; + +if IN_CRDC_ARRST(_unit) then { + if (alive (_unit getVariable [QEGVAR(medical,CPR_provider), objNull])) then { + if (_actualHeartRate == 0) then { _syncValue = true }; // always sync on large change + _actualHeartRate = random [100, 110, 120]; + } else { + if (_actualHeartRate != 0) then { _syncValue = true }; // always sync on large change + _actualHeartRate = 0 + }; +} else { + private _painLevel = GET_PAIN_PERCEIVED(_unit); + + // Adjustments and Pain Levels are taken off of last cycle HR to prevent any spiraling vitials + private _lastCycleHeartRate = GET_HEART_RATE(_unit) - _hrTargetAdjustment - (10 * _painLevel); + private _lastCycleCO2 = _lastCycleHeartRate * HEART_RATE_CO2_MULTIPLIER; + private _demandReturn = _lastCycleCO2 / CO2_TO_DEMAND_DIVISOR; + private _strokeVolume = (_bloodVolume / BLOOD_VOLUME_TO_STROKE_DIVISOR); + + // As HR increases, pressure is taken off decreasing stroke volume. However, this effect decreases at higher heart rates and lower SVs + private _strokeVolumeDifference = [ _strokeVolume / (DEFAULT_STROKE_VOLUME * 0.66), DEFAULT_STROKE_VOLUME / _strokeVolume ] select (DEFAULT_STROKE_VOLUME / _strokeVolume < 1.22); + private _volumeSupportHR = DEFAULT_HEART_RATE * _strokeVolumeDifference; + _strokeVolume = _strokeVolume * _strokeVolumeDifference; + + // Model HR driven by demandReturn divided by stroke volume with pressure applied by volume shortage. 40 point baseline applied to keep movements more stable + private _modelHeartRate = 40 + ((_demandReturn / _strokeVolume) / 2) + (_volumeSupportHR - DEFAULT_HEART_RATE); + + // Actual Heart Rate increases stepwise under the target model + _actualHeartRate = switch (true) do { + case (_modelHeartRate > _lastCycleHeartRate): { (_lastCycleHeartRate + (1 * _deltaT)) min _modelHeartRate }; + case (_modelHeartRate < _lastCycleHeartRate): { (_lastCycleHeartRate - (1 * _deltaT)) max _modelHeartRate }; + default { _modelHeartRate }; + }; + + // All additional adjustments are added back + _actualHeartRate = _actualHeartRate + _hrTargetAdjustment + (10 * _painLevel); +}; + +_unit setVariable [VAR_HEART_RATE, _actualHeartRate, _syncValue]; + +_actualHeartRate \ No newline at end of file diff --git a/addons/vitals/functions/fnc_handleOxygenFunction.sqf b/addons/vitals/functions/fnc_handleOxygenFunction.sqf new file mode 100644 index 000000000..925156509 --- /dev/null +++ b/addons/vitals/functions/fnc_handleOxygenFunction.sqf @@ -0,0 +1,90 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Updates the respiratory variables + * + * Arguments: + * 0: The Unit + * 1: Heart Rate + * 2: Anerobic Pressure + * 3: Blood Gas Array + * 4: Temperature + * 5: Barometric Pressure + * 6: Opioid Depression + * 7: Time since last update + * 8: Sync value? + * + * ReturnValue: + * Current O2 Saturation + * + * Example: + * [player, 80, 0.8, [40,90,0.96,24,7.4], 37, 760, 0, 1, true] call kat_vitals_fnc_handleOxygenFunction; + * + * Public: No + */ + +params ["_unit", "_actualHeartRate", "_anerobicPressure", "_bloodGas", "_temperature", "_baroPressure", "_opioidDepression", "_deltaT", "_syncValues"]; + +#define MAXIMUM_RR 40 +#define HEART_RATE_CO2_MULTIPLIER 60 +#define MINIMUM_VENTILATION 2000 +#define PACO2_MAX_CHANGE 0.05 +#define PAO2_MAX_CHANGE 0.1 +#define DEFAULT_FIO2 0.21 + +private _respiratoryRate = 0; +private _demandVentilation = 0; +private _actualVentilation = 0; +private _previousCyclePaco2 = (_bloodGas select 0); +private _previousCyclePao2 = (_bloodGas select 1); + +if (IN_CRDC_ARRST(_unit)) then { + // When in arrest, there should be no effecive breaths but still a minimum O2 demand. Zero O2 demand would mean a dead patient. Actual ventilation is 1 to prevent issues in the gas tension functions + _demandVentilation = MINIMUM_VENTILATION; + _respiratoryRate = 0; + _actualVentilation = 1; +} else { + // Ventilatory Demand comes from Heart Rate with increase demand from PaCO2 levels + _demandVentilation = ((((_actualHeartRate * HEART_RATE_CO2_MULTIPLIER) / _anerobicPressure) + ((_previousCyclePaco2 - DEFAULT_PACO2) * 200)) max MINIMUM_VENTILATION); + private _tidalVolume = GET_KAT_SURFACE_AREA(_unit); + + // Respiratory Rate is supressed by Opioids + _respiratoryRate = [((_demandVentilation / _tidalVolume) - (_opioidDepression * 10)) min MAXIMUM_RR, 20] select (_unit getVariable [QEGVAR(breathing,BVMInUse), false]); + _actualVentilation = _tidalVolume * _respiratoryRate; +}; + +// The greater the imbalance between CO2 explusion and O2 intake, the higher PaCO2 gets +private _paco2 = if ((_demandVentilation / _actualVentilation) == 1) then { _previousCyclePaco2 + (PACO2_MAX_CHANGE min (-PACO2_MAX_CHANGE max ((DEFAULT_PACO2 + ((_anerobicPressure max 1) - 1) * 150) - _previousCyclePaco2))) } else { [ _previousCyclePaco2 - (PACO2_MAX_CHANGE * _deltaT), _previousCyclePaco2 + (PACO2_MAX_CHANGE * _deltaT)] select ((_demandVentilation / _actualVentilation) > 0) }; +// Generated ETCO2 quadratic. Ensures ETCO2 moves with Respiratory Rate and is constantly below PaCO2 +private _etco2 = [((_paco2 - 3) - ((-0.0416667 * (_respiratoryRate^2)) + (3.09167 * (_respiratoryRate)) - DEFAULT_ETCO2) max 10), 0] select (IN_CRDC_ARRST(_unit)); + +// Extenal pH impacts from saline is included +private _externalPh = _unit getVariable [QEGVAR(pharma,externalPh), 0]; + +// pH is from the Henderson-Hasselbalch equation +private _pH = (6.1 + log(24 / ((0.03 - 0.001 * (_temperature - DEFAULT_TEMPERATURE)) * _paco2))) - ((_externalPh max 1) / 2000); + +// Fractional Oxygen when breathing normal air is 0.21, 1 when breathing 100% Oxygen, and 0 when no air is being brought into the lungs +private _fio2 = switch (true) do { + case ((_unit getVariable [QEGVAR(airway,occluded), false]) || (_unit getVariable [QEGVAR(airway,obstruction), false])): { 0 }; + case ((_unit getVariable [QEGVAR(chemical,airPoisoning), false]) || (_unit getVariable [QEGVAR(breathing,tensionpneumothorax), false]) || (_unit getVariable [QEGVAR(breathing,hemopneumothorax), false])): { 0 }; + case (_unit getVariable [QEGVAR(breathing,oxygenTankConnected), false]): { 1 }; + default { DEFAULT_FIO2 }; +}; + +// Alveolar Gas equation. PALVO2 is largely impacted by Barometric Pressure and FiO2 +private _pALVo2 = ((_fio2 * (_baroPressure - 47)) - (_paco2 / _anerobicPressure)) max 1; + +// PaO2 cannot be higher than PALVO2 and comes from ventilation shortage multipled by RBC volume +private _pao2 = (DEFAULT_PAO2 - ((DEFAULT_ECB / ((GET_BODY_FLUID(_unit) select 0) max 100)) * ((_demandVentilation - _actualVentilation) / 120))) min _pALVo2; + +// PaO2 moves in controlled steps to prevent hard movements when Ventilation Demand spikes +_pao2 = if (_previousCyclePao2 != _pao2) then { ([ _previousCyclePao2 - (PAO2_MAX_CHANGE * _deltaT) , _previousCyclePao2 + (PAO2_MAX_CHANGE * _deltaT)] select ((_previousCyclePao2 - _pao2) < 0)) } else { _pao2 }; + +// Oxy-Hemo Dissociation Curve, driven by PaO2 with shaping done by pH +private _o2Sat = ((_pao2 max 1)^2.7 / ((25 - (((_pH / DEFAULT_PH) - 1) * 150))^2.7 + _pao2^2.7)) min 0.999; + +_unit setVariable [VAR_BREATHING_RATE, _respiratoryRate, _syncValues]; +_unit setVariable [VAR_BLOOD_GAS, [_paco2, _pao2, _o2Sat, 24, _pH, _etco2], _syncValues]; + +_o2Sat * 100 diff --git a/addons/vitals/functions/fnc_handleRespawn.sqf b/addons/vitals/functions/fnc_handleRespawn.sqf new file mode 100644 index 000000000..9b7280d2f --- /dev/null +++ b/addons/vitals/functions/fnc_handleRespawn.sqf @@ -0,0 +1,20 @@ +#include "..\script_component.hpp" +/* + * Author: MiszczuZPolski + * Local callback for fully healing a patient. + * + * Arguments: + * 0: Patient + * + * Return Value: + * None + * + * Example: + * [player] call kat_vitals_fnc_handleRespawn + * + * Public: No + */ + +params ["_patient"]; + +if (!(isPlayer _unit) && GVAR(simpleMedical)) then { _patient setVariable [QGVAR(simpleMedical), true, true] }; \ No newline at end of file diff --git a/addons/vitals/functions/fnc_handleSimpleVitals.sqf b/addons/vitals/functions/fnc_handleSimpleVitals.sqf new file mode 100644 index 000000000..960c8c418 --- /dev/null +++ b/addons/vitals/functions/fnc_handleSimpleVitals.sqf @@ -0,0 +1,122 @@ +#include "..\script_component.hpp" +/* + * Author: Glowbal, Mazinski + * Updates the vitals for simple AI. Called from the statemachine's onState functions. + * + * Arguments: + * 0: The Unit + * + * Return Value: + * Update Ran (at least 1 second between runs) + * + * Example: + * [player] call kat_vitals_fnc_handleSimpleVitals; + * + * Public: No + */ + +params ["_unit"]; + +private _lastTimeUpdated = _unit getVariable [QACEGVAR(medical_vitals,lastTimeUpdated), 0]; +private _deltaT = (CBA_missionTime - _lastTimeUpdated) min 10; +if (_deltaT < 1) exitWith { false }; // state machines could be calling this very rapidly depending on number of local units + +BEGIN_COUNTER(Vitals); + +_unit setVariable [QACEGVAR(medical_vitals,lastTimeUpdated), CBA_missionTime]; +private _lastTimeValuesSynced = _unit getVariable [QACEGVAR(medical_vitals,lastMomentValuesSynced), 0]; +private _syncValues = (CBA_missionTime - _lastTimeValuesSynced) >= (10 + floor(random 10)); + +if (_syncValues) then { + _unit setVariable [QACEGVAR(medical_vitals,lastMomentValuesSynced), CBA_missionTime]; +}; + +//Get Blood Loss and Blood Volume from previous cycle +private _bloodVolume = GET_SIMPLE_BLOOD_VOLUME(_unit); +private _woundBloodLoss = GET_WOUND_BLEEDING(_unit); + +private _bloodVolume = _bloodVolume - (_woundBloodLoss / 100); +_unit setVariable [VAR_BLOOD_VOL, _bloodVolume, _syncValues]; + +private _inPain = GET_PAIN_PERCEIVED(_unit) > 0; +if !(_inPain isEqualTo IS_IN_PAIN(_unit)) then { + _unit setVariable [VAR_IN_PAIN, _inPain, true]; +}; + +// Get Medication Adjustments: +private _hrTargetAdjustment = 0; +private _painSupressAdjustment = 0; +private _adjustments = _unit getVariable [VAR_MEDICATIONS,[]]; + +if !(_adjustments isEqualTo []) then { + private _deleted = false; + { + _x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust", "_alphaFactor"]; + 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; }; + }; + } forEach _adjustments; + + if (_deleted) then { + _unit setVariable [VAR_MEDICATIONS, _adjustments - [objNull], true]; + _syncValues = true; + }; +}; + +private _heartRate = [_unit, _hrTargetAdjustment, _deltaT, _syncValues] call ACEFUNC(medical_vitals,updateHeartRate); //Rename +[_unit, _painSupressAdjustment, _deltaT, _syncValues] call ACEFUNC(medical_vitals,updatePainSuppress); //Leave alone + +// Remeber to change getBloodPressure macro ---------------------------------------------------------- + +private _bloodPressure = [120,80]; +_unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues]; + +_bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; + +// Statements are ordered by most lethal first. +switch (true) do { + case (IN_CRDC_ARRST(_unit)): {}; // if in cardiac arrest just break now to avoid throwing unneeded events + case (_heartRate < 20 || {_heartRate > 220}): { + TRACE_2("heartRate Fatal",_unit,_heartRate); + [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_bloodVolume < 5): { + TRACE_2("bloodVolume Fatal",_unit,_heartRate); + [QACEGVAR(medical,Bleedout), _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 [QACEGVAR(medical_vitals,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 [QACEGVAR(medical_vitals,nextCheckCriticalHeartRate), CBA_missionTime + 5]; + }; + if (_enterCardiacArrest) then { + TRACE_2("Heart rate critical. Cardiac arrest",_unit,_heartRate); + [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + } else { + TRACE_2("Heart rate critical. Critical vitals",_unit,_heartRate); + [QACEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; + }; + }; + case (_inPain): { + [QACEGVAR(medical,LoweredVitals), _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(_woundBloodLoss * 1000) / 1000, round((_woundBloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100]; +}; +#endif + +END_COUNTER(Vitals); + +true \ No newline at end of file diff --git a/addons/vitals/functions/fnc_handleTemperatureFunction.sqf b/addons/vitals/functions/fnc_handleTemperatureFunction.sqf new file mode 100644 index 000000000..3fe2131af --- /dev/null +++ b/addons/vitals/functions/fnc_handleTemperatureFunction.sqf @@ -0,0 +1,35 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Update the temperature of the patient + * + * Arguments: + * 0: The Unit + * 1: Temperature Adjustments + * 2: Blood Volume + * 3: Time since last update + * 4: Sync value? + * + * ReturnValue: + * Current Temperature + * + * Example: + * [player, 0, 6, 1, false] call kat_vitals_fnc_handleTemperatureFunction; + * + * Public: No + */ + +params ["_unit", "_altitudeAdjustment", "_bloodVolume", "_deltaT", "_syncValue"]; + +private _positionTemperature = EGVAR(hypothermia,positionTemperature); +_positionTemperature params ["_lattitude", "_projectedTemperature"]; + +// Diurnal Width increases as lattitudes increase, generally +private _mapTemperature = _projectedTemperature - ((linearConversion [0, 90, _lattitude, 15, 5, true]) * (linearConversion [0, 1, sunOrMoon, 1, 0, true])); + +private _warmingImpact = (_unit getVariable [QEGVAR(hypothermia,warmingImpact), 0]) / ML_TO_LITERS; +private _currentTemperature = DEFAULT_TEMPERATURE min ((-3.5 * (0.95 ^ _mapTemperature + _altitudeAdjustment) + (((_bloodVolume + 0.01) / 6) * (60 + (_warmingImpact * 60))))); + +_unit setVariable [QEGVAR(hypothermia,unitTemperature), _currentTemperature, _syncValue]; + +_currentTemperature \ No newline at end of file diff --git a/addons/vitals/functions/fnc_handleUnitVitals.sqf b/addons/vitals/functions/fnc_handleUnitVitals.sqf new file mode 100644 index 000000000..0930f0e02 --- /dev/null +++ b/addons/vitals/functions/fnc_handleUnitVitals.sqf @@ -0,0 +1,206 @@ +#include "..\script_component.hpp" +/* + * Author: Glowbal, Mazinski + * Updates the vitals. Called from the statemachine's onState functions. + * + * Arguments: + * 0: The Unit + * + * Return Value: + * Update Ran (at least 1 second between runs) + * + * Example: + * [player] call ace_medical_vitals_fnc_handleUnitVitals + * + * Public: No + */ + +params ["_unit"]; + +if (!(isPlayer _unit) && (_unit getVariable [QEGVAR(circulation,simpleMedical), false])) exitWith { [_unit] call FUNC(handleSimpleVitals) }; + +private _lastTimeUpdated = _unit getVariable [QACEGVAR(medical_vitals,lastTimeUpdated), 0]; +private _deltaT = (CBA_missionTime - _lastTimeUpdated) min 10; +if (_deltaT < 1) exitWith { false }; // state machines could be calling this very rapidly depending on number of local units + +BEGIN_COUNTER(Vitals); + +_unit setVariable [QACEGVAR(medical_vitals,lastTimeUpdated), CBA_missionTime]; +private _lastTimeValuesSynced = _unit getVariable [QACEGVAR(medical_vitals,lastMomentValuesSynced), 0]; +private _syncValues = (CBA_missionTime - _lastTimeValuesSynced) >= (10 + floor(random 10)); + +if (_syncValues) then { + _unit setVariable [QACEGVAR(medical_vitals,lastMomentValuesSynced), CBA_missionTime]; +}; + +//Get Blood Volume from previous cycle +private _bloodVolume = ([_unit, _deltaT, _syncValues] call EFUNC(pharma,getBloodVolumeChange)); +_unit setVariable [VAR_BLOOD_VOL, _bloodVolume, _syncValues]; + +private _temperature = 37; +private _baroPressure = 760; + +if (EGVAR(hypothermia,hypothermiaActive)) then { + // Enviromental Impact (Altitude, Temperature, Pressure) + private _altitude = (getPosASL _unit) select 2; + private _altitudeTempImpact = switch (true) do { + case (_altitude >= 10): { abs(_altitude/153) * -1 }; //For every 1000 meters of elevation gain, temperature decreases by ~6.5 degrees celsius + case (_altitude <= -1): { -35 max((abs(_altitude/50) * -1) - 17) }; //Average water temperature is 20 degrees celsius. Decreases to 2 degrees celsius at 1000 meters + default { 0 }; + }; + + _baroPressure = 760 * exp((-(_altitude)) / 8400); + _temperature = [_unit, _altitudeTempImpact, _bloodVolume, _deltaT, _syncValues] call FUNC(handleTemperatureFunction); +}; + +// 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 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; + +if (_tourniquetPain > 0) then { + [_unit, _tourniquetPain] call ACEFUNC(medical_status,adjustPainLevel); +}; + +// Get Medication Adjustments: +private _hrTargetAdjustment = 0; +private _painSupressAdjustment = 0; +private _peripheralResistanceAdjustment = 0; +private _alphaFactorAdjustment = 0; +private _adjustments = _unit getVariable [VAR_MEDICATIONS,[]]; + +if !(_adjustments isEqualTo []) then { + private _deleted = false; + { + _x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust", "_alphaFactor"]; + 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; }; + if (_flowAdjust != 0) then { _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; }; + if (_alphaFactor != 0) then { _alphaFactorAdjustment = _alphaFactorAdjustment + _alphaFactor * _effectRatio; }; + }; + } forEach _adjustments; + + if (_deleted) then { + _unit setVariable [VAR_MEDICATIONS, _adjustments - [objNull], true]; + _syncValues = true; + }; +}; + +[_unit, _painSupressAdjustment, _deltaT, _syncValues] call ACEFUNC(medical_vitals,updatePainSuppress); //Leave alone +[_unit, _peripheralResistanceAdjustment, _deltaT, _syncValues] call ACEFUNC(medical_vitals,updatePeripheralResistance); + +private _heartRate = [_unit, _hrTargetAdjustment, 0, _bloodVolume, _deltaT, _syncValues] call FUNC(handleCardiacFunction); + +private _spo2 = 97; +if (EGVAR(breathing,enable)) then { + // Additional variables for Respiration functions + private _bloodGas = GET_BLOOD_GAS(_unit); + private _opioidDepression = (GET_OPIOID_FACTOR(_unit) - 1); + private _anerobicPressure = (DEFAULT_ANEROBIC_EXCHANGE * (6 / _bloodVolume) - 0) min 1.2; + + _spo2 = [_unit, _heartRate, _anerobicPressure, _bloodGas, _temperature, _baroPressure, _opioidDepression, _deltaT, _syncValues] call FUNC(handleOxygenFunction); +}; + +// Systolic Blood Pressure from Blood Volume with postive Heart Rate impacts capped by Blood Volume, Diastolic Blood Pressure from Vasoconstriction and Systolic BP +private _vasoconstriction = GET_VASOCONSTRICTION(_unit); + +private _bloodPressureSystolic = (_bloodVolume * 20) * ((_unit getVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES]) / 100) + ((_heartRate - DEFAULT_HEART_RATE) - (((5.5 - _bloodVolume) max 0) * 30)); +private _bloodPressureDiastolic = ((_bloodVolume * 13.33) * ((_unit getVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES]) / 100) + ((_vasoconstriction - 1) * 40)) min (_bloodPressureSystolic - 5); + +// Vasoconstriction from Diastolic Blood Pressure and Alpha Adjustment +_vasoconstriction = switch (true) do { + case (_bloodPressureDiastolic <= 40): { 1.5 + _alphaFactorAdjustment }; + case (_bloodPressureDiastolic >= 120): { 0.5 + _alphaFactorAdjustment }; + default { (1.5 - (_bloodPressureDiastolic - 40) * (1 / 80)) + _alphaFactorAdjustment }; +}; + +_unit setVariable [VAR_VASOCONSTRICTION, (1.8 min (0.2 max _vasoconstriction)), _syncValues]; + +// Pull wound blood loss after recalculating vasoconstriction +private _woundBloodLoss = GET_WOUND_BLEEDING(_unit); + +private _bloodPressure = [round(_bloodPressureDiastolic), round(_bloodPressureSystolic)]; +_unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues]; + +_bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; + +// Statements are ordered by most lethal first. +// Add SpO2 reactions to switch statement --------------------------------------------------------------------- + switch (true) do { + case (_spo2 < EGVAR(breathing,SpO2_dieValue) && EGVAR(breathing,SpO2_dieActive)): { + TRACE_3("O2 Fatal",_unit,EGVAR(breathing,SpO2_dieValue),_spo2); + [QACEGVAR(medical,FatalInjury), _unit] call CBA_fnc_localEvent; + }; + case (_bloodVolume < BLOOD_VOLUME_FATAL): { + TRACE_3("BloodVolume Fatal",_unit,BLOOD_VOLUME_FATAL,_bloodVolume); + [QACEGVAR(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 (_spo2 < EGVAR(breathing,SpO2_cardiacValue) && EGVAR(breathing,SpO2_cardiacActive)): { + [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_hemorrhage == 4): { + TRACE_3("Class IV Hemorrhage",_unit,_hemorrhage,_bloodVolume); + [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_heartRate < 20 || {_heartRate > 220}): { + TRACE_2("heartRate Fatal",_unit,_heartRate); + [QACEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_bloodPressureL < 20 || {_bloodPressureL > 180}): { + TRACE_2("bloodPressure L above or below limits",_unit,_bloodPressureL); + [QACEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_spo2 < EGVAR(breathing,SpO2_unconscious)): { + [QACEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_woundBloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD): { + [QACEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; + }; + case (_woundBloodLoss > 0): { + [QACEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent; + }; + case (_inPain): { + [QACEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent; + }; +}; + +#ifdef DEBUG_MODE_FULL +private _cardiacOutput = [_unit] call ACEFUNC(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); + +true diff --git a/addons/misc/functions/fnc_hasStableVitals.sqf b/addons/vitals/functions/fnc_hasStableVitals.sqf similarity index 91% rename from addons/misc/functions/fnc_hasStableVitals.sqf rename to addons/vitals/functions/fnc_hasStableVitals.sqf index f761a38cc..2705db788 100644 --- a/addons/misc/functions/fnc_hasStableVitals.sqf +++ b/addons/vitals/functions/fnc_hasStableVitals.sqf @@ -17,7 +17,7 @@ params ["_unit"]; -private _bloodVolume = GET_BLOOD_VOLUME(_unit); +private _bloodVolume = GET_BLOOD_VOLUME_LITERS(_unit); if (_bloodVolume < ACEGVAR(medical,const_stableVitalsBloodThreshold)) exitWith { false }; if IN_CRDC_ARRST(_unit) exitWith { false }; @@ -35,7 +35,7 @@ if (_bloodPressureL < 50 || {_bloodPressureH < 60}) exitWith { false }; private _heartRate = GET_HEART_RATE(_unit); if (_heartRate < 40) exitWith { false }; -private _o2 = _unit getVariable [QEGVAR(breathing,airwayStatus), 100]; +private _o2 = GET_SPO2(_unit); if (_o2 < EGVAR(breathing,Stable_spo2)) exitWith { false }; true diff --git a/addons/vitals/functions/fnc_init.sqf b/addons/vitals/functions/fnc_init.sqf new file mode 100644 index 000000000..3679e66e3 --- /dev/null +++ b/addons/vitals/functions/fnc_init.sqf @@ -0,0 +1,20 @@ +#include "..\script_component.hpp" +/* + * Author: Mazinski + * Initializes unit variables. + * + * Arguments: + * 0: Patient + * + * Return Value: + * None + * + * Example: + * [player] call kat_vitals_fnc_init + * + * Public: No + */ + +params ["_patient"]; + +if (!(isPlayer _unit) && GVAR(simpleMedical)) then { _patient setVariable [QGVAR(simpleMedical), true, true] }; \ No newline at end of file diff --git a/addons/vitals/script_component.hpp b/addons/vitals/script_component.hpp new file mode 100644 index 000000000..2fbccf669 --- /dev/null +++ b/addons/vitals/script_component.hpp @@ -0,0 +1,17 @@ +#define COMPONENT vitals +#define COMPONENT_BEAUTIFIED KAT - Vitals +#include "\x\kat\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_VITALS + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_VITALS + #define DEBUG_SETTINGS DEBUG_SETTINGS_VITALS +#endif + +#include "\x\kat\addons\main\script_macros.hpp" diff --git a/addons/vitals/stringtable.xml b/addons/vitals/stringtable.xml new file mode 100644 index 000000000..9524c3b2a --- /dev/null +++ b/addons/vitals/stringtable.xml @@ -0,0 +1,8 @@ + + + + + Activate AI Simple Medical + + + diff --git a/addons/zeus/functions/fnc_ui_changeBloodType.sqf b/addons/zeus/functions/fnc_ui_changeBloodType.sqf index 46b1f55ce..3d9a87240 100644 --- a/addons/zeus/functions/fnc_ui_changeBloodType.sqf +++ b/addons/zeus/functions/fnc_ui_changeBloodType.sqf @@ -56,14 +56,14 @@ private _fnc_sliderMove = { private _idc = ctrlIDC _slider; private _logic = GETMVAR(BIS_fnc_initCuratorAttributes_target,objNull); private _unit = attachedTo _logic; - private _curVal = _unit getVariable [QACEGVAR(medical,bloodvolume), 6.0]; + private _curVal = GET_BLOOD_VOLUME_LITERS(_unit); _slider ctrlSetTooltip format [LLSTRING(sliderFormat13was23), parseNumber((sliderPosition _slider) toFixed 2), (parseNumber (_curVal toFixed 2)), "L"]; }; private _slider = _display displayCtrl 26423; _slider sliderSetRange [0, 6]; _slider sliderSetSpeed [1,0.5]; -private _curBloodVol = _unit getVariable [QACEGVAR(medical,bloodvolume), 6.0]; +private _curBloodVol = GET_BLOOD_VOLUME_LITERS(_unit); _slider sliderSetPosition (parseNumber (_curBloodVol toFixed 2)); _slider ctrlAddEventHandler ["SliderPosChanged", _fnc_sliderMove]; [_slider,_curBloodVol] call _fnc_sliderMove; @@ -113,9 +113,10 @@ private _fnc_onConfirm = { _dogtagData set [1, _bloodtype]; }; - private _curBloodVol = _unit getVariable [QACEGVAR(medical,bloodvolume), 6.0]; + private _curBloodVol = GET_BLOOD_VOLUME_LITERS(_unit); private _sliderValue = sliderPosition (_display displayCtrl 26423); - _unit setVariable [QACEGVAR(medical,bloodvolume), ( parseNumber (_sliderValue toFixed 2)), true]; + _sliderValue = parseNumber (_sliderValue toFixed 2); + REDUCE_TOTAL_BLOOD_VOLUME(_unit,_sliderVolume); }; _display displayAddEventHandler ["Unload", _fnc_onUnload]; diff --git a/addons/zeus/functions/fnc_ui_manageAirway.sqf b/addons/zeus/functions/fnc_ui_manageAirway.sqf index 9fa82b5c5..7e187cdfe 100644 --- a/addons/zeus/functions/fnc_ui_manageAirway.sqf +++ b/addons/zeus/functions/fnc_ui_manageAirway.sqf @@ -56,7 +56,7 @@ private _fnc_sliderMove_ptx = { private _logic = GETMVAR(BIS_fnc_initCuratorAttributes_target,objNull); private _unit = attachedTo _logic; private _curVal = _unit getVariable [QEGVAR(breathing,pneumothorax), 0]; - _slider ctrlSetTooltip format [LLSTRING(sliderFormat13was23), round(sliderPosition _slider), round _curVal]; + _slider ctrlSetTooltip format [LLSTRING(sliderFormat13was23), round(sliderPosition _slider), round _curVal, " "]; }; private _sliderPTX = _display displayCtrl 16105; @@ -72,14 +72,14 @@ private _fnc_sliderMove_SPO2 = { private _idc = ctrlIDC _slider; private _logic = GETMVAR(BIS_fnc_initCuratorAttributes_target,objNull); private _unit = attachedTo _logic; - private _curVal = _unit getVariable [QEGVAR(breathing,airwayStatus), 50]; + private _curVal = GET_PAO2(_unit); _slider ctrlSetTooltip format [LLSTRING(sliderFormat13was23), round(sliderPosition _slider), round _curVal, "%"]; }; private _sliderSPO2 = _display displayCtrl 16106; _sliderSPO2 sliderSetRange [0, 100]; _sliderSPO2 sliderSetSpeed [1,10]; -private _curSpO2Val = _unit getVariable [QEGVAR(breathing,airwayStatus), 50]; +private _curSpO2Val = GET_PAO2(_unit); _sliderSPO2 sliderSetPosition (round _curSpO2Val); _sliderSPO2 ctrlAddEventHandler ["SliderPosChanged", _fnc_sliderMove_SPO2]; [_sliderSPO2,_curSpO2Val] call _fnc_sliderMove_SPO2; @@ -118,17 +118,15 @@ private _fnc_onConfirm = { _unit setVariable [_x, _targetState, true]; } forEach [QEGVAR(airway,obstruction), QEGVAR(airway,occluded), QEGVAR(breathing,hemopneumothorax), QEGVAR(breathing,tensionpneumothorax)]; - - private _curSpO2Val = _unit getVariable [QEGVAR(breathing,airwayStatus), 50]; - + + private _curSpO2Val = GET_PAO2(_unit); private _pneumothorax = round(sliderPosition (_display displayCtrl 16105)); _unit setVariable [QEGVAR(breathing,pneumothorax), _pneumothorax, true]; - _unit setVariable [QEGVAR(breathing,airwayStatus), round(sliderPosition (_display displayCtrl 16106)), true]; + private _o2Sat = round(sliderPosition (_display displayCtrl 16106)); - if (_curSpO2Val isEqualTo 100 || _initBreathing) then { - [_unit] call EFUNC(breathing,handleBreathing); - }; + private _bloodGas = GET_BLOOD_GAS(_unit); + _unit setVariable [QEGVAR(circulation,bloodGas),[_bloodGas select 0, _o2Sat, _bloodGas select 2, _bloodGas select 3, _bloodGas select 4], true]; if (_pneumothorax isEqualTo 0 && !(_valueArr select 2) && !(_valueArr select 3)) then { [_unit, 0, 0, "ptx_tension", true] call EFUNC(circulation,updateBloodPressureChange); diff --git a/addons/zeus/script_component.hpp b/addons/zeus/script_component.hpp index 7102ee07f..9e920b86a 100644 --- a/addons/zeus/script_component.hpp +++ b/addons/zeus/script_component.hpp @@ -22,4 +22,4 @@ #define W_PART(num) (num * (SIZEX / 40)) #define H_PART(num) (num * (SIZEY / 25)) #define X_PART(num) (W_PART(num) + (safeZoneX + (safeZoneW - SIZEX) / 2)) -#define Y_PART(num) (H_PART(num) + (safeZoneY + (safeZoneH - SIZEY) / 2)) +#define Y_PART(num) (H_PART(num) + (safeZoneY + (safeZoneH - SIZEY) / 2)) \ No newline at end of file