Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_CampaignMilitaryBaseComponent.c
Go to the documentation of this file.
2{
3 [Attribute("{F7E8D4834A3AFF2F}UI/Imagesets/Conflict/conflict-icons-bw.imageset", UIWidgets.ResourceNamePicker, "Imageset with foreground textures", "imageset", category: "Campaign")]
6 //------------------------------------------------------------------------------------------------
9 {
11 }
12}
19typedef ScriptInvokerBase<OnSpawnPointAssignedDelegate> OnSpawnPointAssignedInvoker;
20
23typedef ScriptInvokerBase<OnBaseStateChangedDelegate> OnBaseStateChangedInvoker;
24
25void OnSupplyLimitChanged(SCR_CampaignMilitaryBaseComponent campaignBase, float supplyLimit);
27typedef ScriptInvokerBase<OnSupplyLimitChangedDelegate> OnSupplyLimitChangedInvoker;
28
31typedef ScriptInvokerBase<OnBaseAttackEndDelegate> OnBaseAttackEndInvoker;
32
35typedef ScriptInvokerBase<OnBaseCreatedAsFOBDelegate> OnBaseCreatedAsFOBInvoker;
36
37class SCR_CampaignMilitaryBaseComponent : SCR_MilitaryBaseComponent
38{
39 [Attribute("0", category: "Campaign"), RplProp()]
40 protected bool m_bIsControlPoint;
41
42 [Attribute("0", desc: "Can this base be picked as a faction's main base?", category: "Campaign")]
43 protected bool m_bCanBeHQ;
44
45 [Attribute("1", category: "Campaign")]
47
48 [Attribute("0", desc: "If enabled, this base will be treated as an HQ when handling supply income.", category: "Campaign")]
49 protected bool m_bIsSupplyHub;
50
51 [Attribute("#AR-MapSymbol_Installation", desc: "The display name of this base.", category: "Campaign")]
52 protected string m_sBaseName;
53
54 [Attribute("#AR-MapSymbol_Installation", desc: "The display name of this base, in upper case.", category: "Campaign")]
55 protected string m_sBaseNameUpper;
56
57 [Attribute("", desc: "Name of associated map location (to hide its label)", category: "Campaign")]
58 protected string m_sMapLocationName;
59
60 [Attribute(defvalue: "0", uiwidget: UIWidgets.ComboBox, desc: "Type", category: "Campaign", enumType:SCR_ECampaignBaseType)]
62
63 [Attribute("true", desc: "Enables or disables the automatic creation of resupply tasks upon reaching the supply limit threshold.", category: "Campaign")]
65
66 [Attribute("60", desc: "Defines how much time must elapse before a player can spawn at this base after it has been captured. [s]", category: "Campaign", params: "0 inf")]
67 protected float m_fRespawnDelayAfterCaptureSeconds;
68
69 [Attribute("-1", desc: "How many supplies are periodically replenished. If value is -1, default Gamemode value will be used.", params: "-1 inf 1", category: "Campaign")]
71
72 [Attribute("-1", desc: "How often are supplies replenished in bases [s]. If value is -1, default Gamemode value will be used.", params: "-1 inf 1", category: "Campaign")]
73 protected int m_iSuppliesArrivalInterval;
74
75 [RplProp(), Attribute("0.2", UIWidgets.Slider, "Defines the supply limit as a percentage of total storage capacity (TSC). If the supply falls below this threshold, a resupply request is triggered.", params: "0, 0.9, 0.01", category: "Campaign")]
76 protected float m_fSupplyLimit;
78 [RplProp(), Attribute("0.5", UIWidgets.Slider, "Defines the amount of supplies that are reserved to be stored inside the base.", params: "0.1 0.9 0.1", category: "Campaign")]
79 protected float m_fReservedSupplyAmount;
81 [RplProp(onRplName: "SupplyRequestExecutionPriorityReplicated"), Attribute(defvalue: SCR_Enum.GetDefault(SCR_ESupplyRequestExecutionPriority.MEDIUM), uiwidget: UIWidgets.ComboBox, desc: "Indicates the priority of resupply task for base when resupply request is evaluated.", enumType: SCR_ESupplyRequestExecutionPriority, category: "Campaign")]
85
86 static const float RADIO_RECONFIGURATION_DURATION = 10.0;
87 static const float BARRACKS_REDUCED_DEPLOY_COST = 0.5;
88 static const int UNDER_ATTACK_WARNING_PERIOD = 60;
89 static const int INVALID_PLAYER_INDEX = -1;
90 static const int INVALID_FACTION_INDEX = -1;
91 static const int RESPAWN_DELAY_AFTER_CAPTURE = 180000;
92 static const int RELAY_BASE_RADIUS = 100;
93
94 static const int SUPPLY_DEPOT_CAPACITY = 4500;
95 static const int DEFENDERS_CHECK_PERIOD = 30000;
96 static const int DEFENDERS_REWARD_PERIOD = 120000;
97 static const int DEFENDERS_REWARD_MULTIPLIER = 3;
98 static const float SUPPLY_LIMIT_MIN = 0;
99 static const float SUPPLY_LIMIT_MAX = 0.9;
100
101 protected static const int TICK_TIME = 1;
102 protected static const int CONTESTED_RESPAWN_DELAY = 35;
103 protected static const int BASES_IN_RANGE_RESUPPLY_THRESHOLD = 5; // max bases to be taken into account when calculating supply income
104 protected static const float HQ_VEHICLE_SPAWN_RADIUS = 40;
105 protected static const float HQ_VEHICLE_QUERY_SPACE = 6;
106 protected static const int ENEMY_PRESENCE_EVALUATION_PERIOD_MS = 3000;
113 protected static ref ScriptInvokerBase<OnBaseCapturedDelegate> s_OnBaseCaptured; // <base, playerID>
114
115 protected ref array<SCR_AmbientPatrolSpawnPointComponent> m_aRemnants = {};
116 protected ref array<IEntity> m_aStartingVehicles = {};
117 protected ref array<SCR_ERadioMsg> m_aServiceBuiltMsgQueue = {};
118
119 protected float m_fStartingSupplies;
120 protected float m_fNextFrameCheck;
121 protected float m_fTimer;
122 protected float m_fRadioRangeDefault;
124
125 protected bool m_bLocalPlayerPresent;
126 protected bool m_bWasHQSet;
127
129 protected SCR_EBaseCaptureState m_eCaptureState;
130
131 protected SCR_CampaignMilitaryBaseMapDescriptorComponent m_MapDescriptor;
132
138 protected SCR_CoverageRadioComponent m_RadioComponent;
139
141
144 protected ref array<SCR_AIGroup> m_aDefendersGroups = {};
145
147
153
154 [RplProp(onRplName: "OnHQSet")]
155 protected bool m_bIsHQ;
156
157 [RplProp(onRplName: "OnInitialized")]
158 protected bool m_bInitialized;
159
160 [RplProp()]
161 protected int m_iSupplyRegenAmount;
162
163 [RplProp(onRplName: "OnCapturingFactionChanged")]
165
166 [RplProp()]
168
169 [RplProp(onRplName: "OnRadioRangeChanged")]
170 protected float m_fRadioRange;
171
172 [RplProp(onRplName: "OnRespawnCooldownChanged")]
174
175 [RplProp(onRplName: "OnAttackingFactionChanged")]
176 protected int m_iAttackingFaction = -1;
177
178 [RplProp()]
180
181 [RplProp()]
182 protected bool m_bBuiltByPlayers;
183
184 [RplProp()]
186
187 [RplProp(onRplName: "OnEnemyPresenceChanged")]
188 protected bool m_bEnemiesPresent;
189
190 //------------------------------------------------------------------------------------------------
198
199 //------------------------------------------------------------------------------------------------
207
208 //------------------------------------------------------------------------------------------------
216
217 //------------------------------------------------------------------------------------------------
225
226 //------------------------------------------------------------------------------------------------
234
235 //------------------------------------------------------------------------------------------------
239 static ScriptInvokerBase<OnBaseCapturedDelegate> GetOnBaseCaptured()
240 {
241 if (!s_OnBaseCaptured)
242 s_OnBaseCaptured = new ScriptInvokerBase<OnBaseCapturedDelegate>();
243
244 return s_OnBaseCaptured;
245 }
247 //------------------------------------------------------------------------------------------------
253 //------------------------------------------------------------------------------------------------
255 {
256 m_BaseBuildingComposition = building;
257 }
258
259 //------------------------------------------------------------------------------------------------
264
265 //------------------------------------------------------------------------------------------------
267 {
268 return GetScarcityLevel() > 0;
269 }
270
271 //------------------------------------------------------------------------------------------------
273 {
274 SCR_ResourceConsumer resourceConsumer = GetResourceConsumer();
275 if (!resourceConsumer)
276 return 0;
277
278 float aggregatedResources = resourceConsumer.GetAggregatedResourceValue();
279 float supplyLimitValue = GetSuppliesMax() * m_fSupplyLimit;
280
281 return supplyLimitValue - aggregatedResources;
282 }
283
284 //------------------------------------------------------------------------------------------------
286 {
287 return m_fSupplyLimit;
288 }
289
290 //------------------------------------------------------------------------------------------------
291 void SetSupplyLimit(float value)
292 {
293 if (m_fSupplyLimit == value)
294 return;
295
297 Replication.BumpMe();
298
301 }
302
303 //------------------------------------------------------------------------------------------------
305 {
307 }
308
309 //------------------------------------------------------------------------------------------------
310 void SetReservedSupplyAmount(float value)
311 {
312 if (m_fReservedSupplyAmount == value)
321
322 //------------------------------------------------------------------------------------------------
324 {
326 }
327
328 //------------------------------------------------------------------------------------------------
333
334 //------------------------------------------------------------------------------------------------
336 {
337 int minPriority, maxPriority, newPriority;
338 SCR_Enum.GetRange(SCR_ESupplyRequestExecutionPriority, minPriority, maxPriority);
339
340 newPriority = Math.ClampInt(priority, minPriority, maxPriority);
341 if (newPriority == m_eSupplyRequestExecutionPriority)
342 return;
343
345 Replication.BumpMe();
346
349 }
350
351 //------------------------------------------------------------------------------------------------
352 SCR_ResourceConsumer GetResourceConsumer()
353 {
354 SCR_ResourceComponent resourceComponent = GetResourceComponent();
355 if (!resourceComponent)
356 return null;
357
358 return resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
359 }
360
361 //------------------------------------------------------------------------------------------------
365 {
367 return string.Format("%1 (%2)", GetBaseNameUpperCase(), GetCallsignDisplayNameOnlyUC());
368
369 // it looks like it has not set callsign data, maybe it is dedicated server
370 SCR_Faction scrFaction = SCR_Faction.Cast(faction);
371 if (!scrFaction)
372 return GetBaseNameUpperCase();
374 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
375 if (!campaign)
376 return GetBaseNameUpperCase();
377
378 if (m_iCallsign == INVALID_BASE_CALLSIGN)
379 return GetBaseNameUpperCase();
380
381 int callsignOffset = campaign.GetCallsignOffset();
382 if (callsignOffset == INVALID_BASE_CALLSIGN)
384
385 SCR_MilitaryBaseCallsign callsignInfo;
386
387 // Use index offset for OPFOR so callsigns are not comparable (i.e. Alabama will not always mean Avrora etc.)
388 if (scrFaction == campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR))
389 callsignInfo = scrFaction.GetBaseCallsignByIndex(m_iCallsign);
390 else
391 callsignInfo = scrFaction.GetBaseCallsignByIndex(m_iCallsign, callsignOffset);
392
393 if (!callsignInfo)
394 return GetBaseNameUpperCase();
395
396 return string.Format("%1 (%2)", GetBaseNameUpperCase(), callsignInfo.GetCallsignUpperCase());
397 }
398
399 //------------------------------------------------------------------------------------------------
400 bool IsValidTarget(notnull SCR_CampaignFaction faction)
401 {
402 if (GetFaction() == faction)
403 return false;
404
405 if (!IsHQRadioTrafficPossible(faction))
406 return false;
407
408 return true;
409 }
410
411 //------------------------------------------------------------------------------------------------
412 void SetBuiltByPlayers(bool builtByPlayers)
413 {
414 if (m_bBuiltByPlayers == builtByPlayers)
415 return;
416
417 m_bBuiltByPlayers = builtByPlayers;
418 Replication.BumpMe();
419 }
420
421 //------------------------------------------------------------------------------------------------
423 {
424 return m_bBuiltByPlayers;
425 }
426
427 //------------------------------------------------------------------------------------------------
428 void SetBuiltFaction(notnull Faction faction)
429 {
430 FactionKey factionKey = faction.GetFactionKey();
431 if (m_sBuiltFaction == factionKey)
432 return;
433
434 m_sBuiltFaction = factionKey;
435 Replication.BumpMe();
436 }
437
438 //------------------------------------------------------------------------------------------------
440 {
441 return m_sBuiltFaction;
442 }
443
444 //------------------------------------------------------------------------------------------------
446 {
447 return m_bEnemiesPresent;
448 }
449
450 //------------------------------------------------------------------------------------------------
452 //! \return
454 {
455 return m_bIsControlPoint;
456 }
457
458 //------------------------------------------------------------------------------------------------
461 bool CanBeHQ()
462 {
463 return m_bCanBeHQ;
464 }
465
466 //------------------------------------------------------------------------------------------------
468 //! \return
470 {
472 }
473
474 //------------------------------------------------------------------------------------------------
478 {
479 return m_sMapLocationName;
480 }
481
482 //------------------------------------------------------------------------------------------------
488
489 //------------------------------------------------------------------------------------------------
492 {
493 if (m_bInitialized || IsProxy())
494 return;
495
496 SCR_CoverageRadioComponent radio = SCR_CoverageRadioComponent.Cast(GetOwner().FindComponent(SCR_CoverageRadioComponent));
497 if (radio)
498 radio.SetPower(true);
499
500 m_bInitialized = true;
501 Replication.BumpMe();
503 }
504
505 //------------------------------------------------------------------------------------------------
507 void Disable()
508 {
509 if (IsProxy())
510 return;
511
512 SCR_CoverageRadioComponent radio = SCR_CoverageRadioComponent.Cast(GetOwner().FindComponent(SCR_CoverageRadioComponent));
513 if (radio)
514 radio.SetPower(false);
515
516 GetGame().GetCallqueue().Remove(SpawnBuilding);
517 GetGame().GetCallqueue().Remove(SpawnStartingVehicles);
518 GetGame().GetCallqueue().Remove(EvaluateDefenders);
519 GetGame().GetCallqueue().Remove(EvaluateEnemyPresence);
520 GetGame().GetCallqueue().Remove(SupplyIncomeTimer);
521 GetGame().GetCallqueue().Remove(HandleSpawnPointFaction);
523
524 m_FactionComponent.SetAffiliatedFaction(null);
525
526 RplComponent.DeleteRplEntity(m_BaseBuildingComposition, false);
527
528 m_bInitialized = false;
529 Replication.BumpMe();
530 OnDisabled();
531 }
532
533 //------------------------------------------------------------------------------------------------
536 {
537 if (!m_bInitialized)
538 return;
539
540 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
541 if (!campaign)
542 return;
543
544 // Register default base spawnpoint
545 SCR_SpawnPoint spawnpoint;
546 IEntity child = GetOwner().GetChildren();
547 while (child)
548 {
549 spawnpoint = SCR_SpawnPoint.Cast(child);
550
551 if (spawnpoint)
552 {
553 m_SpawnPoint = spawnpoint;
554
555 SCR_CampaignBuildingProviderComponent buildingProvider = SCR_CampaignBuildingProviderComponent.Cast(GetOwner().FindComponent(SCR_CampaignBuildingProviderComponent));
556 if (buildingProvider)
557 m_SpawnPoint.SetSpawnPositionRange(buildingProvider.GetBuildingRadius());
558 else
559 m_SpawnPoint.SetSpawnPositionRange(m_iRadius);
560
562 m_OnSpawnPointAssigned.Invoke(spawnpoint);
563
564 break;
565 }
566
567 child = child.GetSibling();
568 }
569
570#ifdef ENABLE_DIAG
571 if (SCR_RespawnComponent.Diag_IsCLISpawnEnabled())
573#endif
574
575 // Initialize registered services
576 array<SCR_ServicePointComponent> services = {};
577 GetServices(services);
578
579 foreach (SCR_ServicePointComponent service : services)
580 {
581 OnServiceBuilt(service);
582 }
583
584 if (RplSession.Mode() != RplMode.Dedicated)
585 {
587
588 Faction playerFaction = SCR_FactionManager.SGetLocalPlayerFaction();
589 if (!playerFaction)
590 playerFaction = campaign.GetBaseManager().GetLocalPlayerFaction();
591
592 if (playerFaction)
593 OnLocalPlayerFactionAssigned(playerFaction);
594 else
595 campaign.GetOnFactionAssignedLocalPlayer().Insert(OnLocalPlayerFactionAssigned);
596 }
597
598 campaign.GetBaseManager().GetOnAllBasesInitialized().Insert(OnAllBasesInitialized);
599
600 if (IsProxy())
601 {
602 campaign.GetBaseManager().AddActiveBase();
603 return;
604 }
605 else
606 {
607 if (!m_bIsHQ && SCR_XPHandlerComponent.IsXpSystemEnabled())
608 {
609 GetGame().GetCallqueue().CallLater(EvaluateDefenders, DEFENDERS_CHECK_PERIOD + Math.RandomIntInclusive(0, DEFENDERS_CHECK_PERIOD * 0.1), true);
610 }
611
612 GetGame().GetCallqueue().CallLater(EvaluateEnemyPresence, ENEMY_PRESENCE_EVALUATION_PERIOD_MS + Math.RandomIntInclusive(0, ENEMY_PRESENCE_EVALUATION_PERIOD_MS * 0.1), true);
613 }
614
615 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(GetOwner().FindComponent(SCR_CampaignSeizingComponent));
616 if (seizingComponent)
617 {
618 seizingComponent.GetOnCaptureStart().Insert(OnCaptureStart);
619 seizingComponent.GetOnCaptureInterrupt().Insert(EndCapture);
620 seizingComponent.GetOnCaptureStateChanged().Insert(CaptureStateChanged);
621 }
622
623 bool isSupportedBaseType = m_eType == SCR_ECampaignBaseType.BASE || m_eType == SCR_ECampaignBaseType.SOURCE_BASE;
624 if (isSupportedBaseType && !campaign.IsTutorial())
625 {
626 // Supplies autoregen loop
627 GetGame().GetCallqueue().CallLater(SupplyIncomeTimer, SCR_GameModeCampaign.UI_UPDATE_DELAY, true, false);
628
629 // Refresh spawnpoint faction after loaded data has been applied
630 GetGame().GetCallqueue().CallLater(HandleSpawnPointFaction, SCR_GameModeCampaign.BACKEND_DELAY);
631 }
632 }
633
634 //------------------------------------------------------------------------------------------------
637 void ApplyHeaderSettings(notnull SCR_CampaignCustomBase settings)
638 {
639 m_bCanBeHQ = settings.GetCanBeHQ();
640 m_bDisableWhenUnusedAsHQ = settings.GetDisableWhenUnusedAsHQ();
641 m_bIsControlPoint = settings.IsControlPoint();
642
643 SCR_CoverageRadioComponent coverageComp = SCR_CoverageRadioComponent.Cast(GetOwner().FindComponent(SCR_CoverageRadioComponent));
644
645 if (coverageComp)
646 coverageComp.SetIsSource(m_bCanBeHQ);
647
648 float radioRange = settings.GetRadioRange();
649
650 if (radioRange < 0)
651 return;
652
653 BaseRadioComponent radio = BaseRadioComponent.Cast(GetOwner().FindComponent(BaseRadioComponent));
654
655 if (!radio)
656 return;
657
658 BaseTransceiver transceiver = radio.GetTransceiver(0);
660 if (!transceiver)
661 return;
662
663 m_fRadioRangeDefault = radioRange;
664 transceiver.SetRange(radioRange);
666 }
667
668 //------------------------------------------------------------------------------------------------
669 override void OnServiceStateChanged(SCR_EServicePointStatus state, notnull SCR_ServicePointComponent serviceComponent)
670 {
671 switch (state)
672 {
673 case SCR_EServicePointStatus.UNDER_CONSTRUCTION:
674 {
675 return;
676 }
677
678 case SCR_EServicePointStatus.ONLINE:
679 {
680 OnServiceBuilt(serviceComponent);
681
682 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
683 if (!campaign)
684 return;
685
686 SCR_CampaignMilitaryBaseManager baseManager = campaign.GetBaseManager();
687 if (!baseManager)
688 return;
689
690 baseManager.OnServiceBuilt(state, serviceComponent);
691 return;
692 }
693 }
694 }
695
696 //------------------------------------------------------------------------------------------------
698 void OnServiceBuilt(notnull SCR_ServicePointComponent service)
699 {
700 bool duringInit = (GetGame().GetWorld().GetWorldTime() <= 0);
701
702 // Delayed call so the composition has time to properly load and register its entire hierarchy on clients as well
703 GetGame().GetCallqueue().CallLater(OnServiceBuilt_AfterInit, SCR_GameModeCampaign.MEDIUM_DELAY, false, service);
704
705 EEditableEntityLabel serviceType = service.GetLabel();
706 SCR_ERadioMsg radio = SCR_ERadioMsg.NONE;
708
709 switch (serviceType)
710 {
711 case EEditableEntityLabel.SERVICE_SUPPLY_STORAGE:
712 {
713 radio = SCR_ERadioMsg.BUILT_SUPPLY;
714 break;
715 }
716
717 case EEditableEntityLabel.SERVICE_FUEL:
718 {
719 radio = SCR_ERadioMsg.BUILT_FUEL;
720 break;
721 }
722
723 case EEditableEntityLabel.SERVICE_ARMORY:
724 {
725 radio = SCR_ERadioMsg.BUILT_ARMORY;
726 break;
727 }
728
729 case EEditableEntityLabel.SERVICE_VEHICLE_DEPOT_LIGHT:
730 {
731 radio = SCR_ERadioMsg.BUILT_VEHICLES_LIGHT;
732 break;
733 }
734
735 case EEditableEntityLabel.SERVICE_VEHICLE_DEPOT_HEAVY:
736 {
737 radio = SCR_ERadioMsg.BUILT_VEHICLES_HEAVY;
738 break;
739 }
740
741 case EEditableEntityLabel.SERVICE_ANTENNA:
742 {
743 radio = SCR_ERadioMsg.BUILT_ANTENNA;
744
745 if (!IsProxy())
747
748 break;
750
751 case EEditableEntityLabel.SERVICE_LIVING_AREA:
752 {
753 radio = SCR_ERadioMsg.BUILT_BARRACKS;
754 break;
755 }
757 case EEditableEntityLabel.SERVICE_FIELD_HOSPITAL:
758 {
759 radio = SCR_ERadioMsg.BUILT_FIELD_HOSPITAL;
760 break;
761 }
762
763 case EEditableEntityLabel.SERVICE_HELIPAD:
764 {
765 radio = SCR_ERadioMsg.BUILT_HELIPAD;
766 break;
767 }
768 }
769
770 if (IsProxy())
771 return;
772
773 GetGame().GetCallqueue().CallLater(SetProviderEntity, 1, false, service); // call later to give a time to a composition to properly register in replication.
774
775 if (radio != SCR_ERadioMsg.NONE && owner && IsHQRadioTrafficPossible(GetCampaignFaction(), SCR_ERadioCoverageStatus.BOTH_WAYS) && !duringInit)
776 {
777 m_aServiceBuiltMsgQueue.Insert(radio);
778 GetGame().GetCallqueue().Remove(SendHighestPriorityMessage);
779
780 // Delayed call so we have all messages gathered
781 GetGame().GetCallqueue().CallLater(SendHighestPriorityMessage, SCR_GameModeCampaign.UI_UPDATE_DELAY, false, owner);
782 }
783
785 }
786
787 //------------------------------------------------------------------------------------------------
793
794 //------------------------------------------------------------------------------------------------
796 {
797 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
798 if (!campaign)
799 return 0;
800
801 // For HQs and Supply Hubs
802 if (m_bIsHQ || m_bIsSupplyHub)
803 {
804 // If base has custom value, use it, otherwise use gamemode's regular supplies income
805 if (m_iRegularSuppliesIncomeBase > -1 && !campaign.GetSuppliesAutoRegenerationEnabled())
807 else
808 return campaign.GetRegularSuppliesIncome();
809 }
810
811 // For Forward Operating Bases when supply regeneration is enabled
812 if (campaign.GetSuppliesAutoRegenerationEnabled())
813 return campaign.GetRegularSuppliesIncomeBase();
814
815 // In case of supply regeneration is disabled, no income for FOBs
816 return 0;
817 }
818
819 //------------------------------------------------------------------------------------------------
821 {
822 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
823 if (!campaign)
824 return int.MAX;
825
826 // If Supply Regeneration is enabled, non-supply-hub bases use regular arrival interval
827 if (!m_bIsSupplyHub && campaign.GetSuppliesAutoRegenerationEnabled())
828 return campaign.GetSuppliesArrivalInterval();
829
830 // Supply regeneration is disabled or base is a supply hub, use custom value if set or arrival interval for source bases
831 if (m_iSuppliesArrivalInterval > -1)
832 return m_iSuppliesArrivalInterval;
833 else
834 return campaign.GetSuppliesArrivalIntervalSource();
835 }
836
837 //------------------------------------------------------------------------------------------------
838 protected void SetProviderEntity(notnull SCR_ServicePointComponent service)
840 SCR_CampaignBuildingCompositionComponent buildingComponent = SCR_CampaignBuildingCompositionComponent.Cast(SCR_EntityHelper.GetMainParent(service.GetOwner(), true).FindComponent(SCR_CampaignBuildingCompositionComponent));
841
842 if (buildingComponent && !buildingComponent.GetProviderEntity())
843 {
844 array<SCR_CampaignBuildingProviderComponent> buildingProviders = {};
845 GetBuildingProviders(buildingProviders);
846
847 foreach (SCR_CampaignBuildingProviderComponent provider : buildingProviders)
848 {
849 if (provider && provider.IsMasterProvider())
850 {
851 buildingComponent.SetProviderEntityServer(provider.GetOwner());
852 break;
853 }
854 }
855 }
856 }
858 //------------------------------------------------------------------------------------------------
859 protected void SendHighestPriorityMessage(notnull SCR_CampaignFaction faction)
860 {
861 if (m_aServiceBuiltMsgQueue.IsEmpty())
862 return;
863
864 SCR_ERadioMsg topPriorityEnum = m_aServiceBuiltMsgQueue[0];
865
867 {
868 if (msg < topPriorityEnum)
869 topPriorityEnum = msg;
870 }
871
873 faction.SendHQMessage(topPriorityEnum, m_iCallsign);
874 }
875
876 //------------------------------------------------------------------------------------------------
878 void OnServiceRemoved(notnull SCR_MilitaryBaseLogicComponent service)
879 {
880 SCR_ServicePointComponent serviceCast = SCR_ServicePointComponent.Cast(service);
881
882 if (!serviceCast || serviceCast.GetServiceState() != SCR_EServicePointStatus.ONLINE)
883 return;
884
885 if (IsProxy())
886 return;
887
888 if (serviceCast.GetType() == SCR_EServicePointType.RADIO_ANTENNA)
890
892 }
893
894 //------------------------------------------------------------------------------------------------
896 void OnServiceBuilt_AfterInit(SCR_ServicePointComponent service)
897 {
898 // In case the composition has been deleted in the meantime
899 if (!service)
900 return;
901
902 if (!IsProxy())
903 {
904 ResourceName delegatePrefab = service.GetDelegatePrefab();
905
906 if (delegatePrefab.IsEmpty())
907 return;
908
909 Resource delegateResource = Resource.Load(delegatePrefab);
910
911 if (!delegateResource || !delegateResource.IsValid())
912 return;
913
915 params.TransformMode = ETransformMode.WORLD;
916 service.GetOwner().GetTransform(params.Transform);
917 IEntity delegateEntity = GetGame().SpawnEntityPrefab(delegateResource, null, params);
918
919 if (!delegateEntity)
920 return;
921
922 SCR_ServicePointDelegateComponent delegateComponent = SCR_ServicePointDelegateComponent.Cast(delegateEntity.FindComponent(SCR_ServicePointDelegateComponent));
923
924 if (!delegateComponent)
925 return;
926
927 service.SetDelegate(delegateComponent);
928 delegateComponent.SetParentBaseId(Replication.FindItemId(this));
929 }
930
931 // Delayed call so clients know about the new delegate
932 if (RplSession.Mode() != RplMode.Dedicated)
933 GetGame().GetCallqueue().CallLater(m_MapDescriptor.HandleMapInfo, SCR_GameModeCampaign.DEFAULT_DELAY, false, null);
934 }
935
936 //------------------------------------------------------------------------------------------------
939 {
940 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
941 if (!campaign)
942 return;
944 if (m_SpawnPoint)
945 {
946 m_SpawnPoint.SetFactionKey(string.Empty);
947 m_SpawnPoint = null;
948 }
949
950 if (m_MapDescriptor)
951 m_MapDescriptor.Item().SetVisible(false);
952
953 if (m_UIElement)
954 m_UIElement.SetVisible(false);
955
956 campaign.GetOnFactionAssignedLocalPlayer().Remove(OnLocalPlayerFactionAssigned);
957
958 if (RplSession.Mode() != RplMode.Dedicated)
960
961 campaign.GetBaseManager().GetOnAllBasesInitialized().Remove(OnAllBasesInitialized);
962
963 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(GetOwner().FindComponent(SCR_CampaignSeizingComponent));
964 if (seizingComponent)
965 {
966 seizingComponent.GetOnCaptureStart().Remove(OnCaptureStart);
967 seizingComponent.GetOnCaptureInterrupt().Remove(EndCapture);
968 seizingComponent.GetOnCaptureStateChanged().Remove(CaptureStateChanged);
969 }
970 }
971
972 //------------------------------------------------------------------------------------------------
976 {
977 return m_bInitialized;
978 }
979
980 //------------------------------------------------------------------------------------------------
982 void SetAsHQ(bool isHQ)
983 {
984 if (IsProxy())
985 return;
986
987 m_bIsHQ = isHQ;
988 if (m_bIsHQ)
989 {
991 SCR_CampaignMilitaryBaseComponent previousHQ = faction.GetMainBase();
992 SCR_CampaignMilitaryBaseComponent enemyHQ = SCR_CampaignFactionManager.Cast(GetGame().GetFactionManager()).GetEnemyFaction(faction).GetMainBase();
993 if (previousHQ && previousHQ != this && previousHQ != enemyHQ)
994 {
995 if (previousHQ.GetDisableWhenUnusedAsHQ())
996 previousHQ.Disable();
997 }
998 }
1000 Replication.BumpMe();
1001 OnHQSet();
1002 }
1003
1004 //------------------------------------------------------------------------------------------------
1005 protected void OnHQSet()
1008 if (faction && m_bIsHQ)
1009 {
1010 faction.SetMainBase(this);
1011 m_bWasHQSet = true;
1012 }
1013
1014 if (IsProxy())
1015 return;
1016
1018
1019 GetGame().GetCallqueue().Remove(SpawnStartingVehicles);
1020
1022 {
1023 SupplyIncomeTimer(true);
1024 GetGame().GetCallqueue().CallLater(SpawnStartingVehicles, 1500, false); // Delay so we don't spawn stuff during init
1025 }
1026 }
1027
1028 //------------------------------------------------------------------------------------------------
1031 bool IsHQ()
1032 {
1033 return m_bIsHQ;
1034 }
1035
1036 //------------------------------------------------------------------------------------------------
1039 {
1040 return !m_bIsHQ;
1041 }
1042
1043 //------------------------------------------------------------------------------------------------
1052
1053 //------------------------------------------------------------------------------------------------
1062
1063 //------------------------------------------------------------------------------------------------
1072
1073 //------------------------------------------------------------------------------------------------
1081
1082 //------------------------------------------------------------------------------------------------
1083
1085 {
1086 if (!m_OnBaseCreatedasFOB)
1087 m_OnBaseCreatedasFOB = new OnBaseCreatedAsFOBInvoker();
1088
1089 return m_OnBaseCreatedasFOB;
1090 }
1091
1092 //------------------------------------------------------------------------------------------------
1095 {
1096 return m_fRadioRange;
1097 }
1098
1099 //------------------------------------------------------------------------------------------------
1100 protected float GetRelayRadioRange(notnull BaseRadioComponent radio)
1101 {
1102 float range;
1103 RelayTransceiver transceiver;
1104 float thisRange;
1105
1106 for (int i = 0, count = radio.TransceiversCount(); i < count; i++)
1107 {
1108 transceiver = RelayTransceiver.Cast(radio.GetTransceiver(i));
1109
1110 if (!transceiver)
1111 continue;
1112
1113 thisRange = transceiver.GetRange();
1114
1115 if (thisRange <= range)
1116 continue;
1117
1118 range = thisRange;
1119 }
1120
1121 return range;
1122 }
1123
1124 //------------------------------------------------------------------------------------------------
1125 bool CanReachByRadio(notnull IEntity entity)
1127 SCR_CoverageRadioComponent radio = SCR_CoverageRadioComponent.Cast(entity.FindComponent(SCR_CoverageRadioComponent));
1128
1129 if (!radio)
1130 return false;
1131
1132 return m_RadioComponent.ConnectedRadiosContain(radio, true);
1133 }
1134
1135 //------------------------------------------------------------------------------------------------
1138 SCR_ERadioCoverageStatus GetHQRadioCoverage(notnull SCR_CampaignFaction faction)
1139 {
1140 SCR_CampaignMilitaryBaseComponent hq = faction.GetMainBase();
1141
1142 if (!hq)
1143 return SCR_ERadioCoverageStatus.NONE;
1144
1145 SCR_CoverageRadioComponent radioHQ = SCR_CoverageRadioComponent.Cast(hq.GetOwner().FindComponent(SCR_CoverageRadioComponent));
1146
1147 if (!radioHQ)
1148 return SCR_ERadioCoverageStatus.NONE;
1149
1150 string encryption = radioHQ.GetEncryptionKey();
1151
1152 SCR_CoverageRadioComponent radio = SCR_CoverageRadioComponent.Cast(GetOwner().FindComponent(SCR_CoverageRadioComponent));
1153
1154 if (!radio)
1155 return SCR_ERadioCoverageStatus.NONE;
1156
1157 return radio.GetCoverageByEncryption(encryption);
1158 }
1159
1160 //------------------------------------------------------------------------------------------------
1161 //!
1162 //! \param[in] faction
1163 //! \param[in] direction
1164 //! \return
1165 bool IsHQRadioTrafficPossible(notnull SCR_CampaignFaction faction, SCR_ERadioCoverageStatus direction = SCR_ERadioCoverageStatus.RECEIVE)
1166 {
1167 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1168
1169 if (campaign && faction == campaign.GetFactionByEnum(SCR_ECampaignFaction.INDFOR))
1170 return true;
1171
1172 SCR_ERadioCoverageStatus status = GetHQRadioCoverage(faction);
1173
1174 switch (direction)
1175 {
1176 case SCR_ERadioCoverageStatus.RECEIVE:
1177 {
1178 return (status == SCR_ERadioCoverageStatus.RECEIVE || status == SCR_ERadioCoverageStatus.BOTH_WAYS);
1179 }
1180
1181 case SCR_ERadioCoverageStatus.SEND:
1182 {
1183 return (status == SCR_ERadioCoverageStatus.SEND || status == SCR_ERadioCoverageStatus.BOTH_WAYS);
1184 }
1185 }
1186
1187 return (status == direction);
1188 }
1189
1190 //------------------------------------------------------------------------------------------------
1191 protected void OnLocalPlayerFactionAssigned(Faction assignedFaction)
1192 {
1193 m_MapDescriptor.MapSetup(assignedFaction);
1194 m_MapDescriptor.HandleMapInfo(SCR_CampaignFaction.Cast(assignedFaction));
1196 }
1197
1198 //------------------------------------------------------------------------------------------------
1201 {
1204
1205 return 1.0;
1206 }
1207
1208 //------------------------------------------------------------------------------------------------
1209 protected void OnCaptureStart(SCR_Faction faction)
1210 {
1211 SCR_CampaignFaction factionC = SCR_CampaignFaction.Cast(faction);
1212
1213 if (!factionC)
1214 return;
1215
1216 BeginCapture(factionC);
1217 }
1218
1219 //------------------------------------------------------------------------------------------------
1220 //!
1221 //! \param[in] attackingFaction
1222 void NotifyAboutEnemyAttack(notnull Faction attackingFaction)
1223 {
1224 SCR_CampaignFaction campaignFaction = GetCampaignFaction();
1225 if (!campaignFaction)
1226 return;
1227
1228 if (!IsHQRadioTrafficPossible(campaignFaction))
1229 return;
1230
1231 ChimeraWorld world = GetOwner().GetWorld();
1232
1233 if (!world)
1234 return;
1235
1236 WorldTimestamp curTime = world.GetServerTimestamp();
1238 {
1240 return;
1241 }
1242
1243 campaignFaction.SendHQMessage(SCR_ERadioMsg.BASE_UNDER_ATTACK, GetCallsign());
1245
1246 if (GetCapturingFaction())
1247 return;
1248
1249 FactionManager fManager = GetGame().GetFactionManager();
1250
1251 if (!fManager)
1252 return;
1253
1254 SetAttackingFaction(fManager.GetFactionIndex(attackingFaction));
1255 }
1256
1257 //------------------------------------------------------------------------------------------------
1258
1261 if (IsProxy())
1262 return;
1263
1264 if (!m_CapturingFaction)
1265 return;
1266 m_CapturingFaction = null;
1268
1269 m_iCapturingFaction = INVALID_FACTION_INDEX;
1270 Replication.BumpMe();
1272
1273 if (m_OnBaseAttackEnd)
1274 m_OnBaseAttackEnd.Invoke(this);
1275 }
1276
1277 //------------------------------------------------------------------------------------------------
1278 void CaptureStateChanged(SCR_EBaseCaptureState state)
1279 {
1280 m_eCaptureState = state;
1282 Replication.BumpMe();
1283
1284 // Spawning ability is impacted by the capture state so we must update accordingly
1286 }
1287
1288 //------------------------------------------------------------------------------------------------
1291 {
1292 if (!m_UIElement)
1293 return;
1294
1295 m_UIElement.SetCaptureWarning(m_eCaptureState == SCR_EBaseCaptureState.CONTESTED || m_eCaptureState == SCR_EBaseCaptureState.CAPTURING);
1296 }
1297
1298 //------------------------------------------------------------------------------------------------
1299 SCR_EBaseCaptureState GetCaptureState()
1300 {
1301 return m_eCaptureState;
1302 }
1303
1304 //------------------------------------------------------------------------------------------------
1307 {
1308 return m_iReconfiguredBy;
1309 }
1310
1311 //------------------------------------------------------------------------------------------------
1314 {
1316 }
1317
1318 //------------------------------------------------------------------------------------------------
1321 {
1322 if (IsProxy() || !faction)
1323 return false;
1324
1325 // The capturing faction already owns this base, return
1326 if (faction == GetFaction())
1327 return false;
1328
1329 // Change the capturing faction
1330 m_CapturingFaction = faction;
1331
1332 m_iCapturingFaction = SCR_CampaignFactionManager.Cast(GetGame().GetFactionManager()).GetFactionIndex(faction);
1333 m_sCapturingFaction = faction.GetFactionKey();
1334
1335 m_iReconfiguredBy = playerID;
1336 Replication.BumpMe();
1338 NotifyAboutEnemyAttack(faction);
1340 if (m_OnBaseUnderAttack)
1341 m_OnBaseUnderAttack.Invoke(this, GetFaction(true), faction);
1342
1343 return true;
1344 }
1345
1346 //------------------------------------------------------------------------------------------------
1350 void CaptureRelay(notnull SCR_CampaignFaction faction, int playerId)
1351 {
1352 if (m_eType != SCR_ECampaignBaseType.RELAY)
1353 return;
1354
1355 if (m_RplComponent.Role() != RplRole.Authority)
1356 return;
1357
1358 if (BeginCapture(faction, playerId))
1359 SetFaction(faction);
1360
1361 if (s_OnBaseCaptured)
1362 s_OnBaseCaptured.Invoke(this, playerId);
1363
1364 if (playerId == INVALID_PLAYER_INDEX)
1365 return;
1366
1367 SCR_PlayerController controller = SCR_PlayerController.Cast(GetGame().GetPlayerManager().GetPlayerController(playerId));
1368 if (!controller)
1369 return;
1370
1372 if (networkComp)
1373 networkComp.SendPlayerMessage(SCR_ERadioMsg.RELAY);
1374 }
1375
1376 //------------------------------------------------------------------------------------------------
1379 {
1380 if (!m_SpawnPoint)
1381 return;
1382
1384 FactionKey currentKey = m_SpawnPoint.GetFactionKey();
1385 FactionKey ownerKey;
1386 FactionKey finalKey;
1387
1388 if (owner)
1389 {
1390 ownerKey = owner.GetFactionKey();
1391 finalKey = ownerKey;
1392
1393 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1394 if (campaign && owner == campaign.GetFactionByEnum(SCR_ECampaignFaction.INDFOR))
1395 {
1396 if (!campaign.GetINDFORCanSpawnOnBases() || (!campaign.GetINDFORCanSpawnOnDistantBases() && !IsHQRadioTrafficPossible(campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR)) && !IsHQRadioTrafficPossible(campaign.GetFactionByEnum(SCR_ECampaignFaction.OPFOR))))
1397 finalKey = FactionKey.Empty;
1398 }
1399 }
1400
1401 if (ownerKey == FactionKey.Empty)
1402 {
1403 if (currentKey != FactionKey.Empty)
1404 m_SpawnPoint.SetFactionKey(FactionKey.Empty);
1405
1406 return;
1407 }
1408
1409 if (owner && !m_bIsHQ && !IsHQRadioTrafficPossible(owner, SCR_ERadioCoverageStatus.BOTH_WAYS))
1410 finalKey = FactionKey.Empty;
1411
1412 ChimeraWorld world = GetOwner().GetWorld();
1413 if (!m_bIsHQ && (m_eCaptureState != SCR_EBaseCaptureState.NONE || world.GetServerTimestamp().Less(m_fRespawnAvailableSince)))
1414 finalKey = FactionKey.Empty;
1415
1416 if (finalKey == currentKey)
1417 return;
1418
1419 m_SpawnPoint.SetFactionKey(finalKey);
1420 }
1421 //------------------------------------------------------------------------------------------------
1424 {
1425 return m_SpawnPoint;
1426 }
1427
1428 //------------------------------------------------------------------------------------------------
1431 {
1432 super.OnCapturingFactionChanged();
1433
1434 SCR_CampaignFactionManager factionmanager = SCR_CampaignFactionManager.Cast(GetGame().GetFactionManager());
1435 if (!factionmanager)
1436 return;
1437
1439 m_CapturingFaction = factionmanager.GetCampaignFactionByIndex(m_iCapturingFaction);
1440 else
1441 m_CapturingFaction = factionmanager.GetCampaignFactionByKey(m_sCapturingFaction);
1442
1443 if (!IsProxy())
1444 {
1445 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1446
1447 if (campaign)
1448 campaign.GetBaseManager().EvaluateControlPoints();
1449 }
1450
1451 if (RplSession.Mode() != RplMode.Dedicated)
1452 {
1453 if (m_CapturingFaction && GetFaction() == SCR_FactionManager.SGetLocalPlayerFaction())
1454 FlashBaseIcon(faction: m_CapturingFaction, infiniteTimer: true);
1455 else
1456 FlashBaseIcon(changeToDefault: true);
1457 }
1458 }
1459
1460 //------------------------------------------------------------------------------------------------
1462 void FlashBaseIcon(float remainingTime = 0, Faction faction = null, bool changeToDefault = false, bool infiniteTimer = false)
1463 {
1464 GetGame().GetCallqueue().Remove(FlashBaseIcon);
1465
1466 if (m_UIElement)
1467 m_UIElement.FlashBaseIcon(faction, changeToDefault);
1468
1469 remainingTime -= SCR_CampaignFeedbackComponent.ICON_FLASH_PERIOD;
1470
1471 if (infiniteTimer || remainingTime > 0 || !changeToDefault)
1472 GetGame().GetCallqueue().CallLater(FlashBaseIcon, SCR_CampaignFeedbackComponent.ICON_FLASH_PERIOD * 1000, false, remainingTime, faction, !changeToDefault, infiniteTimer);
1473 }
1474
1475 //------------------------------------------------------------------------------------------------
1478 {
1479 if (!IsProxy())
1480 {
1482 SupplyIncomeTimer(true);
1483 }
1484
1485 if (m_MapDescriptor && RplSession.Mode() != RplMode.Dedicated)
1486 m_MapDescriptor.HandleMapInfo();
1487
1488 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1489
1490 if (campaign)
1491 campaign.GetBaseManager().GetOnSignalChanged().Invoke(this);
1492 }
1493
1494 //------------------------------------------------------------------------------------------------
1495 protected void OnSuppliesChanged()
1496 {
1497 if (!IsProxy() && !m_bIsHQ)
1499
1500 if (RplSession.Mode() != RplMode.Dedicated && m_UIElement)
1501 m_UIElement.SetIconInfoText();
1502 }
1503
1504 //------------------------------------------------------------------------------------------------
1506 override protected void OnFactionChanged(FactionAffiliationComponent owner, Faction previousFaction, Faction faction)
1507 {
1508 super.OnFactionChanged(owner, previousFaction, faction);
1509
1511 m_OnFactionChangedExtended.Invoke(this, previousFaction, faction);
1512
1513 if (!GetGame().InPlayMode())
1514 return;
1515
1516 SCR_CampaignFaction newCampaignFaction = SCR_CampaignFaction.Cast(faction);
1517
1518 if (!newCampaignFaction)
1519 return;
1520
1521 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1522
1523 if (!campaign)
1524 return;
1525
1526 float curTime = GetGame().GetWorld().GetWorldTime();
1527
1528 if (!IsProxy())
1529 {
1530 bool wasCaptured = IsBeingCaptured();
1531 EndCapture();
1532 m_mDefendersData.Clear();
1534 Replication.BumpMe();
1535
1536 ChangeRadioSettings(newCampaignFaction);
1537
1538 BaseGameMode gameMode = GetGame().GetGameMode();
1539 if (gameMode && wasCaptured && previousFaction && previousFaction != faction)
1540 {
1541 SCR_XPHandlerComponent xpHandlerComponent = SCR_XPHandlerComponent.Cast(gameMode.FindComponent(SCR_XPHandlerComponent));
1542 if (xpHandlerComponent)
1543 xpHandlerComponent.OnBaseSeized(this);
1544 }
1545
1546 // Update signal coverage only if the base was seized during normal play, not at the start
1547 if (curTime > 10000)
1548 {
1549 campaign.GetBaseManager().RecalculateRadioCoverage(campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR));
1550 campaign.GetBaseManager().RecalculateRadioCoverage(campaign.GetFactionByEnum(SCR_ECampaignFaction.OPFOR));
1551 }
1552
1553 // Reset timer for reinforcements
1554 SupplyIncomeTimer(true);
1555
1556 // CallLater for the starting bases of factions, where the faction is set before resources are properly initialized, resulting in incorrect Supply Regeneration calculation
1557 float currentSupplies = GetSupplies();
1558 float maxSupplies = GetSuppliesMax();
1559 GetGame().GetCallqueue().CallLater(CalculateSupplyRegenerationAmount, 1, false, currentSupplies, maxSupplies, newCampaignFaction);
1560
1561 // Delay respawn possibility at newly-captured bases
1562 if (!m_bIsHQ && m_bInitialized && newCampaignFaction.IsPlayable() && campaign.GetBaseManager().IsBasesInitDone() && curTime > SCR_GameModeCampaign.BACKEND_DELAY)
1563 {
1564 ChimeraWorld world = GetOwner().GetWorld();
1565 m_fRespawnAvailableSince = world.GetServerTimestamp().PlusMilliseconds(m_fRespawnDelayAfterCaptureSeconds * 1000);
1567 Replication.BumpMe();
1568 }
1569
1572
1573 // If some Remnants live, send them to recapture
1574 if (newCampaignFaction.IsPlayable() && !m_bIsHQ)
1575 {
1576 foreach (SCR_AmbientPatrolSpawnPointComponent remnants : m_aRemnants)
1577 {
1578 AIGroup grp = remnants.GetSpawnedGroup();
1579
1580 // Make sure groups which are not spawned at this point don't spawn in later
1581 if (grp && !remnants.IsGroupActive())
1582 {
1583 remnants.SetMembersAlive(0);
1584 RplComponent.DeleteRplEntity(grp, false);
1585 continue;
1586 }
1587 else if (!grp)
1588 {
1589 continue;
1590 }
1591
1593 params.TransformMode = ETransformMode.WORLD;
1594 params.Transform[3] = GetOwner().GetOrigin();
1595 m_SeekDestroyWP = SCR_TimedWaypoint.Cast(GetGame().SpawnEntityPrefabLocal(Resource.Load(SCR_GameModeCampaign.GetInstance().GetSeekDestroyWaypointPrefab()), null, params));
1596 m_SeekDestroyWP.SetHoldingTime(60);
1597
1598 if (m_SeekDestroyWP)
1599 grp.AddWaypointAt(m_SeekDestroyWP, 0);
1600 }
1601 }
1602
1603 // Do an auto save every time a base was captured
1604 if (!SCR_PersistenceSystem.IsLoadInProgress() && (GetGame().GetWorld().GetWorldTime() > campaign.BACKEND_DELAY))
1605 GetGame().GetSaveGameManager().RequestSavePoint(ESaveGameType.AUTO);
1606 }
1607 else
1608 {
1609 if (newCampaignFaction && m_bIsHQ && !m_bWasHQSet)
1610 {
1611 newCampaignFaction.SetMainBase(this);
1612 m_bWasHQSet = true;
1613 }
1615
1616 if (RplSession.Mode() != RplMode.Dedicated)
1617 {
1618 if (m_UIElement)
1619 m_UIElement.FlashBaseIcon(changeToDefault: true);
1620
1621 if (m_MapDescriptor)
1622 m_MapDescriptor.HandleMapInfo();
1623
1624 SCR_CampaignFaction playerFaction = SCR_CampaignFaction.Cast(SCR_FactionManager.SGetLocalPlayerFaction());
1626
1627 // TODO: Move this to PlayRadioMsg so it is checked for player being inside radio range
1628 if (campaign)
1629 {
1630 if (player && playerFaction && playerFaction != GetCampaignFaction() && IsHQRadioTrafficPossible(playerFaction))
1632 if (GetCampaignFaction())
1633 SCR_PopUpNotification.GetInstance().PopupMsg("#AR-Campaign_BaseSeized-UC", prio: SCR_ECampaignPopupPriority.BASE_LOST, param1: GetCampaignFaction().GetFactionNameUpperCase(), param2: GetBaseNameUpperCase());
1634 else
1635 {
1636 SCR_CampaignFaction factionR = campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR);
1637
1638 if (factionR)
1640 }
1641
1642 /*if (playerFaction == m_OwningFactionPrevious)
1643 campaign.ShowHint(SCR_ECampaignHints.BASE_LOST); */
1644 }
1645 }
1646 }
1647
1648 m_OwningFactionPrevious = newCampaignFaction;
1649 }
1650
1651 //------------------------------------------------------------------------------------------------
1653 void OnBaseCreatedAsFOB(Faction establishingFaction)
1654 {
1656 m_OnBaseCreatedasFOB.Invoke(this, establishingFaction);
1657 }
1658
1659 //------------------------------------------------------------------------------------------------
1662 {
1663 if (m_MapDescriptor && (RplSession.Mode() != RplMode.Dedicated))
1664 m_MapDescriptor.HandleMapInfo();
1665 }
1666
1667 //------------------------------------------------------------------------------------------------
1669 //! \param[in] faction
1670 void ChangeRadioSettings(notnull SCR_Faction faction)
1671 {
1672 if (!m_RadioComponent || m_RadioComponent.TransceiversCount() == 0)
1673 return;
1674
1675 BaseTransceiver tsv = m_RadioComponent.GetTransceiver(0);
1676
1677 if (!tsv)
1678 return;
1679
1680 m_RadioComponent.SetEncryptionKey(faction.GetFactionRadioEncryptionKey());
1681
1682 int factionFrequency = faction.GetFactionRadioFrequency();
1683
1684 // Setting frequency outside of limits causes a VME
1685 if (factionFrequency < tsv.GetMinFrequency() || factionFrequency > tsv.GetMaxFrequency())
1686 return;
1687
1688 tsv.SetFrequency(factionFrequency);
1689
1691
1692 array<SCR_CoverageRadioComponent> radios = {};
1693 m_RadioComponent.GetRadiosInRange(radios);
1694
1695 foreach (SCR_CoverageRadioComponent radio : radios)
1696 {
1697 if (!radio)
1698 continue;
1699
1700 SCR_CampaignMilitaryBaseComponent base = SCR_CampaignMilitaryBaseComponent.Cast(radio.GetOwner().FindComponent(SCR_CampaignMilitaryBaseComponent));
1701
1702 if (base)
1703 base.RefreshSeizingTimers();
1705 }
1706
1707 //------------------------------------------------------------------------------------------------
1709 {
1710 foreach (SCR_MilitaryBaseLogicComponent logic : m_aSystems)
1711 {
1712 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(logic);
1713
1714 if (!seizingComponent)
1715 continue;
1717 seizingComponent.RefreshSeizingTimer();
1718 }
1719 }
1720
1721 //------------------------------------------------------------------------------------------------
1723 //! \param[in] remnants
1724 void RegisterRemnants(notnull SCR_AmbientPatrolSpawnPointComponent remnants)
1725 {
1726 m_aRemnants.Insert(remnants);
1727 }
1728
1729 //------------------------------------------------------------------------------------------------
1732 {
1734
1735 if (!componentData)
1736 return ResourceName.Empty;
1737
1738 return componentData.GetBuildingIconImageset();
1739 }
1740
1741 //------------------------------------------------------------------------------------------------
1744 {
1745 // event is called for every spawned entity of the AI group. Prevent adding duplicates.
1746 if (m_aDefendersGroups.Contains(grp))
1747 return;
1748
1749 m_aDefendersGroups.Insert(grp);
1750 grp.GetOnEmpty().Insert(RemoveGroup);
1751 }
1752
1753 //------------------------------------------------------------------------------------------------
1756 {
1757 m_aDefendersGroups.RemoveItem(grp);
1758 }
1759
1760 //------------------------------------------------------------------------------------------------
1763 {
1764 return m_aDefendersGroups.Contains(grp);
1765 }
1766
1767 //------------------------------------------------------------------------------------------------
1768 override void SetCallsign(notnull SCR_Faction faction)
1769 {
1770 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1771 if (!campaign)
1772 return;
1774 if (m_iCallsign == INVALID_BASE_CALLSIGN)
1775 return;
1776
1777 int callsignOffset = campaign.GetCallsignOffset();
1778 campaign.GetOnCallsignOffsetChanged().Remove(OnCallsignAssigned);
1779
1780 if (callsignOffset == INVALID_BASE_CALLSIGN)
1781 {
1782 campaign.GetOnCallsignOffsetChanged().Insert(OnCallsignAssigned);
1783 return;
1784 }
1785
1786 // Use index offset for OPFOR so callsigns are not comparable (i.e. Alabama will not always mean Avrora etc.)
1787 SCR_MilitaryBaseCallsign callsignInfo;
1788 if (faction == campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR))
1789 callsignInfo = faction.GetBaseCallsignByIndex(m_iCallsign);
1790 else
1791 callsignInfo = faction.GetBaseCallsignByIndex(m_iCallsign, callsignOffset);
1792
1793 if (!callsignInfo)
1794 return;
1795
1796 m_sCallsign = callsignInfo.GetCallsign();
1797 m_sCallsignNameOnly = callsignInfo.GetCallsignShort();
1798 m_sCallsignNameOnlyUC = callsignInfo.GetCallsignUpperCase();
1799 m_iCallsignSignal = callsignInfo.GetSignalIndex();
1800 }
1801
1802 //------------------------------------------------------------------------------------------------
1804 {
1805 // Handled separately in SCR_CampaignMilitaryBaseManager.InitializeBases()
1806 return;
1807 }
1808
1809 //------------------------------------------------------------------------------------------------
1812 protected void SupplyIncomeTimer(bool reset = false)
1813 {
1814 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1815
1816 if (!campaign)
1817 return;
1818
1819 ChimeraWorld world = GetOwner().GetWorld();
1820
1821 if (!world)
1822 {
1824 Replication.BumpMe();
1825 return;
1826 }
1827
1828 WorldTimestamp curTime = world.GetServerTimestamp();
1829
1830 if (reset)
1831 {
1832 SetSuppliesArrivalTime(curTime.PlusSeconds(GetSuppliesArrivalTimer()));
1833 return;
1834 }
1835
1836 SCR_CampaignFaction owner = GetCampaignFaction();
1837
1838 // Add supplies only to captured bases in HQ radio range which are not under attack
1839 if (!owner || !m_SpawnPoint || (m_eType != SCR_ECampaignBaseType.SOURCE_BASE && !IsHQRadioTrafficPossible(owner, SCR_ERadioCoverageStatus.BOTH_WAYS)) || (m_CapturingFaction && m_CapturingFaction != owner) || world.GetServerTimestamp().Less(m_fRespawnAvailableSince))
1840 {
1842 Replication.BumpMe();
1843 return;
1844 }
1845
1846 if (curTime.GreaterEqual(m_fSuppliesArrivalTime))
1847 {
1849 SetSuppliesArrivalTime(curTime.PlusSeconds(GetSuppliesArrivalTimer()));
1850 }
1851 }
1852
1853 //------------------------------------------------------------------------------------------------
1855 protected void AddRegularSupplyPackage(notnull SCR_CampaignFaction faction)
1856 {
1857 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1858 float currentSupplies = GetSupplies();
1859 float maxSupplies = GetSuppliesMax();
1860
1861 CalculateSupplyRegenerationAmount(currentSupplies, maxSupplies, faction);
1862
1863 float spaceLimit;
1864
1865 if (m_bIsHQ)
1866 spaceLimit = float.MAX;
1867 else
1868 spaceLimit = campaign.GetSuppliesReplenishThreshold() - currentSupplies;
1869
1870 spaceLimit = Math.Min(spaceLimit, maxSupplies - currentSupplies);
1871 if (spaceLimit <= 0 || currentSupplies >= maxSupplies)
1872 return;
1873
1874 AddSupplies(Math.Min(m_iSupplyRegenAmount, spaceLimit));
1875 }
1876
1877 //------------------------------------------------------------------------------------------------
1882 void CalculateSupplyRegenerationAmount(float currentSupplies, float maxSupplies, notnull SCR_CampaignFaction faction)
1883 {
1884 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
1885
1886 int quickReplenishThreshold = campaign.GetQuickSuppliesReplenishThreshold();
1887 float quickReplenishMultiplier = campaign.GetQuickSuppliesReplenishMultiplier();
1888 int income = GetSuppliesIncomeAmount();
1889 int toAdd;
1890
1891 if (currentSupplies < quickReplenishThreshold)
1892 {
1893 int incomeHQQuick = income * quickReplenishMultiplier;
1894 incomeHQQuick = Math.Min(incomeHQQuick, quickReplenishThreshold - currentSupplies);
1895 toAdd = Math.Max(incomeHQQuick, income);
1896 }
1897 else
1898 {
1899 toAdd = income;
1900 }
1901
1902 int extraBasesCount;
1903
1904 if (!m_bIsHQ && campaign.GetSuppliesAutoRegenerationEnabled())
1905 {
1907 array<SCR_CoverageRadioComponent> radios = {};
1908 m_RadioComponent.GetRadiosInRange(radios);
1910 foreach (SCR_CoverageRadioComponent radio : radios)
1911 {
1912 base = SCR_CampaignMilitaryBaseComponent.Cast(radio.GetOwner().FindComponent(SCR_CampaignMilitaryBaseComponent));
1913
1914 if (!base)
1915 continue;
1916
1917 if (base.GetType() != SCR_ECampaignBaseType.BASE)
1918 continue;
1919
1920 if (base.GetCampaignFaction() != faction)
1921 continue;
1922
1923 if (!base.IsHQRadioTrafficPossible(faction))
1924 continue;
1925
1926 extraBasesCount++;
1927
1928 if (extraBasesCount == BASES_IN_RANGE_RESUPPLY_THRESHOLD)
1929 break;
1930 }
1931 }
1932
1933 toAdd += (SCR_GameModeCampaign.GetInstance().GetRegularSuppliesIncomeExtra() * extraBasesCount);
1934
1935 m_iSupplyRegenAmount = toAdd;
1936 Replication.BumpMe();
1937 }
1938
1939 //------------------------------------------------------------------------------------------------
1941 SCR_CampaignMilitaryBaseMapDescriptorComponent GetMapDescriptor()
1942 {
1943 return m_MapDescriptor;
1945
1946 //------------------------------------------------------------------------------------------------
1949 {
1950 return m_UIElement;
1951 }
1952
1953 //------------------------------------------------------------------------------------------------
1956 bool GetIsEntityInMyRange(notnull IEntity entity)
1957 {
1958 return vector.Distance(entity.GetOrigin(), GetOwner().GetOrigin()) <= GetRadioRange();
1959 }
1960
1961 //------------------------------------------------------------------------------------------------
1965 SCR_ResourceComponent resourceComponent = GetResourceComponent();
1966
1967 if (!resourceComponent)
1968 return 0.0;
1969
1970 SCR_ResourceConsumer resourceConsumer = resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
1971
1972 if (!resourceConsumer)
1973 return 0.0;
1974
1975 if (!IsProxy())
1976 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
1977
1978 return resourceConsumer.GetAggregatedResourceValue();
1979 }
1980
1981 //------------------------------------------------------------------------------------------------
1982
1984 {
1985 SCR_ResourceComponent resourceComponent = GetResourceComponent();
1986
1987 if (!resourceComponent)
1988 return 0.0;
1989
1990 SCR_ResourceConsumer resourceConsumer = resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
1991
1992 if (!resourceConsumer)
1993 return 0.0;
1994
1995 if (!IsProxy())
1996 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
1997
1998 return resourceConsumer.GetAggregatedMaxResourceValue();
1999 }
2000
2001 //------------------------------------------------------------------------------------------------
2004 {
2005 return m_iSupplyRegenAmount;
2006 }
2007
2008 //------------------------------------------------------------------------------------------------
2009 override void RegisterLogicComponent(notnull SCR_MilitaryBaseLogicComponent component)
2011 super.RegisterLogicComponent(component);
2012
2013 SCR_FlagComponent flag = SCR_FlagComponent.Cast(component);
2014
2015 // This is indeed a repeated call from super
2016 // Sandbox mil bases spawned via HQ tents are interfering with shown flag as they have different faction
2017 // It's a temporary fix until we switch to full free building and bases on top of each other will no longer be a thing
2018 if (flag && GetFaction())
2019 GetGame().GetCallqueue().CallLater(UpdateFlags, 1000, false);
2020 }
2021
2022 //------------------------------------------------------------------------------------------------
2025 {
2026 if (m_sMapLocationName.IsEmpty() || !GetGame().GetWorld())
2027 return;
2028
2029 GenericEntity ent = GenericEntity.Cast(GetGame().GetWorld().FindEntityByName(m_sMapLocationName));
2030
2031 if (!ent)
2032 return;
2033
2035
2036 if (!comp)
2037 return;
2038
2039 MapItem item = comp.Item();
2040
2041 if (!item)
2042 return;
2043
2044 item.SetVisible(false);
2045 }
2046
2047 //------------------------------------------------------------------------------------------------
2049 SCR_ResourceComponent GetResourceComponent()
2050 {
2051 return SCR_ResourceComponent.FindResourceComponent(GetOwner());
2052 }
2053
2054 //------------------------------------------------------------------------------------------------
2056 //! \param[in] suppliesCount
2057 //! \param[in] replicate
2058 void AddSupplies(int suppliesCount, bool replicate = true)
2059 {
2060 if (suppliesCount == 0)
2061 return;
2062
2063 SCR_ResourceComponent resourceComponent = GetResourceComponent();
2064
2065 if (!resourceComponent)
2066 return;
2067
2068 if (suppliesCount > 0)
2069 {
2070 SCR_ResourceGenerator resourceGenerator = resourceComponent.GetGenerator(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
2071
2072 if (!resourceGenerator)
2073 return;
2074
2075 resourceGenerator.RequestGeneration(suppliesCount);
2077 else
2078 {
2079 SCR_ResourceConsumer resourceConsumer = resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
2080
2081 if (!resourceConsumer)
2082 return;
2083
2084 resourceConsumer.RequestConsumtion(-suppliesCount);
2085 }
2086
2088
2090 m_SuppliesArrivalInvoker.Invoke();
2091 }
2092
2093 //------------------------------------------------------------------------------------------------
2095 void SetSupplies(float suppliesCount)
2096 {
2097 SCR_ResourceComponent resourceComponent = GetResourceComponent();
2099 if (!resourceComponent)
2100 return;
2101
2102 SCR_ResourceConsumer resourceConsumer = resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
2103
2104 if (!resourceConsumer)
2105 return;
2107 if (!IsProxy())
2108 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
2109
2110 AddSupplies(suppliesCount - resourceConsumer.GetAggregatedResourceValue());
2111 }
2112
2113 //------------------------------------------------------------------------------------------------
2114
2115 void SetInitialSupplies(float suppliesCount)
2117 SCR_ResourceComponent resourceComponent = GetResourceComponent();
2118
2119 if (!resourceComponent)
2120 return;
2121
2122 SCR_ResourceConsumer resourceConsumer = resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
2123
2124 if (!resourceConsumer)
2125 return;
2126
2127 if (!IsProxy())
2128 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
2129
2130 // Set starting supplies only if no bigger supply caches are already in the vicinity
2131 if (suppliesCount > resourceConsumer.GetAggregatedResourceValue())
2132 SetSupplies(suppliesCount);
2133 }
2134
2135 //------------------------------------------------------------------------------------------------
2137 void SetStartingSupplies(float suppliesCount)
2138 {
2139 m_fStartingSupplies = suppliesCount;
2140 }
2141
2142 //------------------------------------------------------------------------------------------------
2144 //! \param time (in seconds) This number is added to the timer
2145 void AlterSupplyIncomeTimer(float time)
2146 {
2147 if (time == 0)
2148 return;
2149
2150 m_fSuppliesArrivalTime.PlusSeconds(time);
2151 Replication.BumpMe();
2152 }
2153
2154 //------------------------------------------------------------------------------------------------
2156 {
2157 if (timestamp.Equals(m_fSuppliesArrivalTime))
2158 return;
2159
2160 m_fSuppliesArrivalTime = timestamp;
2161 Replication.BumpMe();
2162 }
2163
2164 //------------------------------------------------------------------------------------------------
2165 //! \param[in] faction
2167 {
2168 if (IsProxy())
2169 return;
2170
2171 if (!m_FactionComponent)
2172 return;
2173
2174 if(m_FactionComponent.GetAffiliatedFaction() == faction)
2175 return;
2176
2177 if(!faction || m_FactionComponent.GetAffiliatedFactionKey() != faction.GetFactionKey())
2178 m_FactionComponent.SetAffiliatedFaction(faction);
2179 }
2180
2181 //------------------------------------------------------------------------------------------------
2185 return SCR_CampaignFaction.Cast(GetFaction());
2186 }
2187
2188 //------------------------------------------------------------------------------------------------
2191 {
2192 return m_eType;
2193 }
2194
2195 //------------------------------------------------------------------------------------------------
2198 {
2199 return m_sBaseName;
2200 }
2201
2202 //------------------------------------------------------------------------------------------------
2205 {
2206 return m_sBaseNameUpper;
2207 }
2208
2209 //------------------------------------------------------------------------------------------------
2212 {
2213 // The capturing faction exists, return true
2215 return true;
2216
2217 // No faction is capturing this base, return false
2218 return false;
2219 }
2220
2221 //------------------------------------------------------------------------------------------------
2223 void SetAttackingFaction(int enemyFaction)
2224 {
2225 m_iAttackingFaction = enemyFaction;
2226
2227 if (m_iAttackingFaction < 0)
2228 return;
2230 Replication.BumpMe();
2232 }
2233
2234 //------------------------------------------------------------------------------------------------
2237 {
2238 Faction enemyFaction = GetGame().GetFactionManager().GetFactionByIndex(m_iAttackingFaction);
2239 Faction playerFaction = SCR_FactionManager.SGetLocalPlayerFaction();
2240
2241 if (!IsProxy())
2242 GetGame().GetCallqueue().CallLater(SetAttackingFaction, 1000, false, -1);
2243 else
2245
2246 if (RplSession.Mode() != RplMode.Dedicated && enemyFaction != playerFaction && GetFaction() == playerFaction)
2247 FlashBaseIcon(SCR_CampaignFeedbackComponent.ICON_FLASH_DURATION, enemyFaction);
2248 }
2249
2250 //------------------------------------------------------------------------------------------------
2253 {
2254 ChimeraWorld world = GetOwner().GetWorld();
2255 WorldTimestamp curTime = world.GetServerTimestamp();
2256
2257 // Make sure the spawnpoint becomes available after timer runs out
2258 if (!IsProxy())
2259 GetGame().GetCallqueue().CallLater(HandleSpawnPointFaction, m_fRespawnAvailableSince.DiffMilliseconds(curTime) + SCR_GameModeCampaign.MEDIUM_DELAY);
2260
2261 // Handle respawn cooldown UI
2262 if (RplSession.Mode() != RplMode.Dedicated)
2264 }
2265
2266 //------------------------------------------------------------------------------------------------
2269 {
2270 ChimeraWorld world = GetOwner().GetWorld();
2271 WorldTimestamp curTime = world.GetServerTimestamp();
2272
2273 if (m_UIElement && SCR_FactionManager.SGetLocalPlayerFaction() == GetFaction())
2274 m_UIElement.SetIconInfoText();
2275
2276 GetGame().GetCallqueue().Remove(UpdateRespawnCooldown);
2277
2278 if (curTime.Less(m_fRespawnAvailableSince))
2279 GetGame().GetCallqueue().CallLater(UpdateRespawnCooldown, SCR_GameModeCampaign.UI_UPDATE_DELAY);
2280 }
2281
2282 //------------------------------------------------------------------------------------------------
2284 {
2285 if (IsProxy())
2286 {
2287 // Delayed call so all radios are powered on for clients
2288 GetGame().GetCallqueue().CallLater(SCR_RadioCoverageSystem.UpdateAll, SCR_GameModeCampaign.DEFAULT_DELAY, false, false);
2289 return;
2290 }
2291
2292 // Spawn building only if not already set (from e.g. savegame)
2294 return;
2295
2296 ResourceName buildingPrefab;
2298
2299 switch (GetType())
2300 {
2301 case SCR_ECampaignBaseType.BASE:
2302 label = EEditableEntityLabel.SERVICE_HQ;
2303 break;
2304 case SCR_ECampaignBaseType.SOURCE_BASE:
2305 label = EEditableEntityLabel.SERVICE_SOURCE_BASE;
2306 break;
2307 default:
2308 return;
2309 }
2310
2311 buildingPrefab = GetCampaignFaction().GetBuildingPrefab(label);
2312 if (!buildingPrefab)
2313 {
2314 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2315
2316 if (Math.RandomFloat01() >= 0.5)
2317 buildingPrefab = campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR).GetBuildingPrefab(label);
2318 else
2319 buildingPrefab = campaign.GetFactionByEnum(SCR_ECampaignFaction.OPFOR).GetBuildingPrefab(label);
2320 }
2321
2322 if (buildingPrefab)
2323 {
2324 // Delay so we don't spawn stuff during init
2325 GetGame().GetCallqueue().CallLater( SpawnBuilding, 1000, false, buildingPrefab, GetOwner().GetOrigin(), GetOwner().GetYawPitchRoll(), true);
2326 }
2327 }
2328
2329 //------------------------------------------------------------------------------------------------
2332 {
2333 float range = m_fRadioRangeDefault;
2334 float thisRange;
2335 array<SCR_ServicePointComponent> antennas = {};
2336 GetServicesByType(antennas, SCR_EServicePointType.RADIO_ANTENNA);
2337 BaseRadioComponent radio;
2338
2339 // Find antenna services, read max radio range from the radio component on their owners
2340 foreach (SCR_ServicePointComponent service : antennas)
2341 {
2342 SCR_AntennaServicePointComponent antenna = SCR_AntennaServicePointComponent.Cast(service);
2343 radio = BaseRadioComponent.Cast(antenna.GetOwner().FindComponent(BaseRadioComponent));
2344
2345 if (!radio)
2346 continue;
2347
2348 // Turn off the radio so we don't hit performance too much with every antenna built
2349 if (radio.IsPowered())
2350 radio.SetPower(false);
2351
2352 thisRange = GetRelayRadioRange(radio);
2353
2354 if (thisRange > range)
2355 range = thisRange;
2356 }
2357
2358 if (m_fRadioRange == range)
2359 return;
2360
2361 // Instead of relying on antenna radio which has been turned off, apply the antenna's signal range to the radio component on the base itself
2362 if (m_RadioComponent)
2363 {
2364 RelayTransceiver transceiver;
2365
2366 for (int i = 0, count = m_RadioComponent.TransceiversCount(); i < count; i++)
2367 {
2368 transceiver = RelayTransceiver.Cast(m_RadioComponent.GetTransceiver(i));
2369
2370 if (!transceiver)
2371 continue;
2372
2373 transceiver.SetRange(range);
2374 }
2375 }
2376
2377 m_fRadioRange = range;
2378 Replication.BumpMe();
2380 }
2382 //------------------------------------------------------------------------------------------------
2385 {
2386 // Delayed call so transceiver ranges on radios are properly updated for clients as well
2387 GetGame().GetCallqueue().CallLater(SCR_RadioCoverageSystem.UpdateAll, SCR_GameModeCampaign.DEFAULT_DELAY, false, false);
2389 if (IsProxy())
2390 return;
2391
2392 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2393
2394 if (!campaign)
2395 return;
2396
2397 SCR_CampaignMilitaryBaseManager bManager = campaign.GetBaseManager();
2398
2399 if (!bManager)
2400 return;
2401
2402 if (GetGame().GetWorld().GetWorldTime() > campaign.BACKEND_DELAY)
2403 {
2404 // Process recalculation immediately unless we're still within save loading period
2405 const SCR_CampaignFaction faction = GetCampaignFaction();
2406 if (faction)
2407 bManager.RecalculateRadioCoverage(faction);
2408 }
2409 else
2410 {
2411 // Otherwise process for both factions only once so we're not doing it for each antenna loaded
2412 GetGame().GetCallqueue().Remove(bManager.RecalculateRadioCoverage);
2413 GetGame().GetCallqueue().CallLater(bManager.RecalculateRadioCoverage, campaign.DEFAULT_DELAY, false, campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR));
2414 GetGame().GetCallqueue().CallLater(bManager.RecalculateRadioCoverage, campaign.DEFAULT_DELAY, false, campaign.GetFactionByEnum(SCR_ECampaignFaction.OPFOR));
2415 }
2416 }
2417
2418 //------------------------------------------------------------------------------------------------
2424
2425 //------------------------------------------------------------------------------------------------
2428 {
2429 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2430 if (!campaign)
2431 return;
2432
2434 if (!newOwner)
2435 return;
2436
2437 int newOwnerPoints = newOwner.GetControlPointsHeld();
2438
2439 if (newOwnerPoints == campaign.GetControlPointTreshold() && IsControlPoint())
2441 newOwner.SendHQMessage(SCR_ERadioMsg.WINNING);
2442
2443 SCR_CampaignFaction losingFaction;
2444 FactionManager factionManager = GetGame().GetFactionManager();
2445 if (!factionManager)
2446 return;
2447
2448 if (newOwner.GetFactionKey() == campaign.GetFactionKeyByEnum(SCR_ECampaignFaction.BLUFOR))
2449 losingFaction = SCR_CampaignFaction.Cast(factionManager.GetFactionByKey(campaign.GetFactionKeyByEnum(SCR_ECampaignFaction.OPFOR)));
2450 else
2451 losingFaction = SCR_CampaignFaction.Cast(factionManager.GetFactionByKey(campaign.GetFactionKeyByEnum(SCR_ECampaignFaction.BLUFOR)));
2452
2453 if (losingFaction)
2454 losingFaction.SendHQMessage(SCR_ERadioMsg.LOSING);
2455 }
2456 else
2457 {
2458 if (m_iCallsign == INVALID_BASE_CALLSIGN)
2459 return;
2460
2461 if (IsHQ())
2462 newOwner.SendHQMessage(SCR_ERadioMsg.SEIZED_MAIN, m_iCallsign);
2463 else if (IsControlPoint())
2464 newOwner.SendHQMessage(SCR_ERadioMsg.SEIZED_MAJOR, m_iCallsign);
2465 else if (GetType() == SCR_ECampaignBaseType.BASE)
2466 newOwner.SendHQMessage(SCR_ERadioMsg.SEIZED_SMALL, m_iCallsign);
2467
2469 {
2470 if (GetType() == SCR_ECampaignBaseType.RELAY)
2471 m_OwningFactionPrevious.SendHQMessage(SCR_ERadioMsg.RELAY_LOST, m_iCallsign);
2472 else
2473 m_OwningFactionPrevious.SendHQMessage(SCR_ERadioMsg.BASE_LOST, m_iCallsign);
2474 }
2475 }
2476 }
2477
2478 //------------------------------------------------------------------------------------------------
2479 protected void SpawnStartingVehicles()
2480 {
2481 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2482
2483 if (!campaign)
2484 return;
2485
2486 if (campaign.IsTutorial())
2487 return;
2488
2490 params.TransformMode = ETransformMode.WORLD;
2491 vector pos, oldPos;
2492 IEntity vehicleEntity;
2493 Physics physicsComponent;
2494
2495 array<ResourceName> prefabNames = {};
2497
2498 foreach (ResourceName prefabName : prefabNames)
2499 {
2500 oldPos = pos;
2501 SCR_WorldTools.FindEmptyTerrainPosition(pos, GetOwner().GetOrigin(), HQ_VEHICLE_SPAWN_RADIUS, HQ_VEHICLE_QUERY_SPACE);
2502
2503 //Should found empty terrain position be too close to last one, do another search with previous position as areaCenter.
2504 if (vector.DistanceSqXZ(pos, oldPos) < 1)
2505 SCR_WorldTools.FindEmptyTerrainPosition(pos, oldPos, HQ_VEHICLE_SPAWN_RADIUS, HQ_VEHICLE_QUERY_SPACE);
2506
2507 params.Transform[3] = pos;
2508
2509 vehicleEntity = GetGame().SpawnEntityPrefabEx(prefabName, false, params: params);
2510 if (vehicleEntity)
2511 {
2512 physicsComponent = vehicleEntity.GetPhysics();
2513 if (physicsComponent)
2514 physicsComponent.SetVelocity("0 -0.1 0"); // Make vehicle copy the terrain properly
2515
2516 m_aStartingVehicles.Insert(vehicleEntity);
2517 }
2518 }
2519 }
2520
2521 //------------------------------------------------------------------------------------------------
2522 protected void DeleteStartingVehicles()
2523 {
2524 foreach (IEntity veh : m_aStartingVehicles)
2525 {
2526 if (veh)
2527 RplComponent.DeleteRplEntity(veh, false);
2528 }
2529 }
2530
2531 //------------------------------------------------------------------------------------------------
2532 protected void RemoveFortifications()
2533 {
2534 IEntity child = GetOwner().GetChildren();
2535 IEntity prevChild;
2536
2537 while (child)
2538 {
2539 if (child.FindComponent(SCR_CampaignBuildingCompositionComponent))
2540 prevChild = child;
2541
2542 child = child.GetSibling();
2543
2544 if (prevChild)
2545 SCR_EntityHelper.DeleteEntityAndChildren(prevChild);
2546 }
2547 }
2548
2549 //------------------------------------------------------------------------------------------------
2555 void SpawnBuilding(ResourceName prefab, vector position, vector rotation, bool isMainTent = false)
2556 {
2557 if (prefab.IsEmpty())
2558 return;
2559
2560 if (position == vector.Zero)
2561 return;
2562
2564 GetOwner().GetWorldTransform(params.Transform);
2565 params.TransformMode = ETransformMode.WORLD;
2566 Math3D.AnglesToMatrix(rotation, params.Transform);
2567 params.Transform[3] = position;
2568
2569 IEntity composition = GetGame().SpawnEntityPrefab(Resource.Load(prefab), null, params);
2570 if (!composition)
2571 return;
2572
2573 m_BaseBuildingComposition = composition;
2574
2575 if (isMainTent)
2576 {
2577 // Delayed call so the supplies system has time to process all the containers first
2578 if (m_fStartingSupplies >= 0)
2579 GetGame().GetCallqueue().CallLater(SetInitialSupplies, SCR_GameModeCampaign.MEDIUM_DELAY, false, m_fStartingSupplies);
2580 }
2581
2582 SCR_AIWorld aiWorld = SCR_AIWorld.Cast(GetGame().GetAIWorld());
2583
2584 if (aiWorld)
2585 aiWorld.RequestNavmeshRebuildEntity(composition);
2586
2587 SCR_EditableEntityComponent editableEntity = SCR_EditableEntityComponent.Cast(composition.FindComponent(SCR_EditableEntityComponent));
2588 vector transform[4];
2589
2590 if (!editableEntity)
2591 {
2592 GetOwner().GetTransform(transform);
2593 SCR_TerrainHelper.SnapToTerrain(transform, composition.GetWorld());
2594 composition.SetTransform(transform);
2595 return;
2596 }
2597
2598 editableEntity.GetTransform(transform);
2599
2600 if (!SCR_TerrainHelper.SnapToTerrain(transform, composition.GetWorld()))
2601 return;
2602
2603 editableEntity.SetTransformWithChildren(transform);
2604 }
2605
2606 //------------------------------------------------------------------------------------------------
2609 {
2611
2612 if (!baseFaction.IsPlayable())
2613 return;
2614
2615 SCR_CampaignFactionManager factionManager = SCR_CampaignFactionManager.Cast(GetGame().GetFactionManager());
2616
2617 if (!factionManager)
2618 return;
2619
2620 if (GetHQRadioCoverage(factionManager.GetEnemyFaction(baseFaction)) == SCR_ERadioCoverageStatus.NONE)
2621 return;
2622
2623 PlayerManager playerManager = GetGame().GetPlayerManager();
2624 array<int> playerIds = {};
2625 array<int> playerIdsPresent = {};
2626 playerManager.GetPlayers(playerIds);
2627 int radiusSq;
2628 vector basePos = GetOwner().GetOrigin();
2629 SCR_XPHandlerComponent compXP = SCR_XPHandlerComponent.Cast(GetGame().GetGameMode().FindComponent(SCR_XPHandlerComponent));
2630 bool enemiesPresent;
2631
2632 if (m_eType == SCR_ECampaignBaseType.BASE)
2633 radiusSq = m_iRadius * m_iRadius;
2634 else
2636
2637 foreach (int playerId : playerIds)
2638 {
2639 SCR_ChimeraCharacter player = SCR_ChimeraCharacter.Cast(playerManager.GetPlayerControlledEntity(playerId));
2640
2641 if (!player)
2642 continue;
2643
2644 CharacterControllerComponent charController = player.GetCharacterController();
2645
2646 if (charController.IsDead())
2647 continue;
2648
2649 if (vector.DistanceSqXZ(player.GetOrigin(), basePos) > radiusSq)
2650 continue;
2651
2652 if (player.GetFaction() == baseFaction)
2653 playerIdsPresent.Insert(playerId);
2654 else
2655 enemiesPresent = true;
2656 }
2657
2658 ChimeraWorld world = GetOwner().GetWorld();
2659 WorldTimestamp curTime = world.GetServerTimestamp();
2660 foreach (int playerId : playerIdsPresent)
2661 {
2662 WorldTimestamp startedDefendingAt = m_mDefendersData.Get(playerId);
2663 if (startedDefendingAt == 0)
2664 {
2665 m_mDefendersData.Set(playerId, curTime)
2666 }
2667 else if (curTime.DiffMilliseconds(startedDefendingAt) >= DEFENDERS_REWARD_PERIOD)
2668 {
2669 m_mDefendersData.Set(playerId, curTime);
2670
2671 if (enemiesPresent)
2672 compXP.AwardXP(playerManager.GetPlayerController(playerId), SCR_EXPRewards.BASE_DEFENDED, DEFENDERS_REWARD_MULTIPLIER);
2673 else
2674 compXP.AwardXP(playerManager.GetPlayerController(playerId), SCR_EXPRewards.BASE_DEFENDED);
2675 }
2676 }
2677
2678 // Clean up non-present players from the list
2679 for (int i = m_mDefendersData.Count() - 1; i >= 0; i--)
2680 {
2681 int playerId = m_mDefendersData.GetKey(i);
2682
2683 if (playerIdsPresent.Contains(playerId))
2684 continue;
2685
2686 m_mDefendersData.Remove(playerId);
2687 }
2688 }
2689
2690 //------------------------------------------------------------------------------------------------
2691 protected void EvaluateEnemyPresence()
2692 {
2693 if (m_eType == SCR_ECampaignBaseType.RELAY || m_eType == SCR_ECampaignBaseType.SOURCE_BASE)
2694 return;
2695
2697 if (!baseFaction || !baseFaction.IsPlayable())
2698 return;
2699
2700 vector basePos = GetOwner().GetOrigin();
2701 bool enemiesPresent = !GetOwner().GetWorld().QueryEntitiesBySphere(basePos, m_iRadius, EvaluateEnemyCharacterPresence, null, EQueryEntitiesFlags.DYNAMIC);
2702
2703 if (m_bEnemiesPresent == enemiesPresent)
2704 return;
2705
2706 m_bEnemiesPresent = enemiesPresent;
2707 Replication.BumpMe();
2708 }
2709
2710 //------------------------------------------------------------------------------------------------
2711 protected bool EvaluateEnemyCharacterPresence(notnull IEntity entity)
2712 {
2713 SCR_ChimeraCharacter character = SCR_ChimeraCharacter.Cast(entity);
2714 if (!character)
2715 return true;
2716
2718 if (!characterDamageManager || characterDamageManager.GetState() == EDamageState.DESTROYED)
2719 return true;
2721 if (!GetFaction().IsFactionEnemy(character.GetFaction()))
2722 return true;
2723
2724 CharacterControllerComponent charController = character.GetCharacterController();
2725 if (!charController)
2726 return true;
2727
2728 int playerId = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(entity);
2729 if (playerId != 0)
2730 return false;
2731
2732 AIControlComponent aiControlComponent = charController.GetAIControlComponent();
2733 if (!aiControlComponent)
2734 return true;
2735
2736 if (aiControlComponent.IsAIActivated())
2737 return false;
2738
2739 return true;
2740 }
2741
2742 //------------------------------------------------------------------------------------------------
2748
2750 {
2751 World world = GetOwner().GetWorld();
2752 CampaignBasesSystem updateSystem = CampaignBasesSystem.Cast(world.FindSystem(CampaignBasesSystem));
2753 if (!updateSystem)
2754 return;
2755
2756 updateSystem.Register(this);
2757 }
2758
2760 {
2761 World world = GetOwner().GetWorld();
2762 CampaignBasesSystem updateSystem = CampaignBasesSystem.Cast(world.FindSystem(CampaignBasesSystem));
2763 if (!updateSystem)
2764 return;
2765
2766 updateSystem.Unregister(this);
2767 }
2768
2769 //------------------------------------------------------------------------------------------------
2772 void Update(float timeSlice)
2773 {
2774 m_fTimer += timeSlice;
2775
2776 // Periodic calls, add random delay to avoid spikes
2778 return;
2779
2780 m_fTimer = 0;
2781 m_fNextFrameCheck = TICK_TIME + (Math.RandomFloat01() * TICK_TIME * 0.5);
2782 bool playerPresentPreviously = m_bLocalPlayerPresent;
2784
2785 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2786
2787 if (campaign && m_bLocalPlayerPresent != playerPresentPreviously)
2788 campaign.GetBaseManager().OnLocalPlayerPresenceChanged(this, m_bLocalPlayerPresent);
2789 }
2790
2791 //------------------------------------------------------------------------------------------------
2792 override void EOnInit(IEntity owner)
2793 {
2794 super.EOnInit(owner);
2795
2796 if (!IsProxy())
2797 {
2798 SCR_ResourceComponent resourceComponent = GetResourceComponent();
2799
2800 if (resourceComponent)
2801 {
2802 SCR_ResourceConsumer consumerComponent = resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
2803
2804 if (consumerComponent)
2805 consumerComponent.GetOnResourcesChanged().Insert(HandleSpawnPointFaction);
2806 }
2807 }
2809 if (m_RadioComponent)
2810 m_RadioComponent.GetOnCoverageChanged().Insert(OnHasSignalChanged);
2811
2812 if (GetGame().GetWorld().GetWorldTime() >= SCR_GameModeCampaign.BACKEND_DELAY)
2813 {
2814 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2815 SCR_CampaignMilitaryBaseManager manager = campaign.GetBaseManager();
2816
2817 if (manager)
2818 GetGame().GetCallqueue().CallLater(manager.OnBaseInitialized, 0, false, this);
2819 }
2820
2821 if (RplSession.Mode() == RplMode.Dedicated)
2822 return;
2823
2824 m_MapDescriptor = SCR_CampaignMilitaryBaseMapDescriptorComponent.Cast(GetOwner().FindComponent(SCR_CampaignMilitaryBaseMapDescriptorComponent));
2825 if (!m_MapDescriptor)
2826 return;
2827
2828 m_MapDescriptor.SetParentBase(this);
2829 m_MapDescriptor.Item().SetVisible(true);
2830 }
2831
2832 //------------------------------------------------------------------------------------------------
2833 override void OnPostInit(IEntity owner)
2834 {
2835 super.OnPostInit(owner);
2836
2837 m_RadioComponent = SCR_CoverageRadioComponent.Cast(GetOwner().FindComponent(SCR_CoverageRadioComponent));
2838
2839 if (m_fRadioRange == 0 && m_RadioComponent)
2840 {
2843 }
2844 }
2845
2846 //------------------------------------------------------------------------------------------------
2847 override void OnDelete(IEntity owner)
2850
2852 if (seizingComponent)
2853 {
2854 seizingComponent.GetOnCaptureStart().Remove(OnCaptureStart);
2855 seizingComponent.GetOnCaptureInterrupt().Remove(EndCapture);
2856 seizingComponent.GetOnCaptureStateChanged().Remove(CaptureStateChanged);
2857 }
2858
2859 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2860 if (campaign)
2861 {
2862 campaign.GetOnFactionAssignedLocalPlayer().Remove(OnLocalPlayerFactionAssigned);
2863 campaign.GetBaseManager().GetOnAllBasesInitialized().Remove(OnAllBasesInitialized);
2864 campaign.GetOnCallsignOffsetChanged().Remove(OnCallsignAssigned);
2865
2866 SCR_CampaignMilitaryBaseManager manager = campaign.GetBaseManager();
2867 if (manager)
2868 GetGame().GetCallqueue().CallLater(manager.UpdateBases, 0, false, false);
2869 }
2870
2871 SCR_ResourceComponent resourceComponent = GetResourceComponent();
2872 if (resourceComponent)
2873 {
2874 SCR_ResourceConsumer consumerComponent = resourceComponent.GetConsumer(EResourceGeneratorID.DEFAULT, EResourceType.SUPPLIES);
2875 if (consumerComponent)
2876 {
2877 consumerComponent.GetOnResourcesChanged().Remove(HandleSpawnPointFaction);
2878 }
2879 }
2880
2881 super.OnDelete(owner);
2882 }
2883
2884 //------------------------------------------------------------------------------------------------
2888 {
2889 if (IsProxy())
2890 return false;
2891
2892 if (m_iCallsign == INVALID_BASE_CALLSIGN)
2893 return false;
2894
2895 if (!m_bInitialized)
2896 return false;
2897
2899 return false;
2900
2901 SCR_GameModeCampaign campaign = SCR_GameModeCampaign.GetInstance();
2902
2903 if (!campaign || campaign.GetCallsignOffset() == SCR_MilitaryBaseComponent.INVALID_BASE_CALLSIGN)
2904 return false;
2905
2906 return true;
2907 }
2908}
2909
2911class SCR_CampaignCustomBase
2912{
2913 [Attribute("", UIWidgets.EditBox, "Base entity name as set up in World Editor.")]
2914 protected string m_sBaseName;
2915
2916 [Attribute(defvalue: "0", uiwidget: UIWidgets.CheckBox)]
2917 protected bool m_bIsControlPoint;
2918
2919 [Attribute(defvalue: "0", uiwidget: UIWidgets.CheckBox)]
2920 protected bool m_bCanBeHQ;
2921
2922 [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox)]
2923 protected bool m_bDisableWhenUnusedAsHQ;
2924
2925 [Attribute("-1", desc: "Use -1 for default base setting.")]
2926 protected float m_fRadioRange;
2927
2928 //------------------------------------------------------------------------------------------------
2930 string GetBaseName()
2931 {
2932 return m_sBaseName;
2933 }
2934
2935 //------------------------------------------------------------------------------------------------
2938 bool IsControlPoint()
2939 {
2940 return m_bIsControlPoint;
2941 }
2942
2943 //------------------------------------------------------------------------------------------------
2945 bool GetCanBeHQ()
2946 {
2947 return m_bCanBeHQ;
2948 }
2949
2950 //------------------------------------------------------------------------------------------------
2953 {
2955 }
2956
2957 //------------------------------------------------------------------------------------------------
2959 float GetRadioRange()
2960 {
2961 return m_fRadioRange;
2962 }
2963}
2964
2971
2972enum EFactionMapID
2973{
2975 EAST = 1,
2976 WEST = 2,
2977 FIA = 3
2978}
EEditableEntityLabel
string FactionKey
Faction unique identifier type.
Definition FactionKey.c:2
ArmaReforgerScripted GetGame()
Definition game.c:1398
PrefabImporterRequest status
RplMode
Mode of replication.
Definition RplMode.c:9
vector GetOrigin()
FactionAffiliationComponent m_FactionComponent
SCR_BaseGameMode GetGameMode()
SCR_CacheNoteComponentClass ScriptComponentClass RplProp()] protected ref array< string > m_aLines
RplComponent m_RplComponent
SCR_ECampaignPopupPriority
Popup message priorities sorted from lowest to highest.
void OnSupplyLimitChanged(SCR_CampaignMilitaryBaseComponent campaignBase, float supplyLimit)
SCR_CampaignMilitaryBaseComponent SCR_MilitaryBaseComponent BaseContainerProps()
WorldTimestamp m_fSuppliesArrivalTime
ref array< SCR_AIGroup > m_aDefendersGroups
ref array< IEntity > m_aStartingVehicles
bool IsHQRadioTrafficPossible(notnull SCR_CampaignFaction faction, SCR_ERadioCoverageStatus direction=SCR_ERadioCoverageStatus.RECEIVE)
ScriptInvokerBase< OnBaseStateChangedDelegate > OnBaseStateChangedInvoker
string GetBaseNameUpperCase()
Returns the upper-case name of this base.
SCR_CampaignFaction GetCampaignFaction()
Returns the owning faction.
void SendHighestPriorityMessage(notnull SCR_CampaignFaction faction)
ScriptInvokerBase< OnBaseAttackEndDelegate > OnBaseAttackEndInvoker
void CaptureStateChanged(SCR_EBaseCaptureState state)
SCR_CampaignMilitaryBaseComponent SCR_MilitaryBaseComponent SCR_BaseContainerCustomTitleResourceName("m_sBaseName", true)
enum SCR_ECampaignBaseType WEST
func OnSupplyLimitChangedDelegate
func OnSpawnPointAssignedDelegate
ScriptInvokerBase< OnBaseCreatedAsFOBDelegate > OnBaseCreatedAsFOBInvoker
ResourceName m_sBuildingIconImageset
ResourceName GetBuildingIconImageset()
SCR_CampaignFaction m_CapturingFaction
ScriptInvokerBase< OnSpawnPointAssignedDelegate > OnSpawnPointAssignedInvoker
ScriptInvokerBase< OnSupplyLimitChangedDelegate > OnSupplyLimitChangedInvoker
enum SCR_ECampaignBaseType EAST
ref ScriptInvokerFloat m_OnReservedSupplyAmountChanged
ref OnSupplyLimitChangedInvoker m_OnSupplyLimitChanged
SCR_CampaignMilitaryBaseMapDescriptorComponent m_MapDescriptor
void HandleSpawnPointFaction()
Changes the faction which can spawn on spawn point groups owned by this base.
FactionKey m_sBuiltFaction
void OnLocalPlayerFactionAssigned(Faction assignedFaction)
WorldTimestamp m_fLastEnemyContactTimestamp
SCR_CampaignMapUIBase m_UIElement
void SetInitialSupplies(float suppliesCount)
string GetBaseName()
Returns the name of this base.
SCR_CoverageRadioComponent m_RadioComponent
If value default Gamemode value will be category
void OnCaptureStart(SCR_Faction faction)
IEntity m_BaseBuildingComposition
void FlashBaseIcon(float remainingTime=0, Faction faction=null, bool changeToDefault=false, bool infiniteTimer=false)
void EndCapture()
Capturing has been terminated.
SCR_SpawnPoint m_SpawnPoint
SCR_CampaignFaction GetFaction()
SCR_CharacterSoundComponentClass GetComponentData()
vector direction
vector position
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
void SCR_FactionManager(IEntitySource src, IEntity parent)
int GetRegularSuppliesIncomeExtra()
void SCR_GameModeCampaign(IEntitySource src, IEntity parent)
Faction GetCapturingFaction()
void OnCallsignAssigned()
int GetServices(out array< SCR_ServicePointComponent > services=null)
int GetCallsign()
int GetBuildingProviders(out array< SCR_CampaignBuildingProviderComponent > providers)
Get all registered systems inherited from SCR_CampaignBuildingProviderComponent.
int GetServicesByType(out array< SCR_ServicePointComponent > services, SCR_EServicePointType type)
void UpdateFlags()
SCR_ServicePointDelegateComponent GetServiceDelegateByType(SCR_EServicePointType type)
LocalizedString GetCallsignDisplayNameOnlyUC()
FactionKey m_sCapturingFaction
bool GetIsLocalPlayerPresent()
EResourceGeneratorID
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
void SCR_RespawnComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
ScriptInvokerBase< ScriptInvokerFloatMethod > ScriptInvokerFloat
ScriptInvokerBase< ScriptInvokerVoidMethod > ScriptInvokerVoid
ScriptInvokerBase< ScriptInvokerBoolMethod > ScriptInvokerBool
ScriptInvokerBase< ScriptInvokerIntMethod > ScriptInvokerInt
class SCR_SeizeProgressionXpRewardInfo SOURCE_BASE
void Unregister(SCR_CampaignMilitaryBaseComponent component)
void Register(SCR_CampaignMilitaryBaseComponent component)
proto external Managed FindComponent(typename typeName)
proto external vector GetOrigin()
proto external Physics GetPhysics()
proto external IEntity GetChildren()
proto external void GetWorldTransform(out vector mat[])
See IEntity::GetTransform.
proto external BaseWorld GetWorld()
proto external bool SetTransform(vector mat[4])
proto external void GetTransform(out vector mat[])
proto external IEntity GetSibling()
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
ScriptInvoker_AIGroupOnEmpty GetOnEmpty()
void RequestNavmeshRebuildEntity(IEntity entity)
void GetStartingVehiclePrefabs(out notnull array< ResourceName > prefabs)
ResourceName GetBuildingPrefab(EEditableEntityLabel type)
void SendHQMessage(SCR_ERadioMsg msgType, int baseCallsign=SCR_MilitaryBaseComponent.INVALID_BASE_CALLSIGN, int calledID=SCR_CampaignMilitaryBaseComponent.INVALID_PLAYER_INDEX, bool public=true, int param=SCR_CampaignRadioMsg.INVALID_RADIO_MSG_PARAM)
void SetMainBase(SCR_CampaignMilitaryBaseComponent mainBase)
SCR_CampaignMilitaryBaseComponent GetMainBase()
void RegisterRemnants(notnull SCR_AmbientPatrolSpawnPointComponent remnants)
static ref OnBaseAttackEndInvoker m_OnBaseAttackEnd
ref OnSupplyLimitChangedInvoker m_OnSupplyLimitChanged
void OnLocalPlayerFactionAssigned(Faction assignedFaction)
static OnBaseStateChangedInvoker GetOnFactionChangedExtended()
void HandleSpawnPointFaction()
Changes the faction which can spawn on spawn point groups owned by this base.
float GetRelayRadioRange(notnull BaseRadioComponent radio)
SCR_ECampaignBaseType GetType()
Returns type of this base.
void EvaluateDefenders()
Periodically add XP to players defending their base.
void SetBaseUI(SCR_CampaignMapUIBase base)
Called from SCR_MapCampaignUI when base UI elements are initialized.
void FlashBaseIcon(float remainingTime=0, Faction faction=null, bool changeToDefault=false, bool infiniteTimer=false)
void CalculateSupplyRegenerationAmount(float currentSupplies, float maxSupplies, notnull SCR_CampaignFaction faction)
bool IsHQRadioTrafficPossible(notnull SCR_CampaignFaction faction, SCR_ERadioCoverageStatus direction=SCR_ERadioCoverageStatus.RECEIVE)
void CaptureStateChanged(SCR_EBaseCaptureState state)
If value default Gamemode value will be category
SCR_CampaignFaction GetCampaignFaction()
Returns the owning faction.
void SpawnBuilding(ResourceName prefab, vector position, vector rotation, bool isMainTent=false)
static ref OnBaseStateChangedInvoker m_OnBaseUnderAttack
static ref OnBaseCreatedAsFOBInvoker m_OnBaseCreatedasFOB
void OnServiceBuilt_AfterInit(SCR_ServicePointComponent service)
ref OnSpawnPointAssignedInvoker m_OnSpawnPointAssigned
void ApplyHeaderSettings(notnull SCR_CampaignCustomBase settings)
string GetBaseName()
Returns the name of this base.
void SetProviderEntity(notnull SCR_ServicePointComponent service)
void SendHighestPriorityMessage(notnull SCR_CampaignFaction faction)
bool EvaluateEnemyCharacterPresence(notnull IEntity entity)
static OnBaseStateChangedInvoker GetOnBaseUnderAttack()
static ScriptInvokerBase< OnBaseCapturedDelegate > GetOnBaseCaptured()
static ref OnBaseStateChangedInvoker m_OnFactionChangedExtended
void ChangeRadioSettings(notnull SCR_Faction faction)
void OnFactionChanged(FactionAffiliationComponent owner, Faction previousFaction, Faction faction)
Event which is triggered when the owning faction changes.
bool IsBeingCaptured()
Returns whether this base is being captured.
void OnBaseCreatedAsFOB(Faction establishingFaction)
Event which is triggered when creating a FOB.
static OnBaseCreatedAsFOBInvoker GetOnBaseCreatedAsFOB()
void EndCapture()
Capturing has been terminated.
ref array< SCR_AmbientPatrolSpawnPointComponent > m_aRemnants
SCR_ESupplyRequestExecutionPriority m_eSupplyRequestExecutionPriority
void AddRegularSupplyPackage(notnull SCR_CampaignFaction faction)
Reinforcements timer has finished, send in reinforcements.
void UpdateCaptureUI()
If the base is being captured or contested and the map is open, update the UI to show the background ...
void CaptureRelay(notnull SCR_CampaignFaction faction, int playerId)
static ref ScriptInvokerBase< OnBaseCapturedDelegate > s_OnBaseCaptured
override void RegisterLogicComponent(notnull SCR_MilitaryBaseLogicComponent component)
SCR_CampaignMilitaryBaseMapDescriptorComponent GetMapDescriptor()
override void SetCallsign(notnull SCR_Faction faction)
SCR_CampaignMilitaryBaseMapDescriptorComponent m_MapDescriptor
SCR_ERadioCoverageStatus GetHQRadioCoverage(notnull SCR_CampaignFaction faction)
SCR_ESupplyRequestExecutionPriority GetSupplyRequestExecutionPriority()
string GetBaseNameUpperCase()
Returns the upper-case name of this base.
SCR_ResourceComponent GetResourceComponent()
return ResourceComponent of base
void OnServiceRemoved(notnull SCR_MilitaryBaseLogicComponent service)
void NotifyAboutEnemyAttack(notnull Faction attackingFaction)
void OnServiceBuilt(notnull SCR_ServicePointComponent service)
override void OnServiceStateChanged(SCR_EServicePointStatus state, notnull SCR_ServicePointComponent serviceComponent)
void SetSupplyRequestExecutionPriority(SCR_ESupplyRequestExecutionPriority priority)
bool IsValidTarget(notnull SCR_CampaignFaction faction)
bool BeginCapture(SCR_CampaignFaction faction, int playerID=INVALID_PLAYER_INDEX)
Capturing has begun.
void AddSupplies(int suppliesCount, bool replicate=true)
override void OnCapturingFactionChanged()
Event which is triggered when the capturing faction changes.
void RecalculateRadioCoverage(notnull SCR_CampaignFaction faction)
Determine the radio coverage of all bases (no coverage / can be reached / can respond / both ways).
void OnBaseInitialized(notnull SCR_CampaignMilitaryBaseComponent base)
int UpdateBases(bool refreshTargetCount=false)
Update the list of Conflict bases.
void OnServiceBuilt(SCR_EServicePointStatus state, notnull SCR_ServicePointComponent serviceComponent)
Takes care of Campaign-specific server <> client communication and requests.
void SendPlayerMessage(SCR_ERadioMsg msgType, int baseCallsign=SCR_MilitaryBaseComponent.INVALID_BASE_CALLSIGN, int calledID=SCR_CampaignMilitaryBaseComponent.INVALID_PLAYER_INDEX, bool public=true, int param=SCR_CampaignRadioMsg.INVALID_RADIO_MSG_PARAM, bool checkHQReached=false)
OnCaptureStateChangedInvoker GetOnCaptureStateChanged()
bool GetTransform(out vector outTransform[4])
void SetTransformWithChildren(vector transform[4])
static IEntity GetMainParent(IEntity entity, bool self=false)
SCR_MilitaryBaseCallsign GetBaseCallsignByIndex(int index, int offset=0)
static sealed bool IsLoadInProgress(float msSinceLoad=1000.0)
static IEntity GetLocalControlledEntity()
Takes care of dynamic and static onscreen popups.
void PopupMsg(string text, float duration=DEFAULT_DURATION, string text2="", int prio=-1, string param1="", string param2="", string param3="", string param4="", string text2param1="", string text2param2="", string text2param3="", string text2param4="", string sound="", SCR_EPopupMsgFilter category=SCR_EPopupMsgFilter.ALL, WorldTimestamp progressStart=null, WorldTimestamp progressEnd=null)
static SCR_PopUpNotification GetInstance()
static bool UpdateAll(bool forceRecalculation=false)
SCR_ResourceGenerationResponse RequestGeneration(float resourceAmount, SCR_ResourceGenerator generator=null)
Spawn point entity defines positions on which players can possibly spawn.
Definition World.c:16
Definition Types.c:486
void EntitySpawnParams()
Definition gameLib.c:130
IEntity GetOwner()
Owner entity of the fuel tank.
SCR_FieldOfViewSettings Attribute
RespawnSystemComponentClass GameComponentClass vector vector rotation
proto external PlayerController GetPlayerController()
EDamageState
ESaveGameType
RplRole
Role of replicated node (and all items in it) within the replication system.
Definition RplRole.c:14
@ UNKNOWN
Definition EPlatform.c:24
T2 param2
Definition tuple.c:92
Tuple param1
proto native bool IsEmpty()
EQueryEntitiesFlags