Fix convoy coordination, AI combat and spectator recovery
This commit is contained in:
@@ -6,15 +6,16 @@ D=ROOT/'addons/core/Scripts/Game/ERR/10_AI'
|
||||
def cpp(s):
|
||||
s=re.sub(r'//[^\n]*','',s).replace('protected ','').replace('override ','').replace('foreach (','for (').replace('null','nullptr')
|
||||
s=s.replace('m_Task.', 'm_Task->').replace('m_Mode.', 'm_Mode->').replace('m_Service.', 'm_Service->')
|
||||
for typ in ('ERR_SupplyConvoyTask','ERR_ConvoyVehicle','ERR_SupplyTeam','ERR_ForceRoute','IEntity'):
|
||||
for typ in ('ERR_SupplyConvoyTask','ERR_ConvoyVehicle','ERR_SupplyTeam','ERR_ForceRoute','ERR_ConvoyBoardingProgress','IEntity'):
|
||||
s=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',s)
|
||||
for obj in ('task','vehicle','departure','team','lost','boarding','stranded','leg','infantryTeam','member','delayed'):
|
||||
s=s.replace(obj+'.',obj+'->')
|
||||
for cls in ('Math','ERR_SupplyConvoyRules','ERR_HQ','ERR_ForceRules','ERR_Actors','vector','string'):
|
||||
s=s.replace(cls+'.',cls+'::')
|
||||
s=s.replace('bool surviving, pending;','bool surviving=false, pending=false;')
|
||||
s=s.replace('bool surviving, pending;','bool surviving=false, pending=false;').replace('bool pending;', 'bool pending=false;')
|
||||
s=s.replace('float nearest = 400; bool found;', 'float nearest = 400; bool found=false;')
|
||||
s=s.replace('m_Support[released].', 'm_Support[released]->').replace('Vehicles[released].', 'Vehicles[released]->').replace('infantryTeam->Group.', 'infantryTeam->Group->')
|
||||
s=s.replace('->Column.', '->Column->').replace('->Combat.', '->Combat->')
|
||||
s=s.replace('->Receipt.', '->Receipt->').replace('Vehicles[2].', 'Vehicles[2]->')
|
||||
s=s.replace('.Entity.', '.Entity->').replace('->Entity.', '->Entity->')
|
||||
return s
|
||||
@@ -36,9 +37,11 @@ run(common+'struct ERR_SupplyConvoyRules{'+next_base+r'''};
|
||||
struct Entity{vector position;vector GetOrigin(){return position;}};
|
||||
struct ERR_ForceRoute{Array<vector> points;void Add(vector p){points.push_back(p);}void Seal(){}};
|
||||
struct Receipt{string SourceId="test";};
|
||||
struct ERR_ConvoyVehicle{bool Released=false,Arrived=false;int cleared=0,RouteIndex=3;struct Entity entity;struct Entity* Entity=&entity;
|
||||
struct Combat{bool Held=false;};
|
||||
struct Column{bool live=true;int resets=0;bool Tick(float){return live;}void Reset(float,bool){resets++;}};
|
||||
struct ERR_ConvoyVehicle{bool Released=false,Arrived=false,SupplyHeld=false;struct Combat combat;struct Combat* Combat=&combat;int cleared=0,RouteIndex=3;struct Entity entity;struct Entity* Entity=&entity;
|
||||
void ClearOrder(){cleared++;}void Tick(void*,ERR_ForceRoute*,float){}};
|
||||
struct ERR_SupplyConvoyTask{Array<ERR_ConvoyVehicle*> Vehicles;float TravelDeadline=1000,Departure=0;bool Waiting=false,stopped=false;int LastBase=-1,Legs=0;
|
||||
struct ERR_SupplyConvoyTask{struct Column column;struct Column* Column=&column;Array<ERR_ConvoyVehicle*> Vehicles;float TravelDeadline=1000,Departure=0;bool Waiting=false,stopped=false;int LastBase=-1,Legs=0;
|
||||
Array<vector> Bases={{0},{1000},{2000}};ERR_ForceRoute* Route=nullptr;struct Receipt receipt;struct Receipt* Receipt=&receipt;
|
||||
void Stop(void*,string){stopped=true;}};
|
||||
struct Service{void* m_Mode=nullptr;
|
||||
@@ -47,18 +50,22 @@ int main(){
|
||||
for(int last=0;last<5;last++)for(int roll=0;roll<4;roll++){int next=ERR_SupplyConvoyRules::NextBase(5,last,roll);assert(next>=0&&next<5&&next!=last);}
|
||||
assert(ERR_SupplyConvoyRules::NextBase(1,0,0)==-1);assert(ERR_SupplyConvoyRules::NextBase(3,3,0)==-1);
|
||||
Service s;ERR_SupplyConvoyTask t;ERR_ConvoyVehicle a,b;t.Vehicles={&a,&b};
|
||||
s.Circuit(&t,999);assert(!t.Waiting&&!a.Arrived);s.Circuit(&t,1000);assert(a.Arrived&&b.Arrived&&t.Waiting&&t.Departure==46000);
|
||||
s.Circuit(&t,45999);assert(t.Legs==0);s.Circuit(&t,46000);assert(t.Legs==1&&!t.Waiting&&!a.Arrived&&!b.Arrived&&t.LastBase==0&&t.TravelDeadline==646000);
|
||||
a.entity.position={250};b.entity.position={251};s.Circuit(&t,47000);assert(a.Arrived&&!b.Arrived&&!t.Waiting);
|
||||
b.entity.position={249};s.Circuit(&t,48000);assert(t.Waiting);s.Circuit(&t,93000);assert(t.LastBase==1&&t.Legs==2);
|
||||
a.Released=true;b.Released=true;s.Circuit(&t,94000);assert(t.stopped); // no replacements
|
||||
s.Circuit(&t,999);assert(!t.Waiting&&!a.Arrived);s.Circuit(&t,1000);assert(!a.Arrived&&!b.Arrived&&!t.Waiting); // timeout is not arrival
|
||||
a.Arrived=b.Arrived=true;a.SupplyHeld=true;s.Circuit(&t,2000);assert(!t.Waiting);
|
||||
a.SupplyHeld=false;b.combat.Held=true;s.Circuit(&t,3000);assert(!t.Waiting);
|
||||
b.combat.Held=false;s.Circuit(&t,4000);assert(t.Waiting&&t.Departure==49000);
|
||||
s.Circuit(&t,48999);assert(t.Legs==0);s.Circuit(&t,49000);assert(t.Legs==1&&!t.Waiting&&!a.Arrived&&!b.Arrived&&t.LastBase==0&&t.column.resets==1);
|
||||
a.entity.position={250};b.entity.position={249};s.Circuit(&t,50000);assert(!a.Arrived&&!b.Arrived&&!t.Waiting); // no 250m shortcut
|
||||
a.Arrived=true;b.Arrived=true;s.Circuit(&t,51000);assert(t.Waiting);s.Circuit(&t,96000);assert(t.LastBase==1&&t.Legs==2);
|
||||
a.Released=true;b.Released=true;t.column.live=false;s.Circuit(&t,97000);assert(t.stopped); // no replacements
|
||||
}
|
||||
''')
|
||||
run(common+r'''
|
||||
struct ERR_ConvoyBoardingProgress{};
|
||||
struct Group{int GetFaction(){return 1;}};struct IEntity{};struct Mode{int EnemyFaction(){return 1;}};
|
||||
namespace ERR_Actors{bool Alive(IEntity*){return true;}struct Group* Group(IEntity*){return nullptr;}}
|
||||
struct ERR_ConvoyVehicle{bool Released=false;void* Group=nullptr;void* Entity=nullptr;};
|
||||
struct ERR_SupplyTeam{bool Released=false,aboard=true,living=true;struct Group nativeGroup;struct Group* Group=&nativeGroup;Array<IEntity*> Members;int orders=0;void Clear(){}
|
||||
struct ERR_SupplyTeam{ERR_ConvoyBoardingProgress* BoardingProgress=nullptr;float BoardingRetryAt=0;bool Released=false,aboard=true,living=true;struct Group nativeGroup;struct Group* Group=&nativeGroup;Array<IEntity*> Members;int orders=0;void Clear(){}
|
||||
bool Aboard(void*,bool required){return aboard==required;}bool Living(){return living;}void Release(void*){Released=true;}void Add(int){orders++;}};
|
||||
struct Receipt{string SourceId="test";};
|
||||
struct ERR_SupplyConvoyTask{Array<ERR_ConvoyVehicle*> Vehicles;Array<ERR_SupplyTeam*> Teams;struct Receipt receipt;struct Receipt* Receipt=&receipt;};
|
||||
@@ -67,7 +74,7 @@ struct Tactics{ERR_SupplyConvoyTask* m_Task;Mode mode;Mode* m_Mode=&mode;Array<E
|
||||
bool Observe(void*,vector& p,float&){p={100};return seeing;}void Start(vector p,float){m_Contact=p;m_State=1;m_TruckWithdrawn=false;starts++;}
|
||||
void Orders(bool,float){reorders++;}bool InfantryAboard(bool required){for(auto t:m_Task->Teams)if(!t->Released&&!t->Aboard(nullptr,required))return false;return true;}
|
||||
void Support(int i,bool hold){if(i==2&&!hold)withdraws++;}bool Usable(int){return truck;}void Clear(){}int Board(void*,bool){return 1;}
|
||||
void Finish(float){m_State=0;finishes++;}
|
||||
float infantryDistance=100;float InfantryDistance(void*){return infantryDistance;}void ProtectInfantry(){}void RefreshBoarding(float){}void Finish(float){m_State=0;finishes++;}
|
||||
'''+cpp(body(D/'ERR_SupplyConvoyTactics.c','void Report('))+cpp(body(D/'ERR_SupplyConvoyTactics.c','bool Tick('))+r'''};
|
||||
int main(){
|
||||
ERR_SupplyConvoyTask task;ERR_ConvoyVehicle driver;task.Vehicles={&driver,&driver,&driver};ERR_SupplyTeam left,right;task.Teams={&left,&right};Tactics t{&task};
|
||||
@@ -75,8 +82,8 @@ int main(){
|
||||
t.Report({100},-1,0);t.Report({100},10,0);t.Report({100},0,60001);assert(t.starts==0);
|
||||
t.Report({100},1000,1000);assert(t.starts==1&&t.m_State==1);t.Report({0},999,1001);assert(t.m_LastContact==1000);
|
||||
assert(t.Tick(60999)&&t.m_State==1&&t.withdraws==0);left.aboard=right.aboard=false;
|
||||
assert(t.Tick(61000)&&t.m_State==2&&t.withdraws==1&&left.orders==1&&right.orders==1&&t.m_BoardDeadline==181000);
|
||||
assert(t.Tick(180999));left.aboard=true;assert(!t.Tick(181000)&&t.finishes==1&&!left.Released&&right.Released);
|
||||
assert(t.Tick(61000)&&t.m_State==2&&t.withdraws==1&&left.orders==1&&right.orders==1&&t.m_BoardDeadline==361000);
|
||||
assert(t.Tick(360999));left.aboard=true;assert(!t.Tick(361000)&&t.finishes==1&&!left.Released&&right.Released);
|
||||
right.Released=false;t.Report({100},200000,200000);t.Tick(260000);assert(t.m_State==2);
|
||||
t.seeing=true;t.Tick(260001);assert(t.m_State==1&&t.starts==3); // fresh contact interrupts reboarding
|
||||
t.seeing=false;t.truck=false;t.Tick(320001);assert(t.m_State==0&&left.Released&&right.Released); // truck lost: release surviving infantry
|
||||
@@ -84,6 +91,9 @@ int main(){
|
||||
left.Released=right.Released=false;left.aboard=right.aboard=true;Tactics retry{&task};retry.Report({100},0,0);
|
||||
for(int i=1;i<=9;i++){retry.Report({100},10000*i,10000*i);retry.Tick(10000*i);}
|
||||
assert(retry.m_DismountAttempts==6&&retry.flanks==12); // six attempts per still-mounted team, no infinite retry
|
||||
left.aboard=right.aboard=false;Tactics safety{&task};safety.Report({100},0,0);safety.infantryDistance=24;
|
||||
safety.Tick(1000);assert(!safety.m_TruckWithdrawn&&safety.withdraws==0); // do not drive through troops at the doors
|
||||
safety.infantryDistance=25;safety.Tick(2000);assert(safety.m_TruckWithdrawn&&safety.withdraws==1);
|
||||
|
||||
}
|
||||
''')
|
||||
|
||||
Reference in New Issue
Block a user