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,121 @@
"""Execute actual pair admission/apply plus the complete existing vehicle policy.
Native doubles inject allocation, AddWaypoint and RemoveWaypoint boundaries.
"""
import contextlib,io,os,re,runpy
from pathlib import Path
import policy_harness as h
path=Path(os.environ.get('ERR_CONVOY_SERVICE',h.ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_ConvoyService.c'))
source=path.read_text()
assert 'bool ReserveInterceptPair(' in source and 'bool ApplyInterceptPair(' in source, 'paired service API absent (baseline feature gap)'
# Reuse existing full vehicle/native doubles without running or changing its assertions.
captured=[]; original_run=h.run
try:
h.run=captured.append
with contextlib.redirect_stdout(io.StringIO()): runpy.run_path(str(h.ROOT/'tests/test_convoy_lifecycle.py'))
finally: h.run=original_run
assert len(captured)==1
cpp=captured[0]
pair='\n'.join(h.body(path,s) for s in ('protected bool InterceptPairEligible(', 'bool ReserveInterceptPair(', 'bool ApplyInterceptPair('))
pair=pair.replace('protected ','').replace('foreach (','for (')
for typ in ['ERR_ConvoyTask','ERR_ConvoyInterceptOrder','ERR_ConvoyVehicle','AIWaypoint']:
pair=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',pair)
for obj in ['task','first','second','lead','partner','existing','claimed','m_Mode','firstWaypoint','secondWaypoint','Receipt']:
pair=pair.replace(obj+'.',obj+'->')
pair=re.sub(r'(Vehicles\[[^\]]+\])\.',r'\1->',pair).replace('Forces().','Forces()->')
for ns in ['ERR_ForceRules','ERR_Actors','ERR_Resources','SCR_EntityHelper','vector']:
pair=pair.replace(ns+'.',ns+'::')
pair=pair.replace('AIWaypoint.Cast(', 'static_cast<AIWaypoint*>(')
cpp=cpp.replace('bool ApplyIntercept(ERR_ConvoyTask*',pair+'\nbool ApplyIntercept(ERR_ConvoyTask*',1)
cpp=cpp[:cpp.index('int main(){')]
cpp=cpp.replace('#include <cassert>','#include <cassert>\n#include <functional>\n#include <map>')
cpp=cpp.replace('void RemoveWaypoint(AIWaypoint*){removes++;}void AddWaypoint(AIWaypoint*){adds++;}', 'std::function<void()> onRemove,onAdd;void RemoveWaypoint(AIWaypoint*){removes++;if(onRemove)onRemove();}void AddWaypoint(AIWaypoint*){adds++;if(onAdd)onAdd();}')
cpp=cpp.replace('ERR_ForceRecord* FindGroup(SCR_AIGroup*){return &record;}', 'std::map<SCR_AIGroup*,ERR_ForceRecord*> records;ERR_ForceRecord* FindGroup(SCR_AIGroup* g){return records.count(g)?records[g]:&record;}')
cpp=cpp.replace('int LogisticsToken(SCR_AIGroup*){return token;}', 'std::map<SCR_AIGroup*,int> tokens;int LogisticsToken(SCR_AIGroup* g){return tokens.count(g)?tokens[g]:token;}')
cpp=cpp.replace('int spawns=0;bool fail=false;', 'int spawns=0,failAt=0;bool fail=false;std::function<void()> onSpawn;')
cpp=cpp.replace('spawns++;return fail?nullptr:new AIWaypoint();','spawns++;if(onSpawn)onSpawn();return (fail||spawns==failAt)?nullptr:new AIWaypoint();')
cpp+=r'''
struct PairCase:InterceptCase{
Case b; ERR_ConvoyInterceptOrder second;ERR_ConvoyVehicle fillers[4];
PairCase(){
b.unit.Index=3;b.mode.ledger.record.Id=10;b.mode.ledger.record.SourceId="original-vehicle-3";
mode.ledger.records[&group]=&mode.ledger.record;mode.ledger.records[&b.group]=&b.mode.ledger.record;
mode.command.tokens[&group]=400001;mode.command.tokens[&b.group]=400002;
second=order;second.Token=400002;second.Group=&b.group;second.VehicleIndex=3;second.Position={740,0,0};
task.Vehicles={&unit,&fillers[0],&fillers[1],&b.unit,&fillers[2],&fillers[3]};
unit.Tick(&mode,&route,0);b.unit.Tick(&mode,&route,0);
}
bool ReservePair(){return service.ReserveInterceptPair(&task,&order,&second,1000);}
bool ApplyPair(){return service.ApplyInterceptPair(&task,&order,&second,2000);}
};
int main(){
{PairCase f;auto a=f.unit.Waypoint;auto b=f.b.unit.Waypoint;float da=f.unit.LegDeadline,db=f.b.unit.LegDeadline;
assert(f.ReservePair());assert(f.service.InterceptCurrent(&f.task,&f.order)&&f.service.InterceptCurrent(&f.task,&f.second));
assert(f.unit.Waypoint==a&&f.b.unit.Waypoint==b&&!f.unit.InterceptActive&&!f.b.unit.InterceptActive&&f.unit.LegDeadline==da&&f.b.unit.LegDeadline==db);
assert(f.ApplyPair());assert(f.unit.InterceptActive&&f.b.unit.InterceptActive&&f.unit.InterceptWaypoint!=f.b.unit.InterceptWaypoint);
assert(f.unit.InterceptWaypoint->radius==15&&f.b.unit.InterceptWaypoint->radius==15&&f.unit.RouteIndex==0&&f.b.unit.RouteIndex==0);
assert(!f.ApplyPair());f.vehicle.position=f.order.Position;f.b.vehicle.position=f.second.Position;
f.unit.Tick(&f.mode,&f.route,3000);f.b.unit.Tick(&f.mode,&f.route,3000);
assert(f.unit.InterceptActive&&f.b.unit.InterceptActive&&!f.unit.InterceptWaypoint&&!f.b.unit.InterceptWaypoint);
f.unit.Tick(&f.mode,&f.route,121000);f.b.unit.Tick(&f.mode,&f.route,121000);
assert(!f.unit.InterceptToken&&!f.b.unit.InterceptToken&&f.unit.Waypoint&&f.b.unit.Waypoint);
}
for(int bad=0;bad<19;bad++){PairCase f;auto a=f.unit.Waypoint;auto b=f.b.unit.Waypoint;
if(bad==0)f.second.Token=f.order.Token;
if(bad==1)f.second.Group=f.order.Group;
if(bad==2)f.second.VehicleIndex=0;
if(bad==3)f.second.Position.x=739;
if(bad==4)f.second.Position.x=NAN;
if(bad==5)f.second.BeliefId++;
if(bad==6)f.second.BeliefRevision++;
if(bad==7)f.second.ReportId++;
if(bad==8)f.second.ObservedAt++;
if(bad==9)f.second.IssuedAt++;
if(bad==10)f.second.ExpiresAt++;
if(bad==11)f.second.SourceId="foreign";
if(bad==12)f.b.driver.player=true;
if(bad==13)f.b.seat.occupant=nullptr;
if(bad==14)f.fillers[0].SupplyToken=9;
if(bad==15)f.fillers[0].Combat->Held=true;
if(bad==16)f.mode.command.tokens[&f.b.group]=0;
if(bad==17)f.b.unit.Entity=&f.vehicle;
if(bad==18){f.order.ExpiresAt=121001;f.second.ExpiresAt=121001;}
assert(!f.ReservePair()&&!f.unit.InterceptToken&&!f.b.unit.InterceptToken&&f.unit.Waypoint==a&&f.b.unit.Waypoint==b);
}
// Claim two fails after claim one: spent token cannot be reused, route untouched.
{PairCase f;assert(f.b.unit.ClaimIntercept(&f.mode,&f.second));f.b.unit.ClearIntercept(&f.second);
auto a=f.unit.Waypoint;auto b=f.b.unit.Waypoint;float deadline=f.unit.LegDeadline;
assert(!f.ReservePair());assert(!f.unit.InterceptToken&&!f.b.unit.InterceptToken&&f.unit.Waypoint==a&&f.b.unit.Waypoint==b&&f.unit.LegDeadline==deadline);
}
// Global exclusion includes a different original task; never steal its claim.
{PairCase f;ERR_ConvoyTask other;ERR_ConvoyVehicle owned;owned.InterceptToken=400099;other.Vehicles={&owned};f.service.m_Tasks.Insert(&other);
assert(!f.ReservePair()&&owned.InterceptToken==400099&&!f.unit.InterceptToken);}
for(int allocation=1;allocation<=2;allocation++){PairCase f;assert(f.ReservePair());auto a=f.unit.Waypoint;auto b=f.b.unit.Waypoint;int deletes=SCR_EntityHelper::deletes,adds=f.group.adds+f.b.group.adds,removes=f.group.removes+f.b.group.removes;
ERR_Actors::failAt=ERR_Actors::spawns+allocation;assert(!f.ApplyPair());ERR_Actors::failAt=0;
assert(!f.unit.InterceptActive&&!f.b.unit.InterceptActive&&f.unit.Waypoint==a&&f.b.unit.Waypoint==b);
assert(SCR_EntityHelper::deletes==deletes+allocation-1);
assert(f.group.adds+f.b.group.adds==adds&&f.group.removes+f.b.group.removes==removes);
assert(f.unit.Entity==&f.vehicle&&f.b.unit.Entity==&f.b.vehicle&&f.unit.Driver==&f.driver&&f.b.unit.Driver==&f.b.driver);
}
// Allocation may revoke original crew. Both prepared handles are deleted before either route changes.
{PairCase f;assert(f.ReservePair());auto a=f.unit.Waypoint;auto b=f.b.unit.Waypoint;int deletes=SCR_EntityHelper::deletes;
ERR_Actors::onSpawn=[&](){f.b.driver.alive=false;};assert(!f.ApplyPair());ERR_Actors::onSpawn={};
assert(f.unit.Waypoint==a&&f.b.unit.Waypoint==b&&SCR_EntityHelper::deletes==deletes+2);}
// Immutable claimed destinations: changing both orders together is still rejected.
{PairCase f;assert(f.ReservePair());f.order.Position.x+=100;f.second.Position.x+=100;assert(!f.ApplyPair()&&!f.unit.InterceptActive&&!f.b.unit.InterceptActive);}
// Native removal and AddWaypoint may synchronously cancel the pair.
for(int boundary=0;boundary<3;boundary++){PairCase f;assert(f.ReservePair());int a=f.group.adds,b=f.b.group.adds;
auto cancel=[&](){f.service.ReleaseIntercept(&f.task,&f.order,2000);f.service.ReleaseIntercept(&f.task,&f.second,2000);};
if(boundary==0)f.group.onRemove=[&](){f.mode.command.tokens[&f.b.group]=0;};
if(boundary==1)f.group.onAdd=cancel;
if(boundary==2)f.b.group.onAdd=cancel;
assert(!f.ApplyPair());assert(!f.unit.InterceptToken&&!f.b.unit.InterceptToken&&!f.unit.InterceptActive&&!f.b.unit.InterceptActive);
assert(f.b.group.adds==b+(boundary==2));assert(f.group.adds==a+(boundary!=0));
}
// Per-member release remains exact and never steals a foreign public waypoint.
{PairCase f;assert(f.ReservePair());assert(f.ApplyPair());AIWaypoint foreign;f.b.unit.InterceptWaypoint=&foreign;
f.service.ReleaseIntercept(&f.task,&f.order,3000);assert(!f.unit.InterceptToken&&f.b.unit.InterceptToken==400002);
f.service.ReleaseIntercept(&f.task,&f.second,3000);assert(f.b.unit.InterceptWaypoint==&foreign&&!f.b.unit.InterceptToken);}
}
'''
h.run(cpp)
print('PASS: actual pair admission, rollback, native allocation/revocation boundaries, per-member ownership, hold and expiry')
@@ -0,0 +1,142 @@
"""Actual native convoy ownership/waypoint policy with small engine API doubles."""
import os,re
from pathlib import Path
from policy_harness import ROOT,run,body
path=Path(os.environ.get('ERR_CONVOY_SERVICE',str(ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_ConvoyService.c')))
source=path.read_text();code=source[source.index('class ERR_ConvoyVehicle'):source.index('class ERR_ConvoyCargoCallback')]
code=re.sub(r'//[^\n]*','',code).replace('class ERR_ConvoyVehicle','struct ERR_ConvoyVehicle').replace('ref ','').replace('protected ','')
code=code.replace('array<IEntity>','Array<IEntity*>').replace('array<BaseCompartmentSlot>','Array<BaseCompartmentSlot*>').replace('array<AIAgent>','Array<AIAgent*>')
for typ in ['Vehicle','SCR_AIGroup','IEntity','BaseCompartmentSlot','AIWaypoint','ERR_GameMode','ERR_ForceRoute','ERR_ForceRecord','AIAgent','ERR_ConvoyCombatState','ERR_ConvoyInterceptOrder','ERR_ConvoyReceipt']:
code=re.sub(r'\b'+typ+r' ([A-Za-z_]\w*)',typ+r'* \1',code)
for obj in ['Waypoint','Group','Entity','mode','record','agent','member','route','Combat','order','detour','m_InterceptWaypoint','m_InterceptGroup','InterceptOrder','hq']:
code=re.sub(r'\b'+obj+r'\.',obj+'->',code)
for cls in ['SCR_EntityHelper','ERR_Actors','ERR_ConvoyRules','ERR_Resources','CompartmentAccessComponent','vector']:
code=code.replace(cls+'.',cls+'::')
code=code.replace('AIWaypoint.Cast(', 'static_cast<AIWaypoint*>(').replace('Seats[i].','Seats[i]->').replace('Forces().','Forces()->').replace('Command().','Command()->').replace('foreach (','for (').replace('null','nullptr').replace('\n}\n','\n};\n')
code=code.replace('ERR_HQ.Cast(mode->Command())','mode->Command()').replace('ERR_HQ hq;', 'ERR_HQ hq=nullptr;')
code=code.replace('int attributed;', 'int attributed=0;')
code=re.sub(r'\b(bool|int|float|[A-Za-z_]\w*\*) ([A-Za-z_]\w*);',r'\1 \2 {};',code)
service='\n'.join(body(path, x) for x in ('protected bool InterceptEligible(', 'bool InterceptCurrent(', 'bool ReserveIntercept(', 'bool ApplyIntercept(', 'void ReleaseIntercept('))
service=service.replace('protected ','').replace('foreach (','for (').replace('null','nullptr')
for typ in ['ERR_ConvoyTask','ERR_ConvoyInterceptOrder','ERR_ConvoyVehicle','ERR_ForceRecord']:
service=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',service)
for obj in ['task','order','unit','record','other','existing','claimed','m_Mode','hq']:
service=service.replace(obj+'.',obj+'->')
for obj in ['Receipt','Route','Combat']:
service=service.replace(obj+'.',obj+'->')
service=service.replace('ERR_HQ.Cast(m_Mode->Command())','m_Mode->Command()').replace('unit->Index.ToString()', 'std::to_string(unit->Index)')
service=service.replace('Forces().','Forces()->').replace('task->Vehicles[order->VehicleIndex].','task->Vehicles[order->VehicleIndex]->')
service=service.replace('ERR_ForceRules.','ERR_ForceRules::').replace('ERR_ForceKind.','ERR_ForceKind::')
service='struct ERR_ConvoyReceipt{bool Consumed=true;std::string SourceId="original";Array<int> Records={7,8,9,10,11,12};}; struct ERR_ConvoyTask{bool Stopped=false,Ready=true;ERR_ConvoyReceipt* Receipt;ERR_ForceRoute* Route;Array<ERR_ConvoyVehicle*> Vehicles;};struct Service{ERR_GameMode* m_Mode;bool current=true;Array<ERR_ConvoyTask*>m_Tasks;bool Current(){return current;}'+service+'};'
run(r'''
#include <cassert>
#include <vector>
#include <algorithm>
#include <cmath>
#include <string>
struct vector{float x=0,y=0,z=0;bool operator!=(vector b){return x!=b.x||y!=b.y||z!=b.z;}static float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);}};
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool IsEmpty(){return this->empty();}void Insert(T v){this->push_back(v);}void Clear(){this->clear();}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}};
struct SCR_AIGroup;struct Vehicle;struct ERR_ConvoyCombatState{bool Held=false;};
struct IEntity{bool alive=true,player=false,awake=true;Vehicle* vehicle=nullptr;SCR_AIGroup* group=nullptr;IEntity* parent=nullptr;IEntity* GetParent(){return parent;}};
struct AIAgent{IEntity* actor=nullptr;IEntity* GetControlledEntity(){return actor;}int lod=0;void SetPermanentLOD(int value){lod=value;}};
struct AIWaypoint:IEntity{float radius=0;void SetCompletionRadius(float value){radius=value;}bool IsWithinCompletionRadius(SCR_AIGroup* group);};
struct SCR_AIGroup:IEntity{bool within=false;AIWaypoint* current=nullptr;int lod=0,faction=1,removes=0,adds=0;Array<AIAgent*> agents;int GetFaction(){return faction;}void SetPermanentLOD(int value){lod=value;}void GetAgents(Array<AIAgent*>& out){out=agents;}void RemoveWaypoint(AIWaypoint*){removes++;}void AddWaypoint(AIWaypoint*){adds++;}};
bool AIWaypoint::IsWithinCompletionRadius(SCR_AIGroup* group){return group->within;}
struct Vehicle:IEntity{vector position;vector GetOrigin(){return position;}};
struct BaseCompartmentSlot{IEntity* occupant=nullptr;IEntity* GetOccupant(){return occupant;}};
namespace ERR_ForceKind{const int CONVOY=3;}
struct ERR_ForceRecord{SCR_AIGroup* Group=nullptr;std::string SourceId="original-vehicle-0";int Id=7,Kind=3;bool Physical=true,Eliminated=false,Pinned=true;};
struct Ledger{ERR_ForceRecord record;ERR_ForceRecord* FindGroup(SCR_AIGroup*){return &record;}};
struct Command{bool ReleaseConvoySurvivors(SCR_AIGroup*){return false;}int token=400001;int LogisticsToken(SCR_AIGroup*){return token;}int unregistrations=0;void UnregisterGroup(SCR_AIGroup*){unregistrations++;}};
using ERR_HQ=Command*;struct ERR_ConvoyReceipt;
struct ERR_GameMode{struct Ledger ledger;struct Command command;int EnemyFaction(){return 1;}struct Ledger* Forces(){return &ledger;}struct Command* Command(){return &command;}};
struct ERR_ForceRoute{Array<vector> points;int Count(){return points.size();}vector At(int i){assert(i>=0&&i<Count());return points[i];}};
namespace ERR_Actors{int spawns=0;bool fail=false;bool Alive(IEntity* a){return a&&a->alive;}bool CanFight(IEntity* a){return Alive(a)&&a->awake;}bool Player(IEntity* a){return a&&a->player;}SCR_AIGroup* Group(IEntity* a){return a?a->group:nullptr;}IEntity* Spawn(int,vector){spawns++;return fail?nullptr:new AIWaypoint();}}
namespace ERR_Resources{int MoveWaypoint(){return 1;}}
namespace CompartmentAccessComponent{IEntity* GetVehicleIn(IEntity* a){return a?a->vehicle:nullptr;}}
namespace ERR_ConvoyRules{inline bool captured=false;bool Captured(Vehicle*,SCR_AIGroup*){return captured;}bool PartOf(IEntity* e,IEntity* root){int depth=0;while(e&&depth++<32){if(e==root)return true;e=e->GetParent();}return false;}}
namespace SCR_EntityHelper{int deletes=0;void DeleteEntityAndChildren(AIWaypoint* p){deletes++;delete p;}}
namespace ERR_ForceRules{bool Finite(float n){return std::isfinite(n);}bool FiniteVector(vector p){return Finite(p.x)&&Finite(p.y)&&Finite(p.z);}}
struct ERR_ConvoyInterceptOrder{int Token=400001,VehicleIndex=0,BeliefId=1,BeliefRevision=1,ReportId=1;SCR_AIGroup* Group=nullptr;std::string SourceId="original";vector Position{700,0,0};float ObservedAt=1000,IssuedAt=1000,ExpiresAt=121000;};
''' + code + service + r'''
struct Case{
ERR_GameMode mode;Vehicle vehicle;SCR_AIGroup group;IEntity driver;AIAgent agent;BaseCompartmentSlot seat;ERR_ConvoyVehicle unit;ERR_ForceRoute route;
Case(){mode.ledger.record.Group=&group;agent.actor=&driver;seat.occupant=&driver;unit.Seats.Insert(&seat);unit.Registered=true;unit.Entity=&vehicle;unit.Group=&group;unit.Driver=&driver;unit.Members.Insert(&driver);driver.vehicle=&vehicle;driver.group=&group;group.agents.Insert(&agent);route.points={{100,0,0},{300,0,0}};}
};
struct InterceptCase:Case{Service service;ERR_ConvoyReceipt receipt;ERR_ConvoyTask task;ERR_ConvoyInterceptOrder order;
InterceptCase(){service.m_Mode=&mode;task.Receipt=&receipt;task.Route=&route;task.Vehicles={&unit};service.m_Tasks={&task};order.Group=&group;}
bool Reserve(){return service.ReserveIntercept(&task,&order,1000);}bool Apply(){return service.ApplyIntercept(&task,&order,2000);}
};
int main(){
{InterceptCase f;f.unit.Tick(&f.mode,&f.route,0);float deadline=f.unit.LegDeadline;auto original=f.unit.Waypoint;assert(f.Reserve());f.service.ReleaseIntercept(&f.task,&f.order,2000);assert(f.unit.Waypoint==original&&f.unit.LegDeadline==deadline);}
{InterceptCase f;f.unit.Tick(&f.mode,&f.route,0);float deadline=f.unit.LegDeadline;assert(f.Reserve());f.unit.Tick(&f.mode,&f.route,121000);assert(f.unit.LegDeadline==deadline);}
{InterceptCase f;assert(f.Reserve());assert(f.Apply());f.service.ReleaseIntercept(&f.task,&f.order,5000);assert(f.unit.LegDeadline==605000&&!f.unit.Waypoint);}
{InterceptCase f;f.unit.Tick(&f.mode,&f.route,0);auto route=f.unit.Waypoint;assert(f.Reserve());assert(f.unit.Waypoint==route&&!f.unit.InterceptActive);
f.unit.Tick(&f.mode,&f.route,1500);assert(f.unit.Waypoint==route&&f.unit.RouteIndex==0);assert(f.Apply());assert(!f.unit.Waypoint&&f.unit.InterceptWaypoint&&f.unit.InterceptActive);
assert(!f.Apply());f.group.within=true;f.unit.Tick(&f.mode,&f.route,3000);assert(f.unit.RouteIndex==0);f.vehicle.position=f.order.Position;
f.unit.Tick(&f.mode,&f.route,4000);assert(f.unit.InterceptActive&&!f.unit.InterceptWaypoint&&f.unit.RouteIndex==0);
f.unit.Tick(&f.mode,&f.route,120999);assert(!f.unit.Waypoint);f.group.within=false;f.unit.Tick(&f.mode,&f.route,121000);assert(!f.unit.InterceptToken&&f.unit.Waypoint&&f.unit.RouteIndex==0);assert(!f.Reserve());}
{InterceptCase f;assert(f.Reserve());f.unit.Tick(&f.mode,&f.route,121000);assert(!f.unit.InterceptToken&&f.unit.Waypoint);}
{InterceptCase f;assert(f.Reserve());f.group.within=true;f.unit.Tick(&f.mode,&f.route,1100);f.unit.Tick(&f.mode,&f.route,1200);assert(f.unit.RouteIndex==1);assert(f.Apply());assert(f.unit.RouteIndex==1);}
for(int bad=0;bad<14;bad++){InterceptCase f;
if(bad==0)f.order.Token=300001;
if(bad==1)f.order.VehicleIndex=1;
if(bad==2)f.order.ExpiresAt=121001;
if(bad==3)f.order.Position.x=NAN;
if(bad==4)f.order.IssuedAt=1001;
if(bad==5)f.unit.Arrived=true;
if(bad==6)f.unit.SupplyToken=100001;
if(bad==7)f.unit.SupplyHeld=true;
if(bad==8)f.unit.Combat->Held=true;
if(bad==9)f.seat.occupant=nullptr;
if(bad==10)f.mode.ledger.record.Id=99;
if(bad==11)f.agent.actor=nullptr;
if(bad==12)f.service.current=false;
if(bad==13)f.mode.command.token=0;
assert(!f.Reserve()&&!f.unit.InterceptToken&&!f.unit.InterceptWaypoint);}
{InterceptCase f;assert(f.Reserve());assert(f.Apply());f.driver.alive=false;f.unit.Tick(&f.mode,&f.route,3000);assert(f.unit.Released&&!f.unit.InterceptToken&&!f.unit.InterceptWaypoint);}
{InterceptCase f;assert(f.Reserve());assert(f.Apply());f.unit.Members.Clear();f.unit.Tick(&f.mode,&f.route,3000);assert(!f.unit.InterceptToken&&!f.unit.InterceptWaypoint);}
{InterceptCase f;assert(f.Reserve());auto foreign=f.order;foreign.Token=400002;f.service.ReleaseIntercept(&f.task,&foreign,2000);assert(f.unit.InterceptToken==400001);
f.unit.InterceptToken=400002;f.service.ReleaseIntercept(&f.task,&f.order,2000);assert(f.unit.InterceptToken==400002);}
{InterceptCase f;assert(f.Reserve());assert(f.Apply());AIWaypoint foreign;f.unit.InterceptWaypoint=&foreign;f.service.ReleaseIntercept(&f.task,&f.order,3000);assert(f.unit.InterceptWaypoint==&foreign&&!f.unit.InterceptToken);}
{InterceptCase f;assert(f.Reserve());f.order.Position.x++;assert(!f.Apply());f.service.ReleaseIntercept(&f.task,&f.order,3000);assert(!f.unit.InterceptToken&&!f.unit.Waypoint);}
{InterceptCase f;assert(f.Reserve());ERR_Actors::fail=true;assert(!f.Apply()&&!f.unit.InterceptActive);ERR_Actors::fail=false;f.service.ReleaseIntercept(&f.task,&f.order,3000);assert(!f.unit.InterceptToken);}
Case travel;travel.unit.Tick(&travel.mode,&travel.route,1000);assert(travel.group.adds==1&&travel.unit.Waypoint&&travel.unit.LegDeadline==601000);
travel.unit.Tick(&travel.mode,&travel.route,2000);assert(travel.group.adds==1&&travel.unit.LegDeadline==601000);
travel.vehicle.position={100,0,0};travel.group.within=true;travel.unit.Tick(&travel.mode,&travel.route,3000);assert(travel.unit.RouteIndex==1&&travel.group.adds==2&&travel.group.removes==1);
travel.vehicle.position={300,0,0};travel.unit.Tick(&travel.mode,&travel.route,4000);assert(travel.unit.Arrived&&!travel.unit.Waypoint&&travel.group.removes==2);
travel.unit.Tick(&travel.mode,&travel.route,5000);assert(travel.group.adds==2);
// Native completion may use seated actors ahead of the vehicle origin; native
// current WP can already be removed while the controller still owns its handle.
Case offset;offset.unit.Tick(&offset.mode,&offset.route,1000);offset.vehicle.position={64.5,0,0};offset.group.within=true;offset.group.current=nullptr;
assert(vector::DistanceXZ(offset.vehicle.position,offset.route.At(0))>35);
offset.unit.Tick(&offset.mode,&offset.route,2000);assert(offset.unit.RouteIndex==1&&offset.group.adds==2&&offset.group.removes==1&&offset.unit.Waypoint);
offset.group.within=false;offset.unit.Tick(&offset.mode,&offset.route,3000);offset.unit.Tick(&offset.mode,&offset.route,4000);assert(offset.unit.RouteIndex==1&&offset.group.adds==2&&offset.group.removes==1);
// A close vehicle origin alone is not the native seated-group arrival predicate.
Case notNative;notNative.vehicle.position={99,0,0};notNative.unit.Tick(&notNative.mode,&notNative.route,1000);notNative.unit.Tick(&notNative.mode,&notNative.route,2000);assert(notNative.unit.RouteIndex==0&&notNative.group.adds==1);
Case supply;supply.unit.SupplyToken=100001;supply.unit.Tick(&supply.mode,&supply.route,1000);assert(supply.group.adds==1); // reservation alone does not deliver hold
supply.unit.SupplyHeld=true;supply.unit.ClearOrder();supply.group.within=true;supply.unit.Tick(&supply.mode,&supply.route,700000);assert(supply.unit.RouteIndex==0&&!supply.unit.Released&&supply.group.adds==1);
supply.unit.SupplyToken=0;supply.unit.SupplyHeld=false;supply.group.within=false;supply.unit.Tick(&supply.mode,&supply.route,701000);assert(supply.group.adds==2&&supply.unit.RouteIndex==0);
supply.unit.Release(&supply.mode);assert(supply.unit.SupplyToken==0&&!supply.unit.SupplyHeld);
Case held;held.unit.Tick(&held.mode,&held.route,1000);held.unit.Combat->Held=true;held.unit.ClearOrder();held.group.within=true;assert(!held.unit.Order(&held.route,2000)&&held.group.adds==1);
held.unit.Tick(&held.mode,&held.route,700000);assert(held.unit.RouteIndex==0&&held.group.adds==1&&!held.unit.Released&&!held.unit.Waypoint);
held.driver.alive=false;held.unit.Tick(&held.mode,&held.route,700001);assert(held.unit.Released&&!held.unit.Combat->Held);
Case timeout;timeout.unit.Tick(&timeout.mode,&timeout.route,1000);timeout.unit.Tick(&timeout.mode,&timeout.route,601000);assert(timeout.unit.Released&&!timeout.unit.Waypoint&&timeout.mode.command.unregistrations==1&&!timeout.mode.ledger.record.Pinned);
timeout.unit.Release(&timeout.mode);timeout.unit.Tick(&timeout.mode,&timeout.route,999999);assert(timeout.mode.command.unregistrations==1&&timeout.group.adds==1&&timeout.group.lod==-1&&timeout.agent.lod==-1);
for(int reason=0;reason<6;reason++){
Case lost;lost.unit.Tick(&lost.mode,&lost.route,1000);
if(reason==0)lost.driver.alive=false;
if(reason==1)lost.driver.player=true;
if(reason==2)lost.driver.vehicle=nullptr;
if(reason==3)lost.group.faction=2;
if(reason==4)lost.vehicle.alive=false;
if(reason==5)lost.driver.group=nullptr;
lost.unit.Tick(&lost.mode,&lost.route,2000);assert(lost.unit.Released&&!lost.unit.Waypoint&&lost.mode.command.unregistrations==1);
assert(lost.unit.Entity==&lost.vehicle&&lost.unit.Group==&lost.group&&lost.unit.Members[0]==&lost.driver);
}
Case failed;ERR_Actors::fail=true;failed.unit.Tick(&failed.mode,&failed.route,1000);assert(failed.unit.Released&&failed.group.adds==0);ERR_Actors::fail=false;
}
''')
print('PASS: actual native seated-group arrival outside35m, native waypoint removal, idempotent advance, and convoy waypoint idempotence/arrival/deadline, missing/dead/captured/reparented crew refusal, failed native waypoint release, original vehicle/member preservation and no replacement')