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.
92 lines
6.2 KiB
Python
92 lines
6.2 KiB
Python
"""Execute the actual full-salvo evidence gates; this is not a native firing result."""
|
|
from policy_harness import ROOT, body, run
|
|
p=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_NativeMortarSalvoProbe.c'
|
|
base=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_NativeMortarFiringProbe.c'
|
|
rules='\n'.join(body(base, sig) for sig in ['static bool AimFresh(', 'static bool CommitFresh(', 'static bool EventBound('])
|
|
rules=rules.replace('ERR_MortarPrediction.', 'ERR_MortarPrediction::')
|
|
complete=body(p,'static bool Complete(').replace('ERR_MortarSalvo.', 'ERR_MortarSalvo::')
|
|
methods='\n'.join(body(p,sig) for sig in ['void NativeCommit(', 'void NativeClosing(', 'void NativeProjectile('])
|
|
for a,b in [('ERR_MortarBattery battery','Battery* battery'),('IEntity gun, IEntity projectile','Entity* gun, Entity* projectile'),('string reason, string failure','std::string reason, std::string failure'),('m_Battery.','m_Battery->'),('battery.','battery->'),('Report.','Report->'),('projectile.GetOrigin()','projectile->GetOrigin()'),('GetGame().GetWorld().GetWorldTime()','clockNow'),('ERR_NativeMortarEvidenceRules.','ERR_NativeMortarEvidenceRules::'),('ERR_MortarSalvo.','ERR_MortarSalvo::')]: methods=methods.replace(a,b)
|
|
run('''#include <cassert>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <string>
|
|
float clockNow=20000;
|
|
struct ERR_MortarPrediction {static constexpr float MAX_REPORT_AGE_MS=60000;};
|
|
struct ERR_MortarSalvo {static constexpr int ROUNDS=8;};
|
|
struct ERR_NativeMortarEvidenceRules {'''+rules+'''};
|
|
struct Rules {'''+complete+'''};
|
|
struct Entity {int GetOrigin(){return 0;}};
|
|
struct Report {int MessageId=7;float ObservedAt=1000;};
|
|
struct Battery {void* Activity=nullptr;void* Refresh=nullptr;bool RefreshRejected=false;bool CommandOpen=true,Released=true,stopped=false;int SourceId=7,OrderId=1,OrderShots=0;float AimedAt=19000,AimValidatedAt=19000,FlightTime=20;struct Report report;struct Report* Report=&report;bool Stopped(){return stopped;}};
|
|
struct Items {std::vector<Entity*> values;bool Contains(Entity* p){return std::find(values.begin(),values.end(),p)!=values.end();}void Insert(Entity* p){values.push_back(p);}};
|
|
template<class... Args>void PrintFormat(Args...args){}
|
|
struct Probe {
|
|
void* m_OriginalActivity=nullptr;bool m_RefreshCase=false;int m_UpdatedCommits=0,m_CommitSource=0;float m_CommitObservedAt=0;
|
|
bool m_Stopped=false,m_BadProjectile=false,m_CommitPending=false,m_ClosureSeen=false,m_ClosureComplete=false;
|
|
Battery* m_Battery;Entity* m_Gun;Items m_Projectiles;int m_Events=0,m_Step=1,m_Source=7,m_Order=1,m_Commits=0,m_CommitOrder=0,m_CommitShot=0;float m_ObservedAt=1000,m_CommittedAt=0;std::string m_BadReason;
|
|
bool ReportKnown(Report* report){return report&&report->MessageId==m_Source&&report->ObservedAt==m_ObservedAt;}
|
|
bool AllAccepted(){return !m_RefreshCase;}
|
|
'''+methods+'''};
|
|
int main(){
|
|
assert(Rules::Complete(8,8,8,8,19,false));
|
|
for(int count=0;count<8;count++)assert(!Rules::Complete(count,count,count,count,27-count,false));
|
|
assert(!Rules::Complete(9,9,9,9,18,false));
|
|
assert(!Rules::Complete(8,7,8,8,19,false));
|
|
assert(!Rules::Complete(8,8,7,8,19,false));
|
|
assert(!Rules::Complete(8,8,8,7,19,false));
|
|
assert(!Rules::Complete(8,8,8,8,20,false));
|
|
assert(!Rules::Complete(8,8,8,8,18,false));
|
|
assert(!Rules::Complete(8,8,8,8,19,true));
|
|
Entity gun,foreign,shots[9];Battery b;Probe p;p.m_Battery=&b;p.m_Gun=&gun;
|
|
p.NativeProjectile(&foreign,&shots[0]);assert(p.m_Events==0);
|
|
for(int i=0;i<8;i++){
|
|
b.OrderShots=i;b.AimedAt=clockNow;b.AimValidatedAt=clockNow;
|
|
p.NativeCommit(&b,clockNow);assert(p.m_CommitPending&&!p.m_BadProjectile&&p.m_Commits==i+1);
|
|
clockNow+=500;p.NativeProjectile(&gun,&shots[i]);assert(p.m_Events==i+1&&!p.m_CommitPending&&!p.m_BadProjectile);
|
|
}
|
|
b.OrderShots=8;p.NativeClosing(&b,"native artillery activity COMPLETED (shot count is separate)","");
|
|
assert(p.m_ClosureSeen&&p.m_ClosureComplete&&!p.m_BadProjectile);
|
|
p.NativeCommit(&b,clockNow);assert(p.m_BadProjectile&&p.m_Commits==8); // ninth commit forbidden
|
|
for(int fault=0;fault<11;fault++){
|
|
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;clockNow=20000;
|
|
if(fault==0)f.report.ObservedAt=1001; // retimestamped contact
|
|
if(fault==1)f.OrderId=2;
|
|
if(fault==2)f.SourceId=8;
|
|
if(fault==3)f.OrderShots=1; // skipped physical event
|
|
if(fault==4)q.m_Step=2; // post-completion replay
|
|
if(fault==5)q.m_CommitPending=true;
|
|
if(fault==6){clockNow=61001;f.AimedAt=61000;f.AimValidatedAt=61000;}
|
|
if(fault==7)f.AimValidatedAt=9999;
|
|
if(fault==8)f.Released=false;
|
|
if(fault==9)f.CommandOpen=false;
|
|
if(fault==10)f.FlightTime=0;
|
|
q.NativeCommit(&f,clockNow);assert(q.m_BadProjectile&&q.m_Commits==0);
|
|
}
|
|
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;clockNow=20000;
|
|
q.NativeCommit(&f,clockNow);q.NativeProjectile(&gun,&shots[0]);q.NativeProjectile(&gun,&shots[0]);assert(q.m_BadProjectile&&q.m_Events==1);
|
|
for(int fault=0;fault<4;fault++){
|
|
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;q.m_Events=8;q.m_Commits=8;f.OrderShots=8;
|
|
std::string reason="native artillery activity COMPLETED (shot count is separate)";
|
|
if(fault==0){q.m_Events=4;q.m_Commits=4;f.OrderShots=4;}
|
|
if(fault==1)reason="native aim or firing authorization rejected";
|
|
if(fault==2)f.stopped=true;
|
|
if(fault==3)q.m_CommitPending=true;
|
|
q.NativeClosing(&f,reason,"delivered target report expired");assert(q.m_BadProjectile);
|
|
}
|
|
Battery stopped;Probe quiet;quiet.m_Battery=&stopped;quiet.m_Gun=&gun;quiet.m_Stopped=true;
|
|
quiet.NativeCommit(&stopped,20000);quiet.NativeProjectile(&gun,&shots[0]);quiet.NativeClosing(&stopped,"HQ stopped","");
|
|
assert(!quiet.m_BadProjectile&&quiet.m_Events==0&&quiet.m_Commits==0&&!quiet.m_ClosureSeen);
|
|
}
|
|
''')
|
|
# Native hooks must count only real events and retain the existing superclass behavior.
|
|
s=p.read_text()
|
|
assert s.startswith('#ifdef WORKBENCH') and 'outcome == "mortar-salvo"' in s
|
|
assert 'super.OnWeaponFired(effectEntity, muzzle, projectileEntity);' in s
|
|
assert 'super.ReserveShellAirspace(now);' in s and 'super.Cancel(reason);' in s
|
|
assert 'm_StopUntil = now + 25000' in s
|
|
assert 'm_Battery.CanRequest(m_Delivered, now)' in s
|
|
assert 'm_Battery.Order(' not in s and 'm_Battery.BeginRequest(' not in s
|
|
assert 'm_Battery.Stop();' in body(p,'void Stop(')
|
|
print('PASS: actual full-salvo gates require eight fresh committed physical launches, natural closure and exact finite inventory; reject partial/extra/replayed events')
|