Medical AI - Prevent medics from being blocked on treatments they can't complete (#10167)

* Add tourniquet support for Medical AI

* Stop blocking start

* Renamed states, condensed `canHeal`

* Renamed `tooManyMeds` state

* Update addons/medical_ai/functions/fnc_healUnit.sqf

Co-authored-by: PabstMirror <pabstmirror@gmail.com>

* Change states to use singular, add states for autoinjectors & splint

---------

Co-authored-by: PabstMirror <pabstmirror@gmail.com>
This commit is contained in:
johnb432 2024-08-11 17:06:59 +02:00 committed by GitHub
parent 0b4029b12f
commit ff31bc69a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 27 deletions

View File

@ -27,7 +27,13 @@ private _healQueue = _this getVariable [QGVAR(healQueue), []];
private _target = _healQueue param [0, objNull]; private _target = _healQueue param [0, objNull];
// If unit died or was healed, be lazy and wait for the next tick // If unit died or was healed, be lazy and wait for the next tick
if (!alive _target || {!(_target call FUNC(isInjured))}) exitWith { // If the unit can't be healed, go to the next unit to be healed
if (!alive _target || {!(_target call FUNC(isInjured))} || {
private _treatmentEvent = (_this getVariable [QGVAR(currentTreatment), []]) param [2, ""];
// Target still needs healing, but the healer doesn't have the required items (only happens if GVAR(requireItems) != 0) or needs to wait
(_treatmentEvent select [0, 6]) == "#needs"
}) exitWith {
_this forceSpeed -1; _this forceSpeed -1;
_target forceSpeed -1; _target forceSpeed -1;
_healQueue deleteAt 0; _healQueue deleteAt 0;

View File

@ -1,7 +1,9 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: BaerMitUmlaut, PabstMirror * Author: BaerMitUmlaut, PabstMirror, johnb43
* Applies healing to target. * Applies healing to target.
* States that contain "needs" are states in which the medic is blocked, either temporairly (HR too high/low) or until resupplied, from treating.
* States that contain "wait" are states where the medic waits temporairly before continuing treatment.
* *
* Arguments: * Arguments:
* 0: Healer <OBJECT> * 0: Healer <OBJECT>
@ -129,7 +131,7 @@ private _fnc_removeTourniquet = {
// If no bandages available, wait // If no bandages available, wait
// If check is done at the start of the scope, it will miss the edge case where the unit ran out of bandages just as they finished bandaging tourniqueted body part // If check is done at the start of the scope, it will miss the edge case where the unit ran out of bandages just as they finished bandaging tourniqueted body part
if !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith { if !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith {
_treatmentEvent = "#waitForBandages"; // TODO: Medic can move onto another patient/should be flagged as out of supplies _treatmentEvent = "#needsBandage";
}; };
// Otherwise keep bandaging // Otherwise keep bandaging
@ -177,7 +179,7 @@ if (true) then {
// Patient is not worth treating if bloodloss can't be stopped // Patient is not worth treating if bloodloss can't be stopped
if !(_hasBandage || _hasTourniquet) exitWith { if !(_hasBandage || _hasTourniquet) exitWith {
_treatmentEvent = "#cantStabilise"; // TODO: Medic should be flagged as out of supplies _treatmentEvent = "#needsBandageOrTourniquet";
}; };
// Bandage the heaviest bleeding body part // Bandage the heaviest bleeding body part
@ -264,25 +266,20 @@ if (true) then {
_treatmentItem = "@iv"; _treatmentItem = "@iv";
}; };
private _fractures = GET_FRACTURES(_target); // Leg fractures
private _index = (GET_FRACTURES(_target) select [4, 2]) find 1;
if ( if (
((_fractures select 4) == 1) && _index != -1 && {
{([_healer, "splint"] call FUNC(itemCheck)) # 0} // In case the unit doesn't have a splint, set state here
_treatmentEvent = "#needsSplint";
([_healer, "splint"] call FUNC(itemCheck)) # 0
}
) exitWith { ) exitWith {
_treatmentEvent = QEGVAR(medical_treatment,splintLocal); _treatmentEvent = QEGVAR(medical_treatment,splintLocal);
_treatmentTime = 6; _treatmentTime = 6;
_treatmentArgs = [_healer, _target, "leftleg"]; _treatmentArgs = [_healer, _target, ALL_BODY_PARTS select (_index + 4)];
_treatmentItem = "splint";
};
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"; _treatmentItem = "splint";
}; };
@ -291,26 +288,32 @@ if (true) then {
if (_needsIV || {_doCPR && {_treatmentEvent == "#waitForIV"}}) exitWith { if (_needsIV || {_doCPR && {_treatmentEvent == "#waitForIV"}}) exitWith {
// If injured is in cardiac arrest and the healer is doing nothing else, start CPR // If injured is in cardiac arrest and the healer is doing nothing else, start CPR
if (_doCPR) exitWith { if (_doCPR) exitWith {
_treatmentEvent = QEGVAR(medical_treatment,cprLocal); // TODO: Medic remains in this loop until injured is given enough IVs or dies // Medic remains in this loop until injured is given enough IVs or dies
_treatmentEvent = QEGVAR(medical_treatment,cprLocal);
_treatmentArgs = [_healer, _target]; _treatmentArgs = [_healer, _target];
_treatmentTime = 15; _treatmentTime = 15;
}; };
// If the injured needs IVs, but healer can't give it to them, have healder wait // If the injured needs IVs, but healer can't give it to them, have healder wait
if (_needsIV) exitWith { if (_needsIV) exitWith {
_treatmentEvent = "#needsIV"; // TODO: Medic can move onto another patient _treatmentEvent = "#needsIV";
}; };
}; };
// These checks are not exitWith, so that the medic can try to bandage up tourniqueted body parts // These checks are not exitWith, so that the medic can try to bandage up tourniqueted body parts
if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) then { if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) then {
_treatmentEvent = "#tooManyMeds"; // TODO: Medic can move onto another patient _treatmentEvent = "#needsFewerMeds";
}; };
private _heartRate = GET_HEART_RATE(_target); private _heartRate = GET_HEART_RATE(_target);
private _canGiveEpinephrine = !(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) && private _canGiveEpinephrine = !(_treatmentEvent in ["#needsFewerMeds", "#waitForIV"]) &&
{IS_UNCONSCIOUS(_target) || {_heartRate <= 50}} && {IS_UNCONSCIOUS(_target) || {_heartRate <= 50}} &&
{([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}; {
// In case the unit doesn't have a epinephrine injector, set state here
_treatmentEvent = "#needsEpinephrine";
([_healer, "epinephrine"] call FUNC(itemCheck)) # 0
};
// This allows for some multitasking // This allows for some multitasking
if (_canGiveEpinephrine) then { if (_canGiveEpinephrine) then {
@ -320,7 +323,7 @@ if (true) then {
}; };
if (_heartRate > 180) then { if (_heartRate > 180) then {
_treatmentEvent = "#waitForSlowerHeart"; // TODO: Medic can move onto another patient, after X amount of time of high HR _treatmentEvent = "#needsSlowerHeart";
_canGiveEpinephrine = false; _canGiveEpinephrine = false;
}; };
}; };
@ -348,15 +351,21 @@ if (true) then {
// Otherwise, if the healer is either done or out of bandages, continue // Otherwise, if the healer is either done or out of bandages, continue
if ( if (
!(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) && !(_treatmentEvent in ["#needsFewerMeds", "#waitForIV"]) &&
{(GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}} && {(GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}} &&
{([_healer, "morphine"] call FUNC(itemCheck)) # 0} {
// In case the unit doesn't have a morphine injector, set state here
_treatmentEvent = "#needsMorphine";
([_healer, "morphine"] call FUNC(itemCheck)) # 0
}
) exitWith { ) exitWith {
if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith {
_treatmentEvent = "#waitForMorphineToTakeEffect"; _treatmentEvent = "#waitForMorphineToTakeEffect";
}; };
if (_heartRate < 60) exitWith { if (_heartRate < 60) exitWith {
_treatmentEvent = "#waitForFasterHeart"; // TODO: Medic can move onto another patient, after X amount of time of low HR _treatmentEvent = "#needsFasterHeart";
}; };
// If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed // If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed