Harden base progression and cleanup; validate finite physical resupply

This commit is contained in:
2026-09-19 10:39:39 +02:00
parent 40a474934c
commit 7c53b4bb81
377 changed files with 51882 additions and 92 deletions
+58 -6
View File
@@ -12,10 +12,12 @@ class ERR_HQUnit
ref ERR_HQReport Assignment;
AIWaypoint Waypoint;
bool ReservedForSupport;
int LogisticsReservation;
ref ERR_MortarSupplyStatus PendingSupplyStatus;
bool Eligible(ERR_GameMode mode)
{
if (ReservedForSupport || !Group || !Utility || Group.GetPlayerCount(true) > 0 || Group.IsSlave() || Group.GetFaction() != mode.EnemyFaction()) return false;
if (ReservedForSupport || LogisticsReservation > 0 || !Group || !Utility || Group.GetPlayerCount(true) > 0 || Group.IsSlave() || Group.GetFaction() != mode.EnemyFaction()) return false;
array<AIAgent> agents = {};
Group.GetAgents(agents);
bool survivor;
@@ -46,6 +48,7 @@ class ERR_HQ : ERR_CommandService
{
protected ERR_GameMode m_Mode;
protected ref ERR_MortarSystem m_Mortars;
protected ref ERR_MortarLogistics m_Logistics;
protected ref array<ref ERR_HQUnit> m_Units = {};
protected ref array<ref ERR_HQReport> m_Contacts = {};
protected ref ERR_HQNetwork m_Network = new ERR_HQNetwork();
@@ -54,7 +57,7 @@ class ERR_HQ : ERR_CommandService
protected float m_NextNetwork;
protected float m_NextAssignment;
void ERR_HQ(ERR_GameMode mode) { m_Mode = mode; m_Mortars = new ERR_MortarSystem(this); }
void ERR_HQ(ERR_GameMode mode) { m_Mode = mode; m_Mortars = new ERR_MortarSystem(this); m_Logistics = new ERR_MortarLogistics(this, mode); }
static ERR_HQ Get()
{
ERR_GameMode mode = ERR_GameMode.Get();
@@ -72,7 +75,8 @@ class ERR_HQ : ERR_CommandService
if (hq) hq.Journal().Write(kind, message, messageId);
}
ERR_MortarSystem Mortars() { return m_Mortars; }
bool PrepareSupport() { return m_Mortars.Prepare(); }
bool PrepareSupport() { return m_Mortars.Prepare() && m_Logistics.Prepare(); }
ERR_MortarLogistics Logistics() { return m_Logistics; }
void ReserveGroup(SCR_AIGroup group)
{
foreach (ERR_HQUnit unit : m_Units)
@@ -82,6 +86,48 @@ class ERR_HQ : ERR_CommandService
unit.ReservedForSupport = true;
}
}
// Temporary reservations never alter the permanent support reservation.
int LogisticsToken(SCR_AIGroup group)
{
foreach (ERR_HQUnit unit : m_Units) if (unit.Group == group) return unit.LogisticsReservation;
return 0;
}
bool ReserveLogistics(SCR_AIGroup group, int token)
{
if (!Replication.IsServer() || token <= 0 || !MissionActive()) return false;
foreach (ERR_HQUnit unit : m_Units)
{
if (unit.Group != group || !unit.Eligible(m_Mode) || !unit.Radio || unit.Assignment || unit.PendingOrder || unit.Downlink || unit.Waypoint) continue;
if (unit.Utility.m_Perception && !unit.Utility.m_Perception.m_aTargets.IsEmpty()) continue;
unit.LogisticsReservation = token;
return true;
}
return false;
}
void ReleaseLogistics(SCR_AIGroup group, int token)
{
foreach (ERR_HQUnit unit : m_Units)
if (unit.Group == group && unit.LogisticsReservation == token) unit.LogisticsReservation = 0;
}
bool QueueSupplyStatus(ERR_MortarBattery battery, float now)
{
if (!Replication.IsServer() || !MissionActive() || !battery || !battery.StartupActivated || !battery.Operational() || !m_Logistics.CanSample(battery) || !ERR_MortarLogisticsRules.Need(battery.CountShells())) return false;
foreach (ERR_HQUnit unit : m_Units)
{
if (unit.Group != battery.Group || unit.Uplink || !unit.Radio || unit.Radio != battery.RadioOperator) continue;
ERR_HQRoute route = m_Network.Route(unit.Radio);
if (!route) return false;
ERR_MortarSupplyStatus report = new ERR_MortarSupplyStatus();
report.Group = battery.Group; report.Gun = battery.Gun; report.Position = battery.Gun.GetOrigin();
report.Shells = battery.CountShells(); report.ObservedAt = now; report.MessageId = m_Journal.Message();
route.MessageId = report.MessageId;
route.Payload = string.Format("mortar supply status; usable HE=%1; position=%2; sampled=%3", report.Shells, report.Position, report.ObservedAt);
unit.PendingSupplyStatus = report; unit.Uplink = route;
m_Journal.Write("SUPPLY REPORT", route.Payload, route.MessageId);
return true;
}
return false;
}
void PhysicalForces(out array<IEntity> entities)
{
entities.Clear();
@@ -131,7 +177,7 @@ class ERR_HQ : ERR_CommandService
ERR_HQJournal Journal() { return m_Journal; }
string Status()
{
return string.Format("HQ: %1 groups, %2 delivered contacts, %3 assignments", m_Units.Count(), m_Contacts.Count(), Assigned()) + "; " + m_Mortars.Status();
return string.Format("HQ: %1 groups, %2 delivered contacts, %3 assignments", m_Units.Count(), m_Contacts.Count(), Assigned()) + "; " + m_Mortars.Status() + "; " + m_Logistics.Status();
}
override void RegisterGroup(SCR_AIGroup group)
@@ -304,8 +350,12 @@ class ERR_HQ : ERR_CommandService
if (unit.Uplink)
{
int delivered = unit.Uplink.Advance(now, m_Journal);
if (delivered == 1) Accept(unit.PendingReport, now);
if (delivered != 0) { unit.Uplink = null; unit.PendingReport = null; }
if (delivered == 1)
{
if (unit.PendingSupplyStatus) m_Logistics.Receive(unit.PendingSupplyStatus, now);
else Accept(unit.PendingReport, now);
}
if (delivered != 0) { unit.Uplink = null; unit.PendingReport = null; unit.PendingSupplyStatus = null; }
}
if (unit.Downlink)
{
@@ -317,12 +367,14 @@ class ERR_HQ : ERR_CommandService
Observe(unit, now);
}
if (now >= m_NextAssignment) { Assign(now); m_NextAssignment = now + 5000; }
m_Logistics.Tick(now);
m_Mortars.Tick(now);
m_Journal.Flush();
}
override void Stop()
{
m_Logistics.Stop();
m_Mortars.Stop();
foreach (ERR_HQUnit unit : m_Units) unit.Release();
m_Units.Clear();