59 lines
4.2 KiB
Python
59 lines
4.2 KiB
Python
"""Execute fixes for the 26 September log failures against boundary doubles."""
|
|
from policy_harness import ROOT, body, run
|
|
r=ROOT/'addons/core/Scripts/Game/ERR/10_AI'
|
|
cleanup=body(r/'ERR_HunterCrewRecovery.c','static void Complete(')
|
|
cleanup=cleanup.replace('SCR_AIVehicleBehavior behavior','Behavior* behavior').replace('IEntity actor','Actor* actor')
|
|
cleanup=cleanup.replace('SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(SCR_AIUtils.GetAIAgent(actor));','Agent* agent = actor->agent;')
|
|
cleanup=cleanup.replace('array<ref AIActionBase> actions = {};','Actions actions;').replace('agent.','agent->').replace('m_UtilityComponent.','m_UtilityComponent->').replace('behavior.Complete()','behavior->Complete()')
|
|
run('''#include <cassert>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
struct Behavior {int completions=0;void Complete(){completions++;}};
|
|
struct Actions:std::vector<Behavior*>{bool Contains(Behavior* b){return std::find(begin(),end(),b)!=end();}};
|
|
struct Utility {void* m_AIInfo=this;Actions queued;void GetActions(Actions& out){out=queued;}};
|
|
struct Agent {Utility* m_UtilityComponent=nullptr;};struct Actor{Agent* agent=nullptr;};
|
|
'''+cleanup+'''
|
|
int main(){Behavior b;Actor actor;Complete(&b,nullptr);Complete(&b,&actor);assert(!b.completions);
|
|
Agent agent;actor.agent=&agent;Complete(&b,&actor);assert(!b.completions);
|
|
Utility utility;agent.m_UtilityComponent=&utility;Complete(&b,&actor);assert(!b.completions);
|
|
utility.queued.push_back(&b);utility.m_AIInfo=nullptr;Complete(&b,&actor);assert(!b.completions);
|
|
utility.m_AIInfo=&utility;Complete(&b,&actor);assert(b.completions==1);
|
|
utility.queued.clear();Complete(&b,&actor);assert(b.completions==1);}
|
|
''')
|
|
# Execute the actual HQ eligibility branch. Its success permits the existing
|
|
# radio request path, never directly a shot; per-shot checks remain separate.
|
|
tick=body(r/'ERR_MortarSystem.c','void Tick(')
|
|
a=tick.index(' vector predicted;');b=tick.index(' selected = battery;',a)
|
|
preflight=tick[a:b].replace('vector predicted;','Vec predicted;').replace('ERR_MortarPrediction.Predict','Predict').replace('battery.Trace','battery->Trace').replace('predicted.ToString()','std::string("reported")')
|
|
run('''#include <cassert>
|
|
#include <string>
|
|
struct Vec{};struct Battery{int holds=0;void Trace(std::string,std::string,std::string){holds++;}};
|
|
struct Test{bool prediction=true,safe=true;int predictions=0,safetyChecks=0,orders=0;std::string SafetyReason="friendly";
|
|
bool Predict(void*,float,float,Vec&){predictions++;return prediction;}
|
|
bool Safe(Battery*,Vec,float){safetyChecks++;return safe;}
|
|
void Tick(Battery* battery){void* report=nullptr;float now=100;for(int i=0;i<1;i++){
|
|
'''+preflight+'''orders++;}}};
|
|
int main(){Test t;Battery battery;t.prediction=false;t.Tick(&battery);assert(!t.orders&&!t.safetyChecks);
|
|
t.prediction=true;t.safe=false;t.Tick(&battery);assert(!t.orders&&battery.holds==1);
|
|
t.safe=true;t.Tick(&battery);assert(t.orders==1&&t.safetyChecks==2);}
|
|
''')
|
|
# Prevent the exact mounted Defend regression from returning: mounted escorts
|
|
# keep Move-to-cover/native vehicle combat, while infantry retain flank/search.
|
|
tactics=r/'ERR_SupplyConvoyTactics.c'
|
|
assert 'DefendWaypoint()' not in body(tactics,'protected void Support(')
|
|
assert 'orders.Add(Move(support))' in body(tactics,'protected void Support(')
|
|
assert 'SearchWaypoint()' in body(tactics,'protected void Flank(')
|
|
print('PASS: stale/deleted AI utility cannot receive Complete; mortar HQ preflight withholds unsafe orders; mounted convoy cover never creates infantry Defend')
|
|
|
|
# The native RHS fixture reproduces this boundary: the convenience API boards
|
|
# before applying a group faction. Keep production affiliation ahead of entry.
|
|
flight=r/'ERR_ReconFlightComponent.c'
|
|
prepare=body(flight,'protected bool PrepareCrew(')
|
|
assert 'SpawnCharacterInCompartment(' not in prepare
|
|
assert prepare.index('ERR_Actors.SetFaction(initialCrew,') < prepare.index('access.GetInVehicle(')
|
|
assert prepare.index('m_Crew.AddAgent(') < prepare.index('access.GetInVehicle(')
|
|
assert 'SpawnCharacterInCompartment(' not in body(flight,'void Initialize(')
|
|
finish=body(flight,'protected bool FinishCrew(')
|
|
assert finish.index('now - m_Started > 45000') < finish.index('m_Assault.Preparing()')
|
|
print('PASS: flight crew affiliation and group precede native boarding; preparation remains bounded even while passengers wait')
|