Medical AI - Add setting to require items for treatment (#9362)

* Medical AI - Add setting to require items for treatment

* all ivs

* invert setting

* Update addons/medical_ai/stringtable.xml

Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>

* move item hash to preStart

---------

Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>
This commit is contained in:
PabstMirror 2023-09-06 11:37:26 -05:00 committed by GitHub
parent f75d237d47
commit 25b8fd6d54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 106 additions and 9 deletions

View File

@ -4,6 +4,7 @@ PREP(healSelf);
PREP(healUnit); PREP(healUnit);
PREP(isInjured); PREP(isInjured);
PREP(isSafe); PREP(isSafe);
PREP(itemCheck);
PREP(playTreatmentAnim); PREP(playTreatmentAnim);
PREP(requestMedic); PREP(requestMedic);
PREP(wasRequested); PREP(wasRequested);

View File

@ -20,4 +20,5 @@
}] call CBA_fnc_addClassEventHandler; }] call CBA_fnc_addClassEventHandler;
#include "stateMachine.sqf" #include "stateMachine.sqf"
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;

View File

@ -13,4 +13,6 @@ if (isNil QGVAR(timeSafe_shoot)) then { GVAR(timeSafe_shoot) = 30; };
if (isNil QGVAR(timeSafe_hit)) then { GVAR(timeSafe_hit) = 30; }; if (isNil QGVAR(timeSafe_hit)) then { GVAR(timeSafe_hit) = 30; };
if (isNil QGVAR(timeSafe_suppressed)) then { GVAR(timeSafe_suppressed) = 30; }; if (isNil QGVAR(timeSafe_suppressed)) then { GVAR(timeSafe_suppressed) = 30; };
GVAR(itemHash) = uinamespace getVariable QGVAR(itemHash);
ADDON = true; ADDON = true;

View File

@ -1,3 +1,27 @@
#include "script_component.hpp" #include "script_component.hpp"
#include "XEH_PREP.hpp" #include "XEH_PREP.hpp"
private _itemHash = createHashMap;
// key is Treatment Type (prefix @ represents a group of treatments)
// value is hash of item/treatment pairs
{
_x params ["_itemType", "_treatments"];
private _typeHash = createHashMap;
{
private _items = getArray (configFile >> "ace_medical_treatment_actions" >> _x >> "items");
if (_items isEqualTo []) then { ERROR_1("bad action %1",_x); };
private _itemClassname = configName (configFile >> "CfgWeapons" >> _items # 0);
private _treatment = if ((count _treatments) > 1) then { _x } else { "" };
_typeHash set [_itemClassname, _treatment];
} forEach _treatments;
_itemHash set [_itemType, _typeHash];
} forEach [
["@bandage", ["FieldDressing", "PackingBandage", "ElasticBandage", "QuikClot"]],
["@iv", ["SalineIV", "SalineIV_500", "SalineIV_250", "BloodIV", "BloodIV_500", "BloodIV_250", "PlasmaIV", "PlasmaIV_500", "PlasmaIV_250"]],
["splint", ["splint"]],
["morphine", ["morphine"]],
["epinephrine", ["epinephrine"]]
];
uinamespace setVariable [QGVAR(itemHash), compileFinal _itemHash];

View File

@ -17,13 +17,19 @@
*/ */
params ["_healer", "_target"]; params ["_healer", "_target"];
(_healer getVariable [QGVAR(currentTreatment), [-1]]) params ["_finishTime", "_treatmentTarget", "_treatmentEvent", "_treatmentArgs"]; (_healer getVariable [QGVAR(currentTreatment), [-1]]) params ["_finishTime", "_treatmentTarget", "_treatmentEvent", "_treatmentArgs", "_treatmentItem"];
// Treatment in progress, check if finished and apply // Treatment in progress, check if finished and apply
if (_finishTime > 0) exitWith { if (_finishTime > 0) exitWith {
if (CBA_missionTime >= _finishTime) then { if (CBA_missionTime >= _finishTime) then {
TRACE_4("treatment finished",_finishTime,_treatmentTarget,_treatmentEvent,_treatmentArgs); TRACE_5("treatment finished",_finishTime,_treatmentTarget,_treatmentEvent,_treatmentArgs,_treatmentItem);
_healer setVariable [QGVAR(currentTreatment), nil]; _healer setVariable [QGVAR(currentTreatment), nil];
if ((GVAR(requireItems)) && {_treatmentItem != ""}) then {
([_healer, _treatmentItem] call FUNC(itemCheck)) params ["_itemOk", "_itemClassname", "_treatmentClass"];
if (!_itemOk) exitWith { _treatmentEvent = "#fail"; }; // no item after delay
_healer removeItem _itemClassname;
if (_treatmentClass != "") then { _treatmentArgs set [2, _treatmentClass]; };
};
if ((_treatmentTarget == _target) && {(_treatmentEvent select [0, 1]) != "#"}) then { if ((_treatmentTarget == _target) && {(_treatmentEvent select [0, 1]) != "#"}) then {
[_treatmentEvent, _treatmentArgs, _target] call CBA_fnc_targetEvent; [_treatmentEvent, _treatmentArgs, _target] call CBA_fnc_targetEvent;
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
@ -41,8 +47,10 @@ private _fractures = GET_FRACTURES(_target);
private _treatmentEvent = "#none"; private _treatmentEvent = "#none";
private _treatmentArgs = []; private _treatmentArgs = [];
private _treatmentTime = 6; private _treatmentTime = 6;
private _treatmentItem = "";
switch (true) do { switch (true) do {
case (GET_WOUND_BLEEDING(_target) > 0): { case ((GET_WOUND_BLEEDING(_target) > 0)
&& {([_healer, "@bandage"] call FUNC(itemCheck)) # 0}): {
// Select first bleeding wound and bandage it // Select first bleeding wound and bandage it
private _selection = "?"; private _selection = "?";
{ {
@ -55,13 +63,15 @@ switch (true) do {
_treatmentEvent = QEGVAR(medical_treatment,bandageLocal); _treatmentEvent = QEGVAR(medical_treatment,bandageLocal);
_treatmentTime = 5; _treatmentTime = 5;
_treatmentArgs = [_target, _selection, "FieldDressing"]; _treatmentArgs = [_target, _selection, "FieldDressing"];
_treatmentItem = "@bandage";
}; };
case (IN_CRDC_ARRST(_target) && {EGVAR(medical_treatment,cprSuccessChanceMin) > 0}): { case (IN_CRDC_ARRST(_target) && {EGVAR(medical_treatment,cprSuccessChanceMin) > 0}): {
_treatmentEvent = QEGVAR(medical_treatment,cprLocal); _treatmentEvent = QEGVAR(medical_treatment,cprLocal);
_treatmentArgs = [_healer, _target]; _treatmentArgs = [_healer, _target];
_treatmentTime = 15; _treatmentTime = 15;
}; };
case (_isMedic && {GET_BLOOD_VOLUME(_target) < BLOOD_VOLUME_CLASS_2_HEMORRHAGE}): { case (_isMedic && {GET_BLOOD_VOLUME(_target) < BLOOD_VOLUME_CLASS_2_HEMORRHAGE}
&& {([_healer, "@iv"] call FUNC(itemCheck)) # 0}): {
// Check if patient's blood volume + remaining IV volume is enough to allow the patient to wake up // Check if patient's blood volume + remaining IV volume is enough to allow the patient to wake up
private _totalIvVolume = 0; //in ml private _totalIvVolume = 0; //in ml
{ {
@ -75,21 +85,27 @@ switch (true) do {
_treatmentEvent = QEGVAR(medical_treatment,ivBagLocal); _treatmentEvent = QEGVAR(medical_treatment,ivBagLocal);
_treatmentTime = 5; _treatmentTime = 5;
_treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "SalineIV"]; _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "SalineIV"];
_treatmentItem = "@iv";
}; };
case ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6): { case ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6): {
_treatmentEvent = "#tooManyMeds"; _treatmentEvent = "#tooManyMeds";
}; };
case ((_fractures select 4) == 1): { case (((_fractures select 4) == 1)
&& {([_healer, "splint"] call FUNC(itemCheck)) # 0}): {
_treatmentEvent = QEGVAR(medical_treatment,splintLocal); _treatmentEvent = QEGVAR(medical_treatment,splintLocal);
_treatmentTime = 6; _treatmentTime = 6;
_treatmentArgs = [_healer, _target, "leftleg"]; _treatmentArgs = [_healer, _target, "leftleg"];
_treatmentItem = "splint";
}; };
case ((_fractures select 5) == 1): { case (((_fractures select 5) == 1)
&& {([_healer, "splint"] call FUNC(itemCheck)) # 0}): {
_treatmentEvent = QEGVAR(medical_treatment,splintLocal); _treatmentEvent = QEGVAR(medical_treatment,splintLocal);
_treatmentTime = 6; _treatmentTime = 6;
_treatmentArgs = [_healer, _target, "rightleg"]; _treatmentArgs = [_healer, _target, "rightleg"];
_treatmentItem = "splint";
}; };
case (IS_UNCONSCIOUS(_target) || {_heartRate <= 50}): { case ((IS_UNCONSCIOUS(_target) || {_heartRate <= 50})
&& {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}): {
if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith {
_treatmentEvent = "#waitForEpinephrineToTakeEffect"; _treatmentEvent = "#waitForEpinephrineToTakeEffect";
}; };
@ -100,8 +116,10 @@ switch (true) do {
_treatmentEvent = QEGVAR(medical_treatment,medicationLocal); _treatmentEvent = QEGVAR(medical_treatment,medicationLocal);
_treatmentTime = 2.5; _treatmentTime = 2.5;
_treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Epinephrine"]; _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Epinephrine"];
_treatmentItem = "epinephrine";
}; };
case ((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}): { case (((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180})
&& {([_healer, "morphine"] call FUNC(itemCheck)) # 0}): {
if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith {
_treatmentEvent = "#waitForMorphineToTakeEffect"; _treatmentEvent = "#waitForMorphineToTakeEffect";
}; };
@ -112,10 +130,11 @@ switch (true) do {
_treatmentEvent = QEGVAR(medical_treatment,medicationLocal); _treatmentEvent = QEGVAR(medical_treatment,medicationLocal);
_treatmentTime = 2.5; _treatmentTime = 2.5;
_treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Morphine"]; _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Morphine"];
_treatmentItem = "morphine";
}; };
}; };
_healer setVariable [QGVAR(currentTreatment), [CBA_missionTime + _treatmentTime, _target, _treatmentEvent, _treatmentArgs]]; _healer setVariable [QGVAR(currentTreatment), [CBA_missionTime + _treatmentTime, _target, _treatmentEvent, _treatmentArgs, _treatmentItem]];
// Play animation // Play animation
if ((_treatmentEvent select [0,1]) != "#") then { if ((_treatmentEvent select [0,1]) != "#") then {

View File

@ -0,0 +1,34 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Checks if AI healer has items
*
* Arguments:
* 0: Healer <OBJECT>
* 1: Treatment Type <STRING>
*
* Return Value:
* 0: Has Item <BOOL>
* 1: Item Classname <STRING> (Optional)
* 2: Treatment <STRING> (Optional)
*
* Example:
* [cursorObject, "@bandage"] call ACE_medical_ai_fnc_itemCheck
*
* Public: No
*/
if (!GVAR(requireItems)) exitWith { [true] };
params ["_healer", "_treatementType"];
private _return = [false];
private _items = _healer call EFUNC(common,uniqueItems);
private _treatment = GVAR(itemHash) get _treatementType;
{
if (_x in _items) exitWith {
_return = [true, _x, _y];
};
} forEach _treatment;
_return

View File

@ -13,3 +13,13 @@ private _categoryArray = [ELSTRING(medical,Category), "STR_TEAM_SWITCH_AI"];
{[QGVAR(enabledFor), _this] call EFUNC(common,cbaSettings_settingChanged)}, {[QGVAR(enabledFor), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart true // Needs mission restart
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[
QGVAR(requireItems), "CHECKBOX",
[LSTRING(requireItems_title), LSTRING(requireItems_desc)],
_categoryArray,
false,
true, // isGlobal
{},
true // Needs mission restart
] call CBA_fnc_addSetting;

View File

@ -48,5 +48,11 @@
<Czech>Pouze Server a HC</Czech> <Czech>Pouze Server a HC</Czech>
<Turkish>Sadece Sunucu ve HC de</Turkish> <Turkish>Sadece Sunucu ve HC de</Turkish>
</Key> </Key>
<Key ID="STR_ACE_Medical_AI_requireItems_title">
<English>Require Items</English>
</Key>
<Key ID="STR_ACE_Medical_AI_requireItems_desc">
<English>AI will only perform medical treatment if they have the necessary items in their inventory.\nRequires custom AI loadouts!</English>
</Key>
</Package> </Package>
</Project> </Project>