Validate independent packed addons and complete physical mortar salvos
This commit is contained in:
@@ -7,6 +7,7 @@ class ERR_MortarSystem
|
||||
protected bool m_Prepared;
|
||||
protected bool m_Stopped;
|
||||
protected float m_NextDecision;
|
||||
protected float m_NextRefreshDecision;
|
||||
string SafetyReason;
|
||||
string SettlementReason;
|
||||
|
||||
@@ -89,6 +90,13 @@ class ERR_MortarSystem
|
||||
if (!battery.Report) return "no delivered target report";
|
||||
return "delivered target report expired or invalid";
|
||||
}
|
||||
// Classify only after SupplyState has observed any accepted inventory move.
|
||||
// Report expiry must not be mislabeled as physical ammunition depletion.
|
||||
string SupplyFailure(ERR_MortarBattery battery, float now)
|
||||
{
|
||||
if (!Latest(battery, now)) return ContactFailure(battery);
|
||||
return "next native load lacks confirmed physical gunner ammunition";
|
||||
}
|
||||
bool OutsideSettlements(vector impact)
|
||||
{
|
||||
bool clear = m_Settlements.OutsideSettlements(impact);
|
||||
@@ -134,13 +142,15 @@ class ERR_MortarSystem
|
||||
float now = GetGame().GetWorld().GetWorldTime();
|
||||
if (m_Stopped || !ERR_HQ.MissionActive()) return Withhold(battery, "mission inactive or HQ stopped");
|
||||
if (!battery.Operational()) return Withhold(battery, battery.OperationalReason());
|
||||
if (battery.RefreshRejected) return Withhold(battery, "target update failed; order awaiting cancellation");
|
||||
if (!battery.CommandOpen || battery.OrderShots >= ERR_MortarSalvo.ROUNDS) return Withhold(battery, "salvo complete or order closed");
|
||||
if (battery.Released) return Withhold(battery, "waiting for committed projectile");
|
||||
if (battery.AimedShot != battery.OrderShots || battery.AimedAt < 0 || now < battery.AimedAt) return Withhold(battery, "fresh aim solution required");
|
||||
ERR_HQReport report = Latest(battery, now);
|
||||
if (!report) return Withhold(battery, ContactFailure(battery));
|
||||
if (!battery.AimSolution || !battery.AimSolution.Matches(battery, report)) return Withhold(battery, "aim command does not match delivered order");
|
||||
if (now - battery.AimedAt > 10000)
|
||||
if (battery.AimValidatedAt < battery.AimedAt || now < battery.AimValidatedAt) return Withhold(battery, "aim validation timestamp invalid");
|
||||
if (now - battery.AimValidatedAt > 10000)
|
||||
{
|
||||
if (!battery.AimSolver) return Withhold(battery, "original native aim solver no longer available");
|
||||
if (!battery.AimSolver.ERR_RevalidateAim(battery, this, report, now)) return false;
|
||||
@@ -190,12 +200,84 @@ class ERR_MortarSystem
|
||||
battery.Order(ready, now);
|
||||
}
|
||||
|
||||
protected void AdvanceRefresh(ERR_MortarBattery battery, float now)
|
||||
{
|
||||
ERR_MortarRefresh update = battery.Refresh;
|
||||
if (!update) return;
|
||||
// A stale transaction must not cancel or modify a later order.
|
||||
if (update.OrderId != battery.OrderId || !battery.CommandOpen)
|
||||
{
|
||||
battery.Refresh = null;
|
||||
return;
|
||||
}
|
||||
if (!update.Owns(battery) || !battery.Operational() || !battery.Activity || !ERR_MortarRefreshRules.Newer(battery.Report, update.Report, now))
|
||||
{
|
||||
battery.RejectRefresh("target update ownership, observation freshness or activity changed");
|
||||
return;
|
||||
}
|
||||
if (update.Route)
|
||||
{
|
||||
int state = update.Route.Advance(now, m_HQ.Journal());
|
||||
if (state == 0) return;
|
||||
if (state < 0)
|
||||
{
|
||||
battery.RejectRefresh("new target observation failed physical HQ radio delivery");
|
||||
return;
|
||||
}
|
||||
update.Route = null;
|
||||
}
|
||||
// The original committed shell owns its report, geometry and airspace until
|
||||
// native OnWeaponFired confirms it. A delivered update cannot relabel it.
|
||||
if (battery.Released) return;
|
||||
if (battery.AimSolution)
|
||||
{
|
||||
if (!battery.AimSolver || !battery.AimSolver.ERR_AdoptReport(battery, this, update.Report, now))
|
||||
{
|
||||
battery.RejectRefresh("delivered update cannot preserve the original native aim command");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No barrel command exists for the next shell yet. Its normal native aim
|
||||
// node must solve this report; receiving it is not an aim authorization.
|
||||
battery.Report = update.Report;
|
||||
}
|
||||
battery.Audit("UPDATE RECEIVED", string.Format("same order; update radio=M%1 accepted observation=M%2 observed=%3; shots=%4 original aim time=%5", update.RadioId, update.Report.MessageId, update.Report.ObservedAt, battery.OrderShots, battery.AimedAt));
|
||||
battery.Refresh = null;
|
||||
}
|
||||
|
||||
protected void QueueRefreshes(float now)
|
||||
{
|
||||
if (now < m_NextRefreshDecision) return;
|
||||
m_NextRefreshDecision = now + 5000;
|
||||
array<ref ERR_HQReport> reports = {};
|
||||
m_HQ.SupportContacts(reports, now);
|
||||
foreach (ERR_MortarBattery battery : m_Batteries)
|
||||
{
|
||||
ERR_HQReport newest;
|
||||
foreach (ERR_HQReport report : reports)
|
||||
{
|
||||
if (!battery.CanRefresh(report, now)) continue;
|
||||
if (!newest || report.ObservedAt > newest.ObservedAt) newest = report;
|
||||
}
|
||||
if (!newest) continue;
|
||||
ERR_HQRoute route = m_HQ.Downlink(battery.Group, "MORTAR UPDATE", newest.Description(now), newest.MessageId);
|
||||
if (!route)
|
||||
{
|
||||
battery.RejectRefresh("HQ has a newer observation but no physical downlink to the active battery");
|
||||
continue;
|
||||
}
|
||||
battery.BeginRefresh(newest, route, now);
|
||||
}
|
||||
}
|
||||
|
||||
void Tick(float now)
|
||||
{
|
||||
if (m_Stopped || !Replication.IsServer()) return;
|
||||
foreach (ERR_MortarBattery battery : m_Batteries)
|
||||
{
|
||||
if (battery.Rejected && !battery.Released)
|
||||
if ((battery.Rejected || battery.RefreshRejected) && !battery.Released)
|
||||
{
|
||||
battery.Cancel("native aim or firing authorization rejected");
|
||||
battery.NextOrder = now + 10000;
|
||||
@@ -203,7 +285,9 @@ class ERR_MortarSystem
|
||||
battery.Rejected = false;
|
||||
battery.Update(now);
|
||||
AdvanceOrder(battery, now);
|
||||
AdvanceRefresh(battery, now);
|
||||
}
|
||||
QueueRefreshes(now);
|
||||
if (now < m_NextDecision) return;
|
||||
m_NextDecision = now + 10000;
|
||||
array<ref ERR_HQReport> reports = {};
|
||||
|
||||
Reference in New Issue
Block a user