Improve AI garrisons, player recovery and mission administration
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""Execute finite site-roster and committed-location spacing policy bodies."""
|
||||
import re
|
||||
from policy_harness import ROOT, body, run
|
||||
core=ROOT/'addons/core/Scripts/Game/ERR/00_Core'
|
||||
roster=body(core/'ERR_SiteSquads.c','static array<ResourceName> Roster(')
|
||||
roster=roster.replace('static array<ResourceName>', 'Array<Text>').replace('array<ResourceName> source','Array<Text>* source').replace('array<ResourceName>','Array<Text>').replace('ResourceName member','Text member').replace('source.', 'source->').replace('source[index % source->Count()]','(*source)[index % source->Count()]').replace('foreach (','for (').replace('member : source','member : *source')
|
||||
spacing=body(core/'ERR_GeneratedSites.c','protected bool Separated(').replace('protected ', '').replace('ERR_SiteDefinition candidate','Site* candidate').replace('ERR_SiteDefinition other','Site* other').replace('vector position','Vec position').replace('foreach (','for (')
|
||||
for name in ('candidate','other','m_Definition'):
|
||||
spacing=spacing.replace(name+'.',name+'->')
|
||||
spacing=spacing.replace('ERR_LocationKind.','Kind::').replace('vector.DistanceXZ','Vec::DistanceXZ').replace('ERR_GameMode.Get().EscapeRadius()','20000')
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
struct Text:std::string {using std::string::string;bool IsEmpty(){return empty();}};
|
||||
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool IsEmpty(){return this->empty();}void Insert(T x){this->push_back(x);}};
|
||||
'''+roster+r'''
|
||||
namespace Kind{enum{PRISON,RADIO,EXTRACTION,OUTPOST,DEPOT,MORTAR,HOSPITAL};}
|
||||
struct Vec{float x,z;static float DistanceXZ(Vec a,Vec b){return std::hypot(a.x-b.x,a.z-b.z);}};
|
||||
struct Site{int Kind=Kind::HOSPITAL;bool RandomClear=true,PlacementResolved=false;Vec Position{0,0};};
|
||||
struct Definition{Array<Site*>Sites;};
|
||||
struct Generator{Definition* m_Definition;
|
||||
'''+spacing+r'''
|
||||
};
|
||||
int main(){
|
||||
Array<Text> source={"medic","rifleman","radioman"},empty,invalid={"rifleman",""};
|
||||
assert(Roster(nullptr,4).IsEmpty()&&Roster(&empty,4).IsEmpty()&&Roster(&invalid,4).IsEmpty());
|
||||
assert(Roster(&source,0).IsEmpty()&&Roster(&source,9).IsEmpty());
|
||||
auto defenders=Roster(&source,4),mobile=Roster(&source,2);
|
||||
assert(defenders.Count()==4&&mobile.Count()==2&&defenders[3]=="medic"&&mobile[1]=="rifleman"&&source.Count()==3);
|
||||
Site a,b;Definition definition{{&a,&b}};Generator generator{&definition};
|
||||
assert(generator.Separated(&a,{0,0},false)); // unresolved seeds do not reserve the map
|
||||
b.PlacementResolved=true;assert(!generator.Separated(&a,{599,0},false));assert(generator.Separated(&a,{600,0},false));
|
||||
b.Kind=Kind::PRISON;assert(!generator.Separated(&a,{599,0},true)); // fallback must pass the same separation check
|
||||
a.Kind=Kind::RADIO;assert(!generator.Separated(&a,{999,0},false));assert(generator.Separated(&a,{1000,0},false));
|
||||
a.Kind=Kind::MORTAR;b.Kind=Kind::MORTAR;assert(!generator.Separated(&a,{999,0},false));assert(generator.Separated(&a,{1000,0},false));
|
||||
}
|
||||
''')
|
||||
print('PASS: exact finite site squads, invalid roster/count rejection, committed-site spacing and safe fallback boundary')
|
||||
|
||||
courier=body(ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_MortarLogistics.c','static ERR_SiteRuntime CourierSource(')
|
||||
courier=courier.replace('static ERR_SiteRuntime', 'Site*').replace('ERR_SiteRuntime site','Site* site').replace('site.', 'site->').replace('null','nullptr')
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
struct Site {Site* Responders=nullptr;bool PatrolCycle=false;};
|
||||
'''+courier+r'''
|
||||
int main(){
|
||||
Site fixed,mobile,legacy;fixed.Responders=&mobile;legacy.PatrolCycle=true;
|
||||
assert(CourierSource(nullptr)==nullptr&&CourierSource(&fixed)==&mobile);
|
||||
fixed.Responders=nullptr;assert(CourierSource(&fixed)==nullptr); // never borrow permanent guards
|
||||
assert(CourierSource(&legacy)==&legacy); // retain explicit old roaming patrol ownership
|
||||
}
|
||||
''')
|
||||
print('PASS: mortar couriers use the mobile site team and refuse permanent-only garrisons')
|
||||
Reference in New Issue
Block a user