Files
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

82 lines
3.8 KiB
C

// Mission-owned finite attempt history. Registration and assignment release
// never reset it. Values are copied before native work; no live enemy queries.
class ERR_EngineerMinePost
{
ref ERR_ForceRecord Record;
SCR_AIGroup Group;
string Source;
int Strength;
ref ERR_HQTask Task;
ref ERR_HQReport Assignment;
int MessageId;
int BeliefId;
int Revision;
float QueuedAt;
float ObservedAt;
vector Post;
bool HasSite;
vector Site;
}
class ERR_EngineerMinePosts
{
protected ref array<ref ERR_EngineerMinePost> m_Posts = {};
int Count() { return m_Posts.Count(); }
bool Eligible(ERR_ForceRecord record, string source, ERR_HQTask task, ERR_HQReport assignment, float now)
{
if (!record || !record.Group || !record.Physical || record.Eliminated || source.IsEmpty() || record.SourceId != source) return false;
if (record.InitialStrength < 1 || record.InitialStrength > 32 || !task || !assignment || m_Posts.Count() >= 32) return false;
if (!task.RoadIntercept || task.ReleaseOnly || task.Investigation() || !task.SecuritySite.IsEmpty()) return false;
if (task.BeliefId <= 0 || task.BeliefRevision <= 0 || assignment.MessageId <= 0) return false;
if (!ERR_ForceRules.Finite(now) || !ERR_ForceRules.Finite(task.QueuedAt) || !ERR_ForceRules.Finite(task.ExpiresAt)
|| !ERR_ForceRules.Finite(assignment.ObservedAt) || assignment.ObservedAt < 0 || task.QueuedAt < assignment.ObservedAt
|| task.QueuedAt > now || now >= task.ExpiresAt) return false;
if (!ERR_ForceRules.FiniteVector(task.Destination) || !ERR_ForceRules.FiniteVector(assignment.Position)) return false;
int used;
foreach (ERR_EngineerMinePost previous : m_Posts)
{
if (!previous) return false;
float separation = vector.DistanceXZ(task.Destination, previous.Post);
if (!ERR_ForceRules.Finite(separation) || separation <= 160) return false;
if (previous.Task == task || previous.Assignment == assignment) return false;
// Same source or physical group under another record cannot acquire quota.
if (previous.Record != record)
{
if (previous.Source == source || previous.Group == record.Group) return false;
continue;
}
if (previous.Source != source || previous.Group != record.Group || previous.Strength != record.InitialStrength) return false;
used++;
if (used >= 5 || task.QueuedAt <= previous.QueuedAt || assignment.ObservedAt <= previous.ObservedAt
|| assignment.MessageId == previous.MessageId) return false;
if (task.BeliefId == previous.BeliefId && task.BeliefRevision <= previous.Revision) return false;
}
return true;
}
// Returns immutable entry index or -1; a refused site/item still consumes it.
int Consume(ERR_ForceRecord record, string source, ERR_HQTask task, ERR_HQReport assignment, float now)
{
if (!Eligible(record, source, task, assignment, now)) return -1;
ERR_EngineerMinePost entry = new ERR_EngineerMinePost();
entry.Record = record; entry.Group = record.Group; entry.Source = source; entry.Strength = record.InitialStrength;
entry.Task = task; entry.Assignment = assignment; entry.MessageId = assignment.MessageId;
entry.BeliefId = task.BeliefId; entry.Revision = task.BeliefRevision;
entry.QueuedAt = task.QueuedAt; entry.ObservedAt = assignment.ObservedAt; entry.Post = task.Destination;
m_Posts.Insert(entry);
return m_Posts.Count() - 1;
}
bool RecordSite(int index, vector site)
{
if (index < 0 || index >= m_Posts.Count() || !ERR_ForceRules.FiniteVector(site)) return false;
ERR_EngineerMinePost entry = m_Posts[index];
if (!entry || entry.HasSite || !ERR_EngineerMineSite.InBand(entry.Post, site)) return false;
entry.Site = site; entry.HasSite = true;
return true;
}
void PriorSites(out array<vector> sites)
{
sites.Clear();
foreach (ERR_EngineerMinePost entry : m_Posts)
if (entry.HasSite) sites.Insert(entry.Site);
}
}