Files
EscapistsReintroduced/tests/test_hunter_profiles.py
T
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

81 lines
7.6 KiB
Python

"""Execute the pre-spawn profile gate; verify registry-backed faction resources."""
from policy_harness import ROOT, body, run
import re
p=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HunterService.c'
method=body(p,'protected bool SpawnHunter(')
# The real preflight block runs before construction/insertion/native spawning.
preflight=method[method.index('{')+1:method.index(' ERR_HunterVehicle unit =')]
preflight=preflight.replace('ResourceName','std::string').replace('ERR_EnemyMedicalCatalog.','ERR_EnemyMedicalCatalog::').replace('ERR_EnemyLoadoutCatalog.','ERR_EnemyLoadoutCatalog::').replace('ERR_HQ.Event','ERR_HQ::Event').replace('string.Format','Format').replace('m_Mode.EnemyFaction().GetFactionKey()','"TEST_FACTION"')
run('''#include <cassert>
#include <string>
namespace ERR_EnemyMedicalCatalog {std::string soldier="soldier",medic="medic";std::string Crew(void*,bool m){return m?medic:soldier;}}
namespace ERR_EnemyLoadoutCatalog {bool Available(std::string p){return !p.empty()&&p!="invalid";}}
int logged=0;namespace ERR_HQ {void Event(std::string,std::string){logged++;}}
template<class...T>std::string Format(std::string text,T...){return text;}
struct Gate {void* m_Mode=nullptr;float m_NextSpawn=0;bool Check(float now){
'''+preflight+'''return true;}};
int main(){Gate gate;assert(gate.Check(1000)&&logged==0);
ERR_EnemyMedicalCatalog::medic="";assert(!gate.Check(1000)&&gate.m_NextSpawn==31000&&logged==1);
ERR_EnemyMedicalCatalog::medic="medic";ERR_EnemyMedicalCatalog::soldier="invalid";assert(!gate.Check(5000)&&gate.m_NextSpawn==35000);
ERR_EnemyMedicalCatalog::soldier="soldier";assert(gate.Check(35000));
}
''')
registry=(ROOT/'addons/core/Configs/ERR/Content/Registry.conf').read_text()
for key in ('RHS_ION','RHS_USAF','RHS_AFRF'):
option=next(x for x in registry.split('ERR_ContentOption {') if f'NativeFactionKey "{key}"' in x)
assert re.search(r'ResponseSoldier "\{[A-F0-9]{16}\}[^"\n]+\.et"',option)
assert re.search(r'ResponseMedic "\{[A-F0-9]{16}\}[^"\n]*Medic[^"\n]*\.et"',option)
print('PASS: missing/invalid faction crew defers before any native spawn or allowance insertion; all registered RHS factions have explicit soldier and medic profiles')
# Execute actual finite vehicle-radio initialization: pending/refused/lost radios
# never cause repeat allocations, and admission requires physical capability.
prepare=body(p,'protected bool PrepareVehicleRadio(').replace('protected ','').replace('ERR_HunterVehicle unit','Unit* unit')
prepare=prepare.replace('InventoryStorageManagerComponent storage = InventoryStorageManagerComponent.Cast(unit.Entity.FindComponent(InventoryStorageManagerComponent));','Storage* storage = vehicleStorage;')
prepare=prepare.replace('ref ','').replace('unit.','unit->').replace('storage.','storage->').replace('RadioOperation.','RadioOperation->').replace('ERR_HQ.Event','Event').replace('ERR_EnemyRadio.MANPACK','"manpack"').replace('EStoragePurpose.PURPOSE_DEPOSIT','1').replace('null','nullptr')
run('''#include <cassert>
#include <string>
struct ERR_EnemyEquipmentCallback{bool Finished=false,Succeeded=false;};
struct Unit{bool Motorbike=false;bool RadioRequested=false;ERR_EnemyEquipmentCallback* RadioOperation=nullptr;void* Driver=nullptr;std::string Source="uaz";};
struct Storage{int calls=0;bool accepts=true;bool TrySpawnPrefabToStorage(std::string,void*,int,int,ERR_EnemyEquipmentCallback*){calls++;return accepts;}};
void Event(std::string,std::string){}
struct Service{bool PrepareMotorbikeRadio(Unit*){assert(false);return false;}Storage* vehicleStorage=nullptr;int physicalCapability=0;int VehicleRadioCapability(void*){return physicalCapability;}
'''+prepare+'''
};
int main(){Service service;Storage storage;service.vehicleStorage=&storage;Unit unit;
assert(!service.PrepareVehicleRadio(&unit)&&storage.calls==1);for(int i=0;i<10;i++)assert(!service.PrepareVehicleRadio(&unit));assert(storage.calls==1);
unit.RadioOperation->Finished=true;unit.RadioOperation->Succeeded=true;assert(!service.PrepareVehicleRadio(&unit));
service.physicalCapability=2;assert(service.PrepareVehicleRadio(&unit)&&storage.calls==1);
service.physicalCapability=0;assert(!service.PrepareVehicleRadio(&unit)&&storage.calls==1); // Loot does not replenish the radio.
Unit refused;storage.accepts=false;assert(!service.PrepareVehicleRadio(&refused));for(int i=0;i<10;i++)assert(!service.PrepareVehicleRadio(&refused));assert(storage.calls==2);
}
''')
print('PASS: vehicle radio issued once; pending, refusal and looting cannot duplicate or fabricate a physical radio link')
capability=body(p,'int VehicleRadioCapability(')
capability=capability.replace('IEntity actor','Entity* actor').replace('foreach (ERR_HunterVehicle unit : m_Hunters)','for (Unit* unit : m_Hunters)').replace('InventoryStorageManagerComponent storage = InventoryStorageManagerComponent.Cast(unit.Entity.FindComponent(InventoryStorageManagerComponent));','Storage* storage = unit->Entity->storage;')
capability=capability.replace('array<IEntity> items = {};','std::vector<Entity*> items;').replace('foreach (IEntity item : items)','for (Entity* item : items)').replace('item.FindComponent(BaseRadioComponent)','item->baseRadio').replace('SCR_RadioComponent radio = SCR_RadioComponent.Cast(item.FindComponent(SCR_RadioComponent));','Radio* radio = item->radio;')
for obj in ('m_Mode','unit','storage','radio'):capability=capability.replace(obj+'.',obj+'->')
capability=capability.replace('ERR_Actors.Alive','Alive').replace('CompartmentAccessComponent.GetVehicleIn','VehicleIn').replace('ERR_ConvoyRules.Captured','Captured')
run('''#include <cassert>
#include <vector>
#include <algorithm>
struct Radio{bool pack=true;bool ERR_IsHQManpack(){return pack;}};
struct Storage;
struct Entity{bool alive=true,baseRadio=true,captured=false;Entity* vehicle=nullptr;Storage* storage=nullptr;Radio* radio=nullptr;};
struct Storage{std::vector<Entity*>items;void GetItems(std::vector<Entity*>&out){out=items;}};
struct Members:std::vector<Entity*>{bool Contains(Entity* p){return std::find(begin(),end(),p)!=end();}};
struct Mode{bool active=true;bool Active(){return active;}};
struct Unit{struct Entity* Entity=nullptr;void* Group=nullptr;bool Released=false,valid=true;struct Members Members;bool CrewValid(Mode*){return valid;}};
bool Alive(Entity* e){return e&&e->alive;}Entity* VehicleIn(Entity* e){return e->vehicle;}bool Captured(Entity* e,void*){return e->captured;}
struct Service{Mode* m_Mode=nullptr;bool m_Stopped=false;std::vector<Unit*>m_Hunters;
'''+capability+'''
};
int main(){Service s;Mode mode;s.m_Mode=&mode;Entity actor,car,item;Radio radio;Storage storage;Unit unit;
unit.Entity=&car;unit.Members.push_back(&actor);actor.vehicle=&car;car.storage=&storage;item.radio=&radio;storage.items={&item};s.m_Hunters={&unit};
assert(s.VehicleRadioCapability(&actor)==2);storage.items.clear();assert(s.VehicleRadioCapability(&actor)==0);storage.items={&item};
actor.vehicle=nullptr;assert(s.VehicleRadioCapability(&actor)==0);actor.vehicle=&car;car.captured=true;assert(s.VehicleRadioCapability(&actor)==0);car.captured=false;
car.alive=false;assert(s.VehicleRadioCapability(&actor)==0);car.alive=true;unit.Released=true;assert(s.VehicleRadioCapability(&actor)==0);unit.Released=false;
mode.active=false;assert(s.VehicleRadioCapability(&actor)==0);mode.active=true;s.m_Stopped=true;assert(s.VehicleRadioCapability(&actor)==0);s.m_Stopped=false;
radio.pack=false;assert(s.VehicleRadioCapability(&actor)==0);radio.pack=true;Entity stranger;stranger.vehicle=&car;assert(s.VehicleRadioCapability(&stranger)==0);
}
''')
print('PASS: actual vehicle-radio link requires the original seated crew, physical manpack and live uncaptured mission vehicle; looting, dismount, release and teardown remove it')