Improve AI garrisons, player recovery and mission administration
This commit is contained in:
@@ -10,7 +10,7 @@ source = ROOT / 'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminMenu.c'
|
||||
layout = ROOT / 'addons/core/UI/layouts/ERR/AdminMenu.layout'
|
||||
keys = re.findall(r'"([A-Za-z]+)"', body(source, 'static array<string> Keys('))
|
||||
settings = re.findall(r'"([A-Za-z]+)"', body(BASE / 'addons/core/Scripts/Game/ERR/00_Core/ERR_Settings.c', 'static array<string> Keys('))
|
||||
assert len(keys) == 11 and set(settings) - set(keys) == {"stingerChanceOneIn", "automaticConvoyEnabled", "heliTimerMinutes"}
|
||||
assert len(keys) == 13 and set(settings) - set(keys) == {"automaticConvoyEnabled", "heliTimerMinutes", "keepWeaponOnUnconscious"}
|
||||
assert set(keys) <= set(settings) # New text-command setting does not alter the fixed native menu.
|
||||
# Native layouts place child widget declarations inside an anonymous Children
|
||||
# block. A missing brace can preserve most widget names yet prevent menu load.
|
||||
@@ -47,12 +47,13 @@ names = re.findall(r'\bName "([^"]+)"', layout.read_text())
|
||||
assert 'RandomDay_startTimeMinutes' in names
|
||||
assert len(names) == len(set(names)), 'Menu widget names must be unique'
|
||||
for key in keys:
|
||||
assert all(name in names for name in (key, 'Apply_' + key, 'Saved_' + key, 'Random_' + key))
|
||||
assert all(name in names for name in (key, 'Apply_' + key, 'Saved_' + key, 'Random_' + key, 'Help_' + key))
|
||||
for name in ('Close', 'SettingsPage', 'HQPage', 'JournalPage', 'JournalText', 'JournalContent', 'JournalScroll', 'PauseJournal', 'LatestJournal', 'Status'):
|
||||
assert name in names
|
||||
for name in re.findall(r'"([A-Za-z]+)"', body(source, 'override void OnMenuOpen(').split('foreach')[0]):
|
||||
assert name in names
|
||||
journal = body(source, 'static string JournalText(')
|
||||
journal = body(source, 'static string JournalText(').replace('ERR_JournalText.Menu', 'ERR_JournalText::Menu')
|
||||
menu_format = body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_JournalText.c', 'static string Menu(')
|
||||
follow = body(source, 'static bool FollowJournal(')
|
||||
command = body(source, 'static string Command(')
|
||||
available = body(source, 'static bool Available(').replace('Keys().Contains(key)', 'Known(key)')
|
||||
@@ -66,9 +67,14 @@ struct string : std::string {
|
||||
string(std::string s):std::string(s){}
|
||||
bool IsEmpty(){return empty();}
|
||||
int Length(){return size();}
|
||||
int IndexOf(string s){auto i=find(s);return i==npos?-1:int(i);}
|
||||
string Substring(int i,int n){return substr(i,n);}
|
||||
void Replace(string a,string b){size_t i=0;while((i=find(a,i))!=npos){replace(i,a.size(),b);i+=b.size();}}
|
||||
string Trim(){auto a=find_first_not_of(" \t\r\n");if(a==npos)return "";auto b=find_last_not_of(" \t\r\n");return substr(a,b-a+1);}
|
||||
};
|
||||
struct ERR_JournalText {
|
||||
''' + menu_format + r'''
|
||||
};
|
||||
struct Fields {
|
||||
static bool Known(string key) {return ''' + known + ';}\n' + command + '\n' + available + '\n' + follow + '\n' + journal + r'''
|
||||
};
|
||||
@@ -91,7 +97,7 @@ int main() {
|
||||
{"intelRevealChancePercent","intel reveal"},{"startTimeMinutes","mission time"},
|
||||
{"timeMultiplier","mission speed"},{"startDateCode","mission date"},
|
||||
{"weatherProfile","mission weather"},{"reportIntervalSeconds","hq interval"},
|
||||
{"supportSquadLimit","hq squads"},{"responseRadiusMetres","hq radius"},{"convoyCount","hq convoy count"}};
|
||||
{"supportSquadLimit","hq squads"},{"responseRadiusMetres","hq radius"},{"convoyCount","hq convoy count"},{"antiAirChancePercent","hq aa"},{"antiPersonnelMineChancePercent","hq mines"}};
|
||||
for(auto pair:cases){
|
||||
assert(Fields::Command(pair.first," 42 ")==pair.second+" set 42");
|
||||
assert(Fields::Command(pair.first,"Random")==pair.second+" set Random");
|
||||
@@ -106,7 +112,7 @@ int main() {
|
||||
for(string key:{"heliTimer","prisonDistance","stingerChance","mission abandon","","bad"}){
|
||||
assert(Fields::Command(key,"1").empty());assert(!Fields::Available(key,true,true));
|
||||
}
|
||||
for(string key:{"reportIntervalSeconds","supportSquadLimit","responseRadiusMetres","convoyCount"}){
|
||||
for(string key:{"reportIntervalSeconds","supportSquadLimit","responseRadiusMetres","convoyCount","antiAirChancePercent","antiPersonnelMineChancePercent"}){
|
||||
assert(!Fields::Available(key,false,true));assert(Fields::Available(key,true,false));
|
||||
}
|
||||
assert(!Fields::Available("aiIntelChancePercent",true,false));
|
||||
@@ -114,4 +120,10 @@ int main() {
|
||||
for(string key:{"intelRevealChancePercent","radioDefenceSeconds","startTimeMinutes","timeMultiplier","startDateCode","weatherProfile"}) assert(Fields::Available(key,false,false));
|
||||
}
|
||||
''')
|
||||
print('PASS: actual menu command routing covers all eleven settings, rejects unsupported keys, gates companions, and matches unique authored widgets')
|
||||
print('PASS: actual menu command routing covers all thirteen settings, rejects unsupported keys, gates companions, and matches unique authored widgets')
|
||||
|
||||
assert all(name in names for name in ('KeepWeaponOn', 'KeepWeaponOff', 'Saved_keepWeaponOnUnconscious'))
|
||||
click=body(source,'protected void OnButton(')
|
||||
assert 'm_Controller.ERR_AdminSubmit("mission keepweapon set " + retain, true)' in click
|
||||
assert click.index('!m_Ready') < click.index('"mission keepweapon set "')
|
||||
print('PASS: explicit weapon retention buttons use the same ready/authorized server command path')
|
||||
|
||||
Reference in New Issue
Block a user