Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
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")]
6
7 [Attribute(defvalue: "75", params: "0 inf", desc: "Radius of default waypoint", "et", category: "Defender Spawner")]
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 //------------------------------------------------------------------------------------------------
19
20 //------------------------------------------------------------------------------------------------
26
27 //------------------------------------------------------------------------------------------------
30 {
31 return m_sExitFormation;
32 }
33}
34
37typedef ScriptInvokerBase<OnDefenderGroupSpawnedDelegate> OnDefenderGroupSpawnedInvoker;
38
40class 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")]
56
57 [Attribute(desc: "Enables supplies usage.", category: "Supplies")]
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;
73 protected AIWaypoint m_Waypoint;
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
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 {
92 }
93
94 //------------------------------------------------------------------------------------------------
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 //------------------------------------------------------------------------------------------------
118
119 //------------------------------------------------------------------------------------------------
123 {
124 if (wp)
125 m_Waypoint = wp;
126 }
127
128 //------------------------------------------------------------------------------------------------
131 {
132 SCR_Faction faction = SCR_Faction.Cast(GetFaction());
133 if (!faction)
134 return;
135
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 //------------------------------------------------------------------------------------------------
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 //------------------------------------------------------------------------------------------------
171
172 //------------------------------------------------------------------------------------------------
175 {
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)
226
227 Replication.BumpMe();
228 }
229
230 //------------------------------------------------------------------------------------------------
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
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
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
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
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)
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 {
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
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
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
546 SCR_AIGroup group = SCR_AIGroup.Cast(GetGame().SpawnEntityPrefab(res, null, params));
547 if (!group || group.m_aUnitPrefabSlots.Count() == 0)
548 {
550 return;
551 }
552
553 m_AIgroup = group;
554
556 m_OnDefenderGroupSpawned.Invoke(this, group);
557
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
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 {
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))
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()))
698
699 if (!m_AIgroup)
700 SpawnGroup();
701 }
702
703 //Spawn queued units
704 if (m_aRefillQueue && !m_aRefillQueue.IsEmpty())
705 {
707 {
708 SpawnUnit(m_aRefillQueue[0], false);
710 }
711 else
712 {
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
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 {
754 {
755 SCR_EntityHelper.DeleteEntityAndChildren(groupWaypoint.param2.GetControlledEntity());
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 {
772
774 m_AIgroup = null;
775 }
776
777 m_GroupEntry = null;
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));
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 {
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 {
834 {
835 if (!groupWaypoint.param2)
836 continue;
837
838 SCR_EntityHelper.DeleteEntityAndChildren(groupWaypoint.param2.GetControlledEntity());
839 }
840 }
841
842 //Delete units from previous owners
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
866enum SCR_EDefenderSpawnerState
867{
870 DEFENDERS_DESPAWN
871}
EEditableEntityLabel
EEntityCatalogType
ArmaReforgerScripted GetGame()
Definition game.c:1398
SCR_CacheNoteComponentClass ScriptComponentClass RplProp()] protected ref array< string > m_aLines
SCR_CampaignFaction GetFaction()
void SCR_CampaignSuppliesComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
void SCR_CharacterRankComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
SCR_CharacterSoundComponentClass GetComponentData()
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
SCR_DefenderSpawnerComponent DEFENDERS_ENABLED
SCR_DefenderSpawnerComponent DEFENDERS_PAUSED_SPAWN
ScriptInvokerBase< OnDefenderGroupSpawnedDelegate > OnDefenderGroupSpawnedInvoker
func OnDefenderGroupSpawnedDelegate
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
void SCR_GameModeCampaign(IEntitySource src, IEntity parent)
EResourceGeneratorID
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
ref array< SCR_EntitySpawnerSlotComponent > m_aNearSlots
ref array< SCR_EntitySpawnerSlotComponent > m_aChildSlots
proto external Managed FindComponent(typename typeName)
proto external vector GetOrigin()
proto external void GetWorldTransform(out vector mat[])
See IEntity::GetTransform.
proto external BaseWorld GetWorld()
proto external EntityPrefabData GetPrefabData()
Definition Math.c:13
Main replication API.
Definition Replication.c:14
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
static void IgnoreSpawning(bool ignore)
ref OnPlayerDeathWithParamInvoker m_OnPlayerDeathWithParam
Service providing group of defenders defined in faction. Requires SCR_EnableDefenderAction on ActionM...
SCR_EntitySpawnerSlotComponent GetFreeSlot()
SCR_CampaignSuppliesComponent m_SupplyComponent
OnDefenderGroupSpawnedInvoker GetOnDefenderGroupSpawned()
void OnMovingCharacterDeath(SCR_CharacterControllerComponent characterController, IEntity killerEntity, Instigator killer)
SCR_CampaignSuppliesComponent GetSpawnerSupplyComponent()
void AssignSupplyComponent(notnull SCR_CampaignSuppliesComponent supplyComp)
ref array< EEditableEntityLabel > m_aAllowedLabels
void OnMoveFinished(SCR_AIActionBase action)
void ReinforceGroup()
Refills AI's in defender group.
SCR_EDefenderSpawnerState GetPlayerDistanceState()
ref OnDefenderGroupSpawnedInvoker m_OnDefenderGroupSpawned
void EnableSpawning(bool enable, int playerID)
ref array< EEditableEntityLabel > m_aIgnoredLabels
void AssignDefenderGroupDataFromOwningFaction()
Set Defender group data from Entity catalog on owning faction.
override void OnPostInit(IEntity owner)
override void OnFactionChanged(FactionAffiliationComponent owner, Faction previousFaction, Faction faction)
void HandleGroup()
Manages automatic group spawning.
bool IsSpawningEnabled()
Returns true if spawner is currently activated.
ref array< ref Tuple3< SCR_AIActionBase, AIAgent, WorldTimestamp > > m_aUnitsOnMove
SCR_SpawnerAIGroupManagerComponent m_GroupSpawningManager
void SpawnUnit(ResourceName unitResource, bool consumeSupplies=true)
float GetSpawnerSupplies()
Get available supplies.
Get supply cost of spawning Entity return Supply cost *int GetSupplyCost()
SCR_EntityCatalog GetFactionEntityCatalogOfType(EEntityCatalogType catalogType, bool printNotFound=true)
static bool IsEditMode()
Definition Functions.c:1566
SCR_ResourceGenerationResponse RequestGeneration(float resourceAmount, SCR_ResourceGenerator generator=null)
void EntitySpawnParams()
Definition gameLib.c:130
IEntity GetOwner()
Owner entity of the fuel tank.
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
SCR_FieldOfViewSettings Attribute
EntityEvent
Various entity events.
Definition EntityEvent.c:14
proto external PlayerController GetPlayerController()
void Tuple3(T1 p1, T2 p2, T3 p3)
Definition tuple.c:95
T3 param3
Definition tuple.c:93
T2 param2
Definition tuple.c:92
Tuple param1