Files
EscapistsReintroduced/docs/evidence/airdrop-frequency-2026-10-09/baseline/ERR_AirSupportPolicy.c
T
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

86 lines
3.0 KiB
C

// Decisions consume detached HQ memory and delivered friendly check-ins only.
class ERR_AirSupportSituation
{
int BeliefId;
int Samples;
int Spotted;
int GroundFit;
int CommittedFit;
int ConfirmedLosses;
float Age;
float Confidence;
float Radius;
float Speed;
bool MotionKnown;
bool Infantry;
bool AircraftReady;
bool ArtilleryBusy;
}
class ERR_AirSupportPolicy
{
int Candidate;
float ConsideringSince = -1;
float NextDrop;
string Reason = "waiting for delivered intelligence";
static string Refusal(ERR_AirSupportSituation s, bool checkAirspace = true)
{
if (!s || !s.AircraftReady) return "no ready helicopter passenger load";
if (!ERR_HQMemoryRules.Finite(s.Age) || !ERR_HQMemoryRules.Finite(s.Confidence) || !ERR_HQMemoryRules.Finite(s.Radius) || !ERR_HQMemoryRules.Finite(s.Speed)) return "invalid memory sample";
if (s.BeliefId <= 0 || s.Samples < 2 || s.Age < 0 || s.Age > 90 || s.Confidence < 0.7 || s.Confidence > 1 || s.Radius < 0 || s.Radius > 160) return "memory is too uncertain; continue reconnaissance";
if (!s.Infantry || !s.MotionKnown || s.Speed < 0 || s.Speed > 6) return "target movement does not justify an infantry drop";
int needed = Math.Clamp(s.Spotted * 2, 4, 12);
if (s.CommittedFit >= needed) return "ground forces already committed in sufficient strength";
if (s.GroundFit + s.CommittedFit >= needed && s.ConfirmedLosses < 2) return "nearby ground forces can handle this contact";
if (checkAirspace && s.ArtilleryBusy) return "mortar order or shells occupy the approach area";
return "";
}
bool Consider(ERR_AirSupportSituation s, float now)
{
if (!ERR_HQMemoryRules.Finite(now) || now < 0) return false;
// Artillery temporarily closes the approach; it does not invalidate fresh
// contact history or the confirmed lack of ground support. Restarting the
// timer on every salvo could prevent a drop through every clear interval.
string refusal = Refusal(s, false);
if (!refusal.IsEmpty()) { Candidate = 0;
ConsideringSince = -1;
Reason = refusal;
return false;
}
if (now < NextDrop) { Reason = "reinforcement cooldown; retain remaining troops";
return false;
}
if (Candidate != s.BeliefId || ConsideringSince < 0) { Candidate = s.BeliefId;
ConsideringSince = now;
}
if (s.ArtilleryBusy) { Reason = Refusal(s);
return false;
}
float delay = 45000;
if (s.ConfirmedLosses >= 2) delay = 20000;
if (now - ConsideringSince < delay) { Reason = "confirming persistent contact and ground-force shortfall";
return false;
}
Reason = "persistent infantry contact exceeds available ground response";
return true;
}
void Committed(float now) { NextDrop = now + 480000;
Candidate = 0;
ConsideringSince = -1;
}
void Retry(float now) { NextDrop = Math.Max(NextDrop, now + 15000);
Candidate = 0;
ConsideringSince = -1;
}
}
// One immutable authorization; receiver revalidates memory and physical safety.
class ERR_AirDropOrder
{
int BeliefId;
int BeliefRevision;
int MessageId;
vector Target;
float ExpiresAt;
ref ERR_HQReport Report;
}