Files
EscapistsReintroduced/tests/test_aircraft_field_flight.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

222 lines
26 KiB
Python

"""Execute prototype flight methods with real rules; native boundaries are fakes."""
from policy_harness import ROOT, body, run
import re
P=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_AircraftFieldFlight.c'
B=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_AircraftFlight.c'
R=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_AircraftFieldRules.c'
source=P.read_text()
def cpp(s):
s=s.replace('protected ','').replace('override ','').replace('ref ','').replace('super.','Base::')
for old,new in [('ERR_AircraftFlightState.','State::'),('ERR_AircraftFlightRules.','FlightRules::'),('ERR_AircraftFieldRules.','Rules::'),('ERR_AircraftTranslationRules.','TranslationRules::'),('Math.','Math::'),('vector.','vector::')]:s=s.replace(old,new)
s=s.replace('ERR_AircraftFieldEnvelope m_Field;', 'ERR_AircraftFieldEnvelope* m_Field=nullptr;')
s=s.replace('FuelManagerComponent fuel = FuelManagerComponent.Cast(aircraft.FindComponent(FuelManagerComponent));','FuelManagerComponent* fuel = FixtureFuel(aircraft);')
s=s.replace('fuel.', 'fuel->').replace('m_Fuel.', 'm_Fuel->')
s=s.replace('ERR_AircraftFieldEnvelope field','ERR_AircraftFieldEnvelope* field').replace('ERR_AircraftFlightEnvelope qualification','int qualification')
s=s.replace('SignalsManagerComponent signals','SignalsManagerComponent* signals').replace('ActionManager actions','ActionManager* actions')
for name in ('field','m_Field','signals','actions'):s=s.replace(name+'.',name+'->')
s=s.replace('"0 0 0"','vector{}').replace('out vector nextIntegral','vector& nextIntegral')
return s
rules=cpp(R.read_text().replace('class ERR_AircraftFieldRules','struct Rules')).rstrip()+';'
fields=cpp(source[source.index(' protected ref'):source.index(' int FieldPhase()')])
# Explicit defaults emulate Enforce's zero-initialized script fields.
fields=re.sub(r'(bool m_\w+);',r'\1=false;',fields)
fields=re.sub(r'(int m_\w+);',r'\1=0;',fields)
methods='\n'.join(cpp(body(P,k)) for k in (
'protected bool FuelAdmission(', 'bool StartField(', 'override bool Start(', 'override bool StartTranslation(',
'protected bool FieldContains(', 'protected override bool Grounded(',
'protected bool BeginFieldBrake(', 'protected override bool Landing(',
'protected override bool BeginTranslation(', 'protected override bool ControlLease(',
'protected vector FieldDemand(', 'override void PrepareActions(',
'protected override void CheckTranslation(', 'override void Tick('))
run(r'''#include <cassert>
#include <cmath>
#include <algorithm>
#include <string>
#include <initializer_list>
#define PrintFormat(...) ((void)0)
using string=std::string;using ERR_GameMode=int;using Vehicle=int;using SCR_AIGroup=int;using IEntity=int;using PilotCompartmentSlot=int;using CharacterControllerComponent=int;
namespace State {enum {IDLE,HOOKS,STARTING,POSITIVE,NEGATIVE,CLIMB,LANDING,SHUTDOWN,COMPLETE,CANCELLED,FAILED,RELINQUISHED,TRANSLATING};}
struct vector {
float v[3]={0,0,0};vector()=default;vector(float x,float y,float z):v{x,y,z}{}
float& operator[](int i){return v[i];}float operator[](int i)const{return v[i];}
vector operator+(vector b)const{return {v[0]+b[0],v[1]+b[1],v[2]+b[2]};}vector operator-(vector b)const{return {v[0]-b[0],v[1]-b[1],v[2]-b[2]};}vector operator*(float s)const{return {v[0]*s,v[1]*s,v[2]*s};}
float Length()const{return std::sqrt(Dot(*this,*this));}static float Dot(vector a,vector b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}static float DistanceXZ(vector a,vector b){return std::hypot(a[0]-b[0],a[2]-b[2]);}
};
struct Math {static float AbsFloat(float x){return std::abs(x);}static float Clamp(float x,float lo,float hi){return std::clamp(x,lo,hi);}static float Min(float a,float b){return std::min(a,b);}static float Max(float a,float b){return std::max(a,b);}static float Sqrt(float a){return std::sqrt(a);}};
'''+rules+r'''
struct FlightRules {
'''+''.join(cpp(body(B,k)) for k in ('static bool Hover(', 'static float Vertical(', 'static int CancelAction('))+r'''
};
struct TranslationRules {
'''+cpp(body(B,'static vector Demand('))+r'''
};
struct ERR_AircraftFieldEnvelope {vector home={0,0,0},destination={100,0,0};bool available=true;vector Home(){return home;}vector Destination(){return destination;}bool Contains(vector p,float u){return available&&Rules::Contains(home,destination,p,u);}};
struct SignalsManagerComponent {bool available=true;int FindSignal(const char*){return available?1:-1;}};
struct Controller {bool hover=true,engine=true,enableAllowed=true;int hoverWrites=0;SignalsManagerComponent signals;explicit operator bool()const{return true;}SignalsManagerComponent* GetSignalsManager(){return &signals;}bool GetAutohoverEnabled(){return hover;}void SetAutohoverEnabled(bool enabled){hoverWrites++;if(enableAllowed)hover=enabled;}bool IsEngineOn(){return engine;}};
struct Simulation {vector velocity,angular;bool contact=false;vector GetVelocity(){return velocity;}vector GetAngularVelocityLocal(){return angular;}bool HasAnyGroundContact(){return contact;}};
struct Aircraft {vector origin={0,8,0};float upright=1;vector GetOrigin(){return origin;}vector GetYawPitchRoll(){return {};}void GetWorldTransform(vector (&t)[4]){t[0]={1,0,0};t[1]={0,upright,0};t[2]={0,0,1};t[3]=origin;}};
struct ActionManager {bool active=true;int activated=0;bool IsContextActive(const char*){return active;}void ActivateContext(const char*,int){activated++;}};
struct FuelManagerComponent {float total=100;bool present=true;bool HasFuel(){return present&&total>0;}float GetTotalFuel(){return total;}};
FuelManagerComponent fuelBoundary;FuelManagerComponent* FixtureFuel(int aircraft){return aircraft==2?&fuelBoundary:nullptr;}
struct Base {
bool m_StartAttempted=false,m_TranslationRequested=false,m_TranslationStarted=false,m_TranslationProven=false,m_Readback=true,m_Cancelled=false;
vector m_TranslationTarget,m_TranslationOrigin,m_Home;float m_TranslationDistance=0,m_Stable=-1,m_Deadline=240000,m_StageDeadline=240000,m_LastControl=0,m_LastTick=-1,m_Collective=-.8,m_Heading=0,clock=0;
int m_State=State::IDLE,m_Token=0,m_TranslationUpdates=0,m_ActionUpdates=0,m_HelicopterUpdates=0,m_Character=11,m_Pilot=12;
FuelManagerComponent* m_Fuel=&fuelBoundary;Controller m_Controller;Simulation m_Simulation;Aircraft m_Aircraft;ActionManager manager;ActionManager* m_Actions=&manager;string m_Reason;
bool owner=true,healthy=true,leased=true,grounded=false,pairsOkay=true,startOkay=true;
int starts=0,claims=0,landings=0,failures=0,relinquished=0,releases=0,shutdowns=0,pairs=0,baseInputs=0,baseTicks=0;float collectiveWrite=0,forwardWrite=0,asideWrite=0;
bool Start(ERR_GameMode,Vehicle,SCR_AIGroup,IEntity,PilotCompartmentSlot,ERR_AircraftFieldEnvelope* q,int token,float deadline){m_StartAttempted=true;starts++;if(!startOkay)return false;claims++;m_Home=q->Home();m_Token=token;m_Deadline=deadline;m_State=State::HOOKS;return true;}
virtual bool Grounded(){return grounded;}virtual bool Landing(float now){landings++;m_State=State::LANDING;m_Stable=-1;m_StageDeadline=Math::Min(m_Deadline,now+65000);return true;}
virtual bool BeginTranslation(float,vector){assert(false);return false;}
bool Owns(){return owner;}bool Healthy(){return healthy;}bool Lease(){return leased&&!Finished();}float Now(){return clock;}bool Finished(){return m_State>=State::COMPLETE&&m_State<=State::RELINQUISHED;}
void Fail(string r){m_Reason=r;failures++;m_State=State::FAILED;}void Relinquish(string r){m_Reason=r;relinquished++;m_State=State::RELINQUISHED;}void Release(bool){releases++;}void RecordState(){}void Shutdown(float now){shutdowns++;m_State=State::SHUTDOWN;m_StageDeadline=Math::Min(m_Deadline,now+15000);m_Stable=-1;m_Controller.engine=false;}
bool Pair(const char* p,const char*,float value){pairs++;string name=p;if(name=="HelicopterCollectiveIncrease")collectiveWrite=value;if(name=="HelicopterCyclicForward")forwardWrite=value;if(name=="HelicopterCyclicRight")asideWrite=value;return pairsOkay;}
void PrepareActions(int,int,ActionManager*,float){baseInputs++;}void Tick(){baseTicks++;}
'''+cpp(body(B,'void Cancel('))+r'''
};
struct Flight:Base {
'''+fields+methods+r'''
};
void started(Flight& f,ERR_AircraftFieldEnvelope& q){assert(f.StartField(1,2,3,4,5,&q,77,240000));f.m_State=State::CLIMB;f.clock=60000;f.m_LastControl=f.clock;assert(f.BeginTranslation(f.clock,{0,8,0}));}
bool near(float a,float b){return std::abs(a-b)<.0001f;}
int main(){
ERR_AircraftFieldEnvelope q;
Flight fuelCheck;assert(!fuelCheck.FuelAdmission(0)&&!fuelCheck.FuelAdmission(999));fuelBoundary.total=49.99f;assert(!fuelCheck.StartField(1,2,3,4,5,&q,77,240000)&&fuelCheck.starts==0&&fuelCheck.claims==0&&!fuelCheck.m_Field);
fuelBoundary.total=50;assert(fuelCheck.FuelAdmission(2));fuelBoundary.present=false;assert(!fuelCheck.FuelAdmission(2));fuelBoundary.present=true;fuelBoundary.total=100;
Flight refuse;assert(!refuse.StartField(1,2,3,4,5,nullptr,77,240000)&&refuse.starts==0);
q.destination={101,0,0};assert(!refuse.StartField(1,2,3,4,5,&q,77,240000)&&refuse.starts==0);q.destination={100,0,0};
assert(!refuse.StartField(1,2,3,4,5,&q,77,238999)&&refuse.starts==0);
assert(!refuse.Start(1,2,3,4,5,1,77,240000));assert(!refuse.StartTranslation(1,2,3,4,5,1,77,240000,{100,0,0}));
Flight f;started(f,q);assert(f.starts==1&&f.claims==1&&f.m_Field==&q&&f.m_TranslationTarget[0]==100&&f.m_TranslationTarget[1]==8&&f.m_Token==77&&f.m_Deadline==240000);
assert(!f.StartField(1,2,3,4,5,&q,78,240000)&&f.starts==1);
assert(f.m_State==State::TRANSLATING&&f.m_FieldPhase==1&&f.m_StageDeadline==220000);
f.CheckTranslation(61000,{-0.23f,8,0},8,0,1);assert(f.m_FieldPhase==1); // actual post-hover distance can exceed100m
vector demand=f.FieldDemand({0,8,0},{},.1f);assert(f.m_FieldReference[0]>0&&f.m_FieldReference.Length()<=.020001f&&demand.Length()<=.080001f);
f.m_FieldReference={2,0,0};f.m_FieldIntegral={1,0,0};f.m_Aircraft.origin={80,8,0};f.m_Simulation.velocity={2,0,0};
f.CheckTranslation(89000,f.m_Aircraft.origin,8,2,1);assert(f.m_FieldPhase==1);
f.m_Aircraft.origin={82,8,0};
f.CheckTranslation(90000,f.m_Aircraft.origin,8,2,1);assert(f.m_FieldPhase==2&&f.m_FieldStopFrozen&&f.m_FieldLandingPoint[0]==100&&f.m_State==State::TRANSLATING&&f.landings==0&&f.m_StageDeadline==135000);
float brakeDeadline=f.m_StageDeadline;assert(f.m_FieldIntegral.Length()==0&&f.m_FieldReference.Length()==2);
auto firstBrake=f.FieldDemand(f.m_Aircraft.origin,f.m_Simulation.velocity,.1f);assert(f.m_FieldReference.Length()<2&&f.m_FieldReference.Length()>=1.9799f&&firstBrake.Length()<=.080001f);
float previous=f.m_FieldReference.Length();for(int i=0;i<20;i++){f.FieldDemand({85,8,0},{1.9f,0,0},.1f);assert(f.m_FieldReference.Length()<=previous+.000001f);previous=f.m_FieldReference.Length();}
auto savedIntegral=f.m_FieldIntegral;auto savedReference=f.m_FieldReference;
f.clock=91000;f.Cancel("stop during brake");assert(f.m_Cancelled&&f.m_FieldLandingPoint[0]==100&&f.m_StageDeadline==brakeDeadline&&f.landings==0);
f.clock=92000;f.Cancel("duplicate");assert(f.m_Reason=="stop during brake"&&f.m_StageDeadline==brakeDeadline&&f.m_Token==77&&(f.m_FieldReference-savedReference).Length()==0&&(f.m_FieldIntegral-savedIntegral).Length()==0);
for(int i=0;i<100;i++)f.FieldDemand(f.m_Aircraft.origin,f.m_Simulation.velocity,.1f);
assert(f.m_FieldReference.Length()<=.00001f);
f.m_Simulation.velocity={.1f,0,0};f.CheckTranslation(92000,{99.6f,8,0},8,.1f,1);f.CheckTranslation(93999,{99.6f,8,0},8,.1f,1);assert(f.m_FieldPhase==2);
f.m_Simulation.velocity={.3f,0,0};f.CheckTranslation(94000,{99.6f,8,0},8,.3f,1);assert(f.m_FieldLowSince<0);
f.m_Simulation.velocity={.1f,0,0};f.CheckTranslation(95000,{99.6f,8,0},8,.1f,1);f.CheckTranslation(97000,{99.6f,8,0},8,.1f,1);
assert(f.m_FieldPhase==3&&f.m_FieldIntegral.Length()==0&&f.m_FieldReference.Length()==0&&f.m_StageDeadline==brakeDeadline&&f.landings==0);
f.CheckTranslation(101999,{99.6f,8,0},8,.1f,1);assert(f.landings==0);
f.CheckTranslation(102000,{99.6f,8,0},8,.1f,1);assert(f.landings==1&&f.m_State==State::LANDING&&!f.m_FieldArrived&&!f.m_TranslationProven&&f.m_StageDeadline==127000&&f.m_Deadline==240000);
// A slow/unresponsive body cannot settle while a large slewed reference remains.
Flight lag;started(lag,q);lag.m_Aircraft.origin={50,8,0};lag.m_Simulation.velocity={1,0,0};lag.m_FieldReference={2,0,0};lag.m_FieldIntegral={4,0,0};lag.clock=70000;lag.Cancel("lag stop");
assert(lag.m_FieldIntegral.Length()==0&&lag.m_FieldReference[0]==2);
auto lagPoint=lag.m_FieldLandingPoint;auto lagDeadline=lag.m_StageDeadline;
vector lagDemand=lag.FieldDemand(lag.m_Aircraft.origin,lag.m_Simulation.velocity,.1f);
assert(near(lag.m_FieldReference[0],1.98f)&&lagDemand[0]>0); // preserve, disclose native lag risk
lag.m_Simulation.velocity={.1f,0,0};lag.CheckTranslation(70000,lag.m_Aircraft.origin,8,.1f,1);lag.CheckTranslation(72000,lag.m_Aircraft.origin,8,.1f,1);assert(lag.m_FieldPhase==2);
for(int i=0;i<110;i++)lag.FieldDemand(lag.m_Aircraft.origin,lag.m_Simulation.velocity,.1f);
lag.CheckTranslation(73000,lag.m_Aircraft.origin,8,.1f,1);assert(lag.m_FieldPhase==3&&lag.m_FieldLandingPoint[0]==lagPoint[0]&&lag.m_StageDeadline==lagDeadline);
// Reversed native velocity does not reverse the braking reference toward the target.
Flight opposite;started(opposite,q);opposite.m_Aircraft.origin={50,8,0};opposite.m_Simulation.velocity={-1,0,0};opposite.m_FieldReference={-2,0,0};opposite.m_FieldIntegral={-3,0,0};opposite.clock=70000;opposite.Cancel("opposing stop");
assert(opposite.m_FieldIntegral.Length()==0&&opposite.m_FieldLandingPoint[0]<50);
for(int i=0;i<110;i++){
vector before=opposite.m_FieldReference;opposite.FieldDemand({60,8,0},opposite.m_Simulation.velocity,.1f);
assert(opposite.m_FieldReference[0]<=.000001f&&opposite.m_FieldReference.Length()<=before.Length()+.000001f&&(opposite.m_FieldReference-before).Length()<=.020001f);
}
assert(opposite.m_FieldReference.Length()<=.00001f);
// Below-threshold jitter resets the observed hold only when speed reaches .25.
Flight jitter;started(jitter,q);jitter.m_Aircraft.origin={99.8f,8,0};assert(jitter.BeginFieldBrake(80000));
jitter.m_Simulation.velocity={.249f,0,0};jitter.CheckTranslation(80000,jitter.m_Aircraft.origin,8,.249f,1);
jitter.m_Simulation.velocity={.25f,0,0};jitter.CheckTranslation(81999,jitter.m_Aircraft.origin,8,.25f,1);assert(jitter.m_FieldLowSince<0);
jitter.m_Simulation.velocity={0,0,0};jitter.CheckTranslation(82000,jitter.m_Aircraft.origin,8,0,1);jitter.CheckTranslation(83999,jitter.m_Aircraft.origin,8,0,1);assert(jitter.m_FieldPhase==2);jitter.CheckTranslation(84000,jitter.m_Aircraft.origin,8,0,1);assert(jitter.m_FieldPhase==3);
// A ground-assisted stop cannot qualify or resume the airborne braking profile.
Flight contactAdmission;started(contactAdmission,q);contactAdmission.m_Simulation.contact=true;
assert(!contactAdmission.BeginFieldBrake(70000)&&contactAdmission.m_State==State::FAILED&&!contactAdmission.m_FieldStopFrozen&&contactAdmission.m_Controller.hoverWrites==0);
Flight contactWrite;started(contactWrite,q);assert(contactWrite.BeginFieldBrake(70000));contactWrite.m_Simulation.contact=true;
contactWrite.PrepareActions(contactWrite.m_Character,contactWrite.m_Pilot,contactWrite.m_Actions,.1f);
assert(contactWrite.m_State==State::FAILED&&contactWrite.pairs==0&&!contactWrite.m_FieldArrived);
contactWrite.m_Simulation.contact=false;contactWrite.Tick();assert(contactWrite.m_State==State::FAILED&&contactWrite.landings==0);
Flight contactStop;started(contactStop,q);assert(contactStop.BeginFieldBrake(70000));contactStop.m_FieldLowSince=70000;contactStop.m_Simulation.contact=true;
contactStop.CheckTranslation(73000,{99.8f,0,0},0,0,1);
assert(contactStop.m_State==State::FAILED&&contactStop.m_FieldPhase==2&&!contactStop.m_FieldArrived&&contactStop.landings==0);
// Real contact remains valid only after the existing airborne hold admitted landing.
Flight permittedLanding;started(permittedLanding,q);permittedLanding.m_FieldPhase=3;permittedLanding.m_State=State::LANDING;permittedLanding.m_Simulation.contact=true;
assert(permittedLanding.ControlLease()&&permittedLanding.failures==0);
// Grounded completion requires exact frozen centre, stable native contact and shutdown.
f.grounded=true;f.m_Aircraft.origin={98,0,0};assert(!f.Grounded());f.m_Aircraft.origin={99.6f,0,0};assert(f.Grounded());
f.clock=103000;f.m_LastControl=f.clock;f.Tick();f.clock=104000;f.m_LastControl=f.clock;f.Tick();f.clock=104999;f.m_LastControl=f.clock;f.Tick();assert(f.shutdowns==0);
f.clock=105000;f.m_LastControl=f.clock;f.Tick();assert(f.shutdowns==1&&f.m_State==State::SHUTDOWN);
f.clock=105100;f.m_LastControl=f.clock;f.Tick();assert(f.m_State==State::CANCELLED&&f.releases==1&&f.m_Token==77&&f.m_Deadline==240000);
// Uncancelled normal hold can produce COMPLETE only after native ground observations.
Flight normal;started(normal,q);normal.m_Aircraft.origin={99.7f,8,0};assert(normal.BeginFieldBrake(80000));
normal.CheckTranslation(80000,normal.m_Aircraft.origin,8,0,1);normal.CheckTranslation(82000,normal.m_Aircraft.origin,8,0,1);
normal.CheckTranslation(85000,{98,8,0},8,0,1);assert(normal.m_Stable<0&&!normal.m_FieldArrived);
normal.CheckTranslation(86000,normal.m_Aircraft.origin,8,0,1);normal.CheckTranslation(90999,normal.m_Aircraft.origin,8,0,1);assert(!normal.m_FieldArrived);
normal.CheckTranslation(91000,normal.m_Aircraft.origin,8,0,1);assert(normal.m_FieldArrived&&normal.m_TranslationProven&&normal.landings==1);
normal.m_Aircraft.origin={99.7f,0,0};normal.grounded=true;
for(int t=92000;t<=94100;t+=700){normal.clock=t;normal.m_LastControl=t;normal.Tick();}
assert(normal.m_State==State::SHUTDOWN);normal.clock=94200;normal.m_LastControl=normal.clock;normal.Tick();assert(normal.m_State==State::COMPLETE&&normal.releases==1);
// Cancelling during climb retains altitude/braking instead of invoking descent.
Flight climb;assert(climb.StartField(1,2,3,4,5,&q,77,240000));climb.m_State=State::CLIMB;climb.clock=30000;climb.m_Aircraft.origin={1,3,0};climb.Cancel("climb stop");
assert(climb.m_State==State::TRANSLATING&&climb.m_FieldPhase==2&&climb.landings==0&&!climb.m_TranslationStarted);
// Actual inherited Cancel may run airborne before startup enabled autohover.
for(int stage:{State::POSITIVE,State::NEGATIVE}){
Flight early;assert(early.StartField(1,2,3,4,5,&q,77,240000));early.m_State=stage;early.m_Controller.hover=false;early.clock=30000;early.m_Aircraft.origin={1,.2f,0};early.m_Simulation.velocity={.1f,0,0};
early.Cancel("pre-climb airborne stop");assert(early.m_Cancelled&&early.m_FieldPhase==2&&early.m_State==State::TRANSLATING&&early.m_Controller.hover&&early.m_Controller.hoverWrites==1&&early.failures==0&&early.landings==0);
auto frozen=early.m_FieldLandingPoint;auto stageDeadline=early.m_StageDeadline;early.PrepareActions(early.m_Character,early.m_Pilot,early.m_Actions,.1f);assert(early.pairs==4&&early.failures==0);
early.Cancel("duplicate");assert(early.m_Controller.hoverWrites==1&&early.m_FieldLandingPoint[0]==frozen[0]&&early.m_StageDeadline==stageDeadline&&early.m_Deadline==240000);
}
Flight refusedHover;started(refusedHover,q);refusedHover.m_Controller.hover=false;refusedHover.m_Controller.enableAllowed=false;refusedHover.Cancel("native hover refuses");assert(refusedHover.failures==1&&!refusedHover.m_FieldStopFrozen&&refusedHover.m_Controller.hoverWrites==1&&refusedHover.m_State==State::FAILED);
Flight capturedBrake;started(capturedBrake,q);capturedBrake.owner=false;capturedBrake.Cancel("captured before brake");assert(capturedBrake.relinquished==1&&capturedBrake.m_Controller.hoverWrites==0&&!capturedBrake.m_FieldStopFrozen);
// First cancellation freezes a velocity-projected qualified point exactly once.
Flight cancel;started(cancel,q);cancel.m_Aircraft.origin={30,8,0};cancel.m_Simulation.velocity={2,0,0};cancel.m_FieldReference={2,0,0};cancel.clock=70000;cancel.Cancel("first");
assert(cancel.m_State==State::TRANSLATING&&cancel.m_FieldPhase==2&&cancel.landings==0&&near(cancel.m_FieldLandingPoint[0],30+Rules::BrakingReserve(2)));
auto centre=cancel.m_FieldLandingPoint;float deadline=cancel.m_StageDeadline;cancel.clock=71000;cancel.m_Aircraft.origin={40,8,0};cancel.Cancel("again");assert(cancel.m_FieldLandingPoint[0]==centre[0]&&cancel.m_StageDeadline==deadline);
Flight settling;started(settling,q);settling.m_Aircraft.origin={99.7f,8,0};assert(settling.BeginFieldBrake(80000));settling.m_FieldPhase=3;settling.m_Stable=81000;settling.clock=82000;auto old=settling.m_StageDeadline;settling.Cancel("mid hold");assert(settling.failures==0&&settling.landings==0&&settling.m_State==State::TRANSLATING&&settling.m_StageDeadline==old);
// Cancellation cannot invent a stopping point beyond qualified space.
Flight outside;started(outside,q);outside.m_Aircraft.origin={100,8,0};outside.m_Simulation.velocity={2,0,0};outside.Cancel("too late");assert(outside.failures==1&&!outside.m_FieldStopFrozen&&outside.landings==0);
// Early abort is owner-tick based and cannot transition inherited input mid-call.
Flight abort;started(abort,q);abort.clock=155000;abort.m_LastControl=abort.clock;abort.m_Aircraft.origin={20,8,0};assert(abort.ControlLease()&&!abort.m_Cancelled);abort.Tick();assert(abort.m_Cancelled&&abort.m_FieldPhase==2&&abort.m_Deadline==240000&&abort.m_StageDeadline==200000);
Flight edge;started(edge,q);edge.clock=153499;edge.m_LastControl=edge.clock;edge.m_Aircraft.origin={20,8,0};edge.Tick();assert(!edge.m_Cancelled);edge.clock=153500;edge.m_LastControl=edge.clock;edge.Tick();assert(edge.m_Cancelled&&edge.m_Deadline==240000);
Flight low;started(low,q);low.m_Aircraft.origin={20,8,0};low.clock=70000;low.m_LastControl=low.clock;fuelBoundary.total=20;low.Tick();assert(low.m_Cancelled&&low.m_FieldPhase==2&&low.m_Reason=="field candidate low-fuel reserve reached");fuelBoundary.total=100;
Flight capture;started(capture,q);capture.owner=false;assert(!capture.ControlLease()&&capture.relinquished==1&&capture.pairs==0);
Flight expiry;started(expiry,q);expiry.clock=240000;assert(!expiry.ControlLease()&&expiry.failures==1);
Flight fast;started(fast,q);fast.m_Simulation.velocity={2.501f,0,0};assert(!fast.ControlLease()&&fast.failures==1);
Flight corridor;started(corridor,q);corridor.m_Aircraft.origin={50,8,8};assert(!corridor.ControlLease()&&corridor.failures==1);
// Exact callbacks only; no native input on invalid timestep or failed lease.
Flight input;started(input,q);input.m_Aircraft.origin={10,8,0};ActionManager other;
input.PrepareActions(999,input.m_Pilot,input.m_Actions,.1f);input.PrepareActions(input.m_Character,999,input.m_Actions,.1f);input.PrepareActions(input.m_Character,input.m_Pilot,&other,.1f);assert(input.pairs==0);
for(float dt:{0.0f,-1.0f,.201f,NAN}) { input.PrepareActions(input.m_Character,input.m_Pilot,input.m_Actions,dt); }
assert(input.pairs==0);
input.PrepareActions(input.m_Character,input.m_Pilot,input.m_Actions,.1f);assert(input.pairs==4&&input.m_ActionUpdates==1&&input.m_TranslationUpdates==1&&input.m_FieldReference.Length()<=.020001f);
input.m_State=State::LANDING;input.m_FieldPhase=3;input.m_FieldLandingPoint={10,0,0};input.m_Aircraft.origin={10,0,0};input.grounded=true;input.PrepareActions(input.m_Character,input.m_Pilot,input.m_Actions,.1f);assert(input.collectiveWrite==-1&&input.forwardWrite==0&&input.asideWrite==0);
input.owner=false;int writes=input.pairs;input.PrepareActions(input.m_Character,input.m_Pilot,input.m_Actions,.1f);assert(input.pairs==writes&&input.relinquished==1);
Flight inactive;started(inactive,q);inactive.manager.active=false;inactive.PrepareActions(inactive.m_Character,inactive.m_Pilot,inactive.m_Actions,.1f);assert(inactive.pairs==0&&!inactive.m_Readback&&inactive.manager.activated==1);
Flight gap;started(gap,q);gap.m_Aircraft.origin={99.7f,8,0};gap.BeginFieldBrake(80000);gap.m_FieldLowSince=81000;gap.m_Stable=81000;gap.m_LastTick=81000;gap.clock=83000;gap.m_LastControl=gap.clock;gap.Tick();assert(gap.m_FieldPhase==2&&gap.m_FieldLowSince==83000&&gap.m_Stable<0);
// Slow positioning/landing never consumes or retains the cruise PI output.
Flight slow;started(slow,q);slow.m_FieldPhase=3;slow.m_FieldStopFrozen=true;slow.m_FieldLandingPoint={100,0,0};slow.m_FieldIntegral={4,0,0};
auto actual=slow.FieldDemand({90,8,0},{1,2,0},.1f);auto shared=TranslationRules::Demand({100,0,0},{90,8,0},{1,2,0});assert((actual-shared).Length()==0&&actual.Length()<=.030001f);
Flight startup;assert(startup.StartField(1,2,3,4,5,&q,77,240000));startup.PrepareActions(11,12,startup.m_Actions,.1f);startup.Tick();assert(startup.baseInputs==1&&startup.baseTicks==1);
}
''')
# Preserve shared ownership, startup and bridge; no new actuation domain.
assert 'class ERR_AircraftFieldFlight : ERR_AircraftFlight' in source
for forbidden in ('s_Owners', 'modded class', 'SetWorldTransform(', 'SetOrigin(', 'SetVelocity(', 'SetActive(', 'Spawn(', '.Claim(', '.SetActionValue(', '.StartEngine(', '.StopEngine('):assert forbidden not in source
for unchanged in ('protected bool Owns(', 'protected bool Healthy(', 'protected bool Lease(', 'protected void Release(', 'void Cancel('):assert unchanged not in source
assert 'return super.Start(' in body(P,'bool StartField(')
assert 'AbortDue' not in body(P,'protected override bool ControlLease(')
assert 'ERR_AircraftFieldRules.AbortDue(now + 1500, m_Deadline)' in body(P,'override void Tick(')
assert 'm_Deadline =' not in source and 'm_Token =' not in source
prepare=body(P,'override void PrepareActions(')
assert prepare.index('!ControlLease()')<prepare.index('FieldDemand(')<prepare.index('Pair(')
assert 'm_StageDeadline' not in body(P,'protected override void CheckTranslation(')
assert 'm_FieldIntegral = "0 0 0"' in body(P,'protected override void CheckTranslation(')
print('PASS: actual field startup delegation, immutable lease/target, braking/settling/cancel transitions, early abort, callback scope, physical terminal policy and shared landing demand; native boundaries faked')
brake=body(P,'protected bool BeginFieldBrake(')
assert brake.index('if (m_FieldStopFrozen) return true;')<brake.index('!Owns()')<brake.index('m_Field.Contains(point, 1)')<brake.index('m_Controller.SetAutohoverEnabled(true)')<brake.index('if (!m_Controller.GetAutohoverEnabled())')<brake.index('m_FieldStopFrozen = true;')
print('PASS: actual inherited airborne pre-CLIMB cancellation enables verified native autohover once, refuses failed enable and never writes after capture')