"""Exercise production one-shot equipment lifecycle with async native boundaries.""" from policy_harness import ROOT, body, run import re p=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_AutomaticEquipment.c' s=p.read_text();s=s[s.index('class ERR_AutomaticEquipmentGrant'):].split('modded class ArmaReforgerScripted', 1)[0] s=re.sub(r'//[^\n]*','',s).replace('protected ','').replace('ref ','').replace('class ','struct ') s=s.replace('GetGame().ERR_ItemSelections().Allows(', 'ItemAllowed(') s=s.replace('ResourceName','string').replace('array','Array').replace('array','Array') s=s.replace('InventoryStorageManagerComponent.Cast(actor.FindComponent(InventoryStorageManagerComponent))','actor->inventory') s=s.replace('BaseWeaponComponent.Cast(m_Issued.FindComponent(BaseWeaponComponent))','m_Issued->weapon') for t in ('ERR_GameMode','SCR_AIGroup','IEntity','InventoryStorageManagerComponent','BaseWeaponComponent','ERR_EnemyEquipmentCallback','ERR_AutomaticEquipmentItem','ERR_EnemyOptics'): s=re.sub(r'\b'+t+r' (\w+)',t+r'* \1',s) for obj in ('actor','mode','inventory','m_Operation','m_Choice','weapon','optics'): s=s.replace(obj+'.',obj+'->') s=s.replace('Settings().','Settings()->').replace('Content().','Content()->').replace('muzzles[0].','muzzles[0]->') for obj in ('ERR_EnemyEquipmentRules','ERR_EnemyLoadoutRules','ERR_AutomaticEquipmentCatalog','ERR_EnemyLoadoutCatalog','ERR_HQ','ERR_EquipmentLog','Math','ERR_Inventory'): s=s.replace(obj+'.',obj+'::') s=s.replace('EStoragePurpose purpose','int purpose').replace('EStoragePurpose.','EStoragePurpose::') s=s.replace('string.Format','Format').replace('.IsEmpty()', '.empty()').replace('null','nullptr') s=re.sub(r'\b(bool|int|\w+\*) (\w+);',r'\1 \2 {};',s).replace('\n}\n','\n};\n') run(r''' #include #include #include #include using string=std::string; bool itemAllowed=true; bool ItemAllowed(string){return itemAllowed;} templatestruct Array:std::vector{using std::vector::operator=;int Count(){return this->size();}bool IsEmpty(){return this->empty();}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Copy(const Array& v){*this=v;}void Clear(){this->clear();}}; struct ERR_EnemyEquipmentCallback{bool Finished=false,Succeeded=false;}; struct BaseMuzzleComponent{string ammo="AMMO";string GetDefaultMagazineOrProjectileName(){return ammo;}}; struct BaseWeaponComponent{Array muzzles;void GetMuzzlesList(Array& a){a=muzzles;}}; struct InventoryStorageManagerComponent; struct IEntity{string prefab;bool eligible=true;InventoryStorageManagerComponent* inventory=nullptr;BaseWeaponComponent* weapon=nullptr;}; namespace EStoragePurpose{const int PURPOSE_DEPOSIT=1,PURPOSE_WEAPON_PROXY=2;} struct InventoryStorageManagerComponent{Array items;ERR_EnemyEquipmentCallback* pending=nullptr;int requests=0,purpose=0;bool accept=true;string last; bool TrySpawnPrefabToStorage(string prefab,void*,int,int p,ERR_EnemyEquipmentCallback* op){requests++;pending=op;last=prefab;purpose=p;return accept;} void Complete(bool ok=true){pending->Finished=true;pending->Succeeded=ok;} }; namespace ERR_Inventory{void Items(InventoryStorageManagerComponent* inv,Array& a){a=inv->items;}} struct Settings{int percent=100;int Runtime(string key){assert(key=="automaticEquipmentChancePercent");return percent;}}; struct Content{bool allow=true;bool Allows(string){return allow;}}; struct ERR_GameMode{struct Settings settings;struct Content content;struct Settings* Settings(){return &settings;}struct Content* Content(){return &content;}}; struct SCR_AIGroup{}; struct ERR_EnemyOptics{int registrations=0;IEntity* issued=nullptr;void RegisterIssuedWeapon(IEntity* item){registrations++;issued=item;}}; namespace ERR_EnemyEquipmentRules{bool Eligible(ERR_GameMode*,SCR_AIGroup*,IEntity* a){return a&&a->eligible;}} namespace Math{int roll=0;int RandomInt(int,int){return roll;}} struct ERR_EnemyLoadoutRules{ '''+body(ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_EnemyLoadout.c','static bool Selected(')+r''' }; struct ERR_AutomaticEquipmentItem{string Prefab="MOD_ITEM";bool Weapon=false;int Catalog=1,Weight=1;}; namespace ERR_AutomaticEquipmentCatalog{ERR_AutomaticEquipmentItem item;bool available=true;int picks=0;int TotalWeight(ERR_GameMode*){return 1;}ERR_AutomaticEquipmentItem* Pick(ERR_GameMode*){picks++;return available?&item:nullptr;}} namespace ERR_EnemyLoadoutCatalog{bool Available(string){return true;}IEntity* Find(string prefab,Array& items,Array& excluded){for(auto* i:items)if(i->prefab==prefab&&!excluded.Contains(i))return i;return nullptr;}} namespace ERR_HQ{void Event(string,string){}} namespace ERR_EquipmentLog{std::vector events;int Actor(IEntity*,SCR_AIGroup*){return 1;}void Write(string event,string){events.push_back(event);}} templatestring Format(string,T...){return "";} '''+s+r''' struct Fixture{ERR_GameMode mode;SCR_AIGroup group;IEntity actor,item,authored;BaseWeaponComponent weapon;BaseMuzzleComponent muzzle;InventoryStorageManagerComponent inv;ERR_AutomaticEquipmentGrant grant; Fixture(){ERR_EquipmentLog::events.clear();itemAllowed=true;actor.inventory=&inv;item.prefab=authored.prefab="MOD_ITEM";weapon.muzzles.push_back(&muzzle);item.weapon=&weapon;inv.items.push_back(&authored);ERR_AutomaticEquipmentCatalog::available=true;ERR_AutomaticEquipmentCatalog::item.Weapon=false;Math::roll=0;} void Tick(){grant.Check(&mode,&group,&actor);}void Insert(){inv.items.push_back(&item);inv.Complete();} }; int main(){ {Fixture f;ERR_EnemyOptics optics;ERR_AutomaticEquipmentCatalog::item.Weapon=true; f.grant.Check(&f.mode,&f.group,&f.actor,&optics);assert(optics.registrations==0); f.Insert();f.grant.Check(&f.mode,&f.group,&f.actor,&optics); assert(optics.registrations==1&&optics.issued==&f.item); f.inv.Complete();f.grant.Check(&f.mode,&f.group,&f.actor,&optics); assert(optics.registrations==1);} {Fixture f;f.actor.inventory=nullptr;f.Tick();itemAllowed=false;f.actor.inventory=&f.inv;f.Tick();assert(f.grant.Done()&&f.inv.requests==0);} {Fixture f;ERR_AutomaticEquipmentCatalog::item.Weapon=true;f.Tick();f.Insert();itemAllowed=false;f.Tick();assert(f.grant.Done()&&f.inv.requests==1);} {Fixture f;f.mode.settings.percent=0;f.Tick();f.mode.settings.percent=100;f.Tick();assert(f.grant.Done()&&f.inv.requests==0);} {Fixture f;ERR_AutomaticEquipmentCatalog::available=false;f.Tick();assert(f.grant.Done()&&f.inv.requests==0);} {Fixture f;f.Tick();assert(f.inv.requests==1&&f.inv.purpose==EStoragePurpose::PURPOSE_DEPOSIT);f.Insert();f.Tick();assert(f.grant.Done()&&f.grant.m_Issued==&f.item);f.inv.items.clear();for(int i=0;i<20;i++)f.Tick();assert(f.inv.requests==1);} {Fixture f;f.inv.accept=false;f.Tick();assert(f.grant.Done()&&f.inv.requests==1&&f.inv.items[0]==&f.authored);} {Fixture f;f.Tick();f.inv.Complete(false);f.Tick();assert(f.grant.Done()&&f.inv.requests==1);} {Fixture f;f.Tick();for(int i=0;i<20;i++)f.Tick();assert(f.grant.Done()&&f.inv.requests==1);f.Insert();f.Tick();assert(f.inv.requests==1);} {Fixture f;f.Tick();f.inv.Complete();f.Tick();assert(f.grant.Done()&&!f.grant.m_Issued&&f.inv.requests==1);} {Fixture f;ERR_AutomaticEquipmentCatalog::item.Weapon=true;f.Tick();assert(f.inv.purpose==EStoragePurpose::PURPOSE_WEAPON_PROXY);f.Insert();f.Tick();assert(f.inv.requests==2&&f.inv.last=="AMMO");f.inv.Complete();f.Tick();assert(f.inv.requests==3);f.inv.Complete();f.Tick();assert(f.grant.Done()&&f.grant.m_Magazines==2&&f.grant.m_AmmoConfirmed==2&&f.grant.m_ItemConfirmed);f.Tick();assert(f.inv.requests==3);} // Failed ammo callback must not be reported as two successful magazines. {Fixture f;ERR_AutomaticEquipmentCatalog::item.Weapon=true;f.Tick();f.Insert();f.Tick();f.inv.Complete();f.Tick();f.inv.Complete(false);f.Tick();assert(f.grant.Done()&&f.grant.m_Magazines==2&&f.grant.m_AmmoConfirmed==1&&f.grant.m_ItemConfirmed);} {Fixture f;f.mode.settings.percent=0;f.Tick();f.Tick();assert((ERR_EquipmentLog::events==std::vector{"ROLL"}));} {Fixture f;f.Tick();f.inv.accept=false;f.Insert();ERR_AutomaticEquipmentCatalog::item.Weapon=true;f.Tick();assert(f.grant.m_ItemConfirmed&&f.grant.m_AmmoConfirmed==0);} // A deleted issued entity must not be confused with an authored gun of the same prefab. {Fixture f;ERR_AutomaticEquipmentCatalog::item.Weapon=true;f.Tick();f.Insert();f.Tick();f.inv.items.pop_back();f.grant.m_Issued=nullptr;f.inv.Complete();f.Tick();assert(f.grant.Done()&&f.inv.requests==2);} {Fixture f;ERR_AutomaticEquipmentCatalog::item.Weapon=true;f.Tick();f.Insert();f.mode.content.allow=false;f.Tick();assert(f.grant.Done()&&f.inv.requests==1);} {Fixture f;f.Tick();f.actor.eligible=false;f.Insert();f.Tick();assert(f.grant.Done()&&f.inv.requests==1);} {Fixture f;f.Tick();f.grant.Stop();f.Insert();f.Tick();assert(f.inv.requests==1);} } ''') print('PASS: automatic inventory one-shot roll, exact item ownership, finite compatible ammo, rejection, capture/stop, deletion, loot and late callback quarantine') # The production catalog filter and insertion, including duplicate faction entries. add=p.read_text().split(' protected static void Add',1)[1].split(' static int Count',1)[0] add='void Add'+add add=add.replace('SCR_ArsenalItem.Cast(entry.GetEntityDataOfType(SCR_ArsenalItem))','entry->Data()') add=add.replace('array','Array').replace('ResourceName','string') for t in ('ERR_GameMode','SCR_EntityCatalog','SCR_EntityCatalogEntry','SCR_ArsenalItem','ERR_AutomaticEquipmentItem','Resource'): add=re.sub(r'\b'+t+r' (\w+)',t+r'* \1',add) for obj in ('catalog','entry','arsenal','mode','resource','item'):add=add.replace(obj+'.',obj+'->') add=add.replace('GetGame().ERR_ItemSelections().Weight(prefab)', 'WeightFor(prefab)').replace('ERR_TerrainCatalog.Key(prefab)', 'prefab') add=add.replace('GetGame().ERR_ItemSelections().Allows(prefab)', 'mode->Content()->Allows(prefab)') add=add.replace('ERR_EquipmentLog.Sources(resource)', 'Sources(resource)').replace('ERR_EquipmentLog.Write', 'Log').replace('string.Format', 'Format') add=add.replace('Content().','Content()->').replace('foreach (','for (').replace('SCR_EArsenalItemType.','SCR_EArsenalItemType::') ticket=body(p,'static ERR_AutomaticEquipmentItem AtTicket(').replace('ERR_AutomaticEquipmentItem AtTicket', 'ERR_AutomaticEquipmentItem* AtTicket').replace('].Ceiling', ']->Ceiling').replace('null','nullptr') filter=body(p,'static bool Supported(').replace('SCR_EArsenalItemType.','SCR_EArsenalItemType::').replace('SCR_EArsenalItemMode.','SCR_EArsenalItemMode::') enums='' for name in ('SCR_EArsenalItemType','SCR_EArsenalItemMode'): # Known public enum values; filter logic itself is compiled from production. names=(['RIFLE','PISTOL','LETHAL_THROWABLE','ROCKET_LAUNCHER','MACHINE_GUN','HEAL','BACKPACK','SNIPER_RIFLE','NON_LETHAL_THROWABLE','HEADWEAR','TORSO','VEST_AND_WAIST','LEGS','FOOTWEAR','RADIO_BACKPACK','EQUIPMENT','WEAPON_ATTACHMENT','EXPLOSIVES','HANDWEAR','MORTARS','HELICOPTER','VEHICLE'] if name.endswith('Type') else ['DEFAULT','WEAPON','WEAPON_VARIANTS','AMMUNITION','CONSUMABLE','ATTACHMENT','SUPPORT_STATION','PYLON']) enums+='namespace '+name+'{'+''.join(f'const int {n}=1<<{i+1};' for i,n in enumerate(names))+'}\n' run(r''' #include #include #include #include #include struct string:std::string{using std::string::string;string(std::string v):std::string(v){}bool IsEmpty(){return empty();}int Length(){return size();}string Substring(int a,int b){return substr(a,b);}void ToLower(){std::transform(begin(),end(),begin(),[](unsigned char c){return std::tolower(c);});}}; templatestruct Array:std::vector{bool IsEmpty(){return this->empty();}int Count(){return this->size();}void Insert(T x){this->push_back(x);}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}}; '''+enums+r''' struct Resource{bool valid=true;bool IsValid(){return valid;}}; struct SCR_ArsenalItem{int type=SCR_EArsenalItemType::RIFLE,mode=SCR_EArsenalItemMode::WEAPON;Resource resource;bool enabled=true;int GetItemType(){return type;}int GetItemMode(){return mode;}Resource* GetItemResource(){return &resource;}}; struct SCR_EntityCatalogEntry{bool enabled=true;string prefab;SCR_ArsenalItem arsenal;bool IsEnabled(){return enabled;}string GetPrefab(){return prefab;}SCR_ArsenalItem* Data(){return arsenal.enabled?&arsenal:nullptr;}}; struct SCR_EntityCatalog{Array entries;void GetEntityList(Array& a){a=entries;}}; struct Content{bool Allows(string p){return p!="DISABLED";}}; struct ERR_GameMode{struct Content content;struct Content* Content(){return &content;}}; struct ERR_AutomaticEquipmentItem{string Prefab;bool Weapon=false;int Catalog=0;int Weight=1,Ceiling=0;}; int s_Catalog=1,s_Entries=0,s_Duplicates=0,s_TotalWeight=0; int WeightFor(string p){return p=="ZERO"?0:(p=="{ABCDEF0123456789}Prefabs/A.et"?100:1);} struct{void Set(string,int){}}s_Tickets; templatestring Format(string,T...){return "";} void Log(string,string){} Array auditReasons; void Audit(string,string reason,int=0,int=0,string=""){auditReasons.Insert(reason);} string Sources(Resource*){return "test_mod";} Array s_Items;Array s_Seen;bool s_Overflow=false; '''+filter+'\n'+add+'\n'+ticket+r''' int main(){ using namespace SCR_EArsenalItemType;using namespace SCR_EArsenalItemMode; assert(Supported(RIFLE,WEAPON)&&Supported(HEAL,CONSUMABLE)&&Supported(EQUIPMENT,DEFAULT)); for(int t:{BACKPACK,ROCKET_LAUNCHER,WEAPON_ATTACHMENT,EXPLOSIVES,MORTARS,VEHICLE,HELICOPTER,HEADWEAR,0})assert(!Supported(t,DEFAULT)); for(int m:{AMMUNITION,ATTACHMENT,SUPPORT_STATION,PYLON,0})assert(!Supported(RIFLE,m)); assert(!Supported(RIFLE|VEHICLE,WEAPON)); ERR_GameMode mode;SCR_EntityCatalog catalog;SCR_EntityCatalogEntry a,b,c,d,e,f,g,z; z.prefab="ZERO"; a.prefab="{ABCDEF0123456789}Prefabs/A.et";b.prefab="{abcdef0123456789}Prefabs/OtherName.et"; c.prefab="MEDICINE";c.arsenal.type=HEAL;c.arsenal.mode=CONSUMABLE; d.prefab="DISABLED";e.prefab="ENTRY_OFF";e.enabled=false;f.prefab="DATA_OFF";f.arsenal.enabled=false;g.prefab="INVALID";g.arsenal.resource.valid=false; for(auto* item:{&a,&b,&c,&d,&e,&f,&g,&z})catalog.entries.Insert(item); Add(&mode,&catalog);assert(s_Items.Count()==2&&s_Items[0]->Weapon&&!s_Items[1]->Weapon); Add(&mode,&catalog);assert(s_Items.Count()==2&&s_Duplicates==4); // same catalog merged again gives no extra tickets assert(s_TotalWeight==101&&s_Items[0]->Weight==100&&s_Items[1]->Weight==1); assert(!AtTicket(-1)&&!AtTicket(101)); int rifles=0,medicine=0;for(int t=0;t<101;t++){auto* chosen=AtTicket(t);assert(chosen);if(chosen->Weapon)rifles++;else medicine++;} assert(rifles==100&&medicine==1&&auditReasons.Contains("zero_weight")); assert(auditReasons.Contains("entry_disabled")&&auditReasons.Contains("no_arsenal_data")&&auditReasons.Contains("content_disabled")&&auditReasons.Contains("invalid_resource")&&auditReasons.Contains("eligible")); catalog.entries.resize(16385);Add(&mode,&catalog);assert(s_Overflow); } ''') print('PASS: enabled/valid catalog eligibility, category restrictions, content filtering, GUID deduplication across factions and bounded catalogs and exact weighted ticket boundaries (100:1, zero excluded)')