4 class WeaponFSM extends HFSMBase<WeaponStateBase, WeaponEventBase, WeaponActionBase, WeaponGuardBase>
 
    6     private static const int MAX_SYNCHRONIZE_ATTEMPTS = 12;
 
    7     private static const int MIN_SYNCHRONIZE_INTERVAL = 3000; 
 
    8     private static const int RESET_SYNCHRONIZE_THRESHOLD = 3600000; 
 
    9     private int m_SynchronizeAttempts;
 
   10     private int m_LastSynchronizeTime;
 
   12     protected int m_NextStateId = 0; 
 
   17         if (state && state.GetInternalStateID() == -1)
 
   19             state.SetInternalStateID(m_NextStateId);
 
   22             m_UniqueStates.Insert(state);
 
   33         super.AddTransition(t);
 
   35         SetInternalID(t.m_srcState);
 
   36         SetInternalID(t.m_dstState);
 
   41         if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] (local) state=" + t.m_srcState.ToString() + 
"-------- event=" + e.ToString() + 
"[G=" + t.m_guard.ToString() +
"]/A=" + t.m_action.ToString() + 
" --------|> dst=" + t.m_dstState.ToString());
 
   48         if (t.m_dstState != NULL)
 
   53                 GetOwnerState().OnSubMachineChanged(t.m_srcState, t.m_dstState);    
 
   56                 m_State.OnStateChanged(t.m_srcState, t.m_dstState); 
 
   63             if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] terminating fsm: state=" + t.m_srcState.ToString() + 
" event=" + e.ToString());
 
   66                 GetOwnerState().OnSubMachineChanged(t.m_srcState, NULL);    
 
   74         if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] (local abort) state=" + t.m_srcState.ToString() + 
"-------- ABORT event=" + e.ToString() + 
"[G=" + t.m_guard.ToString() +
"]/A=" + t.m_action.ToString() + 
" --------|> dst=" + t.m_dstState.ToString());
 
   79         auto tmp = t.m_srcState.GetParentState();
 
   80         if (tmp == t.m_dstState.GetParentState())
 
   84             if (t.m_dstState != NULL)
 
   92                 if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] abort & terminating fsm: state=" + t.m_srcState.ToString() + 
" event=" + e.ToString());
 
  112                 fsmDebugPrint(
"[hfsm] root::ProcessAbortEvent(" + e.Type().ToString() + 
")");
 
  138                     if (GetOwnerState() == abort_dst.GetParentState())
 
  171         int i = FindFirstUnguardedTransition(e);
 
  174             if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] abort event has no transition: src=" + 
m_State.ToString() + 
" e=" + e.Type().ToString());
 
  183         i = FindFirstUnguardedTransition(e);
 
  186             if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] abort event has no transition: src=" + 
m_State.ToString() + 
" e=" + e.Type().ToString());
 
  206                 if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] aborted sub machine=" + 
m_State.ToString() + 
" will fall-through to dst=" + t.m_dstState);
 
  233                 fsmDebugPrint(
"[hfsm] root::ProcessEvent(" + e.Type().ToString() + 
" =" + e.DumpToString());
 
  237         if (m_HasCompletions)
 
  238             ProcessCompletionTransitions();
 
  264         int i = FindFirstUnguardedTransition(e);
 
  267             if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] event has no transition: src=" + 
m_State.ToString() + 
" e=" + e.Type().ToString());
 
  275         i = FindFirstUnguardedTransition(e);
 
  278             if (
LogManager.IsInventoryHFSMLogEnable()) 
fsmDebugPrint(
"[hfsm] event has no transition: src=" + 
m_State.ToString() + 
" e=" + e.Type().ToString());
 
  285         if (row.m_dstState != NULL)
 
  288             if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
 
  289                 res = LocalTransition(i, e); 
 
  291                 Error(
"cross-hierarchy transition or misconfigured transition detected!");
 
  297             if (row.m_srcState.GetParentState() == GetOwnerState())
 
  298                 res = LocalTransition(i, e); 
 
  300                 Error(
"cross-hierarchy transition or misconfigured transition detected!");
 
  312         int state_count = m_UniqueStates.Count();
 
  313         for (
int idx = 0; idx < state_count; ++idx)
 
  315             int state_id = m_UniqueStates.Get(idx).GetInternalStateID();
 
  317                 return m_UniqueStates.Get(idx);
 
  331         int count = m_Transitions.Count();
 
  332         for (
int i = 0; i < count; ++i)
 
  336             if (state && 
id == state.GetCurrentStateID())
 
  344         int curr_state_id = -1;
 
  345         if (!ctx.Read(curr_state_id))
 
  347             Error(
"[wpnfsm] LoadCurrentFSMState - cannot read current state");
 
  355             if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugPrint(
"[wpnfsm] synced current state=" + state + 
" id=" + curr_state_id); }   
 
  361             Error(
"[wpnfsm] LoadCurrentFSMState - cannot find state for id=" + curr_state_id);
 
  371         if (LoadAndSetCurrentFSMState(ctx, version))
 
  373             bool res = 
m_State.LoadCurrentFSMState(ctx, version);
 
  374             if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugSpam(
"[wpnfsm] LoadCurrentFSMState - loaded current state=" + GetCurrentState()); }
 
  382         if (LoadAndSetCurrentFSMState(ctx, version))
 
  385             int state_count = m_UniqueStates.Count();
 
  386             for (
int idx = 0; idx < state_count; ++idx)
 
  388                 if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugSpam(
"[wpnfsm] LoadCurrentUnstableFSMState " + idx + 
"/" + state_count + 
" id=" + m_UniqueStates.Get(idx).GetInternalStateID() + 
" state=" + m_UniqueStates.Get(idx)); }
 
  389                 if (!m_UniqueStates.Get(idx).LoadCurrentFSMState(ctx, version))
 
  390                     Error(
"[wpnfsm] LoadCurrentUnstableFSMState - cannot load unique state " + idx + 
"/" + state_count + 
" with id=" + m_UniqueStates.Get(idx).GetInternalStateID() + 
" state=" + m_UniqueStates.Get(idx));
 
  403         int curr_state_id = state.GetInternalStateID();
 
  404         if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugPrint(
"[wpnfsm] SaveCurrentFSMState - saving current state=" + GetCurrentState() + 
" id=" + curr_state_id); }
 
  406         if (!ctx.Write(curr_state_id))
 
  408             Error(
"[wpnfsm] SaveCurrentFSMState - cannot save curr_state_id=" + curr_state_id);
 
  413         if (!state.SaveCurrentFSMState(ctx))
 
  415             Error(
"[wpnfsm] SaveCurrentFSMState - cannot save currrent state=" +state);
 
  424         int curr_state_id = state.GetInternalStateID();
 
  425         if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugPrint(
"[wpnfsm] SaveCurrentUnstableFSMState - saving current state=" + GetCurrentState() + 
" id=" + curr_state_id); }
 
  427         if (!ctx.Write(curr_state_id))
 
  429             Error(
"[wpnfsm] SaveCurrentFSMState - cannot save curr_state_id=" + curr_state_id);
 
  434         int state_count = m_UniqueStates.Count();
 
  435         for (
int idx = 0; idx < state_count; ++idx)
 
  437             int state_id = m_UniqueStates.Get(idx).GetInternalStateID();
 
  440                 if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugSpam(
"[wpnfsm] SaveCurrentUnstableFSMState " + idx + 
"/" + state_count + 
" id=" + state_id + 
" name=" + m_UniqueStates.Get(idx)); }
 
  441                 if (!m_UniqueStates.Get(idx).SaveCurrentFSMState(ctx))
 
  442                     Error(
"SaveCurrentUnstableFSMState - cannot save unique state=" + m_UniqueStates.Get(idx) + 
" idx=" + idx + 
"/" + state_count + 
" with id=" + state_id);
 
  445                 Error(
"[wpnfsm] SaveCurrentUnstableFSMState state=" + m_UniqueStates.Get(idx) + 
" with unassigned ID!");
 
  453     void ValidateAndRepair()
 
  455         Internal_ValidateAndRepair();
 
  462     protected bool Internal_ValidateAndRepair()
 
  464         bool repaired = 
false;
 
  468         if (state && state.IsRepairEnabled())
 
  473                 repaired |= ValidateAndRepairHelper(weapon,
 
  475                         state.HasMagazine(), ( weapon.GetMagazine(0) != 
null ),
 
  476                         new WeaponEventAttachMagazine, 
new WeaponEventDetachMagazine,
 
  479                 repaired |= ValidateAndRepairHelper(weapon,
 
  481                         state.IsJammed(), weapon.IsJammed(),
 
  482                         new WeaponEventTriggerToJam, 
new WeaponEventUnjam,
 
  485                 if (weapon.IsJammed())
 
  488                 int nMuzzles = weapon.GetMuzzleCount();
 
  493                         repaired |= ValidateAndRepairHelper(weapon,
 
  494                             "ChamberFiredRepair",
 
  495                             state.IsChamberFiredOut(0), weapon.IsChamberFiredOut(0),
 
  496                             new WeaponEventTrigger, 
new WeaponEventMechanism,
 
  499                         repaired |= ValidateAndRepairHelper(weapon,
 
  501                             state.IsChamberFull(0), weapon.IsChamberFullEx(0),
 
  502                             new WeaponEventLoad1Bullet, 
new WeaponEventMechanism,
 
  509                         for (
int i = 0; i < nMuzzles; ++i)
 
  511                             repaired |= ValidateAndRepairHelper(weapon,
 
  512                                 "ChamberFiredRepair",
 
  513                                 state.IsChamberFiredOut(i), weapon.IsChamberFiredOut(i),
 
  517                             repaired |= ValidateAndRepairHelper(weapon,
 
  519                                 state.IsChamberFull(i), weapon.IsChamberFull(i),
 
  535         if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugPrint(
"[wpnfsm] " + weapon.GetDebugName(weapon) + 
" ValidateAndRepair - " + 
name + 
" - " + 
m_State + 
" - state: " + stateCondition + 
" & weapon: " + gunCondition); }
 
  537         if (stateCondition != gunCondition)
 
  545             Error(
string.Format(
"[wpnfsm] ValidateAndRepair Attempting to repair: %1 - %2 - %3 - state: %4 != weapon: %5",
 
  546                 weapon.GetDebugName(weapon), 
name, 
m_State, stateCondition, gunCondition));
 
  549                 repairedState = ValidateAndRepairStateFinder(gunCondition, e1, e2, state);
 
  556                 state = repairedState;
 
  557                 weapon.SyncSelectionState(state.HasBullet(), state.HasMagazine());
 
  558                 repairedState.SyncAnimState();
 
  566                 if (m_SynchronizeAttempts < MAX_SYNCHRONIZE_ATTEMPTS)
 
  568                     int currentTime = 
g_Game.GetTime();
 
  569                     int timeDiff = currentTime - m_LastSynchronizeTime;
 
  572                     if (timeDiff > MIN_SYNCHRONIZE_INTERVAL)
 
  576                         if (timeDiff > RESET_SYNCHRONIZE_THRESHOLD)
 
  577                             m_SynchronizeAttempts = 0;
 
  582                             weapon.RandomizeFSMState();
 
  584                         weapon.Synchronize();
 
  586                         ++m_SynchronizeAttempts;
 
  587                         m_LastSynchronizeTime = currentTime;
 
  592                     OnFailThresholdBreached(weapon, 
name, stateCondition, gunCondition);
 
  600     protected void OnFailThresholdBreached(
Weapon weapon, 
string name, 
bool stateCondition, 
bool gunCondition)
 
  606         Error(
string.Format(
"[wpnfsm] %1 ValidateAndRepair THRESHOLD BREACH - %2 - %3 - state: %4 != weapon: %5",
 
  607                     weapon.GetDebugName(weapon), 
name, 
m_State, stateCondition, gunCondition));
 
  616             interState = FindTransitionState(state, e1);
 
  618             interState = FindTransitionState(state, e2);
 
  635             if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugPrint(
"[wpnfsm] OnStoreLoad - loading current state=" + state + 
" id=" + 
id); }   
 
  641             Print(
"[wpnfsm] Warning! OnStoreLoad - cannot load curent weapon state, id=" + 
id);
 
  657     int GetCurrentStableStateID()
 
  662             return state.GetCurrentStateID();
 
  665         WeaponStateBase abort_dst = FindAbortDestinationState(
new WeaponEventHumanCommandActionAborted(
null));
 
  668         if (closest_stable_state)
 
  670             Print(
"[wpnfsm] Save occured in fsm transition! current state=" + GetCurrentState() + 
" closes stable state=" + closest_stable_state + 
" id=" + closest_stable_state.GetCurrentStateID());
 
  671             return closest_stable_state.GetCurrentStateID();
 
  674         Print(
"[wpnfsm] Warning! Save occured in fsm transition! GetCurrentStateID - cannot find closest weapon stable state.");
 
  681     int GetInternalStateID()
 
  686             id = curr.GetInternalStateID();
 
  695         int id = GetCurrentStableStateID();
 
  696         if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugSpamALot(
"[wpnfsm] OnStoreSave - saving current state=" + GetCurrentState() + 
" id=" + 
id); }
 
  703     void RandomizeFSMState(
bool hasBullet, 
bool hasMagazine, 
bool isJammed)
 
  711         RandomizeFSMStateEx(muzzleStates, hasMagazine, isJammed);
 
  719     void RandomizeFSMStateEx(
array<MuzzleState> muzzleStates, 
bool hasMagazine, 
bool isJammed)
 
  722         int tc = m_Transitions.Count();
 
  726             if (state && state.HasMagazine() == hasMagazine && state.IsJammed() == isJammed)
 
  728                 if (state.IsSingleState())
 
  731                     candidates.Insert(state);
 
  735                 int nMuzzles = muzzleStates.Count();
 
  736                 int nMuzzlesState = state.GetMuzzleStateCount();
 
  737                 if (nMuzzles != nMuzzlesState)
 
  739                     ErrorEx(
string.Format(
"Number of muzzles on the weapon (%1) does not correspond with what state has configured (%2).", nMuzzles, nMuzzlesState));
 
  744                 for (
int i = 0; i < nMuzzles; ++i)
 
  746                     if (muzzleStates[i] != state.GetMuzzleState(i))
 
  754                     candidates.Insert(state);
 
  758         int cc = candidates.Count();
 
  761             int randomIndex = 
Math.RandomInt(0, cc);
 
  765             if (!Internal_ValidateAndRepair())
 
  767             if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugPrint(
"[wpnfsm] RandomizeFSMState - randomized current state=" + 
m_State + 
" id=" + selected.GetCurrentStateID()); }
 
  768             selected.SyncAnimState();
 
  772             if (
LogManager.IsWeaponLogEnable()) { 
wpnDebugPrint(
"[wpnfsm] RandomizeFSMState - warning - cannot randomize, no states available"); }