Integrate radio-delivered convoy cover and conservative squad ammunition reports
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
"""Actual HQ convoy wrappers and authenticated command dispatch; native deployment is a double."""
|
||||
from policy_harness import ROOT,body,run
|
||||
import re
|
||||
import re,os
|
||||
from pathlib import Path
|
||||
H=ROOT/'addons/ai/Scripts/Game/ERR/ERR_HQ.c'
|
||||
P=ROOT/'addons/ai/Scripts/Game/ERR/ERR_HQAdminProvider.c'
|
||||
P=Path(os.environ.get('ERR_HQ_ADMIN_SOURCE',str(ROOT/'addons/ai/Scripts/Game/ERR/ERR_HQAdminProvider.c')))
|
||||
A=ROOT/'addons/core/Scripts/Game/ERR/ERR_AdminService.c'
|
||||
def cpp(s):
|
||||
for old,new in [('protected ',''),('override ',''),('null','nullptr'),('Replication.','Replication::'),
|
||||
@@ -19,10 +20,16 @@ def cpp(s):
|
||||
s=s.replace('foreach (string key : ERR_Settings::Keys())','for (string key : ERR_Settings::Keys())')
|
||||
s=s.replace('mode->Settings()->Get(key).ToString()','string(std::to_string(mode->Settings()->Get(key)))')
|
||||
s=s.replace('bool handled;','bool handled=false;')
|
||||
s=s.replace('Array<string>& parts = {};','Array<string> parts = {};')
|
||||
s=s.replace('out int ', 'int& ').replace('ERR_CommandArguments.Integer', 'ERR_CommandArguments::Integer')
|
||||
s=s.replace('value.ToString()', 'string(std::to_string(value))')
|
||||
s=s.replace('"0123456789".IndexOf(', 'string("0123456789").IndexOf(')
|
||||
return s
|
||||
hq='\n'.join(cpp(body(H,s)) for s in ('static bool MissionActive(', 'bool PrepareConvoy(', 'bool StartConvoy(',
|
||||
'bool StartScenarioConvoy(', 'string ConvoyStatus('))
|
||||
provider=cpp(body(P,'override bool Execute('))
|
||||
provider=cpp(body(P,'protected void StingerSetting('))+cpp(body(P,'override bool Execute('))
|
||||
integer=cpp(body(A,'static bool Integer('))
|
||||
validator=cpp(body(ROOT/'addons/core/Scripts/Game/ERR/ERR_Settings.c','static bool Valid('))
|
||||
extension=cpp(body(A,'protected bool Extension('))
|
||||
# Execute the exact complete auth/normalization/extension-dispatch region.
|
||||
# Unrelated settings/help parsers after this boundary are covered by their own suites.
|
||||
@@ -35,16 +42,30 @@ run(r'''
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
template<class T>struct Array;
|
||||
struct string:std::string{
|
||||
using std::string::string;string(const std::string& v):std::string(v){}
|
||||
bool IsEmpty()const{return empty();}int Length()const{return size();}
|
||||
int IndexOf(const char* s)const{auto p=find(s);return p==npos?-1:int(p);}
|
||||
string Substring(int begin,int count)const{return substr(begin,count);}int ToInt()const{return std::stoi(*this);}
|
||||
void Split(const char* separator,Array<string>& parts,bool skipEmpty)const;
|
||||
int IndexOf(const std::string& s)const{auto p=find(s);return p==npos?-1:int(p);}
|
||||
string Trim()const{auto a=find_first_not_of(" \t\r\n");if(a==npos)return "";
|
||||
return substr(a,find_last_not_of(" \t\r\n")-a+1);}
|
||||
void ToLower(){std::transform(begin(),end(),begin(),[](unsigned char c){return std::tolower(c);});}
|
||||
};
|
||||
template<class T>struct Array:std::vector<T>{void Clear(){this->clear();}void Insert(T n){this->push_back(n);}
|
||||
int Count(){return this->size();}bool IsEmpty(){return this->empty();}};
|
||||
void string::Split(const char* separator,Array<string>& parts,bool skipEmpty)const{
|
||||
parts.Clear();size_t begin=0;const size_t width=std::char_traits<char>::length(separator);assert(width>0);
|
||||
for(;;){auto end=find(separator,begin);string part=substr(begin,end==npos?npos:end-begin);
|
||||
if(!skipEmpty||!part.empty())parts.Insert(part);
|
||||
if(end==npos)break;
|
||||
begin=end+width;
|
||||
}
|
||||
}
|
||||
struct ERR_CommandArguments{
|
||||
'''+integer+r'''
|
||||
};
|
||||
struct vector{float x=0,y=0,z=0;};
|
||||
struct Math{static int Max(int a,int b){return std::max(a,b);}};
|
||||
struct Replication{inline static bool server=true;static bool IsServer(){return server;}};
|
||||
@@ -55,7 +76,13 @@ struct Definition{vector Position{12,3,45};};
|
||||
struct ERR_SiteRuntime{struct Definition* Definition=nullptr;};
|
||||
struct Sites{ERR_SiteRuntime* site=nullptr;int finds=0;string last;
|
||||
ERR_SiteRuntime* Find(string id){finds++;last=id;return site;}};
|
||||
struct ERR_Settings{static Array<string> Keys(){return {}; }int Get(string){return 1;}};
|
||||
struct ERR_Settings{
|
||||
int stinger=15,writes=0;bool saveFails=false;
|
||||
static Array<string> Keys(){return {}; }int Get(string key){return key=="stingerChanceOneIn"?stinger:1;}
|
||||
'''+validator+r'''
|
||||
bool Set(string key,int value){writes++;if(saveFails||!Valid(key,value))return false;
|
||||
assert(key=="stingerChanceOneIn");stinger=value;return true;}
|
||||
};
|
||||
struct ERR_GameMode{
|
||||
inline static ERR_GameMode* current=nullptr;bool active=true,settingsReady=true;Ledger ledger;
|
||||
struct Sites sites;ERR_Settings settings;bool sitesReady=true;
|
||||
@@ -130,6 +157,26 @@ int main(){
|
||||
assert(!provider.Execute(&mode,"hq convoy start extra",replies)&&pool.calls==0);
|
||||
Provider unavailable(nullptr);replies.Clear();assert(unavailable.Execute(&mode,"hq convoy start",replies));
|
||||
assert(replies[0]=="HQ unavailable.");
|
||||
// Stinger commands pass the same actual Core authority and provider dispatch boundary.
|
||||
admin.Execute(&mode,false,"hq stinger set 0",replies);assert(mode.settings.writes==0&&mode.settings.stinger==15);
|
||||
Replication::server=false;admin.Execute(&mode,true,"hq stinger set 0",replies);
|
||||
assert(mode.settings.writes==0&&replies.IsEmpty());Replication::server=true;
|
||||
mode.settingsReady=false;admin.Execute(&mode,true,"hq stinger set 0",replies);
|
||||
assert(mode.settings.writes==0&&replies[0]=="Mission settings are not ready.");mode.settingsReady=true;
|
||||
admin.Execute(&mode,true," HQ STINGER SET 0 ",replies);
|
||||
assert(mode.settings.writes==1&&mode.settings.stinger==0&&pool.calls==0);
|
||||
assert(replies[0].find("have not rolled yet")!=string::npos&&replies[0].find("no reroll, removal or replenishment")!=string::npos);
|
||||
admin.Execute(&mode,true,"hq stinger show",replies);
|
||||
assert(mode.settings.writes==1&&replies[0].find("stingerChanceOneIn=0")!=string::npos);
|
||||
admin.Execute(&mode,true,"hq stinger help",replies);
|
||||
assert(mode.settings.writes==1&&replies[0].find("2..10000 one in N")!=string::npos);
|
||||
mode.settings.saveFails=true;admin.Execute(&mode,true,"hq stinger set 15",replies);
|
||||
assert(mode.settings.stinger==0&&replies[0].find("previous setting retained")!=string::npos);mode.settings.saveFails=false;
|
||||
int writes=mode.settings.writes;
|
||||
admin.Execute(&mode,true,"hq stinger set 1 extra",replies);assert(mode.settings.writes==writes&&mode.settings.stinger==0);
|
||||
admin.Execute(&mode,true,"hq stinger set 1junk",replies);assert(mode.settings.writes==writes&&mode.settings.stinger==0);
|
||||
admin.Execute(&mode,true,"hq stinger set 10001",replies);assert(mode.settings.stinger==0&&replies[0].find("previous setting retained")!=string::npos);
|
||||
replies.Clear();assert(unavailable.Execute(&mode,"hq stinger set 1",replies)&&replies[0]=="HQ unavailable.");
|
||||
// Canonical authored site and preparation failures refuse without consuming the finite receipt.
|
||||
mode.sitesReady=false;assert(!hq.StartScenarioConvoy());mode.sitesReady=true;
|
||||
mode.sites.site=nullptr;assert(!hq.StartScenarioConvoy());mode.sites.site=&site;
|
||||
|
||||
Reference in New Issue
Block a user