"""Execute town activation and no-pop-in policy, including split/invalid observers.""" from policy_harness import ROOT, body, run p=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_TownGarrisons.c' code=body(p,'static bool Safe(')+'\n'+body(p,'static bool Approached(') code=code.replace('array players','Array* players').replace('vector ', 'Vec ').replace('foreach (','for (').replace(' : players)', ' : *players)').replace('players.', 'players->').replace('vector.DistanceXZ','Vec::DistanceXZ').replace('ERR_ForceRules.FiniteVector','Finite') run(r''' #include #include #include #include struct Vec{float x,y,z;static float DistanceXZ(Vec a,Vec b){return std::hypot(a.x-b.x,a.z-b.z);}}; bool Finite(Vec v){return std::isfinite(v.x)&&std::isfinite(v.y)&&std::isfinite(v.z);} templatestruct Array:std::vector{using std::vector::vector;bool IsEmpty(){return this->empty();}}; constexpr float DISTANCE=700; '''+code+r''' int main(){ Array empty,near={{0,1000,0}},far={{701,0,0}},edge={{700,0,0}},split={{700,0,0},{-699,0,0}}; Vec origin{0,0,0}; assert(!Safe(origin,nullptr)&&!Safe(origin,&empty)&&!Approached(origin,&empty)); assert(!Safe(origin,&near)&&Approached(origin,&near)); // Horizontal distance, including helicopters assert(Safe(origin,&far)&&!Approached(origin,&far)); assert(Safe(origin,&edge)&&Approached(origin,&edge)); // Exact 700m is safe and activates assert(!Safe(origin,&edge,702)); // Planning leaves a small ground-placement margin assert(!Safe(origin,&split)); // A distant lead player cannot hide a nearby teammate split[1]={-701,0,0}; assert(Safe(origin,&split)); split[0]={699.99f,0,0}; assert(!Safe(origin,&split)); // Crossing boundary before birth rejects it split[0]={std::numeric_limits::quiet_NaN(),0,0}; assert(!Safe(origin,&split)); assert(!Safe(split[0],&edge)&&!Approached(split[0],&edge)); Array objectEdge={{1000,0,0}},approaching={{1400,0,0}},outside={{1401,0,0}}; assert(Safe(origin,&objectEdge,1000)&&!Safe(origin,&objectEdge,1002)); assert(Approached(origin,&approaching,1400)&&!Approached(origin,&outside,1400)); objectEdge.push_back({999.9f,0,0});assert(!Safe(origin,&objectEdge,1000)); } ''') print('PASS: town trigger and hard 700m exclusion for all observers, empty/invalid positions and final-check crossings') # Execute the production guard split and geometric support policy, including # unsafe chimney openings, steep faces and invalid trace values. guards=body(p,'static int Fixed(')+'\n'+body(p,'static bool Selected(')+'\n'+body(p,'static bool Support(') guards=guards.replace('ERR_ForceRules.Finite','std::isfinite').replace('Math.AbsFloat','std::fabs') run(r''' #include #include #include '''+guards+r''' int main(){ for(int count=0;count<=16;++count){ int fixed=Fixed(count),response=count-fixed; assert(fixed+response==count&&fixed>=response&&fixed-response<=1); assert(Fixed(count,0)==count && Fixed(count,2)==0); } for(int every=1;every<=4;every++) { int selected=0; for(int ordinal=1;ordinal<=32;ordinal++) { bool decision=Selected(ordinal,every); selected+=decision; assert(Selected(ordinal,every)==decision); // Repeated visits never reroll } assert(selected==32/every); } assert(!Selected(0,1)&&!Selected(1,0)&&!Selected(1,5)); assert(Fixed(8)==4&&Fixed(1)==1&&Fixed(0)==0); assert(Support(.5f,1.f,0.f)); assert(!Support(1.f,1.f,0.f)); // No floor below this footprint corner assert(!Support(-1.f,1.f,0.f)); // Exhausted trace budget assert(!Support(.5f,.84f,0.f)); // Steep/sloped face assert(!Support(.5f,1.f,.21f)); // Edge/hole: corner is on a different floor auto nan=std::numeric_limits::quiet_NaN(); assert(!Support(nan,1.f,0.f)&&!Support(.5f,nan,0.f)&&!Support(.5f,1.f,nan)); } ''') print('PASS: object guard split, hard 1000m exclusion / 1400m activation, footprint support, slopes, holes and invalid traces') # Fixed sentries use the real admission hook; responders keep normal HQ eligibility. admitted=body(p,'override protected void Admitted(').replace('override protected ','').replace('ERR_TownGarrison town','Town* town').replace('town.','town->').replace('town->ObjectSite.Id','town->ObjectSite->Id').replace('town->Hold.SetCompletionRadius','town->Hold->SetCompletionRadius').replace('ERR_HQ hq = ERR_HQ.Cast(m_Mode.Command());','HQ* hq = currentHQ;').replace('hq.Dedicate','hq->Dedicate') run(r''' #include struct Site{int Id=17;}; struct Hold{float radius=60;void SetCompletionRadius(float value){radius=value;}}; struct Town{bool FixedGuard=false;Site*ObjectSite;Hold*Hold;int Group=19;}; struct HQ{int calls=0;void Dedicate(int group,int site){assert(group==19&&site==17);calls++;}}; HQ*currentHQ; '''.replace('Hold*Hold','struct Hold*Hold')+admitted+r''' int main(){ HQ hq;currentHQ=&hq;Site site;Hold post;Town response{false,&site,&post}; Admitted(&response);assert(hq.calls==0&&post.radius==60); Town fixed{true,&site,&post};Admitted(&fixed);assert(hq.calls==1&&post.radius==2); } ''') print('PASS: actual fixed-post admission reserves only stationary guards from HQ retasking and tightens their defend radius') import re structure=body(p,'static bool Structure(').replace('EMapDescriptorType.', 'EMapDescriptorType::') labels=sorted(set(re.findall(r'EMapDescriptorType::(\w+)',structure))) run(r''' #include #include #include #include struct string:std::string{ using std::string::string; void ToLower(){std::transform(begin(),end(),begin(),[](unsigned char c){return std::tolower(c);});} bool Contains(const char*s){return find(s)!=npos;} }; namespace EMapDescriptorType{enum {'''+','.join(labels)+r'''};} '''+structure+r''' int main(){ assert(Structure("Prefabs/Structures/Industrial/Houses/Workshop.et",-1)); assert(Structure("Prefabs/Structures/Watchtower.et",-1)); assert(Structure("Prefabs/Custom/FactoryChimney.et",-1)); assert(Structure("UnknownMod/Asset.et",EMapDescriptorType::MDT_TOWER)); assert(!Structure("UnknownMod/Asset.et",-1)); for(const char*path:{"Prefabs/Props/Industrial/Barrel.et","Prefabs/Structures/BuildingParts/Industrial/Wall.et","Prefabs/Structures/Military/Flags/Flag.et","Prefabs/Structures/Ruins/House_Chimney.et","Prefabs/Vehicles/Military/Truck.et"}) assert(!Structure(path,-1)); } ''') print('PASS: production site classification accepts structures/descriptors and excludes industrial props, fragments, flags, ruins and vehicles')