"""Execute production gates behind the RKS2 delayed-start and hunter failures.""" import re from policy_harness import ROOT, body, run r = ROOT/'addons/core/Scripts/Game/ERR/10_AI' # Use the actual stateful deadline block, including first-poll initialization. poll = body(r/'ERR_MortarReadiness.c', 'ERR_MortarSupplyState Poll(') clock = poll[poll.index(' if (m_StartedAt < 0)'):poll.index(' array agents')] admission = body(r/'ERR_HQ.c', 'protected bool ConvoyAdmissionReady(').replace('protected ', '') admission = admission.replace('array batteries = {};', 'Array batteries;') admission = admission.replace('foreach (', 'for (').replace('ERR_HQUnit unit', 'ERR_HQUnit* unit').replace('ERR_MortarBattery support', 'ERR_MortarBattery* support').replace('ERR_MortarBattery battery', 'ERR_MortarBattery* battery') for name in ('m_Mode', 'm_Mortars', 'unit', 'support', 'battery'): admission = admission.replace(name+'.', name+'->') admission = admission.replace('Forces().', 'Forces()->') crew = body(r/'ERR_HunterService.c', 'override bool CrewValid(').replace('override ', '').replace('ERR_GameMode mode','Mode* mode') crew = crew.replace('ERR_Actors.', 'Actors::').replace('mode.', 'mode->').replace('Group.', 'Group->').replace('Seats[0].','Seats[0]->') run(r''' #include #include #include struct Text { bool empty=true; bool IsEmpty(){return empty;} }; templatestruct Array:std::vector{using std::vector::vector;bool IsEmpty(){return this->empty();}int Count(){return this->size();}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}}; struct GroupType {int faction=1;int GetFaction(){return faction;}}; struct Actor {bool alive=true,fit=true,player=false;GroupType* group=nullptr;}; struct Seat {Actor* occupant=nullptr;Actor* GetOccupant(){return occupant;}}; namespace Actors {bool Alive(Actor* x){return x&&x->alive;}bool CanFight(Actor* x){return x&&x->alive&&x->fit;}bool Player(Actor*x){return x&&x->player;}GroupType* Group(Actor*x){return x?x->group:nullptr;}} struct Clock {float m_StartedAt=-1; bool Poll(float now){ '''+clock+r''' return expired; }}; struct Ledger {std::vector registered;bool FindGroup(GroupType*g){return std::find(registered.begin(),registered.end(),g)!=registered.end();}}; struct Mode {Ledger ledger;Ledger* Forces(){return &ledger;}int EnemyFaction(){return 1;}}; struct ERR_HQUnit {GroupType* Group=nullptr;}; struct ERR_MortarBattery {GroupType* group=nullptr;bool stopped=false,StartupActivated=false;Text SpawnFailure;bool Stopped(){return stopped;}}; struct Mortars {Array all;ERR_MortarBattery* FindGroup(GroupType*g){for(auto*b:all)if(b->group==g)return b;return nullptr;}void Batteries(Array&out){out=all;}}; struct HQ {Array m_Units;Mode* m_Mode;Mortars* m_Mortars; '''+admission+r''' }; struct Hunter {GroupType* Group;Actor* Entity;Actor* Driver;Array Members;Array Seats; '''+crew+r''' }; int main(){ Clock c;assert(!c.Poll(150000));assert(!c.Poll(239999));assert(c.Poll(240000)); // 150 seconds in prison does not spend the initialization budget Clock early;assert(!early.Poll(1000));assert(!early.Poll(90999));assert(early.Poll(91000));assert(early.Poll(999)); // finite deadline and clock reversal remain enforced Mode mode;GroupType ordinary,mortar;ERR_HQUnit u{&ordinary},m{&mortar};ERR_MortarBattery battery{&mortar};Mortars support;support.all={&battery};HQ hq{{&u,&m},&mode,&support}; mode.ledger.registered={&ordinary};assert(!hq.ConvoyAdmissionReady()); // unfinished mortar waits battery.SpawnFailure.empty=false;assert(hq.ConvoyAdmissionReady()); // failed optional mortar cannot block convoy admission battery.SpawnFailure.empty=true;battery.stopped=true;assert(hq.ConvoyAdmissionReady()); battery.stopped=false;battery.StartupActivated=true;assert(!hq.ConvoyAdmissionReady()); // success still requires ledger registration mode.ledger.registered.push_back(&mortar);assert(hq.ConvoyAdmissionReady()); mode.ledger.registered={&mortar};battery.SpawnFailure.empty=false;assert(!hq.ConvoyAdmissionReady()); // unrelated pending group is not bypassed Actor vehicle,driver,gunner;driver.group=&ordinary;gunner.group=&ordinary;Seat seat{&driver};Hunter hunter{&ordinary,&vehicle,&driver,{&driver,&gunner},{&seat}}; assert(hunter.CrewValid(&mode));gunner.alive=false;assert(hunter.CrewValid(&mode)); // loss of gunner does not discard a working driver driver.fit=false;assert(!hunter.CrewValid(&mode));driver.fit=true;assert(hunter.CrewValid(&mode)); // temporary incapacitation can resume seat.occupant=nullptr;assert(!hunter.CrewValid(&mode));seat.occupant=&driver;assert(hunter.CrewValid(&mode)); driver.player=true;assert(!hunter.CrewValid(&mode));driver.player=false;vehicle.alive=false;assert(!hunter.CrewValid(&mode)); } ''') print('PASS: real-session mortar deadline, failed-support convoy admission and hunter survivor/recovery gates') # Execute the real retry method with a newer order still pending: the physical # waypoint, not the unsent destination, must be recreated. Exercise retry limits # and combat suppression too. movement = body(r/'ERR_HunterService.c', 'protected void ObserveMovement(') movement = movement.replace('protected ', '').replace('ERR_HunterVehicle unit', 'MovingHunter* unit') movement = movement.replace('SCR_AIGroupUtilityComponent utility', 'Utility* utility').replace('vector ', 'Vec ').replace('vector.DistanceXZ', 'Vec::DistanceXZ') movement = movement.replace('AIWaypoint.Cast(ERR_Actors.Spawn(ERR_Resources.MoveWaypoint(), retryDestination))', 'Spawn(retryDestination)') for name in ('unit', 'utility'): movement = movement.replace(name+'.', name+'->') for name in ('Entity', 'Group', 'Waypoint', 'm_Perception'): movement = movement.replace(name+'.', name+'->') movement = movement.replace('Physics physics =', 'Physics* physics =').replace('physics.GetVelocity()', 'physics->GetVelocity()') movement = movement.replace('GetPhysics().', 'GetPhysics()->').replace('unit->Repaths.ToString()', 'std::to_string(unit->Repaths)') movement = movement.replace('string.Format', 'Format').replace('ERR_HQ.Event', 'Event').replace('ERR_HunterCombat.Active', 'ERR_HunterCombat::Active') movement = re.sub(r'\b(bool|float|Vec) (\w+);', r'\1 \2 {};', movement) run(r''' #include #include #include struct Vec {float x=0,z=0;float Length(){return 0;}static float DistanceXZ(Vec a,Vec b){return std::hypot(a.x-b.x,a.z-b.z);}}; struct Targets {bool empty=true;bool IsEmpty(){return empty;}}; struct Perception {Targets m_aTargets;}; struct Utility {Perception* m_Perception;}; struct Physics {Vec GetVelocity(){return {};}}; struct Vehicle {Vec pos;Physics physics;Vec GetOrigin(){return pos;}Physics* GetPhysics(){return &physics;}}; struct Group {Utility utility;Utility* GetGroupUtilityComponent(){return &utility;}void AddWaypoint(void*){}}; namespace ERR_HunterCombat {bool fresh=false;bool Active(Group*){return fresh;}}; struct Waypoint {Vec pos;bool arrived=false;bool IsWithinCompletionRadius(Group*){return arrived;}Vec GetOrigin(){return pos;}void SetCompletionRadius(float){}}; struct MovingHunter {Vehicle* Entity;struct Group* Group;struct Waypoint* Waypoint;Vec Destination,ProgressPosition;float ProgressAt=1,NextMotionLog=0;int Repaths=0;std::string Source="test";void ClearOrder(){Waypoint=nullptr;}}; // Actual abandonment/exit behavior is covered by test_hunter_stuck.py. int abandonments=0;void AbandonStuckVehicle(MovingHunter*){abandonments++;} Waypoint spawned;Waypoint* Spawn(Vec pos){spawned.pos=pos;return &spawned;} template std::string Format(Args...){return "log";} void Event(std::string,std::string){} '''+movement+r''' int main(){ Perception perception;Group group{{&perception}};Vehicle vehicle;Waypoint delivered{{100,200}}; MovingHunter hunter{&vehicle,&group,&delivered,{900,900}}; ObserveMovement(&hunter,60000);assert(hunter.Waypoint==&delivered&&hunter.Repaths==0); ObserveMovement(&hunter,60001);assert(hunter.Repaths==1&&hunter.Waypoint->pos.x==100&&hunter.Waypoint->pos.z==200);assert(hunter.Destination.x==900); ObserveMovement(&hunter,120001);ObserveMovement(&hunter,180001);assert(hunter.Repaths==3); ObserveMovement(&hunter,240001);assert(hunter.Repaths==3&&abandonments==1); // A separate still-owned patrol makes progress and resumes after contact. hunter={&vehicle,&group,&delivered,{900,900}}; vehicle.pos={20,0};ObserveMovement(&hunter,241001);assert(hunter.Repaths==0); perception.m_aTargets.empty=false;ERR_HunterCombat::fresh=true;ObserveMovement(&hunter,400000);assert(hunter.Repaths==0); ERR_HunterCombat::fresh=false;ObserveMovement(&hunter,400001);assert(hunter.Repaths==0); ObserveMovement(&hunter,460000);assert(hunter.Repaths==1); } ''') print('PASS: native-route retry preserves delivered target, limits attempts and suspends during combat')