"""Execute Cessna boarding policy; engine transitions/components are explicit doubles.""" from policy_harness import ROOT, body, run SOURCE = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_PlaneFlight.c' def cpp(method): # Translate syntax only; the three production decision bodies stay intact. method = method.replace('protected ', '') method = method.replace( 'AIControlComponent.Cast(entry.Actor.FindComponent(AIControlComponent))', 'entry.Actor.Control', ).replace( 'CompartmentAccessComponent.Cast(entry.Actor.FindComponent(CompartmentAccessComponent))', 'entry.Actor.Access', ) for before, after in ( ('ERR_PlaneCrewSeat entry', 'Entry* entry'), ('AIControlComponent control', 'Control* control'), ('CompartmentAccessComponent access', 'Access* access'), ('CompartmentAccessComponent.', 'Access::'), ('SCR_ChimeraAIAgent.Cast(', 'CharacterAgent::Cast('), ('SCR_ChimeraAIAgent characterAgent', 'Agent* characterAgent'), ('SCR_FactionManager.', 'Factions::'), ('ERR_Actors.', 'Actors::'), ('ECloseDoorAfterActions.', 'DoorAction::'), ('string action', 'std::string action'), ): method = method.replace(before, after) for name in ('entry', 'Actor', 'Seat', 'Agent', 'access', 'control', 'm_Mode'): method = method.replace(name + '.', name + '->') return method methods = '\n'.join(cpp(body(SOURCE, signature)) for signature in ( 'protected bool OwnsCrewSeat(', 'protected bool CrewSeated(', 'protected bool PrepareCrewSeat(', )) run(r''' #include #include #include #include struct Entity; struct Seat; struct Access; struct Agent { int lod=2, activations=0, lodWrites=0; bool active=false,playerPending=false,character=true; std::vector calls; void SetPermanentLOD(int value) {lod=value;lodWrites++;calls.push_back("LOD");} void ActivateAI() {active=true;activations++;calls.push_back("activate");} bool IsPlayerPending_S(){return playerPending;} }; struct CharacterAgent {static Agent* Cast(Agent* agent){return agent->character?agent:nullptr;}}; struct Control {Agent* agent=nullptr;Agent* GetControlAIAgent(){return agent;}}; struct Entity { bool player=false,fit=true; int faction=1; Entity* group=nullptr; struct Control* Control=nullptr; struct Access* Access=nullptr; }; struct Seat { Entity* owner=nullptr; Entity* occupant=nullptr; Entity* reservation=nullptr; bool occupied=false,accessible=true,locked=false,reserved=false; Entity* GetOwner(){return owner;} Entity* GetOccupant(){return occupant;} bool IsOccupied(){return occupied||occupant;} bool IsCompartmentAccessible(){return accessible;} bool IsGetInLockedFor(Entity*){return locked;} bool IsReserved(){return reserved;} bool IsReservedBy(Entity* actor){return reservation==actor;} }; struct DoorAction {enum {INVALID=-1};}; struct Access { Entity* actor=nullptr; Entity* vehicle=nullptr; Seat* compartment=nullptr; Seat* expectedSeat=nullptr; bool entering=false,exiting=false,inside=false,accepted=true,synchronousSeat=false; int requests=0; bool IsGettingIn(){return entering;} bool IsGettingOut(){return exiting;} bool IsInCompartment(){return inside;} Seat* GetCompartment(){return compartment;} static Entity* GetVehicleIn(Entity* actor){return actor&&actor->Access?actor->Access->vehicle:nullptr;} bool GetInVehicle(Entity* owner,Seat* seat,bool teleport,int door,int close,bool unknown) { assert(seat==expectedSeat&&owner==expectedSeat->owner); assert(teleport&&door==-1&&close==DoorAction::INVALID&&!unknown); Agent* agent=actor->Control->agent; assert(agent->active&&agent->lod==0); assert(agent->calls.size()>=2&&agent->calls[agent->calls.size()-2]=="LOD"&&agent->calls.back()=="activate"); agent->calls.push_back("board");requests++; if(synchronousSeat) {inside=true;compartment=seat;vehicle=owner;seat->occupant=actor;} return accepted; } }; struct Actors { static bool Player(Entity* actor){return actor->player;} static Entity* Group(Entity* actor){return actor->group;} static bool CanFight(Entity* actor){return actor&&actor->fit;} }; struct Factions {static int SGetFaction(Entity* actor){return actor->faction;}}; struct Mode {int EnemyFaction(){return 1;}}; struct Entry { Entity* Actor=nullptr; struct Seat* Seat=nullptr; struct Agent* Agent=nullptr; int Attempts=0; float NextAttempt=0; }; struct Flight { Mode* m_Mode=nullptr; Entity* Crew=nullptr; Entity* Aircraft=nullptr; std::vector actions; void LogCrewSeat(Entry*,int,float,std::string action="",bool force=false) { if(force)actions.push_back(action); } ''' + methods + r''' }; struct Setup { Mode mode; Entity aircraft,group,actor,other; Agent agent,otherAgent; Control control; Access access; Seat seat,otherSeat; Entry entry; Flight flight; Setup() { flight.m_Mode=&mode;flight.Aircraft=&aircraft;flight.Crew=&group; actor.group=&group;actor.Control=&control;actor.Access=&access;control.agent=&agent; access.actor=&actor;access.expectedSeat=&seat;seat.owner=&aircraft; entry.Actor=&actor;entry.Seat=&seat;entry.Agent=&agent; } bool Tick(float now){return flight.PrepareCrewSeat(&entry,0,now);} void Seated(){access.inside=true;access.compartment=&seat;access.vehicle=&aircraft;seat.occupant=&actor;} }; int main() { // Native acceptance can leave the actor on foot. All requests, including // refused requests, consume the same finite budget with 5s between requests. for(bool accepted:{false,true}) { Setup s;s.access.accepted=accepted; assert(!s.Tick(1000)&&s.entry.Attempts==1&&s.access.requests==1); assert(s.entry.NextAttempt==6000&&s.agent.active&&s.agent.lod==0); assert(!s.Tick(1001)&&!s.Tick(5999)&&s.access.requests==1); assert(!s.Tick(6000)&&s.entry.Attempts==2&&s.entry.NextAttempt==11000); assert(!s.Tick(10999)&&s.access.requests==2); assert(!s.Tick(11000)&&s.entry.Attempts==3&&s.entry.NextAttempt==16000); for(float now:{16000.f,45000.f,1000000.f})assert(!s.Tick(now)); assert(s.access.requests==3&&s.agent.activations==3&&s.agent.lodWrites==3); assert(s.flight.actions==std::vector(3,accepted?"boarding accepted":"boarding refused")); // Delayed native completion is still accepted after the retry cap. s.Seated();assert(s.Tick(1000001)&&s.access.requests==3); } // Even if a fake native request completes synchronously, that request is not // the readiness proof. The next observation must confirm the exact seat. {Setup s;s.access.synchronousSeat=true;assert(!s.Tick(1000));assert(s.Tick(1001)&&s.access.requests==1);} {Setup s;s.Seated();assert(s.Tick(1000)&&s.access.requests==0&&s.agent.activations==0);} // Each independent native reading must agree before readiness is reported; // disagreement must not eject/reboard someone already transitioning/inside. for(const auto& fault:std::vector>{ [](Setup& s){s.seat.occupant=nullptr;}, [](Setup& s){s.seat.occupant=&s.other;}, [](Setup& s){s.access.inside=false;}, [](Setup& s){s.access.compartment=&s.otherSeat;}, [](Setup& s){s.access.vehicle=&s.other;}, [](Setup& s){s.access.vehicle=nullptr;}, [](Setup& s){s.access.entering=true;}, [](Setup& s){s.access.exiting=true;}, [](Setup& s){s.actor.Access=nullptr;}, }) { Setup s;s.Seated();fault(s); assert(!s.flight.CrewSeated(&s.entry)&&!s.Tick(10000)); assert(s.access.requests==0&&s.entry.Attempts==0&&s.agent.activations==0); } // Unfit, player-controlled, foreign, replaced or missing actors/components // cannot receive another request, regardless of the elapsed retry interval. for(const auto& fault:std::vector>{ [](Setup& s){s.entry.Actor=nullptr;}, [](Setup& s){s.actor.player=true;}, [](Setup& s){s.actor.group=nullptr;}, [](Setup& s){s.actor.group=&s.other;}, [](Setup& s){s.actor.faction=2;}, [](Setup& s){s.actor.Control=nullptr;}, [](Setup& s){s.control.agent=&s.otherAgent;}, [](Setup& s){s.control.agent=nullptr;}, [](Setup& s){s.entry.Agent=nullptr;}, [](Setup& s){s.agent.playerPending=true;}, [](Setup& s){s.actor.fit=false;}, [](Setup& s){s.entry.Seat=nullptr;}, [](Setup& s){s.actor.Access=nullptr;}, [](Setup& s){s.access.entering=true;}, [](Setup& s){s.access.exiting=true;}, [](Setup& s){s.access.inside=true;s.access.compartment=&s.otherSeat;}, [](Setup& s){s.access.vehicle=&s.other;}, [](Setup& s){s.seat.occupied=true;}, [](Setup& s){s.seat.occupant=&s.other;}, [](Setup& s){s.seat.accessible=false;}, [](Setup& s){s.seat.locked=true;}, [](Setup& s){s.seat.reserved=true;s.seat.reservation=&s.other;}, }) { Setup s;assert(!s.Tick(1000));fault(s); assert(!s.Tick(10000)&&!s.Tick(20000)); assert(s.access.requests==1&&s.entry.Attempts==1&&s.entry.NextAttempt==6000); assert(s.agent.activations==1&&s.agent.lodWrites==1&&s.otherAgent.activations==0); } // Capture/group/control/health changes also prevent already seated readiness. for(const auto& fault:std::vector>{ [](Setup& s){s.actor.player=true;}, [](Setup& s){s.actor.group=&s.other;}, [](Setup& s){s.actor.faction=2;}, [](Setup& s){s.control.agent=&s.otherAgent;}, [](Setup& s){s.agent.playerPending=true;}, [](Setup& s){s.actor.fit=false;}, }) { Setup s;s.Seated();assert(s.Tick(1000));fault(s);assert(!s.Tick(10000)&&s.access.requests==0); } // Our own reservation is permitted. Native transitions can finish/fail on // their own schedule; skipped ticks do not burn attempts or push the deadline. {Setup s;s.seat.reserved=true;s.seat.reservation=&s.actor;assert(!s.Tick(1000)&&s.access.requests==1);} {Setup s;assert(!s.Tick(1000));s.access.entering=true;assert(!s.Tick(6000)&&!s.Tick(10000)); assert(s.entry.Attempts==1&&s.entry.NextAttempt==6000);s.access.entering=false; assert(!s.Tick(10250)&&s.entry.Attempts==2&&s.entry.NextAttempt==15250);} // Pilot and observer have independent request budgets. {Setup pilot,observer;for(float now:{1000.f,6000.f,11000.f})assert(!pilot.Tick(now)); assert(!pilot.Tick(16000)&&!observer.Tick(16000));assert(pilot.access.requests==3&&observer.access.requests==1);} } ''') print('PASS: production Cessna boarding requires exact observed occupancy, activates before requesting, caps retries at three with 5s spacing, and preserves transition, ownership, health and seat restrictions; engine behavior is faked')