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.
176 lines
12 KiB
Python
176 lines
12 KiB
Python
"""Execute production finite-courier policies and native-operation observation.
|
|
API doubles do not establish engine inventory, navigation, radio or MP behavior.
|
|
"""
|
|
from policy_harness import ROOT, body, run
|
|
import re
|
|
r=ROOT/'addons/core/Scripts/Game/ERR/10_AI'
|
|
p=r/'ERR_MortarLogistics.c'; t=r/'ERR_MortarCourierTransfer.c'
|
|
# C++ would accept an Enforce ownership annotation as an identifier.
|
|
# Reject that native compile regression before executing the source body.
|
|
assert not re.search(r'\b(?:bool|int|float|string)\s+(?:owned|event|autoptr|typename|proto|modded|notnull)\b', p.read_text())
|
|
policies='\n'.join(body(p,s) for s in ('static bool Fresh(', 'static bool Need(', 'static bool NewRequest(', 'static bool Near(', 'static bool ActiveTrip('))
|
|
run('''#include <cassert>
|
|
'''+policies+'''
|
|
int main(){
|
|
assert(Fresh(100,100)&&Fresh(100,180100));
|
|
assert(Fresh(0,0)&&Fresh(0,180000)&&!Fresh(0,180001));
|
|
assert(!Fresh(-1,-1)&&!Fresh(-1,0)&&!Fresh(-1,100)&&!Fresh(-0.001f,0));
|
|
assert(!Fresh(100,99)&&!Fresh(100,180101));
|
|
assert(Need(0)&&Need(6)&&!Need(-1)&&!Need(7));
|
|
assert(NewRequest(4,3,true)&&!NewRequest(4,4,true)&&!NewRequest(3,4,true));
|
|
assert(!NewRequest(1,0,false)&&!NewRequest(0,0,true));
|
|
assert(Near(0)&&Near(12)&&!Near(12.001)&&!Near(-1));
|
|
assert(ActiveTrip(true,false,1,1,true,true));
|
|
assert(!ActiveTrip(false,false,1,1,true,true));
|
|
assert(!ActiveTrip(true,true,1,1,true,true));
|
|
assert(!ActiveTrip(true,false,0,0,true,true));
|
|
assert(!ActiveTrip(true,false,1,2,true,true));
|
|
assert(!ActiveTrip(true,false,1,1,false,true));
|
|
assert(!ActiveTrip(true,false,1,1,true,false));
|
|
}
|
|
''')
|
|
poll=body(t,'int Poll(')
|
|
poll=poll.replace('bool exact;','bool exact=false;').replace('InventoryItemComponent item;','InventoryItemComponent* item=nullptr;')
|
|
poll=poll.replace('if (m_Shell) item = InventoryItemComponent.Cast(m_Shell.FindComponent(InventoryItemComponent));','if (m_Shell) item = m_Shell;')
|
|
poll=poll.replace('item.GetParentSlot().GetStorage()','item->GetParentSlot()->GetStorage()').replace('item.GetParentSlot()','item->GetParentSlot()')
|
|
poll=poll.replace('m_Service.TransferAllowed','m_Service->TransferAllowed')
|
|
run('''#include <cassert>
|
|
struct Slot {void* value;void* GetStorage(){return value;}};
|
|
struct InventoryItemComponent {Slot* slot;Slot* GetParentSlot(){return slot;}};
|
|
struct Service {bool valid=true;int token=1;bool TransferAllowed(int captured,InventoryItemComponent*,int,int,float){return valid&&token==captured;}};
|
|
'''+body(t,'static bool Proven(')+'''
|
|
struct Move {
|
|
Service service; Service* m_Service=&service;
|
|
bool source=true,destination=false,m_Accepted=true,m_Invalidated=false,m_Resolved=false;
|
|
int m_Acknowledgement=0,m_Trip=1,m_From=1,m_To=2,m_Source=1,m_Destination=2;
|
|
float m_Deadline=8000;void* m_Storage=this;
|
|
Slot slot{this};InventoryItemComponent item{&slot};InventoryItemComponent* m_Shell=&item;
|
|
bool Contains(int owner){return m_Shell&&(owner==1?source:destination);}
|
|
'''+body(t,'void Acknowledge(')+body(t,'void Invalidate(')+body(t,'bool Unresolved(')+poll+'''
|
|
};
|
|
int main(){
|
|
for(int bits=0;bits<16;bits++)assert(Proven(bits&1,bits&2,bits&4,bits&8)==(bits==13));
|
|
Move pending;assert(pending.Poll(0)==0&&pending.Unresolved());
|
|
pending.Acknowledge(true);pending.Acknowledge(false);assert(pending.m_Acknowledgement==1);
|
|
assert(pending.Poll(1)==0);pending.destination=true;assert(pending.Poll(2)==0);
|
|
pending.source=false;pending.slot.value=nullptr;assert(pending.Poll(3)==0);
|
|
pending.slot.value=pending.m_Storage;assert(pending.Poll(4)==1&&!pending.Unresolved());
|
|
Move canceled;canceled.Invalidate();assert(canceled.Poll(1)==-1&&canceled.Unresolved());
|
|
canceled.source=false;canceled.destination=true;canceled.Acknowledge(true);
|
|
assert(canceled.Poll(2)==-1&&!canceled.Unresolved()); // late physical success releases reservation, never authority
|
|
Move expired;assert(expired.Poll(8000)==-1&&expired.Unresolved());
|
|
expired.source=false;expired.destination=true;expired.Acknowledge(true);
|
|
assert(expired.Poll(9000)==-1&&!expired.Unresolved());
|
|
Move replaced;replaced.service.token=2;replaced.source=false;replaced.destination=true;replaced.Acknowledge(true);
|
|
assert(replaced.Poll(1)==-1); // callback from previous trip cannot supply new trip
|
|
Move captured;captured.service.valid=false;assert(captured.Poll(1)==-1&&captured.Unresolved());
|
|
Move rejected;rejected.Acknowledge(false);assert(rejected.Poll(1)==-1&&!rejected.Unresolved());
|
|
Move lost;lost.m_Shell=nullptr;lost.Acknowledge(true);assert(lost.Poll(1)==-1&&!lost.Unresolved());assert(lost.Poll(8000)==-1&&!lost.Unresolved());
|
|
}
|
|
''')
|
|
accept=body(p,'bool AcceptsStatus(').replace('ERR_MortarSupplyStatus report','ERR_MortarSupplyStatus* report').replace('m_Battery.','m_Battery->').replace('report.','report->').replace('ERR_MortarLogisticsRules.','Rules::')
|
|
run('''#include <cassert>
|
|
struct Rules {'''+policies+'''};
|
|
struct ERR_MortarSupplyStatus {void* Group;void* Gun;float ObservedAt;int MessageId;int Shells;};
|
|
struct Battery {void* Group;void* Gun;};
|
|
struct Service {bool m_Stopped=false;int m_State=1,m_ConsumedMessage=0;Battery* m_Battery=nullptr;
|
|
'''+accept+'''};
|
|
int main(){int group,gun,other;Battery battery{&group,&gun};Service service;service.m_Battery=&battery;
|
|
ERR_MortarSupplyStatus report{&group,&gun,100,1,0};assert(service.AcceptsStatus(&report,101));
|
|
assert(!service.AcceptsStatus(nullptr,101));
|
|
report.Gun=&other;assert(!service.AcceptsStatus(&report,101));report.Gun=&gun;
|
|
report.Group=&other;assert(!service.AcceptsStatus(&report,101));report.Group=&group;
|
|
report.Shells=7;assert(!service.AcceptsStatus(&report,101));report.Shells=0;
|
|
assert(!service.AcceptsStatus(&report,180101));assert(!service.AcceptsStatus(&report,99));
|
|
report.ObservedAt=-1;assert(!service.AcceptsStatus(&report,100));report.ObservedAt=100;
|
|
service.m_ConsumedMessage=1;assert(!service.AcceptsStatus(&report,101));report.MessageId=2;assert(service.AcceptsStatus(&report,101));
|
|
service.m_State=3;assert(!service.AcceptsStatus(&report,101));service.m_State=1;
|
|
service.m_Stopped=true;assert(!service.AcceptsStatus(&report,101));
|
|
}
|
|
''')
|
|
print('PASS: actual finite-courier age, token, exact ownership/callback and delivered-status admission reject stale, replayed, captured, canceled and ambiguous work')
|
|
# Run the actual gun-capture gate with narrow native identity/compartment doubles.
|
|
target=body(p,'bool TargetAvailable(')
|
|
target=target.replace('m_Battery.','m_Battery->').replace('m_HQ.Mortars().FindGun','m_HQ->Mortars()->FindGun').replace('m_Mode.EnemyFaction()','m_Mode->EnemyFaction()')
|
|
target=target.replace('SCR_FactionManager.SGetFaction','SCR_FactionManager::SGetFaction').replace('ERR_Actors.','ERR_Actors::')
|
|
target=target.replace('SCR_AIVehicleUsageComponent usage = SCR_AIVehicleUsageComponent.Cast(m_OriginalGun.FindComponent(SCR_AIVehicleUsageComponent));','Usage* usage = m_OriginalGun->usage;')
|
|
target=target.replace('IEntity occupant','Actor* occupant').replace('usage.GetTurretCompartmentSlot().GetOccupant()','usage->GetTurretCompartmentSlot()->GetOccupant()').replace('usage.GetTurretCompartmentSlot()','usage->GetTurretCompartmentSlot()')
|
|
run('''#include <cassert>
|
|
struct Usage;
|
|
struct Actor {void* faction;void* group;bool alive=true;bool player=false;Usage* usage=nullptr;};
|
|
struct Slot {Actor* occupant=nullptr;Actor* GetOccupant(){return occupant;}};
|
|
struct Usage {Slot slot;bool present=true;Slot* GetTurretCompartmentSlot(){return present?&slot:nullptr;}};
|
|
struct Battery {Actor* Gun;void* Group;bool StartupActivated=true;bool operational=true;bool stopped=false;bool Stopped(){return stopped;}bool Operational(){return operational;}};
|
|
struct Registry {Battery* battery;Battery* FindGun(Actor* gun){return battery&&battery->Gun==gun?battery:nullptr;}};
|
|
struct HQ {Registry registry;Registry* Mortars(){return ®istry;}};
|
|
struct Mode {void* faction;void* EnemyFaction(){return faction;}};
|
|
struct SCR_FactionManager {static void* SGetFaction(Actor* actor){return actor->faction;}};
|
|
struct ERR_Actors {static bool CanFight(Actor* a){return a->alive;}static bool Player(Actor* a){return a->player;}static void* Group(Actor* a){return a->group;}};
|
|
struct Members {Actor* member;bool IsEmpty(){return !member;}bool Contains(Actor* a){return a==member;}};
|
|
struct Service {Battery* m_Battery;Actor* m_OriginalGun;void* m_OriginalBatteryGroup;HQ* m_HQ;Mode* m_Mode;Members m_BatteryMembers;
|
|
'''+target+'''
|
|
};
|
|
int main(){int faction,group,foreign;Usage usage;Actor gun{&faction,&group};gun.usage=&usage;Actor original{&faction,&group};
|
|
Battery battery{&gun,&group};HQ hq{{&battery}};Mode mode{&faction};Service service{&battery,&gun,&group,&hq,&mode,{&original}};
|
|
assert(service.TargetAvailable());usage.slot.occupant=&original;assert(service.TargetAvailable());
|
|
original.player=true;assert(!service.TargetAvailable());original.player=false;
|
|
original.alive=false;assert(!service.TargetAvailable());original.alive=true;
|
|
original.group=&foreign;assert(!service.TargetAvailable());original.group=&group;
|
|
original.faction=&foreign;assert(!service.TargetAvailable());original.faction=&faction;
|
|
Actor stranger{&faction,&group};usage.slot.occupant=&stranger;assert(!service.TargetAvailable());usage.slot.occupant=&original;
|
|
gun.faction=&foreign;assert(!service.TargetAvailable());gun.faction=&faction;
|
|
usage.present=false;assert(!service.TargetAvailable());usage.present=true;
|
|
battery.operational=false;assert(!service.TargetAvailable());battery.operational=true;
|
|
battery.stopped=true;assert(!service.TargetAvailable());battery.stopped=false;
|
|
battery.Gun=&stranger;assert(!service.TargetAvailable());battery.Gun=&gun;
|
|
hq.registry.battery=nullptr;assert(!service.TargetAvailable());hq.registry.battery=&battery;
|
|
service.m_BatteryMembers.member=nullptr;assert(!service.TargetAvailable());
|
|
}
|
|
''')
|
|
print('PASS: actual native-gun ownership gate rejects player/foreign/replaced/dead occupant, faction change, missing seat and missing registry')
|
|
|
|
# Exercise the production between-trip target selector with four batteries.
|
|
select = body(p, 'protected void SelectBattery(')
|
|
select = select.replace('protected ', '').replace('ERR_MortarLogisticsRules.', 'Rules::').replace('vector.DistanceXZ', 'Distance')
|
|
select = select.replace('array<ref ERR_MortarBattery> batteries = {};', 'Array<Battery*> batteries;').replace('ERR_MortarBattery selected;', 'Battery* selected=nullptr;')
|
|
select = select.replace('foreach (ERR_MortarBattery candidate : batteries)', 'for (Battery* candidate : batteries)').replace('float.MAX', '999999')
|
|
select = select.replace('m_HQ.Mortars().Batteries(batteries)', 'system.Batteries(batteries)')
|
|
for name in ('m_Battery', 'candidate', 'selected', 'm_Cache'):
|
|
select = select.replace(name+'.', name+'->')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <vector>
|
|
using std::abs;
|
|
struct Battery { bool StartupActivated=true, stopped=false, operational=true; int shells=0, Gun=1, Group=1; float Position=0;
|
|
bool Stopped(){return stopped;} bool Operational(){return operational;} int CountShells(){return shells;} };
|
|
template<class T> struct Array:std::vector<T>{using std::vector<T>::operator=;void Clear(){this->clear();}};
|
|
struct System {Array<Battery*> all; void Batteries(Array<Battery*>& out){out=all;}};
|
|
struct Cache {float GetOrigin(){return 0;}};
|
|
float Distance(float a,float b){return abs(a-b);}
|
|
namespace Rules {bool Need(int n){return n>=0&&n<=6;}}
|
|
struct Courier {int m_State=1;bool m_Report=false,m_Move=false,m_Order=false; Battery* m_Battery=nullptr;
|
|
int m_OriginalGun=0,m_OriginalBatteryGroup=0;Array<int> m_BatteryMembers;float m_NextReport=99;
|
|
Cache cache;Cache* m_Cache=&cache;System system;
|
|
bool TargetAvailable(){return m_Battery&&m_Battery->StartupActivated&&!m_Battery->Stopped()&&m_Battery->Operational();}
|
|
''' + select + r'''
|
|
};
|
|
int main(){
|
|
Battery a,b,c,d;a.Position=200;b.Position=100;c.Position=300;d.Position=400;
|
|
Courier s;s.system.all={&a,&b,&c,&d};s.SelectBattery();assert(s.m_Battery==&b);
|
|
// Keep an active low-ammo recipient; a new nearer request cannot retarget it.
|
|
a.Position=1;s.SelectBattery();assert(s.m_Battery==&b);
|
|
// Once replenished, choose another depleted battery and reset only binding.
|
|
b.shells=12;s.m_BatteryMembers={9};s.SelectBattery();assert(s.m_Battery==&a&&s.m_BatteryMembers.empty()&&s.m_NextReport==0);
|
|
a.operational=false;s.SelectBattery();assert(s.m_Battery==&c);
|
|
c.stopped=true;d.StartupActivated=false;s.SelectBattery();assert(s.m_Battery==&c);
|
|
d.StartupActivated=true;
|
|
for(int gate=0;gate<4;gate++){
|
|
s.m_State=gate==0?3:1;s.m_Report=gate==1;s.m_Move=gate==2;s.m_Order=gate==3;
|
|
s.SelectBattery();assert(s.m_Battery==&c);
|
|
}
|
|
s.m_Order=false;s.SelectBattery();assert(s.m_Battery==&d);
|
|
}
|
|
''')
|
|
print('PASS: four-battery courier selection preserves pending trip/report/transfer identity, skips unavailable crews, and selects the next depleted battery without new stock')
|