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.
99 lines
13 KiB
Python
99 lines
13 KiB
Python
"""Execute actual Intel reroll methods against adversarial async inventory adapters."""
|
|
import re
|
|
from policy_harness import ROOT, body, run
|
|
service=ROOT/'addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelService.c'
|
|
batch=ROOT/'addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelReroll.c'
|
|
def adapt(text,cls):
|
|
text=text.replace('protected ', '').replace('null','nullptr')
|
|
text=re.sub(r'array<([^>]+)> (\w+) = \{\};',r'Array<\1> \2;',text)
|
|
text=text.replace('set<IEntity> cohort = new set<IEntity>();','Set<IEntity> cohort;')
|
|
text=re.sub(r'foreach \((\w+) (\w+) : ([^)]+)\)',r'for (\1 \2 : \3)',text)
|
|
for n in ('Replication','ERR_Actors','Math','ERR_Resources','ERR_DiscoveryService','SCR_InventoryStorageManagerComponent','InventoryItemComponent'):
|
|
text=text.replace(n+'.',n+'::')
|
|
text=text.replace('SCR_InventoryStorageManagerComponent inventory','Inventory* inventory').replace('InventoryItemComponent item','Item* item')
|
|
for n in ('m_Mode','m_Service','m_Reroll','entry','request','inventory','actor','group','member','known','folder','item'):
|
|
text=text.replace(n+'.',n+'->')
|
|
text=text.replace('Actor.FindComponent(', 'Actor->FindComponent(').replace('Removing.FindComponent(', 'Removing->FindComponent(').replace('Removing.GetParent()', 'Removing->GetParent()')
|
|
text=text.replace('Settings().','Settings()->').replace('Discovery().','Discovery()->')
|
|
text=text.replace('FindComponent(SCR_InventoryStorageManagerComponent)','FindComponent(INVENTORY)').replace('FindComponent(InventoryItemComponent)','FindComponent(ITEM)').replace('FindComponent(ERR_DocumentComponent)','FindComponent(DOCUMENT)')
|
|
text=text.replace('purpose: EStoragePurpose.PURPOSE_ANY','0').replace('cb: ', '')
|
|
text=text.replace('Operation.', 'Operation->')
|
|
text=text.replace('new ERR_IntelRerollEntry()', 'new Entry()').replace('new ERR_IntelReroll(', 'new Batch(').replace('new ERR_IntelRequest()', 'new Request()').replace('new ERR_IntelInsertCallback()', 'new Callback()')
|
|
text=re.sub(r'^.*Print\([^\n]*$', ';',text,flags=re.M)
|
|
text=re.sub(r'^(\w+) (\w+)\(',lambda m:m[1]+' '+cls+'::'+m[2]+'(',text)
|
|
# Defaults belong only to declarations in C++.
|
|
text=text.replace('bool failed = false, bool skipped = false','bool failed, bool skipped')
|
|
return text.replace('Evidence().','Evidence()->')
|
|
service_methods=[('void RegisterGroup(', 'void RegisterGroup(SCR_AIGroup group);'),('void Tick(', 'void Tick(float now);'),('bool BeginReroll(', 'bool BeginReroll();'),('bool HasPendingInsertion(', 'bool HasPendingInsertion(IEntity actor);'),('void Unsettled(', 'void Unsettled(IEntity actor);'),('bool Settled(', 'bool Settled(IEntity actor);'),('void Stop(', 'void Stop();')]
|
|
batch_methods=[('void Add(', 'void Add(IEntity actor);'),('bool Running(', 'bool Running();'),('void Tick(', 'void Tick();'),('protected void Finish(', 'void Finish(ERR_IntelRerollEntry entry,bool failed=false,bool skipped=false);'),('protected void Fail(', 'void Fail(ERR_IntelRerollEntry entry,string reason);'),('protected void Process(', 'void Process(ERR_IntelRerollEntry entry);'),('void Stop(', 'void Stop();')]
|
|
code=r'''
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <string>
|
|
using string=std::string;
|
|
template<class T> struct Array:std::vector<T>{int Count(){return this->size();}bool IsEmpty(){return this->empty();}void Insert(T a){this->push_back(a);}void Remove(int i){this->erase(this->begin()+i);}void Clear(){this->clear();}bool Contains(T a){return std::find(this->begin(),this->end(),a)!=this->end();}};
|
|
template<class T> struct Set:std::set<T>{bool Contains(T a){return this->count(a);}void Insert(T a){this->insert(a);}void RemoveItem(T a){this->erase(a);}void Clear(){this->clear();}};
|
|
namespace Replication{bool server=true;bool IsServer(){return server;}}
|
|
namespace Math{int rolls=0;int RandomInt(int,int){rolls++;return 0;}int Min(int a,int b){return std::min(a,b);}}
|
|
const int INVENTORY=1,ITEM=2,DOCUMENT=3;
|
|
struct Actor;using IEntity=Actor*;
|
|
struct Item{bool attached=false;bool GetParentSlot(){return attached;}static Item* Cast(void* p){return (Item*)p;}};using InventoryItemComponent=Item;
|
|
struct Callback{bool Finished=false,Succeeded=false;};
|
|
struct Inventory{Array<IEntity> folders;int spawns=0,removes=0;bool acceptSpawn=true,acceptRemove=true;bool TrySpawnPrefabToStorage(int,int,Callback*){spawns++;return acceptSpawn;}bool TryRemoveItemFromInventory(IEntity){removes++;return acceptRemove;}static Inventory* Cast(void* p){return (Inventory*)p;}};using SCR_InventoryStorageManagerComponent=Inventory;
|
|
struct Actor{bool alive=true,player=false,document=false,parent=false,hasInventory=true;Item item;Inventory inv;void* FindComponent(int kind){if(kind==INVENTORY)return hasInventory?&inv:nullptr;if(kind==ITEM)return &item;return document?this:nullptr;}bool GetParent(){return parent;}};
|
|
struct Agent{IEntity actor;IEntity GetControlledEntity(){return actor;}};using AIAgent=Agent*;
|
|
struct Group{Array<AIAgent> agents;void GetAgents(Array<AIAgent>& out){out=agents;}};using SCR_AIGroup=Group*;
|
|
namespace ERR_Actors{bool Alive(IEntity a){return a&&a->alive;}bool Player(IEntity a){return a&&a->player;}}
|
|
namespace ERR_Resources{int IntelFolder(){return 1;}}
|
|
struct Discovery{Set<IEntity> spent;bool capacity=true;static void Folders(Inventory* i,Array<IEntity>& out){out=i->folders;}bool IsSpent(IEntity a){return spent.Contains(a);}bool CanMarkSpent(IEntity a){return capacity;}bool MarkSpent(IEntity a){if(!capacity)return false;spent.Insert(a);return true;}};using ERR_DiscoveryService=Discovery;
|
|
struct Settings{int chance=100;int Runtime(const char*){return chance;}};
|
|
struct EvidenceService{void Capture(IEntity){}void Retire(IEntity){}};
|
|
struct Mode{EvidenceService evidence;EvidenceService* Evidence(){return &evidence;}bool active=true;struct Settings settings;struct Discovery discovery;Set<IEntity> owned;bool Active(){return active;}struct Settings* Settings(){return &settings;}struct Discovery* Discovery(){return &discovery;}void Own(IEntity a){owned.Insert(a);}};
|
|
struct Entry{string WaitingFor="inventory";Callback* Operation=nullptr;IEntity Actor=nullptr,Removing=nullptr;int Attempts=0;bool GiveIntel=false,Inserting=false,Accepted=false,Done=false;};using ERR_IntelRerollEntry=Entry*;
|
|
struct Request{Callback* Operation=nullptr;IEntity Actor=nullptr;int Attempts=0;bool Accepted=false;};using ERR_IntelRequest=Request*;
|
|
struct Service;struct Batch;
|
|
struct Batch{Mode* m_Mode;Service* m_Service;Array<ERR_IntelRerollEntry> m_Entries;int m_Percent=0,m_Next=0,m_Completed=0,m_Failed=0,m_Skipped=0;bool m_Cancelled=false;Batch(Mode* m,Service* s,int p):m_Mode(m),m_Service(s),m_Percent(p){}
|
|
'''+ '\n'.join(x[1] for x in batch_methods)+r'''
|
|
};
|
|
struct Service{Mode* m_Mode;Array<ERR_IntelRequest> m_Requests;Set<IEntity> m_Rolled,m_Unsettled;Batch* m_Reroll=nullptr;bool m_Stopped=false;Service(Mode* m):m_Mode(m){}
|
|
'''+ '\n'.join(x[1] for x in service_methods)+r'''
|
|
};
|
|
'''+ '\n'.join(adapt(body(service,x[0]),'Service') for x in service_methods)+ '\n'.join(adapt(body(batch,x[0]),'Batch') for x in batch_methods)+r'''
|
|
void Add(Service& s,Actor& a){s.m_Rolled.Insert(&a);}
|
|
void Drain(Service& s,int n=70){for(int i=0;i<n;i++)s.Tick(i);}
|
|
int main(){
|
|
// Authority, terminal/stopped rounds, snapshot chance/cohort and duplicate guard.
|
|
Mode m;Service s(&m);Actor a,late;Add(s,a);Replication::server=false;assert(!s.BeginReroll());Replication::server=true;m.active=false;assert(!s.BeginReroll());m.active=true;m.settings.chance=0;assert(s.BeginReroll());assert(!s.BeginReroll());m.settings.chance=100;Add(s,late);Drain(s);assert(s.m_Reroll->m_Entries.Count()==1&&s.m_Reroll->m_Percent==0&&a.inv.spawns==0&&late.inv.spawns==0&&s.m_Reroll->m_Completed==1);
|
|
// Old unaccepted work cancelled, accepted native spawn retained and observed.
|
|
Mode pendingMode;Service pending(&pendingMode);Actor p,folder;Add(pending,p);auto req=new Request();req->Actor=&p;pending.m_Requests.Insert(req);pendingMode.settings.chance=0;assert(pending.BeginReroll());assert(pending.m_Requests.IsEmpty());Drain(pending);assert(p.inv.spawns==0);
|
|
auto accepted=new Request();accepted->Actor=&p;accepted->Accepted=true;accepted->Operation=new Callback();pending.m_Requests.Insert(accepted);assert(pending.BeginReroll());pending.Tick(0);assert(pending.m_Requests.Count()==1&&p.inv.removes==0&&p.inv.spawns==0);p.inv.folders.Insert(&folder);folder.item.attached=true;pending.Tick(1);assert(pending.m_Requests.Count()==1&&p.inv.removes==0);accepted->Operation->Finished=true;accepted->Operation->Succeeded=true;pending.Tick(1);assert(pending.m_Requests.IsEmpty()&&p.inv.removes==1&&pendingMode.discovery.IsSpent(&folder)&&pendingMode.owned.Contains(&folder));pending.Tick(2);assert(p.inv.removes==1);p.inv.folders.Clear();folder.item.attached=false;pending.Tick(3);assert(!pending.m_Reroll->Running()&&p.inv.spawns==0);
|
|
// Accepted insertion never repeated. A vanished/late native insertion blocks rerolls.
|
|
Mode delayedMode;Service delayed(&delayedMode);Actor d;Add(delayed,d);assert(delayed.BeginReroll());Drain(delayed);assert(d.inv.spawns==1&&delayed.m_Reroll->m_Failed==1&&delayed.m_Unsettled.Contains(&d));assert(delayed.BeginReroll());Drain(delayed);assert(d.inv.spawns==1&&delayed.m_Reroll->m_Failed==1);Actor arrived;d.inv.folders.Insert(&arrived);assert(delayed.BeginReroll());delayed.Tick(0);assert(d.inv.removes==0&&delayed.m_Unsettled.Contains(&d));
|
|
// Arbitrary transferred folder never acknowledges a pending reroll insertion.
|
|
Mode extraMode;Service extra(&extraMode);Actor e,unrelated;Add(extra,e);assert(extra.BeginReroll());extra.Tick(0);assert(e.inv.spawns==1);e.inv.folders.Insert(&unrelated);extra.Tick(1);assert(extra.m_Reroll->Running()&&!extra.BeginReroll()&&e.inv.spawns==1);auto op=extra.m_Reroll->m_Entries[0]->Operation;op->Finished=true;op->Succeeded=true;extra.Tick(2);assert(!extra.m_Reroll->Running()&&extra.m_Reroll->m_Failed==0);
|
|
// A surviving collected/spent folder or targeted mission document is untouched.
|
|
Mode safeMode;Service safe(&safeMode);Actor collector,spent,mission,doc;Add(safe,collector);Add(safe,mission);collector.inv.folders.Insert(&spent);safeMode.discovery.spent.Insert(&spent);mission.inv.folders.Insert(&doc);doc.document=true;assert(safe.BeginReroll());Drain(safe);assert(safe.m_Reroll->m_Skipped==2&&collector.inv.removes==0&&mission.inv.removes==0&&safeMode.discovery.IsSpent(&spent));
|
|
// Newly player-controlled/dead cohort members skipped without touching inventory.
|
|
Mode skipMode;Service skip(&skipMode);Actor player,dead;Add(skip,player);Add(skip,dead);assert(skip.BeginReroll());player.player=true;dead.alive=false;Drain(skip);assert(skip.m_Reroll->m_Skipped==2&&player.inv.spawns==0&&dead.inv.spawns==0);
|
|
// Removal ownership race and spent capacity refusal never create replacement.
|
|
Mode raceMode;Service race(&raceMode);Actor ai,f;Add(race,ai);ai.inv.folders.Insert(&f);assert(race.BeginReroll());race.Tick(0);assert(ai.inv.removes==1);ai.inv.folders.Clear();f.item.attached=true;race.Tick(1);assert(race.m_Reroll->m_Skipped==1&&ai.inv.spawns==0);
|
|
Mode capMode;Service cap(&capMode);Actor ca,cf;Add(cap,ca);ca.inv.folders.Insert(&cf);capMode.discovery.capacity=false;assert(cap.BeginReroll());Drain(cap);assert(cap.m_Reroll->m_Failed==1&&ca.inv.removes==0&&ca.inv.spawns==0);
|
|
// Rejected native removal preserves usable unspent documents for a retry.
|
|
Mode rejectMode;Service reject(&rejectMode);Actor ra,rf;Add(reject,ra);ra.inv.folders.Insert(&rf);ra.inv.acceptRemove=false;rejectMode.settings.chance=0;assert(reject.BeginReroll());reject.Tick(0);assert(reject.m_Reroll->Running()&&reject.m_Reroll->m_Failed==0&&!rejectMode.discovery.IsSpent(&rf)&&!rejectMode.owned.Contains(&rf));ra.inv.acceptRemove=true;reject.Tick(1);assert(ra.inv.removes==2&&rejectMode.discovery.IsSpent(&rf)&&rejectMode.owned.Contains(&rf));ra.inv.folders.Clear();rf.item.attached=false;reject.Tick(2);assert(!reject.m_Reroll->Running()&&reject.m_Reroll->m_Failed==0);
|
|
// Persistent refusal exhausts exactly thirty native attempts without spending.
|
|
Mode refusalMode;Service refusal(&refusalMode);Actor pa,pf;Add(refusal,pa);pa.inv.folders.Insert(&pf);pa.inv.acceptRemove=false;assert(refusal.BeginReroll());Drain(refusal);assert(pa.inv.removes==30&&refusal.m_Reroll->m_Failed==1&&!refusalMode.discovery.IsSpent(&pf)&&!refusalMode.owned.Contains(&pf)&&refusal.m_Reroll->m_Entries[0]->WaitingFor=="removal-refused");
|
|
// Tick budget, bounded missing inventory, Stop prevents further work/restart.
|
|
Mode manyMode;Service many(&manyMode);Actor actors[20];for(auto& actor:actors){actor.hasInventory=false;Add(many,actor);}assert(many.BeginReroll());many.Tick(0);int attempts=0;for(auto entry:many.m_Reroll->m_Entries)attempts+=entry->Attempts;assert(attempts==8);Drain(many,100);assert(many.m_Reroll->m_Failed==20);many.Stop();assert(!many.BeginReroll()&&many.m_Rolled.empty()&&many.m_Requests.IsEmpty()&&many.m_Reroll->m_Cancelled);for(auto entry:many.m_Reroll->m_Entries)assert(!entry->Actor&&!entry->Removing);
|
|
}
|
|
'''
|
|
run(code)
|
|
source=batch.read_text()
|
|
assert 'DeleteEntity' not in source and 'CallLater' not in source
|
|
assert source.index('CanMarkSpent(folder)') < source.index('TryRemoveItemFromInventory(folder)') < source.index('Discovery().MarkSpent(folder)')
|
|
assert 'm_Mode.Own(folder)' in source
|
|
assert '%3/%4 AI processed, %5 failed, %6 skipped.' in source
|
|
assert 'ERR_IntelService Intel()' in service.read_text()
|
|
print('PASS: actual reroll snapshot, authority, cancellation, ownership, accepted operations, quarantine, bounded work and stop methods; no native runtime claim')
|