Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
86 lines
3.0 KiB
C
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;
|
|
}
|