Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
@@ -19,7 +19,7 @@ run(r'''
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
struct AIWaypoint{};
|
||||
struct ERR_HQTask {bool ReleaseOnly=false,RoadIntercept=false;std::string SecuritySite;float ExpiresAt=100000;};
|
||||
struct ERR_HQTask {int OperationId=0;bool Maneuver=false,ReleaseOnly=false,RoadIntercept=false;std::string SecuritySite;float ExpiresAt=100000;};
|
||||
struct Group {std::vector<AIWaypoint*> queue;int adds=0,removes=0;
|
||||
void RemoveWaypoint(AIWaypoint* w){removes++;queue.erase(std::remove(queue.begin(),queue.end(),w),queue.end());}
|
||||
void AddWaypointAt(AIWaypoint* w,int slot){assert(slot==0);adds++;queue.insert(queue.begin(),w);}};
|
||||
@@ -39,6 +39,8 @@ int main(){
|
||||
assert(f.combat.Update(&f.unit,true,false,19000)==2&&!f.combat.Held&&!f.combat.Paused());
|
||||
assert(f.group.adds==1&&f.group.queue.size()==2&&f.group.queue[0]==&f.search);
|
||||
assert(f.combat.Update(&f.unit,true,false,20000)==0&&f.group.adds==1);}
|
||||
// Explicit HQ flank movement survives contact; expiration returns to normal combat.
|
||||
{Fixture f;f.task.Maneuver=true;assert(f.combat.Update(&f.unit,true,true,2000)==0&&!f.combat.Held&&f.group.removes==0);f.task.ExpiresAt=3000;assert(f.combat.Update(&f.unit,true,true,3000)==1&&f.combat.Paused());}
|
||||
// Never resurrect expired, released, replaced, or newly defensive tasks.
|
||||
for(int invalid=0;invalid<6;invalid++){Fixture f;ERR_HQTask replacement;AIWaypoint other;
|
||||
f.combat.Update(&f.unit,true,true,0);
|
||||
@@ -69,11 +71,12 @@ hq=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQ.c'
|
||||
tick=body(hq,'override void Tick(')
|
||||
assert tick.index('UpdateInfantryCombat(unit, now)') < tick.index('unit.Downlink.Advance')
|
||||
assert 'unit.InfantryCombat.Held || ERR_HunterCombat.Active(unit.Group)' in body(hq,'protected bool Fighting(')
|
||||
assert 'if (unit.PendingTask) LostOrder(unit, now)' in body(hq,'protected void UpdateInfantryCombat(')
|
||||
assert 'if (unit.PendingTask && !unit.PendingTask.Maneuver) LostOrder(unit, now)' in body(hq,'protected void UpdateInfantryCombat(')
|
||||
print('PASS: infantry combat gate precedes radio delivery and preserves non-task transports')
|
||||
|
||||
update=body(hq,'protected void UpdateInfantryCombat(').replace('protected ', '')
|
||||
update=update.replace('ERR_HQUnit unit','ERR_HQUnit* unit').replace('unit.', 'unit->')
|
||||
update=update.replace('PendingTask.', 'PendingTask->')
|
||||
update=update.replace('InfantryCombat.', 'InfantryCombat->').replace('Group.', 'Group->')
|
||||
update=update.replace('array<AIAgent> reacting', 'std::vector<AIAgent*> reacting')
|
||||
update=update.replace('foreach (AIAgent actor : reacting)', 'for (AIAgent* actor : reacting)').replace('actor.', 'actor->')
|
||||
@@ -90,18 +93,19 @@ struct ERR_Actors{static bool CanFight(AIAgent* a){return a->fit;}};
|
||||
struct ERR_HunterCombat{static bool Active(Group*){return true;}};
|
||||
struct ERR_HQUnit;
|
||||
struct State{int change=1;bool paused=true;int Update(ERR_HQUnit*,bool eligible,bool,float){return eligible?change:0;}bool Paused(){return paused;}};
|
||||
struct ERR_HQUnit{int Id=7;string ForceSourceId="town";struct Group* Group;State* InfantryCombat;void* PendingTask=nullptr;bool eligible=true;bool Eligible(int){return eligible;}};
|
||||
struct Task{bool Maneuver=false;};
|
||||
struct ERR_HQUnit{int Id=7;string ForceSourceId="town";struct Group* Group;State* InfantryCombat;Task* PendingTask=nullptr;bool eligible=true;bool Eligible(int){return eligible;}};
|
||||
struct Journal{int logs=0;void Write(string,string){logs++;}};
|
||||
struct HQ{int m_Mode=1,cancelled=0;Journal m_Journal;void LostOrder(ERR_HQUnit* u,float){cancelled++;u->PendingTask=nullptr;}
|
||||
'''+update+r'''
|
||||
};
|
||||
int main(){HQ h;Group g;State state;ERR_HQUnit u;u.Group=&g;u.InfantryCombat=&state;
|
||||
AIAgent fit,casualty;casualty.fit=false;g.members={&fit,&casualty,nullptr};u.PendingTask=&fit;
|
||||
AIAgent fit,casualty;casualty.fit=false;g.members={&fit,&casualty,nullptr};Task pending;u.PendingTask=&pending;
|
||||
h.UpdateInfantryCombat(&u,1000);assert(g.activations==1&&fit.activations==1&&casualty.activations==0&&h.cancelled==1&&h.m_Journal.logs==1);
|
||||
state.change=0;h.UpdateInfantryCombat(&u,2000);assert(g.activations==1&&h.cancelled==1);
|
||||
state.change=1;u.PendingTask=nullptr;h.UpdateInfantryCombat(&u,3000);assert(h.cancelled==1&&fit.activations==2);
|
||||
u.eligible=false;h.UpdateInfantryCombat(&u,4000);assert(g.activations==2&&h.m_Journal.logs==2);
|
||||
u.eligible=true;state.change=2;h.UpdateInfantryCombat(&u,5000);assert(g.activations==2&&h.m_Journal.logs==3);
|
||||
u.eligible=true;pending.Maneuver=true;u.PendingTask=&pending;h.UpdateInfantryCombat(&u,4500);assert(u.PendingTask==&pending&&h.cancelled==1);state.change=2;h.UpdateInfantryCombat(&u,5000);assert(g.activations==3&&h.m_Journal.logs==4);
|
||||
}
|
||||
''')
|
||||
print('PASS: actual HQ contact transition wakes only fit squad members, cancels only task orders and logs changes once')
|
||||
|
||||
Reference in New Issue
Block a user