Integrate radio-delivered convoy cover and conservative squad ammunition reports

This commit is contained in:
2026-09-20 04:23:11 +02:00
parent 9b6596eb3e
commit 9205e2129a
88 changed files with 13934 additions and 28 deletions
+36 -1
View File
@@ -112,6 +112,7 @@ class ERR_ConvoyVehicle
int RouteIndex;
bool Released;
bool Registered;
ref ERR_ConvoyCombatState Combat = new ERR_ConvoyCombatState();
bool Arrived;
float LegDeadline;
float NextReadinessNote;
@@ -126,6 +127,7 @@ class ERR_ConvoyVehicle
{
if (Released) return;
Released = true;
Combat.Held = false;
ClearOrder();
if (mode && mode.Forces())
{
@@ -151,7 +153,7 @@ class ERR_ConvoyVehicle
}
bool Order(ERR_ForceRoute route, float now)
{
if (Released || Arrived || !Group || !Entity || !route || RouteIndex >= route.Count()) return false;
if (Released || Arrived || Combat.Held || !Group || !Entity || !route || RouteIndex >= route.Count()) return false;
if (Waypoint) return true;
Waypoint = AIWaypoint.Cast(ERR_Actors.Spawn(ERR_Resources.MoveWaypoint(), route.At(RouteIndex)));
if (!Waypoint) return false;
@@ -164,6 +166,7 @@ class ERR_ConvoyVehicle
{
if (Released || Arrived) return;
if (!CrewValid(mode)) { Release(mode); return; }
if (Combat.Held) return;
// Native completion measures the seated group, not the vehicle origin.
// Keep the same predicate after native removal of the completed waypoint.
if (Waypoint && Waypoint.IsWithinCompletionRadius(Group))
@@ -344,6 +347,9 @@ class ERR_ConvoyService
m_Mode.RegisterGroup(unit.Group);
ERR_HQ hq = ERR_HQ.Cast(m_Mode.Command());
if (hq) hq.ReserveGroup(unit.Group);
// Native helper idempotently registers deletion/damage callbacks and mounted
// combat activity; raw vehicle-manager admission alone omits those hooks.
utility.AddUsableVehicle(usage);
unit.Group.SetPermanentLOD(0); unit.Group.ActivateAI();
foreach (AIAgent active : agents) { active.SetPermanentLOD(0); active.ActivateAI(); }
}
@@ -389,6 +395,35 @@ class ERR_ConvoyService
if (!pending) task.Stop(m_Mode, "finite authored road route ended or all vehicle orders released");
}
}
bool ApplyCombatOrder(ERR_ConvoyTask task, ERR_ConvoyCombatOrder order, float now)
{
if (!Current() || !task || !order || !m_Tasks.Contains(task) || task.Stopped || !task.Ready || !task.Receipt || !task.Receipt.Consumed) return false;
if (order.VehicleIndex < 0 || order.VehicleIndex >= task.Vehicles.Count() || order.SourceId != task.Receipt.SourceId) return false;
ERR_ConvoyVehicle unit = task.Vehicles[order.VehicleIndex];
if (!unit || !unit.Registered || unit.Released || unit.Arrived || unit.Index != order.VehicleIndex || unit.Group != order.Group || !unit.CrewValid(m_Mode)) return false;
if (ERR_ConvoyRules.Captured(unit.Entity, unit.Group) || unit.Index >= task.Receipt.Records.Count()) return false;
if (!ERR_ConvoyCombatRules.Accept(unit.Combat, order, now) || !task.Route || unit.RouteIndex >= task.Route.Count()) return false;
ERR_ForceRecord record = m_Mode.Forces().FindGroup(unit.Group);
if (!record || !record.Physical || record.Eliminated || record.Kind != ERR_ForceKind.CONVOY || record.Id != task.Receipt.Records[unit.Index]) return false;
array<AIAgent> agents = {}; unit.Group.GetAgents(agents);
if (agents.Count() != unit.Members.Count()) return false;
foreach (AIAgent agent : agents)
if (!agent || !unit.Members.Contains(agent.GetControlledEntity())) return false;
// No caller can replay even a command whose native waypoint recreation fails.
unit.Combat.LastCommandId = order.CommandId;
if (order.Hold)
{
if (!unit.Combat.Held) unit.ClearOrder();
unit.Combat.Held = true; unit.Combat.ReportId = order.ReportId; unit.Combat.ObservedAt = order.ObservedAt;
}
else
{
unit.Combat.Held = false;
if (!unit.Order(task.Route, now)) { unit.Release(m_Mode); return false; }
}
ERR_HQ.Event("CONVOY COVER", string.Format("command M%1 report M%2 vehicle=%3 held=%4 routeIndex=%5", order.CommandId, order.ReportId, unit.Index, unit.Combat.Held, unit.RouteIndex));
return true;
}
int Count() { return m_Tasks.Count(); }
string Status()
{