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:
@@ -0,0 +1,115 @@
|
||||
"""Execute tactical cue selection, queueing and playback revalidation from production."""
|
||||
import re
|
||||
from policy_harness import ROOT, body, run
|
||||
P=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQOperationSpeech.c'
|
||||
C=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_SoldierSpeechContext.c'
|
||||
E=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQExecution.c'
|
||||
T=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQTask.c'
|
||||
def cpp(s):
|
||||
s=s.replace('protected ','').replace('null','nullptr')
|
||||
for typ in ('ERR_HQTask','ERR_HQExecutionReport','ERR_HQUnit','SCR_AITalkRequest'):
|
||||
s=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',s)
|
||||
for n in ('task','report','unit','request','m_Agent','m_VoNComponent','Group','Task','Execution'):
|
||||
s=s.replace(n+'.',n+'->')
|
||||
for n in ('ERR_HQOperationRole','ERR_HQExecutionState','ERR_HQExecutionRules','ERR_HQOperationSpeechRules','ERR_SoldierConversationRules','ECommMethod','ECommunicationType','vector','SCR_EAITalkRequestPreset'):
|
||||
s=s.replace(n+'.',n+'::')
|
||||
return s
|
||||
enums=body(T,'enum ERR_HQOperationRole')+';'+body(E,'enum ERR_HQExecutionState')+';'
|
||||
enums=enums.replace('enum ','enum class ')
|
||||
rules=cpp(body(P,'static int Phrase(')+body(P,'static bool QueuedFresh('))
|
||||
execute=cpp(body(C,'void ERR_SpeechOperation(')+body(C,'protected bool ERR_SpeechOperationValid('))
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
'''+enums+r'''
|
||||
struct ERR_HQTask{int OperationId=1,OperationRevision=2,ExecutionId=10;float ExpiresAt=100000,SupportUntil=21000;ERR_HQOperationRole OperationRole=ERR_HQOperationRole::RESERVE;};
|
||||
struct ERR_HQExecutionReport{int OperationId=1,OperationRevision=2,ExecutionId=10;float ObservedAt=10000,SupportUntil=21000,SearchedRadius=0;bool PhysicallyArrived=true,HasContact=false,SupportReady=false;ERR_HQExecutionState State=ERR_HQExecutionState::ARRIVED;};
|
||||
struct ERR_HQExecutionRules{static bool Terminal(ERR_HQExecutionState s){return s==ERR_HQExecutionState::COMPLETED||s==ERR_HQExecutionState::FAILED||s==ERR_HQExecutionState::SUPERSEDED;}static bool SupportFresh(float at,float now){return at>now&&at<=now+30000;}};
|
||||
struct ERR_HQOperationSpeechRules{
|
||||
'''+rules+r'''
|
||||
};
|
||||
struct Agent;
|
||||
struct Group{Agent*leader=nullptr;bool slave=false;int players=0;bool IsSlave(){return slave;}int GetPlayerCount(bool){return players;}Agent*GetLeaderAgent(){return leader;}};
|
||||
struct Agent{Group*group=nullptr;Group*GetParentGroup(){return group;}};
|
||||
struct Execution{ERR_HQExecutionReport report;bool pending=true;ERR_HQExecutionReport*Snapshot(int,int,float){return pending?&report:nullptr;}};
|
||||
struct ERR_HQUnit{int Id=1,LogisticsReservation=0;bool HomeGuard=false,ReservedForSupport=false;struct Group*Group=nullptr;ERR_HQTask*Task=nullptr;struct Execution*Execution=nullptr;};
|
||||
namespace ECommMethod{enum{DIRECT,RADIO};}
|
||||
namespace ECommunicationType{enum{REPORT_IDLE};}
|
||||
namespace SCR_EAITalkRequestPreset{enum{IRRELEVANT};}
|
||||
namespace vector{int Zero=0;}
|
||||
struct Von{int method=ECommMethod::DIRECT;int GetCommMethod(){return method;}};
|
||||
struct SCR_AITalkRequest{int m_ERRSpeechPhrase=-1,m_ERROperationExecution=0;float m_ERROperationQueuedAt=-1;ERR_HQUnit*m_ERROperationUnit=nullptr;SCR_AITalkRequest(int,void*,int,int,bool,bool,int){}};
|
||||
struct ERR_SoldierConversationRules{static bool Quiet(bool threat,bool overt){return threat&&!overt;}};
|
||||
struct Handler{bool enabled=true,m_ERRSpeechThreat=false,m_ERRSpeechOvert=false;float m_ERROperationNext=0,m_ERRSpeechNextLine=0;int m_ERROperationLastExecution=0,m_ERROperationLastPhrase=-1,requests=0;Agent*m_Agent=nullptr;Von*m_VoNComponent=nullptr;SCR_AITalkRequest*queued=nullptr;
|
||||
bool ERR_SpeechEnabled(){return enabled;}void ERR_SpeechObserve(float){}void AddRequest(SCR_AITalkRequest*q){requests++;queued=q;}
|
||||
'''+execute+r'''
|
||||
};
|
||||
struct Fixture{ERR_HQTask task;Execution exec;ERR_HQUnit unit;Agent actor;Group group;Von von;Handler comms;
|
||||
Fixture(){unit.Group=&group;unit.Task=&task;unit.Execution=&exec;actor.group=&group;group.leader=&actor;comms.m_Agent=&actor;comms.m_VoNComponent=&von;}
|
||||
int Phrase(float now=10000){return ERR_HQOperationSpeechRules::Phrase(&task,&exec.report,now);}
|
||||
};
|
||||
int main(){
|
||||
{Fixture f;assert(f.Phrase()==1203);f.exec.report.PhysicallyArrived=false;assert(f.Phrase()==-1);}
|
||||
for(int failure=0;failure<9;failure++){Fixture f;
|
||||
if(failure==0)f.exec.report.ExecutionId++;
|
||||
if(failure==1)f.exec.report.OperationId++;
|
||||
if(failure==2)f.exec.report.OperationRevision++;
|
||||
if(failure==3)f.task.ExpiresAt=10000;
|
||||
if(failure==4)f.exec.report.ObservedAt=10001;
|
||||
if(failure==5)f.exec.report.ObservedAt=7499;
|
||||
if(failure==6)f.exec.report.ObservedAt=-1;
|
||||
if(failure==7)f.exec.report.ObservedAt=std::numeric_limits<float>::quiet_NaN();
|
||||
if(failure==8)f.exec.report.State=ERR_HQExecutionState::FAILED;
|
||||
assert(f.Phrase()==-1);
|
||||
}
|
||||
{Fixture f;f.task.OperationRole=ERR_HQOperationRole::FIX;f.exec.report.HasContact=true;
|
||||
assert(f.Phrase()==-1);f.exec.report.SupportReady=true;assert(f.Phrase()==1200);
|
||||
f.exec.report.HasContact=false;assert(f.Phrase()==-1); // remembered-area fire never says it can cover an advance
|
||||
f.exec.report.HasContact=true;f.exec.report.SupportUntil=10000;assert(f.Phrase()==-1);
|
||||
f.exec.report.SupportUntil=21000;f.exec.report.State=ERR_HQExecutionState::SUPERSEDED;assert(f.Phrase()==-1);
|
||||
}
|
||||
{Fixture f;f.task.OperationRole=ERR_HQOperationRole::SEARCH;f.exec.report.State=ERR_HQExecutionState::COMPLETED;
|
||||
assert(f.Phrase()==-1);f.exec.report.SearchedRadius=10;assert(f.Phrase()==1204);
|
||||
f.exec.report.HasContact=true;assert(f.Phrase()==-1);
|
||||
}
|
||||
{Fixture f;f.task.OperationRole=ERR_HQOperationRole::FLANK;f.exec.report.State=ERR_HQExecutionState::TRAVELLING;
|
||||
assert(f.Phrase()==1201);f.task.SupportUntil=10000;assert(f.Phrase()==-1);
|
||||
f.task.OperationRole=ERR_HQOperationRole::WITHDRAW;assert(f.Phrase()==1202);
|
||||
f.exec.report.State=ERR_HQExecutionState::BLOCKED;assert(f.Phrase()==-1);
|
||||
}
|
||||
{Fixture f;f.comms.ERR_SpeechOperation(&f.unit,10000);assert(f.comms.requests==1&&f.comms.queued->m_ERRSpeechPhrase==1203);
|
||||
assert(f.comms.ERR_SpeechOperationValid(f.comms.queued,10001));
|
||||
f.comms.ERR_SpeechOperation(&f.unit,10001);assert(f.comms.requests==1);
|
||||
f.exec.report.ObservedAt=40000;f.comms.ERR_SpeechOperation(&f.unit,40000);assert(f.comms.requests==1); // same order/action is not repeated
|
||||
f.task.ExecutionId++;f.exec.report.ExecutionId++;f.comms.ERR_SpeechOperation(&f.unit,40000);assert(f.comms.requests==2);
|
||||
}
|
||||
for(int failure=0;failure<11;failure++){Fixture f;f.comms.ERR_SpeechOperation(&f.unit,10000);auto q=f.comms.queued;assert(q);
|
||||
if(failure==0)f.unit.Task=nullptr;
|
||||
if(failure==1)f.task.ExecutionId++;
|
||||
if(failure==2)f.exec.pending=false; // acknowledgement is not fresh physical proof
|
||||
if(failure==3)f.unit.HomeGuard=true;
|
||||
if(failure==4)f.unit.ReservedForSupport=true;
|
||||
if(failure==5)f.unit.LogisticsReservation=1;
|
||||
if(failure==6)f.group.slave=true;
|
||||
if(failure==7)f.group.players=1;
|
||||
if(failure==8)f.group.leader=nullptr;
|
||||
if(failure==9)f.actor.group=nullptr;
|
||||
if(failure==10)f.exec.report.HasContact=true;
|
||||
assert(!f.comms.ERR_SpeechOperationValid(q,10001));
|
||||
}
|
||||
{Fixture f;f.comms.ERR_SpeechOperation(&f.unit,10000);f.exec.report.ObservedAt=13000;
|
||||
assert(!f.comms.ERR_SpeechOperationValid(f.comms.queued,13000)); // stale queue cannot become true again
|
||||
}
|
||||
for(int failure=0;failure<4;failure++){Fixture f;
|
||||
if(failure==0)f.comms.enabled=false;
|
||||
if(failure==1)f.von.method=ECommMethod::RADIO;
|
||||
if(failure==2)f.comms.m_ERRSpeechThreat=true;
|
||||
if(failure==3)f.group.leader=nullptr;
|
||||
f.comms.ERR_SpeechOperation(&f.unit,10000);assert(!f.comms.requests);
|
||||
}
|
||||
assert(!ERR_HQOperationSpeechRules::QueuedFresh(10000,9999));
|
||||
assert(ERR_HQOperationSpeechRules::QueuedFresh(10000,12500));
|
||||
assert(!ERR_HQOperationSpeechRules::QueuedFresh(10000,12501));
|
||||
}
|
||||
''')
|
||||
print('PASS: actual-action speech, finite current cover, local search wording, silence after replacement/transfer/stale queue, stable cooldown and optional direct speech')
|
||||
Reference in New Issue
Block a user