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,155 @@
"""Actual depot porter selection/planner/state transitions and final finite import; native boundaries doubled."""
import os,re
from pathlib import Path
from policy_harness import ROOT,body,run
BASE=Path(os.environ.get('ERR_DEPOT_ROOT',ROOT))
P=BASE/'addons/core/Scripts/Game/ERR/10_AI/ERR_GroundDepotLoading.c'
S=Path(os.environ.get('ERR_INFANTRY_RESUPPLY_SOURCE',BASE/'addons/core/Scripts/Game/ERR/10_AI/ERR_InfantryResupply.c'))
source=P.read_text()
valid=body(P,'protected bool Valid(')
assert 'ERR_GroundDepotTransfer.Cargo(m_Item, m_MineCargo)' in valid
assert 'm_Service.DepotCurrent()' in valid and 'DepotAvailable()' not in valid and 'DepotNeeded()' not in valid
for forbidden in ('Teleport(', 'TrySpawn', 'SetAmmoCount', 'SetOrigin(', 'SetTransform('):assert forbidden not in source
def cpp(s):
s=s.replace('protected ','').replace('ref ','').replace('null','nullptr')
for t in ('ERR_HQUnit','ERR_InfantryResupply','ERR_ConvoyVehicle','ERR_HQWatchEntry','ERR_SiteRuntime','ERR_GroundDepotTransfer','ERR_GroundDepotLoading','ERR_FiniteMagazineReservation','SCR_ChimeraAIAgent'):
s=re.sub(r'\b'+t+r' (\w+)',t+r'* \1',s)
s=s.replace('ERR_FiniteMagazineReservation(m_Original, m_Spent, item)','ERR_FiniteMagazineReservation(&m_Original, &m_Spent, item)')
for ns in ('ERR_ForceRules','ERR_InfantryResupplyRules','ERR_GroundDepotTransfer','ERR_InfantryAmmoTransfer','ERR_GroundDepotAccess','ERR_Actors','ERR_EnemyEquipmentRules','CompartmentAccessComponent','ERR_InfantryMineTransfer','Math'):
s=s.replace(ns+'.',ns+'::')
for n in ('m_HQ','m_Mode','m_Service','m_Move','m_Reservation','m_Order','m_Truck','m_Crew','m_Donor','m_Worker','m_Site','m_Cache','service','truck','donor','report','site','crew','operation','actor','agent'):
s=re.sub(r'\b'+n+r'\.',n+'->',s)
s=s.replace('crew->StatusSampler.', 'crew->StatusSampler->').replace('agent->m_UtilityComponent.', 'agent->m_UtilityComponent->')
s=s.replace('SCR_ChimeraAIAgent.Cast(SCR_AIUtils.GetAIAgent(actor))', 'actor->agent')
s=s.replace('InventoryItemComponent.Cast(item.FindComponent(InventoryItemComponent))','item->carried').replace('InventoryItemComponent carried','InventoryItem* carried').replace('carried.GetParentSlot()', 'carried->GetParentSlot()').replace('GetParentSlot().','GetParentSlot()->')
s=s.replace('Sites().','Sites()->').replace('Watch().','Watch()->').replace('Forces().','Forces()->')
s=s.replace('site->Responders.Group','site->Responders->Group').replace('site->Definition.Position','site->Definition->Position').replace('m_Site->Definition.Position','m_Site->Definition->Position')
s=s.replace('m_Truck->Entity.GetOrigin()', 'm_Truck->Entity->GetOrigin()')
s=s.replace('vector.DistanceXZ','Vec::DistanceXZ').replace('string.Format','Format')
s=s.replace('InventoryStorageManagerComponent.Cast(m_Cache->FindComponent(InventoryStorageManagerComponent))','m_Cache->inventory')
s=s.replace('"3 0 0"','Vec{3}').replace('"2 0 0"','Vec{2}')
return s
methods='\n'.join(cpp(body(P,x)) for x in ('bool MineCargo(', 'protected bool SelectWorker(', 'void Plan(', 'void Tick(', 'protected void Abort(', 'void Stop(', 'bool TransferValid(', 'bool ClaimDelivery(', 'bool DeliveredTo('))
admit=(cpp(body(S,'bool AdmitDepot('))+cpp(body(S,'bool AdmitDepotMine('))).replace('job.','job->').replace('m_Stock.Insert(item); Audit(', 'm_Stock.Insert(item); Audit(')
run(r'''
#include <cassert>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
using string=std::string;
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}void Insert(T v){this->push_back(v);}void RemoveItem(T v){this->erase(std::remove(this->begin(),this->end(),v),this->end());}};
struct Vec{float x=0;Vec operator+(Vec b){return {x+b.x};}static float DistanceXZ(Vec a,Vec b){return std::abs(a.x-b.x);}};
template<class...T>string Format(string s,T...){return s;}
struct ERR_ForceRules{static bool Finite(float f){return std::isfinite(f);}};
struct Math{static float Min(float a,float b){return std::min(a,b);}};
struct Entity;struct Slot{Entity*attached=nullptr;Entity*GetAttachedEntity(){return attached;}};struct InventoryItem{Slot*slot=nullptr;Slot*GetParentSlot(){return slot;}};
struct Group{int faction=1;};struct Inventory{};struct Utility{bool m_AIInfo=true;};struct SCR_ChimeraAIAgent{Utility*m_UtilityComponent=nullptr;};
struct Entity{Vec pos;Inventory*inventory=nullptr;bool stock=true,compatible=true,alive=true,player=false,aboard=false,attributed=true,equipmentEligible=true,mine=false,armed=false,defaultArmed=false,collision=true;InventoryItem*carried=nullptr;Entity*parent=nullptr;int faction=1,well=1,rounds=30,maxRounds=30;Group*group=nullptr;SCR_ChimeraAIAgent*agent=nullptr;Vec GetOrigin(){return pos;}};using IEntity=Entity*;
struct Sampler{Array<IEntity>members;Group*group=nullptr;bool owns=true;int InitialStrength(){return members.Count();}bool OwnsRoster(Group*g){return owns&&g==group;}IEntity InitialMember(int i){return members[i];}bool CanAttribute(int i,IEntity a,bool){return a&&members[i]==a&&a->attributed&&a->group==group&&!a->player&&a->faction==group->faction;}};
struct ERR_Actors{static bool CanFight(IEntity a){return a&&a->alive;}};
struct CompartmentAccessComponent{static bool GetVehicleIn(IEntity a){return a&&a->aboard;}};
struct Definition{Vec Position;};struct ERR_SiteRuntime{struct Definition*Definition=nullptr;ERR_SiteRuntime*Responders=nullptr;struct Group*Group=nullptr;IEntity Container=nullptr;Array<IEntity>items;};
struct Sites{Array<ERR_SiteRuntime*>sites;int Count(){return sites.Count();}ERR_SiteRuntime*At(int i){return sites[i];}int DepotItemCount(ERR_SiteRuntime*s){return s?s->items.Count():0;}IEntity DepotItem(ERR_SiteRuntime*s,int i){return s->items[i];}};
struct ERR_HQUnit{struct Group*Group=nullptr;int ForceSourceId=0,LogisticsReservation=0;float NextStatus=0;bool eligible=true,HomeGuard=false,ReservedForSupport=false,Assignment=false,Task=false,PendingTask=false,PendingOrder=false,Downlink=false,Waypoint=false;Sampler*StatusSampler=nullptr;};
struct ERR_ConvoyTask{};
struct ERR_ConvoyVehicle{struct Group*Group=nullptr;IEntity Entity=nullptr;int SupplyToken=0;bool SupplyHeld=false;int clears=0;void ClearOrder(){clears++;}};
struct ERR_HQWatchEntry{int SourceId=2,MessageId=1;float ObservedAt=0;Vec Position;bool valid=true;};
struct ERR_InfantryResupplyRules{static bool Fresh(ERR_HQWatchEntry*r,float n){return r&&r->valid&&n>=r->ObservedAt&&n-r->ObservedAt<=120000;}};
struct Watch{ERR_HQWatchEntry report;ERR_HQWatchEntry*Find(int){return &report;}};
struct Ledger{void*FindGroup(Group*){return this;}};
struct Mode{struct Sites sites;Ledger ledger;struct Sites*Sites(){return &sites;}Ledger*Forces(){return &ledger;}};
struct ERR_EnemyEquipmentRules{static bool Eligible(Mode*,Group*g,IEntity a){return a&&a->equipmentEligible&&a->group==g&&a->faction==g->faction&&!a->player&&a->alive;}};
struct ERR_GroundDepotLoading;struct ERR_InfantryResupply;
struct ERR_FiniteMagazineReservation{Array<IEntity>*original,*spent;IEntity item;bool committed=false,closed=false;ERR_FiniteMagazineReservation(Array<IEntity>*a,Array<IEntity>*b,IEntity i):original(a),spent(b),item(i){}bool Reserve(){if(!item||!original->Contains(item)||spent->Contains(item)||spent->Count()>=96)return false;spent->Insert(item);return true;}bool ReleaseUnsubmitted(){if(closed||committed)return false;closed=true;spent->RemoveItem(item);return true;}bool CommittedFor(IEntity i){return committed&&i==item&&spent->Contains(i);}};
struct Route{int outcome=1,calls=0;int Advance(float,void*){calls++;return outcome;}};
struct HQ{Array<ERR_InfantryResupply*>services;ERR_HQUnit*crew=nullptr,*donor=nullptr;struct Watch watch;Route route;bool claim=true,radio=true;int orders=0,releases=0,claims=0;
int GroundSupplyCount(){return services.Count();}ERR_InfantryResupply*GroundSupplyAt(int i){return services[i];}ERR_HQUnit*GroundUnit(Group*g){return crew&&crew->Group==g?crew:donor&&donor->Group==g?donor:nullptr;}struct Watch*Watch(){return &watch;}void*Journal(){return this;}
bool ReserveGroundDepot(ERR_HQUnit*,ERR_HQUnit*,ERR_InfantryResupply*,int,bool=false);
void ReleaseGroundDepot(ERR_HQUnit*c,ERR_HQUnit*d,ERR_ConvoyVehicle*t,int token){releases++;if(c&&c->LogisticsReservation==token)c->LogisticsReservation=0;if(d&&d->LogisticsReservation==token)d->LogisticsReservation=0;if(t&&t->SupplyToken==token){t->SupplyToken=0;t->SupplyHeld=false;}}
Route*Downlink(Group*,string,string,int){orders++;return radio?&route:nullptr;}
};
// Native compatibility boundary double: pair-specific carried weapon well,
// supported weapon flag, and sane positive ammo. Real Compatible's full native
// weapon/muzzle/type/ownership logic remains covered by the transfer/planning suites.
struct ERR_InfantryAmmoTransfer{static bool StoredUnder(IEntity i,IEntity owner){return i&&i->parent==owner;}static bool Compatible(IEntity a,IEntity i){return a&&i&&i->compatible&&a->compatible&&a->well>0&&a->well==i->well&&i->rounds>0&&i->maxRounds>0&&i->rounds<=i->maxRounds;}};
struct ERR_InfantryMineTransfer{static bool ReadyMine(IEntity i){return i&&i->mine&&i->alive&&!i->armed&&!i->defaultArmed&&i->collision;}};
struct ERR_GroundDepotAccess{static inline bool clear=true;static bool Clear(IEntity,IEntity){return clear;}};
struct ERR_GroundDepotTransfer{static inline int constructed=0;bool mineCargo=false,delivery=false,submitted=true,unknown=true,confirmed=false;int result=0;IEntity item;ERR_FiniteMagazineReservation*r;
ERR_GroundDepotTransfer(ERR_GroundDepotLoading*,IEntity,IEntity,IEntity i,ERR_FiniteMagazineReservation*q,bool d,bool m=false):mineCargo(m),delivery(d),item(i),r(q){constructed++;r->committed=true;}
static bool Magazine(IEntity i){return i&&i->stock&&!i->mine;}static bool Cargo(IEntity i,bool mine=false){return mine?ERR_InfantryMineTransfer::ReadyMine(i):Magazine(i);}bool MineCargo(){return mineCargo;}bool Delivery(){return delivery;}IEntity Item(){return item;}bool Unresolved(){return submitted&&unknown;}bool Confirmed(){return confirmed&&Cargo(item,mineCargo);}void Stop(){result=-1;}int Tick(float){return result;}
};
struct ERR_InfantryResupply{bool available=true,needed=true,mineNeeded=false;int m_DepotImports=0,m_DepotMineImports=0;ERR_ConvoyVehicle*truck=nullptr;ERR_ConvoyTask task;Array<IEntity>m_Stock,m_MineStock,m_Spent;ERR_ConvoyVehicle*m_Truck=nullptr;
bool DepotAvailable(){return available&&m_Stock.Count()<96;}bool DepotNeeded(){return DepotAvailable()&&needed;}bool DepotMineNeeded(){return available&&mineNeeded&&m_MineStock.Count()<96&&m_DepotMineImports==0;}ERR_ConvoyVehicle*DepotTruck(){return available?truck:nullptr;}ERR_ConvoyTask*Task(){return &task;}bool Contains(IEntity,IEntity i){return i!=nullptr;}void Audit(string){}bool AdmitDepot(ERR_GroundDepotLoading*,IEntity);bool AdmitDepotMine(ERR_GroundDepotLoading*,IEntity);
};
struct ERR_GroundDepotLoading{HQ*m_HQ;Mode*m_Mode;Array<IEntity>m_Original,m_Spent;bool active=true,valid=true,stationary=true,canWalk=true,m_Stopped=false,m_Captured=false,m_PickedUp=false,m_DeliveryClaimed=false,m_Imported=false,m_MineCargo=false;int m_State=0,m_Attempts=0,m_Delivered=0,m_Token=0,m_WorkerSlot=0,walks=0,cleanups=0,notes=0;float m_NextPlan=0,m_Deadline=0,m_Last=-1,m_NextTick=0,m_HeldAt=-1;Vec m_CachePosition,m_TruckPosition;
Utility*m_Utility=nullptr;ERR_HQUnit*m_Crew=nullptr,*m_Donor=nullptr;ERR_SiteRuntime*m_Site=nullptr;IEntity m_Worker=nullptr,m_Cache=nullptr,m_Item=nullptr;Inventory*m_CacheInventory=nullptr;void*m_CrewRecord=nullptr;ERR_InfantryResupply*m_Service=nullptr;ERR_ConvoyTask*m_Task=nullptr;ERR_ConvoyVehicle*m_Truck=nullptr;Route*m_Order=nullptr;ERR_GroundDepotTransfer*m_Move=nullptr;ERR_FiniteMagazineReservation*m_Reservation=nullptr;
bool Active(){return active&&!m_Stopped;}bool Busy(){return m_State!=0;}bool Unresolved(){return m_Move&&m_Move->Unresolved();}bool Valid(){return Active()&&valid&&(!m_Service||m_Service->available)&&ERR_GroundDepotTransfer::Cargo(m_Item,m_MineCargo);}bool Stationary(){return stationary;}bool Quiet(ERR_HQUnit*u){return u&&u->eligible;}bool Stored(IEntity,IEntity){return true;}void Capture(){m_Captured=true;}void Note(string){notes++;}void ClearAction(){}bool Walk(Vec){walks++;return canWalk;}
void Cleanup(){cleanups++;if(m_Reservation)m_Reservation->ReleaseUnsubmitted();m_HQ->ReleaseGroundDepot(m_Crew,m_Donor,m_Truck,m_Token);m_State=0;m_Token=0;m_Move=nullptr;m_Order=nullptr;}
METHODS
};
ADMISSION
bool HQ::ReserveGroundDepot(ERR_HQUnit*c,ERR_HQUnit*d,ERR_InfantryResupply*s,int token,bool mineCargo){if(!(mineCargo?s->DepotMineNeeded():s->DepotNeeded())||!claim||c->LogisticsReservation||d->LogisticsReservation||s->truck->SupplyToken)return false;claims++;c->LogisticsReservation=d->LogisticsReservation=s->truck->SupplyToken=token;return true;}
struct F{Mode mode;HQ hq;ERR_GroundDepotLoading job;Group cg,dg;ERR_HQUnit crew,donor;Definition def;ERR_SiteRuntime site,responders;Entity worker,second,cache,truck,item;Inventory inv;Slot itemSlot;InventoryItem carriedItem;Utility workerUtility,secondUtility;SCR_ChimeraAIAgent workerAgent,secondAgent;Sampler sampler;ERR_ConvoyVehicle vehicle;ERR_InfantryResupply service;
F(){itemSlot.attached=&item;carriedItem.slot=&itemSlot;item.carried=&carriedItem;item.parent=&truck;worker.group=second.group=&cg;workerAgent.m_UtilityComponent=&workerUtility;secondAgent.m_UtilityComponent=&secondUtility;worker.agent=&workerAgent;second.agent=&secondAgent;sampler.group=&cg;sampler.members={&worker};crew.StatusSampler=&sampler;truck.pos={20};crew.Group=&cg;donor.Group=&dg;hq.crew=&crew;hq.donor=&donor;vehicle.Group=&dg;vehicle.Entity=&truck;service.truck=service.m_Truck=&vehicle;hq.services={&service};site.Definition=&def;site.Responders=&responders;responders.Group=&cg;site.Container=&cache;site.items={&item};cache.inventory=&inv;mode.sites.sites={&site};job.m_HQ=&hq;job.m_Mode=&mode;job.m_Worker=&worker;job.m_Original={&item};ERR_GroundDepotAccess::clear=true;}
void Mine(){item.mine=true;service.mineNeeded=true;service.needed=false;worker.compatible=false;}
void Start(){job.Plan(0);assert(job.m_State==1&&hq.claims==1&&hq.orders==1);}
void Reach(){Start();job.Tick(0);assert(job.m_State==2&&vehicle.SupplyHeld&&vehicle.clears==1);job.Tick(1000);assert(donor.NextStatus==1000&&job.walks==0);job.Tick(2000);assert(job.m_State==2);hq.watch.report.ObservedAt=3000;job.Tick(3000);assert(job.m_State==3&&hq.orders==2&&job.walks==0);job.Tick(4000);assert(job.m_State==4&&job.walks==1);}
};
int main(){
// A mine-only deficit chooses the original porter without rifle compatibility,
// but still follows both delivered radio orders and exact two-leg proof.
{F f;f.Mine();f.Reach();assert(f.job.MineCargo()&&f.job.m_Worker==&f.worker);f.job.Tick(5000);auto*pick=f.job.m_Move;assert(pick->MineCargo());pick->unknown=false;pick->confirmed=true;pick->result=1;f.job.Tick(6000);f.job.Tick(7000);auto*drop=f.job.m_Move;assert(drop->MineCargo());drop->unknown=false;drop->confirmed=true;drop->result=1;assert(!f.service.AdmitDepot(&f.job,&f.item));f.job.Tick(8000);assert(f.job.m_State==6&&f.service.m_Stock.empty()&&f.service.m_MineStock.Count()==1&&f.service.m_DepotMineImports==1&&f.service.m_DepotImports==0);f.job.Tick(9000);assert(!f.job.Busy());}
// Armed or changed cargo aborts at each active stage; uncertain native moves
// retain claims until proof settles, and never import through a late callback.
for(int phase=1;phase<=5;phase++){F f;f.Mine();if(phase<=2){f.Start();if(phase==2)f.job.Tick(0);}else{f.Reach();if(phase==3)f.job.m_State=3;if(phase==5){f.job.Tick(5000);f.job.m_Move->unknown=false;f.job.m_Move->result=1;f.job.Tick(6000);}}
f.item.armed=true;f.job.Tick(10000);assert(!f.job.Busy()&&f.service.m_MineStock.empty()&&f.job.m_Delivered==0);}
{F f;f.Mine();f.Reach();f.job.Tick(5000);auto*leaf=f.job.m_Move;f.item.armed=true;f.job.Tick(6000);assert(f.job.m_State==7&&f.crew.LogisticsReservation>0);leaf->unknown=false;leaf->confirmed=true;leaf->result=1;f.job.Tick(7000);assert(!f.job.Busy()&&f.service.m_MineStock.empty()&&f.job.m_Delivered==0&&f.job.m_Spent.Count()==1);}
{F f;f.Mine();f.Reach();f.job.Tick(5000);f.job.m_Move->mineCargo=false;assert(!f.job.TransferValid(f.job.m_Move));}
{F f;f.Mine();f.Reach();f.job.Tick(5000);f.job.m_Move->unknown=false;f.job.m_Move->result=1;f.job.Tick(6000);f.job.Tick(7000);f.service.mineNeeded=false;assert(!f.job.ClaimDelivery(f.job.m_Move));f.job.m_Move->unknown=false;f.job.m_Move->confirmed=true;f.job.m_Move->result=1;f.job.Tick(8000);assert(f.service.m_MineStock.empty()&&f.job.m_Delivered==0);}
for(int kind=0;kind<5;kind++){F f;f.Mine();if(kind==0)f.item.armed=true;if(kind==1)f.item.defaultArmed=true;if(kind==2)f.item.alive=false;if(kind==3)f.item.collision=false;if(kind==4)f.service.mineNeeded=false;f.job.Plan(0);assert(!f.job.Busy()&&f.hq.orders==0&&f.hq.claims==0&&f.job.m_Attempts==0);}
// Actual Plan must enumerate worker/item pairs: the first fit original can
// carry the wrong weapon while a second original can use this exact magazine.
{F f;f.worker.well=2;f.second.well=1;f.sampler.members={&f.worker,&f.second};f.job.Plan(0);assert(f.job.m_State==1&&f.hq.claims==1&&f.hq.orders==1&&"compatible second original must permit planning despite incompatible first original");assert(f.job.m_Worker==&f.second&&f.job.m_WorkerSlot==1&&f.job.m_Item==&f.item&&f.job.m_Attempts==1);}
{F f;f.worker.well=2;f.second.well=1;f.sampler.members={&f.second,&f.worker};f.Start();assert(f.job.m_Worker==&f.second&&f.job.m_WorkerSlot==0);}
// Bad first originals do not hide a later valid original; if no eligible
// compatible member remains, planning must not reserve or issue a command.
for(int k=0;k<11;k++)for(bool later:{false,true}){F f;Group foreign;f.sampler.members={&f.worker};
if(k==0)f.sampler.members[0]=nullptr;
if(k==1)f.worker.attributed=false;
if(k==2)f.worker.group=&foreign;
if(k==3)f.worker.player=true;
if(k==4)f.worker.alive=false;
if(k==5)f.worker.aboard=true;
if(k==6)f.worker.agent=nullptr;
if(k==7)f.workerAgent.m_UtilityComponent=nullptr;
if(k==8)f.workerUtility.m_AIInfo=false;
if(k==9)f.worker.faction=2;
if(k==10)f.worker.equipmentEligible=false;
if(later)f.sampler.members.Insert(&f.second);
f.job.Plan(0);
if(later){assert(f.job.Busy()&&f.job.m_Worker==&f.second&&f.job.m_WorkerSlot==1&&f.hq.claims==1&&f.hq.orders==1&&f.job.m_Attempts==1);}
else{assert(!f.job.Busy()&&f.hq.claims==0&&f.hq.orders==0&&f.job.m_Attempts==0&&f.job.m_Spent.empty()&&f.crew.LogisticsReservation==0&&f.donor.LogisticsReservation==0&&f.vehicle.SupplyToken==0);}
}
for(int k=0;k<5;k++){F f;f.sampler.members={&f.worker,&f.second};if(k==0)f.worker.well=f.second.well=2;if(k==1)f.item.rounds=0;if(k==2)f.item.maxRounds=0;if(k==3)f.item.rounds=31;if(k==4)f.worker.compatible=f.second.compatible=false;f.job.Plan(0);assert(!f.job.Busy()&&f.hq.claims==0&&f.hq.orders==0&&f.job.m_Attempts==0&&f.job.m_Spent.empty());}
{F f;f.sampler.owns=false;f.job.Plan(0);assert(!f.job.Busy()&&f.hq.claims==0&&f.hq.orders==0&&f.job.m_Attempts==0);}
{F f;f.sampler.members.resize(33,&f.worker);f.job.Plan(0);assert(!f.job.Busy()&&f.hq.claims==0&&f.hq.orders==0&&f.job.m_Attempts==0);}
// No new stock or commands on missing capacity/camp/worker/report/claim.
for(int k=0;k<8;k++){F f;if(k==0)f.service.available=false;if(k==1)f.site.items.clear();if(k==2)f.crew.eligible=false;if(k==3)f.hq.watch.report.valid=false;if(k==4)f.hq.claim=false;if(k==5)f.item.compatible=false;if(k==6)f.job.m_Original.clear();if(k==7)f.service.needed=false;f.job.Plan(0);assert(!f.job.Busy()&&f.hq.orders==0&&f.job.m_Spent.empty());}
{F f;f.Start();f.hq.route.outcome=-1;f.job.Tick(0);assert(!f.job.Busy()&&f.job.walks==0&&!f.vehicle.SupplyHeld&&f.job.m_Spent.empty());}
// Complete actual state sequence; first proof retires before delivery callback.
{F f;f.Reach();f.job.Tick(5000);auto*pickup=f.job.m_Move;assert(pickup&&!pickup->Delivery());pickup->unknown=false;pickup->confirmed=true;pickup->result=1;f.job.Tick(6000);assert(f.job.m_State==5&&!f.job.m_Move&&f.job.walks==2);f.job.Tick(7000);auto*delivery=f.job.m_Move;assert(delivery&&delivery!=pickup&&delivery->Delivery());delivery->unknown=false;delivery->confirmed=true;delivery->result=1;f.job.Tick(8000);assert(f.service.m_Stock.Count()==1&&f.job.m_Delivered==1&&f.job.m_State==6);f.job.Tick(9000);assert(!f.job.Busy()&&!f.vehicle.SupplyHeld&&f.job.m_Spent.Count()==1);}
for(bool second:{false,true}){F f;f.Reach();f.job.Tick(5000);if(second){f.job.m_Move->unknown=false;f.job.m_Move->result=1;f.job.Tick(6000);f.job.Tick(7000);}auto*leaf=f.job.m_Move;int walks=f.job.walks;f.job.Stop();assert(f.job.m_State==7&&f.vehicle.SupplyHeld&&f.crew.LogisticsReservation>0);f.job.Tick(200000);assert(f.job.m_State==7&&f.service.m_Stock.empty()&&f.job.walks==walks);leaf->unknown=false;leaf->confirmed=true;f.job.Tick(200001);assert(!f.job.Busy()&&f.service.m_Stock.empty()&&f.job.m_Spent.Count()==1&&!f.vehicle.SupplyHeld);f.job.Plan(300000);assert(!f.job.Busy());}
// Expiry never extends the job; late proof does not adopt cargo.
{F f;f.Reach();f.job.Tick(5000);f.job.Tick(f.job.m_Deadline);assert(f.job.m_State==7);f.job.m_Move->unknown=false;f.job.Tick(999999);assert(!f.job.Busy()&&f.service.m_Stock.empty());}
// Target lifetime96 allowance: no eviction of spent/deleted identities.
{F f;f.service.m_Stock.resize(96,nullptr);f.job.Plan(0);assert(!f.job.Busy()&&f.hq.orders==0);}
// Filling the final lifetime slot does not invalidate the return phase.
{F f;f.service.m_Stock.resize(95,nullptr);f.Reach();f.job.Tick(5000);f.job.m_Move->unknown=false;f.job.m_Move->result=1;f.job.Tick(6000);f.job.Tick(7000);f.job.m_Move->unknown=false;f.job.m_Move->confirmed=true;f.job.m_Move->result=1;f.job.Tick(8000);assert(f.service.m_Stock.Count()==96&&f.job.m_State==6);f.truck.pos={3};f.job.Tick(9000);assert(f.job.m_State==6&&f.vehicle.SupplyHeld);f.truck.pos={20};f.job.Tick(10000);assert(!f.job.Busy());}
// A completed physical move cannot import wrong/previously-spent/foreign identity.
{F f;f.Reach();f.job.Tick(5000);auto*l=f.job.m_Move;l->unknown=false;l->result=1;f.job.Tick(6000);f.job.Tick(7000);f.job.m_Move->unknown=false;f.job.m_Move->confirmed=true;Entity foreign;assert(!f.service.AdmitDepot(&f.job,&foreign));f.service.m_Spent.Insert(&f.item);assert(!f.service.AdmitDepot(&f.job,&f.item));}
}
'''.replace('METHODS',methods).replace('ADMISSION',admit.replace('bool AdmitDepot(', 'bool ERR_InfantryResupply::AdmitDepot(').replace('bool AdmitDepotMine(', 'bool ERR_InfantryResupply::AdmitDepotMine(')))
print('PASS: actual depot mixed-roster worker/item selection, ownership/refusal and radio/planning/two-leg state transitions, fixed deadline, late proof quarantine, finite import and no adoption after Stop')
@@ -0,0 +1,47 @@
"""Actual HQ cargo-class reservation and service demand; native availability doubled."""
import os,re
from pathlib import Path
from policy_harness import ROOT,body,run
H=Path(os.environ.get('ERR_DEPOT_HQ_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_GroundDepotHQ.c'))
S=Path(os.environ.get('ERR_INFANTRY_RESUPPLY_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_InfantryResupply.c'))
def cpp(s):
s=s.replace('protected ','').replace('null','nullptr').replace('int committed;', 'int committed = 0;')
for typ in ('ERR_HQUnit','ERR_InfantryResupply','ERR_ConvoyVehicle'):
s=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',s)
for name in ('m_Mode','crew','donor','service','truck'):
s=re.sub(r'\b'+name+r'\.',name+'->',s)
s=s.replace('Replication.IsServer()', 'server').replace('ERR_GameMode.Get()', 'current')
s=s.replace('foreach (IEntity item : m_Spent)', 'for (IEntity item : m_Spent)')
return s
hq='\n'.join(cpp(body(H,x)) for x in ('bool ReserveGroundDepot(', 'void ReleaseGroundDepot('))
demand='\n'.join(cpp(body(S,x)) for x in ('bool DepotNeeded(', 'bool DepotMineNeeded('))
run(r'''
#include <cassert>
#include <vector>
#include <algorithm>
struct Entity{};using IEntity=Entity*;
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}};
struct Group{};struct HQ;
struct Mode{HQ*owner=nullptr;bool active=true;bool Active(){return active;}HQ*Command(){return owner;}};
bool server=true;Mode*current=nullptr;
struct ERR_HQUnit{struct Group*Group=nullptr;bool HomeGuard=false,ReservedForSupport=false,Task=false,PendingTask=false,PendingCheckin=false,PendingConvoyOrder=false;int LogisticsReservation=0;};
struct ERR_ConvoyVehicle{struct Group*Group=nullptr;int SupplyToken=0;bool SupplyHeld=false;};
struct ERR_InfantryResupply{bool magAvailable=true,mineAvailable=true,captured=true;int m_DepotImports=0,m_DepotMineImports=0;Array<IEntity>m_Stock,m_MineStock,m_Spent;ERR_ConvoyVehicle*truck=nullptr;bool DepotAvailable(){return magAvailable;}bool DepotMineAvailable(){return mineAvailable;}bool CaptureMines(){return captured;}ERR_ConvoyVehicle*DepotTruck(){return truck;}
DEMAND
};
struct HQ{Mode*m_Mode=nullptr;bool m_Stopping=false,eligible=true,reserve=true;Array<ERR_HQUnit*>m_Units;int claims=0,releases=0;bool MountedLogisticsEligible(ERR_HQUnit*){return eligible;}bool ReserveLogistics(Group*g,int token){if(!reserve)return false;for(auto*u:m_Units)if(u->Group==g){if(u->LogisticsReservation)return false;u->LogisticsReservation=token;claims++;return true;}return false;}void ReleaseLogistics(Group*g,int token){for(auto*u:m_Units)if(u->Group==g&&u->LogisticsReservation==token){u->LogisticsReservation=0;releases++;}}
HQMETHODS
};
struct F{Mode mode;HQ h;Group cg,dg;ERR_HQUnit crew,donor;ERR_ConvoyVehicle truck;ERR_InfantryResupply s;Entity mine,mag,foreign;F(){server=true;current=&mode;mode.owner=&h;h.m_Mode=&mode;crew.Group=&cg;donor.Group=truck.Group=&dg;h.m_Units={&crew,&donor};s.truck=&truck;s.m_Stock={&mag};s.m_MineStock={&mine};}void Unclaimed(){assert(h.claims==0&&crew.LogisticsReservation==0&&donor.LogisticsReservation==0&&truck.SupplyToken==0&&!truck.SupplyHeld);}};
int main(){
// Mine-only expenditure authorizes mine cargo only. Magazine-only is inverse.
for(bool mines:{false,true})for(bool cargo:{false,true}){F f;f.s.m_Spent={mines?&f.mine:&f.mag};bool accepted=f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300001,cargo);assert(accepted==(mines==cargo));if(!accepted)f.Unclaimed();else{assert(f.h.claims==1&&f.crew.LogisticsReservation==300001&&f.donor.LogisticsReservation==300001&&f.truck.SupplyToken==300001);assert(!f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300002,cargo));f.truck.SupplyHeld=true;f.h.ReleaseGroundDepot(&f.crew,&f.donor,&f.truck,300002);assert(f.truck.SupplyToken==300001&&f.truck.SupplyHeld);f.h.ReleaseGroundDepot(&f.crew,&f.donor,&f.truck,300001);assert(!f.crew.LogisticsReservation&&!f.donor.LogisticsReservation&&!f.truck.SupplyToken&&!f.truck.SupplyHeld);}}
// Null/deleted/unrelated spent identities and satisfied imported demand never count.
for(bool mines:{false,true})for(int k=0;k<4;k++){F f;if(k==0){f.s.m_Spent={nullptr};f.s.m_Stock.push_back(nullptr);f.s.m_MineStock.push_back(nullptr);}if(k==1)f.s.m_Spent={&f.foreign};if(k==2){f.s.m_Spent={mines?&f.mine:&f.mag};if(mines)f.s.m_DepotMineImports=1;else f.s.m_DepotImports=1;}if(k==3){f.s.m_Spent={mines?&f.mine:&f.mag};if(mines)f.s.mineAvailable=false;else f.s.magAvailable=false;}assert(!f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300001,mines));f.Unclaimed();}
// Existing authority, task ownership and token gates apply equally to mine jobs.
for(int k=0;k<15;k++){F f;f.s.m_Spent={&f.mine};int token=300001;if(k==0)server=false;if(k==1)f.h.m_Stopping=true;if(k==2)current=nullptr;if(k==3)f.mode.active=false;if(k==4)f.mode.owner=nullptr;if(k==5)token=300000;if(k==6)token=300097;if(k==7)f.h.m_Units.clear();if(k==8)f.h.eligible=false;if(k==9)f.crew.HomeGuard=true;if(k==10)f.crew.ReservedForSupport=true;if(k==11)f.crew.PendingCheckin=true;if(k==12)f.crew.PendingConvoyOrder=true;if(k==13)f.h.reserve=false;if(k==14)f.truck.Group=&f.cg;assert(!f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,token,true));f.Unclaimed();}
// Legacy default remains magazine demand; distinct import counters don't cross classes.
{F f;f.s.m_Spent={&f.mag,&f.mine};f.s.m_DepotMineImports=1;assert(!f.s.DepotMineNeeded()&&f.s.DepotNeeded());assert(f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300001));}
}
'''.replace('DEMAND',demand).replace('HQMETHODS',hq))
print('PASS: actual HQ mine/magazine claim separation, real demand methods, exact token cleanup and original authority gates; native availability doubled')
@@ -0,0 +1,131 @@
"""Actual authored-stock capture/access and exact post-delivery stock admission."""
import os,re
from pathlib import Path
from policy_harness import ROOT,body,run
from test_finite_magazine_reservation import translated_reservation
B=Path(os.environ.get('ERR_GROUND_DEPOT_ROOT',ROOT))
S=Path(os.environ.get('ERR_SITE_SERVICE_SOURCE',B/'addons/core/Scripts/Game/ERR/00_Core/ERR_SiteService.c'))
I=Path(os.environ.get('ERR_INFANTRY_RESUPPLY_SOURCE',B/'addons/core/Scripts/Game/ERR/10_AI/ERR_InfantryResupply.c'))
L=Path(os.environ.get('ERR_GROUND_DEPOT_LOADING_SOURCE',B/'addons/core/Scripts/Game/ERR/10_AI/ERR_GroundDepotLoading.c'))
assert 'int DepotItemCount(' in S.read_text() and 'bool AdmitDepotMine(' in I.read_text(), 'finite authored camp mine provenance/import API is absent'
# Read the actual authored configuration, not a duplicated stock fixture.
conf=(B/'addons/core/Configs/ERR/EveronSites.conf').read_text()
pmn='{B05A816C0BF50802}Prefabs/Weapons/Explosives/Mine_PMN4/Mine_PMN4.et'
camps=[]
for match in re.finditer(r' ERR_SiteDefinition \{',conf):
end=match.end();depth=1
while depth:
if conf[end]=='{':depth+=1
elif conf[end]=='}':depth-=1
end+=1
block=conf[match.start():end]
eligible=bool(re.search(r'^ Kind 3$',block,re.M)) and not re.search(r'^ RevealOnEscape 1$',block,re.M)
stocks=re.findall(r'ERR_SiteStock \{ Prefab "([^"\n]+)" Count (\d+)([^}]*?) \}',block)
mines=[row for row in stocks if row[0]==pmn]
if eligible:
assert len(mines)==1 and mines[0][1]=='2' and 'TargetId' not in mines[0][2]
camps.append(re.search(r'Id "([^"]+)"',block).group(1))
else:assert not mines
assert len(camps)==5
assert 'ERR_InfantryMineTransfer' not in S.read_text(), 'Core must not depend on the AI mine transfer layer'
source=S.read_text();start=source.index(' if (spec.Kind == ERR_LocationKind.OUTPOST');capture=source[start:source.index(' placement.Item = item;',start)]
access='\n'.join(body(S,k) for k in ('int DepotMagazineCount(', 'int DepotMineCount(', 'int DepotItemCount(', 'IEntity DepotItem(', 'void DepotStock(', 'IEntity DepotMagazine(', 'bool DepotOriginal('))
admit='\n'.join(body(I,k) for k in ('bool DepotCurrent(', 'bool DepotAvailable(', 'bool DepotNeeded(', 'bool AdmitDepot(', 'bool DepotMineAvailable(', 'bool DepotMineNeeded(', 'bool AdmitDepotMine(', 'protected bool CaptureMines('))
delivered=body(L,'bool DeliveredTo(')
def adapt(s):
s=s.replace('array<IEntity>','Array<IEntity>').replace('out Array<IEntity> items','Array<IEntity>& items').replace('ERR_SiteRuntime site','Site* site').replace('ERR_GroundDepotLoading job','Loading* job').replace('ERR_InfantryResupply service','Service* service')
s=s.replace('protected ', '').replace('ERR_SupplyConvoyTask supply = ERR_SupplyConvoyTask.Cast(m_Convoy);','Supply* supply = m_Convoy;')
s=s.replace('InventoryItemComponent carried = InventoryItemComponent.Cast(item.FindComponent(InventoryItemComponent));','InventoryItem* carried = item->inventoryItem;')
s=s.replace('foreach (IEntity item : m_MineStock)', 'for (IEntity item : m_MineStock)')
s=s.replace('ERR_InfantryMineTransfer.', 'ERR_InfantryMineTransfer::').replace('ERR_InfantryAmmoTransfer.', 'ERR_InfantryAmmoTransfer::')
for name in ('supply','m_MineBatch','carried'):s=s.replace(name+'.',name+'->')
s=s.replace('GetParentSlot().','GetParentSlot()->')
for name in ('site','spec','stock','item','m_Stock','m_Spent','m_Mounted','m_Truck','job','m_Move','m_Reservation'):
if name not in ('m_Stock','m_Spent'): s=s.replace(name+'.',name+'->')
s=s.replace('site->Definition.', 'site->Definition->').replace('site->Responders.', 'site->Responders->')
s=s.replace('stock->TargetId.IsEmpty()','stock->TargetId.empty()').replace('item->FindComponent(BaseMagazineComponent)','item->magazine')
s=s.replace('foreach (IEntity item : m_Spent)', 'for (IEntity item : m_Spent)').replace('int committed;', 'int committed=0;')
s=s.replace('Replication.IsServer()','server').replace('ERR_PrepareResult.READY','1').replace('ERR_LocationKind.OUTPOST','3').replace('null','nullptr')
return s
run(r'''
#include <cassert>
#include <vector>
#include <algorithm>
#include <string>
using string=std::string;bool server=true;
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool IsEmpty(){return this->empty();}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Insert(T x){this->push_back(x);}void RemoveItem(T x){this->erase(std::remove(this->begin(),this->end(),x),this->end());}};
struct Entity;using IEntity=Entity*;
struct Slot{IEntity attached=nullptr;IEntity GetAttachedEntity(){return attached;}};
struct InventoryItem{Slot* slot=nullptr;Slot* GetParentSlot(){return slot;}};
struct Entity{bool magazine=true,ready=false,stored=true;Slot slot;InventoryItem inventory;InventoryItem*inventoryItem=&inventory;Entity(){slot.attached=this;inventory.slot=&slot;}};
// Native ready predicate and storage graph are doubled; actual readiness is separately tested by mine-transfer suites.
struct ERR_InfantryMineTransfer{static bool ReadyMine(IEntity item){return item&&item->ready;}};
struct ERR_InfantryAmmoTransfer{static bool StoredUnder(IEntity item,IEntity){return item&&item->stored;}};
struct Def{int Kind=3;bool RevealOnEscape=false;};struct Stock{string TargetId,Prefab;};
struct Responders{bool Group=true;};struct Site{Def* Definition=nullptr;IEntity Container=nullptr;struct Responders* Responders=nullptr;Array<IEntity>DepotMagazines,DepotMines;};
struct Sites{bool m_Stopped=false;int m_State=0;Array<Site*>m_Sites;Array<IEntity>m_Entities;bool Owns(IEntity x){return m_Entities.Contains(x);}
''' + adapt(access)+ '\nvoid Capture(Def* spec,Stock* stock,Site* site,IEntity item){'+adapt(capture)+r'''}
};
''' + translated_reservation()+r'''
struct Service;
struct Proof{bool done=true,delivery=true,mine=false;bool MineCargo(){return mine;}bool Confirmed(){return done;}bool Delivery(){return delivery;}};
struct Loading{bool m_Imported=false,valid=true,m_MineCargo=false;int m_State=5;Service* m_Service=nullptr;IEntity m_Item=nullptr;Proof* m_Move=nullptr;ERR_FiniteMagazineReservation* m_Reservation=nullptr;bool Valid(){return valid;}bool DeliveredTo(Service*,IEntity,bool=false);};
struct Mounted{bool busy=false;bool Busy(){return busy;}};
struct Truck{IEntity Entity=nullptr;};
struct Batch{bool complete=true;Array<IEntity>items;bool Complete(){return complete;}int Count(){return items.Count();}IEntity At(int index){return items[index];}};
struct Supply{Batch*MineStock=nullptr;};
struct Service{Supply*m_Convoy=nullptr;Batch*m_MineBatch=nullptr;bool m_MineStockCaptured=false;Array<IEntity>m_MineStock;int m_DepotMineImports=0;bool current=true,truckValid=true,unresolved=false,m_Move=false,m_MineMove=false;int m_State=1,audits=0,m_DepotImports=0;Array<IEntity>m_Stock,m_Spent,cargo;Mounted* m_Mounted=nullptr;Truck* m_Truck=nullptr;bool Current(){return current;}bool Unresolved(){return unresolved;}bool TruckValid(bool endpoint){assert(endpoint);return truckValid;}bool Contains(IEntity,IEntity item){return cargo.Contains(item);}void Audit(string){audits++;}
''' + adapt(admit)+r'''};
''' + adapt(delivered).replace('bool DeliveredTo(', 'bool Loading::DeliveredTo(').replace('bool mineCargo = false','bool mineCargo')+r'''
struct F{Entity cache,item,foreign,truck;Def def;Stock stock;Responders responders;Site site;Sites sites;Array<IEntity>original,spent;ERR_FiniteMagazineReservation reservation;Service service;Loading job;Proof proof;Truck vehicle;Mounted mounted;
F():reservation(&original,&spent,&item){site.Definition=&def;site.Container=&cache;site.Responders=&responders;sites.m_Sites={&site};sites.m_Entities={&cache};sites.Capture(&def,&stock,&site,&item);original={&item};assert(reservation.Reserve()&&reservation.Commit());job.m_Reservation=&reservation;job.m_Move=&proof;job.m_Item=&item;job.m_Service=&service;vehicle.Entity=&truck;service.m_Truck=&vehicle;service.m_Mounted=&mounted;service.cargo={&item};}
};
struct M:F{Entity initial;Batch batch;Supply supply;
M(){item.magazine=false;item.ready=true;initial.magazine=false;initial.ready=true;batch.items={&initial};supply.MineStock=&batch;service.m_Convoy=&supply;service.m_MineBatch=&batch;service.m_Spent={&initial};job.m_MineCargo=true;proof.mine=true;}
};
int main(){
// Authored inert mines join detached startup provenance, without replacing magazine APIs.
{F f;f.sites.m_State=1;f.stock.Prefab="{B05A816C0BF50802}Prefabs/Weapons/Explosives/Mine_PMN4/Mine_PMN4.et";Entity mine;mine.magazine=false;mine.ready=true;f.sites.Capture(&f.def,&f.stock,&f.site,&mine);assert(f.sites.DepotMagazineCount(&f.site)==1&&f.sites.DepotMineCount(&f.site)==1&&f.sites.DepotItemCount(&f.site)==2);assert(f.sites.DepotItem(&f.site,1)==&mine&&f.sites.DepotOriginal(&f.site,&mine));Array<IEntity>out;f.sites.DepotStock(&f.site,out);out.clear();assert(f.sites.DepotItemCount(&f.site)==2);Entity other;other.magazine=false;other.ready=true;assert(!f.sites.DepotOriginal(&f.site,&other));f.sites.Capture(&f.def,&f.stock,&f.site,&other);Entity third;third.magazine=false;third.ready=true;f.sites.Capture(&f.def,&f.stock,&f.site,&third);assert(f.sites.DepotMineCount(&f.site)==2&&!f.sites.DepotOriginal(&f.site,&third));}
for(int bad=0;bad<4;bad++){F f;f.item.magazine=false;f.item.ready=true;f.stock.Prefab="{B05A816C0BF50802}Prefabs/Weapons/Explosives/Mine_PMN4/Mine_PMN4.et";f.site.DepotMagazines.clear();if(bad==0)f.def.RevealOnEscape=true;if(bad==1)f.def.Kind=4;if(bad==2)f.stock.TargetId="radio";if(bad==3)f.stock.Prefab="foreign";f.sites.Capture(&f.def,&f.stock,&f.site,&f.item);assert(f.site.DepotMines.empty());}
{M f;assert(f.service.DepotMineNeeded()&&!f.service.DepotNeeded());assert(f.service.AdmitDepotMine(&f.job,&f.item));assert(f.service.m_MineStock.Count()==2&&f.service.m_DepotMineImports==1&&f.service.m_Stock.empty());assert(!f.service.DepotMineNeeded()&&!f.service.AdmitDepotMine(&f.job,&f.item));assert(f.spent.Count()==1&&f.service.m_Spent.Count()==1);ERR_FiniteMagazineReservation next(&f.service.m_MineStock,&f.service.m_Spent,&f.item);assert(next.Reserve()&&next.Commit());assert(f.service.DepotMineNeeded());}
// Known mine expenditure only; missing/deleted/magazine identities never become mine demand.
{M f;f.service.m_Spent.clear();assert(!f.service.DepotMineNeeded());f.service.m_Spent={nullptr,&f.foreign};f.service.m_Stock={&f.foreign};assert(f.service.DepotNeeded()&&!f.service.DepotMineNeeded());f.service.m_MineStock={nullptr};assert(!f.service.DepotMineNeeded());}
for(int bad=0;bad<21;bad++){M f;assert(f.service.DepotMineNeeded());if(bad==0)f.service.current=false;if(bad==1)f.service.m_State=7;if(bad==2)f.batch.complete=false;if(bad==3)f.supply.MineStock=nullptr;if(bad==4)f.service.m_MineBatch=nullptr;if(bad==5)f.service.m_MineStock.resize(96,&f.initial);if(bad==6)f.service.m_Spent.resize(96,&f.initial);if(bad==7)f.item.ready=false;if(bad==8)f.service.m_Stock.Insert(&f.item);if(bad==9)f.service.m_Spent.Insert(&f.item);if(bad==10)f.service.cargo.clear();if(bad==11)f.item.stored=false;if(bad==12)f.item.inventoryItem=nullptr;if(bad==13)f.item.inventory.slot=nullptr;if(bad==14)f.item.slot.attached=&f.foreign;if(bad==15)f.job.m_MineCargo=false;if(bad==16)f.proof.mine=false;if(bad==17)f.job.m_State=7;if(bad==18)f.job.valid=false;if(bad==19)f.proof.done=false;if(bad==20)f.service.m_Spent.clear();int before=f.service.m_MineStock.Count();assert(!f.service.AdmitDepotMine(&f.job,&f.item));assert(f.service.m_MineStock.Count()==before&&f.service.m_DepotMineImports==0);}
{M f;f.batch.items.clear();f.service.m_Spent.clear();assert(!f.service.DepotMineNeeded()&&!f.service.AdmitDepotMine(&f.job,&f.item));}
{M f;assert(f.service.DepotMineNeeded());f.service.m_MineStock.resize(95,&f.initial);assert(f.service.AdmitDepotMine(&f.job,&f.item));assert(f.service.m_MineStock.Count()==96&&f.service.DepotCurrent()&&!f.service.DepotMineAvailable());}
{F f;Array<IEntity>out;f.sites.DepotStock(&f.site,out);assert(out.empty());f.sites.m_State=1;f.sites.DepotStock(&f.site,out);assert(out.Count()==1&&out[0]==&f.item);out[0]=&f.foreign;out.clear();assert(f.sites.DepotOriginal(&f.site,&f.item)&&!f.sites.DepotOriginal(&f.site,&f.foreign));assert(f.sites.DepotMagazine(&f.site,-1)==nullptr&&f.sites.DepotMagazine(&f.site,1)==nullptr);f.sites.m_Stopped=true;assert(!f.sites.DepotOriginal(&f.site,&f.item));}
for(int kind=0;kind<6;kind++){F f;f.site.DepotMagazines.clear();if(kind==0)f.def.RevealOnEscape=true;if(kind==1)f.def.Kind=4;if(kind==2)f.stock.TargetId="radio";if(kind==3)f.item.magazine=false;if(kind==4)f.site.DepotMagazines.resize(96,&f.foreign);f.sites.Capture(&f.def,&f.stock,&f.site,&f.item);assert(f.site.DepotMagazines.Contains(&f.item)==(kind==5));}
for(int bad=0;bad<7;bad++){F f;f.sites.m_State=1;if(bad==0)server=false;if(bad==1)f.sites.m_Sites.clear();if(bad==2)f.site.Container=nullptr;if(bad==3)f.sites.m_Entities.clear();if(bad==4)f.site.Responders=nullptr;if(bad==5)f.responders.Group=false;if(bad==6)f.site.DepotMagazines.resize(97,&f.item);assert(f.sites.DepotMagazineCount(&f.site)==0);server=true;}
{F f;assert(f.service.AdmitDepot(&f.job,&f.item));assert(f.service.m_Stock.Count()==1&&f.service.m_Stock[0]==&f.item&&f.service.audits==1);assert(!f.service.AdmitDepot(&f.job,&f.item));ERR_FiniteMagazineReservation outgoing(&f.service.m_Stock,&f.service.m_Spent,&f.item);assert(outgoing.Reserve()&&outgoing.Commit());assert(f.spent.Count()==1&&f.service.m_Spent.Count()==1);assert(!f.service.AdmitDepot(&f.job,&f.item));}
// Deleted identities and mine-only spent entries cannot create magazine demand.
{F f;f.service.m_Stock={nullptr};f.service.m_Spent={nullptr,&f.foreign};assert(!f.service.DepotNeeded());f.service.m_Stock.Insert(&f.foreign);assert(f.service.DepotNeeded());f.service.m_DepotImports=1;assert(!f.service.DepotNeeded());Entity another;f.service.m_Stock.Insert(&another);f.service.m_Spent.Insert(&another);assert(f.service.DepotNeeded());}
// Final lifetime slot can complete delivery and departure; admission then closes.
{F f;f.service.m_Stock.resize(95,&f.foreign);f.service.m_Spent={&f.foreign};assert(f.service.DepotNeeded());assert(f.service.AdmitDepot(&f.job,&f.item));assert(f.service.m_Stock.Count()==96&&f.service.m_DepotImports==1);assert(f.service.DepotCurrent()&&!f.service.DepotAvailable()&&!f.service.DepotNeeded());}
for(int bad=0;bad<21;bad++){F f;
if(bad==0)f.service.current=false;
if(bad==1)f.service.m_State=7;
if(bad==2)f.service.m_Move=true;
if(bad==3)f.service.m_MineMove=true;
if(bad==4)f.service.unresolved=true;
if(bad==5)f.mounted.busy=true;
if(bad==6)f.service.truckValid=false;
if(bad==7)f.service.m_Stock.resize(96,&f.foreign);
if(bad==8)f.service.m_Spent.resize(96,&f.foreign);
if(bad==9)f.service.m_Spent={&f.item};
if(bad==10)f.service.cargo.clear();
if(bad==11)f.job.m_Imported=true;
if(bad==12)f.job.m_State=7;
if(bad==13)f.job.m_Service=nullptr;
if(bad==14)f.job.m_Item=&f.foreign;
if(bad==15)f.proof.done=false;
if(bad==16)f.proof.delivery=false;
if(bad==17)f.job.m_Move=nullptr;
if(bad==18)f.job.m_Reservation=nullptr;
if(bad==19)f.job.valid=false;
if(bad==20)f.spent.clear();
int before=f.service.m_Stock.Count();assert(!f.service.AdmitDepot(&f.job,&f.item));assert(f.service.m_Stock.Count()==before&&f.service.audits==0);}
{F f;f.job.m_State=7;f.proof.done=true;assert(!f.service.AdmitDepot(&f.job,&f.item));f.job.m_State=5;f.job.valid=false;assert(!f.service.AdmitDepot(&f.job,&f.item));}
}
''')
print('PASS: actual mine/magazine provenance and separated finite mine imports; actual authored identity capture, READY-only detached provenance, same shared stock admission, completed exact two-leg proof, lifetime caps and Stop no late adoption')
@@ -0,0 +1,105 @@
"""Execute complete actual finite two-leg transfer with native inventory boundaries."""
import os,re
from pathlib import Path
from policy_harness import ROOT,run
from test_finite_magazine_reservation import translated_reservation
p=Path(os.environ.get('ERR_GROUND_DEPOT_TRANSFER_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_GroundDepotTransfer.c'))
s=p.read_text();code=s[s.index('class ERR_GroundDepotTransfer\n'):]
code=re.sub(r'//[^\n]*','',code).replace('protected ','').replace('ref ','').replace('class ','struct ').replace('void ERR_GroundDepotTransfer(','ERR_GroundDepotTransfer(').replace('array<','Array<').replace('null','nullptr')
for kind,field in {'InventoryStorageManagerComponent':'inventory','InventoryItemComponent':'item','BaseMagazineComponent':'magazine','DamageManagerComponent':'damage'}.items():
code=re.sub(kind+r'\.Cast\(([^;\n]*?)\.FindComponent\('+kind+r'\)\)',lambda m:m[1]+'.'+field,code)
code=code.replace('.FindComponent('+kind+')','.'+field)
for name in ('EStoragePurpose','ERR_ForceRules','ERR_InfantryAmmoTransfer','ERR_InfantryMineTransfer'):code=code.replace(name+'.',name+'::')
for name in ('m_Owner','m_From','m_To','m_Item','m_Source','m_Destination','m_FromSlot','m_FromStorage','m_ToStorage','m_Reservation','m_Callback','source','destination','item','inventoryItem','magazine','damage','inventory','storage','slot'):
code=re.sub(r'\b'+name+r'\.',name+'->',code)
code=code.replace(').',')->').replace('ERR_FiniteMagazineReservation ', 'ERR_FiniteMagazineReservation* ').replace('ERR_GroundDepotCallback ', 'ERR_GroundDepotCallback* ')
code=re.sub(r'\b(bool|int|IEntity|ERR_GroundDepotLoading|InventoryStorageManagerComponent|InventoryStorageSlot|BaseInventoryStorageComponent|ERR_FiniteMagazineReservation\*|ERR_GroundDepotCallback\*) (\w+);',r'\1 \2{};',code)
code=code.replace('\n}\n','\n};\n')
callbacks=[]
for n in ('OnComplete','OnAllComplete','OnFailed','OnAllFailed'):
b=re.search('protected override void '+n+r'\(\) (\{[^\n]+\})',s)[1]
callbacks.append('void ERR_GroundDepotCallback::'+n+'() '+b.replace('Transfer.','Transfer->'))
pre=r'''
#include <cassert>
#include <cmath>
#include <vector>
#include <algorithm>
#include <functional>
#include <limits>
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Insert(T x){this->push_back(x);}void RemoveItem(T x){this->erase(std::remove(this->begin(),this->end(),x),this->end());}};
struct Entity;struct Inventory;struct Slot;struct Storage;struct Magazine;struct Owner;
using IEntity=Entity*;using InventoryStorageManagerComponent=Inventory*;using InventoryStorageSlot=Slot*;using BaseInventoryStorageComponent=Storage*;using BaseMagazineComponent=Magazine*;using ERR_GroundDepotLoading=Owner*;
struct Item{Slot*slot=nullptr;Slot*GetParentSlot(){return slot;}};using InventoryItemComponent=Item*;
struct Damage{bool destroyed=false;bool IsDestroyed(){return destroyed;}};using DamageManagerComponent=Damage*;
struct Entity{Entity*parent=nullptr;Item*item=nullptr;Magazine*magazine=nullptr;Damage*damage=nullptr;Inventory*inventory=nullptr;bool mine=false,armed=false,defaultArmed=false,collision=true;};
struct Slot{Storage*storage=nullptr;IEntity attached=nullptr;Storage*GetStorage(){return storage;}IEntity GetAttachedEntity(){return attached;}};
struct Storage{IEntity owner=nullptr;IEntity GetOwner(){return owner;}};
struct Magazine{bool used=false,well=true;int rounds=30,capacity=30;bool IsUsed(){return used;}bool GetMagazineWell(){return well;}int GetAmmoCount(){return rounds;}int GetMaxAmmoCount(){return capacity;}};
struct ERR_ForceRules{static bool Finite(float x){return std::isfinite(x);}};
struct ERR_InfantryAmmoTransfer{static bool StoredUnder(IEntity e,IEntity root){for(int i=0;e&&i<16;i++,e=e->parent)if(e==root)return true;return false;}};
// ReadyMine is an explicit native-component boundary; its complete implementation
// is covered by infantry mine transfer tests. This models exact inert PMN4 state.
struct ERR_InfantryMineTransfer{static bool ReadyMine(IEntity e){return e&&e->mine&&e->damage&&!e->damage->destroyed&&!e->armed&&!e->defaultArmed&&e->collision;}};
struct EStoragePurpose{static const int PURPOSE_DEPOSIT=1;};
struct ScriptedInventoryOperationCallback{virtual void OnComplete(){}virtual void OnAllComplete(){}virtual void OnFailed(){}virtual void OnAllFailed(){}virtual ~ScriptedInventoryOperationCallback()=default;};
struct ERR_GroundDepotTransfer;
struct ERR_GroundDepotCallback:ScriptedInventoryOperationCallback{ERR_GroundDepotTransfer*Transfer=nullptr;void OnComplete()override;void OnAllComplete()override;void OnFailed()override;void OnAllFailed()override;};
struct Owner{bool valid=true,claimed=false;int claims=0;bool TransferValid(ERR_GroundDepotTransfer*){return valid;}bool ClaimDelivery(ERR_GroundDepotTransfer*){claims++;if(claimed)return false;claimed=true;return true;}};
struct Inventory{IEntity owner=nullptr;Array<IEntity>items;Array<Storage*>storages;Storage*selected=nullptr;bool allow=true,accept=true;int calls=0,ack=0;ScriptedInventoryOperationCallback*last=nullptr;std::function<void()>effect;
IEntity GetOwner(){return owner;}void GetItems(Array<IEntity>&a,int){a=items;}void GetStorages(Array<Storage*>&a,int){a=storages;}Storage*FindStorageForItem(IEntity,int){return selected;}
bool CanMoveItemToStorage(IEntity,Storage*,int){return allow;}
bool TryMoveItemToStorage(IEntity,Storage*,int,ScriptedInventoryOperationCallback*cb){calls++;last=cb;if(effect)effect();if(ack==1)cb->OnComplete();if(ack==-1)cb->OnFailed();return accept;}};
'''
main=r'''
struct Fixture{bool mine=false;Owner owner;Entity cache,porter,truck,mag,foreign;Inventory source,carry,cargo;Storage cs,ps,ts;Slot cslot,pslot,tslot;Item item;Magazine magazine;Damage damage;Array<IEntity>original,spent;ERR_FiniteMagazineReservation reservation;
Fixture():reservation(&original,&spent,&mag){cache.inventory=&source;porter.inventory=&carry;truck.inventory=&cargo;source.owner=&cache;carry.owner=&porter;cargo.owner=&truck;cs.owner=&cache;ps.owner=&porter;ts.owner=&truck;source.storages={&cs};carry.storages={&ps};cargo.storages={&ts};carry.selected=&ps;cargo.selected=&ts;cslot.storage=&cs;pslot.storage=&ps;tslot.storage=&ts;cslot.attached=&mag;item.slot=&cslot;mag.item=&item;mag.magazine=&magazine;mag.damage=&damage;source.items={&mag};original={&mag};assert(reservation.Reserve());}
ERR_GroundDepotTransfer Pickup(){return {&owner,&cache,&porter,&mag ,&reservation,false,mine};}
ERR_GroundDepotTransfer Delivery(){return {&owner,&porter,&truck,&mag ,&reservation,true,mine};}
void Pick(){source.items.clear();carry.items={&mag};cslot.attached=nullptr;pslot.attached=&mag;item.slot=&pslot;}
void Deliver(){carry.items.clear();cargo.items={&mag};pslot.attached=nullptr;tslot.attached=&mag;item.slot=&tslot;}
};
int main(){
// Ready inert PMN4 uses the same exact native two-leg custody protocol,
// shared reservation and isolated callbacks, without a magazine component.
{Fixture f;f.mine=f.mag.mine=true;f.mag.magazine=nullptr;auto a=f.Pickup();assert(a.MineCargo()&&a.Tick(0)==0&&a.Unresolved());f.Pick();f.source.last->OnComplete();assert(a.Tick(1)==1&&a.Confirmed());auto b=f.Delivery();assert(b.MineCargo()&&b.Tick(2)==0&&f.owner.claims==1);f.Deliver();f.carry.last->OnComplete();assert(b.Tick(3)==1&&b.Confirmed()&&!b.Unresolved()&&f.spent.Count()==1);}
// Every phase refuses changed/armed/default-armed/non-PMN4/destroyed identity.
for(int phase=0;phase<3;phase++)for(int kind=0;kind<5;kind++){Fixture f;f.mine=f.mag.mine=true;f.mag.magazine=nullptr;auto a=f.Pickup();
if(phase==1)assert(a.Tick(0)==0);
if(phase==2){assert(a.Tick(0)==0);f.Pick();f.source.last->OnComplete();assert(a.Tick(1)==1);}
if(kind==0)f.mag.armed=true;
if(kind==1)f.mag.defaultArmed=true;
if(kind==2)f.mag.mine=false;
if(kind==3)f.damage.destroyed=true;
if(kind==4)f.mag.collision=false;
if(phase==2){auto b=f.Delivery();assert(b.Tick(2)==-1&&!b.Submitted()&&f.carry.calls==0&&!a.Confirmed());}
else{assert(a.Tick(1)==-1);assert(f.source.calls==(phase==1?1:0));if(phase==1)assert(a.Unresolved());}
}
// Inline native mutation after initial ready check cannot promote success.
{Fixture f;f.mine=f.mag.mine=true;auto a=f.Pickup();f.source.ack=1;f.source.effect=[&]{f.Pick();f.mag.armed=true;};assert(a.Tick(0)==-1&&!a.Confirmed()&&!a.Unresolved());}
{Fixture f;f.mine=f.mag.mine=true;auto a=f.Pickup();assert(a.Tick(0)==0);a.Stop();f.Pick();f.source.last->OnComplete();assert(a.Tick(1)==-1&&!a.Confirmed()&&!a.Unresolved()&&f.source.calls==1&&f.spent.Count()==1);}
{Fixture f;f.mine=f.mag.mine=true;f.source.accept=false;auto a=f.Pickup();assert(a.Tick(0)==-1&&a.Unresolved());f.damage.destroyed=true;assert(a.Unresolved());a.m_Item=nullptr;assert(!a.Unresolved()&&f.spent.Count()==1);}
{Fixture f;f.mine=f.mag.mine=true;f.mag.magazine=nullptr;auto wrong=ERR_GroundDepotTransfer(&f.owner,&f.cache,&f.porter,&f.mag,&f.reservation,false,false);assert(wrong.Tick(0)==-1&&!wrong.Submitted()&&f.source.calls==0);}
{Fixture f;auto a=f.Pickup();a.Acknowledge(true);assert(a.m_Ack==0);assert(a.Tick(0)==0&&a.Submitted()&&a.Unresolved());assert(f.reservation.CommittedFor(&f.mag));f.source.last->OnComplete();assert(a.Tick(1)==0);f.Pick();assert(a.Tick(2)==1&&a.Confirmed()&&!a.Unresolved());auto b=f.Delivery();assert(b.Tick(3)==0&&f.owner.claims==1);f.source.last->OnAllComplete();assert(b.Tick(4)==0);f.Deliver();assert(b.Tick(5)==0);f.carry.last->OnAllComplete();assert(b.Tick(6)==1&&b.Confirmed()&&!b.Unresolved());assert(f.source.calls==1&&f.carry.calls==1&&f.spent.Count()==1);}
{Fixture f;f.source.ack=1;f.source.accept=false;f.source.effect=[&]{assert(f.reservation.CommittedFor(&f.mag));assert(!f.reservation.ReleaseUnsubmitted());f.Pick();};auto a=f.Pickup();assert(a.Tick(0)==1&&!a.Unresolved());}
{Fixture f;f.source.accept=false;auto a=f.Pickup();assert(a.Tick(0)==-1&&a.Unresolved());a.Stop();f.Pick();f.source.last->OnComplete();assert(!a.Unresolved()&&!a.Confirmed()&&a.Tick(1)==-1);}
{Fixture f;auto a=f.Pickup();a.Tick(0);a.Stop();f.Pick();f.source.last->OnComplete();assert(!a.Unresolved()&&!a.Confirmed()&&a.Tick(1)==-1);}
{Fixture f;auto a=f.Pickup();f.source.ack=1;f.source.effect=[&]{a.Stop();f.Pick();};assert(a.Tick(0)==-1&&!a.Confirmed()&&!a.Unresolved());}
{Fixture f;auto a=f.Pickup();f.source.ack=1;f.source.effect=[&]{f.owner.valid=false;f.Pick();};assert(a.Tick(0)==-1&&!a.Confirmed()&&!a.Unresolved());}
{Fixture f;auto a=f.Pickup();a.Tick(0);f.source.last->OnComplete();f.source.last->OnFailed();assert(a.Tick(1)==-1&&!a.Unresolved());f.source.last->OnAllComplete();assert(a.Tick(2)==-1);}
{Fixture f;auto a=f.Pickup();a.Tick(0);f.item.slot=nullptr;f.source.last->OnFailed();assert(a.Tick(1)==-1&&a.Unresolved());}
{Fixture f;auto a=f.Pickup();a.Tick(0);assert(a.Tick(8000)==-1&&a.Unresolved());assert(f.source.calls==1&&!f.reservation.ReleaseUnsubmitted());}
{Fixture f;auto a=f.Pickup();a.Tick(10);assert(a.Tick(9)==-1&&a.Unresolved());}
{Fixture f;auto a=f.Pickup();a.Stop();assert(a.Tick(0)==-1&&!a.Submitted()&&f.reservation.ReleaseUnsubmitted());}
{Fixture f;auto a=f.Pickup();a.Tick(0);a.m_Item=nullptr;assert(a.Tick(1)==-1&&!a.Unresolved()&&f.spent.Count()==1);}
{Fixture f;auto a=f.Pickup();a.Tick(0);f.damage.destroyed=true;assert(a.Tick(1)==-1&&a.Unresolved());}
for(int bad=0;bad<15;bad++){Fixture f;auto a=f.Pickup();switch(bad){case0:break;}
if(bad==0)f.magazine.used=true;if(bad==1)f.magazine.rounds=0;if(bad==2)f.magazine.capacity=100001;if(bad==3)f.damage.destroyed=true;if(bad==4)f.owner.valid=false;if(bad==5)f.source.allow=false;if(bad==6)f.carry.selected=nullptr;if(bad==7)f.cslot.attached=&f.foreign;if(bad==8)f.item.slot=&f.pslot;if(bad==9)f.source.items.clear();if(bad==10)f.carry.items={&f.mag};if(bad==11)f.carry.storages.clear();if(bad==12)f.carry.owner=&f.foreign;if(bad==13)f.source.items.resize(129,&f.mag);if(bad==14)f.source.storages.resize(65,&f.cs);
assert(a.Tick(0)==-1&&!a.Submitted()&&f.source.calls==0&&f.reservation.ReleaseUnsubmitted());}
{Fixture f;auto a=f.Pickup();a.Tick(0);f.magazine.rounds--;assert(a.Tick(1)==-1&&a.Unresolved());}
{Fixture f;f.Pick();assert(f.reservation.Commit());auto a=f.Delivery();a.Tick(0);auto b=f.Delivery();assert(b.Tick(1)==-1&&!b.Submitted()&&f.carry.calls==1);}
}
'''.replace('switch(bad){case0:break;}','')
main=main.replace(';if(bad', ';\n if(bad')
run(pre+translated_reservation()+code+'\n'.join(callbacks)+main)
print('PASS: actual full magazine/inert-PMN4 depot leaf, exact custody, isolated callbacks, finite reservation, false/unknown and Stop quarantine, once-only delivery and caps; native movement unqualified')