Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_AIGroupPerception.c
Go to the documentation of this file.
3 
6 
7 void SCR_AIGroupPerceptionOnEnemyDetected(SCR_AIGroup group, SCR_AITargetInfo target);
9 
10 void SCR_AIGroupPerceptionOnEnemyDetectedFiltered(SCR_AIGroup group, SCR_AITargetInfo target, AIAgent reporter);
12 
13 class SCR_AIGroupPerception : Managed
14 {
15  // Target is considered lost if noone has seen it for this time.
16  // This value should be consistent with actual duration of AI combat behavior (see TARGET_MAX_LAST_SEEN)
17  const float TARGET_LOST_THRESHOLD_S = 45.0;
18 
19  // Time till target is totally forgotten and is removed from memory.
20  // This doesn't need to be much longer than MAX_CLUSTER_AGE_S
21  const float TARGET_FORGET_THRESHOLD_S = 150.0;
22 
23  protected SCR_AIGroup m_Group;
24  protected SCR_AIGroupUtilityComponent m_Utility;
25 
26  protected ref ScriptInvokerBase<SCR_AIOnTargetClusterStateDeleted> Event_OnTargetClusterStateDeleted = new ScriptInvokerBase<SCR_AIOnTargetClusterStateDeleted>();
27  protected ref ScriptInvokerBase<SCR_AIGroupPerceptionOnEnemyDetected> Event_OnEnemyDetected;
28  protected ref ScriptInvokerBase<SCR_AIGroupPerceptionOnEnemyDetectedFiltered> Event_OnEnemyDetectedFiltered;
29  protected ref ScriptInvokerBase<SCR_AIGroupPerceptionOnNoEnemy> Event_OnNoEnemy;
30 
31  ref array<IEntity> m_aTargetEntities = new array<IEntity>; // Read only! Don't dare to modify it!
32  ref array<ref SCR_AITargetInfo> m_aTargets = new array<ref SCR_AITargetInfo>; // Read only!
33  ref array<ref SCR_AIGroupTargetCluster> m_aTargetClusters = {}; // Read only!
34 
35 
36  //---------------------------------------------------------------------------------------------------
37  void SCR_AIGroupPerception(SCR_AIGroupUtilityComponent utility, SCR_AIGroup group)
38  {
39  m_Group = group;
40  m_Utility = utility;
41  }
42 
43  //---------------------------------------------------------------------------------------------------
44  ScriptInvokerBase<SCR_AIOnTargetClusterStateDeleted> GetOnTargetClusterDeleted()
45  {
46  return Event_OnTargetClusterStateDeleted;
47  }
48 
49  //---------------------------------------------------------------------------------------------------
50  ScriptInvokerBase<SCR_AIGroupPerceptionOnEnemyDetected> GetOnEnemyDetected()
51  {
52  if (!Event_OnEnemyDetected)
53  Event_OnEnemyDetected = new ScriptInvokerBase<SCR_AIGroupPerceptionOnEnemyDetected>();
54 
55  return Event_OnEnemyDetected;
56  }
57 
58  //---------------------------------------------------------------------------------------------------
61  ScriptInvokerBase<SCR_AIGroupPerceptionOnEnemyDetectedFiltered> GetOnEnemyDetectedFiltered()
62  {
63  if (!Event_OnEnemyDetectedFiltered)
64  Event_OnEnemyDetectedFiltered = new ScriptInvokerBase<SCR_AIGroupPerceptionOnEnemyDetectedFiltered>();
65 
66  return Event_OnEnemyDetectedFiltered;
67  }
68 
69  //---------------------------------------------------------------------------------------------------
70  ScriptInvokerBase<SCR_AIGroupPerceptionOnNoEnemy> GetOnNoEnemy()
71  {
72  if (!Event_OnNoEnemy)
73  Event_OnNoEnemy = new ScriptInvokerBase<SCR_AIGroupPerceptionOnNoEnemy>();
74 
75  return Event_OnNoEnemy;
76  }
77 
78  //---------------------------------------------------------------------------------------------------
79  protected void RemoveTarget(IEntity enemy)
80  {
81  if (!enemy)
82  return;
83 
84  int index = m_aTargetEntities.Find(enemy);
85 
86  if (index > -1)
87  {
88  m_aTargetEntities.Remove(index);
89  m_aTargets.Remove(index);
90  if (m_aTargetEntities.IsEmpty() && Event_OnNoEnemy)
91  Event_OnNoEnemy.Invoke(m_Group);
92  }
93  }
94 
95  //---------------------------------------------------------------------------------------------------
96  protected void RemoveTarget(int id)
97  {
98  m_aTargetEntities.Remove(id);
99  m_aTargets.Remove(id);
100 
101  if (m_aTargetEntities.IsEmpty() && Event_OnNoEnemy)
102  Event_OnNoEnemy.Invoke(m_Group);
103  }
104 
105  //---------------------------------------------------------------------------------------------------
106  // Adds or updates target from BaseTarget
107  SCR_AITargetInfo AddOrUpdateTarget(notnull BaseTarget target, out bool outNewTarget)
108  {
109  IEntity enemy = target.GetTargetEntity();
110 
111  if (!enemy)
112  {
113  outNewTarget = false;
114  return null;
115  }
116 
117  int id = m_aTargetEntities.Find(enemy);
118  if (id > -1)
119  {
120  SCR_AITargetInfo oldTargetInfo = m_aTargets[id];
121  EAITargetInfoCategory oldCategory = m_aTargets[id].m_eCategory;
122 
123  // Ignore if destroyed or disarmed
124  if (oldCategory == EAITargetInfoCategory.DESTROYED || oldCategory == EAITargetInfoCategory.DISARMED)
125  {
126  outNewTarget = false;
127  return oldTargetInfo;
128  }
129 
130  // This target was already found
131  // Which newTimestamp to use? Depends on target category
132  float newTimestamp;
133  ETargetCategory targetCategory = target.GetTargetCategory();
134  if (targetCategory == ETargetCategory.DETECTED)
135  newTimestamp = target.GetTimeLastDetected();
136  else
137  newTimestamp = target.GetTimeLastDetected();
138 
139  if (oldTargetInfo.m_fTimestamp < newTimestamp)
140  {
141  // New information is newer
142  // Is new data more relevant?
143  if ((targetCategory == ETargetCategory.ENEMY) || // If enemy, always update
144  ((targetCategory == ETargetCategory.DETECTED) && (oldCategory != EAITargetInfoCategory.IDENTIFIED)) )
145  {
146  oldTargetInfo.UpdateFromBaseTarget(target);
147  }
148  }
149 
150  outNewTarget = false;
151  return oldTargetInfo;
152  }
153 
154  // new enemy found
155 
156  // Ignore if disarmed
157  if (target.IsDisarmed())
158  {
159  outNewTarget = false;
160  return null;
161  }
162 
163  SCR_AITargetInfo targetInfo = new SCR_AITargetInfo();
164  targetInfo.InitFromBaseTarget(target);
165 
166  m_aTargetEntities.Insert(enemy);
167  m_aTargets.Insert(targetInfo);
168 
169  if (Event_OnEnemyDetected)
170  {
171  Event_OnEnemyDetected.Invoke(m_Group, targetInfo);
172  }
173 
174  outNewTarget = true;
175  return targetInfo;
176  }
177 
178  //---------------------------------------------------------------------------------------------------
179  void AddOrUpdateGunshot(notnull IEntity shooter, vector worldPos, float timestamp)
180  {
181  int id = m_aTargetEntities.Find(shooter);
182  if (id > -1)
183  {
184  // Update data
185  SCR_AITargetInfo oldTargetInfo = m_aTargets[id];
186  if ((oldTargetInfo.m_eCategory != EAITargetInfoCategory.IDENTIFIED) && // Update only if it wasn't seen yet
187  (timestamp > oldTargetInfo.m_fTimestamp)) // Update only if new data is newer
188  {
189  oldTargetInfo.UpdateFromGunshot(worldPos, timestamp);
190  }
191  }
192  else
193  {
194  // Create new data
195  SCR_AITargetInfo targetInfo = new SCR_AITargetInfo();
196  targetInfo.InitFromGunshot(shooter, worldPos, timestamp);
197 
198  m_aTargets.Insert(targetInfo);
199  m_aTargetEntities.Insert(shooter);
200  }
201  }
202 
203  //---------------------------------------------------------------------------------------------------
204  void Update()
205  {
206  UpdateTargetsFromMembers(); // These calls ...
207  MaintainTargets(); // ... must be ... | <- this one removed targets
208  ClusterTargets(); // ... in this order. | thus clustering must happen after it
209  }
210 
211  //---------------------------------------------------------------------------------------------------
212  protected void UpdateTargetsFromMembers()
213  {
214  IEntity leaderEntity = m_Group.GetLeaderEntity();
215 
216  // Makes no sense without a leader
217  if (!leaderEntity)
218  return;
219 
220  // Update all targets from our group members
221  array<AIAgent> agents = {};
222  m_Group.GetAgents(agents);
223 
224  array<BaseTarget> targets = {};
225 
226  bool targetIsNew;
227  SCR_AITargetInfo targetInfo;
228  bool invokedEvent = false;
229 
230  foreach (SCR_AIInfoComponent infoComp : m_Utility.m_aInfoComponents)
231  {
232  PerceptionComponent perception = infoComp.m_Perception;
233 
234  targets.Clear();
235  perception.GetTargetsList(targets, ETargetCategory.DETECTED);
236  foreach (BaseTarget baseTarget : targets)
237  {
238  targetInfo = AddOrUpdateTarget(baseTarget, targetIsNew);
239 
240  if (targetIsNew && !invokedEvent)
241  {
242  if (Event_OnEnemyDetectedFiltered)
243  {
244  AIAgent reporter = AIAgent.Cast(infoComp.GetOwner());
245  Event_OnEnemyDetectedFiltered.Invoke(m_Group, targetInfo, reporter);
246  }
247  invokedEvent = true;
248  }
249  }
250 
251  targets.Clear();
252  perception.GetTargetsList(targets, ETargetCategory.ENEMY);
253  foreach (BaseTarget baseTarget : targets)
254  {
255  targetInfo = AddOrUpdateTarget(baseTarget, targetIsNew);
256 
257  if (targetIsNew && !invokedEvent)
258  {
259  if (Event_OnEnemyDetectedFiltered)
260  {
261  AIAgent reporter = AIAgent.Cast(infoComp.GetOwner());
262  Event_OnEnemyDetectedFiltered.Invoke(m_Group, targetInfo, reporter);
263  }
264  invokedEvent = true;
265  }
266  }
267  }
268  }
269 
270  //---------------------------------------------------------------------------
271  protected void MaintainTargets()
272  {
273  float timeNow;
274  PerceptionManager pm = GetGame().GetPerceptionManager();
275  if (pm)
276  timeNow = pm.GetTime();
277 
278  for (int i = m_aTargets.Count()-1; i >= 0; i--)
279  {
280  SCR_AITargetInfo tgtInfo = m_aTargets[i];
281  EAITargetInfoCategory category = tgtInfo.m_eCategory;
282  if (timeNow - tgtInfo.m_fTimestamp > TARGET_FORGET_THRESHOLD_S) // Time to forget?
283  {
284  RemoveTarget(i);
285  }
286  else if (category == EAITargetInfoCategory.DISARMED) // Disarmed?
287  {
288  if (tgtInfo.m_DamageManager && tgtInfo.m_DamageManager.IsDestroyed()) // Destroyed?
289  tgtInfo.m_eCategory = EAITargetInfoCategory.DESTROYED;
290  if (tgtInfo.m_Perceivable && !tgtInfo.m_Perceivable.IsDisarmed()) // Not disarmed any more?
291  tgtInfo.m_eCategory = EAITargetInfoCategory.DETECTED; // Back to detected
292  }
293  else if (category != EAITargetInfoCategory.DESTROYED) // Not destroyed?
294  {
295  if (tgtInfo.m_DamageManager && tgtInfo.m_DamageManager.IsDestroyed()) // Destroyed?
296  tgtInfo.m_eCategory = EAITargetInfoCategory.DESTROYED;
297  else if (!tgtInfo.m_Entity) // Deleted? Treat as destroyed.
298  tgtInfo.m_eCategory = EAITargetInfoCategory.DESTROYED;
299  else if (timeNow - tgtInfo.m_fTimestamp > TARGET_LOST_THRESHOLD_S) // Lost?
300  tgtInfo.m_eCategory = EAITargetInfoCategory.LOST;
301  else if (tgtInfo.m_Perceivable && tgtInfo.m_Perceivable.IsDisarmed()) // Disarmed?
302  tgtInfo.m_eCategory = EAITargetInfoCategory.DISARMED;
303  }
304  }
305  }
306 
307  //---------------------------------------------------------------------------
308  protected void ClusterTargets()
309  {
310  vector centerPos = m_Group.GetCenterOfMass();
311 
312  if (centerPos == vector.Zero) // It's zero when group is empty
313  return;
314 
315  float minAngularDist = Math.DEG2RAD * 30.0;
316  array<ref SCR_AIGroupTargetCluster> newClusters = {};
317  GenerateClusters(m_aTargets, newClusters, centerPos, minAngularDist);
318 
319  // Calculate association of old clusters to new clusters
320  array<ref array<int>> association = {};
321  association.Resize(m_aTargetClusters.Count());
322  for (int oldClusterId = 0; oldClusterId < m_aTargetClusters.Count(); oldClusterId++)
323  {
324  array<int> row = new array<int>();
325  row.Resize(newClusters.Count());
326  association[oldClusterId] = row;
327 
328  for (int newClusterId = 0; newClusterId < newClusters.Count(); newClusterId++)
329  {
330  int associationValue = GetClusterAssociation(m_aTargetClusters[oldClusterId], newClusters[newClusterId]);
331  row[newClusterId] = associationValue;
332  }
333  }
334 
335  // Transfer previous orders from old clusters to new clusters
336 
337  array<int> newClusterStateIds = {}; // Index is ID of new cluster, value is ID of old cluster
338  newClusterStateIds.Resize(newClusters.Count()); // From which we are transfering state
339  for (int i = 0; i < newClusters.Count(); i++)
340  newClusterStateIds[i] = -1;
341 
342  for (int oldClusterId = 0; oldClusterId < m_aTargetClusters.Count(); oldClusterId++)
343  {
344  // Find the new cluster with which this one associates most
345  int maxAssociation = 0;
346  int newClusterIdMaxAssociation = -1;
347 
348  array<int> row = association[oldClusterId];
349  for (int i = 0; i < row.Count(); i++)
350  {
351  if (row[i] > maxAssociation)
352  {
353  maxAssociation = row[i];
354  newClusterIdMaxAssociation = i;
355  }
356  }
357 
358  bool transferClusterState = false;
359 
360  if (newClusterIdMaxAssociation != -1)
361  {
362  // Old cluster associates with some new cluster
363 
364 
365  int stateTransferedFrom = newClusterStateIds[newClusterIdMaxAssociation];
366  if (stateTransferedFrom != -1)
367  {
368  // There is a conflict, we transfered state to this new cluster already
369  // Decide which association value is greater
370 
371  if (association[stateTransferedFrom][newClusterIdMaxAssociation] < association[oldClusterId][newClusterIdMaxAssociation])
372  {
373  DeleteClusterState(newClusters[newClusterIdMaxAssociation]);
374  transferClusterState = true;
375  }
376  }
377  else
378  {
379  transferClusterState = true;
380  }
381  }
382 
383  if (transferClusterState)
384  {
385  TransferClusterState(m_aTargetClusters[oldClusterId], newClusters[newClusterIdMaxAssociation]);
386  newClusterStateIds[newClusterIdMaxAssociation] = oldClusterId;
387  }
388  else
389  {
390  // Can't transfer state from old cluster to any new cluster, delete it
391  DeleteClusterState(m_aTargetClusters[oldClusterId]);
392  }
393  }
394 
395  // Create state for all new clusters which did not inherit state
396  // Process targets in all new clusters
397  foreach (SCR_AIGroupTargetCluster c : newClusters)
398  {
399  if (!c.m_State)
400  c.m_State = new SCR_AITargetClusterState(c);
401 
402  c.m_State.ProcessTargets();
403  }
404 
405  m_aTargetClusters = newClusters;
406 
407  //DiagPrintClusterAssociation(association);
408  }
409 
410  //---------------------------------------------------------------------------
411  void GenerateClusters(array<ref SCR_AITargetInfo> targets, array<ref SCR_AIGroupTargetCluster> outClusters, vector centerPos, float minAngularDist)
412  {
413  outClusters.Clear();
414 
415  // Bail if no targets are provided
416  if (targets.IsEmpty())
417  return;
418 
419  int nTargets = targets.Count();
420 
421  //-------------------------------------------
422  // Convert all positions to polar coordinates
423  array<ref SCR_AITargetInfoPolar> targetsPolar = {};
424  targetsPolar.Resize(nTargets);
425 
426  for (int i = 0; i < nTargets; i++)
427  {
428  SCR_AITargetInfo target = targets[i];
429  vector vdir = target.m_vWorldPos - centerPos; // Not normalized!
430  float angle = SCR_AIPolar.DirToAngle(vdir);
431  float dist = vector.DistanceXZ(target.m_vWorldPos, centerPos);
432 
433  SCR_AITargetInfoPolar targetPolar = new SCR_AITargetInfoPolar();
434  targetPolar.m_Target = target;
435  targetPolar.m_fAngle = angle;
436  targetPolar.m_fDistance = dist;
437 
438  targetsPolar[i] = targetPolar;
439  }
440 
441  //-------------------------------------------
442  // Iterate points and make clusters
443 
444  // First sort by angle
445  targetsPolar.Sort(false);
446 
447  // Iterate targets sorted by angle
448  SCR_AIGroupTargetCluster currentCluster = new SCR_AIGroupTargetCluster();
449  currentCluster.AddTarget(targetsPolar[0].m_Target, targetsPolar[0].m_fAngle, targetsPolar[0].m_fDistance);
450  currentCluster.m_fAngleMin = targetsPolar[0].m_fAngle;
451  currentCluster.m_fAngleMax = currentCluster.m_fAngleMin;
452 
453  outClusters.Insert(currentCluster);
454 
455  for (int i = 1; i < nTargets; i++)
456  {
457  SCR_AITargetInfoPolar target = targetsPolar[i];
458 
459  float angle = target.m_fAngle;
460 
461  if (angle - currentCluster.m_fAngleMax < minAngularDist)
462  {
463  // Add the target
464  currentCluster.AddTarget(target.m_Target, angle, target.m_fDistance);
465  currentCluster.m_fAngleMax = angle; // Increase max angle
466  }
467  else
468  {
469  // Otherwise make a new cluster
470  currentCluster = new SCR_AIGroupTargetCluster();
471  currentCluster.AddTarget(target.m_Target, target.m_fAngle, target.m_fDistance);
472  currentCluster.m_fAngleMin = target.m_fAngle;
473  currentCluster.m_fAngleMax = currentCluster.m_fAngleMin;
474  outClusters.Insert(currentCluster);
475  }
476  }
477 
478  // Merge last and first cluster if they are too close
479 
480  if (outClusters.Count() > 1)
481  {
482  SCR_AIGroupTargetCluster first = outClusters[0];
483  SCR_AIGroupTargetCluster last = outClusters[outClusters.Count()-1];
484 
485  float distLastToFirst = Math.PI2 - last.m_fAngleMax + first.m_fAngleMin;
486  if (distLastToFirst < minAngularDist)
487  {
488  // Merge last cluster into first one and remove it
489  first.AddCluster(last);
490  outClusters.RemoveOrdered(outClusters.Count()-1);
491  }
492  }
493 
494  // We are done!
495  }
496 
497  //---------------------------------------------------------------------------
498  // Returns integer, how cluster 'a' associates with cluster 'b'
499  protected int GetClusterAssociation(SCR_AIGroupTargetCluster a, SCR_AIGroupTargetCluster b)
500  {
501  int intersection = 0;
502  array<SCR_AITargetInfo> bTargets = b.m_aTargets;
503  foreach (SCR_AITargetInfo aTarget : a.m_aTargets)
504  {
505  if (aTarget && // Don't associate null-targets
506  bTargets.Find(aTarget) != -1)
507  intersection++;
508  }
509  return intersection;
510  }
511 
512  //---------------------------------------------------------------------------
513  protected void DeleteClusterState(SCR_AIGroupTargetCluster c)
514  {
515  Event_OnTargetClusterStateDeleted.Invoke(c.m_State);
516  c.m_State = null;
517  }
518 
519  //---------------------------------------------------------------------------
520  protected void TransferClusterState(SCR_AIGroupTargetCluster oldCluster, SCR_AIGroupTargetCluster newCluster)
521  {
522  newCluster.MoveStateFrom(oldCluster);
523  }
524 
525  //---------------------------------------------------------------------------
526  int GetTargetClusterStateId(SCR_AITargetClusterState s)
527  {
528  foreach (int i, SCR_AIGroupTargetCluster c : m_aTargetClusters)
529  {
530  if (c.m_State == s)
531  return i;
532  }
533  return -1;
534  }
535 
536  //---------------------------------------------------------------------------
537  void DiagPrintClusterAssociation(array<ref array<int>> association)
538  {
539  Print("Cluster association:");
540  for (int oldClusterId = 0; oldClusterId < association.Count(); oldClusterId++)
541  {
542  array<int> row = association[oldClusterId];
543 
544  string s = string.Format("%1: ", oldClusterId);
545  for (int newClusterId = 0; newClusterId < row.Count(); newClusterId++)
546  s = s + string.Format("%1\t", row[newClusterId].ToString());
547 
548  Print(s);
549  }
550  }
551 
552 
553  //---------------------------------------------------------------------------
554  void DiagDrawClusters()
555  {
556  PerceptionManager pm = GetGame().GetPerceptionManager();
557  float timeNow_s = pm.GetTime();
558 
559  foreach (int clusterId, SCR_AIGroupTargetCluster cluster : m_aTargetClusters)
560  {
561  foreach (SCR_AITargetInfo targetInfo : cluster.m_aTargets)
562  {
563  vector mrkPos = targetInfo.m_vWorldPos + Vector(0, 3, 0);
564 
565  string s = string.Empty;
566 
567  float timeSinceTimestamp_s = timeNow_s - targetInfo.m_fTimestamp;
568  s = s + string.Format("C: %1, time-timestamp: %2\n", clusterId.ToString(), timeSinceTimestamp_s.ToString(5, 1));
569 
570  s = s + string.Format("Category: %1", typename.EnumToString(EAITargetInfoCategory, targetInfo.m_eCategory));
571 
572  DebugTextWorldSpace.Create(GetGame().GetWorld(), s, DebugTextFlags.ONCE | DebugTextFlags.CENTER | DebugTextFlags.FACE_CAMERA,
573  mrkPos[0], mrkPos[1], mrkPos[2],
574  color: 0xFFFFFFFF, bgColor: 0xFF000000,
575  size: 10.0);
576  //float size = 20.0, int , int , int priority = 1000);
577  }
578 
579  vector clusterCenter = cluster.m_State.GetCenterPosition();
580 
581  // Mark for cluster
582  string s = string.Empty;
583 
584  s = s + string.Format("Cluster: %1\n", clusterId);
585  if (cluster.m_State)
586  {
587  s = s + string.Format("State: %1, Time since Info: %2, Max age: %3",
588  typename.EnumToString(EAITargetClusterState, cluster.m_State.m_eState),
589  cluster.m_State.GetTimeSinceLastNewInformation().ToString(5,1),
590  cluster.m_State.m_fMaxAge_s.ToString(5, 1));
591  }
592 
593  DebugTextWorldSpace.Create(GetGame().GetWorld(), s, DebugTextFlags.ONCE | DebugTextFlags.CENTER | DebugTextFlags.FACE_CAMERA,
594  clusterCenter[0], clusterCenter[1] + 10.0, clusterCenter[2],
595  color: 0xFFFFFFFF, bgColor: 0xFF000000,
596  size: 12.0);
597  }
598  }
599 }
m_fDistance
float m_fDistance
Definition: SCR_AIGroupTargetCluster.c:38
SCR_AIGroupPerceptionOnNoEnemy
func SCR_AIGroupPerceptionOnNoEnemy
Definition: SCR_AIGroupPerception.c:5
SCR_AIGroupPerceptionOnEnemyDetectedFiltered
func SCR_AIGroupPerceptionOnEnemyDetectedFiltered
Definition: SCR_AIGroupPerception.c:11
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
ETargetCategory
ETargetCategory
Definition: ETargetCategory.c:12
m_Target
class SCR_AIPolar m_Target
SCR_AIOnTargetClusterStateDeleted
func SCR_AIOnTargetClusterStateDeleted
Definition: SCR_AIGroupPerception.c:2
m_Group
protected SCR_AIGroup m_Group
Definition: SCR_CallsignGroupComponent.c:10
func
func
Definition: SCR_AIThreatSystem.c:5
BaseTarget
Definition: BaseTarget.c:12
SCR_AIGroupPerceptionOnEnemyDetected
func SCR_AIGroupPerceptionOnEnemyDetected
Definition: SCR_AIGroupPerception.c:8
SCR_AIGroupTargetCluster
Definition: SCR_AIGroupTargetCluster.c:41
index
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Definition: SCR_DestructionSynchronizationComponent.c:17
SCR_AIGroup
Definition: SCR_AIGroup.c:68
EAITargetInfoCategory
EAITargetInfoCategory
Definition: SCR_AITargetInfo.c:1
SCR_AITargetClusterState
void SCR_AITargetClusterState(SCR_AIGroupTargetCluster cluster)
Definition: SCR_AITargetClusterState.c:38
EAITargetClusterState
EAITargetClusterState
Definition: SCR_AITargetClusterState.c:6
SCR_AIPolar
Definition: SCR_AIGroupTargetCluster.c:1
m_fAngle
float m_fAngle
Definition: SCR_AIGroupTargetCluster.c:36
SCR_AIGroupPerception
Definition: SCR_AIGroupPerception.c:13
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180