Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DefenderSpawnerComponent.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameScripted/ScriptWizard", description: "Component to be used with barrack compositions, handing unit spawning.", color: "0 0 255 255")]
3 {
4  [Attribute(defvalue: "{93291E72AC23930F}Prefabs/AI/Waypoints/AIWaypoint_Defend.et", UIWidgets.ResourceNamePicker, desc: "Default waypoint prefab", "et", category: "Defender Spawner")]
5  protected ResourceName m_sDefaultWaypointPrefab;
6 
7  [Attribute(defvalue: "75", params: "0 inf", desc: "Radius of default waypoint", "et", category: "Defender Spawner")]
8  protected float m_fDefaultWaypointCompletionRadius;
9 
10  [Attribute(defvalue :"Wedge", UIWidgets.Auto, desc: "Group formation created on rally point. Available formations are found on SCR_AIWorld entity", category: "Defender Spawner")]
11  protected string m_sExitFormation;
12 
13  //------------------------------------------------------------------------------------------------
15  ResourceName GetDefaultWaypointPrefab()
16  {
18  }
19 
20  //------------------------------------------------------------------------------------------------
22  float GetDefaultWaypointCompletionRadius()
23  {
25  }
26 
27  //------------------------------------------------------------------------------------------------
29  string GetExitFormation()
30  {
31  return m_sExitFormation;
32  }
33 }
34 
37 typedef ScriptInvokerBase<OnDefenderGroupSpawnedDelegate> OnDefenderGroupSpawnedInvoker;
38 
40 class SCR_DefenderSpawnerComponent : SCR_SlotServiceComponent
41 {
42  [Attribute(uiwidget: UIWidgets.SearchComboBox, category: "Defender Spawner", desc: "Allowed labels.", enums: ParamEnumArray.FromEnum(EEditableEntityLabel))]
43  protected ref array<EEditableEntityLabel> m_aAllowedLabels;
44 
45  [Attribute(uiwidget: UIWidgets.SearchComboBox, category: "Defender Spawner", desc: "Ignored labels.", enums: ParamEnumArray.FromEnum(EEditableEntityLabel))]
46  protected ref array<EEditableEntityLabel> m_aIgnoredLabels;
47 
48  [Attribute(defvalue: "300", uiwidget: UIWidgets.Auto, category: "Defender Spawner", desc: "Time in seconds between unit respawns")]
49  protected float m_fRespawnDelay;
50 
51  [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox, category: "Defender Spawner", desc: "Enable spawning"), RplProp()]
52  protected bool m_bEnableSpawning;
53 
54  [Attribute(defvalue: "30", params: "0 inf", desc: "Minimum distance to hostile players for spawner to work", "et")]
55  protected float m_fMinHostilePlayerDistance;
56 
57  [Attribute(desc: "Enables supplies usage.", category: "Supplies")]
58  protected bool m_bSuppliesConsumptionEnabled;
59 
60  [Attribute(params: "0 inf", desc: "Custom supplies value.", category: "Supplies")]
61  protected int m_iCustomSupplies;
62 
63  [Attribute(SCR_ECharacterRank.CORPORAL.ToString(), uiwidget: UIWidgets.ComboBox, enums: ParamEnumArray.FromEnum(SCR_ECharacterRank))]
64  protected SCR_ECharacterRank m_eMinimumRankForEnabling;
65 
66  protected RplComponent m_RplComponent;
67  protected SCR_CampaignSuppliesComponent m_SupplyComponent; //TODO: Temporary until supply sandbox rework
68  protected SCR_ResourceComponent m_ResourceComponent;
69  protected SCR_SpawnerAIGroupManagerComponent m_GroupSpawningManager;
70  protected WorldTimestamp m_fNextRespawnTime;
71  protected SCR_EntityCatalogEntry m_GroupEntry;
72  protected SCR_AIGroup m_AIgroup;
73  protected AIWaypoint m_Waypoint;
74  protected int m_iDespawnedGroupMembers;
75  protected ref array<ref Tuple3<SCR_AIActionBase, AIAgent, WorldTimestamp>> m_aUnitsOnMove = {};
76  protected ref array<ResourceName> m_aRefillQueue;
77  protected ref array<SCR_AIGroup> m_aPreviousGroups;
78  protected ref array<IEntity> m_aOldUnits;
79 
80  protected ref OnDefenderGroupSpawnedInvoker m_OnDefenderGroupSpawned;
81 
82  protected static const int SPAWN_CHECK_INTERVAL = 1000;
83  protected static const int SPAWN_GROUP_JOIN_TIMEOUT = 20; //Maximum time in seconds for spawned unit to reach waypoint, before it is assigned to group automatically
84  protected static const int SPAWN_RADIUS_MIN = Math.Pow(500, 2);
85  protected static const int SPAWN_RADIUS_MAX = Math.Pow(1000, 2);
86 
87  //------------------------------------------------------------------------------------------------
89  SCR_ECharacterRank GetMinimumRank()
90  {
91  return m_eMinimumRankForEnabling;
92  }
93 
94  //------------------------------------------------------------------------------------------------
98  bool UserRankCheck(IEntity user)
99  {
100  SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
101  if (!campaign)
102  return true;
103 
104  SCR_ECharacterRank rank = SCR_CharacterRankComponent.GetCharacterRank(user);
105 
106  return rank >= m_eMinimumRankForEnabling;
107  }
108 
109  //------------------------------------------------------------------------------------------------
111  OnDefenderGroupSpawnedInvoker GetOnDefenderGroupSpawned()
112  {
113  if (!m_OnDefenderGroupSpawned)
114  m_OnDefenderGroupSpawned = new OnDefenderGroupSpawnedInvoker();
115 
116  return m_OnDefenderGroupSpawned;
117  }
118 
119  //------------------------------------------------------------------------------------------------
122  void SetWaypoint(SCR_AIWaypoint wp)
123  {
124  if (wp)
125  m_Waypoint = wp;
126  }
127 
128  //------------------------------------------------------------------------------------------------
130  protected void AssignDefenderGroupDataFromOwningFaction()
131  {
132  SCR_Faction faction = SCR_Faction.Cast(GetFaction());
133  if (!faction)
134  return;
135 
136  SCR_EntityCatalog catalog = faction.GetFactionEntityCatalogOfType(EEntityCatalogType.GROUP);
137  if (!catalog)
138  {
139  Print("SCR_Faction Config lacks catalog of GROUP type. SCR_DefenderSpawnerComponent won't work without it", LogLevel.ERROR);
140  return;
141  }
142 
143  array<SCR_EntityCatalogEntry> entityEntries = {};
144  array<typename> includedDataClasses = {};
145  includedDataClasses.Insert(SCR_EntityCatalogSpawnerData); //~ The Data the entity must have
146 
147  catalog.GetFullFilteredEntityList(entityEntries, m_aAllowedLabels, m_aIgnoredLabels, includedDataClasses, null, false);
148 
149  //Only one entry of defender group should be used. Rest will be ditched, at least for now
150  if (!entityEntries.IsEmpty())
151  m_GroupEntry = entityEntries[0];
152  }
153 
154  //------------------------------------------------------------------------------------------------
157  void AssignSupplyComponent(notnull SCR_CampaignSuppliesComponent supplyComp)
158  {
159  m_SupplyComponent = supplyComp;
160 
161  //Resets timer, so new soldiers are spawned, if spawning is enabled.
162  m_fNextRespawnTime = null;
163  }
164 
165  //------------------------------------------------------------------------------------------------
167  SCR_CampaignSuppliesComponent GetSpawnerSupplyComponent()
168  {
169  return m_SupplyComponent;
170  }
171 
172  //------------------------------------------------------------------------------------------------
174  float GetSpawnerSupplies()
175  {
176  if (!m_ResourceComponent)
177  return m_iCustomSupplies;
178 
179  SCR_ResourceConsumer consumer = m_ResourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
180 
181  if (!consumer)
182  return 0.0;
183 
184  if (m_RplComponent && !m_RplComponent.IsProxy())
185  GetGame().GetResourceGrid().UpdateInteractor(consumer);
186 
187  return consumer.GetAggregatedResourceValue();
188  }
189 
190  //------------------------------------------------------------------------------------------------
193  void AddSupplies(float value)
194  {
196  {
197  SCR_ResourceInteractor interactor;
198 
199  if (value >= 0)
200  {
201  SCR_ResourceGenerator generator = m_ResourceComponent.GetGenerator(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
202 
203  if (!generator)
204  return;
205 
206  interactor = generator;
207 
208  generator.RequestGeneration(value);
209  }
210  else
211  {
212  SCR_ResourceConsumer consumer = m_ResourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
213 
214  if (!consumer)
215  return;
216 
217  interactor = consumer;
218 
219  consumer.RequestConsumtion(-value);
220  }
221  }
222 
224  if (m_iCustomSupplies < 0)
225  m_iCustomSupplies = 0;
226 
227  Replication.BumpMe();
228  }
229 
230  //------------------------------------------------------------------------------------------------
232  bool IsSpawningEnabled()
233  {
234  return m_bEnableSpawning;
235  }
236 
237  //------------------------------------------------------------------------------------------------
241  void EnableSpawning(bool enable, int playerID)
242  {
243  SCR_PlayerController playerController = SCR_PlayerController.Cast(GetGame().GetPlayerManager().GetPlayerController(playerID));
244  if (!playerController)
245  return;
246 
247  SCR_ChimeraCharacter chimeraCharacter = SCR_ChimeraCharacter.Cast(playerController.GetControlledEntity());
248  if (!chimeraCharacter || chimeraCharacter.GetFaction() != GetFaction())
249  return;
250 
251  if (!UserRankCheck(chimeraCharacter))
252  return;
253 
254  m_bEnableSpawning = enable;
255  Replication.BumpMe();
256  }
257 
258  //------------------------------------------------------------------------------------------------
260  bool IsProxy()
261  {
262  return (m_RplComponent && m_RplComponent.IsProxy());
263  }
264 
265  //------------------------------------------------------------------------------------------------
269  protected void SpawnUnit(ResourceName unitResource, bool consumeSupplies = true)
270  {
271  if (IsProxy())
272  return;
273 
274  if (!m_GroupEntry || !m_AIgroup || !m_AIgroup.m_aUnitPrefabSlots || m_AIgroup.m_aUnitPrefabSlots.IsEmpty())
275  return;
276 
277  AIWorld aiWorld = GetGame().GetAIWorld();
278  if (!aiWorld)
279  return;
280 
281  SCR_EntityCatalogSpawnerData entityData = SCR_EntityCatalogSpawnerData.Cast(m_GroupEntry.GetEntityDataOfType(SCR_EntityCatalogSpawnerData));
282  if (!entityData)
283  return;
284 
285  SCR_EntitySpawnerSlotComponent slot = GetFreeSlot();
286  if (!slot)
287  return;
288 
289  // Calculate unit spawn cost from overall group member count
290  int spawnCost;
291  if (m_AIgroup.m_aUnitPrefabSlots.Count() > 0)
292  spawnCost = entityData.GetSupplyCost() / m_AIgroup.m_aUnitPrefabSlots.Count();
293 
294  EntitySpawnParams spawnParams = new EntitySpawnParams();
295  spawnParams.TransformMode = ETransformMode.WORLD;
296  slot.GetOwner().GetTransform(spawnParams.Transform);
297  Resource res = Resource.Load(unitResource);
298 
299  IEntity ai = GetGame().SpawnEntityPrefab(res, null, spawnParams);
300  if (!ai)
301  return;
302 
303  if (m_aRefillQueue)
304  m_aRefillQueue.RemoveItem(unitResource);
305 
306  // consume supplies, if their consumption is enabled and revents spawning, if there is not enough supplies available.
307  if (consumeSupplies && m_bSuppliesConsumptionEnabled && GetSpawnerSupplies() >= spawnCost)
308  AddSupplies(-spawnCost);
309 
310  AIControlComponent control = AIControlComponent.Cast(ai.FindComponent(AIControlComponent));
311  if (control)
312  control.ActivateAI();
313 
314  AIAgent agent = control.GetAIAgent();
315  if (!agent)
316  return;
317 
318  //Remove group waypoint to reduce performance impact due to new members being added to it.
319  if (m_Waypoint)
320  m_AIgroup.RemoveWaypoint(m_Waypoint);
321 
323 
324  SCR_EntityLabelPointComponent rallyPointComponent = slot.GetRallyPoint();
325  if (rallyPointComponent && prefabData)
326  {
327  IEntity rallyPointEntity = rallyPointComponent.GetOwner();
328 
329  // Create temporary group for unit and later rally point waypoint
330  SCR_AIUtilityComponent utilityComponent = SCR_AIUtilityComponent.Cast(agent.FindComponent(SCR_AIUtilityComponent));
331 
332  vector rpTransform[4];
333  rallyPointEntity.GetWorldTransform(rpTransform);
334 
335  AIFormationDefinition formationDefiniton = aiWorld.GetFormation(prefabData.GetExitFormation());
336  vector posLocal;
337 
338  if (m_aUnitsOnMove && formationDefiniton)
339  {
340  vector formationOffset = 0.5 * formationDefiniton.GetOffsetPosition(m_aUnitsOnMove.Count());
341  posLocal = posLocal + formationOffset;
342  }
343 
344  vector posWorld = posLocal.Multiply4(rpTransform);
345 
346  SCR_AIMoveIndividuallyBehavior moveBehavior = new SCR_AIMoveIndividuallyBehavior(utilityComponent, null, posWorld, SCR_AIActionBase.PRIORITY_BEHAVIOR_MOVE, SCR_AIActionBase.PRIORITY_LEVEL_GAMEMASTER, radius: 0.5);
347  if (!moveBehavior)
348  {
349  m_AIgroup.AddAgent(agent);
350  return;
351  }
352 
353  utilityComponent.AddAction(moveBehavior);
354 
355  if (!m_aUnitsOnMove)
356  m_aUnitsOnMove = {};
357 
358  ChimeraWorld world = GetOwner().GetWorld();
359 
360  m_aUnitsOnMove.Insert(new Tuple3<SCR_AIActionBase, AIAgent, WorldTimestamp>(moveBehavior, agent, world.GetServerTimestamp()));
361 
362  moveBehavior.m_OnActionCompleted.Insert(OnMoveFinished);
363 
365  if (!charController)
366  return;
367 
368  charController.m_OnPlayerDeathWithParam.Insert(OnMovingCharacterDeath);
369  }
370  else
371  {
372  // Rally point not found, add spawned ai directly to controlled group
373  m_AIgroup.AddAgent(agent);
374  }
375  }
376 
377  //------------------------------------------------------------------------------------------------
378  protected void OnMovingCharacterDeath(SCR_CharacterControllerComponent characterController, IEntity killerEntity, Instigator killer)
379  {
380  if (!characterController)
381  return;
382 
383  IEntity character = characterController.GetOwner();
384  if (!character)
385  return;
386 
387  foreach (int index, Tuple3<SCR_AIActionBase, AIAgent, WorldTimestamp> AIaction : m_aUnitsOnMove)
388  {
389  if (AIaction.param2.GetControlledEntity() != character)
390  continue;
391 
392  m_aUnitsOnMove.Remove(index);
393  break;
394  }
395 
396  if (m_aUnitsOnMove.IsEmpty())
397  m_aUnitsOnMove = null;
398  }
399 
400  //------------------------------------------------------------------------------------------------
401  protected void OnMoveFinished(SCR_AIActionBase action)
402  {
403  if (!m_aUnitsOnMove)
404  return;
405 
406  AIAgent agent;
407  int groupIndex;
408 
409  foreach (int i, Tuple3<SCR_AIActionBase, AIAgent, WorldTimestamp> AIaction : m_aUnitsOnMove)
410  {
411  if (AIaction.param1 != action)
412  continue;
413 
414  agent = AIaction.param2;
415  groupIndex = i;
416  break;
417  }
418 
419  SCR_ChimeraCharacter agentEntity = SCR_ChimeraCharacter.Cast(agent.GetControlledEntity());
420  if (!agentEntity)
421  return;
422 
424  if (charController)
425  charController.m_OnPlayerDeathWithParam.Remove(OnMovingCharacterDeath);
426 
427  if (!agent || !m_AIgroup)
428  {
429  if (!m_aOldUnits)
430  m_aOldUnits = {};
431 
432  m_aOldUnits.Insert(agentEntity);
433 
434  return;
435  }
436 
437  if (agentEntity.GetFaction() == m_AIgroup.GetFaction())
438  m_AIgroup.AddAgent(agent);
439 
440  m_aUnitsOnMove.Remove(groupIndex);
441  if (m_aUnitsOnMove.IsEmpty())
442  m_aUnitsOnMove = null;
443 
444  if ((m_AIgroup.GetAgentsCount() == m_AIgroup.m_aUnitPrefabSlots.Count()) || (!m_aUnitsOnMove))
445  m_AIgroup.AddWaypoint(GetWaypoint());
446  }
447 
448  //------------------------------------------------------------------------------------------------
450  SCR_EntitySpawnerSlotComponent GetFreeSlot()
451  {
452  foreach (SCR_EntitySpawnerSlotComponent slot : m_aChildSlots)
453  {
454  if (!slot.IsOccupied())
455  return slot;
456  }
457 
458  foreach (SCR_EntitySpawnerSlotComponent slot : m_aNearSlots)
459  {
460  if (!slot.IsOccupied())
461  return slot;
462  }
463 
464  return null;
465  }
466 
467  //------------------------------------------------------------------------------------------------
469  protected void ReinforceGroup()
470  {
471  array<ResourceName> unitPrefabs = {};
472  unitPrefabs.Copy(m_AIgroup.m_aUnitPrefabSlots);
473 
474  array<AIAgent> outAgents = {};
475  m_AIgroup.GetAgents(outAgents);
476 
477  foreach (AIAgent agent : outAgents)
478  {
479  IEntity controlledEntity = agent.GetControlledEntity();
480  if (!controlledEntity)
481  return;
482 
483  EntityPrefabData prefabData = controlledEntity.GetPrefabData();
484  if (!prefabData)
485  return;
486 
487  ResourceName aiResource = prefabData.GetPrefabName();
488  unitPrefabs.RemoveItem(aiResource);
489  }
490 
491  IEntity ent;
492  if (m_aUnitsOnMove)
493  {
494  foreach (Tuple3<SCR_AIActionBase, AIAgent, WorldTimestamp> groups : m_aUnitsOnMove)
495  {
496  if (groups.param2)
497  ent = groups.param2.GetControlledEntity();
498 
499  if (!ent)
500  continue;
501 
502  EntityPrefabData prefabData = ent.GetPrefabData();
503  if (!prefabData)
504  continue;
505 
506  unitPrefabs.RemoveItem(prefabData.GetPrefabName());
507  }
508  }
509 
510  m_aRefillQueue = unitPrefabs;
511  }
512 
513  //------------------------------------------------------------------------------------------------
516  protected void SpawnGroup()
517  {
518  if (IsProxy())
519  return;
520 
521  if (!m_GroupEntry)
522  return;
523 
524  SCR_EntityCatalogSpawnerData entityData = SCR_EntityCatalogSpawnerData.Cast(m_GroupEntry.GetEntityDataOfType(SCR_EntityCatalogSpawnerData));
525  if (!entityData)
526  return;
527 
528  float supplies = GetSpawnerSupplies();
529  int spawnCost = entityData.GetSupplyCost();
530  if (supplies < entityData.GetSupplyCost() && m_bSuppliesConsumptionEnabled)
531  return;
532 
533  SCR_EntitySpawnerSlotComponent slot = GetFreeSlot();
534  if (!slot)
535  return;
536 
537  EntitySpawnParams params = new EntitySpawnParams();
538  params.TransformMode = ETransformMode.WORLD;
539  slot.GetOwner().GetTransform(params.Transform);
540 
541  Resource res = Resource.Load(m_GroupEntry.GetPrefab());
542  if (!res.IsValid())
543  return;
544 
545  SCR_AIGroup.IgnoreSpawning(true);
546  SCR_AIGroup group = SCR_AIGroup.Cast(GetGame().SpawnEntityPrefab(res, null, params));
547  if (!group || group.m_aUnitPrefabSlots.Count() == 0)
548  {
549  SCR_AIGroup.IgnoreSpawning(false);
550  return;
551  }
552 
553  m_AIgroup = group;
554 
555  if (m_OnDefenderGroupSpawned)
556  m_OnDefenderGroupSpawned.Invoke(this, group);
557 
558  ReinforceGroup();
559  }
560 
561  //------------------------------------------------------------------------------------------------
562  protected AIWaypoint GetWaypoint()
563  {
564  if (m_Waypoint)
565  return m_Waypoint;
566 
567  SCR_EntitySpawnerSlotComponent slot = GetFreeSlot();
568  if (!slot)
569  return null;
570 
571  EntitySpawnParams params = new EntitySpawnParams();
572  params.TransformMode = ETransformMode.WORLD;
573 
574  SCR_EntityLabelPointComponent rallyPoint = slot.GetRallyPoint();
575  //If rally point is available, create waypoint on it, otherwise use slot position
576  if (rallyPoint)
577  rallyPoint.GetOwner().GetTransform(params.Transform);
578  else
579  slot.GetOwner().GetTransform(params.Transform);
580 
582  if (!prefabData)
583  return null;
584 
585  Resource wpRes = Resource.Load(prefabData.GetDefaultWaypointPrefab());
586  if (!wpRes.IsValid())
587  return null;
588 
589  m_Waypoint = SCR_AIWaypoint.Cast(GetGame().SpawnEntityPrefabLocal(wpRes, null, params));
590  if (!m_Waypoint)
591  return null;
592 
593  m_Waypoint.SetCompletionRadius(prefabData.GetDefaultWaypointCompletionRadius());
594 
595  return m_Waypoint;
596  }
597 
598  //------------------------------------------------------------------------------------------------
600  protected SCR_EDefenderSpawnerState GetPlayerDistanceState()
601  {
602  array<int> players = {};
603  GetGame().GetPlayerManager().GetPlayers(players);
604 
605  float spawnDistanceSq = Math.Clamp(Math.Pow(GetGame().GetViewDistance() * 0.5, 2), SPAWN_RADIUS_MAX, SPAWN_RADIUS_MIN);
606  float despawnDistanceSq = Math.Clamp(Math.Pow(GetGame().GetViewDistance() * 0.5, 2), SPAWN_RADIUS_MIN, SPAWN_RADIUS_MAX);
607  float minSpawnDistanceSq = m_fMinHostilePlayerDistance * m_fMinHostilePlayerDistance; //Minimum range for hostile players in vicinity
608 
609  SCR_ChimeraCharacter playerEntity;
610  float dist;
611  vector origin = GetOwner().GetOrigin();
612 
613  SCR_EDefenderSpawnerState outState = SCR_EDefenderSpawnerState.DEFENDERS_DESPAWN;
614 
615  foreach (int player : players)
616  {
617  playerEntity = SCR_ChimeraCharacter.Cast(GetGame().GetPlayerManager().GetPlayerControlledEntity(player));
618  if (!playerEntity)
619  continue;
620 
621  dist = vector.DistanceSq(playerEntity.GetOrigin(), origin);
622 
623  if (outState == SCR_EDefenderSpawnerState.DEFENDERS_DESPAWN) //Do this check only if outstate is set to Despawn, otherwise it is not necessary to repeat it
624  {
625  if (dist < spawnDistanceSq) //If player is withing the range, enable defenders
626  {
627  outState = SCR_EDefenderSpawnerState.DEFENDERS_ENABLED;
628  }
629  else //If player is not within range, set to DEFENDER_DESPAWN and skip to next
630  {
631  outState = SCR_EDefenderSpawnerState.DEFENDERS_DESPAWN;
632  continue;
633  }
634  }
635 
636  if (dist < minSpawnDistanceSq && playerEntity.GetFaction() != GetFaction()) //if player in vicinity is hostile and is not in minimum distance, pause spawning
637  {
638  outState = SCR_EDefenderSpawnerState.DEFENDERS_PAUSED_SPAWN;
639  break;
640  }
641  }
642 
643  return outState;
644  }
645 
646  //------------------------------------------------------------------------------------------------
648  protected void HandleGroup()
649  {
650  ChimeraWorld world = GetOwner().GetWorld();
651  WorldTimestamp replicationTime = world.GetServerTimestamp();
652 
653  AIWorld aiWorld = GetGame().GetAIWorld();
654  if (!aiWorld)
655  return;
656 
657  //If another Ai would be over limit, stop requesting and prevent players from enabling it again.
658  if ((aiWorld.GetCurrentAmountOfLimitedAIs() + 1) >= aiWorld.GetAILimit())
659  {
660  if (m_bEnableSpawning)
661  {
662  m_bEnableSpawning = false; //disable spawner
663  Replication.BumpMe();
664 
665  m_GroupSpawningManager.SetIsAtAILimit(true); //block requesting action
666  }
667 
668  return;
669  }
670 
671  SCR_EDefenderSpawnerState distanceState = GetPlayerDistanceState();
672 
673  if (m_bEnableSpawning && (distanceState == SCR_EDefenderSpawnerState.DEFENDERS_ENABLED))
674  {
675  // Add any stray or stuck units to group
676  if (m_aUnitsOnMove)
677  {
678  int count = m_aUnitsOnMove.Count()-1;
679  for (int i = count; i >= 0; i--)
680  {
681  if (!m_aUnitsOnMove[i].param2)
682  {
683  m_aUnitsOnMove.Remove(i);
684  continue;
685  }
686 
687  if (!m_aUnitsOnMove[i].param3.PlusSeconds(SPAWN_GROUP_JOIN_TIMEOUT).GreaterEqual(replicationTime))
688  OnMoveFinished(m_aUnitsOnMove[i].param1);
689  }
690  }
691 
692  // Reinforce existing or create new defender group. Also handles respawning of despawned defenders
693  if (m_iDespawnedGroupMembers > 0 || replicationTime.Greater(m_fNextRespawnTime))
694  {
695  m_fNextRespawnTime = replicationTime.PlusSeconds(m_fRespawnDelay);
696  if (m_AIgroup && (m_AIgroup.m_aUnitPrefabSlots.Count() != m_AIgroup.GetAgentsCount()))
697  ReinforceGroup();
698 
699  if (!m_AIgroup)
700  SpawnGroup();
701  }
702 
703  //Spawn queued units
704  if (m_aRefillQueue && !m_aRefillQueue.IsEmpty())
705  {
706  if (m_iDespawnedGroupMembers > 0)
707  {
708  SpawnUnit(m_aRefillQueue[0], false);
709  m_iDespawnedGroupMembers--;
710  }
711  else
712  {
713  SpawnUnit(m_aRefillQueue[0]);
714  }
715  }
716  }
717 
718  //Despawn units that are too far away from players
719  if (distanceState == SCR_EDefenderSpawnerState.DEFENDERS_DESPAWN)
720  {
721  if (m_AIgroup)
722  {
723  m_iDespawnedGroupMembers = m_AIgroup.GetAgentsCount();
724  SCR_EntityHelper.DeleteEntityAndChildren(m_AIgroup);
725  }
726 
727  //If leftover groups from previous owners remains alive, they will be despawned
728  if (m_aPreviousGroups)
729  {
730  foreach (SCR_AIGroup aiGroup : m_aPreviousGroups)
731  {
732  SCR_EntityHelper.DeleteEntityAndChildren(aiGroup);
733  }
734 
735  m_aPreviousGroups = null;
736  }
737 
738  //Delete units from previous owners that were spawning in process of faction change. (edge case, but might happen)
739  if (m_aOldUnits)
740  {
741  int index = m_aOldUnits.Count()-1;
742  for (index; index >= 0; index--)
743  {
744  SCR_EntityHelper.DeleteEntityAndChildren(m_aOldUnits[index]);
745  }
746 
747  m_aOldUnits = null;
748  }
749 
750  //Despawn any units that are currently walking to RP
751  if (m_aUnitsOnMove)
752  {
753  foreach (Tuple3<SCR_AIActionBase, AIAgent, WorldTimestamp> groupWaypoint : m_aUnitsOnMove)
754  {
755  SCR_EntityHelper.DeleteEntityAndChildren(groupWaypoint.param2.GetControlledEntity());
756  m_iDespawnedGroupMembers++;
757  }
758 
759  m_aUnitsOnMove = null;
760  }
761  }
762  }
763 
764  //------------------------------------------------------------------------------------------------
765  protected override void OnFactionChanged(FactionAffiliationComponent owner, Faction previousFaction, Faction faction)
766  {
767  //if there is already a group from current faction, cache it for despawn
768  if (m_AIgroup)
769  {
770  if (!m_aPreviousGroups)
771  m_aPreviousGroups = {};
772 
773  m_aPreviousGroups.Insert(m_AIgroup);
774  m_AIgroup = null;
775  }
776 
777  m_GroupEntry = null;
778  AssignDefenderGroupDataFromOwningFaction();
779  }
780 
781  //------------------------------------------------------------------------------------------------
782  protected override void EOnInit(IEntity owner)
783  {
784  if (!GetGame().InPlayMode())
785  return;
786 
787  super.EOnInit(owner);
788 
789  m_ResourceComponent = SCR_ResourceComponent.FindResourceComponent(owner);
790  m_RplComponent = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
791  if (!m_RplComponent)
792  return;
793 
794  BaseGameMode gameMode = GetGame().GetGameMode();
795  if (!gameMode)
796  return;
797 
798  m_GroupSpawningManager = SCR_SpawnerAIGroupManagerComponent.Cast(gameMode.FindComponent(SCR_SpawnerAIGroupManagerComponent));
799  if (!m_GroupSpawningManager)
800  {
801  Print("SCR_DefenderSpawnerComponent requires SCR_SpawnerAIGroupManagerComponent attached to gamemode to work properly!", LogLevel.ERROR);
802  return;
803  }
804 
805  if (IsProxy())
806  return;
807 
808  //Setup group handling (spawning and refilling). This delay also prevents potential JIP replication error on clients
809  GetGame().GetCallqueue().CallLater(HandleGroup, SPAWN_CHECK_INTERVAL, true);
810  }
811 
812  //------------------------------------------------------------------------------------------------
813  protected override void OnPostInit(IEntity owner)
814  {
815  if (SCR_Global.IsEditMode())
816  return;
817 
818  super.OnPostInit(owner);
819 
820  SetEventMask(owner, EntityEvent.INIT);
821  }
822 
823  //------------------------------------------------------------------------------------------------
824  // destructor
826  {
827  if (m_AIgroup)
828  SCR_EntityHelper.DeleteEntityAndChildren(m_AIgroup);
829 
830  //Delete units in process of spawning
831  if (m_aUnitsOnMove)
832  {
833  foreach (Tuple3<SCR_AIActionBase, AIAgent, WorldTimestamp> groupWaypoint : m_aUnitsOnMove)
834  {
835  if (!groupWaypoint.param2)
836  continue;
837 
838  SCR_EntityHelper.DeleteEntityAndChildren(groupWaypoint.param2.GetControlledEntity());
839  }
840  }
841 
842  //Delete units from previous owners
843  if (m_aPreviousGroups)
844  {
845  int index = m_aPreviousGroups.Count()-1;
846  for (index; index >= 0; index--)
847  {
848  SCR_EntityHelper.DeleteEntityAndChildren(m_aPreviousGroups[index]);
849  }
850  }
851 
852  //Delete units from previous owners that were spawning in process of faction change. (edge case, but might happen)
853  if (m_aOldUnits)
854  {
855  int index = m_aOldUnits.Count()-1;
856  for (index; index >= 0; index--)
857  {
858  SCR_EntityHelper.DeleteEntityAndChildren(m_aOldUnits[index]);
859  }
860  }
861 
862  GetGame().GetCallqueue().Remove(HandleGroup);
863  }
864 }
865 
866 enum SCR_EDefenderSpawnerState
867 {
870  DEFENDERS_DESPAWN
871 }
ChimeraWorld
Definition: ChimeraWorld.c:12
EEditableEntityLabel
EEditableEntityLabel
Definition: EEditableEntityLabel.c:1
SCR_PlayerController
Definition: SCR_PlayerController.c:31
SCR_EntityHelper
Definition: SCR_EntityHelper.c:1
OnDefenderGroupSpawnedDelegate
func OnDefenderGroupSpawnedDelegate
Definition: SCR_DefenderSpawnerComponent.c:36
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
SCR_AIActionBase
Definition: SCR_AIAction.c:1
SCR_DefenderSpawnerComponent
Service providing group of defenders defined in faction. Requires SCR_EnableDefenderAction on ActionM...
Definition: SCR_DefenderSpawnerComponent.c:40
m_aIgnoredLabels
protected ref array< EEditableEntityLabel > m_aIgnoredLabels
Definition: SCR_CatalogEntitySpawnerComponent.c:77
DEFENDERS_PAUSED_SPAWN
SCR_DefenderSpawnerComponent DEFENDERS_PAUSED_SPAWN
RplProp
SCR_RplTestEntityClass RplProp
Used for handling entity spawning requests for SCR_CatalogEntitySpawnerComponent and inherited classe...
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
SCR_AIWaypoint
Definition: SCR_AIWaypoint.c:5
EEntityCatalogType
EEntityCatalogType
Definition: EEntityCatalogType.c:4
SCR_ECharacterRank
SCR_ECharacterRank
Definition: SCR_CharacterRankComponent.c:305
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
func
func
Definition: SCR_AIThreatSystem.c:5
SCR_CharacterControllerComponent
Definition: SCR_CharacterControllerComponent.c:35
GetPlayerController
proto external PlayerController GetPlayerController()
Definition: SCR_PlayerDeployMenuHandlerComponent.c:307
Instigator
Definition: Instigator.c:6
SCR_CharacterRankComponent
void SCR_CharacterRankComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
Definition: SCR_CharacterRankComponent.c:209
m_aChildSlots
protected ref array< SCR_EntitySpawnerSlotComponent > m_aChildSlots
Definition: SCR_SlotService.c:18
SCR_CampaignSuppliesComponent
void SCR_CampaignSuppliesComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
Definition: SCR_CampaignSuppliesComponent.c:327
SCR_DefenderSpawnerComponentClass
Definition: SCR_DefenderSpawnerComponent.c:2
SCR_GameModeCampaign
void SCR_GameModeCampaign(IEntitySource src, IEntity parent)
Definition: SCR_GameModeCampaign.c:1927
m_iCustomSupplies
protected int m_iCustomSupplies
Definition: SCR_CatalogEntitySpawnerComponent.c:95
m_sExitFormation
protected string m_sExitFormation
Definition: SCR_DefenderSpawnerComponent.c:9
Attribute
typedef Attribute
Post-process effect of scripted camera.
m_fDefaultWaypointCompletionRadius
protected float m_fDefaultWaypointCompletionRadius
Definition: SCR_DefenderSpawnerComponent.c:6
OnDefenderGroupSpawnedInvoker
ScriptInvokerBase< OnDefenderGroupSpawnedDelegate > OnDefenderGroupSpawnedInvoker
Definition: SCR_DefenderSpawnerComponent.c:37
m_Waypoint
protected AIWaypoint m_Waypoint
Definition: SCR_AmbientPatrolSpawnPointComponent.c:48
m_aAllowedLabels
protected ref array< EEditableEntityLabel > m_aAllowedLabels
Definition: SCR_CatalogEntitySpawnerComponent.c:74
EResourceType
EResourceType
Definition: SCR_ResourceContainer.c:1
m_ResourceComponent
protected SCR_ResourceComponent m_ResourceComponent
Definition: SCR_CampaignBuildingProviderComponent.c:51
SCR_EntityCatalogSpawnerData
Definition: SCR_EntityCatalogSpawnerData.c:5
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
SCR_AIMoveIndividuallyBehavior
Definition: SCR_AIMoveBehavior.c:30
SCR_SlotServiceComponentClass
Definition: SCR_SlotService.c:1
Faction
Definition: Faction.c:12
m_RplComponent
protected RplComponent m_RplComponent
Definition: SCR_CampaignBuildingManagerComponent.c:42
index
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Definition: SCR_DestructionSynchronizationComponent.c:17
SCR_Global
Definition: Functions.c:6
SCR_EntityCatalog
Definition: SCR_EntityCatalog.c:181
SCR_AIGroup
Definition: SCR_AIGroup.c:68
DEFENDERS_ENABLED
SCR_DefenderSpawnerComponent DEFENDERS_ENABLED
params
Configs ServerBrowser KickDialogs params
Definition: SCR_NotificationSenderComponent.c:24
m_bSuppliesConsumptionEnabled
protected bool m_bSuppliesConsumptionEnabled
Definition: SCR_CatalogEntitySpawnerComponent.c:92
GetFaction
SCR_CampaignFaction GetFaction()
Definition: SCR_CampaignMobileAssemblyStandaloneComponent.c:351
m_aNearSlots
protected ref array< SCR_EntitySpawnerSlotComponent > m_aNearSlots
Definition: SCR_SlotService.c:19
SCR_Faction
Definition: SCR_Faction.c:6
SCR_EntityCatalogEntry
Definition: SCR_EntityCatalogEntry.c:5
SCR_ResourceGenerator
Definition: SCR_ResourceGenerator.c:79
m_sDefaultWaypointPrefab
protected ResourceName m_sDefaultWaypointPrefab
Definition: SCR_AmbientPatrolSpawnPointComponent.c:6
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180
EResourceGeneratorID
EResourceGeneratorID
Definition: SCR_ResourceGenerator.c:1