"""Execute production spotting math/delivery/adoption with native API doubles. This is not evidence of native explosion callbacks or live impact accuracy. """ import re from policy_harness import ROOT, body, run p=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_MortarSpotting.c' r=p.parent def cpp(path, signature): s=body(path,signature).replace('protected ','') # Logging/formatting are inert at the native boundary, not delivery logic. while 'string.Format(' in s: start=s.index('string.Format('); end=start+len('string.Format('); level=1 while level: level+=(s[end]=='(')-(s[end]==')');end+=1 s=s[:start]+'"log"'+s[end:] for typ in ['ERR_MortarSpotReport','ERR_MortarBattery','ERR_HQReport']: s=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',s) s=s.replace('ERR_MortarSpotReport* best;','ERR_MortarSpotReport* best=nullptr;') s=s.replace('bool searched;', 'bool searched=false;') for cls in ['ERR_ForceRules','ERR_MortarSpotRules','ERR_MortarRefreshRules','ERR_MortarPrediction','ERR_MortarSalvo','vector','Math']: s=s.replace(cls+'.',cls+'::') for field in ['spot','battery','report','best','m_HQ','update','shot','Observation','Gun','AimSolution','Refresh','Report','Battery','Downlink']: s=s.replace(field+'.',field+'->') s=s.replace('foreach (ERR_MortarSpotReport* spot : m_Reports)', 'for (ERR_MortarSpotReport* spot : m_Reports.values)') s=s.replace('null','nullptr').replace('nullptrptr','nullptr') return s rules='\n'.join(cpp(p,s) for s in ['static bool Fresh(', 'static vector Bias(', 'static vector CorrectedOffset(']) newer=cpp(r/'ERR_MortarRefresh.c','static bool Newer(').replace('current.', 'current->').replace('incoming.','incoming->') methods='\n'.join(cpp(p,s) for s in ['protected bool Usable(', 'protected ERR_MortarSpotReport Latest(', 'vector Offset(', 'void PrepareAim(', 'void ReceiveHQ(', 'void Tick(']) run(r'''#include #include #include #include struct vector { float v[3]{};float& operator[](int i){return v[i];} vector operator+(vector b) const{return {v[0]+b.v[0],v[1]+b.v[1],v[2]+b.v[2]};} vector operator-(vector b) const{return {v[0]-b.v[0],v[1]-b.v[1],v[2]-b.v[2]};} vector operator*(float b) const{return {v[0]*b,v[1]*b,v[2]*b};} float Length() const{return std::sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);} vector Normalized() const {float l=Length();return l?(*this)*(1/l):vector{};} static float Distance(vector a,vector b){return (a-b).Length();} }; struct Math {static float Round(float v){return std::round(v);}}; struct ERR_ForceRules {static bool Finite(float v){return std::isfinite(v);}}; struct ERR_MortarSpotRules { '''+rules+r'''}; struct Entity {vector position;vector GetOrigin(){return position;}}; struct ERR_HQReport {Entity* Target=nullptr;int MessageId=1;float ObservedAt=0;vector Position;ERR_HQReport* Snapshot(){return this;}}; struct ERR_MortarPrediction {static bool Fresh(ERR_HQReport* r,float t){return t>=r->ObservedAt&&t-r->ObservedAt<=60000;}}; struct ERR_MortarRefreshRules { '''+newer+r'''}; struct Aim {vector SalvoOffset;}; struct RefreshState {ERR_HQReport* Report=nullptr;}; struct ERR_MortarBattery { Entity* Gun=nullptr;void* Group=this;ERR_HQReport* Report=nullptr;RefreshState* Refresh=nullptr;Aim* AimSolution=nullptr; bool operational=true,CommandOpen=true,Released=false,RefreshRejected=false,Rejected=false; int SiteId=1,OrderId=1,OrderShots=1;bool Operational(){return operational;} void Audit(const char*,const char*){} }; struct ERR_HQRoute {int result=0;int Advance(float,void*){return result;}}; struct ERR_MortarSpotReport { ERR_MortarBattery* Battery=nullptr;Entity *Gun=nullptr,*Target=nullptr; ERR_HQReport* Observation=nullptr;ERR_HQRoute* Downlink=nullptr; vector GunOrigin,Bias;bool Delivered=false;float FiredAt=0,ImpactAt=-1;int GroupsChecked=0; }; template struct Items { std::vector values;int Count(){return values.size();}void Insert(T t){values.push_back(t);} void Remove(int i){values.erase(values.begin()+i);}T operator[](int i){return values[i];} }; struct HQ {ERR_HQRoute* route=nullptr;int surveys=0; ERR_HQRoute* Downlink(void*,const char*,const char*,int){return route;} void* Journal(){return nullptr;}bool ReportMortarSplash(ERR_MortarSpotReport*,float){surveys++;return false;} }; struct ERR_MortarSalvo {static vector Offset(int,int,int){return {80,0,0};}}; struct Spotting {bool m_Stopped=false;HQ* m_HQ=nullptr;Items m_Reports,m_Flying; '''+methods+r'''}; struct Fixture { Entity gun,target;ERR_HQReport original,observed;ERR_MortarBattery battery;ERR_MortarSpotReport spot;HQ hq;ERR_HQRoute route;Spotting service; Fixture(){original.Target=⌖observed=original;observed.MessageId=2;observed.ObservedAt=2000; battery.Gun=&gun;battery.Report=&original;spot.Battery=&battery;spot.Gun=&gun;spot.Target=⌖spot.Observation=&observed; spot.Bias={15,0,0};spot.FiredAt=1000;service.m_HQ=&hq;hq.route=&route;} void receive(){service.ReceiveHQ(&spot,3000);} void deliver(){route.result=1;service.Tick(4000);} vector offset(){return service.Offset(&battery,battery.Report,4000);} }; int main(){ assert(ERR_MortarSpotRules::Fresh(0,45000)&&!ERR_MortarSpotRules::Fresh(0,45001)); assert(!ERR_MortarSpotRules::Fresh(1,0)&&!ERR_MortarSpotRules::Fresh(-1,0)); assert(!ERR_MortarSpotRules::Fresh(0,std::numeric_limits::quiet_NaN())); vector aim{1000,40,1000},landing{985,10,1000}; vector correction=ERR_MortarSpotRules::Bias(aim,landing); assert(correction[0]==15&&correction[1]==0&&correction[2]==0); // After applying +15m, another identical -15m ballistic error stays +15m. assert(ERR_MortarSpotRules::Bias(aim+correction,landing+correction)[0]==15); assert(ERR_MortarSpotRules::Bias(aim,aim).Length()==0); // deliberate spread is not ballistic error assert(std::fabs(ERR_MortarSpotRules::Bias({1000,0,1000},{}).Length()-60)<.001); Fixture f;assert(f.offset()[0]==80);f.receive();assert(f.offset()[0]==80); f.service.Tick(3500);assert(!f.spot.Delivered&&f.offset()[0]==80); // radio still in flight f.deliver();assert(f.spot.Delivered&&f.offset()[0]==23); // 8m spread plus 15m calibration f.battery.Released=true;f.service.PrepareAim(&f.battery,4000);assert(f.battery.Report==&f.original); f.battery.Released=false;Aim commanded;commanded.SalvoOffset={42,0,1};f.battery.AimSolution=&commanded; assert(f.offset()[0]==42);f.service.PrepareAim(&f.battery,4000);assert(f.battery.Report==&f.original); f.battery.AimSolution=nullptr;f.service.PrepareAim(&f.battery,4000);assert(f.battery.Report==&f.observed&&f.observed.ObservedAt==2000); ERR_MortarSpotReport older=f.spot;older.FiredAt=500;older.Bias={-40,0,0};f.service.m_Reports.Insert(&older); assert(f.offset()[0]==23); // older airborne round arrives after newer correction f.gun.position={3,0,0};assert(f.offset()[0]==80);f.gun.position={}; Entity another;f.battery.Report->Target=&another;assert(f.offset()[0]==80);f.battery.Report->Target=&f.target; assert(f.service.Offset(&f.battery,f.battery.Report,47001)[0]==80); // age not renewed by delivery Fixture lost;lost.receive();lost.route.result=-1;lost.service.Tick(4000);assert(lost.service.m_Reports.Count()==0&&!lost.spot.Delivered&&lost.offset()[0]==80); Fixture disconnected;disconnected.hq.route=nullptr;disconnected.receive();assert(disconnected.service.m_Reports.Count()==0); Fixture dead;dead.receive();dead.battery.operational=false;dead.deliver();assert(!dead.spot.Delivered&&dead.service.m_Reports.Count()==0); Fixture stale;stale.service.ReceiveHQ(&stale.spot,47001);assert(stale.service.m_Reports.Count()==0); Fixture bounded;for(int i=0;i<33;i++)bounded.receive();assert(bounded.service.m_Reports.Count()==32); Fixture scan;ERR_MortarSpotReport second=scan.spot;scan.spot.ImpactAt=second.ImpactAt=3000; scan.service.m_Flying.Insert(&scan.spot);scan.service.m_Flying.Insert(&second);scan.service.Tick(4000);assert(scan.hq.surveys==1); scan.service.Tick(9000);assert(scan.service.m_Flying.Count()==0); // splash not observable indefinitely } ''') # Wiring and native-boundary guards, distinct from the executed state tests. source=p.read_text() firing=(r/'ERR_MortarFiring.c').read_text() assert firing.index('system.TrackProjectile(')').replace('contact.', 'contact->') intake=intake.replace('foreach (ERR_HQReport* contact : m_Contacts)', 'for (ERR_HQReport* contact : m_Contacts)') run(r'''#include #include struct vector {float x=0,y=0,z=0;}; struct ERR_HQReport {void* Target=nullptr;float ObservedAt=0;vector Position,Velocity;bool HasVelocity=false;ERR_HQReport* Snapshot(){return new ERR_HQReport(*this);}}; struct ERR_MortarSpotReport {ERR_HQReport* Observation=nullptr;}; struct ERR_MortarSpotRules {static bool Fresh(float t,float now){return t>=0&&now>=t&&now-t<=45000;}}; struct ERR_MortarPrediction {static bool Fresh(ERR_HQReport* r,float now){return r->Target&&now>=r->ObservedAt&&now-r->ObservedAt<=60000;}}; struct Mortars {int calls=0;ERR_HQReport* delivered=nullptr;void ReceiveSpot(ERR_MortarSpotReport* spot,float){calls++;delivered=spot->Observation;}}; struct HQ {std::vector m_Contacts;Mortars m_Mortars;int accepts=0; // Represents Accept's output, not a substitute motion-estimation algorithm. void Accept(ERR_HQReport*,float){accepts++;} '''+intake+r'''}; int main(){ int target=1,other=2;ERR_HQReport sighting;sighting.Target=⌖sighting.ObservedAt=1000;sighting.Position={100,0,100}; ERR_HQReport enriched=sighting;enriched.HasVelocity=true;enriched.Velocity={3,0,-2}; ERR_MortarSpotReport spot;spot.Observation=&sighting;HQ hq;hq.m_Contacts.push_back(&enriched); hq.AcceptMortarSpot(&spot,2000);assert(hq.accepts==1&&hq.m_Mortars.calls==1); assert(spot.Observation!=&sighting&&spot.Observation!=&enriched&&spot.Observation->HasVelocity); assert(spot.Observation->Velocity.x==3&&spot.Observation->Velocity.z==-2&&spot.Observation->ObservedAt==1000); assert(!sighting.HasVelocity); // the captured sighting was not magically given native live speed // A more recent delivered sighting carries its OWN position, time and velocity. enriched.ObservedAt=1500;enriched.Position={102,0,99};enriched.Velocity={-1,0,4};spot.Observation=&sighting; hq.AcceptMortarSpot(&spot,2000);assert(spot.Observation->ObservedAt==1500&&spot.Observation->Position.x==102&&spot.Observation->Velocity.z==4); // Insufficient/conflicting history must not preserve an older movement estimate. enriched.HasVelocity=false;enriched.Velocity={};spot.Observation=&sighting; hq.AcceptMortarSpot(&spot,2000);assert(!spot.Observation->HasVelocity); HQ rejected;rejected.m_Contacts.push_back(&enriched);enriched.Target=&other;spot.Observation=&sighting; rejected.AcceptMortarSpot(&spot,2000);assert(rejected.m_Mortars.calls==0); enriched.Target=⌖enriched.ObservedAt=999;rejected.AcceptMortarSpot(&spot,2000);assert(rejected.m_Mortars.calls==0); int before=rejected.accepts;rejected.AcceptMortarSpot(&spot,46001);assert(rejected.accepts==before); } ''') print('PASS: splash reports retain HQ-estimated movement with matching position/time; stale, mismatched or unsupported estimates rejected')