"""Run the production prison hold/release callbacks with engine boundaries stubbed.""" from policy_harness import ROOT, body, run from pathlib import Path import os source = Path(os.environ.get('ERR_PRISON_AI_SOURCE', ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_PrisonAI.c')) def cpp(signature): s=body(source,signature).replace('protected ','') for ns in ('Replication','SCR_Global','ERR_GameMode','ERR_Phase','ERR_Actors','SCR_FactionManager'): s=s.replace(ns+'.',ns+'::') s=s.replace('ERR_GameMode mode =','ERR_GameMode* mode =').replace('IEntity actor =','Actor* actor =') for var in ('mode','actor','m_ERRPrisonMode'): s=s.replace(var+'.',var+'->') s=s.replace('ERR_Phase previous, ERR_Phase current','int previous, int current') for callback in ('ERR_PrisonPhaseChanged','ERR_PrisonStopped'): s=s.replace('Insert('+callback+')','Insert("'+callback+'")').replace('Remove('+callback+')','Remove("'+callback+'")') s=s.replace('OnPhaseChanged().','OnPhaseChanged()->').replace('OnStop().','OnStop()->') return s run(r''' #include #include #include #define null nullptr namespace Replication {bool server=true;bool IsServer(){return server;}} namespace SCR_Global {bool edit=false;bool IsEditMode(){return edit;}} namespace ERR_Phase {constexpr int PRISON=1,RADIO_SEARCH=2;} struct Actor {bool player=false, fighting=true;int faction=2;}; namespace ERR_Actors {bool Player(Actor* a){return a&&a->player;}bool CanFight(Actor* a){return a&&a->fighting;}} namespace SCR_FactionManager {int SGetFaction(Actor* a){return a->faction;}} struct Hook {std::set callbacks;int inserted=0;void Insert(std::string c){callbacks.insert(c);inserted++;}void Remove(std::string c){callbacks.erase(c);}}; struct ERR_GameMode {static ERR_GameMode* current;int phase=0,enemy=2;Hook phases,stops; static ERR_GameMode* Get(){return current;}int Phase(){return phase;}int EnemyFaction(){return enemy;}bool IsMissionEnemy(int f){return enemy&&f>=enemy;} Hook* OnPhaseChanged(){return &phases;}Hook* OnStop(){return &stops;}}; ERR_GameMode* ERR_GameMode::current=nullptr; struct Agent {ERR_GameMode* m_ERRPrisonMode=nullptr;Actor* actor=nullptr;bool pending=false,active=true;int starts=0; Actor* GetControlledEntity(){return actor;}bool IsPlayerPending_S(){return pending;} void DeactivateAI(){active=false;}void ActivateAI(){active=true;starts++;} '''+cpp('bool ERR_PrisonHeldForTest(')+cpp('void ERR_HoldForPrison(')+cpp('protected void ERR_PrisonUnsubscribe(')+cpp('protected void ERR_PrisonPhaseChanged(')+cpp('protected void ERR_PrisonStopped(')+r''' }; int main(){ for(int phase=0;phase<=1;phase++){ ERR_GameMode mode;mode.phase=phase;ERR_GameMode::current=&mode;Actor actor;Agent a;a.actor=&actor; a.ERR_HoldForPrison();assert(a.ERR_PrisonHeldForTest());assert(!a.active&&mode.phases.callbacks.size()==1&&mode.stops.callbacks.size()==1); a.active=true;a.ERR_HoldForPrison();assert(!a.active&&mode.phases.inserted==1); a.ERR_PrisonPhaseChanged(0,1);assert(!a.active&&a.m_ERRPrisonMode==&mode); mode.phase=2;a.ERR_PrisonPhaseChanged(phase,2);assert(a.active&&a.starts==1&&!a.m_ERRPrisonMode&&mode.phases.callbacks.empty()&&mode.stops.callbacks.empty()); a.ERR_HoldForPrison();assert(a.active&&mode.phases.inserted==1); assert(!a.ERR_PrisonHeldForTest());a.DeactivateAI();assert(!a.active&&!a.ERR_PrisonHeldForTest()); } for(int fault=0;fault<8;fault++){ ERR_GameMode mode;ERR_GameMode::current=&mode;Actor actor;Agent a;a.actor=&actor; if(fault==0)Replication::server=false;if(fault==1)SCR_Global::edit=true; if(fault==2)ERR_GameMode::current=nullptr;if(fault==3)a.actor=nullptr; if(fault==4)actor.player=true;if(fault==5)a.pending=true; if(fault==6)actor.faction=1;if(fault==7)mode.enemy=0; a.ERR_HoldForPrison();assert(a.active&&!a.m_ERRPrisonMode&&mode.phases.callbacks.empty()); Replication::server=true;SCR_Global::edit=false; } // Dead/unconscious, newly possessed, pending-player and removed actors cannot // be activated by the release callback; all subscriptions are still removed. for(int fault=0;fault<4;fault++){ ERR_GameMode mode;ERR_GameMode::current=&mode;Actor actor;Agent a;a.actor=&actor;a.ERR_HoldForPrison(); if(fault==0)actor.fighting=false;if(fault==1)actor.player=true; if(fault==2)a.pending=true;if(fault==3)a.actor=nullptr; mode.phase=2;a.ERR_PrisonPhaseChanged(1,2);assert(!a.active&&a.starts==0&&mode.phases.callbacks.empty()); } {ERR_GameMode mode;ERR_GameMode::current=&mode;Actor actor;Agent a;a.actor=&actor;a.ERR_HoldForPrison(); a.ERR_PrisonStopped();assert(!a.active&&a.starts==0&&!a.m_ERRPrisonMode&&mode.phases.callbacks.empty()&&mode.stops.callbacks.empty());} } '''.replace(';if(', ';\n if(')) print('PASS: production prison AI hold/release, repeat activation, authority/faction/player exclusion, dead actor and stop cleanup')