Add initial medical state component

This commit is contained in:
Glowbal 2016-06-30 23:43:25 +02:00
parent 3aa88c80bf
commit 2d330e36e0
4 changed files with 219 additions and 0 deletions

View File

@ -0,0 +1,89 @@
class ACE_Medical_StateMachine {
class Default {
onState = QUOTE(DFUNC(handleDefaultState));
onStateEntered = "";
onStateLeaving = "";
class Injury {
targetState = "Injured";
events[] = {'TakenInjury'};
};
class CriticalInjuryOrVitals {
targetState = "Unconscious";
events[] = {'InjuryCritical', 'CriticalVitals'};
};
class FatalInjuryOrVitals {
targetState = "Dead";
events[] = {'FatalVitals', 'InjuryFatal'};
};
};
class Injured {
onState = QUOTE(DFUNC(handleInjuredState));
onStateEntered = "";
onStateLeaving = "";
class FullHeal {
targetState = "Default";
events[] = {'FullHeal'};
};
class LastWoundTreated {
targetState = "Default";
events[] = {'LastWoundTreated'};
};
class CriticalInjuryOrVitals {
targetState = "Unconscious";
events[] = {'InjuryCritical', 'CriticalVitals'};
};
class FatalInjuryOrVitals {
targetState = "Dead";
events[] = {'FatalVitals', 'InjuryFatal'};
};
};
class Unconscious {
onState = QUOTE(DFUNC(handleUnconciousState));
onStateEntered = QUOTE(DFUNC(enteredUnconscious)); // set unconscious animation & state
onStateLeaving = QUOTE(DFUNC(leavingUnconscious)); // leave unconscious animation & state
class WakeUpFromKnockDown {
targetState = "Injured";
condition = QUOTE(_unit call FUNC(hasStableVitals));
events[] = {'MinUnconsciousTimer'};
};
class WakeUpStable {
targetState = "Injured";
condition = "unitUnconsciousTimer >= MinUnconsciousTimer";
events[] = {'VitalsWentStable'};
};
class FatalTransitions {
targetState = "Dead";
events[] = {'InjuryFatal', 'FatalVitals', 'UnconsciousTimerRanOut'};
};
};
class Dead {
onStateEntered = "(_this select 0) setDamage 1"; // killing a unit also exits the state machine for this unit
};
class Revive {
onState = QUOTE(DFUNC(handleReviveState));
onStateEntered = QUOTE(DFUNC(enteredRevive)); // set unconscious animation & state
onStateLeaving = QUOTE(DFUNC(leavingRevive)); // leave unconscious animation & state
class FullHeal {
targetState = "Default";
events[] = {'fullyHealed'};
onTransition = "";
};
class Revived {
targetState = "Injured";
events[] = {'Revived'};
onTransition = "";
};
class TimerRanOut {
targetState = "Dead";
condition = "timerValue >= maxReviveTime";
events[] = {'ReviveTimer'};
onTransition = "";
};
class FatalTransitions {
targetState = "Dead";
condition = "killOnFatalDamageInRevive && inReviveState >= 10";
events[] = {'FatalInjury'};
};
};
};

View File

@ -0,0 +1,53 @@
#include "script_component.hpp"
params ["_stateMachineConfig"];
private _getCode = {
params ["_config", "_attribute"];
private _value = getText (_config >> _attribute);
if (_value == "") {_value = "true"};
compile _value;
};
private _states = [];
{
private _stateName = configName _x;
private _onState = [_x, "onState"] call _getCode;
private _onEntry = [_x, "onEntry"] call _getCode;
private _onExit = [_x, "onExit"] call _getCode;
// Collect all the transitions for the state
private _transitions = [];
{
private _transitionName = configName _x;
private _targetState = getText (_x >> "targetState");
private _events = getArray (_x >> "events");
private _condition = [_x, "condition"] call _getCode;
private _onTransition = [_x, "onTransition"] call _getCode;
_transitions pushBack [_transitionName, _condition, _events, _onTransition, _targetState];
} forEach ("true" configClasses _x);
_states pushBack [_stateName, _onState, _onEntry, _onExit, _transitions];
} forEach ("true" configClasses _stateMachineConfig);
// Helper method for finding the desired state when linking (See below)
private _getState = {
params ["_stateName"];
private _state = ["Invalid", {}, {}, {}, []];
{
if (_stateName == (_x select 0)) exitWith {_state = _x};
} forEach _states;
_state;
};
// Now we have collected all the states, link them in transitions so we do not have to look them up on state transitions
{
_x params ["", "", "", "", "_transitions"];
{
_x params ["", "", "", "", "_targetState"];
private _state = [_targetState] call _getState;
_x set [4, _state];
} forEach _transitions;
} forEach _states;
_states;

View File

@ -0,0 +1,33 @@
#include "script_component.hpp"
params ["_unit", "_event", "_args"];
private _unitState = _unit getvariable [QGVAR(state), [CBA_missionTime, DEFAULT_STATE]];
_unitState params ["_lastTime", "_state"];
_state params ["_name", "_handler", "_onEntry", "_onExit", "_transitions"];
{
_x params ["_transitionName", "_condition", "_events", "_onTransition", "_targetState"];
if (_condition && {_event in _events}) exitWith {
_targetState params ["_targetStateName", "_targetStateHandler", "_targetStateOnEntry", "_targetStateOnExit", "_targetStateTansitions"];
// Handle state leaving
[_unit, _event, _args] call {
params ["_unit", "_event", "_args"];
[_unit, _event, _args] call _onExit;
[_unit, _event, _args] call _onTransition;
};
// Switch the state
_unitState set [1, _targetState];
_unit setvariable [QGVAR(state), _unitState];
// Enter the state
[_unit, _event, _args] call {
params ["_unit", "_event", "_args"];
[_unit, _event, _args] call _targetStateOnEntry;
};
};
} forEach _transitions;

View File

@ -0,0 +1,44 @@
#include "script_component.hpp"
// Delay between state runs
#define DELAY 10
#define DEFAULT_STATE [0, "Default", {}, {}, {}, []];
GVAR(monitoredUnitsList) = [];
GVAR(monitoredUnitsListIsSorted) = false;
[{
params ["_args", "_pfhId"];
if (!GVAR(monitoredUnitsListIsSorted)) then {
GVAR(monitoredUnitsList) sort true;
GVAR(monitoredUnitsListIsSorted) = true;
};
private _delete = false;
private _exit = false;
{
_x params ["_unit"];
if (!isNull _unit && alive _unit) {
private _unitState = _unit getvariable [QGVAR(state), [CBA_missionTime, DEFAULT_STATE]];
_unitState params ["_lastTime", "_state"];
if ((_lastTime + DELAY) > CBA_missionTime) exitWith {_exit = true;};
_state params ["_name", "_handler", "_onEntry", "_onExit", "_transitions"];
_unitState set [0, CBA_missionTime];
_unit setvariable [QGVAR(state), _unitState];
[_unit, _name] call _handler;
} else {
_delete = true;
GVAR(monitoredUnitsList) set [_forEachIndex, objNull];
};
if (_exit) exitwith {};
} forEach GVAR(monitoredUnitsList);
if (_delete) then {
GVAR(monitoredUnitsList) = GVAR(monitoredUnitsList) - [objNull];
};
}, 0, []] call CBA_fnc_addPerFrameHandler;