Files
EscapistsReintroduced/tests/test_air_recon.py
T
jakub 1b1a8b5173 Add mission customization, HQ support and aggression-driven AI
Integrate faction and random settings menus, generated objectives, scouts, convoys, air support, mortar stations and body-intel recovery. Add identified-body aggression, finite hunter UAZ deployment, dedicated objective defence and maximum AI skill with separate reduced aim accuracy. Include policy tests, native probes, evidence and documentation.
2026-09-23 15:07:14 +02:00

65 lines
4.7 KiB
Python

"""Production recon timing, orbit and standoff geometry; no native flight claim."""
import re
from policy_harness import ROOT,body,run
path=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_AirReconSystem.c'
schedule=path.read_text().split('class ERR_AirReconSystem')[0]
schedule=schedule[schedule.index('class ERR_ReconSchedule'):].replace('class ERR_ReconSchedule','struct ERR_ReconSchedule').replace('\n}\n','\n};\n')
flight=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_ReconFlightComponent.c'
rules=body(flight,'static vector Cruise(')+'\n'+body(flight,'static vector StandOff(')
rules=rules.replace('Math.','Math::').replace('vector.','vector::')
run(r'''
#include <cassert>
#include <algorithm>
#include <cmath>
#include <cstdio>
struct Math{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 Clamp(float a,float lo,float hi){return std::clamp(a,lo,hi);}};
struct vector{float x=0,y=0,z=0;vector()=default;vector(float a,float b,float c):x(a),y(b),z(c){}vector(const char*s){sscanf(s,"%f %f %f",&x,&y,&z);}float&operator[](int i){return i==0?x:i==1?y:z;}vector operator+(vector b)const{return{x+b.x,y+b.y,z+b.z};}vector operator-(vector b)const{return{x-b.x,y-b.y,z-b.z};}vector operator*(float f)const{return{x*f,y*f,z*f};}vector&operator-=(vector b){x-=b.x;y-=b.y;z-=b.z;return*this;}float Length()const{return std::sqrt(x*x+y*y+z*z);}vector Normalized()const{float f=Length();if(f==0)return{};return{x/f,y/f,z/f};}void Normalize(){*this=Normalized();}static float Dot(vector a,vector b){return a.x*b.x+a.y*b.y+a.z*b.z;}};
vector Vector(float x,float y,float z){return{x,y,z};}
'''+schedule+rules+r'''
int main(){
ERR_ReconSchedule s{};assert(!s.Due(1000000,false));s.Begin(1000);assert(s.Deadline==901000);
s.Begin(2000);assert(s.Deadline==901000);assert(!s.Due(900999,false));assert(s.Due(901000,false));assert(!s.Due(901000,true));
s.Launched();assert(s.Deadline<0&&!s.Due(2000000,false));s.Change(2,2000,true);assert(s.Deadline<0&&s.Minutes==2);
s.Lost(3000);assert(s.Deadline==123000&&!s.Due(122999,false));s.Change(15,4000,false);assert(s.Deadline==904000);
s.Stop();s.Begin(100);s.Lost(200);s.Change(1,300,false);assert(s.Deadline<0&&!s.Due(1e8,false));
vector orbit=Cruise({300,120,0},{0,0,0},false);assert(std::abs(orbit.x)<.001&&std::abs(orbit.z+28)<.001);
vector far=Cruise({1000,120,0},{0,0,0},false);assert(far.x==-40&&far.y==0);
vector near=Cruise({100,120,0},{0,0,0},false);assert(near.x>0); // push back out toward 300m orbit
vector home=Cruise({20,120,0},{0,0,0},true);assert(home.x==-8); // return approaches pad instead of orbiting
vector away=StandOff({100,120,0},{0,0,0},{-40,0,0});assert(away.x>0);
vector clear=StandOff({300,120,0},{0,0,0},{-40,0,0});assert(clear.x==-40);
vector coincident=StandOff({0,120,0},{0,0,0},{0,0,0});assert(std::isfinite(coincident.x)&&coincident.x>0);
}
''')
print('PASS: original 15-minute launch/loss cadence, active/captured timer disarm, saved delay reset, stop, 300m orbit and close-contact standoff')
# Explicit entity deletion must not leave an inactive launch deadline behind.
removed=body(path,'void Removed(')
for old,new in [('ERR_ReconFlightComponent flight','Flight* flight'),('Replication.','Replication::'),('ERR_HQ.','ERR_HQ::'),('m_Mode.','m_Mode->'),('null','nullptr'),('GetGame().GetWorld().GetWorldTime()','clockNow')]:
removed=removed.replace(old,new)
run(r'''
#include <cassert>
#include <string>
using string=std::string;
struct Flight{};struct Mode{bool active=true;bool Active(){return active;}};
struct Replication{inline static bool server=true;static bool IsServer(){return server;}};
struct ERR_HQ{inline static int events=0;static void Event(string,string){events++;}};
float clockNow=5000;
'''+schedule+r'''
struct System{
ERR_ReconSchedule m_Schedule;Flight* m_Current=nullptr;Mode* m_Mode=nullptr;int m_PadAttempts=3;string m_Reason;
string Status(){return m_Reason;}
'''+removed+r'''
};
int main(){
Mode mode;Flight owned,other;System s{};s.m_Mode=&mode;s.m_Current=&owned;s.m_Schedule.Begin(0);s.m_Schedule.Launched();
s.Removed(nullptr);s.Removed(&other);assert(s.m_Current==&owned&&s.m_Schedule.Deadline<0&&ERR_HQ::events==0);
Replication::server=false;s.Removed(&owned);assert(s.m_Current==&owned);Replication::server=true;
mode.active=false;s.Removed(&owned);assert(s.m_Current==&owned);mode.active=true;
s.Removed(&owned);assert(!s.m_Current&&s.m_PadAttempts==0&&s.m_Schedule.Deadline==905000&&ERR_HQ::events==1);
clockNow=9000;s.Removed(&owned);assert(s.m_Schedule.Deadline==905000&&ERR_HQ::events==1);
s.m_Current=&other;s.m_Schedule.Stop();s.Removed(&other);assert(s.m_Current==&other&&s.m_Schedule.Deadline<0);
}
''')
print('PASS: actual aircraft-removal notification guards owner/server/active/stop and schedules one full delay without replay extension')