From 05e4f74e7324a7dc0d79e2e2a8041f0e01ae8da7 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Wed, 3 Jul 2019 09:59:28 -0500 Subject: [PATCH] Medical AI - Adjust healing logic for rewrite (#6902) * Medical AI - Adjust healing logic for rewrite - move state machine from config to sqf - move all healing logic to seperate func - attempt to handle healing for new system * prioritize unitReady medics * move setting to subcategory under medical * Use faster GET_WOUND_BLEEDING * Update fnc_healingLogic.sqf * Update for wound array changes * Update treatment events changes * Fractures/splint * formating / use GET_OPEN_WOUNDS * Use non-localized medical category --- addons/medical/dev/debugDisplay.sqf | 6 +- addons/medical_ai/StateMachine.hpp | 86 ------------- addons/medical_ai/XEH_PREP.hpp | 1 + addons/medical_ai/XEH_postInit.sqf | 27 +--- addons/medical_ai/config.cpp | 1 - .../functions/fnc_canRequestMedic.sqf | 16 ++- addons/medical_ai/functions/fnc_healSelf.sqf | 41 +----- addons/medical_ai/functions/fnc_healUnit.sqf | 75 +++-------- .../medical_ai/functions/fnc_healingLogic.sqf | 117 ++++++++++++++++++ addons/medical_ai/functions/fnc_isInjured.sqf | 12 +- .../functions/fnc_playTreatmentAnim.sqf | 15 +-- addons/medical_ai/initSettings.sqf | 13 +- addons/medical_ai/stateMachine.sqf | 67 ++++++++++ addons/medical_ai/stringtable.xml | 6 - 14 files changed, 247 insertions(+), 236 deletions(-) delete mode 100644 addons/medical_ai/StateMachine.hpp create mode 100644 addons/medical_ai/functions/fnc_healingLogic.sqf create mode 100644 addons/medical_ai/stateMachine.sqf diff --git a/addons/medical/dev/debugDisplay.sqf b/addons/medical/dev/debugDisplay.sqf index 3d8323f46b..541aaaccba 100644 --- a/addons/medical/dev/debugDisplay.sqf +++ b/addons/medical/dev/debugDisplay.sqf @@ -23,7 +23,11 @@ if (!isNull cursorTarget && {cursorTarget isKindOf "CAManBase"}) then { private _targetState = [cursorTarget, EGVAR(medical,STATE_MACHINE)] call CBA_statemachine_fnc_getCurrentState; - drawIcon3D ["", [0.6, 0, 0, 1], cursorTarget modelToWorldVisual (cursorTarget selectionPosition "pelvis"), 0, 0, 0, format ["State: %1", _targetState], 2, 40 * pixelH, "RobotoCondensed"]; + private _targetStateAI = ""; + if (!isNil QEGVAR(medical_ai,stateMachine)) then { + _targetStateAI = [cursorTarget, EGVAR(medical_ai,stateMachine)] call CBA_statemachine_fnc_getCurrentState; + }; + drawIcon3D ["", [0.6, 0, 0, 1], cursorTarget modelToWorldVisual (cursorTarget selectionPosition "pelvis"), 0, 0, 0, format ["State: %1 / %2", _targetState,_targetStateAI], 2, 40 * pixelH, "RobotoCondensed"]; }; }, 0 ,[]] call CBA_fnc_addPerFrameHandler; }, []] call CBA_fnc_waitUntilAndExecute; diff --git a/addons/medical_ai/StateMachine.hpp b/addons/medical_ai/StateMachine.hpp deleted file mode 100644 index 0c428e4c65..0000000000 --- a/addons/medical_ai/StateMachine.hpp +++ /dev/null @@ -1,86 +0,0 @@ -class GVAR(stateMachine) { - list = QUOTE(call EFUNC(common,getLocalUnits)); - skipNull = 1; - - class Initial { - class Injured { - targetState = "Injured"; - condition = QFUNC(isInjured); - }; - class HealUnit { - targetState = "HealUnit"; - condition = QUOTE((call FUNC(isSafe)) && {call FUNC(wasRequested)}); - }; - }; - - class Injured { - #ifdef DEBUG_MODE_FULL - onState = "systemChat format [""%1 is injured"", _this]"; - #endif - - class InSafety { - targetState = "Safe"; - condition = QFUNC(isSafe); - }; - }; - - class Safe { - #ifdef DEBUG_MODE_FULL - onState = "systemChat format [""%1 is injured, but safe"", _this]"; - #endif - - class RequestMedic { - targetState = "HealSelf"; - condition = QFUNC(canRequestMedic); - onTransition = QFUNC(requestMedic); - }; - class HealSelf { - targetState = "HealSelf"; - condition = "true"; - }; - }; - - class HealSelf { - onState = QFUNC(healSelf); - onStateLeaving = QUOTE(_this setVariable [ARR_2(QUOTE(QGVAR(treatmentOverAt)),nil)]); - - class Initial { - // Go back to initial state when done healing - targetState = "Initial"; - condition = QUOTE( \ - !(call FUNC(isInjured)) \ - && {_this getVariable [ARR_2(QUOTE(QGVAR(treatmentOverAt)),CBA_missionTime)] <= CBA_missionTime} \ - ); - }; - class Injured { - // Stop treating when it's no more safe - targetState = "Injured"; - condition = QUOTE( \ - !(call FUNC(isSafe)) \ - && {_this getVariable [ARR_2(QUOTE(QGVAR(treatmentOverAt)),CBA_missionTime)] <= CBA_missionTime} \ - ); - }; - }; - - class HealUnit { - onState = QFUNC(healUnit); - onStateLeaving = QUOTE(_this setVariable [ARR_2(QUOTE(QGVAR(treatmentOverAt)),nil)]); - - class Initial { - // Go back to initial state when done healing or it's no more safe to treat - targetState = "Initial"; - condition = QUOTE( \ - !((call FUNC(wasRequested)) && {call FUNC(isSafe)}) \ - && {_this getVariable [ARR_2(QUOTE(QGVAR(treatmentOverAt)),CBA_missionTime)] <= CBA_missionTime} \ - ); - }; - class Injured { - // Treating yourself has priority - targetState = "Injured"; - condition = QUOTE( \ - (call FUNC(isInjured)) \ - && {_this getVariable [ARR_2(QUOTE(QGVAR(treatmentOverAt)),CBA_missionTime)] <= CBA_missionTime} \ - ); - }; - }; -}; diff --git a/addons/medical_ai/XEH_PREP.hpp b/addons/medical_ai/XEH_PREP.hpp index f55636612a..9300f0cbb3 100644 --- a/addons/medical_ai/XEH_PREP.hpp +++ b/addons/medical_ai/XEH_PREP.hpp @@ -1,4 +1,5 @@ PREP(canRequestMedic); +PREP(healingLogic); PREP(healSelf); PREP(healUnit); PREP(isInjured); diff --git a/addons/medical_ai/XEH_postInit.sqf b/addons/medical_ai/XEH_postInit.sqf index e3a902d27a..d8676e9695 100644 --- a/addons/medical_ai/XEH_postInit.sqf +++ b/addons/medical_ai/XEH_postInit.sqf @@ -1,35 +1,14 @@ #include "script_component.hpp" -/*["ace_settingsInitialized", { +["ace_settingsInitialized", { TRACE_1("settingsInitialized", GVAR(enabledFor)); if (GVAR(enabledFor) == 0) exitWith {}; // 0: disabled if ((GVAR(enabledFor) == 1) && {!isServer} && {hasInterface}) exitWith {}; // 1: Don't Run on non-hc Clients - // Only run for AI that does not have to deal with advanced medical - if (EGVAR(medical,enableFor) == 1 || {hasInterface}) exitWith {}; - ["ace_firedNonPlayer", { _unit setVariable [QGVAR(lastFired), CBA_missionTime]; }] call CBA_fnc_addEventHandler; - if (hasInterface) then { - ["ace_unconscious", { - params ["_unit", "_unconscious"]; - if (!_unconscious || {_unit != ACE_player}) exitWith {}; + #include "stateMachine.sqf" +}] call CBA_fnc_addEventHandler; - private _medic = objNull; - { - if ((!isPlayer _x) && {[_x] call EFUNC(medical_treatment,isMedic)}) exitWith { - _medic = _x; - }; - } forEach (units _unit); - if (isNull _medic) exitWith {}; - - private _healQueue = _medic getVariable [QGVAR(healQueue), []]; - _healQueue pushBack _unit; - _medic setVariable [QGVAR(healQueue), _healQueue]; - }] call CBA_fnc_addEventHandler; - }; - - GVAR(statemachine) = [configFile >> "ACE_Medical_AI_StateMachine"] call CBA_statemachine_fnc_createFromConfig; -}] call CBA_fnc_addEventHandler;*/ diff --git a/addons/medical_ai/config.cpp b/addons/medical_ai/config.cpp index e9df7730c4..c42fc98f95 100644 --- a/addons/medical_ai/config.cpp +++ b/addons/medical_ai/config.cpp @@ -16,4 +16,3 @@ class CfgPatches { #include "ACE_Settings.hpp" #include "CfgEventHandlers.hpp" -#include "StateMachine.hpp" diff --git a/addons/medical_ai/functions/fnc_canRequestMedic.sqf b/addons/medical_ai/functions/fnc_canRequestMedic.sqf index 8865819d6a..c2a29c1c9f 100644 --- a/addons/medical_ai/functions/fnc_canRequestMedic.sqf +++ b/addons/medical_ai/functions/fnc_canRequestMedic.sqf @@ -10,7 +10,7 @@ * Can request medic * * Example: - * call ACE_medical_ai_fnc_canRequestMedic + * player call ACE_medical_ai_fnc_canRequestMedic * * Public: No */ @@ -21,10 +21,14 @@ if ([_this] call EFUNC(medical_treatment,isMedic) || {vehicle _this != _this}) exitWith {false}; +// Search for a medic, prioritize unitReady +private _medic = objNull; { - if ([_x] call EFUNC(medical_treatment,isMedic) && {!([_x] call EFUNC(common,isPlayer))}) exitWith { - _this setVariable [QGVAR(assignedMedic), _x]; - true - }; - false + if ([_x] call EFUNC(medical_treatment,isMedic) && {!([_x] call EFUNC(common,isPlayer))} && { + _medic = _x; + (unitReady _medic) + }) exitWith {}; } forEach (units _this); + +_this setVariable [QGVAR(assignedMedic), _medic]; +!isNull _medic diff --git a/addons/medical_ai/functions/fnc_healSelf.sqf b/addons/medical_ai/functions/fnc_healSelf.sqf index c03dccdad8..524625f3c3 100644 --- a/addons/medical_ai/functions/fnc_healSelf.sqf +++ b/addons/medical_ai/functions/fnc_healSelf.sqf @@ -18,41 +18,8 @@ // Player will have to do this manually of course if ([_this] call EFUNC(common,isPlayer)) exitWith {}; // Can't heal self when unconscious -if IS_UNCONSCIOUS(_this) exitWith {}; -// Check if we're still treating -if ((_this getVariable [QGVAR(treatmentOverAt), CBA_missionTime]) > CBA_missionTime) exitWith {}; - -private _needsBandaging = GET_BLOOD_LOSS(_this) > 0; -private _needsMorphine = GET_PAIN(_this) > 0.2; - -switch (true) do { - case _needsBandaging: { - // Select first wound and bandage it - private _openWounds = _this getVariable [QEGVAR(medical,openWounds), []]; - private _partIndex = { - _x params ["", "", "_index", "_amount", "_percentage"]; - if (_amount * _percentage > 0) exitWith { - _index - }; - } forEach _openWounds; - private _selection = ALL_BODY_PARTS select _partIndex; - [_this, "BasicBandage", _selection] call EFUNC(medical_treatment,treatmentBandageLocal); - - #ifdef DEBUG_MODE_FULL - systemChat format ["%1 is bandaging selection %2", _this, _selection]; - #endif - - // Play animation - [_this, true, true] call FUNC(playTreatmentAnim); - _this setVariable [QGVAR(treatmentOverAt), CBA_missionTime + 5]; - }; - case _needsMorphine: { - [_this, "Morphine", 2] call EFUNC(medical_treatment,treatmentMedicationLocal); - [_this, false, true] call FUNC(playTreatmentAnim); - _this setVariable [QGVAR(treatmentOverAt), CBA_missionTime + 2]; - - #ifdef DEBUG_MODE_FULL - systemChat format ["%1 is giving himself morphine", _this]; - #endif - }; +if IS_UNCONSCIOUS(_this) exitWith { + _this setVariable [QGVAR(currentTreatment), nil]; }; + +[_this, _this] call FUNC(healingLogic); diff --git a/addons/medical_ai/functions/fnc_healUnit.sqf b/addons/medical_ai/functions/fnc_healUnit.sqf index 003c85a4b5..158de90f36 100644 --- a/addons/medical_ai/functions/fnc_healUnit.sqf +++ b/addons/medical_ai/functions/fnc_healUnit.sqf @@ -14,11 +14,12 @@ * * Public: No */ - +// Player will have to do this manually of course +if ([_this] call EFUNC(common,isPlayer)) exitWith {}; // Can't heal other units when unconscious -if IS_UNCONSCIOUS(_this) exitWith {}; -// Check if we're still treating -if ((_this getVariable [QGVAR(treatmentOverAt), CBA_missionTime]) > CBA_missionTime) exitWith {}; +if IS_UNCONSCIOUS(_this) exitWith { + _this setVariable [QGVAR(currentTreatment), nil]; +}; // Find next unit to treat private _healQueue = _this getVariable [QGVAR(healQueue), []]; @@ -26,74 +27,34 @@ private _target = _healQueue select 0; // If unit died or was healed, be lazy and wait for the next tick if (isNull _target || {!alive _target} || {!(_target call FUNC(isInjured))}) exitWith { + _this forceSpeed -1; _target forceSpeed -1; _healQueue deleteAt 0; - _this getVariable [QGVAR(healQueue), _healQueue]; - _this forceSpeed -1; + _this setVariable [QGVAR(healQueue), _healQueue]; // return to formation instead of going where the injured unit was if it healed itself in the mean time _this doFollow leader _this; - _this setVariable [QGVAR(movingToInjured), false]; + _this setVariable [QGVAR(nextMoveOrder), nil]; + _this setVariable [QGVAR(currentTreatment), nil]; #ifdef DEBUG_MODE_FULL - systemChat format ["%1 finished healing %2", _this, _target]; + systemChat format ["%1 finished healing %2", _this, _target]; #endif }; // Move to target... -if (_this distance _target > 2) exitWith { - if !(_this getVariable [QGVAR(movingToInjured), false]) then { - _this setVariable [QGVAR(movingToInjured), true]; +if (_this distance _target > 2.5) exitWith { + _this setVariable [QGVAR(currentTreatment), nil]; + if (CBA_missionTime >= (_this getVariable [QGVAR(nextMoveOrder), CBA_missionTime])) then { + _this setVariable [QGVAR(nextMoveOrder), CBA_missionTime + 10]; _this doMove getPosATL _target; + #ifdef DEBUG_MODE_FULL + systemChat format ["%1 moving to %2", _this, _target]; + #endif }; }; -_this setVariable [QGVAR(movingToInjured), false]; // ...and make sure medic and target don't move _this forceSpeed 0; _target forceSpeed 0; -private _needsBandaging = GET_BLOOD_LOSS(_target) > 0; -private _needsMorphine = GET_PAIN(_target) > 0.2; -private _needsEpinephrine = IS_UNCONSCIOUS(_target); - -switch (true) do { - case _needsBandaging: { - // Select first wound and bandage it - private _openWounds = _target getVariable [QEGVAR(medical,openWounds), []]; - private _partIndex = { - _x params ["", "", "_index", "_amount", "_percentage"]; - if (_amount * _percentage > 0) exitWith { - _index - }; - } forEach _openWounds; - private _selection = ALL_BODY_PARTS select _partIndex; - [_target, "BasicBandage", _selection] call EFUNC(medical_treatment,treatmentBandageLocal); - - #ifdef DEBUG_MODE_FULL - systemChat format ["%1 is bandaging selection %2 on %3", _this, _selection, _target]; - #endif - - // Play animation - [_this, true, false] call FUNC(playTreatmentAnim); - _this setVariable [QGVAR(treatmentOverAt), CBA_missionTime + 5]; - }; - case _needsMorphine: { - [_this, "Morphine", 2] call EFUNC(medical_treatment,treatmentMedicationLocal); - [_this, false, false] call FUNC(playTreatmentAnim); - _this setVariable [QGVAR(treatmentOverAt), CBA_missionTime + 2]; - - #ifdef DEBUG_MODE_FULL - systemChat format ["%1 is giving %2 morphine", _this, _target]; - #endif - }; -//ToDo - Figure out how to connect to new medical - // case _needsEpinephrine: { - // [_this, _target] call EFUNC(medical,treatmentBasic_epipen); - // [_this, false, false] call FUNC(playTreatmentAnim); - // _this setVariable [QGVAR(treatmentOverAt), CBA_missionTime + 2]; - - // #ifdef DEBUG_MODE_FULL - // systemChat format ["%1 is using an epipen on %2", _this, _target]; - // #endif - // }; -}; +[_this, _target] call FUNC(healingLogic); diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf new file mode 100644 index 0000000000..d2beec1a2d --- /dev/null +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -0,0 +1,117 @@ +#include "script_component.hpp" +/* + * Author: BaerMitUmlaut, PabstMirror + * Applies healing to target + * + * Arguments: + * 0: Healer + * 1: Target + * + * Return Value: + * Nothing + * + * Example: + * [a, b] call ACE_medical_ai_fnc_healingLogic + * + * Public: No + */ + +params ["_healer", "_target"]; +(_healer getVariable [QGVAR(currentTreatment), [-1]]) params ["_finishTime", "_treatmentTarget", "_treatmentEvent", "_treatmentArgs"]; + +// Treatment in progress, check if finished and apply +if (_finishTime > 0) exitWith { + if (CBA_missionTime >= _finishTime) then { + TRACE_4("treatment finished",_finishTime,_treatmentTarget,_treatmentEvent,_treatmentArgs); + _healer setVariable [QGVAR(currentTreatment), nil]; + if ((_treatmentTarget == _target) && {(_treatmentEvent select [0, 1]) != "#"}) then { + [_treatmentEvent, _treatmentArgs, _target] call CBA_fnc_targetEvent; + #ifdef DEBUG_MODE_FULL + INFO_4("%1->%2: %3 - %4",_healer,_target,_treatmentEvent,_treatmentArgs); + systemChat format ["Applying [%1->%2]: %3", _healer, _treatmentTarget, _treatmentEvent]; + #endif + }; + }; +}; + +private _isMedic = [_healer] call EFUNC(medical_treatment,isMedic); +private _heartRate = GET_HEART_RATE(_target); +private _fractures = GET_FRACTURES(_target); + +private _treatmentEvent = "#none"; +private _treatmentArgs = []; +private _treatmentTime = 6; +switch (true) do { + case (GET_WOUND_BLEEDING(_target) > 0): { + // Select first bleeding wound and bandage it + private _openWounds = GET_OPEN_WOUNDS(_target); + private _selection = "?"; + { + _x params ["", "_index", "_amount", "_percentage"]; + if ((_amount * _percentage) > 0) exitWith { _selection = ALL_BODY_PARTS select _index; }; + } forEach _openWounds; + _treatmentEvent = QEGVAR(medical_treatment,bandageLocal); + _treatmentTime = 5; + _treatmentArgs = [_target, _selection, "FieldDressing"]; + }; + case (_isMedic && {GET_BLOOD_VOLUME(_target) < BLOOD_VOLUME_CLASS_2_HEMORRHAGE}): { + private _bloodBags = _target getVariable [QEGVAR(medical,ivBags), []]; + if ((count _bloodBags) >= 2) exitWith { + _treatmentEvent = "#waitForBlood"; + }; + _treatmentEvent = QEGVAR(medical_treatment,ivBagLocal); + _treatmentTime = 5; + _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "SalineIV"]; + }; + case ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6): { + _treatmentEvent = "#tooManyMeds"; + }; + case ((_fractures select 4) == 1): { + _treatmentEvent = QEGVAR(medical_treatment,splintLocal); + _treatmentTime = 6; + _treatmentArgs = [_healer, _target, "leftleg"]; + }; + case ((_fractures select 5) == 1): { + _treatmentEvent = QEGVAR(medical_treatment,splintLocal); + _treatmentTime = 6; + _treatmentArgs = [_healer, _target, "rightleg"]; + }; + case (IS_UNCONSCIOUS(_target) || {_heartRate <= 50}): { + if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith { + _treatmentEvent = "#waitForEpinephrineToTakeEffect"; + }; + if (_heartRate > 180) exitWith { + _treatmentEvent = "#waitForSlowerHeart"; + }; + _target setVariable [QGVAR(nextEpinephrine), CBA_missionTime + 10]; + _treatmentEvent = QEGVAR(medical_treatment,medicationLocal); + _treatmentTime = 2.5; + _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Epinephrine"]; + }; + case ((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}): { + if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith { + _treatmentEvent = "#waitForMorphineToTakeEffect"; + }; + if (_heartRate < 60) exitWith { + _treatmentEvent = "#waitForFasterHeart"; + }; + _target setVariable [QGVAR(nextMorphine), CBA_missionTime + 30]; + _treatmentEvent = QEGVAR(medical_treatment,medicationLocal); + _treatmentTime = 2.5; + _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Morphine"]; + }; +}; + +_healer setVariable [QGVAR(currentTreatment), [CBA_missionTime + _treatmentTime, _target, _treatmentEvent, _treatmentArgs]]; + +// Play animation +if ((_treatmentEvent select [0,1]) != "#") then { + private _treatmentClassname = _treatmentArgs select 2; + if (_treatmentEvent == QEGVAR(medical_treatment,splintLocal)) then { _treatmentClassname = "Splint" }; + [_healer, _treatmentClassname, (_healer == _target)] call FUNC(playTreatmentAnim); +}; + +#ifdef DEBUG_MODE_FULL +TRACE_4("treatment started",_treatmentTime,_target,_treatmentEvent,_treatmentArgs); +systemChat format ["Treatment [%1->%2]: %3", _healer, _target, _treatmentEvent]; +#endif diff --git a/addons/medical_ai/functions/fnc_isInjured.sqf b/addons/medical_ai/functions/fnc_isInjured.sqf index 3fa5370641..d022770f6d 100644 --- a/addons/medical_ai/functions/fnc_isInjured.sqf +++ b/addons/medical_ai/functions/fnc_isInjured.sqf @@ -17,8 +17,10 @@ if !(alive _this) exitWith {false}; -private _bloodLoss = GET_BLOOD_LOSS(_this); -private _pain = GET_PAIN_PERCEIVED(_this); -private _unconscious = IS_UNCONSCIOUS(_this); - -(_bloodLoss > 0) || {_pain > 0.2} || _unconscious +(GET_WOUND_BLEEDING(_this) > 0) +|| {GET_PAIN_PERCEIVED(_this) > 0.25} +|| {IS_UNCONSCIOUS(_this)} +|| { + private _fractures = GET_FRACTURES(_this); + ((_fractures select 4) == 1) || {(_fractures select 5) == 1} +} diff --git a/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf b/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf index 0a2587cd00..5b594edae2 100644 --- a/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf +++ b/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf @@ -5,7 +5,7 @@ * * Arguments: * 0: Unit - * 1: Is bandage + * 1: Treatment name * 2: Is self treatment * * Return Value: @@ -16,16 +16,11 @@ * * Public: No */ -params ["_unit", "_isBandage", "_isSelfTreatment"]; +params ["_unit", "_actionName", "_isSelfTreatment"]; +TRACE_3("playTreatmentAnim",_unit,_actionName,_isSelfTreatment); if (vehicle _unit != _unit) exitWith {}; -private _animConfig = if (_isBandage) then { - configFile >> "ACE_Medical_Actions" >> "Basic" >> "BasicBandage"; -} else { - configFile >> "ACE_Medical_Actions" >> "Basic" >> "Morphine"; -}; - private _configProperty = "animationMedic"; if (_isSelfTreatment) then { _configProperty = _configProperty + "Self"; @@ -34,7 +29,9 @@ if (stance _unit == "PRONE") then { _configProperty = _configProperty + "Prone"; }; -private _anim = getText (_animConfig >> _configProperty); +private _anim = getText (configFile >> QEGVAR(medical_treatment,Actions) >> _actionName >> _configProperty); +if (_anim == "") exitWith { WARNING_2("no anim [%1, %2]",_actionName,_configProperty); }; + private _wpn = switch (true) do { case ((currentWeapon _unit) == ""): {"non"}; case ((currentWeapon _unit) == (primaryWeapon _unit)): {"rfl"}; diff --git a/addons/medical_ai/initSettings.sqf b/addons/medical_ai/initSettings.sqf index 297961872c..6fada00db5 100644 --- a/addons/medical_ai/initSettings.sqf +++ b/addons/medical_ai/initSettings.sqf @@ -1,12 +1,17 @@ +// CBA Settings [ADDON: ace_medical_ai]: + +private _categoryArray = [ELSTRING(medical,Category), "STR_TEAM_SWITCH_AI"]; + [ - QGVAR(enabledFor), - "LIST", + QGVAR(enabledFor), "LIST", [LLSTRING(enableFor_title), LLSTRING(enableFor_desc)], - LLSTRING(settingCategory), + _categoryArray, [ [0, 1, 2], [LELSTRING(Common,Disabled), LLSTRING(enabledFor_OnlyServerAndHC), LELSTRING(Common,Enabled)], 2 ], - true + true, // isGlobal + {[QGVAR(enabledFor), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_settings_fnc_init; diff --git a/addons/medical_ai/stateMachine.sqf b/addons/medical_ai/stateMachine.sqf new file mode 100644 index 0000000000..48d5a6ef8e --- /dev/null +++ b/addons/medical_ai/stateMachine.sqf @@ -0,0 +1,67 @@ +GVAR(stateMachine) = [{call EFUNC(common,getLocalUnits)}, true] call CBA_statemachine_fnc_create; + +// Add states [statemachine, onState, onStateEntered, onStateLeaving, name] +[GVAR(stateMachine), {}, {}, {}, "Initial"] call CBA_statemachine_fnc_addState; + +[GVAR(stateMachine), { + #ifdef DEBUG_MODE_FULL + systemChat format ["%1 is injured", _this]; + #endif +}, {}, {}, "Injured"] call CBA_statemachine_fnc_addState; + +[GVAR(stateMachine), { + #ifdef DEBUG_MODE_FULL + systemChat format ["%1 is injured and safe", _this]; + #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; + +// Add Transistions [statemachine, originalState, targetState, condition, onTransition, name] +[GVAR(stateMachine), "Initial", "Injured", LINKFUNC(isInjured), {}, "Injured"] call CBA_statemachine_fnc_addTransition; +[GVAR(stateMachine), "Initial", "HealUnit", {(call FUNC(isSafe)) && FUNC(wasRequested)}, {}, "HealUnit"] call CBA_statemachine_fnc_addTransition; + +[GVAR(stateMachine), "Injured", "Safe", LINKFUNC(isSafe), {}, "InSafety"] call CBA_statemachine_fnc_addTransition; + +[GVAR(stateMachine), "Safe", "HealSelf", LINKFUNC(canRequestMedic), LINKFUNC(requestMedic), "RequestMedic"] call CBA_statemachine_fnc_addTransition; +[GVAR(stateMachine), "Safe", "HealSelf", {true}, {}, "HealSelf"] call CBA_statemachine_fnc_addTransition; + + +[GVAR(stateMachine), "HealSelf", "Initial", { // Go back to initial state when done healing + !(call FUNC(isInjured)) && {isNil {_this getVariable QGVAR(currentTreatment)}} +}, { + #ifdef DEBUG_MODE_FULL + systemChat format ["%1 finished healing themself", _this]; + #endif +}, "Initial"] call CBA_statemachine_fnc_addTransition; + +[GVAR(stateMachine), "HealSelf", "Injured", { // Stop treating when it's no more safe + !(call FUNC(isSafe)) && {isNil {_this getVariable QGVAR(currentTreatment)}} +}, { + #ifdef DEBUG_MODE_FULL + systemChat format ["%1 is no longer safe", _this]; + #endif +}, "Injured"] call CBA_statemachine_fnc_addTransition; + + +[GVAR(stateMachine), "HealUnit", "Initial", { // Go back to initial state when done healing or it's no more safe to treat + !((call FUNC(wasRequested)) && FUNC(isSafe)) && {isNil {_this getVariable QGVAR(currentTreatment)}} +}, { + #ifdef DEBUG_MODE_FULL + systemChat format ["%1 finished healing someone", _this]; + #endif +}, "Initial"] call CBA_statemachine_fnc_addTransition; + +[GVAR(stateMachine), "HealUnit", "Injured", { // Treating yourself has priority + (call FUNC(isInjured)) && {isNil {_this getVariable QGVAR(currentTreatment)}} +}, { + #ifdef DEBUG_MODE_FULL + systemChat format ["%1 was injured while healing someone", _this]; + #endif +}, "Injured"] call CBA_statemachine_fnc_addTransition; diff --git a/addons/medical_ai/stringtable.xml b/addons/medical_ai/stringtable.xml index 0230a64b08..13a57f26f3 100644 --- a/addons/medical_ai/stringtable.xml +++ b/addons/medical_ai/stringtable.xml @@ -1,12 +1,6 @@ - - ACE Medical - AI - ACE 医療 - AI - ACE Медицина - ИИ - ACE Sanitäts - KI - Medic AI Sanitäts KI