"""Execute both production monitor bodies; native hint/camera boundaries are fakes.""" from policy_harness import ROOT, body, run from pathlib import Path import os GUIDE=Path(os.environ.get('ERR_GUIDE_SOURCE', ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_PlayerGuide.c')) OBSERVER=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_Observer.c' def cpp(text): text=text.replace('protected ', '').replace('override ', '').replace('super.OnControlledEntityChanged(from, to);', 'nativeChanges++;') for name in ('ERR_GameMode','ERR_Phase','ERR_ObserverReason','ERR_Actors','ERR_ObjectiveText','SCR_HintManagerComponent','ERR_ObserverGuidance','Resource','ETransformMode','SCR_ManualCamera','SCR_RespawnSystemComponent','RplId'): text=text.replace(name+'.',name+'::') for typename in ('ERR_GameMode','SCR_HintManagerComponent','Resource','SCR_RespawnSystemComponent','CameraManager'): text=text.replace(typename+' ',typename+'* ') for variable in ('mode','hints','resource','respawn','manager'): text=text.replace(variable+'.',variable+'->') text=text.replace('GetGame().','GetGame()->').replace('EntitySpawnParams params = new EntitySpawnParams();','EntitySpawnParams params;') return text methods=cpp(body(GUIDE,'override void OnControlledEntityChanged('))+'\n'+cpp(body(GUIDE,'protected void ERR_UpdateGuide('))+'\n'+cpp(body(OBSERVER,'protected void ERR_UpdateObserverClient(')) guidance=cpp(body(OBSERVER,'static string Message('))+'\n'+cpp(body(OBSERVER,'static bool Refresh(')) run(r'''#include #include struct string:std::string {using std::string::string;using std::string::operator=;string(std::string s):std::string(s){}bool IsEmpty()const{return empty();}}; namespace ERR_Phase {enum {PREPARING,PRISON,RADIO_SEARCH,RADIO_DEFENCE,EXTRACTION};} namespace ERR_ObserverReason {enum {NONE,SPENT_LIFE,LATE_EXTRACTION,SPAWN_UNAVAILABLE};} struct Actor {bool alive=true;bool unconscious=false;} actor;using IEntity=Actor*; struct ERR_Actors {static bool Alive(Actor* a){return a&&a->alive;}}; struct ERR_GameMode {int phase=ERR_Phase::PRISON;bool active=true;string message="prison";static ERR_GameMode* current;static ERR_GameMode* Get(){return current;}int Phase(){return phase;}bool Active(){return active;}} mode; ERR_GameMode* ERR_GameMode::current=&mode; struct ERR_ObjectiveText {static string Description(ERR_GameMode* m,bool){return m->message;}static string Title(int){return "objective";}}; struct SCR_HintManagerComponent {static SCR_HintManagerComponent* current;bool accepts=true;int attempts=0,shown=0;string last;static SCR_HintManagerComponent* GetInstance(){return current;}bool ShowCustom(string text,string,int){attempts++;if(!accepts)return false;shown++;last=text;return true;}} hints; SCR_HintManagerComponent* SCR_HintManagerComponent::current=&hints; struct ERR_ObserverGuidance { '''+guidance+r''' }; struct Vec {Vec operator+(const char*)const{return {};}}; struct EntitySpawnParams {int TransformMode=0;Vec Transform[4];}; namespace ETransformMode {enum {WORLD};} struct Resource {bool valid=true;static Resource* current;static Resource* Load(const char*){return current;}bool IsValid(){return valid;}} resource; Resource* Resource::current=&resource; struct SCR_ManualCamera {static SCR_ManualCamera* Cast(SCR_ManualCamera* c){return c;}} camera; struct CameraManager {SCR_ManualCamera* current=&camera;SCR_ManualCamera* CurrentCamera(){return current;}} manager; struct SCR_RespawnSystemComponent {int destroys=0;static SCR_RespawnSystemComponent* current;static SCR_RespawnSystemComponent* GetInstance(){return current;}void DestroyLoadingPlaceholder(){destroys++;}} respawn; SCR_RespawnSystemComponent* SCR_RespawnSystemComponent::current=&respawn; struct RplId {static int Invalid(){return -1;}}; struct Game {int spawns=0;SCR_ManualCamera* SpawnEntityPrefab(Resource*,int,EntitySpawnParams){spawns++;return &camera;}int GetWorld(){return 1;}CameraManager* GetCameraManager(){return &manager;}} game; Game* GetGame(){return &game;} struct Controller { int nativeChanges=0,starts=0;void ERR_StartGuide(){starts++;} int m_ERRGuidePhase=-1;string m_ERRGuideMessage; Actor* controlled=&actor;int m_ERRObserverReason=ERR_ObserverReason::NONE; SCR_ManualCamera* m_ERRObserverCamera=nullptr;Vec m_ERRObserverAnchor; int m_ERRObservedId=1;bool m_ERRObserverReady=false; int m_ERRShownObserverReason=0;bool m_ERRShownObserverAvailable=false;int closes=0; Actor* GetControlledEntity(){return controlled;}int ERR_ObserverState(){return m_ERRObserverReason;} void ERR_CloseObserverCamera(){closes++;m_ERRObserverReady=false;m_ERRObserverCamera=nullptr;} '''+methods+r''' }; void reset(){mode=ERR_GameMode();ERR_GameMode::current=&mode;hints=SCR_HintManagerComponent();SCR_HintManagerComponent::current=&hints;actor=Actor();Resource::current=&resource;manager.current=&camera;} int main(){ reset();Controller g; SCR_HintManagerComponent::current=nullptr;g.ERR_UpdateGuide();assert(g.m_ERRGuidePhase==-1&&hints.attempts==0); SCR_HintManagerComponent::current=&hints;hints.accepts=false; g.ERR_UpdateGuide();g.ERR_UpdateGuide();assert(hints.attempts==2&&hints.shown==0&&g.m_ERRGuidePhase==-1&&g.m_ERRGuideMessage.empty()); hints.accepts=true;g.ERR_UpdateGuide();assert(hints.shown==1&&g.m_ERRGuidePhase==mode.phase&&g.m_ERRGuideMessage==mode.message); g.ERR_UpdateGuide();assert(hints.attempts==3); mode.message="";g.ERR_UpdateGuide();assert(hints.attempts==3&&g.m_ERRGuideMessage=="prison"); // Same-phase content updates are retryable and do not erase the delivered cache. mode.message="transmission interrupted";hints.accepts=false;g.ERR_UpdateGuide();assert(g.m_ERRGuideMessage=="prison"); hints.accepts=true;g.ERR_UpdateGuide();assert(hints.shown==2&&g.m_ERRGuideMessage==mode.message); mode.phase=ERR_Phase::RADIO_SEARCH;g.ERR_UpdateGuide();assert(hints.shown==3); // Reacquiring a character in the same phase clears delivery once; native // lifecycle and the existing monitor remain responsible for actual delivery. Actor replacement;int shown=hints.shown; g.OnControlledEntityChanged(&actor,&replacement);g.controlled=&replacement; assert(g.nativeChanges==1&&g.starts==1&&g.m_ERRGuidePhase==-1); hints.accepts=false;g.ERR_UpdateGuide();assert(hints.shown==shown&&g.m_ERRGuidePhase==-1); hints.accepts=true;g.ERR_UpdateGuide();assert(hints.shown==shown+1); g.ERR_UpdateGuide();assert(hints.shown==shown+1); g.OnControlledEntityChanged(&replacement,&replacement);g.ERR_UpdateGuide();assert(hints.shown==shown+1); g.OnControlledEntityChanged(&replacement,nullptr);g.controlled=nullptr; g.ERR_UpdateGuide();assert(hints.shown==shown+1); g.OnControlledEntityChanged(nullptr,&replacement);g.controlled=&replacement; g.ERR_UpdateGuide();assert(hints.shown==shown+2&&g.nativeChanges==4&&g.starts==4); // Explicit observation, death and absence suppress ordinary phase instructions. for(int excluded=0;excluded<3;excluded++){ Controller c;if(excluded==0)c.m_ERRObserverReason=ERR_ObserverReason::SPENT_LIFE; if(excluded==1){actor.alive=false;}if(excluded==2){c.controlled=nullptr;} int attempts=hints.attempts;c.ERR_UpdateGuide();assert(hints.attempts==attempts&&c.m_ERRGuidePhase==-1); actor.alive=true;c.controlled=&actor;c.m_ERRObserverReason=ERR_ObserverReason::NONE;c.ERR_UpdateGuide();assert(hints.attempts==attempts+1); } // Unconscious living prisoners retain recovery guidance. Preparing needs no body. Controller unconscious;actor.unconscious=true;unconscious.ERR_UpdateGuide();assert(unconscious.m_ERRGuidePhase==mode.phase);actor.unconscious=false; Controller preparing;preparing.controlled=nullptr;mode.phase=ERR_Phase::PREPARING;mode.message="preparing";preparing.ERR_UpdateGuide();assert(preparing.m_ERRGuideMessage=="preparing"); ERR_GameMode::current=nullptr;int attempts=hints.attempts;preparing.ERR_UpdateGuide();assert(hints.attempts==attempts); reset();Controller s;s.controlled=nullptr;s.m_ERRObserverReason=ERR_ObserverReason::SPENT_LIFE; // Actual camera setup executes; missing manager cannot consume delivery state. SCR_HintManagerComponent::current=nullptr;s.ERR_UpdateObserverClient();assert(s.m_ERRObserverCamera==&camera&&!s.m_ERRObserverReady); SCR_HintManagerComponent::current=&hints;hints.accepts=false;s.ERR_UpdateObserverClient();s.ERR_UpdateObserverClient();assert(hints.attempts==2&&!s.m_ERRObserverReady&&s.m_ERRShownObserverReason==0); hints.accepts=true;s.ERR_UpdateObserverClient();assert(hints.shown==1&&s.m_ERRObserverReady&&s.m_ERRShownObserverReason==ERR_ObserverReason::SPENT_LIFE&&s.m_ERRShownObserverAvailable); s.ERR_UpdateObserverClient();assert(hints.attempts==3); // Reason changes and a genuinely empty survivor set retry independently. s.m_ERRObserverReason=ERR_ObserverReason::LATE_EXTRACTION;hints.accepts=false;s.ERR_UpdateObserverClient();assert(s.m_ERRShownObserverReason==ERR_ObserverReason::SPENT_LIFE); hints.accepts=true;s.ERR_UpdateObserverClient();assert(s.m_ERRShownObserverReason==ERR_ObserverReason::LATE_EXTRACTION&&hints.shown==2); s.m_ERRObservedId=RplId::Invalid();hints.accepts=false;s.ERR_UpdateObserverClient();assert(s.m_ERRShownObserverAvailable); hints.accepts=true;s.ERR_UpdateObserverClient();assert(!s.m_ERRShownObserverAvailable&&hints.last.find("No survivor")!=string::npos); s.ERR_UpdateObserverClient();assert(hints.shown==3); // A living body closes observation without attempting a spectator hint. s.controlled=&actor;attempts=hints.attempts;s.ERR_UpdateObserverClient();assert(s.closes==1&&!s.m_ERRObserverReady&&hints.attempts==attempts); s.controlled=nullptr;s.ERR_UpdateObserverClient();assert(hints.shown==4&&s.m_ERRObserverReady); } ''') for path,signature in ((GUIDE,'protected void ERR_UpdateGuide('),(OBSERVER,'protected void ERR_UpdateObserverClient(')): assert 'CallLater' not in body(path,signature), 'Delivery retry uses the existing monitor only' print('PASS: actual guide/observer monitors retry native refusal, cache successful delivery, deduplicate and preserve living/preparing/spectator boundaries; native UI not exercised')