Files
EscapistsReintroduced/tests/test_prison_escape_policy.py
jakub cab998fb64 Combine Workshop addon and fix prison startup
Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
2026-09-20 16:42:52 +02:00

80 lines
4.8 KiB
Python

"""Boundary/discontinuity regressions execute production policy bodies, not a copy.
Native probe separately exercises the direct locked-door boundary and destroyed gate.
"""
from policy_harness import ROOT, body, run
path=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_PrisonEscapeService.c'
functions='\n'.join(body(path,s) for s in ('static bool Inside(', 'static bool Continuous(', 'static bool Registration(', 'static bool Grounded(', 'static bool Crossing(')).replace('Math.AbsFloat','std::abs')
run('''#include <cassert>
#include <cmath>
#include <initializer_list>
'''+functions+'''
int main() {
// Initial identity, unique intact gate and complete bounded traversal required.
assert(Registration(true,1,true,true));
assert(!Registration(false,1,true,true));
assert(!Registration(true,0,true,true));
assert(!Registration(true,2,true,true));
assert(!Registration(true,1,false,true));
assert(!Registration(true,1,true,false));
// Four ordinary sides and diagonal boundary behavior; exact boundary still in.
for (float sign : {-1.f,1.f}) {
assert(Crossing(true,sign*7,0,sign*9,0,1000,2));
assert(Crossing(true,0,sign*7,0,sign*9,1000,2));
assert(!Crossing(true,sign*7,0,sign*8,0,1000,1));
}
assert(Crossing(true,7,7,9,9,1000,std::sqrt(8.f)));
// Gate health is deliberately absent: a registered genuine exit counts even
// when intact. Missing registration is still rejected above and by Tick.
// An unarmed/already-outside body or no crossing cannot finish prison.
assert(!Crossing(false,7,0,9,0,1000,2));
assert(!Crossing(true,4,0,5,0,1000,1));
assert(!Crossing(true,9,0,10,0,1000,1));
// Reject far teleport, expired sample, clock reversal/duplicate and flight.
assert(!Crossing(true,0,0,35,0,1000,35));
assert(!Crossing(true,7,0,9,0,2501,2));
assert(!Crossing(true,7,0,9,0,0,2));
assert(!Crossing(true,7,0,9,0,-1,2));
assert(Grounded(0.1f) && Grounded(2.5f));
assert(!Grounded(2.501f) && !Grounded(-0.501f));
// Native spawn candidates can arm; an outside/perimeter-only arrival cannot.
for (float x : {-4.5f,-1.5f,1.5f,4.5f})
for (float z : {-4.5f,-1.5f,1.5f,4.5f}) assert(Inside(x,z,5.5));
assert(!Inside(6,0,5.5) && Inside(6,0,8));
assert(Continuous(2500,31.5f) && !Continuous(2500,31.501f));
}
''')
print('PASS: actual prison registration/crossing policies reject missing/duplicate/destroyed initial gate, incomplete ownership/scan, outside-only body, jumps and stale samples; physical exit independent of later gate damage')
# Actual action bodies, with only native type/member syntax adapted to C++.
# This tests direct execution, not merely a duplicate availability predicate.
action_path=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_Actions.c'
class ActionSource:
def read_text(self):
source=action_path.read_text()
return source[source.index('class ERR_PrisonDoorAction'):source.index('class ERR_TuneRadioAction')]
action=ActionSource()
availability=body(action,'override bool CanBePerformedScript(').replace('override ','').replace('ERR_GameMode mode = ERR_GameMode.Get();','ERR_GameMode* mode = ERR_GameMode::Get();').replace('mode.Phase()','mode->Phase()').replace('ERR_Phase.PRISON','ERR_Phase::PRISON').replace('super.CanBePerformedScript','Base::CanBePerformedScript').replace('string.Empty','std::string{}')
execution=body(action,'override void PerformAction(').replace('override ','').replace('super.PerformAction','Base::PerformAction')
run('''#include <cassert>
#include <string>
using IEntity=int;
enum ERR_Phase {PREPARING,PRISON,RADIO_SEARCH,RADIO_DEFENCE};
struct ERR_GameMode {int phase=PRISON;static ERR_GameMode* current;static ERR_GameMode* Get(){return current;}int Phase(){return phase;}};
ERR_GameMode* ERR_GameMode::current=nullptr;
struct Base {void SetCannotPerformReason(const std::string&){}bool nativeAllowed=true;int calls=0,owner=0,user=0;bool CanBePerformedScript(IEntity){return nativeAllowed;}void PerformAction(IEntity pOwnerEntity,IEntity pUserEntity){calls++;owner=pOwnerEntity;user=pUserEntity;}};
struct Action:Base {
'''+availability+execution+'''
};
int main(){
Action action;action.PerformAction(42,7);assert(action.calls==0);
ERR_GameMode mode;ERR_GameMode::current=&mode;
mode.phase=PREPARING;action.PerformAction(42,7);assert(action.calls==0);
mode.phase=PRISON;action.PerformAction(42,7);assert(action.calls==0); // AI direct invocation blocked
mode.phase=RADIO_SEARCH;action.nativeAllowed=false;action.PerformAction(42,7);assert(action.calls==0);
action.nativeAllowed=true;action.PerformAction(42,7);assert(action.calls==1&&action.owner==42&&action.user==7);
mode.phase=RADIO_DEFENCE;action.PerformAction(42,8);assert(action.calls==2&&action.user==8);
mode.phase=PRISON;action.PerformAction(42,7);assert(action.calls==2); // revalidated at execution time
}
''')
print('PASS: actual prison door execution blocks direct AI/UI bypass while locked and delegates unchanged native action once after unlock and permission approval')