Integrate radio-delivered convoy cover and conservative squad ammunition reports
This commit is contained in:
@@ -28,6 +28,7 @@ class ERR_HQUnit
|
||||
bool ReservedForSupport;
|
||||
int LogisticsReservation;
|
||||
ref ERR_MortarSupplyStatus PendingSupplyStatus;
|
||||
ref ERR_ConvoyCombatOrder PendingConvoyOrder;
|
||||
|
||||
bool Eligible(ERR_GameMode mode)
|
||||
{
|
||||
@@ -47,6 +48,7 @@ class ERR_HQUnit
|
||||
void CancelPending()
|
||||
{
|
||||
PendingOrder = null;
|
||||
PendingConvoyOrder = null;
|
||||
PendingCheckin = false;
|
||||
PendingTask = null;
|
||||
Downlink = null;
|
||||
@@ -429,6 +431,9 @@ class ERR_HQ : ERR_CommandService
|
||||
if (!report) return;
|
||||
route.MessageId = report.MessageId;
|
||||
route.Payload = string.Format("status %1: %2 living, %3 fit, %4 confirmed losses; sampled=%5", report.SourceId, report.Count, report.Fit, report.ConfirmedLosses, report.ObservedAt);
|
||||
string ammunition = "unknown";
|
||||
if (report.AmmoState && report.AmmoState.Complete) ammunition = string.Format("%1 magazine rounds, %2 chambered", report.AmmoState.SmallArmsRounds, report.AmmoState.SmallArmsChambers);
|
||||
route.Payload += "; small-arms ammunition=" + ammunition;
|
||||
unit.PendingStatus = report; unit.Uplink = route; unit.NextStatus = now + 180000;
|
||||
m_Journal.Write("STATUS REPORT", route.Payload, route.MessageId);
|
||||
}
|
||||
@@ -514,6 +519,7 @@ class ERR_HQ : ERR_CommandService
|
||||
foreach (ERR_HQUnit unit : m_Units)
|
||||
{
|
||||
if (unit.ForceSourceId == entry.SourceId || !unit.Radio || !unit.PlanEligible || unit.PlanFighting || unit.Assignment || unit.PendingOrder || unit.Downlink) continue;
|
||||
if (m_Watch.ArmedSearchBlocked(unit.ForceSourceId, now)) continue;
|
||||
if (unit.HomeGuard && HomeAvailable(unit) <= 1) continue;
|
||||
if (!ERR_HQPursuitRules.BearingAllowed(ERR_HQPursuitRules.Bearing(unit.PlanPosition, entry.Position), first, second)) continue;
|
||||
float candidate = vector.DistanceXZ(unit.PlanPosition, entry.Position);
|
||||
@@ -610,6 +616,7 @@ class ERR_HQ : ERR_CommandService
|
||||
else unit.CancelPending();
|
||||
return;
|
||||
}
|
||||
if (m_Watch.ArmedSearchBlocked(unit.ForceSourceId, now)) { LostOrder(unit, now); return; }
|
||||
if (task.Investigation())
|
||||
{
|
||||
if (!WatchTaskValid(task)) { LostOrder(unit, now); return; }
|
||||
@@ -718,7 +725,8 @@ class ERR_HQ : ERR_CommandService
|
||||
{
|
||||
foreach (ERR_HQUnit unit : m_Units)
|
||||
{
|
||||
if (!unit.Assignment || !unit.Task || unit.Task.Investigation() || unit.PendingOrder || !unit.Radio || unit.PlanFighting || !unit.PlanEligible) continue;
|
||||
if (!unit.Assignment || !unit.Task || unit.Task.Investigation() || unit.PendingOrder || unit.Downlink || !unit.Radio || unit.PlanFighting || !unit.PlanEligible) continue;
|
||||
if (m_Watch.ArmedSearchBlocked(unit.ForceSourceId, now)) continue;
|
||||
ERR_HQBelief belief = m_Memory.GetById(unit.Task.BeliefId);
|
||||
if (!belief || belief.BeliefRevision == unit.Task.BeliefRevision || now - belief.ObservedAt > 45000) continue;
|
||||
// Nearby updates refine memory without churning native movement orders.
|
||||
@@ -753,6 +761,85 @@ class ERR_HQ : ERR_CommandService
|
||||
if (hunt) hunt.NextHunt = Math.Max(hunt.NextHunt, task.ExpiresAt + 180000);
|
||||
}
|
||||
}
|
||||
// Convoy planning reads delivered own-position status and delivered sightings.
|
||||
// A silent convoy keeps its last order; no target or vehicle position is queried.
|
||||
protected bool ConvoyPositionKnown(ERR_HQUnit unit, float now)
|
||||
{
|
||||
ERR_HQWatchEntry entry = m_Watch.Find(unit.ForceSourceId);
|
||||
return entry && !entry.Closed && entry.Count > 0 && entry.ObservedAt >= 0
|
||||
&& ERR_HQPursuitRules.Finite(now) && now >= entry.ObservedAt
|
||||
&& now - entry.ObservedAt <= 180000;
|
||||
}
|
||||
protected ERR_HQReport ConvoyContact(ERR_HQUnit unit, float now)
|
||||
{
|
||||
if (!ConvoyPositionKnown(unit, now)) return null;
|
||||
ERR_HQWatchEntry entry = m_Watch.Find(unit.ForceSourceId);
|
||||
ERR_HQReport best;
|
||||
foreach (ERR_HQReport report : m_Contacts)
|
||||
{
|
||||
if (report.ObservedAt < 0 || now < report.ObservedAt || now - report.ObservedAt >= 60000
|
||||
|| vector.DistanceXZ(entry.Position, report.Position) > 400) continue;
|
||||
if (!best || report.ObservedAt > best.ObservedAt
|
||||
|| (report.ObservedAt == best.ObservedAt && report.MessageId > best.MessageId)) best = report;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
protected void PlanConvoy(float now)
|
||||
{
|
||||
if (!m_ConvoyTask || m_ConvoyTask.Stopped || !m_ConvoyTask.Ready) return;
|
||||
foreach (ERR_ConvoyVehicle vehicle : m_ConvoyTask.Vehicles)
|
||||
{
|
||||
if (vehicle.Released || vehicle.Arrived || !vehicle.Registered || !vehicle.Group) continue;
|
||||
foreach (ERR_HQUnit unit : m_Units)
|
||||
{
|
||||
if (unit.Group != vehicle.Group || !unit.ReservedForSupport || unit.Downlink || !unit.Radio) continue;
|
||||
if (!ConvoyPositionKnown(unit, now)) break;
|
||||
ERR_HQReport contact = ConvoyContact(unit, now);
|
||||
if (contact)
|
||||
{
|
||||
if (vehicle.Combat.Held && contact.MessageId == vehicle.Combat.ReportId) break;
|
||||
if (contact.ObservedAt < vehicle.Combat.ObservedAt) break;
|
||||
}
|
||||
else if (!vehicle.Combat.Held || now - vehicle.Combat.ObservedAt < 60000) break;
|
||||
ERR_HQRoute route = m_Network.Route(unit.Radio, true);
|
||||
if (!route) break;
|
||||
ERR_ConvoyCombatOrder order = new ERR_ConvoyCombatOrder();
|
||||
order.CommandId = m_Journal.Message(); order.SourceId = m_ConvoyTask.Receipt.SourceId;
|
||||
order.VehicleIndex = vehicle.Index; order.Group = unit.Group;
|
||||
order.Hold = contact != null; order.IssuedAt = now; order.ExpiresAt = now + 30000;
|
||||
order.ReportId = vehicle.Combat.ReportId; order.ObservedAt = vehicle.Combat.ObservedAt;
|
||||
string action = "resume authored route";
|
||||
if (contact)
|
||||
{
|
||||
order.ReportId = contact.MessageId; order.ObservedAt = contact.ObservedAt;
|
||||
action = "suspend travel for mounted cover";
|
||||
}
|
||||
route.MessageId = order.CommandId;
|
||||
route.Payload = string.Format("convoy vehicle %1: %2; delivered sighting M%3", vehicle.Index, action, order.ReportId);
|
||||
unit.PendingConvoyOrder = order; unit.Downlink = route;
|
||||
m_Journal.Write("CONVOY ORDER QUEUED", route.Payload, route.MessageId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void DeliverConvoyOrder(ERR_HQUnit unit, float now)
|
||||
{
|
||||
ERR_ConvoyCombatOrder order = unit.PendingConvoyOrder;
|
||||
bool accepted;
|
||||
if (order && order.Group == unit.Group && ConvoyPositionKnown(unit, now))
|
||||
{
|
||||
ERR_HQReport contact = ConvoyContact(unit, now);
|
||||
// A newer nearby sighting still justifies HOLD: frequent reports must not
|
||||
// starve a slower radio downlink. New threat evidence always invalidates RESUME.
|
||||
bool current = !order.Hold && !contact;
|
||||
if (order.Hold && contact) current = contact.ObservedAt >= order.ObservedAt;
|
||||
if (current) accepted = m_Convoys.ApplyCombatOrder(m_ConvoyTask, order, now);
|
||||
}
|
||||
if (accepted) m_Journal.Write("CONVOY ORDER DELIVERED", "original crew applied radio travel command", order.CommandId);
|
||||
else if (order) m_Journal.Write("CONVOY ORDER REJECTED", "stale evidence or unavailable original crew; current order retained", order.CommandId);
|
||||
unit.CancelPending();
|
||||
}
|
||||
|
||||
protected void Assign(float now)
|
||||
{
|
||||
int globalLimit = m_Watch.SquadLimit(m_Mode.Settings().Get("supportSquadLimit"));
|
||||
@@ -832,6 +919,7 @@ class ERR_HQ : ERR_CommandService
|
||||
int bestBearing = -1;
|
||||
foreach (ERR_HQUnit unit : m_Units)
|
||||
{
|
||||
if (m_Watch.ArmedSearchBlocked(unit.ForceSourceId, now)) continue;
|
||||
bool busy = unit.Assignment || unit.PendingOrder || unit.Downlink || unit.PlanFighting;
|
||||
if (!unit.Radio || !ERR_HQPursuitRules.CanCommit(unit.Group != null, unit.PlanEligible, busy, unit.HomeGuard, HomeAvailable(unit), assigned, limit)) continue;
|
||||
vector position = unit.PlanPosition;
|
||||
@@ -895,7 +983,8 @@ class ERR_HQ : ERR_CommandService
|
||||
int delivered = unit.Downlink.Advance(now, m_Journal);
|
||||
if (delivered == 1)
|
||||
{
|
||||
if (unit.PendingCheckin) { unit.NextStatus = now; unit.CancelPending(); }
|
||||
if (unit.PendingConvoyOrder) DeliverConvoyOrder(unit, now);
|
||||
else if (unit.PendingCheckin) { unit.NextStatus = now; unit.CancelPending(); }
|
||||
else DeliverOrder(unit, now);
|
||||
}
|
||||
else if (delivered < 0) LostOrder(unit, now);
|
||||
@@ -903,7 +992,7 @@ class ERR_HQ : ERR_CommandService
|
||||
if (!unit.Group && !unit.Uplink) { ReleaseUnit(unit, now); m_Units.Remove(i); continue; }
|
||||
QueueReports(unit, now);
|
||||
}
|
||||
if (now >= m_NextAssignment) { Assign(now); m_NextAssignment = now + 5000; }
|
||||
if (now >= m_NextAssignment) { PlanConvoy(now); Assign(now); m_NextAssignment = now + 5000; }
|
||||
m_Logistics.Tick(now);
|
||||
m_Mortars.Tick(now);
|
||||
m_Journal.Flush();
|
||||
|
||||
Reference in New Issue
Block a user