// Local own-roster sampling schedule only. Urgency requests an ordinary status // frame; it grants no HQ knowledge and never changes ammunition or assignments. class ERR_HQAmmoReporting { protected float m_NextScan = -1; protected float m_NextCall = 0; protected float m_LastAttempt = -1; void Initialize(int sourceId, float now) { if (m_NextScan >= 0 || sourceId <= 0 || !ERR_HQPursuitRules.Finite(now) || now < 0) return; int phase = sourceId % 6; m_NextScan = now + phase * 5000; } bool ScanDue(float now) { return m_NextScan >= 0 && ERR_HQPursuitRules.Finite(now) && now >= m_NextScan; } // An unavailable route also consumes this local attempt. Routine/requested // check-ins retain their independent existing retry and deadline semantics. void Scanned(float now) { if (!ERR_HQPursuitRules.Finite(now) || now < 0 || now < m_LastAttempt) return; m_LastAttempt = now; m_NextScan = now + 30000; } bool Urgent(ERR_HQStatusReport report, float now) { if (!report || !report.AmmoState || !ERR_HQPursuitRules.Finite(now) || now < 0 || now < m_NextCall || report.ObservedAt != now) return false; ERR_HQAmmoSnapshot stock = report.AmmoState; if (!stock.Complete || !stock.Valid(report.Count) || stock.Members <= 0 || stock.SmallArmsMuzzles <= 0) return false; // Chambers are usable rounds too. Launchers never substitute for small arms. return stock.SmallArmsRounds + stock.SmallArmsChambers <= 30 * stock.Members; } // Any queued status already reports current stock. Persistent low ammunition // can ask again after one minute, even when the previous route was interrupted. void Queued(float now) { if (!ERR_HQPursuitRules.Finite(now) || now < 0 || now < m_LastAttempt) return; m_NextCall = now + 60000; } }