Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Medical AI - Give blood in Cardiac Arrest before doing CPR #10154

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 76 additions & 17 deletions addons/medical_ai/functions/fnc_healingLogic.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,23 @@ if (_finishTime > 0) exitWith {
};
if ((_treatmentTarget == _target) && {(_treatmentEvent select [0, 1]) != "#"}) then {
[_treatmentEvent, _treatmentArgs, _target] call CBA_fnc_targetEvent;

// Splints are already logged on their own
switch (_treatmentEvent) do {
case QEGVAR(medical_treatment,bandageLocal): {
[_target, "activity", ELSTRING(medical_treatment,Activity_bandagedPatient), [[_healer, false, true] call EFUNC(common,getName)]] call EFUNC(medical_treatment,addToLog);
};
case QEGVAR(medical_treatment,ivBagLocal): {
[_target, _treatmentArgs select 2] call EFUNC(medical_treatment,addToTriageCard);
[_target, "activity", ELSTRING(medical_treatment,Activity_gaveIV), [[_healer, false, true] call EFUNC(common,getName)]] call EFUNC(medical_treatment,addToLog);
};
case QEGVAR(medical_treatment,medicationLocal): {
private _usedItem = ["ACE_epinephrine", "ACE_morphine"] select (_treatmentArgs select 2 == "Morphine");
[_target, _usedItem] call EFUNC(medical_treatment,addToTriageCard);
[_target, "activity", ELSTRING(medical_treatment,Activity_usedItem), [[_healer, false, true] call EFUNC(common,getName), getText (configFile >> "CfgWeapons" >> _usedItem >> "displayName")]] call EFUNC(medical_treatment,addToLog);
};
};

#ifdef DEBUG_MODE_FULL
INFO_4("%1->%2: %3 - %4",_healer,_target,_treatmentEvent,_treatmentArgs);
systemChat format ["Applying [%1->%2]: %3", _healer, _treatmentTarget, _treatmentEvent];
Expand Down Expand Up @@ -75,9 +92,12 @@ private _treatmentEvent = "#none";
private _treatmentArgs = [];
private _treatmentTime = 6;
private _treatmentItem = "";
switch (true) do {
case ((GET_WOUND_BLEEDING(_target) > 0)
&& {([_healer, "@bandage"] call FUNC(itemCheck)) # 0}): {

if (true) then {
if (
(GET_WOUND_BLEEDING(_target) > 0) &&
{([_healer, "@bandage"] call FUNC(itemCheck)) # 0}
) exitWith {
// Select first bleeding wound and bandage it
private _selection = "?";
{
Expand All @@ -94,47 +114,82 @@ switch (true) do {
_treatmentArgs = [_target, _selection, "FieldDressing"];
_treatmentItem = "@bandage";
};
case (IN_CRDC_ARRST(_target) && {EGVAR(medical_treatment,cprSuccessChanceMin) > 0}): {

private _hasIV = ([_healer, "@iv"] call FUNC(itemCheck)) # 0;
private _bloodVolume = GET_BLOOD_VOLUME(_target);

// If in cardiac arrest, first add some blood to injured if necessary, then do CPR (doing CPR when not enough blood is suboptimal if you have IVs)
// If healer has no IVs, allow AI to do CPR to keep injured alive
if (
IN_CRDC_ARRST(_target) &&
{EGVAR(medical_treatment,cprSuccessChanceMin) > 0} &&
{!_hasIV || {_bloodVolume >= BLOOD_VOLUME_CLASS_3_HEMORRHAGE}}
) exitWith {
_treatmentEvent = QEGVAR(medical_treatment,cprLocal);
_treatmentArgs = [_healer, _target];
_treatmentTime = 15;
};
case (_isMedic && {GET_BLOOD_VOLUME(_target) < MINIMUM_BLOOD_FOR_STABLE_VITALS}
&& {([_healer, "@iv"] call FUNC(itemCheck)) # 0}): {

private _needsIv = _bloodVolume < MINIMUM_BLOOD_FOR_STABLE_VITALS;
private _canGiveIv = _isMedic && _hasIV && _needsIv;

if (_canGiveIv) then {
// Check if patient's blood volume + remaining IV volume is enough to allow the patient to wake up
private _totalIvVolume = 0; //in ml
{
_x params ["_volumeRemaining"];
_totalIvVolume = _totalIvVolume + _volumeRemaining;
} forEach (_target getVariable [QEGVAR(medical,ivBags), []]);

if (GET_BLOOD_VOLUME(_target) + (_totalIvVolume / 1000) > MINIMUM_BLOOD_FOR_STABLE_VITALS) exitWith {
_treatmentEvent = "#waitForBlood";
// Check if the medic has to wait, which allows for a little multitasking
if (_bloodVolume + (_totalIvVolume / 1000) >= MINIMUM_BLOOD_FOR_STABLE_VITALS) then {
_treatmentEvent = "#waitForIV";
_canGiveIv = false;
};
};

if (_canGiveIv) exitWith {
_treatmentEvent = QEGVAR(medical_treatment,ivBagLocal);
_treatmentTime = 5;
_treatmentArgs = [_target, call _fnc_findNoTourniquet, "SalineIV"];
_treatmentItem = "@iv";
};
case (((_fractures select 4) == 1)
&& {([_healer, "splint"] call FUNC(itemCheck)) # 0}): {

if (
((_fractures select 4) == 1) &&
{([_healer, "splint"] call FUNC(itemCheck)) # 0}
) exitWith {
_treatmentEvent = QEGVAR(medical_treatment,splintLocal);
_treatmentTime = 6;
_treatmentArgs = [_healer, _target, "leftleg"];
_treatmentItem = "splint";
};
case (((_fractures select 5) == 1)
&& {([_healer, "splint"] call FUNC(itemCheck)) # 0}): {

if (
((_fractures select 5) == 1) &&
{([_healer, "splint"] call FUNC(itemCheck)) # 0}
) exitWith {
_treatmentEvent = QEGVAR(medical_treatment,splintLocal);
_treatmentTime = 6;
_treatmentArgs = [_healer, _target, "rightleg"];
_treatmentItem = "splint";
};
case ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6): {

// Wait until the injured has enough blood before administering drugs
if (_needsIv) then {
_treatmentEvent = "#waitForIV"
};

if (_treatmentEvent == "#waitForIV") exitWith {};

if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) exitWith {
_treatmentEvent = "#tooManyMeds";
};
case ((IS_UNCONSCIOUS(_target) || {_heartRate <= 50})
&& {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}): {

if (
((IS_UNCONSCIOUS(_target) && {_heartRate < 160}) || {_heartRate <= 50}) &&
{([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}
) exitWith {
if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith {
_treatmentEvent = "#waitForEpinephrineToTakeEffect";
};
Expand All @@ -147,8 +202,11 @@ switch (true) do {
_treatmentArgs = [_target, call _fnc_findNoTourniquet, "Epinephrine"];
_treatmentItem = "epinephrine";
};
case (((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180})
&& {([_healer, "morphine"] call FUNC(itemCheck)) # 0}): {

if (
(((GET_PAIN_PERCEIVED(_target) > 0.25) && {_heartRate > 40}) || {_heartRate >= 180}) &&
{([_healer, "morphine"] call FUNC(itemCheck)) # 0}
) exitWith {
if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith {
_treatmentEvent = "#waitForMorphineToTakeEffect";
};
Expand All @@ -169,6 +227,7 @@ _healer setVariable [QGVAR(currentTreatment), [CBA_missionTime + _treatmentTime,
if ((_treatmentEvent select [0,1]) != "#") then {
private _treatmentClassname = _treatmentArgs select 2;
if (_treatmentEvent == QEGVAR(medical_treatment,splintLocal)) then { _treatmentClassname = "Splint" };
if (_treatmentEvent == QEGVAR(medical_treatment,cprLocal)) then { _treatmentClassname = "CPR" };
[_healer, _treatmentClassname, (_healer == _target)] call FUNC(playTreatmentAnim);
};

Expand Down
2 changes: 1 addition & 1 deletion addons/medical_ai/functions/fnc_playTreatmentAnim.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* None
*
* Example:
* [cursorObject, true, true] call ace_medical_ai_fnc_playTreatmentAnim
* [cursorObject, "Splint", true] call ace_medical_ai_fnc_playTreatmentAnim
*
* Public: No
*/
Expand Down
7 changes: 5 additions & 2 deletions addons/medical_ai/functions/fnc_requestMedic.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

private _assignedMedic = _this getVariable QGVAR(assignedMedic);
private _healQueue = _assignedMedic getVariable [QGVAR(healQueue), []];
_healQueue pushBack _this;
_assignedMedic setVariable [QGVAR(healQueue), _healQueue];

// Only update if it was actually changed
if (_healQueue pushBackUnique _this != -1) then {
_assignedMedic setVariable [QGVAR(healQueue), _healQueue];
};

#ifdef DEBUG_MODE_FULL
systemChat format ["%1 requested %2 for medical treatment", _this, _assignedMedic];
Expand Down
9 changes: 2 additions & 7 deletions addons/medical_ai/stateMachine.inc.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,8 @@ GVAR(stateMachine) = [{call EFUNC(common,getLocalUnits)}, true] call CBA_statema
#endif
}, {}, {}, "Safe"] call CBA_statemachine_fnc_addState;

[GVAR(stateMachine), LINKFUNC(healSelf), {}, {
_this setVariable [QGVAR(treatmentOverAt), nil];
}, "HealSelf"] call CBA_statemachine_fnc_addState;

[GVAR(stateMachine), LINKFUNC(healUnit), {}, {
_this setVariable [QGVAR(treatmentOverAt), nil];
}, "HealUnit"] call CBA_statemachine_fnc_addState;
[GVAR(stateMachine), LINKFUNC(healSelf), {}, {}, "HealSelf"] call CBA_statemachine_fnc_addState;
[GVAR(stateMachine), LINKFUNC(healUnit), {}, {}, "HealUnit"] call CBA_statemachine_fnc_addState;

// Add Transistions [statemachine, originalState, targetState, condition, onTransition, name]
[GVAR(stateMachine), "Initial", "Injured", LINKFUNC(isInjured), {}, "Injured"] call CBA_statemachine_fnc_addTransition;
Expand Down