"""Execute the production drone scheduling policy and validate integration boundaries.""" from policy_harness import ROOT, body, run import re path = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_DroneRecon.c' schedule = body(path, 'class ERR_DroneSchedule').replace('class ERR_DroneSchedule', 'struct ERR_DroneSchedule') + ';' run('#include \n' + schedule + r''' int main() { ERR_DroneSchedule s{}; assert(!s.Due(0,0,0)); assert(s.Due(0,0,1)); assert(!s.Due(0,1,1)); assert(!s.Fresh(-1,0)); assert(!s.Fresh(1,0)); assert(s.Fresh(0,60000)); assert(!s.Fresh(0,60001)); s.Attempt(1000,2000,300); assert(!s.Fresh(1000,3000)); assert(!s.Fresh(999,3000)); assert(s.Fresh(1001,3000)); assert(!s.Due(301999,0,1)); assert(s.Due(302000,0,1)); s.Result(false); s.Result(false); assert(s.Due(302000,0,1)); s.Result(false); assert(!s.Due(302000,0,1)); ERR_DroneSchedule limit{}; for(int i=0;i<64;i++) { limit.Launched++; limit.Result(true); } assert(!limit.Due(9999999,0,3)); ERR_DroneSchedule stopped{}; stopped.Stopped=true; assert(!stopped.Due(9999999,0,3)); } ''') # Foreign types must remain inside the optional dynamically compiled adapter. bridge = (path.parent / 'ERR_DroneBridge.c').read_text() without_strings = re.sub(r'"(?:[^"\\]|\\.)*"', '""', bridge) assert 'SAL_' not in without_strings assert '65AD60E204191D37' not in (ROOT/'addons/core/addon.gproj').read_text() assert 'name.EndsWith("/djibase.et")' in bridge assert 'ERR_DroneState(e)!=1' in bridge assert 'c.m_iOwner=old' in bridge assert 'SetOrigin(' not in bridge and 'SetVelocity(' not in bridge s = path.read_text() assert 'report.DroneObservation' in s assert 'm_Schedule.Fresh(report.ObservedAt, now)' in s assert 'report.Position' in s and 'report.Target.GetOrigin' not in s assert 'TraceFlags.ENTS | TraceFlags.WORLD' in s assert 'CameraCone(Drone.GetOrigin(), Search, point)' in s assert 'QueueDroneObservation(Group, report, now)' in s assert 'GetCallqueue().Remove(Advance)' in s hq = (path.parent/'ERR_HQ.c').read_text() queue = body(path.parent/'ERR_HQ.c',' bool QueueDroneObservation') assert 'ObservationRoute(unit)' in queue and 'unit.PendingReport = report.Snapshot()' in queue assert 'Accept(' not in queue and 'm_Memory' not in queue assert 'm_DroneRecon.Stop()' in hq print('PASS: drone cooldown, capacity, freshness, replay, bounded retries, round cap, stop, optional API and radio boundaries') rules = '\n'.join(body(path, signature) for signature in ('static vector Controls(', 'static bool CameraCone(')) rules = rules.replace('Math.', 'Math::').replace('vector.', 'vector::') run(r''' #include #include #include struct vector { float x=0,y=0,z=0; float operator[](int i)const{return i==0?x:(i==1?y:z);} vector operator-(vector v)const{return{x-v.x,y-v.y,z-v.z};} float Length()const{return std::sqrt(x*x+y*y+z*z);} vector Normalized()const{float n=Length();if(n==0)return{};return{x/n,y/n,z/n};} static float Dot(vector a,vector b){return a.x*b.x+a.y*b.y+a.z*b.z;} }; vector Vector(float x,float y,float z){return{x,y,z};} namespace Math {float Clamp(float x,float a,float b){return std::clamp(x,a,b);}} ''' + rules + r''' int main() { assert(CameraCone({0,70,0},{0,0,0},{0,0,0})); assert(CameraCone({0,70,0},{0,0,0},{30,0,0})); assert(!CameraCone({0,70,0},{0,0,0},{50,0,0})); assert(!CameraCone({0,70,0},{0,0,0},{0,80,0})); assert(!CameraCone({0,400,0},{0,0,0},{0,0,0})); assert(!CameraCone({0,1,0},{0,0,0},{0,0,0})); auto hover=Controls({0,0,0},{0,0,0},{0,0,1},{1,0,0}); assert(hover.x==.49f && hover.y==0 && hover.z==0); assert(Controls({0,5,0},{0,0,0},{0,0,1},{1,0,0}).xhover.x); assert(Controls({0,0,0},{0,0,8},{0,0,1},{1,0,0}).y<0); assert(Controls({0,0,0},{8,0,0},{0,0,1},{1,0,0}).z<0); for(float speed:{-1000.f,1000.f}) { auto c=Controls({speed,speed,speed},{0,0,0},{0,0,1},{1,0,0}); assert(c.x>=.15f && c.x<=.85f && std::abs(c.y)<=.5f && std::abs(c.z)<=.5f); } } ''') print('PASS: production camera cone/range rejects behind-camera and distant actors; control directions, damping and limits') # Execute the actual enqueue method; the route boundary is substituted, so these # checks prove rejection/snapshot semantics rather than native radio reception. queue = queue.replace('foreach (ERR_HQUnit unit : m_Units)', 'for (ERR_HQUnit* unit : m_Units)') for name in ('SCR_AIGroup', 'ERR_HQReport', 'ERR_HQRoute'): queue = re.sub(r'\b'+name+r' (?=\w)', name+'* ', queue) for name in ('unit','report','route'): queue = queue.replace(name+'.', name+'->') for name in ('Replication','ERR_Actors','ERR_Phase'): queue = queue.replace(name+'.', name+'::') run(r''' #include #include #include struct SCR_AIGroup {}; struct Actor { bool conscious=true; }; namespace Replication { bool server=true; bool IsServer(){return server;} } namespace ERR_Actors {bool CanFight(Actor* a){return a&&a->conscious;}} namespace ERR_Phase {constexpr int RADIO_SEARCH=2;} struct ERR_HQReport { bool DroneObservation=true;int MessageId=0,Position=19;SCR_AIGroup* Source=nullptr; ERR_HQReport* Snapshot(){return new ERR_HQReport(*this);} std::string Description(float){return "camera";} }; struct ERR_HQRoute {int MessageId=0;std::string Payload;}; struct ERR_HQUnit {SCR_AIGroup* Group=nullptr;Actor* Radio=nullptr;ERR_HQRoute* Uplink=nullptr;ERR_HQReport* PendingReport=nullptr;}; struct HQ { struct Mode {int phase=2;int Phase(){return phase;}} m_Mode; struct Journal {int messages=0,writes=0;int Message(){return ++messages;}void Write(std::string,std::string,int){writes++;}} m_Journal; std::vector m_Units;ERR_HQRoute* available=nullptr;int routeCalls=0; ERR_HQRoute* ObservationRoute(ERR_HQUnit*){routeCalls++;return available;} ''' + queue + r''' }; int main(){ HQ h;SCR_AIGroup group,other;Actor radio;ERR_HQUnit unit;ERR_HQReport report;ERR_HQRoute route; unit.Group=&group;unit.Radio=&radio;h.m_Units.push_back(&unit);h.available=&route; Replication::server=false;assert(!h.QueueDroneObservation(&group,&report,1000));Replication::server=true; h.m_Mode.phase=1;assert(!h.QueueDroneObservation(&group,&report,1000));h.m_Mode.phase=2; assert(!h.QueueDroneObservation(nullptr,&report,1000));assert(!h.QueueDroneObservation(&group,nullptr,1000)); report.DroneObservation=false;assert(!h.QueueDroneObservation(&group,&report,1000));report.DroneObservation=true; assert(!h.QueueDroneObservation(&other,&report,1000)); radio.conscious=false;assert(!h.QueueDroneObservation(&group,&report,1000));radio.conscious=true; unit.Radio=nullptr;assert(!h.QueueDroneObservation(&group,&report,1000));unit.Radio=&radio; unit.Uplink=&route;assert(!h.QueueDroneObservation(&group,&report,1000));unit.Uplink=nullptr; assert(h.routeCalls==0&&h.m_Journal.messages==0); h.available=nullptr;assert(!h.QueueDroneObservation(&group,&report,1000));assert(!unit.PendingReport&&!unit.Uplink); h.available=&route;assert(h.QueueDroneObservation(&group,&report,1000)); assert(unit.PendingReport!=&report&&unit.PendingReport->DroneObservation&&unit.PendingReport->Source==&group); assert(unit.Uplink==&route&&route.MessageId==report.MessageId&&h.m_Journal.writes==1); report.Position=77;assert(unit.PendingReport->Position==19); assert(!h.QueueDroneObservation(&group,&report,2000));assert(h.m_Journal.messages==1); delete unit.PendingReport; } ''') print('PASS: production drone radio queue rejects wrong phase/authority/group, busy or unconscious radios and absent routes; snapshots only eligible observations') # Native traces can hit the operator's helmet instead of the character root. hit = body(path, 'static bool HitsTarget(').replace('IEntity ', 'Entity* ').replace('null', 'nullptr').replace('hit.GetParent()', 'hit->GetParent()') run('#include \nstruct Entity {Entity* parent=nullptr;Entity* GetParent(){return parent;}};\n' + hit + r''' int main(){ Entity actor,helmet{&actor},attachment{&helmet},wall,other,foreignHelmet{&other}; assert(HitsTarget(&actor,&actor)&&HitsTarget(&helmet,&actor)&&HitsTarget(&attachment,&actor)); assert(!HitsTarget(&wall,&actor)&&!HitsTarget(&foreignHelmet,&actor)); assert(!HitsTarget(nullptr,&actor)&&!HitsTarget(&wall,nullptr)); Entity cycle;cycle.parent=&cycle;assert(!HitsTarget(&cycle,&actor)); } ''') print('PASS: target equipment counts as character contact; unrelated blockers and cyclic hierarchies stay blocked')