"""Execute preparation-time fleet survey and dispatch obstruction recovery.""" import re from policy_harness import ROOT, body, run landing = ROOT / 'addons/core/Scripts/Game/ERR/00_Core/ERR_RescueLanding.c' service = ROOT / 'addons/core/Scripts/Game/ERR/00_Core/ERR_ExtractionService.c' assets = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_RescueAssets.c' def native(text): text = text.replace('array pads)', 'Array& pads)').replace('array', 'Array') text = re.sub(r'\bvector\b', 'Vec', text).replace('protected ', '') text = text.replace('string faction', 'std::string faction').replace('ERR_GameMode mode', 'ERR_GameMode* mode') text = text.replace('GetGame().GetWorldEntity().GetWorldBounds(', 'GetGame()->GetWorldEntity()->GetWorldBounds(') text = text.replace('GetGame().GetWorldEntity()', 'GetGame()->GetWorldEntity()') for name in ('mode', 'm_Mode'): text = text.replace(name + '.PlayerFaction().GetFactionKey()', name + '->PlayerFaction()->GetFactionKey()') text = re.sub(r'\b' + name + r'\.', name + '->', text) for name in ('Math', 'ERR_Actors', 'Replication', 'ERR_AirfieldPlacement', 'ERR_GameMode', 'ERR_RescueAssets', 'ERR_RescueLanding'): text = text.replace(name + '.', name + '::') return text asset_methods = native('\n'.join(body(assets, signature) for signature in ('static bool Western(', 'static int TransportCount('))) landing_methods = native('\n'.join(body(landing, signature) for signature in ('static vector Candidate(', 'static bool SecondaryClear(', 'static bool Survey(', 'static bool Fits('))) service_methods = native('\n'.join(body(service, signature) for signature in ('bool ConfigurePickup(', 'protected bool LandingPads('))) run(r''' #include #include #include #include templatestruct Array:std::vector{using std::vector::vector;void Clear(){this->clear();}void Insert(T v){this->push_back(v);}int Count(){return this->size();}}; struct Vec { float values[3]={0,0,0};Vec(){}Vec(float x,float y,float z):values{x,y,z}{} float& operator[](int i){return values[i];}float operator[](int i)const{return values[i];} Vec operator+(Vec b)const{return {values[0]+b[0],values[1]+b[1],values[2]+b[2]};} Vec operator*(float scale)const{return {values[0]*scale,values[1]*scale,values[2]*scale};} }; Vec Vector(float x,float y,float z){return {x,y,z};} bool Same(Vec a,Vec b){return std::abs(a[0]-b[0])<0.01&&std::abs(a[1]-b[1])<0.01&&std::abs(a[2]-b[2])<0.01;} namespace Math{const float PI2=6.283185307f;int Mod(int a,int b){return a%b;}float Cos(float a){return std::cos(a);}float Sin(float a){return std::sin(a);}} struct ERR_Actors{static Vec Ground(Vec p){p[1]=10;return p;}}; struct Replication{static inline bool server=true;static bool IsServer(){return server;}}; struct World{Vec low{0,0,0},high{10000,1000,10000};void GetWorldBounds(Vec& a,Vec& b){a=low;b=high;}}; struct Game{World world;bool available=true;World* GetWorldEntity(){return available?&world:nullptr;}}; Game game;Game* GetGame(){return &game;} struct ERR_AirfieldPlacement{ static inline std::vector clear,queries; static bool ClearGround(Vec p){queries.push_back(p);for(Vec candidate:clear)if(Same(p,candidate))return true;return false;} }; struct Faction{std::string key="US";std::string GetFactionKey(){return key;}}; struct ERR_GameMode{ static inline ERR_GameMode* current=nullptr;Faction* faction=nullptr; static ERR_GameMode* Get(){return current;}Faction* PlayerFaction(){return faction;} }; templatevoid PrintFormat(Args...args){} struct ERR_RescueAssets{ ''' + asset_methods + r''' }; struct ERR_RescueLanding{ ''' + landing_methods + r''' }; struct Service{ bool m_PickupConfigured=false,m_Begun=false,m_Stopped=false;ERR_GameMode* m_Mode=nullptr; std::string m_RescueFaction;Array m_TransportPickups;Vec m_Pickup; ''' + service_methods + r''' }; int main(){ Vec primary{5000,10,5000};Array pads;Faction faction;ERR_GameMode mode;mode.faction=&faction;ERR_GameMode::current=&mode; Vec first=ERR_RescueLanding::Candidate(primary,0),last=ERR_RescueLanding::Candidate(primary,47); assert(Same(first,{5090,10,5000}));assert(Same(ERR_RescueLanding::Candidate(primary,16),{5130,10,5000})); assert(std::abs(std::hypot(last[0]-primary[0],last[2]-primary[2])-170)<0.01); // A clear primary is insufficient for a two-Huey faction: reject before configured. Service service;assert(!service.ConfigurePickup(primary));assert(!service.m_PickupConfigured&&service.m_TransportPickups.Count()==0); assert(ERR_AirfieldPlacement::queries.size()==48); ERR_AirfieldPlacement::queries.clear();ERR_AirfieldPlacement::clear={last}; assert(ERR_RescueLanding::Fits(primary));assert(ERR_AirfieldPlacement::queries.size()==48); assert(service.ConfigurePickup(primary));assert(service.m_PickupConfigured&&service.m_TransportPickups.Count()==2); assert(Same(service.m_TransportPickups[0],primary)&&Same(service.m_TransportPickups[1],last)); // Dispatch reuses a still-clear reserved secondary. It never rechecks the occupied smoke marker. ERR_AirfieldPlacement::queries.clear();assert(service.LandingPads());assert(ERR_AirfieldPlacement::queries.size()==1&&Same(ERR_AirfieldPlacement::queries[0],last)); // Obstructing that pad selects another safe candidate without modifying primary. ERR_AirfieldPlacement::clear={first};ERR_AirfieldPlacement::queries.clear(); assert(service.LandingPads());assert(service.m_TransportPickups.Count()==2&&Same(service.m_TransportPickups[1],first)); assert(ERR_AirfieldPlacement::queries.size()==2&&Same(service.m_Pickup,primary)); // With every candidate blocked, the finite search fails and no partial pad list is usable. ERR_AirfieldPlacement::clear.clear();ERR_AirfieldPlacement::queries.clear(); assert(!service.LandingPads());assert(service.m_TransportPickups.Count()==0&&ERR_AirfieldPlacement::queries.size()==49); ERR_AirfieldPlacement::clear={first};assert(service.LandingPads()); // A later bounded dispatch attempt can recover. assert(!service.ConfigurePickup({6000,10,6000}));assert(Same(service.m_Pickup,primary)); // Existing single-Mi8 extraction does not gain a spurious extra footprint requirement. faction.key="USSR";ERR_AirfieldPlacement::clear.clear();ERR_AirfieldPlacement::queries.clear();Service east; assert(east.ConfigurePickup(primary)&&east.m_TransportPickups.Count()==1&&east.LandingPads());assert(ERR_AirfieldPlacement::queries.empty()); assert(!ERR_RescueLanding::Survey(primary,0,pads)&&pads.Count()==0); assert(!ERR_RescueLanding::Survey(primary,3,pads)&&pads.Count()==0); Replication::server=false;assert(!ERR_RescueLanding::Survey(primary,1,pads));Service client;assert(!client.ConfigurePickup(primary));Replication::server=true; // Bounds are checked with the original 40-metre aircraft clearance margin. ERR_AirfieldPlacement::clear={{39,10,100},{40,10,100}}; assert(!ERR_RescueLanding::SecondaryClear({39,10,100}));assert(ERR_RescueLanding::SecondaryClear({40,10,100})); game.available=false;assert(!ERR_RescueLanding::SecondaryClear(first));game.available=true; mode.faction=nullptr;assert(!ERR_RescueLanding::Fits(primary));ERR_GameMode::current=nullptr;assert(!ERR_RescueLanding::Fits(primary)); } ''') print('PASS: fleet space is required before pickup registration; dispatch rechecks/replaces only the secondary within the original 48-candidate footprint budget')