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 - Improve tourniquet removal (for #10166) #10178

Merged
merged 5 commits into from
Aug 10, 2024
Merged
Changes from 1 commit
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
100 changes: 47 additions & 53 deletions addons/medical_ai/functions/fnc_healingLogic.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -88,32 +88,35 @@ if (_finishTime > 0) exitWith {

// Find a suitable limb (no tourniquets) for injecting and giving IVs
private _fnc_findNoTourniquet = {
params ["_removeAllTourniquets"];

// Ignore head & torso if not removing all tourniquets (= administering drugs/IVs)
private _offset = [2, 0] select _removeAllTourniquets;
private _bodyPart = "";

// If all limbs have tourniquets, find the least damaged limb and try to bandage it
if ((_tourniquets select [2]) find 0 == -1) then {
// If no bandages available, wait
if !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith {
_treatmentEvent = "#waitForNonTourniquetedLimb"; // TODO: Medic can move onto another patient/should be flagged as out of supplies
};

if (_removeAllTourniquets || {(_tourniquets select [2]) find 0 == -1}) then {
// Bandage the least bleeding body part
private _bodyPartBleeding = [0, 0, 0, 0];
private _bodyPartBleeding = [];
_bodyPartBleeding resize [[4, 6] select _removeAllTourniquets, -1];

{
// Ignore head and torso
private _partIndex = (ALL_BODY_PARTS find _x) - 2;
// Ignore head and torso, if only looking for place to administer drugs/IVs
private _partIndex = (ALL_BODY_PARTS find _x) - _offset;

if (_partIndex >= 0) then {
if (_partIndex >= 0 && {_tourniquets select _partIndex != 0}) then {
{
_x params ["", "_amountOf", "_bleeding"];
_bodyPartBleeding set [_partIndex, (_bodyPartBleeding select _partIndex) + (_amountOf * _bleeding)];

// max 0, to set the baseline to 0, as body parts with no wounds are marked with -1
_bodyPartBleeding set [_partIndex, ((_bodyPartBleeding select _partIndex) max 0) + (_amountOf * _bleeding)];
} forEach _y;
};
} forEach GET_OPEN_WOUNDS(_target);

private _minBodyPartBleeding = selectMin _bodyPartBleeding;
private _selection = ALL_BODY_PARTS select ((_bodyPartBleeding find _minBodyPartBleeding) + 2);
// Ignore body parts that don't have open wounds (-1)
private _minBodyPartBleeding = selectMin (_bodyPartBleeding select {_x != -1});
private _selection = ALL_BODY_PARTS select ((_bodyPartBleeding find _minBodyPartBleeding) + _offset);

// If not bleeding anymore, remove the tourniquet
if (_minBodyPartBleeding == 0) exitWith {
Expand All @@ -122,6 +125,12 @@ private _fnc_findNoTourniquet = {
_treatmentArgs = [_healer, _target, _selection];
};

// 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 !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith {
_treatmentEvent = "#waitForBandages"; // TODO: Medic can move onto another patient/should be flagged as out of supplies
};

// Otherwise keep bandaging
_treatmentEvent = QEGVAR(medical_treatment,bandageLocal);
_treatmentTime = 5;
Expand Down Expand Up @@ -217,7 +226,7 @@ if (true) then {
if (
_canGiveIV && {
// If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed
_bodyPart = call _fnc_findNoTourniquet;
_bodyPart = false call _fnc_findNoTourniquet;
_bodyPart == ""
}
) exitWith {};
Expand Down Expand Up @@ -269,7 +278,7 @@ if (true) then {

// Wait until the injured has enough blood before administering drugs
// (_needsIV && !_canGiveIV), but _canGiveIV is false here, otherwise IV would be given
if (_needsIV || {_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 (_doCPR) exitWith {
_treatmentEvent = QEGVAR(medical_treatment,cprLocal); // TODO: Medic remains in this loop until injured is given enough IVs or dies
Expand All @@ -283,25 +292,32 @@ if (true) then {
};
};

if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) exitWith {
// 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 {
_treatmentEvent = "#tooManyMeds"; // TODO: Medic can move onto another patient
};

private _heartRate = GET_HEART_RATE(_target);
private _canGiveEpinephrine = !(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) &&
{IS_UNCONSCIOUS(_target) || {_heartRate <= 50}} &&
{([_healer, "epinephrine"] call FUNC(itemCheck)) # 0};

if (
(IS_UNCONSCIOUS(_target) || {_heartRate <= 50}) &&
{([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}
) exitWith {
if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith {
// This allows for some multitasking
if (_canGiveEpinephrine) then {
if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) then {
_treatmentEvent = "#waitForEpinephrineToTakeEffect";
_canGiveEpinephrine = false;
};
if (_heartRate > 180) exitWith {

if (_heartRate > 180) then {
_treatmentEvent = "#waitForSlowerHeart"; // TODO: Medic can move onto another patient, after X amount of time of high HR
_canGiveEpinephrine = false;
};
};

if (_canGiveEpinephrine) exitWith {
// If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed
_bodyPart = call _fnc_findNoTourniquet;
_bodyPart = false call _fnc_findNoTourniquet;

if (_bodyPart == "") exitWith {};

Expand All @@ -312,8 +328,14 @@ if (true) then {
_treatmentItem = "epinephrine";
};

// Remove all remaining tourniquets by bandaging all body parts
if (_tourniquets isNotEqualTo DEFAULT_TOURNIQUET_VALUES) exitWith {
true call _fnc_findNoTourniquet;
};

if (
((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}) &&
!(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) &&
{(GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}} &&
{([_healer, "morphine"] call FUNC(itemCheck)) # 0}
) exitWith {
if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith {
Expand All @@ -324,7 +346,7 @@ if (true) then {
};

// If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed
_bodyPart = call _fnc_findNoTourniquet;
_bodyPart = false call _fnc_findNoTourniquet;
PabstMirror marked this conversation as resolved.
Show resolved Hide resolved

if (_bodyPart == "") exitWith {};

Expand All @@ -334,34 +356,6 @@ if (true) then {
_treatmentArgs = [_target, _bodyPart, "Morphine"];
_treatmentItem = "morphine";
};
if (_tourniquets isNotEqualTo DEFAULT_TOURNIQUET_VALUES) exitWith {
// Check if we have wounds that would bleed
private _bleedingSelection = "";
{
private _selection = _x;
{
_x params ["", "_amountOf", "_bleeding"];
if ((_amountOf * _bleeding) > 0) exitWith { _bleedingSelection = _selection; };
} forEach _y;
} forEach GET_OPEN_WOUNDS(_target);

// Bandage before removing tourniquet
if (_bleedingSelection != "") exitWith {
private _hasBandage = ([_healer, "@bandage"] call FUNC(itemCheck)) # 0;
if (!_hasBandage) exitWith {
_treatmentEvent = "#waitForBandages"; // TODO: Medic can move onto another patient/should be flagged as out of supplies
};
_treatmentEvent = QEGVAR(medical_treatment,bandageLocal);
_treatmentTime = 5;
_treatmentArgs = [_target, _bleedingSelection, "FieldDressing"];
_treatmentItem = "@bandage";
};

private _tourniquetIndex = _tourniquets findIf { _x != 0 };
_treatmentEvent = QGVAR(tourniquetRemove);
_treatmentTime = 7;
_treatmentArgs = [_healer, _target, ALL_BODY_PARTS select _tourniquetIndex];
};
};

_healer setVariable [QGVAR(currentTreatment), [CBA_missionTime + _treatmentTime, _target, _treatmentEvent, _treatmentArgs, _treatmentItem]];
Expand Down