Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
48 lines
5.6 KiB
Python
48 lines
5.6 KiB
Python
"""Actual HQ cargo-class reservation and service demand; native availability doubled."""
|
|
import os,re
|
|
from pathlib import Path
|
|
from policy_harness import ROOT,body,run
|
|
H=Path(os.environ.get('ERR_DEPOT_HQ_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_GroundDepotHQ.c'))
|
|
S=Path(os.environ.get('ERR_INFANTRY_RESUPPLY_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_InfantryResupply.c'))
|
|
def cpp(s):
|
|
s=s.replace('protected ','').replace('null','nullptr').replace('int committed;', 'int committed = 0;')
|
|
for typ in ('ERR_HQUnit','ERR_InfantryResupply','ERR_ConvoyVehicle'):
|
|
s=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',s)
|
|
for name in ('m_Mode','crew','donor','service','truck'):
|
|
s=re.sub(r'\b'+name+r'\.',name+'->',s)
|
|
s=s.replace('Replication.IsServer()', 'server').replace('ERR_GameMode.Get()', 'current')
|
|
s=s.replace('foreach (IEntity item : m_Spent)', 'for (IEntity item : m_Spent)')
|
|
return s
|
|
hq='\n'.join(cpp(body(H,x)) for x in ('bool ReserveGroundDepot(', 'void ReleaseGroundDepot('))
|
|
demand='\n'.join(cpp(body(S,x)) for x in ('bool DepotNeeded(', 'bool DepotMineNeeded('))
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
struct Entity{};using IEntity=Entity*;
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}};
|
|
struct Group{};struct HQ;
|
|
struct Mode{HQ*owner=nullptr;bool active=true;bool Active(){return active;}HQ*Command(){return owner;}};
|
|
bool server=true;Mode*current=nullptr;
|
|
struct ERR_HQUnit{struct Group*Group=nullptr;bool HomeGuard=false,ReservedForSupport=false,Task=false,PendingTask=false,PendingCheckin=false,PendingConvoyOrder=false;int LogisticsReservation=0;};
|
|
struct ERR_ConvoyVehicle{struct Group*Group=nullptr;int SupplyToken=0;bool SupplyHeld=false;};
|
|
struct ERR_InfantryResupply{bool magAvailable=true,mineAvailable=true,captured=true;int m_DepotImports=0,m_DepotMineImports=0;Array<IEntity>m_Stock,m_MineStock,m_Spent;ERR_ConvoyVehicle*truck=nullptr;bool DepotAvailable(){return magAvailable;}bool DepotMineAvailable(){return mineAvailable;}bool CaptureMines(){return captured;}ERR_ConvoyVehicle*DepotTruck(){return truck;}
|
|
DEMAND
|
|
};
|
|
struct HQ{Mode*m_Mode=nullptr;bool m_Stopping=false,eligible=true,reserve=true;Array<ERR_HQUnit*>m_Units;int claims=0,releases=0;bool MountedLogisticsEligible(ERR_HQUnit*){return eligible;}bool ReserveLogistics(Group*g,int token){if(!reserve)return false;for(auto*u:m_Units)if(u->Group==g){if(u->LogisticsReservation)return false;u->LogisticsReservation=token;claims++;return true;}return false;}void ReleaseLogistics(Group*g,int token){for(auto*u:m_Units)if(u->Group==g&&u->LogisticsReservation==token){u->LogisticsReservation=0;releases++;}}
|
|
HQMETHODS
|
|
};
|
|
struct F{Mode mode;HQ h;Group cg,dg;ERR_HQUnit crew,donor;ERR_ConvoyVehicle truck;ERR_InfantryResupply s;Entity mine,mag,foreign;F(){server=true;current=&mode;mode.owner=&h;h.m_Mode=&mode;crew.Group=&cg;donor.Group=truck.Group=&dg;h.m_Units={&crew,&donor};s.truck=&truck;s.m_Stock={&mag};s.m_MineStock={&mine};}void Unclaimed(){assert(h.claims==0&&crew.LogisticsReservation==0&&donor.LogisticsReservation==0&&truck.SupplyToken==0&&!truck.SupplyHeld);}};
|
|
int main(){
|
|
// Mine-only expenditure authorizes mine cargo only. Magazine-only is inverse.
|
|
for(bool mines:{false,true})for(bool cargo:{false,true}){F f;f.s.m_Spent={mines?&f.mine:&f.mag};bool accepted=f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300001,cargo);assert(accepted==(mines==cargo));if(!accepted)f.Unclaimed();else{assert(f.h.claims==1&&f.crew.LogisticsReservation==300001&&f.donor.LogisticsReservation==300001&&f.truck.SupplyToken==300001);assert(!f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300002,cargo));f.truck.SupplyHeld=true;f.h.ReleaseGroundDepot(&f.crew,&f.donor,&f.truck,300002);assert(f.truck.SupplyToken==300001&&f.truck.SupplyHeld);f.h.ReleaseGroundDepot(&f.crew,&f.donor,&f.truck,300001);assert(!f.crew.LogisticsReservation&&!f.donor.LogisticsReservation&&!f.truck.SupplyToken&&!f.truck.SupplyHeld);}}
|
|
// Null/deleted/unrelated spent identities and satisfied imported demand never count.
|
|
for(bool mines:{false,true})for(int k=0;k<4;k++){F f;if(k==0){f.s.m_Spent={nullptr};f.s.m_Stock.push_back(nullptr);f.s.m_MineStock.push_back(nullptr);}if(k==1)f.s.m_Spent={&f.foreign};if(k==2){f.s.m_Spent={mines?&f.mine:&f.mag};if(mines)f.s.m_DepotMineImports=1;else f.s.m_DepotImports=1;}if(k==3){f.s.m_Spent={mines?&f.mine:&f.mag};if(mines)f.s.mineAvailable=false;else f.s.magAvailable=false;}assert(!f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300001,mines));f.Unclaimed();}
|
|
// Existing authority, task ownership and token gates apply equally to mine jobs.
|
|
for(int k=0;k<15;k++){F f;f.s.m_Spent={&f.mine};int token=300001;if(k==0)server=false;if(k==1)f.h.m_Stopping=true;if(k==2)current=nullptr;if(k==3)f.mode.active=false;if(k==4)f.mode.owner=nullptr;if(k==5)token=300000;if(k==6)token=300097;if(k==7)f.h.m_Units.clear();if(k==8)f.h.eligible=false;if(k==9)f.crew.HomeGuard=true;if(k==10)f.crew.ReservedForSupport=true;if(k==11)f.crew.PendingCheckin=true;if(k==12)f.crew.PendingConvoyOrder=true;if(k==13)f.h.reserve=false;if(k==14)f.truck.Group=&f.cg;assert(!f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,token,true));f.Unclaimed();}
|
|
// Legacy default remains magazine demand; distinct import counters don't cross classes.
|
|
{F f;f.s.m_Spent={&f.mag,&f.mine};f.s.m_DepotMineImports=1;assert(!f.s.DepotMineNeeded()&&f.s.DepotNeeded());assert(f.h.ReserveGroundDepot(&f.crew,&f.donor,&f.s,300001));}
|
|
}
|
|
'''.replace('DEMAND',demand).replace('HQMETHODS',hq))
|
|
print('PASS: actual HQ mine/magazine claim separation, real demand methods, exact token cleanup and original authority gates; native availability doubled')
|