3 [
Attribute(
"{F7E8D4834A3AFF2F}UI/Imagesets/Conflict/conflict-icons-bw.imageset", UIWidgets.ResourceNamePicker,
"Imageset with foreground textures",
"imageset",
category:
"Campaign")]
4 ResourceName m_sBuildingIconImageset;
6 [
Attribute(
"{C35F29E48086221A}Configs/Campaign/CampaignGraphLinesConfig.conf", UIWidgets.ResourceNamePicker,
"",
"conf",
category:
"Campaign")]
10 protected float m_fLineWidth;
14 ResourceName GetBuildingIconImageset()
41 protected bool m_bIsControlPoint;
44 protected bool m_bCanBeHQ;
47 protected bool m_bDisableWhenUnusedAsHQ;
49 [
Attribute(
"0",
desc:
"If enabled, this base will be treated as an HQ when handling supply income.",
category:
"Campaign")]
50 protected bool m_bIsSupplyHub;
52 [
Attribute(
"#AR-MapSymbol_Installation",
desc:
"The display name of this base.",
category:
"Campaign")]
53 protected string m_sBaseName;
55 [
Attribute(
"#AR-MapSymbol_Installation",
desc:
"The display name of this base, in upper case.",
category:
"Campaign")]
56 protected string m_sBaseNameUpper;
59 protected string m_sMapLocationName;
64 protected ref map<int, WorldTimestamp> m_mDefendersData =
new map<int, WorldTimestamp>();
66 static const float RADIO_RECONFIGURATION_DURATION = 10.0;
67 static const float BARRACKS_REDUCED_DEPLOY_COST = 0.5;
68 static const int UNDER_ATTACK_WARNING_PERIOD = 60;
69 static const int INVALID_PLAYER_INDEX = -1;
70 static const int INVALID_FACTION_INDEX = -1;
71 static const int RESPAWN_DELAY_AFTER_CAPTURE = 180000;
72 static const int RELAY_BASE_RADIUS = 100;
74 static const int SUPPLY_DEPOT_CAPACITY = 4500;
75 static const int DEFENDERS_CHECK_PERIOD = 30000;
76 static const int DEFENDERS_REWARD_PERIOD = 120000;
77 static const int DEFENDERS_REWARD_MULTIPLIER = 3;
79 protected static const int TICK_TIME = 1;
80 protected static const int CONTESTED_RESPAWN_DELAY = 35;
81 protected static const int BASES_IN_RANGE_RESUPPLY_THRESHOLD = 5;
82 protected static const float HQ_VEHICLE_SPAWN_RADIUS = 40;
83 protected static const float HQ_VEHICLE_QUERY_SPACE = 6;
84 protected static const string RADIO_CHATTER_SIGNAL_NAME =
"RadioChatter";
85 protected static const string ESTABLISH_ACTION_SIGNAL_NAME =
"EstablishAction";
89 protected ref array<SCR_CampaignMilitaryBaseComponent> m_aBasesInRadioRange = {};
90 protected ref array<SCR_AmbientPatrolSpawnPointComponent> m_aRemnants = {};
91 protected ref array<IEntity> m_aStartingVehicles = {};
92 protected ref array<SCR_ERadioMsg> m_aServiceBuiltMsgQueue = {};
94 protected float m_fStartingSupplies;
95 protected float m_fSuppliesArrivalTime =
float.MAX;
96 protected float m_fNextFrameCheck;
97 protected float m_fTimer;
98 protected float m_fRadioRangeDefault;
99 protected WorldTimestamp m_fLastEnemyContactTimestamp;
101 protected bool m_bLocalPlayerPresent;
103 protected SCR_CampaignMilitaryBaseMapDescriptorComponent m_MapDescriptor;
110 protected BaseRadioComponent m_RadioComponent;
112 protected IEntity m_HQRadio;
113 protected IEntity m_HQTent;
119 protected ref array<SCR_AIGroup> m_aDefendersGroups = {};
121 [
RplProp(onRplName:
"OnHQSet")]
122 protected bool m_bIsHQ;
124 [
RplProp(onRplName:
"OnInitialized")]
125 protected bool m_bInitialized;
128 protected int m_iSupplyRegenAmount;
130 [
RplProp(onRplName:
"OnHasSignalChanged")]
131 protected SCR_ECampaignHQRadioComms m_eRadioCoverageBLUFOR = SCR_ECampaignHQRadioComms.NONE;
133 [
RplProp(onRplName:
"OnHasSignalChanged")]
134 protected SCR_ECampaignHQRadioComms m_eRadioCoverageOPFOR = SCR_ECampaignHQRadioComms.NONE;
136 [
RplProp(onRplName:
"OnCapturingFactionChanged")]
137 protected int m_iCapturingFaction = INVALID_FACTION_INDEX;
140 protected int m_iReconfiguredBy = INVALID_PLAYER_INDEX;
142 [
RplProp(onRplName:
"OnRadioRangeChanged")]
143 protected float m_fRadioRange;
145 [
RplProp(onRplName:
"OnRespawnCooldownChanged")]
146 protected WorldTimestamp m_fRespawnAvailableSince;
148 [
RplProp(onRplName:
"OnAttackingFactionChanged")]
149 protected int m_iAttackingFaction = -1;
154 bool IsControlPoint()
170 bool DisableWhenUnusedAsHQ()
177 WorldTimestamp GetRespawnTimestamp()
190 Replication.BumpMe();
201 GetGame().GetCallqueue().Remove(SpawnBuilding);
202 GetGame().GetCallqueue().Remove(SpawnStartingVehicles);
203 GetGame().GetCallqueue().Remove(EvaluateDefenders);
204 GetGame().GetCallqueue().Remove(SupplyIncomeTimer);
205 GetGame().GetCallqueue().Remove(HandleSpawnPointFaction);
207 DeleteStartingVehicles();
212 RplComponent.DeleteRplEntity(
m_HQTent,
false);
215 Replication.BumpMe();
233 IEntity child =
GetOwner().GetChildren();
243 SCR_CampaignBuildingProviderComponent buildingProvider = SCR_CampaignBuildingProviderComponent.Cast(
GetOwner().FindComponent(SCR_CampaignBuildingProviderComponent));
244 if (buildingProvider)
245 m_SpawnPoint.SetSpawnPositionRange(buildingProvider.GetBuildingRadius());
255 child = child.GetSibling();
259 array<SCR_ServicePointComponent> services = {};
262 foreach (SCR_ServicePointComponent service : services)
264 OnServiceBuilt(service);
267 if (RplSession.Mode() != RplMode.Dedicated)
269 ConnectToCampaignBasesSystem();
274 playerFaction = campaign.GetBaseManager().GetLocalPlayerFaction();
277 OnLocalPlayerFactionAssigned(playerFaction);
279 campaign.GetOnFactionAssignedLocalPlayer().Insert(OnLocalPlayerFactionAssigned);
282 campaign.GetBaseManager().GetOnAllBasesInitialized().Insert(OnAllBasesInitialized);
286 campaign.GetBaseManager().AddActiveBase();
292 GetGame().GetCallqueue().CallLater(EvaluateDefenders, DEFENDERS_CHECK_PERIOD + Math.RandomIntInclusive(0, DEFENDERS_CHECK_PERIOD * 0.1),
true);
295 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(
GetOwner().FindComponent(SCR_CampaignSeizingComponent));
297 if (seizingComponent)
299 seizingComponent.GetOnCaptureStart().Insert(OnCaptureStart);
300 seizingComponent.GetOnCaptureInterrupt().Insert(EndCapture);
316 void ApplyHeaderSettings(notnull SCR_CampaignCustomBase settings)
322 float radioRange = settings.GetRadioRange();
327 BaseRadioComponent radio = BaseRadioComponent.Cast(
GetOwner().FindComponent(BaseRadioComponent));
338 transceiver.SetRange(radioRange);
339 RecalculateRadioRange();
343 override void OnServiceStateChanged(SCR_EServicePointStatus state, notnull SCR_ServicePointComponent serviceComponent)
347 case SCR_EServicePointStatus.UNDER_CONSTRUCTION:
352 case SCR_EServicePointStatus.ONLINE:
354 OnServiceBuilt(serviceComponent);
364 baseManager.OnServiceBuilt(state, serviceComponent);
372 void OnServiceBuilt(notnull SCR_ServicePointComponent service)
374 bool duringInit = (
GetGame().GetWorld().GetWorldTime() <= 0);
420 RecalculateRadioRange();
447 SCR_CampaignBuildingCompositionComponent buildingComponent = SCR_CampaignBuildingCompositionComponent.Cast(
SCR_EntityHelper.GetMainParent(service.GetOwner(),
true).FindComponent(SCR_CampaignBuildingCompositionComponent));
449 if (buildingComponent && !buildingComponent.GetProviderEntity())
450 buildingComponent.SetProviderEntityServer(
GetOwner());
452 if (radio !=
SCR_ERadioMsg.NONE && owner && IsHQRadioTrafficPossible(
GetFaction(), SCR_ECampaignHQRadioComms.BOTH_WAYS) && !duringInit)
455 GetGame().GetCallqueue().Remove(SendHighestPriorityMessage);
461 foreach (SCR_MilitaryBaseLogicComponent logic : m_aSystems)
463 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(logic);
465 if (!seizingComponent)
468 seizingComponent.RefreshSeizingTimer();
482 if (msg < topPriorityEnum)
483 topPriorityEnum = msg;
487 faction.SendHQMessage(topPriorityEnum,
m_iCallsign);
492 void OnServiceRemoved(notnull SCR_MilitaryBaseLogicComponent service)
494 SCR_ServicePointComponent serviceCast = SCR_ServicePointComponent.Cast(service);
496 if (!serviceCast || serviceCast.GetServiceState() != SCR_EServicePointStatus.ONLINE)
503 RecalculateRadioRange();
505 foreach (SCR_MilitaryBaseLogicComponent logic : m_aSystems)
507 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(logic);
509 if (!seizingComponent)
512 seizingComponent.RefreshSeizingTimer();
518 void OnServiceBuilt_AfterInit(SCR_ServicePointComponent service)
526 ResourceName delegatePrefab = service.GetDelegatePrefab();
528 if (delegatePrefab.IsEmpty())
531 Resource delegateResource = Resource.Load(delegatePrefab);
533 if (!delegateResource || !delegateResource.IsValid())
536 EntitySpawnParams
params = EntitySpawnParams();
537 params.TransformMode = ETransformMode.WORLD;
538 service.GetOwner().GetTransform(
params.Transform);
539 IEntity delegateEntity =
GetGame().SpawnEntityPrefab(delegateResource,
null,
params);
544 SCR_ServicePointDelegateComponent delegateComponent = SCR_ServicePointDelegateComponent.Cast(delegateEntity.FindComponent(SCR_ServicePointDelegateComponent));
546 if (!delegateComponent)
549 service.SetDelegate(delegateComponent);
550 delegateComponent.SetParentBaseId(Replication.FindId(
this));
554 if (RplSession.Mode() != RplMode.Dedicated)
579 campaign.GetOnFactionAssignedLocalPlayer().Remove(OnLocalPlayerFactionAssigned);
581 if (RplSession.Mode() != RplMode.Dedicated)
582 DisconnectFromCampaignBasesSystem();
584 campaign.GetBaseManager().GetOnAllBasesInitialized().Remove(OnAllBasesInitialized);
586 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(
GetOwner().FindComponent(SCR_CampaignSeizingComponent));
588 if (seizingComponent)
590 seizingComponent.GetOnCaptureStart().Remove(OnCaptureStart);
591 seizingComponent.GetOnCaptureInterrupt().Remove(EndCapture);
605 void SetAsHQ(
bool isHQ)
618 if (previousHQ && previousHQ !=
this && previousHQ != enemyHQ)
620 if (previousHQ.GetDisableWhenUnusedAsHQ())
621 previousHQ.Disable();
625 Replication.BumpMe();
630 protected void OnHQSet()
635 owner.SetMainBase(
this);
640 HandleSpawnPointFaction();
642 GetGame().GetCallqueue().Remove(SpawnStartingVehicles);
646 SupplyIncomeTimer(
true);
647 GetGame().GetCallqueue().CallLater(SpawnStartingVehicles, 1500,
false);
661 bool CostSuppliesToSpawn()
678 float GetRadioRange()
684 protected float GetRelayRadioRange(notnull BaseRadioComponent radio)
687 int transceiversCount;
691 for (
int i = 0, count = radio.TransceiversCount(); i < count; i++)
698 thisRange = transceiver.GetRange();
700 if (thisRange <= range)
711 void UpdateBasesInRadioRange()
714 array<SCR_MilitaryBaseComponent> bases = {};
715 baseManager.GetBases(bases);
718 float radioRange = GetRadioRange();
719 radioRange = radioRange * radioRange;
720 vector basePosition =
GetOwner().GetOrigin();
724 foreach (SCR_MilitaryBaseComponent base : bases)
728 if (!campaignBase || !campaignBase.IsInitialized() || campaignBase ==
this)
731 if (vector.DistanceSqXZ(basePosition, campaignBase.GetOwner().GetOrigin()) < radioRange)
749 bool CanReachByRadio(notnull SCR_CampaignMobileAssemblyStandaloneComponent mobileAssembly)
751 return (vector.DistanceXZ(
GetOwner().
GetOrigin(), mobileAssembly.GetOwner().GetOrigin()) <= GetRadioRange());
757 void SetHQRadioConverage(notnull
SCR_Faction faction, SCR_ECampaignHQRadioComms coverage)
779 Replication.BumpMe();
780 OnHasSignalChanged();
786 SCR_ECampaignHQRadioComms GetHQRadioCoverage(notnull
Faction faction)
791 return SCR_ECampaignHQRadioComms.NONE;
798 return SCR_ECampaignHQRadioComms.NONE;
806 bool IsHQRadioTrafficPossible(
Faction faction, SCR_ECampaignHQRadioComms
direction = SCR_ECampaignHQRadioComms.RECEIVE)
820 case SCR_ECampaignHQRadioComms.RECEIVE:
823 return (m_eRadioCoverageBLUFOR == SCR_ECampaignHQRadioComms.RECEIVE || m_eRadioCoverageBLUFOR == SCR_ECampaignHQRadioComms.BOTH_WAYS);
825 return (m_eRadioCoverageOPFOR == SCR_ECampaignHQRadioComms.RECEIVE || m_eRadioCoverageOPFOR == SCR_ECampaignHQRadioComms.BOTH_WAYS);
830 case SCR_ECampaignHQRadioComms.SEND:
833 return (m_eRadioCoverageBLUFOR == SCR_ECampaignHQRadioComms.SEND || m_eRadioCoverageBLUFOR == SCR_ECampaignHQRadioComms.BOTH_WAYS);
835 return (m_eRadioCoverageOPFOR == SCR_ECampaignHQRadioComms.SEND || m_eRadioCoverageOPFOR == SCR_ECampaignHQRadioComms.BOTH_WAYS);
842 return (
direction == m_eRadioCoverageBLUFOR);
844 return (
direction == m_eRadioCoverageOPFOR);
848 protected void OnLocalPlayerFactionAssigned(
Faction assignedFaction)
850 UpdateBasesInRadioRange();
853 HideMapLocationLabel();
858 float GetBaseSpawnCostFactor()
861 return BARRACKS_REDUCED_DEPLOY_COST;
868 int GetBaseSpawnCost()
876 return campaign.GetSpawnCost() * GetBaseSpawnCostFactor();
887 BeginCapture(factionC);
900 supportClass.GenerateCaptureTasks(
GetOwner());
906 void NotifyAboutEnemyAttack(notnull
Faction attackingFaction)
915 WorldTimestamp curTime = world.GetServerTimestamp();
942 Replication.BumpMe();
943 OnCapturingFactionChanged();
948 int GetReconfiguredByID()
955 bool GetDisableWhenUnusedAsHQ()
977 Replication.BumpMe();
978 OnCapturingFactionChanged();
979 NotifyAboutEnemyAttack(faction);
986 protected void HandleSpawnPointFaction()
998 ownerKey = owner.GetFactionKey();
1002 if (ownerKey == FactionKey.Empty)
1004 if (currentKey != FactionKey.Empty)
1010 if (!
m_bIsHQ && !IsHQRadioTrafficPossible(owner, SCR_ECampaignHQRadioComms.BOTH_WAYS))
1011 finalKey = FactionKey.Empty;
1015 finalKey = FactionKey.Empty;
1017 if (GetSupplies() < GetBaseSpawnCost() && !
m_bIsHQ)
1018 finalKey = FactionKey.Empty;
1020 if (finalKey == currentKey)
1034 override void OnCapturingFactionChanged()
1036 super.OnCapturingFactionChanged();
1051 SignalsManagerComponent comp = SignalsManagerComponent.Cast(
m_HQRadio.FindComponent(SignalsManagerComponent));
1056 comp.SetSignalValue(comp.AddOrFindSignal(ESTABLISH_ACTION_SIGNAL_NAME), 1);
1058 comp.SetSignalValue(comp.AddOrFindSignal(ESTABLISH_ACTION_SIGNAL_NAME), 0);
1067 campaign.GetBaseManager().EvaluateControlPoints();
1070 if (RplSession.Mode() != RplMode.Dedicated)
1075 FlashBaseIcon(changeToDefault:
true);
1081 void FlashBaseIcon(
float remainingTime = 0,
Faction faction =
null,
bool changeToDefault =
false,
bool infiniteTimer =
false)
1083 GetGame().GetCallqueue().Remove(FlashBaseIcon);
1086 m_UIElement.FlashBaseIcon(faction, changeToDefault);
1088 remainingTime -= SCR_CampaignFeedbackComponent.ICON_FLASH_PERIOD;
1090 if (infiniteTimer || remainingTime > 0 || !changeToDefault)
1091 GetGame().GetCallqueue().CallLater(FlashBaseIcon, SCR_CampaignFeedbackComponent.ICON_FLASH_PERIOD * 1000,
false, remainingTime, faction, !changeToDefault, infiniteTimer);
1096 void OnHasSignalChanged()
1100 HandleSpawnPointFaction();
1101 SupplyIncomeTimer(
true);
1104 if (RplSession.Mode() != RplMode.Dedicated)
1110 campaign.GetBaseManager().GetOnSignalChanged().Invoke(
this);
1114 protected void OnSuppliesChanged()
1117 HandleSpawnPointFaction();
1119 if (RplSession.Mode() != RplMode.Dedicated &&
m_UIElement)
1125 override protected void OnFactionChanged(FactionAffiliationComponent owner,
Faction previousFaction,
Faction faction)
1127 super.OnFactionChanged(owner, previousFaction, faction);
1134 if (!newCampaignFaction)
1142 float curTime =
GetGame().GetWorld().GetWorldTime();
1149 Replication.BumpMe();
1152 if (curTime > 10000)
1154 campaign.GetBaseManager().RecalculateRadioCoverage(campaign.GetFactionByEnum(
SCR_ECampaignFaction.BLUFOR));
1155 campaign.GetBaseManager().RecalculateRadioCoverage(campaign.GetFactionByEnum(
SCR_ECampaignFaction.OPFOR));
1158 ChangeRadioSettings(newCampaignFaction);
1161 SupplyIncomeTimer(
true);
1168 OnRespawnCooldownChanged();
1169 Replication.BumpMe();
1172 HandleSpawnPointFaction();
1173 SendHQMessageBaseCaptured();
1176 if (newCampaignFaction.IsPlayable() && !
m_bIsHQ)
1178 foreach (SCR_AmbientPatrolSpawnPointComponent remnants :
m_aRemnants)
1180 AIGroup grp = remnants.GetSpawnedGroup();
1187 EntitySpawnParams
params = EntitySpawnParams();
1188 params.TransformMode = ETransformMode.WORLD;
1199 if (
GetGame().GetWorld().GetWorldTime() != 0)
1203 if (RplSession.Mode() != RplMode.Dedicated)
1211 SetRadioChatterSignal(newCampaignFaction);
1219 if (player && playerFaction && playerFaction != GetCampaignFaction() && IsHQRadioTrafficPossible(playerFaction))
1221 if (GetCampaignFaction())
1242 void OnSpawnPointFactionAssigned(FactionKey faction)
1244 if (RplSession.Mode() != RplMode.Dedicated)
1251 void ChangeRadioSettings(notnull
SCR_Faction faction)
1263 int factionFrequency = faction.GetFactionRadioFrequency();
1266 if (factionFrequency < tsv.GetMinFrequency() || factionFrequency > tsv.GetMaxFrequency())
1269 tsv.SetFrequency(factionFrequency);
1275 void RegisterRemnants(notnull SCR_AmbientPatrolSpawnPointComponent remnants)
1282 ResourceName GetBuildingIconImageset()
1287 return ResourceName.Empty;
1289 return componentData.GetBuildingIconImageset();
1301 return componentData.GetGraphLinesData();
1306 float GetLineWidth()
1313 return componentData.GetLineWidth();
1325 grp.GetOnEmpty().Insert(RemoveGroup);
1343 override void SetCallsign(notnull
SCR_Faction faction)
1353 int callsignOffset = campaign.GetCallsignOffset();
1354 campaign.GetOnCallsignOffsetChanged().Remove(OnCallsignAssigned);
1356 if (callsignOffset == INVALID_BASE_CALLSIGN)
1358 campaign.GetOnCallsignOffsetChanged().Insert(OnCallsignAssigned);
1362 SCR_MilitaryBaseCallsign callsignInfo;
1366 callsignInfo = faction.GetBaseCallsignByIndex(
m_iCallsign);
1368 callsignInfo = faction.GetBaseCallsignByIndex(
m_iCallsign, callsignOffset);
1373 m_sCallsign = callsignInfo.GetCallsign();
1374 m_sCallsignNameOnly = callsignInfo.GetCallsignShort();
1375 m_sCallsignNameOnlyUC = callsignInfo.GetCallsignUpperCase();
1376 m_iCallsignSignal = callsignInfo.GetSignalIndex();
1380 override void SetCallsignIndexAutomatic(
int index)
1389 protected void SupplyIncomeTimer(
bool reset =
false)
1396 Replication.BumpMe();
1400 float curTime = world.GetWorldTime();
1414 Replication.BumpMe();
1420 AddRegularSupplyPackage(owner);
1427 protected void AddRegularSupplyPackage(notnull
Faction faction)
1430 float currentSupplies = GetSupplies();
1431 float maxSupplies = GetSuppliesMax();
1435 spaceLimit =
float.MAX;
1437 spaceLimit = campaign.GetSuppliesReplenishThreshold() - currentSupplies;
1439 if (spaceLimit <= 0 || currentSupplies >= maxSupplies)
1442 Replication.BumpMe();
1446 int quickReplenishThreshold = campaign.GetQuickSuppliesReplenishThreshold();
1447 float quickReplenishMultiplier = campaign.GetQuickSuppliesReplenishMultiplier();
1448 int income = campaign.GetRegularSuppliesIncomeBase();
1449 int incomeHQ = campaign.GetRegularSuppliesIncome();
1454 if (currentSupplies < quickReplenishThreshold)
1456 int incomeHQQuick = incomeHQ * quickReplenishMultiplier;
1457 incomeHQQuick = Math.Min(incomeHQQuick, quickReplenishThreshold - currentSupplies);
1458 toAdd = Math.Max(incomeHQQuick, incomeHQ);
1467 if (currentSupplies < quickReplenishThreshold)
1469 int incomeQuick = income * quickReplenishMultiplier;
1470 incomeQuick = Math.Min(incomeQuick, quickReplenishThreshold - currentSupplies);
1471 toAdd = Math.Max(incomeQuick, income);
1479 int extraBasesCount;
1488 if (base.GetFaction() != faction)
1491 if (!base.IsHQRadioTrafficPossible(faction))
1496 if (extraBasesCount == BASES_IN_RANGE_RESUPPLY_THRESHOLD)
1501 toAdd += (
SCR_GameModeCampaign.GetInstance().GetRegularSuppliesIncomeExtra() * extraBasesCount);
1502 AddSupplies(Math.Min(toAdd, spaceLimit));
1505 Replication.BumpMe();
1510 SCR_CampaignMilitaryBaseMapDescriptorComponent GetMapDescriptor()
1525 bool GetIsEntityInMyRange(notnull IEntity entity)
1527 return vector.Distance(entity.GetOrigin(),
GetOwner().
GetOrigin()) <= GetRadioRange();
1534 SCR_ResourceComponent resourceComponent = GetResourceComponent();
1536 if (!resourceComponent)
1541 if (!resourceConsumer)
1545 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
1547 return resourceConsumer.GetAggregatedResourceValue();
1552 float GetSuppliesMax()
1554 SCR_ResourceComponent resourceComponent = GetResourceComponent();
1556 if (!resourceComponent)
1561 if (!resourceConsumer)
1565 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
1567 return resourceConsumer.GetAggregatedMaxResourceValue();
1572 int GetSuppliesIncome()
1580 void RegisterHQRadio(notnull IEntity radio)
1583 SetRadioChatterSignal(GetCampaignFaction());
1587 override void RegisterLogicComponent(notnull SCR_MilitaryBaseLogicComponent component)
1589 super.RegisterLogicComponent(component);
1591 SCR_FlagComponent flag = SCR_FlagComponent.Cast(component);
1612 SignalsManagerComponent comp = SignalsManagerComponent.Cast(
m_HQRadio.FindComponent(SignalsManagerComponent));
1617 if (!faction || faction.GetFactionKey() == campaign.GetFactionKeyByEnum(
SCR_ECampaignFaction.INDFOR))
1619 comp.SetSignalValue(comp.AddOrFindSignal(RADIO_CHATTER_SIGNAL_NAME), 0);
1625 comp.SetSignalValue(comp.AddOrFindSignal(RADIO_CHATTER_SIGNAL_NAME), 1);
1629 comp.SetSignalValue(comp.AddOrFindSignal(RADIO_CHATTER_SIGNAL_NAME), 2);
1636 IEntity GetHQRadio()
1643 void HideMapLocationLabel()
1653 MapDescriptorComponent comp = MapDescriptorComponent.Cast(ent.FindComponent(MapDescriptorComponent));
1663 item.SetVisible(
false);
1668 SCR_ResourceComponent GetResourceComponent()
1670 return SCR_ResourceComponent.FindResourceComponent(
GetOwner());
1677 void AddSupplies(
int suppliesCount,
bool replicate =
true)
1679 if (suppliesCount == 0)
1682 SCR_ResourceComponent resourceComponent = GetResourceComponent();
1684 if (!resourceComponent)
1687 if (suppliesCount > 0)
1691 if (!resourceGenerator)
1694 resourceGenerator.RequestGeneration(suppliesCount);
1700 if (!resourceConsumer)
1703 resourceConsumer.RequestConsumtion(-suppliesCount);
1706 HandleSpawnPointFaction();
1711 void SetSupplies(
float suppliesCount)
1713 SCR_ResourceComponent resourceComponent = GetResourceComponent();
1715 if (!resourceComponent)
1720 if (!resourceConsumer)
1724 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
1726 AddSupplies(suppliesCount - resourceConsumer.GetAggregatedResourceValue());
1731 void SetInitialSupplies(
float suppliesCount)
1733 SCR_ResourceComponent resourceComponent = GetResourceComponent();
1735 if (!resourceComponent)
1740 if (!resourceConsumer)
1744 GetGame().GetResourceGrid().UpdateInteractor(resourceConsumer);
1747 if (suppliesCount > resourceConsumer.GetAggregatedResourceValue())
1748 SetSupplies(suppliesCount);
1753 void SetStartingSupplies(
float suppliesCount)
1761 void AlterSupplyIncomeTimer(
float time)
1768 int GetBasesInRange(
SCR_ECampaignBaseType filter, notnull out array<SCR_CampaignMilitaryBaseComponent> basesInRange)
1779 if ((filter & baseType) == baseType)
1781 basesInRange.Insert(base);
1818 string GetBaseName()
1825 string GetBaseNameUpperCase()
1832 bool IsBeingCaptured()
1844 void SetAttackingFaction(
int enemyFaction)
1851 Replication.BumpMe();
1852 OnAttackingFactionChanged();
1857 void OnAttackingFactionChanged()
1863 GetGame().GetCallqueue().CallLater(SetAttackingFaction, 1000,
false, -1);
1867 if (RplSession.Mode() != RplMode.Dedicated && enemyFaction != playerFaction &&
GetFaction() == playerFaction)
1868 FlashBaseIcon(SCR_CampaignFeedbackComponent.ICON_FLASH_DURATION, enemyFaction);
1873 void OnRespawnCooldownChanged()
1876 WorldTimestamp curTime = world.GetServerTimestamp();
1883 if (RplSession.Mode() != RplMode.Dedicated)
1884 UpdateRespawnCooldown();
1889 void UpdateRespawnCooldown()
1892 WorldTimestamp curTime = world.GetServerTimestamp();
1897 GetGame().GetCallqueue().Remove(UpdateRespawnCooldown);
1904 override void OnCallsignAssigned()
1919 campaign.GetOnCallsignOffsetChanged().Remove(OnCallsignAssigned);
1920 int callsignOffset = campaign.GetCallsignOffset();
1922 if (callsignOffset == INVALID_BASE_CALLSIGN)
1924 campaign.GetOnCallsignOffsetChanged().Insert(OnCallsignAssigned);
1928 SetCallsign(faction);
1933 void OnAllBasesInitialized()
1937 UpdateBasesInRadioRange();
1945 ResourceName buildingPrefab = GetCampaignFaction().GetBuildingPrefab(
EEditableEntityLabel.SERVICE_HQ);
1947 if (!buildingPrefab)
1951 if (Math.RandomFloat01() >= 0.5)
1964 void RecalculateRadioRange()
1968 array<SCR_ServicePointComponent> antennas = {};
1970 BaseRadioComponent radio;
1973 foreach (SCR_ServicePointComponent service : antennas)
1975 SCR_AntennaServicePointComponent antenna = SCR_AntennaServicePointComponent.Cast(service);
1976 radio = BaseRadioComponent.Cast(antenna.GetOwner().FindComponent(BaseRadioComponent));
1982 if (radio.IsPowered())
1983 radio.SetPower(
false);
1985 thisRange = GetRelayRadioRange(radio);
1987 if (thisRange > range)
1999 for (
int i = 0, count =
m_RadioComponent.TransceiversCount(); i < count; i++)
2006 transceiver.SetRange(range);
2011 Replication.BumpMe();
2012 OnRadioRangeChanged();
2017 void OnRadioRangeChanged()
2019 UpdateBasesInRadioRange();
2037 if (
GetGame().GetWorld().GetWorldTime() > campaign.BACKEND_DELAY)
2040 bManager.RecalculateRadioCoverage(GetCampaignFaction());
2045 GetGame().GetCallqueue().Remove(bManager.RecalculateRadioCoverage);
2046 GetGame().GetCallqueue().CallLater(bManager.RecalculateRadioCoverage, campaign.DEFAULT_DELAY,
false, campaign.GetFactionByEnum(
SCR_ECampaignFaction.BLUFOR));
2047 GetGame().GetCallqueue().CallLater(bManager.RecalculateRadioCoverage, campaign.DEFAULT_DELAY,
false, campaign.GetFactionByEnum(
SCR_ECampaignFaction.OPFOR));
2062 void SendHQMessageBaseCaptured()
2072 int newOwnerPoints = newOwner.GetControlPointsHeld();
2074 if (newOwnerPoints == campaign.GetControlPointTreshold() && IsControlPoint())
2079 FactionManager factionManager =
GetGame().GetFactionManager();
2080 if (!factionManager)
2095 else if (IsControlPoint())
2111 protected void SpawnStartingVehicles()
2118 if (campaign.IsTutorial())
2121 EntitySpawnParams
params =
new EntitySpawnParams();
2122 params.TransformMode = ETransformMode.WORLD;
2124 IEntity vehicleEntity;
2125 Physics physicsComponent;
2127 array<ResourceName> prefabNames = {};
2128 GetCampaignFaction().GetStartingVehiclePrefabs(prefabNames);
2130 foreach (ResourceName prefabName : prefabNames)
2136 if (vector.DistanceSqXZ(pos, oldPos) < 1)
2137 SCR_WorldTools.FindEmptyTerrainPosition(pos, oldPos, HQ_VEHICLE_SPAWN_RADIUS, HQ_VEHICLE_QUERY_SPACE);
2139 params.Transform[3] = pos;
2141 Resource veh = Resource.Load(prefabName);
2143 if (!veh || !veh.IsValid())
2150 physicsComponent = vehicleEntity.GetPhysics();
2152 if (physicsComponent)
2153 physicsComponent.SetVelocity(
"0 -0.1 0");
2161 protected void DeleteStartingVehicles()
2166 RplComponent.DeleteRplEntity(veh,
false);
2171 protected void RemoveFortifications()
2173 IEntity child =
GetOwner().GetChildren();
2178 if (child.FindComponent(SCR_CampaignBuildingCompositionComponent))
2181 child = child.GetSibling();
2198 FactionManager factionManager =
GetGame().GetFactionManager();
2200 if (!factionManager)
2205 if (faction && GetCampaignFaction() != faction)
2207 SetFaction(faction);
2208 RemoveFortifications();
2213 SetAsHQ(baseStruct.IsHQ());
2214 UpdateBasesInRadioRange();
2216 GetGame().GetCallqueue().Remove(SpawnBuilding);
2220 RplComponent.DeleteRplEntity(
m_HQTent,
false);
2223 GetGame().GetCallqueue().Remove(SpawnStartingVehicles);
2224 GetGame().GetCallqueue().Remove(SetInitialSupplies);
2225 DeleteStartingVehicles();
2254 void SpawnBuilding(ResourceName prefab, vector
position, vector
rotation,
bool isMainTent =
false)
2256 if (prefab.IsEmpty())
2262 EntitySpawnParams
params = EntitySpawnParams();
2264 params.TransformMode = ETransformMode.WORLD;
2268 IEntity composition =
GetGame().SpawnEntityPrefab(Resource.Load(prefab),
null,
params);
2278 if (m_fStartingSupplies >= 0)
2285 aiWorld.RequestNavmeshRebuildEntity(composition);
2288 vector transform[4];
2290 if (!editableEntity)
2292 GetOwner().GetTransform(transform);
2294 composition.SetTransform(transform);
2298 editableEntity.GetTransform(transform);
2303 editableEntity.SetTransformWithChildren(transform);
2308 void EvaluateDefenders()
2312 if (!baseFaction.IsPlayable())
2315 SCR_CampaignFactionManager factionManager = SCR_CampaignFactionManager.Cast(
GetGame().GetFactionManager());
2317 if (!factionManager)
2320 if (GetHQRadioCoverage(factionManager.GetEnemyFaction(baseFaction)) == SCR_ECampaignHQRadioComms.NONE)
2324 array<int> playerIds = {};
2325 array<int> playerIdsPresent = {};
2326 playerManager.GetPlayers(playerIds);
2328 vector basePos =
GetOwner().GetOrigin();
2329 SCR_XPHandlerComponent compXP = SCR_XPHandlerComponent.Cast(
GetGame().
GetGameMode().FindComponent(SCR_XPHandlerComponent));
2330 bool enemiesPresent;
2333 radiusSq = m_iRadius * m_iRadius;
2335 radiusSq = RELAY_BASE_RADIUS * RELAY_BASE_RADIUS;
2337 foreach (
int playerId : playerIds)
2339 SCR_ChimeraCharacter player = SCR_ChimeraCharacter.Cast(playerManager.GetPlayerControlledEntity(playerId));
2344 CharacterControllerComponent charController = player.GetCharacterController();
2346 if (charController.IsDead())
2349 if (vector.DistanceSqXZ(player.GetOrigin(), basePos) > radiusSq)
2352 if (player.GetFaction() == baseFaction)
2353 playerIdsPresent.Insert(playerId);
2355 enemiesPresent =
true;
2359 WorldTimestamp curTime = world.GetServerTimestamp();
2360 foreach (
int playerId : playerIdsPresent)
2363 if (startedDefendingAt == 0)
2367 else if (curTime.DiffMilliseconds(startedDefendingAt) >= DEFENDERS_REWARD_PERIOD)
2372 compXP.AwardXP(playerManager.GetPlayerController(playerId),
SCR_EXPRewards.BASE_DEFENDED, DEFENDERS_REWARD_MULTIPLIER);
2374 compXP.AwardXP(playerManager.GetPlayerController(playerId),
SCR_EXPRewards.BASE_DEFENDED);
2383 if (playerIdsPresent.Contains(playerId))
2395 baseStruct.SetIsHQ(IsHQ());
2399 baseStruct.SetSupplies(GetSupplies());
2403 protected void ConnectToCampaignBasesSystem()
2405 World world =
GetOwner().GetWorld();
2410 updateSystem.Register(
this);
2413 protected void DisconnectFromCampaignBasesSystem()
2415 World world =
GetOwner().GetWorld();
2420 updateSystem.Unregister(
this);
2426 void Update(
float timeSlice)
2446 override void EOnInit(IEntity owner)
2448 super.EOnInit(owner);
2450 if (RplSession.Mode() != RplMode.Dedicated)
2451 m_MapDescriptor = SCR_CampaignMilitaryBaseMapDescriptorComponent.Cast(
GetOwner().FindComponent(SCR_CampaignMilitaryBaseMapDescriptorComponent));
2461 SCR_ResourceComponent resourceComponent = GetResourceComponent();
2462 if (resourceComponent)
2465 if (consumerComponent)
2467 consumerComponent.GetOnResourcesChanged().Insert(HandleSpawnPointFaction);
2473 override void OnPostInit(IEntity owner)
2475 super.OnPostInit(owner);
2487 override void OnDelete(IEntity owner)
2489 DisconnectFromCampaignBasesSystem();
2491 SCR_CampaignSeizingComponent seizingComponent = SCR_CampaignSeizingComponent.Cast(
GetOwner().FindComponent(SCR_CampaignSeizingComponent));
2493 if (seizingComponent)
2495 seizingComponent.GetOnCaptureStart().Remove(OnCaptureStart);
2496 seizingComponent.GetOnCaptureInterrupt().Remove(EndCapture);
2503 campaign.GetOnFactionAssignedLocalPlayer().Remove(OnLocalPlayerFactionAssigned);
2504 campaign.GetBaseManager().GetOnAllBasesInitialized().Remove(OnAllBasesInitialized);
2505 campaign.GetOnCallsignOffsetChanged().Remove(OnCallsignAssigned);
2508 SCR_ResourceComponent resourceComponent = GetResourceComponent();
2509 if (resourceComponent)
2512 if (consumerComponent)
2514 consumerComponent.GetOnResourcesChanged().Remove(HandleSpawnPointFaction);
2518 super.OnDelete(owner);
2523 class SCR_CampaignCustomBase
2525 [
Attribute(
"", UIWidgets.EditBox,
"Base entity name as set up in World Editor.")]
2528 [
Attribute(defvalue:
"0", uiwidget: UIWidgets.CheckBox)]
2531 [
Attribute(defvalue:
"0", uiwidget: UIWidgets.CheckBox)]
2534 [
Attribute(defvalue:
"1", uiwidget: UIWidgets.CheckBox)]