Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
60 lines
4.3 KiB
Python
60 lines
4.3 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 'AIWaypoint movement = Move(support)' in body(tactics,'protected void Support(')
|
|
assert 'orders.Add(movement)' in body(tactics,'protected void Support(')
|
|
assert 'SearchWaypoint()' in body(tactics,'protected bool PlanFlank(')
|
|
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')
|