Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_CampaignMilitaryBaseManager.c
Go to the documentation of this file.
6 
12 
13 typedef ScriptInvokerBase<OnSignalChangedDelegate> OnSignalChangedInvoker;
14 typedef ScriptInvokerBase<OnAllBasesInitializedDelegate> OnAllBasesInitializedInvoker;
15 typedef ScriptInvokerBase<OnLocalPlayerEnteredBaseDelegate> OnLocalPlayerEnteredBaseInvoker;
16 typedef ScriptInvokerBase<OnLocalPlayerLeftBaseDelegate> OnLocalPlayerLeftBaseInvoker;
17 typedef ScriptInvokerBase<OnLocalFactionCapturedBaseDelegate> OnLocalFactionCapturedBaseInvoker;
18 
19 //------------------------------------------------------------------------------------------------
22 {
23  protected static const int PARENT_BASE_DISTANCE_THRESHOLD = 300; //AI patrols closer than this to a base will couterattack
24  protected static const int HQ_NO_REMNANTS_RADIUS = 300; //AI patrols closer than this to main HQs will be removed
25  protected static const int HQ_NO_REMNANTS_PATROL_RADIUS = 600; //AI patrols with a waypoint which is closer than this to main HQs will be removed
26  protected static const int MAX_HQ_SELECTION_ITERATIONS = 20;
27  protected static const int DEPOT_PLAYER_PRESENCE_CHECK_INTERVAL = 2000; //ms
28  protected static const float CP_AVG_DISTANCE_TOLERANCE = 0.25; //highest relative distance tolerance to control points when evaluating main HQs
29  protected static const string ICON_NAME_SUPPLIES = "Slot_Supplies";
30  protected static const float MAX_DIST_TO_BASE = 300;
31  protected static const float PARKED_LIFETIME = 3600;
32 
33  protected SCR_GameModeCampaign m_Campaign;
34 
35  protected SCR_CampaignFaction m_LocalPlayerFaction;
36 
37  protected ref array<SCR_CampaignMilitaryBaseComponent> m_aBases = {};
38  protected ref array<SCR_CampaignMilitaryBaseComponent> m_aControlPoints = {};
39  protected ref array<SCR_CampaignSuppliesComponent> m_aRemnantSupplyDepots = {};
40 
41  protected ref OnSignalChangedInvoker m_OnSignalChanged;
42  protected ref OnAllBasesInitializedInvoker m_OnAllBasesInitialized;
43  protected ref OnLocalPlayerEnteredBaseInvoker m_OnLocalPlayerEnteredBase;
44  protected ref OnLocalPlayerLeftBaseInvoker m_OnLocalPlayerLeftBase;
45 
46  protected int m_iActiveBases;
47  protected int m_iTargetActiveBases;
48 
49  protected bool m_bAllBasesInitialized;
50 
51  //------------------------------------------------------------------------------------------------
53  int GetActiveBasesCount()
54  {
55  return m_iActiveBases;
56  }
57 
58  //------------------------------------------------------------------------------------------------
60  int GetTargetActiveBasesCount()
61  {
62  return m_iTargetActiveBases;
63  }
64 
65  //------------------------------------------------------------------------------------------------
66  void AddActiveBase()
67  {
68  m_iActiveBases++;
69 
70  if (m_iActiveBases == m_iTargetActiveBases)
71  OnAllBasesInitialized();
72  }
73 
74  //------------------------------------------------------------------------------------------------
75  void AddTargetActiveBase()
76  {
77  m_iTargetActiveBases++;
78  }
79 
80  //------------------------------------------------------------------------------------------------
81  void SetTargetActiveBasesCount(int count)
82  {
83  m_iTargetActiveBases = count;
84  }
85 
86  //------------------------------------------------------------------------------------------------
87  OnLocalPlayerEnteredBaseInvoker GetOnLocalPlayerEnteredBase()
88  {
89  if (!m_OnLocalPlayerEnteredBase)
90  m_OnLocalPlayerEnteredBase = new OnLocalPlayerEnteredBaseInvoker();
91 
92  return m_OnLocalPlayerEnteredBase;
93  }
94 
95  //------------------------------------------------------------------------------------------------
96  OnLocalPlayerLeftBaseInvoker GetOnLocalPlayerLeftBase()
97  {
98  if (!m_OnLocalPlayerLeftBase)
99  m_OnLocalPlayerLeftBase = new OnLocalPlayerLeftBaseInvoker();
100 
101  return m_OnLocalPlayerLeftBase;
102  }
103 
104  //------------------------------------------------------------------------------------------------
106  OnAllBasesInitializedInvoker GetOnAllBasesInitialized()
107  {
108  if (!m_OnAllBasesInitialized)
109  m_OnAllBasesInitialized = new OnAllBasesInitializedInvoker();
110 
111  return m_OnAllBasesInitialized;
112  }
113 
114  //------------------------------------------------------------------------------------------------
116  OnSignalChangedInvoker GetOnSignalChanged()
117  {
118  if (!m_OnSignalChanged)
119  m_OnSignalChanged = new OnSignalChangedInvoker();
120 
121  return m_OnSignalChanged;
122  }
123 
124  //------------------------------------------------------------------------------------------------
125  void OnAllBasesInitialized()
126  {
127  m_bAllBasesInitialized = true;
128 
129  // On server, this is done in gamemode class Start() method
130  if (m_Campaign.IsProxy())
131  UpdateBases();
132 
133  if (m_OnAllBasesInitialized)
134  m_OnAllBasesInitialized.Invoke();
135 
136  if (RplSession.Mode() != RplMode.Dedicated)
137  {
138  InitializeSupplyDepotIcons();
139  HideUnusedBaseIcons();
140  }
141 
142  if (m_Campaign.IsProxy())
143  return;
144 
145  SCR_MilitaryBaseSystem.GetInstance().GetOnLogicRegisteredInBase().Insert(DisableExtraSeizingComponents);
146  ProcessRemnantsPresence();
147  RecalculateRadioCoverage(m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR));
148  RecalculateRadioCoverage(m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.OPFOR));
149  }
150 
151  //------------------------------------------------------------------------------------------------
152  bool IsBasesInitDone()
153  {
154  return m_bAllBasesInitialized;
155  }
156 
157  //------------------------------------------------------------------------------------------------
158  protected void DisableExtraSeizingComponents(SCR_MilitaryBaseComponent base, SCR_MilitaryBaseLogicComponent logic)
159  {
160  if (logic.Type() == SCR_SeizingComponent)
161  SCR_SeizingComponent.Cast(logic).Disable();
162  }
163 
164  //------------------------------------------------------------------------------------------------
165  void SetLocalPlayerFaction(notnull SCR_CampaignFaction faction)
166  {
167  m_LocalPlayerFaction = faction;
168  }
169 
170  //------------------------------------------------------------------------------------------------
171  SCR_CampaignFaction GetLocalPlayerFaction()
172  {
173  return m_LocalPlayerFaction;
174  }
175 
176  //------------------------------------------------------------------------------------------------
178  int UpdateBases()
179  {
180  SCR_MilitaryBaseSystem baseManager = SCR_MilitaryBaseSystem.GetInstance();
181  array<SCR_MilitaryBaseComponent> bases = {};
182  baseManager.GetBases(bases);
183 
184  m_aBases.Clear();
185  m_aControlPoints.Clear();
186  int count;
187 
188  foreach (SCR_MilitaryBaseComponent base : bases)
189  {
191 
192  if (!campaignBase)
193  continue;
194 
195  m_aBases.Insert(campaignBase);
196  count++;
197 
198  if (campaignBase.IsControlPoint())
199  m_aControlPoints.Insert(campaignBase);
200  }
201 
202  return count;
203  }
204 
205  //------------------------------------------------------------------------------------------------
207  void SelectHQs(notnull array<SCR_CampaignMilitaryBaseComponent> candidates, notnull array<SCR_CampaignMilitaryBaseComponent> controlPoints, out notnull array<SCR_CampaignMilitaryBaseComponent> selectedHQs)
208  {
209  // Pick the same HQs every time when debugging
210 #ifdef TDM_CLI_SELECTION
211  SelectHQsSimple(candidates, selectedHQs);
212  return;
213 #endif
214 
215  int candidatesCount = candidates.Count();
216 
217  // If only two HQs are set up, don't waste time with processing
218  if (candidatesCount == 2)
219  {
220  SelectHQsSimple(candidates, selectedHQs);
221  return;
222  }
223 
224  int iterations;
225  int totalBasesDistance;
228  array<SCR_CampaignMilitaryBaseComponent> eligibleForHQ;
229  vector bluforHQPos;
230  int averageHQDistance;
231  int averageCPDistance;
232  int acceptedCPDistanceDiff;
233 
234  while (!opforHQ && iterations < MAX_HQ_SELECTION_ITERATIONS)
235  {
236  iterations++;
237  totalBasesDistance = 0;
238  eligibleForHQ = {};
239 
240  // Pick one of the HQs at random
241  Math.Randomize(-1);
242  bluforHQ = candidates.GetRandomElement();
243  bluforHQPos = bluforHQ.GetOwner().GetOrigin();
244 
245  // Calculate average distance between our HQ and others
246  foreach (SCR_CampaignMilitaryBaseComponent otherHQ : candidates)
247  {
248  if (otherHQ == bluforHQ)
249  continue;
250 
251  totalBasesDistance += vector.DistanceSqXZ(bluforHQPos, otherHQ.GetOwner().GetOrigin());
252  }
253 
254  averageHQDistance = totalBasesDistance / (candidatesCount - 1); // Our HQ is subtracted
255  averageCPDistance = GetAvgCPDistanceSq(bluforHQ, controlPoints);
256  acceptedCPDistanceDiff = averageCPDistance * CP_AVG_DISTANCE_TOLERANCE;
257 
258  foreach (SCR_CampaignMilitaryBaseComponent candidate : candidates)
259  {
260  if (candidate == bluforHQ)
261  continue;
262 
263  // Ignore HQs closer than the average distance
264  if (vector.DistanceSqXZ(bluforHQPos, candidate.GetOwner().GetOrigin()) < averageHQDistance)
265  continue;
266 
267  // Ignore HQs too far from control points (relative to our HQ)
268  if (Math.AbsInt(averageCPDistance - GetAvgCPDistanceSq(candidate, controlPoints)) > acceptedCPDistanceDiff)
269  continue;
270 
271  eligibleForHQ.Insert(candidate);
272  }
273 
274  // No HQs fit the condition, restart loop
275  if (eligibleForHQ.Count() == 0)
276  continue;
277 
278  Math.Randomize(-1);
279  opforHQ = eligibleForHQ.GetRandomElement();
280  }
281 
282  // Selection failed, use the simplified but reliable one
283  if (!opforHQ)
284  {
285  SelectHQsSimple(candidates, selectedHQs);
286  return;
287  }
288 
289  // Randomly assign the factions in reverse in case primary selection gets too limited
290  if (Math.RandomFloat01() >= 0.5)
291  selectedHQs = {bluforHQ, opforHQ};
292  else
293  selectedHQs = {opforHQ, bluforHQ};
294  }
295 
296  //------------------------------------------------------------------------------------------------
298  protected void SelectHQsSimple(notnull array<SCR_CampaignMilitaryBaseComponent> candidates, out notnull array<SCR_CampaignMilitaryBaseComponent> selectedHQs)
299  {
300  // Pick the same HQs every time when debugging
301 #ifdef TDM_CLI_SELECTION
302  selectedHQs = {candidates[0], candidates[1]};
303  return;
304 #endif
305 
306  // In Tutorial mode, we always want to use the same HQs
307  if (m_Campaign.IsTutorial())
308  {
309  if (candidates[0].GetFaction(true) == m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR))
310  selectedHQs = {candidates[0], candidates[1]};
311  else
312  selectedHQs = {candidates[1], candidates[0]};
313 
314  return;
315  }
316 
317  Math.Randomize(-1);
318  SCR_CampaignMilitaryBaseComponent bluforHQ = candidates.GetRandomElement();
319  candidates.RemoveItem(bluforHQ);
320  SCR_CampaignMilitaryBaseComponent opforHQ = candidates.GetRandomElement();
321 
322  if (Math.RandomFloat01() >= 0.5)
323  selectedHQs = {bluforHQ, opforHQ};
324  else
325  selectedHQs = {opforHQ, bluforHQ};
326  }
327 
328  //------------------------------------------------------------------------------------------------
329  void SetHQFactions(notnull array<SCR_CampaignMilitaryBaseComponent> selectedHQs)
330  {
331  SCR_CampaignFaction factionBLUFOR = m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR);
332  SCR_CampaignFaction factionOPFOR = m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.OPFOR);
333  SCR_CampaignFaction factionINDFOR = m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.INDFOR);
334 
335  if (selectedHQs[0].GetFaction() == selectedHQs[1].GetFaction())
336  {
337  // Preset owners are the same or null, assign new owners normally
338  selectedHQs[0].SetFaction(factionBLUFOR);
339  selectedHQs[1].SetFaction(factionOPFOR);
340  }
341  else
342  {
343  // Check if one of the preset owners is invalid, if yes, assign a new owner which is not assigned to the other HQ
344  if (!selectedHQs[0].GetFaction() || selectedHQs[0].GetFaction() == factionINDFOR)
345  {
346  if (selectedHQs[1].GetFaction() == factionBLUFOR)
347  selectedHQs[0].SetFaction(factionOPFOR);
348  else
349  selectedHQs[0].SetFaction(factionBLUFOR);
350  }
351  else if (!selectedHQs[1].GetFaction() || selectedHQs[1].GetFaction() == factionINDFOR)
352  {
353  if (selectedHQs[0].GetFaction() == factionBLUFOR)
354  selectedHQs[1].SetFaction(factionOPFOR);
355  else
356  selectedHQs[1].SetFaction(factionBLUFOR);
357  }
358  }
359  }
360 
361  //------------------------------------------------------------------------------------------------
363  protected int GetAvgCPDistanceSq(notnull SCR_CampaignMilitaryBaseComponent HQ, notnull array<SCR_CampaignMilitaryBaseComponent> controlPoints)
364  {
365  int thresholdCP = m_Campaign.GetControlPointTreshold();
366 
367  // Avoid division by zero
368  if (thresholdCP == 0)
369  return 0;
370 
371  array<SCR_CampaignMilitaryBaseComponent> nearestControlPoints = {};
372 
373  int distanceToHQ;
374  int controlPointsCount;
375  int arrayIndex;
376  int nearestControlPointsCount;
377 
378  vector HQPos = HQ.GetOwner().GetOrigin();
379 
380  foreach (SCR_CampaignMilitaryBaseComponent controlPoint : controlPoints)
381  {
382  if (!controlPoint)
383  continue;
384 
385  distanceToHQ = vector.DistanceSqXZ(controlPoint.GetOwner().GetOrigin(), HQPos);
386  controlPointsCount = nearestControlPoints.Count();
387  arrayIndex = controlPointsCount;
388 
389  for (int i = 0; i < controlPointsCount; i++)
390  {
391  if (distanceToHQ < vector.DistanceSqXZ(HQPos, nearestControlPoints[i].GetOwner().GetOrigin()))
392  {
393  arrayIndex = i;
394  break;
395  }
396  }
397 
398  nearestControlPointsCount = nearestControlPoints.InsertAt(controlPoint, arrayIndex);
399  }
400 
401  // Avoid division by zero
402  if (nearestControlPointsCount == 0)
403  return 0;
404 
405  if (thresholdCP < nearestControlPointsCount)
406  nearestControlPoints.Resize(thresholdCP);
407 
408  int totalDist;
409 
410  foreach (SCR_CampaignMilitaryBaseComponent controlPoint : nearestControlPoints)
411  {
412  totalDist += vector.DistanceSqXZ(HQPos, controlPoint.GetOwner().GetOrigin());
413  }
414 
415  return totalDist / nearestControlPointsCount;
416  }
417 
418  //------------------------------------------------------------------------------------------------
419  void InitializeBases(notnull array<SCR_CampaignMilitaryBaseComponent> selectedHQs, bool randomizeSupplies)
420  {
421  array<SCR_CampaignMilitaryBaseComponent> basesSorted = {};
422  SCR_CampaignMilitaryBaseComponent baseCheckedAgainst;
423  vector originHQ1 = selectedHQs[0].GetOwner().GetOrigin();
424  vector originHQ2 = selectedHQs[1].GetOwner().GetOrigin();
425  float distanceToHQ;
426  bool indexFound;
427  int callsignIndex;
428  array<int> allCallsignIndexes = {};
429  array<int> callsignIndexesBLUFOR = m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.BLUFOR).GetBaseCallsignIndexes();
430  SCR_CampaignFaction factionOPFOR = m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.OPFOR);
431 
432  // Grab all valid base callsign indexes (if both factions have the index)
433  foreach (int indexBLUFOR : callsignIndexesBLUFOR)
434  {
435  if (factionOPFOR.GetBaseCallsignByIndex(indexBLUFOR))
436  allCallsignIndexes.Insert(indexBLUFOR);
437  }
438 
439  int callsignsCount = allCallsignIndexes.Count();
440  Math.Randomize(-1);
441  Faction defaultFaction;
442  BaseRadioComponent radio;
443  BaseTransceiver tsv;
444 
445  foreach (int iBase, SCR_CampaignMilitaryBaseComponent campaignBase : m_aBases)
446  {
447  if (!campaignBase.IsInitialized())
448  continue;
449 
450  defaultFaction = campaignBase.GetFaction(true);
451 
452  // Apply default faction set in FactionAffiliationComponent or INDFOR if undefined
453  if (!campaignBase.GetFaction())
454  {
455  if (defaultFaction)
456  campaignBase.SetFaction(defaultFaction);
457  else
458  campaignBase.SetFaction(m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.INDFOR));
459  }
460 
461  // Register bases in range of each other
462  campaignBase.UpdateBasesInRadioRange();
463 
464  // Assign callsign
465  if (campaignBase.GetType() == SCR_ECampaignBaseType.BASE)
466  {
467  callsignIndex = allCallsignIndexes.GetRandomIndex();
468  campaignBase.SetCallsignIndex(allCallsignIndexes[callsignIndex]);
469  allCallsignIndexes.Remove(callsignIndex);
470  }
471  else
472  {
473  // Relays use a dummy callsign just so search by callsign is still possible
474  campaignBase.SetCallsignIndex(callsignsCount + iBase);
475  }
476 
477  // Sort bases by distance to a HQ so randomized supplies can be applied fairly (if enabled)
478  if (randomizeSupplies && campaignBase.GetType() == SCR_ECampaignBaseType.BASE)
479  {
480  indexFound = false;
481  distanceToHQ = vector.DistanceSqXZ(originHQ1, campaignBase.GetOwner().GetOrigin());
482 
483  for (int i = 0, count = basesSorted.Count(); i < count; i++)
484  {
485  baseCheckedAgainst = basesSorted[i];
486 
487  if (distanceToHQ < vector.DistanceSqXZ(originHQ1, baseCheckedAgainst.GetOwner().GetOrigin()))
488  {
489  basesSorted.InsertAt(campaignBase, i);
490  indexFound = true;
491  break;
492  }
493  }
494 
495  if (!indexFound)
496  basesSorted.Insert(campaignBase);
497  }
498  }
499 
500  if (randomizeSupplies)
501  AddRandomSupplies(basesSorted, selectedHQs);
502  }
503 
504  //------------------------------------------------------------------------------------------------
506  void AddRandomSupplies(notnull array<SCR_CampaignMilitaryBaseComponent> basesSorted, notnull array<SCR_CampaignMilitaryBaseComponent> selectedHQs)
507  {
508  array<int> suppliesBufferBLUFOR = {};
509  array<int> suppliesBufferOPFOR = {};
510  int intervalMultiplier = Math.Floor((m_Campaign.GetMaxStartingSupplies() - m_Campaign.GetMinStartingSupplies()) / m_Campaign.GetStartingSuppliesInterval());
511  FactionKey factionToProcess;
512  vector basePosition;
513  float distanceToHQ1;
514  float distanceToHQ2;
515  int suppliesToAdd;
516 
517  foreach (SCR_CampaignMilitaryBaseComponent base : basesSorted)
518  {
519  if (base.IsHQ())
520  continue;
521 
522  basePosition = base.GetOwner().GetOrigin();
523  distanceToHQ1 = vector.DistanceSq(basePosition, selectedHQs[0].GetOwner().GetOrigin());
524  distanceToHQ2 = vector.DistanceSq(basePosition, selectedHQs[1].GetOwner().GetOrigin());
525 
526  if (distanceToHQ1 > distanceToHQ2)
527  factionToProcess = selectedHQs[1].GetCampaignFaction().GetFactionKey();
528  else
529  factionToProcess = selectedHQs[0].GetCampaignFaction().GetFactionKey();
530 
531  // Check if we have preset supplies stored in buffer
532  if (factionToProcess == m_Campaign.GetFactionKeyByEnum(SCR_ECampaignFaction.BLUFOR) && !suppliesBufferBLUFOR.IsEmpty())
533  {
534  suppliesToAdd = suppliesBufferBLUFOR[0];
535  suppliesBufferBLUFOR.RemoveOrdered(0);
536  }
537  else if (factionToProcess == m_Campaign.GetFactionKeyByEnum(SCR_ECampaignFaction.OPFOR) && !suppliesBufferOPFOR.IsEmpty())
538  {
539  suppliesToAdd = suppliesBufferOPFOR[0];
540  suppliesBufferOPFOR.RemoveOrdered(0);
541  }
542  else
543  {
544  // Supplies from buffer not applied, add random amount, store to opposite faction's buffer
545  suppliesToAdd = m_Campaign.GetMinStartingSupplies() + (m_Campaign.GetStartingSuppliesInterval() * Math.RandomIntInclusive(0, intervalMultiplier));
546 
547  if (factionToProcess == m_Campaign.GetFactionKeyByEnum(SCR_ECampaignFaction.BLUFOR))
548  suppliesBufferOPFOR.Insert(suppliesToAdd);
549  else
550  suppliesBufferBLUFOR.Insert(suppliesToAdd);
551  }
552 
553  base.SetStartingSupplies(suppliesToAdd);
554  }
555  }
556 
557  //------------------------------------------------------------------------------------------------
560  void UpdateTaskBases(Faction assignedFaction)
561  {
563  {
564  if (base.IsInitialized() && base.GetCallsignDisplayName().IsEmpty())
565  base.GetMapDescriptor().HandleMapInfo();
566  }
567 
568  SCR_BaseTaskManager taskManager = GetTaskManager();
569 
570  if (!taskManager)
571  return;
572 
573  array<SCR_BaseTask> tasks = {};
574  taskManager.GetFilteredTasks(tasks, assignedFaction);
575 
576  foreach (SCR_BaseTask task : tasks)
577  {
578  SCR_CampaignBaseTask conflictTask = SCR_CampaignBaseTask.Cast(task);
579 
580  if (!conflictTask)
581  continue;
582 
583  int baseId = conflictTask.GetTargetBaseId();
584 
585  if (baseId == -1)
586  continue;
587 
588  SCR_CampaignMilitaryBaseComponent base = FindBaseByCallsign(baseId);
589 
590  if (!base || base.GetFaction() == conflictTask.GetTargetFaction())
591  continue;
592 
593  conflictTask.SetTargetBase(base);
594  }
595  }
596 
597  //------------------------------------------------------------------------------------------------
599  void InitializeSupplyDepotIcons()
600  {
601  IEntity depot;
602  vector origin;
603  MapItem item;
605  MapDescriptorProps props;
606  SCR_MapDescriptorComponent mapDescriptorComponent;
607  int threshold = m_Campaign.GetSupplyDepotIconThreshold();
608  Color colorFIA = m_Campaign.GetFactionByEnum(SCR_ECampaignFaction.INDFOR).GetFactionColor();
609 
610  foreach (SCR_CampaignSuppliesComponent comp : m_aRemnantSupplyDepots)
611  {
612  depot = comp.GetOwner();
613 
614  if (!depot)
615  continue;
616 
617  mapDescriptorComponent = SCR_MapDescriptorComponent.Cast(depot.FindComponent(SCR_MapDescriptorComponent));
618 
619  if (!mapDescriptorComponent)
620  continue;
621 
622  item = mapDescriptorComponent.Item();
623  origin = depot.GetOrigin();
624  closestBase = FindClosestBase(origin);
625 
626  if (!closestBase)
627  continue;
628 
629  if (vector.Distance(origin, closestBase.GetOwner().GetOrigin()) <= threshold)
630  {
631  item.SetVisible(true);
632  item.SetImageDef(ICON_NAME_SUPPLIES);
633 
634  props = item.GetProps();
635  props.SetIconSize(32, 0.25, 0.25);
636  props.SetFrontColor(colorFIA);
637  props.SetTextVisible(false);
638  props.Activate(true);
639  }
640  else
641  {
642  item.SetVisible(false);
643  }
644  }
645  }
646 
647  //------------------------------------------------------------------------------------------------
648  void RegisterRemnantSupplyDepot(notnull SCR_CampaignSuppliesComponent comp)
649  {
650  m_aRemnantSupplyDepots.Insert(comp);
651  }
652 
653  //------------------------------------------------------------------------------------------------
654  void HideUnusedBaseIcons()
655  {
656  SCR_MapDescriptorComponent mapDescriptorComponent;
657  MapItem item;
658 
660  {
661  if (base.IsInitialized())
662  continue;
663 
664  mapDescriptorComponent = SCR_MapDescriptorComponent.Cast(base.GetOwner().FindComponent(SCR_MapDescriptorComponent));
665 
666  if (!mapDescriptorComponent)
667  continue;
668 
669  item = mapDescriptorComponent.Item();
670 
671  if (!item)
672  continue;
673 
674  item.SetVisible(false);
675  }
676  }
677 
678  //------------------------------------------------------------------------------------------------
680  void RecalculateRadioCoverage(notnull SCR_CampaignFaction faction)
681  {
682  SCR_CampaignMilitaryBaseComponent hq = faction.GetMainBase();
683 
684  // No HQ is currently operational, switch all bases to out of signal state
685  if (!hq)
686  {
688  {
689  if (!base.IsInitialized())
690  continue;
691 
692  if (base.GetFaction() == faction)
693  base.SetHQRadioConverage(faction, SCR_ECampaignHQRadioComms.NONE);
694  }
695 
696  return;
697  }
698 
699  int basesCount = m_aBases.Count();
701  map<SCR_CampaignMilitaryBaseComponent, SCR_ECampaignHQRadioComms> newSettings = new map<SCR_CampaignMilitaryBaseComponent, SCR_ECampaignHQRadioComms>();
702  array<SCR_CampaignMilitaryBaseComponent> canReceiveHQ = {};
703  array<SCR_CampaignMilitaryBaseComponent> canReachHQ = {};
704  SCR_CampaignMobileAssemblyStandaloneComponent mobileHQComponent = faction.GetMobileAssembly();
705  SCR_ECampaignHQRadioComms connectionMHQ = SCR_ECampaignHQRadioComms.NONE;
706  bool processedMHQ;
707  int noMHQNeeded;
708 
709  // This loop is restarted every time a new link has been found to make sure all new possible links are also handled
710  for (int i = 0; i < basesCount; i++)
711  {
713 
714  if (base.IsInitialized() && (!base.IsHQ() || base.GetFaction() == faction))
715  CheckBaseRadioCoverage(i, base, hq, mobileHQComponent, connectionMHQ, faction, canReceiveHQ, canReachHQ, newSettings);
716 
717  // All bases have been processed, check MHQ connection
718  if (i == basesCount - 1 && !processedMHQ && connectionMHQ != SCR_ECampaignHQRadioComms.NONE)
719  {
720  processedMHQ = true;
721 
722  if (noMHQNeeded == 0)
723  noMHQNeeded = canReceiveHQ.Count();
724 
725  array<SCR_CampaignMilitaryBaseComponent> connectedBases = {};
726  mobileHQComponent.GetBasesInRange(connectedBases);
727  vector posMHQ = mobileHQComponent.GetOwner().GetOrigin();
728 
729  foreach (SCR_CampaignMilitaryBaseComponent connectedBase : connectedBases)
730  {
731  if (connectedBase.IsHQ() && connectedBase.GetFaction() != faction)
732  continue;
733 
734  CheckBaseMHQConnection(i, connectedBase, connectionMHQ, newSettings, canReceiveHQ, canReachHQ, vector.DistanceXZ(posMHQ, connectedBase.GetOwner().GetOrigin()));
735  }
736  }
737  }
738 
739  // We want to know how many bases are linked only by MHQ (shown in a user action)
740  if (mobileHQComponent)
741  mobileHQComponent.SetCountOfExclusivelyLinkedBases(canReceiveHQ.Count() - noMHQNeeded);
742 
743  int settingsCount = newSettings.Count();
744  SCR_ECampaignHQRadioComms newCoverage;
745 
746  // Trace finished, apply radio status to all bases where the coverage has actually changed
747  for (int i = 0; i < settingsCount; i++)
748  {
749  base = newSettings.GetKey(i);
750  newCoverage = newSettings.Get(base);
751 
752  if (base.GetHQRadioCoverage(faction) != newCoverage)
753  base.SetHQRadioConverage(faction, newCoverage);
754  }
755 
756  if (settingsCount != 0)
757  {
758  EvaluateControlPoints();
759  SelectPrimaryTarget(faction);
760  }
761  }
762 
763  //------------------------------------------------------------------------------------------------
764  void CheckBaseRadioCoverage(inout int i, notnull SCR_CampaignMilitaryBaseComponent base, notnull SCR_CampaignMilitaryBaseComponent hq, SCR_CampaignMobileAssemblyStandaloneComponent mobileHQComponent, inout SCR_ECampaignHQRadioComms connectionMHQ, notnull SCR_CampaignFaction faction, inout notnull array<SCR_CampaignMilitaryBaseComponent> canReceiveHQ, inout notnull array<SCR_CampaignMilitaryBaseComponent> canReachHQ, inout notnull map<SCR_CampaignMilitaryBaseComponent, SCR_ECampaignHQRadioComms> newSettings)
765  {
766  bool processedReceive = canReceiveHQ.Contains(base);
767  bool processedReach = canReachHQ.Contains(base);
768 
769  if (processedReceive && processedReach)
770  return;
771 
772  bool canReceive;
773  bool canReach;
774  SCR_ECampaignHQRadioComms newCoverage;
775  SCR_ECampaignHQRadioComms savedCoverage;
776 
777  if (base == hq)
778  {
779  canReceive = true;
780  canReach = true;
781  }
782  else
783  {
784  savedCoverage = newSettings.Get(base);
785 
786  if (processedReceive)
787  {
788  canReceive = (savedCoverage == SCR_ECampaignHQRadioComms.RECEIVE);
789  }
790  else
791  {
792  // Checked base can receive broadcast from a base which can receive broadcast from HQ
793  foreach (SCR_CampaignMilitaryBaseComponent receiving : canReceiveHQ)
794  {
795  if (receiving.GetFaction() == faction && receiving.CanReachByRadio(base))
796  {
797  canReceive = true;
798  break;
799  }
800  }
801  }
802 
803  if (processedReach)
804  {
805  canReach = (savedCoverage == SCR_ECampaignHQRadioComms.SEND);
806  }
807  else
808  {
809  // Checked base can broadcast to a base which can broadcast to HQ
810  foreach (SCR_CampaignMilitaryBaseComponent reaching : canReachHQ)
811  {
812  if (reaching.GetFaction() == faction && base.CanReachByRadio(reaching))
813  {
814  canReach = true;
815  break;
816  }
817  }
818  }
819  }
820 
821  if (newSettings.Contains(base))
822  newCoverage = savedCoverage;
823  else
824  newCoverage = base.GetHQRadioCoverage(faction);
825 
826  if (!canReceive && !canReach)
827  {
828  newCoverage = SCR_ECampaignHQRadioComms.NONE;
829  }
830  else
831  {
832  if (canReceive && !processedReceive)
833  {
834  if (canReach || processedReach)
835  newCoverage = SCR_ECampaignHQRadioComms.BOTH_WAYS;
836  else
837  newCoverage = SCR_ECampaignHQRadioComms.RECEIVE;
838 
839  canReceiveHQ.Insert(base);
840  i = -1; // New link has been found - restart loop
841  }
842 
843  if (canReach && !processedReach)
844  {
845  if (canReceive || processedReceive)
846  newCoverage = SCR_ECampaignHQRadioComms.BOTH_WAYS;
847  else
848  newCoverage = SCR_ECampaignHQRadioComms.SEND;
849 
850  canReachHQ.Insert(base);
851  i = -1; // New link has been found - restart loop
852  }
853  }
854 
855  newSettings.Set(base, newCoverage);
856 
857  // Check if MHQ is connected to the radio network and its traffic capabilities
858  if (mobileHQComponent && connectionMHQ != SCR_ECampaignHQRadioComms.BOTH_WAYS)
859  {
860  if ((newCoverage == SCR_ECampaignHQRadioComms.BOTH_WAYS || newCoverage == SCR_ECampaignHQRadioComms.RECEIVE) && mobileHQComponent.CanReachByRadio(base))
861  connectionMHQ = newCoverage;
862  }
863  }
864 
865  //------------------------------------------------------------------------------------------------
866  void CheckBaseMHQConnection(inout int i, notnull SCR_CampaignMilitaryBaseComponent connectedBase, SCR_ECampaignHQRadioComms connectionMHQ, inout notnull map<SCR_CampaignMilitaryBaseComponent, SCR_ECampaignHQRadioComms> newSettings, inout notnull array<SCR_CampaignMilitaryBaseComponent> canReceiveHQ, inout notnull array<SCR_CampaignMilitaryBaseComponent> canReachHQ, float distance)
867  {
868  SCR_ECampaignHQRadioComms coverage = newSettings.Get(connectedBase);
869 
870  if (coverage == SCR_ECampaignHQRadioComms.BOTH_WAYS || coverage == connectionMHQ)
871  return;
872 
873  i = -1; // We found a new linked base, restart the loop
874 
875  if (!canReceiveHQ.Contains(connectedBase))
876  canReceiveHQ.Insert(connectedBase);
877 
878  bool canReach;
879 
880  if (connectionMHQ == SCR_ECampaignHQRadioComms.BOTH_WAYS && connectedBase.GetRadioRange() > distance)
881  {
882  if (!canReachHQ.Contains(connectedBase))
883  canReachHQ.Insert(connectedBase);
884 
885  canReach = true;
886  }
887 
888  if (coverage == SCR_ECampaignHQRadioComms.NONE)
889  {
890  if (canReach)
891  newSettings.Set(connectedBase, connectionMHQ);
892  else
893  newSettings.Set(connectedBase, SCR_ECampaignHQRadioComms.RECEIVE);
894  }
895  else if (canReach || coverage == SCR_ECampaignHQRadioComms.SEND)
896  {
897  newSettings.Set(connectedBase, SCR_ECampaignHQRadioComms.BOTH_WAYS);
898  }
899  }
900 
901  //------------------------------------------------------------------------------------------------
903  void SelectPrimaryTarget(notnull SCR_CampaignFaction faction)
904  {
905  array<SCR_CampaignMilitaryBaseComponent> controlPointsInRange = {};
906 
907  // Get all Control Points which are now available for capture
908  foreach (SCR_CampaignMilitaryBaseComponent base : m_aControlPoints)
909  {
910  if (!base.IsInitialized() || base.IsHQ())
911  continue;
912 
913  if (base.GetFaction() == faction)
914  continue;
915 
916  if (!base.IsHQRadioTrafficPossible(faction))
917  continue;
918 
919  controlPointsInRange.Insert(base);
920  }
921 
923  int minDistance = int.MAX;
924 
925  // If there are some Control Points in radio range, find the closest one
926  if (!controlPointsInRange.IsEmpty())
927  {
928  array<SCR_CampaignMilitaryBaseComponent> ownedBases = {};
929 
930  // Get all bases the given faction currently holds
932  {
933  if (!base.IsInitialized())
934  continue;
935 
936  if (base.GetFaction() != faction)
937  continue;
938 
939  if (!base.IsHQRadioTrafficPossible(faction))
940  continue;
941 
942  ownedBases.Insert(base);
943  }
944 
945  foreach (SCR_CampaignMilitaryBaseComponent controlPoint : controlPointsInRange)
946  {
947  vector positionCP = controlPoint.GetOwner().GetOrigin();
948 
949  foreach (SCR_CampaignMilitaryBaseComponent base : ownedBases)
950  {
951  int distance = vector.DistanceSqXZ(base.GetOwner().GetOrigin(), positionCP);
952 
953  if (distance > minDistance)
954  continue;
955 
956  minDistance = distance;
957  target = controlPoint;
958  }
959  }
960  }
961  else // Otherwise, find the Control Point closest to one of the capturable bases
962  {
963  array<SCR_CampaignMilitaryBaseComponent> basesInRange = {};
964 
965  // Get all bases which are now available for capture
967  {
968  if (!base.IsInitialized() || base.IsHQ())
969  continue;
970 
971  if (base.GetFaction() == faction)
972  continue;
973 
974  if (!base.IsHQRadioTrafficPossible(faction))
975  continue;
976 
977  basesInRange.Insert(base);
978  }
979 
980  bool targetCoversControlPoint;
981 
982  foreach (SCR_CampaignMilitaryBaseComponent controlPoint : m_aControlPoints)
983  {
984  if (!controlPoint.IsInitialized() || controlPoint.IsHQ())
985  continue;
986 
987  if (controlPoint.GetFaction() == faction)
988  continue;
989 
990  vector positionCP = controlPoint.GetOwner().GetOrigin();
991 
992  foreach (SCR_CampaignMilitaryBaseComponent base : basesInRange)
993  {
994  int distance = vector.DistanceSqXZ(base.GetOwner().GetOrigin(), positionCP);
995  bool closer = distance < minDistance;
996  bool coversControlPoint = base.CanReachByRadio(controlPoint);
997 
998  // Also check if some of the bases in range can reach the Control Point with radio
999  if (coversControlPoint)
1000  {
1001  if (targetCoversControlPoint && !closer)
1002  continue;
1003  }
1004  else
1005  {
1006  if (targetCoversControlPoint || !closer)
1007  continue;
1008  }
1009 
1010  minDistance = distance;
1011  target = base;
1012  }
1013  }
1014  }
1015 
1016  m_Campaign.SetPrimaryTarget(faction, target);
1017  }
1018 
1019  //------------------------------------------------------------------------------------------------
1020  // Checks whether some faction is winning the game
1021  void EvaluateControlPoints()
1022  {
1023  FactionManager factionManager = GetGame().GetFactionManager();
1024  array<Faction> factions = {};
1025  factionManager.GetFactionsList(factions);
1026 
1027  int controlPointsHeld;
1028  int controlPointsContested;
1029  ChimeraWorld world = GetGame().GetWorld();
1030  WorldTimestamp currentTime = world.GetServerTimestamp();
1031  WorldTimestamp victoryTimestamp;
1032  WorldTimestamp blockPauseTimestamp;
1033 
1034  foreach (Faction faction : factions)
1035  {
1036  SCR_CampaignFaction fCast = SCR_CampaignFaction.Cast(faction);
1037 
1038  if (!fCast || !fCast.IsPlayable())
1039  continue;
1040 
1041  controlPointsHeld = 0;
1042  controlPointsContested = 0;
1043 
1044  // Update amount of control points currently held by this faction
1045  foreach (SCR_CampaignMilitaryBaseComponent controlPoint : m_aControlPoints)
1046  {
1047  if (controlPoint.IsInitialized() && controlPoint.GetFaction() == fCast && controlPoint.IsHQRadioTrafficPossible(fCast, SCR_ECampaignHQRadioComms.RECEIVE))
1048  {
1049  controlPointsHeld++;
1050 
1051  if (controlPoint.GetCapturingFaction() && controlPoint.GetCapturingFaction() != fCast)
1052  controlPointsContested++
1053  }
1054  }
1055 
1056  m_Campaign.SetControlPointsHeld(fCast, controlPointsHeld);
1057 
1058  victoryTimestamp = fCast.GetVictoryTimestamp();
1059  blockPauseTimestamp = fCast.GetPauseByBlockTimestamp();
1060  int controlPointsThreshold = m_Campaign.GetControlPointTreshold();
1061 
1062  // Update timers (if a faction starts winning or a point is contested)
1063  if (controlPointsHeld >= controlPointsThreshold)
1064  {
1065  if ((controlPointsHeld - controlPointsContested) < controlPointsThreshold)
1066  {
1067  if (blockPauseTimestamp == 0)
1068  fCast.SetPauseByBlockTimestamp(currentTime);
1069  }
1070  else if (blockPauseTimestamp != 0)
1071  {
1072  fCast.SetVictoryTimestamp(currentTime.PlusMilliseconds(victoryTimestamp.DiffMilliseconds(blockPauseTimestamp)));
1073  fCast.SetPauseByBlockTimestamp(null);
1074  }
1075 
1076  if (victoryTimestamp == 0)
1077  fCast.SetVictoryTimestamp(currentTime.PlusSeconds(m_Campaign.GetVictoryTimer()));
1078  }
1079  else
1080  {
1081  fCast.SetVictoryTimestamp(null);
1082  fCast.SetPauseByBlockTimestamp(null);
1083  }
1084  }
1085  }
1086 
1087  //------------------------------------------------------------------------------------------------
1088  void OnEnemyDetectedByDefenders(SCR_AIGroup group, SCR_AITargetInfo target, AIAgent reporter)
1089  {
1090  // Identify the base under attack, notify about it
1092  {
1093  if (!base.IsInitialized())
1094  continue;
1095 
1096  if (base.ContainsGroup(group))
1097  {
1098  base.NotifyAboutEnemyAttack(target.m_Faction);
1099  return;
1100  }
1101  }
1102  }
1103 
1104  //------------------------------------------------------------------------------------------------
1105  SCR_CampaignMilitaryBaseComponent FindClosestBase(vector position)
1106  {
1108  float closestBaseDistance = float.MAX;
1109 
1111  {
1112  if (!base.IsInitialized())
1113  continue;
1114 
1115  float distance = vector.DistanceSq(base.GetOwner().GetOrigin(), position);
1116 
1117  if (distance < closestBaseDistance)
1118  {
1119  closestBaseDistance = distance;
1120  closestBase = base;
1121  }
1122  }
1123 
1124  return closestBase;
1125  }
1126 
1127  //------------------------------------------------------------------------------------------------
1128  SCR_CampaignMilitaryBaseComponent FindBaseByCallsign(int callsign)
1129  {
1130  if (callsign == SCR_MilitaryBaseComponent.INVALID_BASE_CALLSIGN)
1131  return null;
1132 
1134  {
1135  if (base.GetCallsign() == callsign)
1136  return base;
1137  }
1138 
1139  return null;
1140  }
1141 
1142  //------------------------------------------------------------------------------------------------
1143  SCR_CampaignMilitaryBaseComponent FindBaseByPosition(vector position)
1144  {
1146  {
1147  if (base.GetOwner().GetOrigin() == position)
1148  return base;
1149  }
1150 
1151  return null;
1152  }
1153 
1154  //------------------------------------------------------------------------------------------------
1155  bool IsEntityInFactionRadioSignal(notnull IEntity entity, notnull Faction faction)
1156  {
1157  SCR_CampaignFaction factionC = SCR_CampaignFaction.Cast(faction);
1158 
1159  if (!factionC)
1160  return false;
1161 
1162  // Check if the entity is within range of deployed mobile HQ which is able to relay the signal
1163  SCR_CampaignMobileAssemblyStandaloneComponent mobileHQ = factionC.GetMobileAssembly();
1164 
1165  if (mobileHQ && mobileHQ.GetOwner() != entity && mobileHQ.IsInRadioRange())
1166  {
1167  if (vector.DistanceSq(entity.GetOrigin(), mobileHQ.GetOwner().GetOrigin()) < Math.Pow(mobileHQ.GetRadioRange(), 2))
1168  return true;
1169  }
1170 
1172  {
1173  if (!base)
1174  continue;
1175 
1176  if (faction != base.GetFaction())
1177  continue;
1178 
1179  if (base.GetIsEntityInMyRange(entity) && base.IsHQRadioTrafficPossible(factionC))
1180  return true;
1181  }
1182 
1183  return false;
1184  }
1185 
1186  //------------------------------------------------------------------------------------------------
1187  void StoreBasesStates(out notnull array<ref SCR_CampaignBaseStruct> outEntries)
1188  {
1190  {
1191  if (!base.IsInitialized())
1192  continue;
1193 
1195  base.StoreState(struct);
1196  outEntries.Insert(struct);
1197  }
1198  }
1199 
1200  //------------------------------------------------------------------------------------------------
1201  void LoadBasesStates(notnull array<ref SCR_CampaignBaseStruct> entries)
1202  {
1203  foreach (SCR_CampaignBaseStruct struct : entries)
1204  {
1205  SCR_CampaignMilitaryBaseComponent base = FindBaseByPosition(struct.GetPosition());
1206 
1207  if (!base)
1208  continue;
1209 
1210  base.LoadState(struct);
1211  }
1212 
1213  UpdateBases();
1214 
1216  {
1217  base.UpdateBasesInRadioRange();
1218  }
1219  }
1220 
1221  //------------------------------------------------------------------------------------------------
1223  void ProcessRemnantsPresence()
1224  {
1225  SCR_AmbientPatrolSystem manager = SCR_AmbientPatrolSystem.GetInstance();
1226 
1227  if (!manager)
1228  return;
1229 
1230  array<SCR_AmbientPatrolSpawnPointComponent> patrols = {};
1231  manager.GetPatrols(patrols);
1232 
1233  int distLimit = Math.Pow(PARENT_BASE_DISTANCE_THRESHOLD, 2);
1234  float minDistance;
1236  bool register = true;
1237  float dist;
1238  vector center;
1239 
1240  int distLimitHQ = Math.Pow(HQ_NO_REMNANTS_RADIUS, 2);
1241  int distLimitHQPatrol = Math.Pow(HQ_NO_REMNANTS_PATROL_RADIUS, 2);
1242 
1243  foreach (SCR_AmbientPatrolSpawnPointComponent patrol : patrols)
1244  {
1245  minDistance = float.MAX;
1246  register = true;
1247  center = patrol.GetOwner().GetOrigin();
1248  nearestBase = null;
1249 
1251  {
1252  if (!base.IsInitialized() || base.GetType() == SCR_ECampaignBaseType.RELAY)
1253  continue;
1254 
1255  dist = vector.DistanceSqXZ(center, base.GetOwner().GetOrigin());
1256 
1257  // Don't clear Remnants patrols around HQs if their state was already loaded
1258  if (base.IsHQ() && !m_Campaign.WasRemnantsStateLoaded())
1259  {
1260  if (dist < distLimitHQ)
1261  {
1262  patrol.SetMembersAlive(0);
1263  register = false;
1264  break;
1265 
1266  }
1267  else if (dist < distLimitHQPatrol)
1268  {
1269  AIWaypointCycle waypoint = AIWaypointCycle.Cast(patrol.GetWaypoint());
1270 
1271  if (waypoint)
1272  {
1273  patrol.SetMembersAlive(0);
1274  register = false;
1275  break;
1276  }
1277  }
1278  }
1279 
1280  if (dist > distLimit || dist > minDistance)
1281  continue;
1282 
1283  if (!base.IsHQ())
1284  {
1285  nearestBase = base;
1286  minDistance = dist;
1287  }
1288  else
1289  {
1290  register = false;
1291  break;
1292  }
1293  }
1294 
1295  if (register && nearestBase)
1296  nearestBase.RegisterRemnants(patrol);
1297  }
1298  }
1299 
1300  //------------------------------------------------------------------------------------------------
1301  void OnPlayerDisconnected(int playerId)
1302  {
1303  // If the disconnecting player is currently capturing a base; handle it
1305  {
1306  if (!base.IsInitialized())
1307  continue;
1308 
1309  if (base.GetCapturingFaction() && base.GetReconfiguredByID() == playerId)
1310  {
1311  base.EndCapture();
1312  break;
1313  }
1314  }
1315  }
1316 
1317  //------------------------------------------------------------------------------------------------
1318  void OnLocalPlayerPresenceChanged(notnull SCR_CampaignMilitaryBaseComponent base, bool present)
1319  {
1320  if (present)
1321  {
1322  if (m_OnLocalPlayerEnteredBase)
1323  m_OnLocalPlayerEnteredBase.Invoke(base);
1324  }
1325  else if (m_OnLocalPlayerLeftBase)
1326  {
1327  m_OnLocalPlayerLeftBase.Invoke(base);
1328  }
1329  }
1330 
1331  //------------------------------------------------------------------------------------------------
1332  protected void OnBaseFactionChanged(SCR_MilitaryBaseComponent base, Faction newFaction)
1333  {
1334  if (!m_Campaign.IsProxy())
1335  EvaluateControlPoints();
1336  }
1337 
1338  //------------------------------------------------------------------------------------------------
1339  void OnServiceBuilt(SCR_EServicePointStatus state, notnull SCR_ServicePointComponent serviceComponent)
1340  {
1341 
1342  }
1343 
1344  //------------------------------------------------------------------------------------------------
1345  void OnServiceRemoved(notnull SCR_MilitaryBaseComponent base, notnull SCR_MilitaryBaseLogicComponent service)
1346  {
1348 
1349  if (!campaignBase)
1350  return;
1351 
1352  campaignBase.OnServiceRemoved(service);
1353 
1354  SCR_CatalogEntitySpawnerComponent spawner = SCR_CatalogEntitySpawnerComponent.Cast(service);
1355 
1356  if (!spawner)
1357  return;
1358 
1359  spawner.GetOnEntitySpawned().Remove(m_Campaign.OnEntityRequested);
1360  }
1361 
1362  //------------------------------------------------------------------------------------------------
1364  void OnDefenderGroupSpawned(notnull SCR_MilitaryBaseLogicComponent service, notnull SCR_AIGroup group)
1365  {
1366  SCR_AIGroupUtilityComponent comp = SCR_AIGroupUtilityComponent.Cast(group.FindComponent(SCR_AIGroupUtilityComponent));
1367 
1368  if (!comp)
1369  return;
1370 
1371  ScriptInvokerBase<SCR_AIGroupPerceptionOnEnemyDetectedFiltered> onEnemyDetected = comp.m_Perception.GetOnEnemyDetectedFiltered();
1372 
1373  if (!onEnemyDetected)
1374  return;
1375 
1376  onEnemyDetected.Insert(OnEnemyDetectedByDefenders);
1377 
1378  array<SCR_MilitaryBaseComponent> bases = {};
1379  service.GetBases(bases);
1380 
1381  foreach (SCR_MilitaryBaseComponent base : bases)
1382  {
1384 
1385  if (!campaignBase)
1386  continue;
1387 
1388  campaignBase.SetDefendersGroup(group);
1389  }
1390  }
1391 
1392  //------------------------------------------------------------------------------------------------
1393  void OnConflictStarted()
1394  {
1395  }
1396 
1397  //------------------------------------------------------------------------------------------------
1399  {
1400  m_Campaign = campaign;
1401  SCR_MilitaryBaseSystem baseManager = SCR_MilitaryBaseSystem.GetInstance();
1402 
1403  if (!baseManager)
1404  return;
1405 
1406  baseManager.GetOnLogicUnregisteredInBase().Insert(OnServiceRemoved);
1407  baseManager.GetOnBaseFactionChanged().Insert(OnBaseFactionChanged);
1408 
1409  m_Campaign.GetOnStarted().Insert(OnConflictStarted);
1410  }
1411 
1412  //------------------------------------------------------------------------------------------------
1414  {
1415  //Unregister from script invokers
1416  SCR_MilitaryBaseSystem baseManager = SCR_MilitaryBaseSystem.GetInstance();
1417 
1418  if (baseManager)
1419  {
1420  baseManager.GetOnLogicUnregisteredInBase().Remove(OnServiceRemoved);
1421  baseManager.GetOnBaseFactionChanged().Remove(OnBaseFactionChanged);
1422  }
1423 
1424  if (m_Campaign)
1425  m_Campaign.GetOnStarted().Remove(OnConflictStarted);
1426  }
1427 }
1428 
1429 //------------------------------------------------------------------------------------------------
1430 enum SCR_ECampaignHQRadioComms
1431 {
1432  NONE,
1433  RECEIVE,
1434  SEND,
1435  BOTH_WAYS
1436 }
OnLocalFactionCapturedBaseDelegate
func OnLocalFactionCapturedBaseDelegate
Definition: SCR_CampaignMilitaryBaseManager.c:11
ChimeraWorld
Definition: ChimeraWorld.c:12
OnLocalPlayerLeftBaseInvoker
ScriptInvokerBase< OnLocalPlayerLeftBaseDelegate > OnLocalPlayerLeftBaseInvoker
Definition: SCR_CampaignMilitaryBaseManager.c:16
SCR_ECampaignFaction
SCR_ECampaignFaction
Definition: SCR_CampaignFactionManager.c:130
SCR_CampaignBaseTask
Definition: SCR_CampaignBaseTask.c:9
OnSignalChangedInvoker
ScriptInvokerBase< OnSignalChangedDelegate > OnSignalChangedInvoker
Definition: SCR_CampaignMilitaryBaseManager.c:13
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
OnLocalPlayerLeftBaseDelegate
func OnLocalPlayerLeftBaseDelegate
Definition: SCR_CampaignMilitaryBaseManager.c:10
OnLocalFactionCapturedBaseInvoker
ScriptInvokerBase< OnLocalFactionCapturedBaseDelegate > OnLocalFactionCapturedBaseInvoker
Definition: SCR_CampaignMilitaryBaseManager.c:17
SCR_MilitaryBaseSystem
Definition: SCR_MilitaryBaseSystem.c:11
func
func
Definition: SCR_AIThreatSystem.c:5
OnBaseFactionChanged
void OnBaseFactionChanged(notnull SCR_MilitaryBaseComponent base, Faction faction)
Definition: SCR_CampaignFeedbackComponent.c:528
SCR_BaseTask
A base class for tasks.
Definition: SCR_BaseTask.c:8
SCR_ECampaignBaseType
SCR_ECampaignBaseType
Definition: SCR_CampaignMilitaryBaseComponent.c:2577
OnAllBasesInitializedDelegate
func OnAllBasesInitializedDelegate
Definition: SCR_CampaignMilitaryBaseManager.c:8
SCR_CampaignSuppliesComponent
void SCR_CampaignSuppliesComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
Definition: SCR_CampaignSuppliesComponent.c:327
SCR_GameModeCampaign
void SCR_GameModeCampaign(IEntitySource src, IEntity parent)
Definition: SCR_GameModeCampaign.c:1927
OnServiceRemoved
void OnServiceRemoved(notnull SCR_MilitaryBaseLogicComponent service)
Definition: SCR_CampaignMilitaryBaseComponent.c:489
m_aBases
SCR_MilitaryBaseLogicComponentClass m_aBases
GetOrigin
vector GetOrigin()
Definition: SCR_AIUtilityComponent.c:279
MapDescriptorProps
Definition: MapDescriptorProps.c:12
MapItem
Definition: MapItem.c:12
distance
float distance
Definition: SCR_DestructibleTreeV2.c:29
GetTaskManager
SCR_BaseTaskManager GetTaskManager()
Definition: SCR_BaseTaskManager.c:7
SCR_AmbientPatrolSystem
Definition: SCR_AmbientPatrolSystem.c:2
OnLocalPlayerEnteredBaseInvoker
ScriptInvokerBase< OnLocalPlayerEnteredBaseDelegate > OnLocalPlayerEnteredBaseInvoker
Definition: SCR_CampaignMilitaryBaseManager.c:15
SCR_BaseTaskManager
Definition: SCR_BaseTaskManager.c:25
RECEIVE
class SCR_CampaignMilitaryBaseManager RECEIVE
SCR_SeizingComponent
Definition: SCR_SeizingComponent.c:18
BaseTransceiver
Definition: BaseTransceiver.c:12
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
SCR_CampaignBaseStruct
Definition: SCR_CampaignStruct.c:245
SEND
class SCR_CampaignMilitaryBaseManager SEND
Faction
Definition: Faction.c:12
OnSignalChangedDelegate
func OnSignalChangedDelegate
Definition: SCR_CampaignMilitaryBaseManager.c:7
SCR_CampaignMilitaryBaseManager
Created in SCR_GameModeCampaign.
Definition: SCR_CampaignMilitaryBaseManager.c:21
OnServiceBuilt
void OnServiceBuilt(notnull SCR_ServicePointComponent service)
Definition: SCR_CampaignMilitaryBaseComponent.c:369
SCR_CampaignFaction
Definition: SCR_CampaignFaction.c:2
SCR_AIGroup
Definition: SCR_AIGroup.c:68
OnLocalPlayerEnteredBaseDelegate
func OnLocalPlayerEnteredBaseDelegate
Definition: SCR_CampaignMilitaryBaseManager.c:9
OnAllBasesInitializedInvoker
ScriptInvokerBase< OnAllBasesInitializedDelegate > OnAllBasesInitializedInvoker
Definition: SCR_CampaignMilitaryBaseManager.c:14
GetFaction
SCR_CampaignFaction GetFaction()
Definition: SCR_CampaignMobileAssemblyStandaloneComponent.c:351
GetPosition
vector GetPosition()
Definition: SCR_BaseSupportStationComponent.c:690
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
OnPlayerDisconnected
override void OnPlayerDisconnected(int playerId, KickCauseCode cause, int timeout)
Definition: SCR_PlayerProfileManagerComponent.c:119
NONE
class SCR_CampaignMilitaryBaseManager NONE
SCR_CampaignMilitaryBaseComponent
Definition: SCR_CampaignMilitaryBaseComponent.c:38