Capture current mission, AI, map and administration development

Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
2026-10-13 22:52:53 +02:00
parent a951a96edc
commit 6a667d8deb
8104 changed files with 2124945 additions and 2061 deletions
@@ -0,0 +1,105 @@
--- a/addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c
+++ b/addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c
@@ -1,6 +1,39 @@
// Decisions consumed by the finite original-item controller below.
class ERR_EngineerMineRules
{
+ // Straight XZ corridors are conservative local checks, not native route proofs.
+ static bool CorridorClear(vector start, vector end, array<vector> priorSites)
+ {
+ if (!ERR_ForceRules.FiniteVector(start) || !ERR_ForceRules.FiniteVector(end)) return false;
+ if (!priorSites) return true;
+ if (priorSites.Count() > 32) return false;
+ float dx = end[0] - start[0], dz = end[2] - start[2];
+ float squared = dx * dx + dz * dz;
+ if (!ERR_ForceRules.Finite(squared)) return false;
+ foreach (vector site : priorSites)
+ {
+ if (!ERR_ForceRules.FiniteVector(site)) return false;
+ float along = 0;
+ if (squared > 0)
+ {
+ float projection = (site[0] - start[0]) * dx + (site[2] - start[2]) * dz;
+ if (!ERR_ForceRules.Finite(projection)) return false;
+ along = projection / squared;
+ if (!ERR_ForceRules.Finite(along)) return false;
+ along = Math.Clamp(along, 0, 1);
+ }
+ float x = start[0] + along * dx - site[0], z = start[2] + along * dz - site[2];
+ float clearance = x * x + z * z;
+ if (!ERR_ForceRules.Finite(clearance) || clearance <= 400) return false;
+ }
+ return true;
+ }
+ static bool WithinWorkArea(vector post, vector actor)
+ {
+ if (!ERR_ForceRules.FiniteVector(post) || !ERR_ForceRules.FiniteVector(actor)) return false;
+ float distance = vector.DistanceXZ(post, actor);
+ return ERR_ForceRules.Finite(distance) && distance <= 60;
+ }
static bool Within(float started, float previous, float now)
{
return ERR_ForceRules.Finite(started) && ERR_ForceRules.Finite(previous) && ERR_ForceRules.Finite(now)
@@ -56,6 +89,7 @@
protected ref ERR_EngineerMineRemoval m_Removal;
protected ref array<IEntity> m_Attempted;
protected ref array<IEntity> m_IntelFolders = {};
+ protected ref array<vector> m_PriorSites = {};
protected vector m_Position;
protected vector m_Rally;
protected float m_Started = -1;
@@ -70,6 +104,14 @@
void ERR_EngineerMine(array<IEntity> attempted) { m_Attempted = attempted; }
bool Finished() { return m_Stopped || m_State == 4; }
+ bool BlocksNextPost(ERR_ForceRecord record)
+ {
+ if (!record || record != m_Record) return false;
+ if (m_Begun && !Finished()) return true;
+ // A late terminal callback or exact deletion settles only the old job.
+ // Destroyed but surviving items and uncertain native refusals remain pinned.
+ return m_Removal && !m_Removal.Result && m_Mine;
+ }
protected bool Refuse() { Stop(); return false; }
protected bool Quiet()
{
@@ -90,6 +132,11 @@
if (m_Record.SourceId != m_SourceId || m_Unit.ForceSourceId != m_SourceId || m_Record.InitialStrength != m_Strength) return false;
if (!m_Unit.StatusSampler.OwnsRoster(m_Group) || m_Unit.StatusSampler.InitialStrength() != m_Strength) return false;
if (!m_Actor || !ERR_Actors.CanFight(m_Actor) || ERR_Actors.Player(m_Actor) || CompartmentAccessComponent.GetVehicleIn(m_Actor)) return false;
+ vector actorPosition = m_Actor.GetOrigin();
+ if (!ERR_EngineerMineRules.WithinWorkArea(m_Rally, actorPosition) || !ERR_EngineerMineRules.WithinWorkArea(m_Rally, m_Position)) return false;
+ if (!ERR_EngineerMineRules.CorridorClear(actorPosition, actorPosition, m_PriorSites)
+ || !ERR_EngineerMineRules.CorridorClear(m_Position, m_Position, m_PriorSites)
+ || !ERR_EngineerMineRules.CorridorClear(m_Rally, m_Rally, m_PriorSites)) return false;
if (!m_Unit.StatusSampler.CanAttribute(m_Slot, m_Actor, false) || ERR_Actors.Group(m_Actor) != m_Group) return false;
if (SCR_FactionManager.SGetFaction(m_Actor) != m_Mode.EnemyFaction()) return false;
SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(SCR_AIUtils.GetAIAgent(m_Actor));
@@ -190,7 +237,7 @@
}
return false;
}
- bool Begin(ERR_GameMode mode, ERR_HQUnit unit, ERR_HQTask task, vector minePosition, float now)
+ bool Begin(ERR_GameMode mode, ERR_HQUnit unit, ERR_HQTask task, vector minePosition, float now, array<vector> priorSites = null)
{
if (m_Begun || m_Stopped) return false;
m_Begun = true;
@@ -203,7 +250,18 @@
m_Position = minePosition; m_Rally = task.Destination;
float distance = vector.DistanceXZ(m_Position, m_Rally);
if (!ERR_ForceRules.FiniteVector(m_Rally) || distance < 25 || distance > 60 || now >= task.ExpiresAt) return Refuse();
+ if (priorSites)
+ {
+ if (priorSites.Count() > 32) return Refuse();
+ foreach (vector prior : priorSites)
+ {
+ if (!ERR_ForceRules.FiniteVector(prior)) return Refuse();
+ m_PriorSites.Insert(prior);
+ }
+ }
if (!SelectActor() || !Owned() || !Quiet()) return Refuse();
+ if (!ERR_EngineerMineRules.CorridorClear(m_Actor.GetOrigin(), m_Position, m_PriorSites)
+ || !ERR_EngineerMineRules.CorridorClear(m_Position, m_Rally, m_PriorSites)) return Refuse();
// The shared exact-item tombstone survives pickup, transfer and late callbacks.
m_Attempted.Insert(m_Mine);
if (!Carried()) return Refuse();