Files
EscapistsReintroduced/tests/test_action_feedback.py
T

63 lines
4.9 KiB
Python

"""Execute actual action availability methods; native UI rendering is separate."""
from policy_harness import ROOT, body, run
source=(ROOT/'addons/core/Scripts/Game/ERR/ERR_Actions.c').read_text()
class Source:
def __init__(self,name): self.text=source.split('class '+name+' :',1)[1].split('\nclass ',1)[0]
def read_text(self): return self.text
def method(name):
s=body(Source(name),'override bool CanBePerformedScript(').replace('override ','')
s=s.replace('ERR_GameMode mode = ERR_GameMode.Get();','ERR_GameMode* mode = ERR_GameMode::Get();').replace('mode.Phase()','mode->Phase()')
s=s.replace('ERR_LocationComponent location = ERR_LocationComponent.Cast(GetOwner().FindComponent(ERR_LocationComponent));','Location* location = GetOwner()->location;')
s=s.replace('location.Knowledge()','location->Knowledge()').replace('ERR_Phase.','ERR_Phase::').replace('ERR_Actors.','ERR_Actors::')
return s.replace('string.Empty','string{}').replace('super.CanBePerformedScript','NativeDoor::CanBePerformedScript')
run(r'''
#include <cassert>
#include <string>
using string=std::string;
struct Actor{bool conscious=true;};using IEntity=Actor*;
namespace ERR_Actors{bool CanFight(IEntity a){return a&&a->conscious;}}
namespace ERR_Phase{enum Value{PREPARING,PRISON,RADIO_SEARCH,RADIO_DEFENCE,EXTRACTION,VICTORY,DEFEAT};}
struct ERR_GameMode{int phase=0;static ERR_GameMode* current;static ERR_GameMode* Get(){return current;}int Phase(){return phase;}};ERR_GameMode* ERR_GameMode::current=nullptr;
struct Location{int knowledge=0;int Knowledge(){return knowledge;}};
struct Owner{Location* location=nullptr;};
struct ActionBase{string reason="stale";Owner owner;void SetCannotPerformReason(string s){reason=s;}Owner* GetOwner(){return &owner;}};
struct NativeDoor:ActionBase{bool allowed=true,explain=true;int queries=0;bool CanBePerformedScript(IEntity){queries++;if(!allowed&&explain)SetCannotPerformReason("Native door obstructed");return allowed;}};
struct Unlock:ActionBase{
'''+method('ERR_UnlockPrisonAction')+r'''
};struct Door:NativeDoor{
'''+method('ERR_PrisonDoorAction')+r'''
};struct Radio:ActionBase{
'''+method('ERR_TuneRadioAction')+r'''
};
int main(){
Actor actor;ERR_GameMode mode;Location location;
for(int present=0;present<2;present++)for(int phase=0;phase<7;phase++)for(int conscious=0;conscious<2;conscious++)for(int known=-1;known<=3;known++)for(int presentLocation=0;presentLocation<2;presentLocation++){
ERR_GameMode::current=present?&mode:nullptr;mode.phase=phase;actor.conscious=conscious;location.knowledge=known;
Unlock unlock;Radio radio;radio.owner.location=presentLocation?&location:nullptr;
bool lockAllowed=present&&phase==ERR_Phase::PRISON&&conscious;
bool radioAllowed=present&&phase==ERR_Phase::RADIO_SEARCH&&presentLocation&&known==2&&conscious;
assert(unlock.CanBePerformedScript(&actor)==lockAllowed);assert(unlock.reason.empty()==lockAllowed);
assert(radio.CanBePerformedScript(&actor)==radioAllowed);assert(radio.reason.empty()==radioAllowed);
for(int native=0;native<2;native++){
Door door;door.allowed=native;bool doorAllowed=present&&phase>ERR_Phase::PRISON&&native;
assert(door.CanBePerformedScript(&actor)==doorAllowed);assert(door.reason.empty()==doorAllowed);
bool delegated=present&&phase>ERR_Phase::PRISON;assert(door.queries==(delegated?1:0));
if(delegated&&!native)assert(door.reason=="Native door obstructed");
}
}
ERR_GameMode::current=&mode;actor.conscious=true;Radio radio;radio.owner.location=&location;mode.phase=ERR_Phase::RADIO_SEARCH;location.knowledge=1;
assert(!radio.CanBePerformedScript(&actor)&&radio.reason.find("Identify")!=string::npos);
location.knowledge=2;assert(radio.CanBePerformedScript(&actor)&&radio.reason.empty());
actor.conscious=false;assert(!radio.CanBePerformedScript(&actor)&&radio.reason=="You must be alive and conscious");
actor.conscious=true;assert(radio.CanBePerformedScript(&actor)&&radio.reason.empty());
mode.phase=ERR_Phase::RADIO_DEFENCE;assert(!radio.CanBePerformedScript(&actor)&&radio.reason.find("already in progress")!=string::npos);
mode.phase=ERR_Phase::EXTRACTION;assert(!radio.CanBePerformedScript(&actor)&&radio.reason.find("complete")!=string::npos);
mode.phase=ERR_Phase::PRISON;Door door;assert(!door.CanBePerformedScript(&actor)&&door.reason.find("Pick the prison lock")!=string::npos);
mode.phase=ERR_Phase::RADIO_SEARCH;door.allowed=false;assert(!door.CanBePerformedScript(&actor)&&door.reason=="Native door obstructed");
door.allowed=true;assert(door.CanBePerformedScript(&actor)&&door.reason.empty());
door.allowed=false;door.explain=false;assert(!door.CanBePerformedScript(&actor)&&door.reason.empty()); // No stale native denial either.
mode.phase=ERR_Phase::PRISON;Unlock unlock;assert(!unlock.CanBePerformedScript(nullptr));assert(unlock.CanBePerformedScript(&actor)&&unlock.reason.empty());
}
''')
print('PASS: actual action permission matrix unchanged; useful phase/intel/consciousness denials, stale reason cleared, native door denial preserved; no native UI claim')