Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_GroupsManagerComponent.c
Go to the documentation of this file.
1typedef set<Faction> FactionHolder;
2
3[EntityEditorProps(category: "GameScripted/Groups", description: "Player groups manager, attach to game mode entity!.")]
7
9{
10 [Attribute()]
11 protected ResourceName m_sDefaultGroupPrefab;
12
13 [Attribute("1000")]
15
16 [Attribute("38000")]
18
19 [Attribute("54000")]
21
22 [Attribute("1", desc:"If checked, the added agent will tune the radio to the group frequency")]
24
25 [Attribute("1", desc:"If checked, the player will tune the radio to the group frequency when is spawn")]
27
28 [Attribute("Flags", UIWidgets.ResourcePickerThumbnail, "Flag icon of this particular group.", params: "edds")]
29 private ref array<ResourceName> m_aGroupFlags;
30
31 [Attribute(defvalue: "1", desc: "When true group menu will be normally accesible, when false group menu will be disabled, but NOT the group functionality")]
32 protected bool m_bAllowGroupMenu;
33
34 [Attribute("1", desc: "If true reconnected player automatically rejoins the group")]
36
37 [Attribute("0", desc: "When checked, the players are allowed to volunteer for group leader role.")]
39
40 [Attribute("2", desc: "Amount of groups below player capacity that can exist before it restricts you from making more squads of that type", params: "0 inf")]
42
43 //this is changed only localy and doesnt replicate
44 protected bool m_bConfirmedByPlayer;
45
46 protected bool m_bNewGroupsAllowed = true;
47 protected bool m_bCanPlayersChangeAttributes = true;
48
49 protected static SCR_GroupsManagerComponent s_Instance;
50
51#ifdef DEBUG_GROUPS
52 static Widget s_wDebugLayout;
53#endif
54
59 protected int m_iLatestGroupID = 1000; // Lower ids reserved for pre-defined groups
63 protected ref array<SCR_AIGroup> m_aDeletionQueue = {};
64 protected int m_iMovingPlayerToGroupID = -1;
66
67 //------------------------------------------------------------------------------------------------
69 static SCR_GroupsManagerComponent GetInstance()
70 {
71 return s_Instance;
72 }
73
74 //------------------------------------------------------------------------------------------------
76 void GetGroupFlags(notnull array<ResourceName> targetArray)
77 {
78 targetArray.Copy(m_aGroupFlags);
79 }
80
81 //------------------------------------------------------------------------------------------------
86
87 //------------------------------------------------------------------------------------------------
93
94 protected bool IsProxy()
95 {
96 RplComponent rplComponent = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
97 if (!rplComponent)
98 return false;
99
100 return rplComponent.IsProxy();
101 }
102
103 //------------------------------------------------------------------------------------------------
109 int MovePlayerToGroup(int playerID, int previousGroupID, int newGroupID)
110 {
111 m_iMovingPlayerToGroupID = newGroupID;
112 SCR_AIGroup previousGroup = FindGroup(previousGroupID);
113 if (previousGroup)
114 previousGroup.RemovePlayer(playerID);
115
116 SCR_AIGroup newGroup = FindGroup(newGroupID);
117 if (newGroup)
118 {
119 if (newGroup.IsFull())
120 {
122 return -1;
123 }
124
125 newGroup.AddPlayer(playerID);
127 return newGroupID;
128 }
129 else
130 {
132 return -1;
133 }
134 }
135
136 //------------------------------------------------------------------------------------------------
140 void ClearRequests(int groupID, int playerID)
141 {
142 SCR_PlayerControllerGroupComponent playerGroupController = SCR_PlayerControllerGroupComponent.GetLocalPlayerControllerGroupComponent();
143 if (!playerGroupController)
144 return;
145
146 SCR_AIGroup group = FindGroup(groupID);
147 if (!group)
148 return;
149
150 RplId groupRplID = Replication.FindItemId(group);
151
152 array<int> requesterIDs = {};
153 group.GetRequesterIDs(requesterIDs);
154
155 for (int i = 0, count = requesterIDs.Count(); i < count; i++)
156 {
157 if (!group.IsPlayerInGroup(playerID))
158 SCR_NotificationsComponent.SendToPlayer(requesterIDs[i], ENotification.GROUPS_REQUEST_CANCELLED);
159 }
160
161 playerGroupController.ClearAllRequesters(groupRplID);
162 }
163
164 //------------------------------------------------------------------------------------------------
169 int AddPlayerToGroup(int groupID, int playerID)
170 {
171 SCR_AIGroup group = FindGroup(groupID);
172 if (!group)
173 return -1;
174
175 if (group.IsFull())
176 return -1;
177
178 group.AddPlayer(playerID);
179 return groupID;
180 }
181
182 //------------------------------------------------------------------------------------------------
186 void AddDisconnectedPlayer(int playerID, int groupID)
187 {
188 m_mDisconnectedPlayerIDs.Set(playerID, groupID);
189 }
190
191 //------------------------------------------------------------------------------------------------
193 protected void CreatePredefinedGroups()
194 {
195 FactionManager factionManager = GetGame().GetFactionManager();
196 if (!factionManager)
197 return;
198
199 array<Faction> factions = {};
200 factionManager.GetFactionsList(factions);
201
202 bool isCommanderRoleEnabled = true;
204 if (gameModeCampaign)
205 isCommanderRoleEnabled = gameModeCampaign.GetCommanderRoleEnabled();
206
207 int presetGroupId = 1;
208 foreach (Faction faction : factions)
209 {
210 SCR_Faction scrFaction = SCR_Faction.Cast(faction);
211 if (!scrFaction)
212 return;
213
214 array<ref SCR_GroupPreset> groups = {};
215 scrFaction.GetPredefinedGroups(groups);
216
217 array<SCR_GroupRolePresetConfig> groupRolePresetConfigs = {};
218 scrFaction.GetGroupRolePresetConfigs(groupRolePresetConfigs);
219
220 const array<SCR_AIGroup> existingGroups = GetPlayableGroupsByFaction(scrFaction);
221
222 SCR_AIGroup newGroup;
223 foreach (SCR_GroupPreset gr : groups)
224 {
225 const int groupId = presetGroupId++;
226
227 if (!isCommanderRoleEnabled && gr.GetGroupRole() == SCR_EGroupRole.COMMANDER)
228 continue;
229
230 // Pre defined group was already loaded from e.g. save-game, so no need to create it
231 bool found;
232 if (existingGroups)
233 {
234 foreach (SCR_AIGroup group : existingGroups)
235 {
236 if (group.GetPresetResource() == gr.GetStoreName())
237 {
238 found = true;
239 break;
240 }
241 }
242
243 if (found)
244 continue;
245 }
246
247 // Swap to pre defined ID for creation process as events are fired that would otherwise link the wrong id
248 const int latestId = m_iLatestGroupID;
249 m_iLatestGroupID = groupId;
250 newGroup = CreateNewPlayableGroup(faction, gr.GetGroupRole());
251 m_iLatestGroupID = latestId;
252 if (!newGroup)
253 continue;
254
255 newGroup.SetPresetResource(gr.GetStoreName());
256 newGroup.SetCanDeleteIfNoPlayer(false);
257
258 // setup group by groupRolePresetConfig if is configured
259 bool isConfigFound;
260 foreach (SCR_GroupRolePresetConfig config : groupRolePresetConfigs)
261 {
262 if (config.GetGroupRole() == gr.GetGroupRole())
263 {
264 config.SetupGroupWithOverride(newGroup, gr);
265 config.SetupGroupFlag(newGroup, scrFaction);
266 isConfigFound = true;
267 break;
268 }
269 }
270
271 if (!isConfigFound)
272 {
273 // setup group only by predefined preset
274 gr.SetupGroup(newGroup); // set defaults
275 gr.SetupGroupFlag(newGroup, scrFaction);
276 }
277 }
278 }
279 }
280
281 //------------------------------------------------------------------------------------------------
284 //------------------------------------------------------------------------------------------------
285 void SetGroupLeader(int groupID, int playerID)
286 {
287 SCR_AIGroup group = FindGroup(groupID);
288 if (!group)
289 return;
290 group.SetGroupLeader(playerID);
291 }
292
293 //------------------------------------------------------------------------------------------------
295 void SetNewGroupsAllowed(bool isAllowed)
296 {
297 if (isAllowed == m_bNewGroupsAllowed)
298 return;
299
300 RPC_DoSetNewGroupsAllowed(isAllowed);
301 Rpc(RPC_DoSetNewGroupsAllowed, isAllowed);
302 }
303
304 //------------------------------------------------------------------------------------------------
307 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
308 void RPC_DoSetNewGroupsAllowed(bool isAllowed)
309 {
310 if (isAllowed == m_bNewGroupsAllowed)
311 return;
312
313 m_bNewGroupsAllowed = isAllowed;
315 }
316
317 //------------------------------------------------------------------------------------------------
319 void SetCanPlayersChangeAttributes(bool isAllowed)
320 {
321 if (isAllowed == m_bCanPlayersChangeAttributes)
322 return;
323
325 Rpc(RPC_SetCanPlayersChangeAttributes, isAllowed);
326 }
327
328 //------------------------------------------------------------------------------------------------
331 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
333 {
334 if (isAllowed == m_bCanPlayersChangeAttributes)
335 return;
336
339 }
340
341 //------------------------------------------------------------------------------------------------
344 //------------------------------------------------------------------------------------------------
345 void SetPrivateGroup(int groupID, bool isPrivate)
346 {
347 SCR_AIGroup group = FindGroup(groupID);
348 if (!group)
349 return;
350 group.SetPrivate(isPrivate);
351 }
352
353 //------------------------------------------------------------------------------------------------
357 //------------------------------------------------------------------------------------------------
359 {
360 array<SCR_AIGroup> groups;
361
362 for (int i = m_mPlayableGroups.Count() - 1; i >= 0; i--)
363 {
364 groups = m_mPlayableGroups.GetElement(i);
365
366 for (int j = groups.Count() - 1; j >= 0; j--)
367 {
368 if (groups[j] && groups[j].GetGroupID() == groupID)
369 return groups[j];
370 }
371 }
372
373 return null;
374 }
375
376 //------------------------------------------------------------------------------------------------
378 //------------------------------------------------------------------------------------------------
383
384 //------------------------------------------------------------------------------------------------
386 //------------------------------------------------------------------------------------------------
391
392 //------------------------------------------------------------------------------------------------
394 //------------------------------------------------------------------------------------------------
399
400 //------------------------------------------------------------------------------------------------
403 //------------------------------------------------------------------------------------------------
404 // Returns group by player id
406 {
407 SCR_FactionManager factionManager = SCR_FactionManager.Cast(GetGame().GetFactionManager());
408 if (!factionManager)
409 return null;
410
411 Faction faction = factionManager.GetPlayerFaction(playerID);
412 if (!faction)
413 return null;
414
415 array<SCR_AIGroup> playableGroups = GetPlayableGroupsByFaction(faction);
416 if (!playableGroups)
417 return null;
418
419 for (int i = playableGroups.Count() - 1; i >= 0; i--)
420 {
421 if (playableGroups[i] && playableGroups[i].IsPlayerInGroup(playerID))
422 return playableGroups[i];
423 }
424
425 return null;
426 }
427
428 //------------------------------------------------------------------------------------------------
432 //------------------------------------------------------------------------------------------------
433 bool IsPlayerInAnyGroup(int playerID)
434 {
435 array<SCR_AIGroup> groups;
436
437 for (int i = m_mPlayableGroups.Count() - 1; i >= 0; i--)
438 {
439 groups = m_mPlayableGroups.GetElement(i);
440 for (int j = groups.Count() - 1; j >= 0; j--)
441 {
442 if (groups[j] && groups[j].IsPlayerInGroup(playerID))
443 return true;
444 }
445 }
446
447 return false;
448 }
449
450#ifdef DEBUG_GROUPS
451
452 //------------------------------------------------------------------------------------------------
453 void UpdateDebugUI()
454 {
455 if (!s_wDebugLayout)
456 s_wDebugLayout = GetGame().GetWorkspace().CreateWidgets("{661C199F3D59BB24}UI/layouts/Debug/Groups.layout");
457
458 VerticalLayoutWidget groupsLayout = VerticalLayoutWidget.Cast(s_wDebugLayout.FindAnyWidget("GroupsLayout"));
459 if (!groupsLayout)
460 return;
461
462 //Clear entries
463 while (groupsLayout.GetChildren())
464 {
465 groupsLayout.GetChildren().RemoveFromHierarchy();
466 }
467
468 array<SCR_AIGroup> playableGroups = GetAllPlayableGroups();
469 for (int i = playableGroups.Count() - 1; i >= 0; i--)
470 {
471 Widget groupEntry = GetGame().GetWorkspace().CreateWidgets("{898A1945FD29FC71}UI/layouts/Debug/GroupsGroupEntry.layout", groupsLayout);
472 RichTextWidget groupName = RichTextWidget.Cast(groupEntry.FindAnyWidget("GroupName"));
473 if (groupName)
474 groupName.SetText(playableGroups[i].GetGroupID().ToString() + ": " + playableGroups[i].GetCallsignSingleString());
475
476 array<int> playerIDs = playableGroups[i].GetPlayerIDs();
477 int playersCount = playerIDs.Count();
478
479 for (int j = 0; j < playersCount; j++)
480 {
481 HorizontalLayoutWidget characterEntry = HorizontalLayoutWidget.Cast(groupEntry.GetWorkspace().CreateWidgets("{952C36C11AF74465}UI/layouts/Debug/GroupsCharacterEntry.layout", groupEntry));
482 TextWidget playerNameWidget = TextWidget.Cast(characterEntry.FindAnyWidget("CharacterName"));
483 if (!playerNameWidget)
484 continue;
485
486 playerNameWidget.SetText(SCR_PlayerNamesFilterCache.GetInstance().GetPlayerDisplayName(playerIDs[j]));
487 }
488 }
489 }
490#endif
491
492 //------------------------------------------------------------------------------------------------
495 array<SCR_AIGroup> GetPlayableGroupsByFaction(Faction faction)
496 {
497 return m_mPlayableGroups.Get(faction);
498 }
499
500 //------------------------------------------------------------------------------------------------
503 array<SCR_AIGroup> GetSortedPlayableGroupsByFaction(Faction faction)
504 {
505 array<SCR_AIGroup> playableGroupsOrdered = {};
506 array<SCR_AIGroup> playableGroups = m_mPlayableGroups.Get(faction);
507 if (!playableGroups)
508 return playableGroupsOrdered;
509
510 int groupCount = playableGroups.Count();
511
512 array<int> sortedGroupIds = {};
513 for (int i = 0; i < groupCount; i++)
514 {
515 sortedGroupIds.Insert(playableGroups[i].GetGroupID());
516 }
517
518 sortedGroupIds.Sort();
519
520 for (int i = 0; i < groupCount; i++)
521 {
522 playableGroupsOrdered.Insert(FindGroup(sortedGroupIds[i]));
523 }
524
525 return playableGroupsOrdered;
526 }
527
528 //------------------------------------------------------------------------------------------------
530 void GetAllPlayableGroups(out array<SCR_AIGroup> outAllGroups)
531 {
532 array<SCR_AIGroup> allGroups = {};
533 array<SCR_AIGroup> currentGroups = {};
534 for (int i = m_mPlayableGroups.Count() - 1; i >= 0; i--)
535 {
536 currentGroups = m_mPlayableGroups.GetElement(i);
537
538 for (int j = currentGroups.Count() - 1; j >= 0; j--)
539 {
540 if (currentGroups[j])
541 allGroups.Insert(currentGroups[j]);
542 }
543 }
544
545 outAllGroups = allGroups;
546 }
547
548 //------------------------------------------------------------------------------------------------
552 SCR_ECharacterRank GetRequiredRank(SCR_EGroupRole groupRole, notnull SCR_Faction faction)
553 {
554 array<SCR_GroupRolePresetConfig> groupRolePresetConfigs = {};
555 faction.GetGroupRolePresetConfigs(groupRolePresetConfigs);
556
557 foreach (SCR_GroupRolePresetConfig preset : groupRolePresetConfigs)
558 {
559 if (preset.GetGroupRole() == groupRole)
560 return preset.GetRequiredRank();
561 }
562
563 return SCR_ECharacterRank.PRIVATE;
564 }
565
566 //------------------------------------------------------------------------------------------------
570 array<SCR_EGroupRole> GetConfiguredGroupRoles(notnull Faction faction, bool creatableByPlayerFilter = false)
571 {
572 array<SCR_EGroupRole> availableGroupRoles = {};
573
574 // get group roles from the config in predefined groups, a group that is not set in the config will not be visible.
575 SCR_Faction scrFaction = SCR_Faction.Cast(faction);
576 if (!scrFaction)
577 return availableGroupRoles;
578
579 array<SCR_GroupRolePresetConfig> groupRolePresetConfigs = {};
580 scrFaction.GetGroupRolePresetConfigs(groupRolePresetConfigs);
581
582 foreach (SCR_GroupRolePresetConfig preset : groupRolePresetConfigs)
583 {
584 if (!creatableByPlayerFilter || creatableByPlayerFilter && preset.CanBeCreatedByPlayer())
585 availableGroupRoles.Insert(preset.GetGroupRole());
586 }
587
588 return availableGroupRoles;
589 }
590
591 //------------------------------------------------------------------------------------------------
595 array<SCR_EGroupRole> GetAvailableGroupRoles(notnull Faction faction, int playerId)
596 {
597 array<SCR_EGroupRole> availableGroupRoles = {};
598
599 SCR_Faction scrFaction = SCR_Faction.Cast(faction);
600 if (!scrFaction)
601 return availableGroupRoles;
602
603 bool isPlayerCommander = scrFaction.IsPlayerCommander(playerId);
604
605 array<SCR_GroupRolePresetConfig> availableGroupRolePresetConfigs = {};
606 scrFaction.GetGroupRolePresetConfigs(availableGroupRolePresetConfigs);
607 foreach (SCR_GroupRolePresetConfig preset : availableGroupRolePresetConfigs)
608 {
609 if (!preset.CanBeCreatedByPlayer())
610 continue;
611
612 if (isPlayerCommander || (!isPlayerCommander && HasPlayerRequiredRank(preset, playerId, false)))
613 availableGroupRoles.Insert(preset.GetGroupRole());
614 }
615
616 array<SCR_AIGroup> playableGroups = GetPlayableGroupsByFaction(faction);
617 if (!playableGroups)
618 return {};
619
620 // faction commander can create all group roles
621 if (isPlayerCommander)
622 return availableGroupRoles;
623
624 for (int i = availableGroupRoles.Count() - 1; i >= 0; i--)
625 {
626 int joinableGroupAmount = 0;
627
628 foreach (SCR_AIGroup group : playableGroups)
629 {
630 if (!group)
631 continue;
632
633 if (group.GetGroupRole() != availableGroupRoles[i])
634 continue;
635
636 if (group.IsPrivate())
637 continue;
638
639 // remove group role if is in group more members than half of it's max group size
640 if (group.GetPlayerCount() > (group.GetMaxMembers() * 0.5))
641 continue;
642
643 joinableGroupAmount++;
644
645 if (joinableGroupAmount >= m_iFreeGroupAmountBeforeRestriction)
646 {
647 availableGroupRoles.RemoveOrdered(i);
648 break;
649 }
650 }
651 }
652
653 return availableGroupRoles;
654 }
655
656 //------------------------------------------------------------------------------------------------
661 {
662 PlayerController pc = GetGame().GetPlayerController();
663 int playerId;
664 if (pc)
665 playerId = pc.GetPlayerId();
666
667 SCR_Faction scrFaction = SCR_Faction.Cast(faction);
668 if (!scrFaction)
669 return true;
670
671 array<SCR_GroupRolePresetConfig> availableGroupRolePresetConfigs = {};
672 scrFaction.GetGroupRolePresetConfigs(availableGroupRolePresetConfigs);
673 foreach (SCR_GroupRolePresetConfig preset : availableGroupRolePresetConfigs)
674 {
675 if (preset.GetGroupRole() != groupRole || !preset.CanBeCreatedByPlayer())
676 continue;
677
678 if (HasPlayerRequiredRank(preset, playerId, false))
679 return true;
680 }
681
682 return false;
683 }
684
685 //------------------------------------------------------------------------------------------------
689 bool AreAllGroupsMajorityFull(SCR_EGroupRole groupRole, notnull Faction faction)
690 {
691 array<SCR_AIGroup> playableGroups = GetPlayableGroupsByFaction(faction);
692 foreach (SCR_AIGroup group : playableGroups)
693 {
694 if (!group || group.IsPrivate() || group.GetGroupRole() != groupRole)
695 continue;
696
697 if (group.GetPlayerCount() <= (group.GetMaxMembers() * 0.5))
698 return false;
699 }
700
701 return true;
702 }
703
704 //------------------------------------------------------------------------------------------------
705 protected void AssignGroupFrequency(notnull SCR_AIGroup group)
706 {
707 int frequency = 0;
708 Faction groupFaction = group.GetFaction();
709
710 frequency = GetFreeFrequency(groupFaction);
711 if (frequency == -1)
712 return;
713
714 ClaimFrequency(frequency, groupFaction);
715 group.SetRadioFrequency(frequency);
716 }
717
718 //------------------------------------------------------------------------------------------------
722 {
723 if (m_aDeletionQueue.Contains(group))
724 return;
725
726 if (m_aDeletionQueue.Count() == 0)
727 GetGame().GetCallqueue().Call(DeleteGroups);
728
729 m_aDeletionQueue.Insert(group);
730 }
731
732 //------------------------------------------------------------------------------------------------
735 void OnGroupPlayerRemoved(SCR_AIGroup group, int playerID)
736 {
737 // This script should only run on the server
738 if (IsProxy())
739 return;
740
741 // Is empty?
742 if (group.GetPlayerCount() > 0)
743 return;
744
745 //Can this group exist empty?
746 if (!group.GetDeleteIfNoPlayer())
747 {
748 if (group.IsPrivacyChangeable() && group.IsPrivate())
749 group.SetPrivate(false);
750
751 return;
752 }
753
754 // Yes, can we delete it?
755 array<SCR_AIGroup> playableGroups = GetPlayableGroupsByFaction(group.GetFaction());
756 if (!playableGroups || playableGroups.Count() <= 1) // faction should always have at least one group active.
757 {
758 // ensure that last group is always unlocked so players can join it
759 if (group.IsPrivacyChangeable() && group.IsPrivate())
760 group.SetPrivate(false);
761
762 return;
763 }
764
765 DeleteGroupDelayed(group);
766 }
767
768 //------------------------------------------------------------------------------------------------
771 void OnGroupPlayerAdded(SCR_AIGroup group, int playerID)
772 {
773 if (IsProxy())
774 return;
775
776 // Is group full?
777 if (!group.IsFull())
778 return; // Group not full, we don't have to make any new groups
779
780 // Group was full, we need to see if we have any other not full group
781 Faction faction = group.GetFaction();
782 if (!faction)
783 return;
784
785 SCR_Faction scrFaction = SCR_Faction.Cast(faction);
786 if (!scrFaction)
787 return;
788
789 array<SCR_AIGroup> groups = GetPlayableGroupsByFaction(faction);
790 if (!groups)
791 return;
792
793 // No groups found for faction?
794 int groupsCount = groups.Count();
795 if (groupsCount == 0 && !scrFaction.GetCanCreateOnlyPredefinedGroups())
796 {
797 // Anyway we create a new one
798 CreateNewPlayableGroup(faction);
799 return;
800 }
801
802 for (int i = groupsCount - 1; i >= 0; i--)
803 {
804 // We are checking for full groups if at least one group is not full, we return, we don't have to create new one
805 if (groups[i].GetPlayerCount() < group.GetMaxMembers())
806 return;
807 }
808
809 // All the groups were full, create new one
811 CreateNewPlayableGroup(faction);
812 }
813
814 //------------------------------------------------------------------------------------------------
819 bool HasPlayerRequiredRank(SCR_GroupRolePresetConfig preset, int playerId, bool ignoreGroupRequiredRank)
820 {
821 if (playerId == 0)
822 return true;
823
824 SCR_PlayerController pc = SCR_PlayerController.Cast(GetGame().GetPlayerManager().GetPlayerController(playerId));
825 if (!pc)
826 return true;
827
829 if (!xpHandler)
830 return true;
831
832 SCR_ECharacterRank playerRank = xpHandler.GetPlayerRankByXP();
833 SCR_ECharacterRank requiredRank = preset.GetRequiredRank();
834
835 // Check if player has required rank of the group role preset
836 if (!ignoreGroupRequiredRank && playerRank < requiredRank)
837 return false;
838
839 SCR_EntityCatalogManagerComponent entityCatalogManager = SCR_EntityCatalogManagerComponent.GetInstance();
840 if (!entityCatalogManager)
841 return true;
842
843 // Check if player has required rank for at least one of the group preset loadout
844 requiredRank = SCR_ECharacterRank.INVALID;
845 array<ResourceName> loadouts = preset.GetLoadouts();
846 Resource resource;
849 foreach (ResourceName loadoutResource : loadouts)
850 {
851 resource = Resource.Load(loadoutResource);
852 if (!resource)
853 continue;
854
855 entry = entityCatalogManager.GetEntryWithPrefabFromAnyCatalog(EEntityCatalogType.CHARACTER, resource.GetResource().GetResourceName());
856 if (!entry)
857 continue;
858
860 if (!data)
861 continue;
862
863 requiredRank = Math.Min(requiredRank, data.GetRequiredRank());
864 }
865
866 return playerRank >= requiredRank;
867 }
868
869 //------------------------------------------------------------------------------------------------
871 {
872 SCR_Faction scrFaction = SCR_Faction.Cast(faction);
873 if (!scrFaction)
874 return null;
875
876 array<SCR_GroupRolePresetConfig> groupRolePresetConfigs = {};
877 scrFaction.GetGroupRolePresetConfigs(groupRolePresetConfigs);
878 SCR_GroupRolePresetConfig groupPreset;
879
880 foreach (SCR_GroupRolePresetConfig preset : groupRolePresetConfigs)
881 {
882 if (preset.GetGroupRole() == role)
883 {
884 groupPreset = preset;
885 break;
886 }
887 }
888
889 return groupPreset;
890 }
891
892 //------------------------------------------------------------------------------------------------
894 private BaseRadioComponent GetCommunicationDevice(notnull IEntity controlledEntity)
895 {
896 SCR_GadgetManagerComponent gagdetManager = SCR_GadgetManagerComponent.Cast(controlledEntity.FindComponent(SCR_GadgetManagerComponent));
897 if (!gagdetManager)
898 return null;
899
900 IEntity radio = gagdetManager.GetGadgetByType(EGadgetType.RADIO); //variable purpose = debug
901 if (!radio)
902 return null;
903
904 return BaseRadioComponent.Cast(radio.FindComponent(BaseRadioComponent));
905 }
906
907 //------------------------------------------------------------------------------------------------
908 private void TuneAgentsRadio(AIAgent agentEntity)
909 {
910 if (!agentEntity)
911 return;
912
913 SCR_AIGroup group = SCR_AIGroup.Cast(agentEntity.GetParentGroup());
914 if (!group)
915 return;
916
917 BaseRadioComponent radio = GetCommunicationDevice(agentEntity.GetControlledEntity());
918
919 if (!radio)
920 return;
921
923 {
924 BaseTransceiver tsv = radio.GetTransceiver(0);
925 if (tsv)
926 tsv.SetFrequency(group.GetRadioFrequency());
927 }
928
929 // Set radio active channel to group default radio channel
930 int playerId = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(agentEntity.GetControlledEntity());
931 if (playerId <= 0)
932 return;
933
934 SCR_PlayerController pc = SCR_PlayerController.Cast(GetGame().GetPlayerManager().GetPlayerController(playerId));
935 if (!pc)
936 return;
937
938 SCR_VONController vonController = SCR_VONController.Cast(pc.FindComponent(SCR_VONController));
939 if (!vonController)
940 return;
941
942 vonController.SetActiveChannel(group.GetDefaultActiveRadioChannel());
943 }
944
945 //------------------------------------------------------------------------------------------------
947 void OnGroupAgentAdded(AIAgent child)
948 {
949 GetGame().GetCallqueue().CallLater(TuneAgentsRadio, 1, false, child);
950 }
951
952 //------------------------------------------------------------------------------------------------
955 void OnGroupAgentRemoved(SCR_AIGroup group, AIAgent child)
956 {
957 return; //For now we don't delete empty groups
958
959 if (!group)
960 return;
961
962 // Is group empty?
963 if (group.GetAgentsCount() > 0)
964 return;
965
966 // Group is empty, can we delete it?
967 Faction faction = group.GetFaction();
968 if (!faction)
969 return;
970
971 array<SCR_AIGroup> groups = GetPlayableGroupsByFaction(faction);
972 if (!groups)
973 return;
974
975 // No groups found for faction?
976 int groupsCount = groups.Count();
977 if (groupsCount == 0)
978 return;
979
980 // If we find any other group, which is empty, we delete this group
981 for (int i = groupsCount - 1; i >= 0; i--)
982 {
983 if (groups[i] == group)
984 continue;
985
986 if (groups[i].GetAgentsCount() == 0)
987 {
988 DeleteAndUnregisterGroup(group);
989 return;
990 }
991 }
992 }
993
994 //------------------------------------------------------------------------------------------------
997 void DeleteAndUnregisterGroup(notnull SCR_AIGroup group)
998 {
999 m_OnPlayableGroupRemoved.Invoke(group);
1000 UnregisterGroup(group);
1001 delete group;
1002 }
1003
1004 //------------------------------------------------------------------------------------------------
1007 void UnregisterGroup(notnull SCR_AIGroup group)
1008 {
1009 Faction faction = group.GetFaction();
1010 if (!faction)
1011 return;
1012
1013 array<SCR_AIGroup> groups = GetPlayableGroupsByFaction(faction);
1014 if (!groups)
1015 return;
1016
1017 int frequency = group.GetRadioFrequency();
1018 int foundGroupsWithFrequency = 0;
1019 array<SCR_AIGroup> existingGroups = {};
1020
1021 existingGroups = GetPlayableGroupsByFaction(faction);
1022 if (existingGroups)
1023 {
1024 foreach (SCR_AIGroup checkedGroup : existingGroups)
1025 {
1026 if (checkedGroup && checkedGroup.GetRadioFrequency() == frequency)
1027 foundGroupsWithFrequency++;
1028 }
1029 }
1030
1031 //if there is only our group with this frequency or none, release it before changing our frequency
1032 if (foundGroupsWithFrequency <= 1)
1033 ReleaseFrequency(frequency, faction);
1034
1035 SCR_AIGroup slaveGroup = group.GetSlave();
1036
1037 //in case the slave group doesnt have any AIs in it, delete
1038 //mourTodo: handle what the AIs should do in case their master group is deleted
1039 if (slaveGroup && slaveGroup.GetAgentsCount() <= 0)
1040 delete slaveGroup;
1041
1042 if (groups.Find(group) >= 0)
1043 groups.RemoveItem(group);
1044 }
1045
1046 //------------------------------------------------------------------------------------------------
1049 void RegisterGroup(notnull SCR_AIGroup group)
1050 {
1051 array<SCR_AIGroup> outGroups;
1052 Faction faction = group.GetFaction();
1053 if (!m_mPlayableGroups.Find(faction, outGroups))
1054 {
1055 // No array found, let's make one
1056 outGroups = {};
1057 m_mPlayableGroups.Insert(faction, outGroups);
1058 }
1059 else if (outGroups.Contains(group))
1060 {
1061 return;
1062 }
1063
1064 outGroups.Insert(group);
1065 group.GetOnAgentAdded().Insert(OnGroupAgentAdded);
1066 group.GetOnAgentRemoved().Insert(OnGroupAgentRemoved);
1067 }
1068
1069 //------------------------------------------------------------------------------------------------
1073 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
1074 void RPC_DoSetGroupFaction(RplId groupID, int factionIndex)
1075 {
1076 FactionManager factionManager = GetGame().GetFactionManager();
1077 if (!factionManager)
1078 return;
1079
1080 Faction faction = factionManager.GetFactionByIndex(factionIndex);
1081 if (!faction)
1082 return;
1083
1084 SCR_AIGroup group = SCR_AIGroup.Cast(Replication.FindItem(groupID));
1085 if (group)
1086 group.SetFaction(faction);
1087 }
1088
1089 //------------------------------------------------------------------------------------------------
1090 void AssignGroupID(SCR_AIGroup group)
1091 {
1092 if (group.GetGroupID() != -1)
1093 return; // Already assigned
1094
1097 }
1098
1099 //------------------------------------------------------------------------------------------------
1101 void OnPlayerFactionChanged(notnull FactionAffiliationComponent owner, Faction previousFaction, Faction newFaction)
1102 {
1103 if (!newFaction)
1104 return;
1105
1106 SCR_Faction scrFaction = SCR_Faction.Cast(newFaction);
1107 if (!scrFaction)
1108 return;
1109 if (scrFaction.GetCanCreateOnlyPredefinedGroups())
1110 return;
1111
1112 SCR_AIGroup newPlayerGroup = GetFirstNotFullForFaction(newFaction);
1113 if (!newPlayerGroup && scrFaction.IsEnabledAutoGroupCreationWhenFull())
1114 newPlayerGroup = CreateNewPlayableGroup(newFaction);
1115
1116 if (!owner)
1117 return;
1118
1119 PlayerController controller = PlayerController.Cast(owner.GetOwner());
1120 if (!controller)
1121 return;
1122
1123 SCR_PlayerControllerGroupComponent groupComp = SCR_PlayerControllerGroupComponent.Cast(controller.FindComponent(SCR_PlayerControllerGroupComponent));
1124 if (!groupComp)
1125 return;
1126
1127 SCR_AIGroup oldGroup = FindGroup(groupComp.GetGroupID());
1128 if (oldGroup)
1129 {
1130 oldGroup.RemovePlayer(controller.GetPlayerId());
1131 }
1132 else
1133 {
1134 // call next frame, because we need the OnPlayerFactionChanged event to be called for all registered callbacks so that the faction is set everywhere
1136 GetGame().GetCallqueue().Call(RejoinPlayer, controller.GetPlayerId(), scrFaction);
1137 }
1138
1139 groupComp.ResetGroupIDs_S();
1140 }
1141
1142 //------------------------------------------------------------------------------------------------
1143 protected void RejoinPlayer(int playerID, notnull SCR_Faction faction)
1144 {
1145 SCR_PlayerControllerGroupComponent playerGroupCompoment = SCR_PlayerControllerGroupComponent.GetPlayerControllerComponent(playerID);
1146 if (!playerGroupCompoment)
1147 return;
1148
1149 int groupID;
1150 if (!m_mDisconnectedPlayerIDs.Find(playerID, groupID))
1151 return;
1152
1153 SCR_AIGroup group = FindGroup(groupID);
1154 if (group)
1155 {
1156 // cannot be rejoined to the commander group, because the commander automatically resigns after disconnecting
1157 if (group.GetGroupRole() != SCR_EGroupRole.COMMANDER && !group.IsFull())
1158 {
1159 playerGroupCompoment.RequestJoinGroup(group.GetGroupID());
1160 return;
1161 }
1162 }
1163
1164 // group not found, try find empty group
1165 group = GetFirstNotFullForFaction(faction, null, true);
1166 if (group)
1167 {
1168 playerGroupCompoment.RequestJoinGroup(group.GetGroupID());
1169 return;
1170 }
1171
1172 // group not found, create new one and join
1173 playerGroupCompoment.RequestCreateGroupWithData(faction.GetDefaultGroupRoleForNewGroup(), false, "", "", true);
1174 }
1175
1176 //------------------------------------------------------------------------------------------------
1179 {
1180 m_OnPlayableGroupCreated.Invoke(group);
1181 }
1182
1183 //------------------------------------------------------------------------------------------------
1189 {
1190 array<SCR_AIGroup> factionGroups = GetPlayableGroupsByFaction(faction);
1191
1192 foreach (SCR_AIGroup group : factionGroups)
1193 {
1194 if (group.GetGroupRole() == role)
1195 return group;
1196 }
1197
1198 return null;
1199 }
1200
1201 //------------------------------------------------------------------------------------------------
1206 {
1207 array<SCR_AIGroup> factionGroups = GetPlayableGroupsByFaction(faction);
1208 if (!factionGroups)
1209 return null;
1210
1211 for (int i = factionGroups.Count() - 1; i >= 0; i--)
1212 {
1213 if (!factionGroups[i])
1214 return null;
1215
1216 if (factionGroups[i].GetPlayerCount() == 0)
1217 return factionGroups[i];
1218 }
1219
1220 return null;
1221 }
1222
1223 //------------------------------------------------------------------------------------------------
1229 {
1230 RplComponent rplComp = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
1231 if (!rplComp)
1232 return null;
1233 // TO DO: Commented out coz of initial replication
1234
1235 //bool isMaster = rplComp.IsMaster();
1236 //if (!rplComp.IsMaster()) // TO DO: Commented out coz of initial replication
1237 // return null;
1238
1239 Resource groupResource = Resource.Load(m_sDefaultGroupPrefab);
1240 if (!groupResource.IsValid())
1241 return null;
1242
1243 SCR_AIGroup group = SCR_AIGroup.Cast(GetGame().SpawnEntityPrefab(groupResource, GetOwner().GetWorld()));
1244 if (!group)
1245 return null;
1246
1247 group.DeactivateAI();
1248
1249 group.SetFaction(faction);
1250 RegisterGroup(group);
1251 AssignGroupFrequency(group);
1252 AssignGroupID(group);
1253 group.SetGroupRole(groupRole);
1254
1255 //if there is commanding present, we create the slave group for AIs at the creation of the group
1256 SCR_CommandingManagerComponent commandingManager = SCR_CommandingManagerComponent.GetInstance();
1257 if (commandingManager)
1258 {
1259 IEntity groupEntity = GetGame().SpawnEntityPrefab(Resource.Load(commandingManager.GetGroupPrefab()));
1260 if (!groupEntity)
1261 return null;
1262
1263 SCR_AIGroup slaveGroup = SCR_AIGroup.Cast(groupEntity);
1264 if (!slaveGroup)
1265 return null;
1266
1267 slaveGroup.DeactivateAI();
1268
1269 RplComponent RplComp = RplComponent.Cast(slaveGroup.FindComponent(RplComponent));
1270 if (!RplComp)
1271 return null;
1272
1273 RplId slaveGroupRplID = RplComp.Id();
1274
1275 RplComp = RplComponent.Cast(group.FindComponent(RplComponent));
1276 if (!RplComp)
1277 return null;
1278
1279 RequestSetGroupSlave(RplComp.Id(), slaveGroupRplID);
1280 }
1281
1282 m_OnPlayableGroupCreated.Invoke(group);
1283
1284#ifdef DEBUG_GROUPS
1285 GetGame().GetCallqueue().CallLater(UpdateDebugUI, 1, false);
1286#endif
1287
1288 return group;
1289 }
1290
1291 //------------------------------------------------------------------------------------------------
1296 SCR_AIGroup GetFirstNotFullForFaction(notnull Faction faction, SCR_AIGroup ownGroup = null, bool respectPrivate = false)
1297 {
1298 SCR_AIGroup group;
1299 array<SCR_AIGroup> factionGroups = GetPlayableGroupsByFaction(faction);
1300 if (!factionGroups)
1301 return group;
1302
1303 for (int i = 0, count = factionGroups.Count(); i < count; i++)
1304 {
1305 if (!factionGroups[i].IsFull() && factionGroups[i] != ownGroup && (!respectPrivate || !factionGroups[i].IsPrivate()))
1306 {
1307 group = factionGroups[i];
1308 break;
1309 }
1310 }
1311
1312 return group;
1313 }
1314
1315 //------------------------------------------------------------------------------------------------
1319 bool CanCreateNewGroup(notnull Faction newGroupFaction)
1320 {
1322 return false;
1323
1324 SCR_Faction scrFaction = SCR_Faction.Cast(newGroupFaction);
1325 if (scrFaction.GetCanCreateOnlyPredefinedGroups())
1326 return false;
1327
1328 if (GetFreeFrequency(newGroupFaction) == -1)
1329 return false;
1330
1331 int playerId = SCR_PlayerController.GetLocalPlayerId();
1332
1333 if (scrFaction.IsGroupRolesConfigured())
1334 {
1335 array<SCR_EGroupRole> availableGroupRoles = GetAvailableGroupRoles(newGroupFaction, playerId);
1336 if (availableGroupRoles.IsEmpty())
1337 return false;
1338 }
1339 else
1340 {
1341 SCR_AIGroup playerGroup = GetPlayerGroup(playerId);
1342
1343 // disable creation of new group if player is the last in his group as there is no reason to create new one
1344 if (playerGroup && playerGroup.GetPlayerCount() == 1)
1345 return false;
1346
1347 if (TryFindEmptyGroup(newGroupFaction))
1348 return false;
1349 }
1350
1351 return true;
1352 }
1353
1354 //------------------------------------------------------------------------------------------------
1361
1362 //------------------------------------------------------------------------------------------------
1365 int GetFreeFrequency(Faction frequencyFaction)
1366 {
1367 FactionHolder usedForFactions = new FactionHolder();
1368
1369 int factionHQFrequency; // Don't assign this frequency to any of the groups
1370 SCR_Faction militaryFaction = SCR_Faction.Cast(frequencyFaction);
1371 if (militaryFaction)
1372 factionHQFrequency = militaryFaction.GetFactionRadioFrequency();
1373
1374 int minFrequencyAvailable = m_iPlayableGroupFrequencyMin;
1375
1376 while (minFrequencyAvailable <= m_iPlayableGroupFrequencyMax)
1377 {
1378 if (minFrequencyAvailable == factionHQFrequency)
1379 {
1380 minFrequencyAvailable += m_iPlayableGroupFrequencyOffset;
1381 continue; // We cannot assign this frequency to any group, it is used by the factions HQ
1382 }
1383
1384 if (!m_mUsedFrequenciesMap.Find(minFrequencyAvailable, usedForFactions))
1385 break; // No assigned frequencies for this faction yet
1386
1387 if (usedForFactions.Find(frequencyFaction) == -1)
1388 break; // Unused frequency found
1389
1390 minFrequencyAvailable += m_iPlayableGroupFrequencyOffset;
1391 }
1392
1393 if (minFrequencyAvailable <= m_iPlayableGroupFrequencyMax)
1394 return minFrequencyAvailable;
1395
1396 Print("Ran out of frequencies for groups", LogLevel.WARNING);
1397 return -1;
1398
1399 }
1400
1401 //------------------------------------------------------------------------------------------------
1405 void ClaimFrequency(int frequency, Faction faction)
1406 {
1407 FactionHolder usedForFactions = new FactionHolder();
1408 FactionHolder factions = new FactionHolder();
1409
1410 if (!m_mUsedFrequenciesMap.Find(frequency, usedForFactions))
1411 {
1412 factions.Insert(faction);
1413 m_mUsedFrequenciesMap.Insert(frequency, factions);
1414 return;
1415 }
1416 if (usedForFactions.Find(faction) == -1)
1417 {
1418 usedForFactions.Insert(faction);
1419 }
1420 }
1421
1422 //------------------------------------------------------------------------------------------------
1427 bool IsFrequencyClaimed(int frequency, Faction faction)
1428 {
1429 FactionHolder usedForFactions = new FactionHolder();
1430 if (!m_mUsedFrequenciesMap.Find(frequency, usedForFactions))
1431 return false;
1432
1433 if (usedForFactions.Find(faction))
1434 return true;
1435
1436 return false;
1437 }
1438
1439 //------------------------------------------------------------------------------------------------
1443 void ReleaseFrequency(int frequency, Faction faction)
1444 {
1445 if (!faction || !frequency)
1446 return;
1447
1448 FactionHolder factions = new FactionHolder();
1449 if (m_mUsedFrequenciesMap.Find(frequency, factions))
1450 {
1451 if (factions.Count() <= 1 && factions.Find(faction) != -1)
1452 m_mUsedFrequenciesMap.Remove(frequency);
1453 else
1454 {
1455 int factionIdx = factions.Find(faction);
1456 if (factionIdx >= 0 && factionIdx < factions.Count())
1457 factions.Remove(factionIdx);
1458 }
1459 }
1460 }
1461
1462 //------------------------------------------------------------------------------------------------
1466 void RequestSetGroupSlave(RplId compID, RplId slaveID)
1467 {
1468 RPC_DoSetGroupSlave(compID, slaveID);
1469 //Call next method later to be sure that SCR_AIGroup was replicated to the client succesfully (temporary solution)
1470 GetGame().GetCallqueue().CallLater(RpcWrapper, 2000, false, compID, slaveID);
1471 }
1472
1473 //------------------------------------------------------------------------------------------------
1477 void RpcWrapper(RplId compID, RplId slaveID)
1478 {
1479 Rpc(RPC_DoSetGroupSlave, compID, slaveID);
1480 }
1481
1482 //------------------------------------------------------------------------------------------------
1486 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
1487 void RPC_DoSetGroupSlave(RplId masterGroupID, RplId slaveGroupID)
1488 {
1489 SCR_AIGroup masterGroup, group;
1490 RplComponent rplComp = RplComponent.Cast(Replication.FindItem(masterGroupID));
1491 if (!rplComp)
1492 return;
1493
1494 masterGroup = SCR_AIGroup.Cast(rplComp.GetEntity());
1495 if (!masterGroup)
1496 return;
1497
1498 rplComp = RplComponent.Cast(Replication.FindItem(slaveGroupID));
1499 if (!rplComp)
1500 return;
1501
1502 group = SCR_AIGroup.Cast(rplComp.GetEntity());
1503 if (!group)
1504 return;
1505
1506 masterGroup.SetSlave(group);
1507 group.GetOnAgentRemoved().Insert(OnAIMemberRemoved);
1508 }
1509
1510 //------------------------------------------------------------------------------------------------
1514 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
1515 void RPC_DoRemoveAIMemberFromGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
1516 {
1517 SCR_ChimeraCharacter AIMember;
1518 array<SCR_ChimeraCharacter> AIMembers;
1519 GetAIMembers(groupRplCompID, aiCharacterComponentID, AIMembers, AIMember);
1520 if (!AIMembers || !AIMember)
1521 return;
1522
1523 AIMember.SetRecruited(false);
1524 AIMembers.RemoveItem(AIMember);
1525 }
1526
1527 //------------------------------------------------------------------------------------------------
1532 void GetAIMembers(RplId groupRplCompID, RplId aiCharacterComponentID, out array<SCR_ChimeraCharacter> members, out SCR_ChimeraCharacter AIMember)
1533 {
1534 RplComponent rplComp = RplComponent.Cast(Replication.FindItem(aiCharacterComponentID));
1535 if (!rplComp)
1536 return;
1537
1538 AIMember = SCR_ChimeraCharacter.Cast(rplComp.GetEntity());
1539 if (!AIMember)
1540 return;
1541
1542 rplComp = RplComponent.Cast(Replication.FindItem(groupRplCompID));
1543 if (!rplComp)
1544 return;
1545
1546 SCR_AIGroup group = SCR_AIGroup.Cast(rplComp.GetEntity());
1547 if (!group)
1548 return;
1549
1550 members = group.GetAIMembers();
1551 }
1552
1553 //------------------------------------------------------------------------------------------------
1557 void AskRemoveAiMemberFromGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
1558 {
1559 RPC_DoRemoveAIMemberFromGroup(groupRplCompID, aiCharacterComponentID);
1560 Rpc(RPC_DoRemoveAIMemberFromGroup, groupRplCompID, aiCharacterComponentID);
1561 }
1562
1563 //------------------------------------------------------------------------------------------------
1567 void AskAddAiMemberToGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
1568 {
1569 RPC_DoAddAIMemberToGroup(groupRplCompID, aiCharacterComponentID);
1570 Rpc(RPC_DoAddAIMemberToGroup, groupRplCompID, aiCharacterComponentID);
1571 }
1572
1573 //------------------------------------------------------------------------------------------------
1577 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
1578 void RPC_DoAddAIMemberToGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
1579 {
1580 SCR_ChimeraCharacter AIMember;
1581 array<SCR_ChimeraCharacter> AIMembers;
1582 GetAIMembers(groupRplCompID, aiCharacterComponentID, AIMembers, AIMember);
1583 if (!AIMembers || !AIMember)
1584 return;
1585
1586 AIMember.SetRecruited(true);
1587 AIMembers.Insert(AIMember);
1588 }
1589
1590 //------------------------------------------------------------------------------------------------
1593 void OnAIMemberRemoved(SCR_AIGroup group, AIAgent agent)
1594 {
1595 if (!group || !agent)
1596 return;
1597
1598 SCR_ChimeraCharacter character = SCR_ChimeraCharacter.Cast(agent.GetControlledEntity());
1599 if (!character)
1600 return;
1601
1602 RplId groupCompRplID, characterCompRplID;
1603 RplComponent rplComp = RplComponent.Cast(group.FindComponent(RplComponent));
1604 if (!rplComp)
1605 return;
1606
1607 groupCompRplID = rplComp.Id();
1608
1609 rplComp = RplComponent.Cast(character.FindComponent(RplComponent));
1610 if (!rplComp)
1611 return;
1612
1613 characterCompRplID = rplComp.Id();
1614 AskRemoveAiMemberFromGroup(groupCompRplID, characterCompRplID);
1615 }
1616
1617 //------------------------------------------------------------------------------------------------
1620 {
1621 return m_bConfirmedByPlayer;
1622 }
1623
1624 //------------------------------------------------------------------------------------------------
1627 {
1628 return m_bAllowGroupMenu;
1629 }
1630
1631 //------------------------------------------------------------------------------------------------
1634 {
1635 return m_bNewGroupsAllowed;
1636 }
1637
1638 //------------------------------------------------------------------------------------------------
1640 void SetConfirmedByPlayer(bool isConfirmed)
1641 {
1642 m_bConfirmedByPlayer = isConfirmed;
1643 }
1644
1645 //------------------------------------------------------------------------------------------------
1648 {
1649 for (int i = m_aDeletionQueue.Count() - 1; i >= 0; i--)
1650 {
1651 DeleteAndUnregisterGroup(m_aDeletionQueue[i]);
1652 m_aDeletionQueue.Remove(i);
1653 }
1654 }
1655
1656 //------------------------------------------------------------------------------------------------
1660 void TunePlayersFrequency(int playerId, IEntity player)
1661 {
1662 PlayerController controller = GetGame().GetPlayerManager().GetPlayerController(playerId);
1663 if (!controller)
1664 return;
1665
1667 if (!gadgetManager)
1668 return;
1669
1670 IEntity radio = gadgetManager.GetGadgetByType(EGadgetType.RADIO);
1671 if (!radio)
1672 return;
1673
1674 BaseRadioComponent radioComponent = BaseRadioComponent.Cast(radio.FindComponent(BaseRadioComponent));
1675 if (!radioComponent)
1676 return;
1677
1678 SCR_PlayerControllerGroupComponent groupComponent = SCR_PlayerControllerGroupComponent.Cast(controller.FindComponent(SCR_PlayerControllerGroupComponent));
1679 if (!groupComponent || groupComponent.GetActualGroupFrequency() == 0)
1680 return;
1681
1682 BaseTransceiver transceiver = radioComponent.GetTransceiver(0);
1683 if (!transceiver)
1684 return;
1685
1686 transceiver.SetFrequency(groupComponent.GetActualGroupFrequency());
1687 }
1688
1689 //------------------------------------------------------------------------------------------------
1690 protected override void OnPlayerRegistered(int playerId)
1691 {
1692 if (!m_pGameMode.IsMaster())
1693 return;
1694
1695 PlayerController playerController = GetGame().GetPlayerManager().GetPlayerController(playerId);
1696 SCR_PlayerFactionAffiliationComponent playerFactionAffiliation = SCR_PlayerFactionAffiliationComponent.Cast(playerController.FindComponent(SCR_PlayerFactionAffiliationComponent));
1697 if (playerFactionAffiliation)
1698 playerFactionAffiliation.GetOnFactionChanged().Insert(OnPlayerFactionChanged);
1699 }
1700
1701 //------------------------------------------------------------------------------------------------
1702 protected override void OnPlayerDisconnected(int playerId, KickCauseCode cause, int timeout)
1703 {
1704 // TODO@AS: Ensure authority only
1705 PlayerController playerController = GetGame().GetPlayerManager().GetPlayerController(playerId);
1706 if (playerController)
1707 {
1708 SCR_PlayerFactionAffiliationComponent playerFactionAffiliation = SCR_PlayerFactionAffiliationComponent.Cast(playerController.FindComponent(SCR_PlayerFactionAffiliationComponent));
1709 if (playerFactionAffiliation)
1710 playerFactionAffiliation.GetOnFactionChanged().Remove(OnPlayerFactionChanged);
1711 }
1712 }
1713
1714 //------------------------------------------------------------------------------------------------
1715 override void OnPostInit(IEntity owner)
1716 {
1717 SetEventMask(owner, EntityEvent.INIT);
1718 }
1719
1720 //------------------------------------------------------------------------------------------------
1721 override void EOnInit(IEntity owner)
1722 {
1726
1727 SCR_BaseGameMode gameMode = GetGameMode();
1728
1730 gameMode.GetOnPlayerSpawned().Insert(TunePlayersFrequency);
1731
1732 m_bConfirmedByPlayer = false;
1733
1734 if (IsProxy())
1735 return;
1736
1737 // call later because the SCR_MapMarkerManagerComponent is not yet initted, which creates dynamic markers via SCR_MapMarkerEntrySquadLeader
1738 // Also call later so save game data is applied if needed
1739 gameMode.GetOnGameStart().Insert(CreatePredefinedGroups);
1740 }
1741
1742 //------------------------------------------------------------------------------------------------
1743 // constructor
1748 {
1749 if (!s_Instance)
1750 s_Instance = this;
1751 }
1752
1753 //------------------------------------------------------------------------------------------------
1754 // destructor
1756 {
1757#ifdef DEBUG_GROUPS
1758 if (s_wDebugLayout)
1759 s_wDebugLayout.RemoveFromHierarchy();
1760#endif
1761 }
1762}
EEntityCatalogType
ENotification
ArmaReforgerScripted GetGame()
Definition game.c:1398
bool IsPlayerInGroup(int playerID)
array< SCR_ChimeraCharacter > GetAIMembers()
bool IsPrivate()
bool IsFull()
void SetGroupLeader(int playerID)
Called on the server (authority).
int GetGroupID()
void SCR_AIGroup(IEntitySource src, IEntity parent)
SCR_ECharacterRank GetRequiredRank()
SCR_BaseGameModeComponentClass m_pGameMode
The game mode entity this component is attached to.
SCR_BaseGameMode GetGameMode()
void SCR_BaseGameModeComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
void SCR_CommandingManagerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
SCR_EGroupRole
Group roles.
Get all prefabs that have the spawner data
Get all prefabs that have the spawner the given labels and are valid in the editor mode param catalogType Type to catalog to get prefabs from param editorMode Editor mode to get valid entries from param faction Faction(Optional)
int GetPlayerCount()
ref array< ResourceName > m_aGroupFlags
Definition SCR_Faction.c:84
void SCR_FactionManager(IEntitySource src, IEntity parent)
void SCR_GameModeCampaign(IEntitySource src, IEntity parent)
void AskRemoveAiMemberFromGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
ref array< SCR_AIGroup > m_aDeletionQueue
void CreatePredefinedGroups()
Setup preset groups once.
SCR_AIGroup TryFindEmptyGroup(notnull Faction faction)
void AskAddAiMemberToGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
int m_iPlayableGroupFrequencyMin
void SetConfirmedByPlayer(bool isConfirmed)
SCR_AIGroup GetPlayerGroup(int playerID)
bool m_bConfirmedByPlayer
void SCR_GroupsManagerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
void RPC_SetCanPlayersChangeAttributes(bool isAllowed)
void RPC_DoSetNewGroupsAllowed(bool isAllowed)
bool AreAllGroupsMajorityFull(SCR_EGroupRole groupRole, notnull Faction faction)
bool m_bTuneAgentsRadioToGroupFrequency
ScriptInvoker GetOnCanPlayersChangeAttributeChanged()
bool m_bAllowRejoinPlayerAfterReconnecting
set< Faction > FactionHolder
array< SCR_EGroupRole > GetAvailableGroupRoles(notnull Faction faction, int playerId)
bool IsGroupMenuAllowed()
void DeleteGroupDelayed(SCR_AIGroup group)
void SetCanPlayersChangeAttributes(bool isAllowed)
called on server only
ref map< int, ref FactionHolder > m_mUsedFrequenciesMap
void TunePlayersFrequency(int playerId, IEntity player)
void ClearRequests(int groupID, int playerID)
ScriptInvoker GetOnPlayableGroupRemoved()
bool m_bAllowGroupLeaderVolunteering
void AddDisconnectedPlayer(int playerID, int groupID)
void SetNewGroupsAllowed(bool isAllowed)
called on server only
ref map< Faction, ref array< SCR_AIGroup > > m_mPlayableGroups
void GetGroupFlags(notnull array< ResourceName > targetArray)
void RPC_DoRemoveAIMemberFromGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
bool HasPlayerRequiredRank(SCR_GroupRolePresetConfig preset, int playerId, bool ignoreGroupRequiredRank)
SCR_AIGroup FindGroup(int groupID)
void AssignGroupFrequency(notnull SCR_AIGroup group)
array< SCR_AIGroup > GetPlayableGroupsByFaction(Faction faction)
bool GetNewGroupsAllowed()
void ReleaseFrequency(int frequency, Faction faction)
bool m_bAllowGroupMenu
void OnGroupPlayerRemoved(SCR_AIGroup group, int playerID)
bool CanCreateNewGroup(notnull Faction newGroupFaction)
bool CanPlayersChangeAttributes()
int m_iPlayableGroupFrequencyMax
void OnGroupCreated(SCR_AIGroup group)
Called on clients (proxies) to notice a playable group has been created.
bool m_bNewGroupsAllowed
int m_iPlayableGroupFrequencyOffset
void GetAllPlayableGroups(out array< SCR_AIGroup > outAllGroups)
ref ScriptInvoker m_OnPlayableGroupRemoved
void RequestSetGroupSlave(RplId compID, RplId slaveID)
array< SCR_EGroupRole > GetConfiguredGroupRoles(notnull Faction faction, bool creatableByPlayerFilter=false)
void RpcWrapper(RplId compID, RplId slaveID)
bool m_bTunePlayersRadioToGroupFrequency
int AddPlayerToGroup(int groupID, int playerID)
ref map< int, int > m_mDisconnectedPlayerIDs
<playerID, groupID>
bool IsFrequencyClaimed(int frequency, Faction faction)
void DeleteGroups()
bool IsPlayerInAnyGroup(int playerID)
void OnGroupPlayerAdded(SCR_AIGroup group, int playerID)
ScriptInvoker GetOnPlayableGroupCreated()
bool GetConfirmedByPlayer()
array< SCR_AIGroup > GetSortedPlayableGroupsByFaction(Faction faction)
int m_iMovingPlayerToGroupID
int m_iFreeGroupAmountBeforeRestriction
ScriptInvoker GetOnNewGroupsAllowedChanged()
SCR_AIGroup FindGroupInFaction(SCR_EGroupRole role, notnull Faction faction)
void RPC_DoAddAIMemberToGroup(RplId groupRplCompID, RplId aiCharacterComponentID)
SCR_AIGroup GetFirstNotFullForFaction(notnull Faction faction, SCR_AIGroup ownGroup=null, bool respectPrivate=false)
void RPC_DoSetGroupSlave(RplId masterGroupID, RplId slaveGroupID)
int MovePlayerToGroup(int playerID, int previousGroupID, int newGroupID)
SCR_AIGroup CreateNewPlayableGroup(Faction faction, SCR_EGroupRole groupRole=SCR_EGroupRole.NONE)
void ~SCR_GroupsManagerComponent()
int GetFreeFrequency(Faction frequencyFaction)
SCR_GroupRolePresetConfig FindGroupRolePresetConfig(notnull Faction faction, SCR_EGroupRole role)
bool IsGroupLeaderVolunteeringAllowed()
ref ScriptInvoker m_OnCanPlayersChangeAttributeChanged
void OnAIMemberRemoved(SCR_AIGroup group, AIAgent agent)
bool CanCreateGroupWithLocalPlayerRank(SCR_EGroupRole groupRole, notnull Faction faction)
ref ScriptInvoker m_OnNewGroupsAllowedChanged
bool m_bCanPlayersChangeAttributes
void SetPrivateGroup(int groupID, bool isPrivate)
void RejoinPlayer(int playerID, notnull SCR_Faction faction)
ref map< Faction, int > m_mPlayableGroupFrequencies
void ClaimFrequency(int frequency, Faction faction)
ref ScriptInvoker m_OnPlayableGroupCreated
void OnPlayerFactionChanged(SCR_PlayerFactionAffiliationComponent component, Faction previous, Faction current)
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
enum EVehicleType IEntity
proto external Managed FindComponent(typename typeName)
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
Replication item identifier.
Definition RplId.c:14
array< SCR_ChimeraCharacter > GetAIMembers()
void RemovePlayer(int playerID)
Called on the server (authority).
int GetPlayerCount(bool checkMasterAndSlaves=false)
void SetGroupID(int id)
static ScriptInvoker GetOnPlayerRemoved()
ScriptInvoker GetOnAgentRemoved()
SCR_EGroupRole GetGroupRole()
void AddPlayer(int playerID)
Called on the server (authority).
void SetPresetResource(ResourceName preset)
bool IsPrivacyChangeable()
int GetRequesterIDs(out array< int > valueArray)
void SetPrivate(bool isPrivate)
Called on the server (authority).
void SetSlave(SCR_AIGroup group)
int GetRadioFrequency()
void SetCanDeleteIfNoPlayer(bool deleteEmpty)
Sets if the group should be deleted when all players leave.
int GetMaxMembers()
static ScriptInvoker GetOnPlayerLeaderChanged()
static ScriptInvoker GetOnPlayerAdded()
bool IsPrivate()
int GetGroupID()
bool SetFaction(Faction faction)
bool IsFull()
void SetGroupRole(SCR_EGroupRole groupRole)
Faction GetFaction()
bool GetDeleteIfNoPlayer()
Returns true if the group is set to be deleted when all players leave.
bool IsPlayerInGroup(int playerID)
void SetGroupLeader(int playerID)
Called on the server (authority).
int GetDefaultActiveRadioChannel()
ScriptInvokerBase< SCR_BaseGameMode_PlayerIdAndEntity > GetOnPlayerSpawned()
ScriptInvoker GetOnGameStart()
Get prefab entity Data of type Ignores disabled Data s param dataType class of Data type you with to obtain return Entity Data of given type Null if not found *SCR_BaseEntityCatalogData GetEntityDataOfType(typename dataType)
bool GetCanCreateOnlyPredefinedGroups()
int GetFactionRadioFrequency()
bool IsGroupRolesConfigured()
void GetPredefinedGroups(notnull array< ref SCR_GroupPreset > groupArray)
void GetGroupRolePresetConfigs(notnull array< SCR_GroupRolePresetConfig > groupArray)
bool IsEnabledAutoGroupCreationWhenFull()
bool IsPlayerCommander(int playerId)
IEntity GetGadgetByType(EGadgetType type)
static SCR_GadgetManagerComponent GetGadgetManager(IEntity entity)
array< ResourceName > GetLoadouts()
static int GetLocalPlayerId()
Returns either a valid ID of local player or 0.
Definition Types.c:486
IEntity GetOwner()
Owner entity of the fuel tank.
override void EOnInit(IEntity owner)
proto external int GetAgentsCount()
BaseRadioComponentClass BaseTransceiver
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
override void OnPlayerRegistered(int playerId)
override void OnPlayerDisconnected(int playerId, KickCauseCode cause, int timeout)
proto external PlayerController GetPlayerController()
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
Definition EnNetwork.c:95
RplRcver
Definition RplRcver.c:59
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.
Definition RplChannel.c:14
int RplId
Definition EnNetwork.c:33
proto external string ToString()
Plain C++ pointer, no weak pointers, no memory management.
ScriptInvokerBase< func > ScriptInvoker
Definition tools.c:134