"""Actual radio task delivery/ownership methods with native waypoint and memory doubles.""" from pathlib import Path import os,re from policy_harness import ROOT,body,run P=Path(os.environ.get('ERR_HQ_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQ.c')) ROAD=Path(os.environ.get('ERR_HQ_ROAD_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQRoadIntercept.c')) def cpp(s): s=s.replace('protected ','').replace('null','nullptr').replace('string.Format','Format') for name in ('Math','ERR_GameMode','SCR_EntityHelper','ERR_HQPursuitRules','AIWaypoint','ERR_Actors','ERR_Resources','ERR_ForceDuty','ERR_HQRoadIntercept','ERR_ForceRules','ERR_HQPursuitRole','ERR_HQMemoryKind'): s=s.replace(name+'.',name+'::') for typ in ('ERR_HQUnit','ERR_HQTask','ERR_GameMode','ERR_HQReport','ERR_HQBelief','ERR_ForceRecord','ERR_HQHuntWindow','AIWaypoint'): s=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',s) s=re.sub(r'foreach \((ERR_HQUnit\*) (\w+) : ([^)]+)\)',r'for (\1 \2 : \3)',s) for name in ('unit','other','task','planned','order','belief','record','mode','Group','hunt','m_Mode'): s=s.replace(name+'.',name+'->') s=s.replace('ResourceName ', 'int ') s=s.replace('PendingTask.', 'PendingTask->').replace('Task.', 'Task->') s=s.replace('Downlink.', 'Downlink->').replace('Forces().','Forces()->').replace('ERR_ForceRecord* record;','ERR_ForceRecord* record=nullptr;') return s units='\n'.join(cpp(body(P,x)) for x in ('void CancelPending(', 'ERR_HQTask PlannedTask(', 'void ReleaseAssignment(', 'void Release()')) methods='\n'.join(cpp(body(P,x)) for x in ('protected void FinishWatch(', 'protected void ReleaseUnit(', 'protected void LostOrder(', 'protected void DeliverOrder(')) cleanup=cpp(body(P,' foreach (ERR_HQUnit unit : m_Units)\n {\n if (!unit.Assignment && !unit.PendingOrder) continue;\n if (!unit.PlanEligible || assigned > globalLimit)')) R=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQPursuit.c' rules='\n'.join(cpp(body(R,x)) for x in ('static bool Finite(', 'static bool PositionValid(', 'static bool Actionable(', 'static bool Heading(', 'static ERR_HQPursuitRole Role(')) eligible=cpp(body(ROAD,'static bool Eligible(')) run(r''' #include #include #include #include #include using string=std::string; templatestring Format(T...){return "order";} struct vector{float x=0,y=0,z=0;float& operator[](int i){return i==0?x:(i==1?y:z);}float Length(){return std::sqrt(x*x+y*y+z*z);}}; enum class ERR_HQPursuitRole{SEARCH,INTERCEPT,CONTAIN}; struct ERR_ForceRules{static bool Finite(float f){return std::isfinite(f);}}; struct ERR_HQMemoryKind{static const int SIGHTING=1;}; struct ERR_HQPursuitRules{ '''+rules+r''' }; struct Math{static float Min(float a,float b){return std::min(a,b);}}; struct ERR_HQTask{bool RoadIntercept=false,ReleaseOnly=false;ERR_HQTask* ReplacesTask=nullptr;string WatchSourceId;int WatchMessageId=0,WatchRequestId=0; int BeliefId=1,BeliefRevision=2,Role=0;vector Destination{40,0,50};float QueuedAt=0,ExpiresAt=60000;bool Investigation(){return !WatchSourceId.empty();}string Name(){return "search";}}; struct ERR_HQReport{int MessageId=10;float ObservedAt=0;}; struct ERR_HQRoute{int MessageId=20;}; struct AIWaypoint{int resource=0,deletes=0;static AIWaypoint* Cast(AIWaypoint* p){return p;}}; struct SCR_AIGroup{int removals=0,additions=0;AIWaypoint* last=nullptr;void RemoveWaypoint(AIWaypoint* w){removals++;last=w;}void AddWaypointAt(AIWaypoint* w,int at){assert(at==0);additions++;last=w;}}; struct ERR_ForceRecord{bool Eliminated=false;int Duty=2,HomeDuty=1;vector DutyTarget,HomePosition;}; struct Ledger{ERR_ForceRecord record;ERR_ForceRecord* FindGroup(SCR_AIGroup*){return &record;}}; struct ERR_GameMode{static inline ERR_GameMode* current=nullptr;Ledger ledger;static ERR_GameMode* Get(){return current;}Ledger* Forces(){return &ledger;}}; struct SCR_EntityHelper{static void DeleteEntityAndChildren(AIWaypoint* p){p->deletes++;}}; struct ERR_Actors{static inline bool refuse=false;static inline int spawns=0;static AIWaypoint* Spawn(int resource,vector){spawns++;if(refuse)return nullptr;auto w=new AIWaypoint;w->resource=resource;return w;}static vector Ground(vector p){return p;}}; struct ERR_Resources{static int SearchWaypoint(){return 1;}static int DefendWaypoint(){return 2;}}; struct ERR_ForceDuty{static const int SEARCH=2;}; struct ERR_HQUnit{int Id=1;string ForceSourceId="original";SCR_AIGroup* Group=nullptr;AIWaypoint* Waypoint=nullptr; ERR_HQTask* Task=nullptr;ERR_HQTask* PendingTask=nullptr;ERR_HQReport* Assignment=nullptr;ERR_HQReport* PendingOrder=nullptr; ERR_HQRoute* Downlink=nullptr;void* PendingConvoyOrder=nullptr;bool PendingCheckin=false,eligible=true,fighting=false,PlanEligible=true; bool Eligible(ERR_GameMode*){return eligible&&Group;} '''+units+r''' }; struct ERR_HQBelief{int BeliefId=1,BeliefRevision=2,Kind=1,SampleCount=2,MessageId=10;float Confidence=.8f,Radius=60,ObservedAt=0,LastDeliveredAt=0;string TravelMode="on foot";vector Velocity{0,0,3};bool HasVelocity=true;}; struct ERR_HQRoadIntercept{ '''+eligible+r''' }; struct Memory{ERR_HQBelief* belief=nullptr;ERR_HQBelief* GetById(int id){return belief&&belief->BeliefId==id?belief:nullptr;}}; struct Watch{bool empty=false;int finished=0;bool ArmedSearchBlocked(string,float){return empty;}bool FinishInvestigation(string,int,int,float){finished++;return true;}}; struct Journal{int writes=0;void Write(string,string,int=0){writes++;}}; struct ERR_HQHuntWindow{float NextHunt=200000;}; struct HQ{ERR_GameMode* m_Mode;Memory m_Memory;Watch m_Watch;Journal m_Journal;std::vectorm_Units;ERR_HQHuntWindow hunt;bool watchValid=true; bool Fighting(ERR_HQUnit* u){return u->fighting;}bool WatchTaskValid(ERR_HQTask*){return watchValid;}ERR_HQHuntWindow* Hunt(int){return &hunt;} '''+methods+'\nvoid Cleanup(float now,int assigned,int globalLimit){'+cleanup+'}'+r''' }; struct Fixture{ERR_GameMode mode;HQ hq;ERR_HQUnit unit;SCR_AIGroup group;AIWaypoint previous;ERR_HQTask active,next;ERR_HQReport oldReport,newReport;ERR_HQRoute route;ERR_HQBelief belief; Fixture(){ERR_GameMode::current=&mode;ERR_Actors::refuse=false;ERR_Actors::spawns=0;hq.m_Mode=&mode;hq.m_Units={&unit};hq.m_Memory.belief=&belief; unit.Group=&group;unit.Task=&active;unit.Assignment=&oldReport;unit.Waypoint=&previous;unit.PendingTask=&next;unit.PendingOrder=&newReport;unit.Downlink=&route;active.BeliefId=9;} void Retained(){assert(unit.Task==&active&&unit.Assignment==&oldReport&&unit.Waypoint==&previous&&previous.deletes==0&&group.removals==0&&!unit.PendingTask&&!unit.PendingOrder&&!unit.Downlink);} }; int main(){ // A changed belief revision or absent/stale/uncertain track cannot create a native destination. for(int invalid=0;invalid<5;invalid++){Fixture f; if(invalid==0){f.belief.BeliefRevision=3;}if(invalid==1){f.hq.m_Memory.belief=nullptr;} if(invalid==2){f.belief.ObservedAt=2000;}if(invalid==3){f.belief.Confidence=.1f;}if(invalid==4){f.belief.Radius=2001;} f.hq.DeliverOrder(&f.unit,1000);f.Retained();assert(ERR_Actors::spawns==0);} // Exact absolute expiry boundary, combat, physical reservation eligibility and known-empty ammo remain gates. for(int invalid=0;invalid<4;invalid++){Fixture f; if(invalid==0){f.next.ExpiresAt=1000;}if(invalid==1){f.unit.fighting=true;}if(invalid==2){f.unit.eligible=false;}if(invalid==3){f.hq.m_Watch.empty=true;} f.hq.DeliverOrder(&f.unit,1000);f.Retained();assert(ERR_Actors::spawns==0);} // Native spawn refusal must leave the delivered old waypoint and duty intact. {Fixture f;ERR_Actors::refuse=true;f.hq.DeliverOrder(&f.unit,1000);f.Retained();assert(ERR_Actors::spawns==1&&f.mode.ledger.record.Duty==2);} // Commit swaps the old task only after native success. Duplicate delivery has no pending lineage and cannot spawn twice. {Fixture f;f.hq.DeliverOrder(&f.unit,1000);assert(ERR_Actors::spawns==1&&f.previous.deletes==1&&f.group.removals==1&&f.group.additions==1); assert(f.unit.Waypoint->resource==1); assert(f.unit.Task==&f.next&&f.unit.Assignment==&f.newReport&&f.unit.Waypoint!=&f.previous&&!f.unit.PendingTask&&!f.unit.Downlink); auto retained=f.unit.Waypoint;f.hq.DeliverOrder(&f.unit,1001);assert(ERR_Actors::spawns==1&&f.unit.Waypoint==retained&&f.group.additions==1); assert(f.mode.ledger.record.DutyTarget.x==f.next.Destination.x);f.unit.ReleaseAssignment();assert(retained->deletes==1&&f.mode.ledger.record.Duty==f.mode.ledger.record.HomeDuty);} // Actual assignment-pass expiry releases only the expired reservation, preserving the other lineage. {Fixture f;f.active.ExpiresAt=1000;f.hq.Cleanup(1000,1,4); assert(!f.unit.Task&&!f.unit.Assignment&&!f.unit.Waypoint&&f.previous.deletes==1&&f.unit.PendingTask==&f.next&&f.unit.Downlink==&f.route); assert(f.mode.ledger.record.Duty==f.mode.ledger.record.HomeDuty);f.hq.Cleanup(1001,1,4);assert(f.previous.deletes==1&&f.unit.PendingTask==&f.next);} {Fixture f;f.active.BeliefId=1;f.next.ExpiresAt=1000;f.hq.Cleanup(1000,1,4);f.Retained();} {Fixture f;f.unit.PlanEligible=false;f.hq.Cleanup(1000,1,4);assert(!f.unit.Task&&!f.unit.PendingTask&&!f.unit.Downlink&&f.previous.deletes==1);} // Radio latency may age a precision interception beyond its 45-second authorization. // Eligibility uses the actual road helper and pursuit rules, never a test predicate. for(int invalid=0;invalid<9;invalid++){Fixture f;f.next.RoadIntercept=true;float now=1000; if(invalid==0)now=45001; if(invalid==1)f.belief.LastDeliveredAt=1001; if(invalid==2)f.belief.SampleCount=1; if(invalid==3)f.belief.Velocity={0,0,1.99f}; if(invalid==4)f.belief.HasVelocity=false; if(invalid==5)f.belief.TravelMode="aircraft"; if(invalid==6)f.belief.Kind=2; if(invalid==7)f.belief.MessageId=0; if(invalid==8){f.belief.ObservedAt=1;f.belief.LastDeliveredAt=0;} f.hq.DeliverOrder(&f.unit,now);f.Retained();assert(ERR_Actors::spawns==0);} {Fixture f;f.next.RoadIntercept=true;f.hq.DeliverOrder(&f.unit,45000); assert(ERR_Actors::spawns==1&&f.unit.Waypoint&&f.unit.Waypoint->resource==2&&f.unit.Task==&f.next&&f.previous.deletes==1); f.hq.DeliverOrder(&f.unit,45001);assert(ERR_Actors::spawns==1&&f.group.additions==1); f.hq.Cleanup(60000,1,4);assert(!f.unit.Task&&!f.unit.Waypoint&&f.mode.ledger.record.Duty==f.mode.ledger.record.HomeDuty);} // Cancelling a mismatched recall never releases a replacement task which arrived first. {Fixture f;f.next.ReleaseOnly=true;f.next.ReplacesTask=nullptr;f.hq.DeliverOrder(&f.unit,1000);f.Retained();assert(ERR_Actors::spawns==0);} {Fixture f;f.next.ReleaseOnly=true;f.next.ReplacesTask=&f.active;f.hq.DeliverOrder(&f.unit,1000);assert(!f.unit.Task&&!f.unit.Assignment&&!f.unit.Waypoint&&f.previous.deletes==1&&ERR_Actors::spawns==0);} } ''') print('PASS: actual delivered-task lineage, expiry, old-order retention, native commit, release, road precision expiry and duplicate delivery')