8 protected const float INITIAL_DECISION_DELAY_MS = 5000.0;
12 protected const float MAX_CLUSTER_AGE_S = 120.0;
14 protected SCR_AIGroupUtilityComponent m_Utility;
16 ref ScriptInvokerBase<SCR_AITargetClusterStateChanged> m_OnClusterStateChanged =
new ScriptInvokerBase<SCR_AITargetClusterStateChanged>();
21 s.m_fTimer_ms += deltaTime_ms;
23 if (s.m_eState != s.m_ePrevState)
25 OnLeaveState(s, s.m_ePrevState);
26 OnEnterState(s, s.m_eState);
35 if (newDesiredState == s.m_eState)
45 if (s.m_fTimer_ms > INITIAL_DECISION_DELAY_MS)
47 SwitchToState(s, newDesiredState);
56 if (newDesiredState == s.m_eState)
66 SwitchToState(s, newDesiredState);
75 if (newDesiredState == s.m_eState)
79 if (!HasActivityForState(s, newDesiredState))
94 SCR_AIActivityBase activity = TryCreateActivityForState(s, newDesiredState, mainFireteams, auxFireteams);
97 AssignActivity(s, activity);
115 SwitchToState(s, newDesiredState);
123 if (newDesiredState != s.m_eState)
125 SwitchToState(s, newDesiredState);
136 vector centerPos = 0.5*(s.m_vBBMin + s.m_vBBMax);
138 bool playerControlled = m_Utility.m_Owner.IsSlave();
140 if (s.GetTimeSinceLastNewInformation() > s.m_fMaxAge_s)
144 else if (!m_Utility.IsPositionAllowed(centerPos))
148 if (s.m_iCountIdentified > 0)
161 if (s.m_iCountIdentified > 0)
163 else if ( ((s.m_iCountLost + s.m_iCountDetected + s.m_iCountDestroyed) > 0) &&
178 s.m_fMaxAge_s = CalculateMaxAgeThreshold_s(s, newState);
184 AddDebugMessage(
string.Format(
"%1: SwitchToState: %2", s,
typename.EnumToString(
EAITargetClusterState, newState)));
187 s.m_ePrevState = s.m_eState;
188 s.m_eState = newState;
189 m_OnClusterStateChanged.Invoke(s, s.m_ePrevState, s.m_eState);
195 AddDebugMessage(
string.Format(
"%1: AssignActivity: %2", s, activity));
203 m_Utility.AddAction(parallelAction);
205 parallelAction.AddAction(activity);
207 s.m_Activity = activity;
213 AddDebugMessage(
string.Format(
"%1: UnassignActivity: %2", s, s.m_Activity));
220 s.m_Activity.Complete();
248 array<SCR_AIGroupFireteam> newFireteams = {};
258 if (!inFtsMain.IsEmpty())
264 if (!inFtsAux.IsEmpty())
270 AllocateMoreFireteams(s, ftsMain, ftsAux);
273 if (ftsMain.IsEmpty())
284 if (ftsAux.IsEmpty())
286 if (ftsMain.Count() > 1)
289 ftsMain.Remove(ftsMain.Count()-1);
290 ftsAux.Insert(ftLock);
292 else if (m_Utility.m_FireteamMgr.FindFreeFireteams(newFireteams, 1))
297 else if(ftsAux.Count() > 1)
300 while (ftsAux.Count() > 1)
303 ftsMain.Insert(ftLock);
304 ftsAux.Remove(ftsAux.Count()-1);
313 if (!inFtsMain.IsEmpty() || !inFtsAux.IsEmpty())
318 foreach (
auto ft : inFtsMain)
320 foreach (
auto ft : inFtsAux)
325 else if (m_Utility.m_FireteamMgr.FindFreeFireteams(newFireteams, 1))
383 float fEnemies = 1.3 * (float)s.m_iCountDetected + 1.3*s.m_iCountIdentified + 1.3*s.m_iCountLost + 0.5*s.m_iCountDestroyed;
385 int nEnemies = Math.Ceil(fEnemies);
388 int nSoldiersAllocated = 0;
390 nSoldiersAllocated += ftLock.GetFireteam().GetMemberCount();
392 nSoldiersAllocated += ftLock.GetFireteam().GetMemberCount();
395 array<SCR_AIGroupFireteam> freeFireteams = {};
396 m_Utility.m_FireteamMgr.GetFreeFireteams(freeFireteams);
397 while (nSoldiersAllocated < nEnemies && !freeFireteams.IsEmpty())
401 inOutFtLocksMain.Insert(newFtLock);
402 freeFireteams.Remove(0);
404 nSoldiersAllocated += newFireteam.GetMemberCount();
411 outMainFireteams.Clear();
412 outAuxFireteams.Clear();
435 int countAlive = s.m_iCountLost + s.m_iCountDetected + s.m_iCountIdentified;
440 return MAX_CLUSTER_AGE_S;
445 vector ourPos = m_Utility.m_Owner.GetCenterOfMass();
446 vector tgtPos = 0.5 * (s.m_vBBMin + s.m_vBBMax);
447 float distance = vector.DistanceXZ(ourPos, tgtPos);
448 float tgtCount = s.m_iCountDestroyed + s.m_iCountIdentified;
450 const float movementSpeed = 2.0;
451 float duration_s =
distance / movementSpeed + 15.0 * tgtCount;
452 duration_s = Math.Max(20.0, duration_s);
464 void AddDebugMessage(
string str)
466 SCR_AIInfoBaseComponent infoComp = m_Utility.m_GroupInfo;
467 infoComp.AddDebugMessage(
string.Format(
"%1: %2",
this, str), msgType:
EAIDebugMsgType.CLUSTER);