Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
82 lines
7.3 KiB
Plaintext
82 lines
7.3 KiB
Plaintext
--- a/addons/core/Scripts/Game/ERR/10_AI/ERR_HQAdminProvider.c
|
|
+++ b/addons/core/Scripts/Game/ERR/10_AI/ERR_HQAdminProvider.c
|
|
@@ -32,12 +32,12 @@
|
|
{
|
|
string key = "antiAirChancePercent";
|
|
string effect = "Only eligible actors which have not rolled yet use this chance; no reroll, removal or replenishment of existing equipment.";
|
|
- string range = "0..100 percent (0 off, 100 every eligible soldier); faction MANPADS preferred, FIM-92 fallback";
|
|
+ string range = "0..100 percent or random (0 off, 100 every eligible soldier); faction MANPADS preferred, FIM-92 fallback";
|
|
if (parts.Count() == 3 && parts[2] == "show")
|
|
- { replies.Insert(key + "=" + mode.Settings().Get(key).ToString() + ". " + effect); return; }
|
|
+ { replies.Insert(key + "=" + ERR_Settings.SelectionText(mode.Settings().Get(key)) + ". " + effect); return; }
|
|
int value;
|
|
- if (parts.Count() == 4 && parts[2] == "set" && ERR_CommandArguments.Integer(parts[3], value) && mode.Settings().Set(key, value))
|
|
- replies.Insert(key + "=" + value.ToString() + " saved. " + effect);
|
|
+ if (parts.Count() == 4 && parts[2] == "set" && ERR_CommandArguments.Selection(key, parts[3], value) && mode.Settings().Set(key, value))
|
|
+ replies.Insert(key + "=" + ERR_Settings.SelectionText(value) + " saved. " + effect);
|
|
else if (parts.Count() == 3 && parts[2] == "help") replies.Insert(range + ". " + effect);
|
|
else replies.Insert("Invalid value or settings could not be saved; previous setting retained. " + range + ". " + effect);
|
|
}
|
|
@@ -125,7 +125,7 @@
|
|
replies.Insert("/esc convoys show|set 0..20|random | hq convoy count show|set N (default three; next round)");
|
|
replies.Insert("/esc hq show | hq memory | hq log show|next|set on|off | hq convoy show|start");
|
|
replies.Insert("/esc hq interval|squads|radius|stinger show|set N | hq convoy auto show|set 0|1|help");
|
|
- replies.Insert("Stinger: 0..100 percent (0 off, 100 every eligible soldier); faction MANPADS preferred, FIM-92 fallback; applies only before each actor rolls.");
|
|
+ replies.Insert("Stinger: 0..100 percent or random (0 off, 100 every eligible soldier); faction MANPADS preferred, FIM-92 fallback; applies only before each actor rolls.");
|
|
replies.Insert("Convoy auto: default 1, next round, finite fleet. /esc hq heli show | hq heli timer set 1..1440 | hq heli return");
|
|
return true;
|
|
}
|
|
--- a/tests/test_ai_stinger_admin.py
|
|
+++ b/tests/test_ai_stinger_admin.py
|
|
@@ -7,24 +7,31 @@
|
|
valid=body(S,'static bool Valid(').replace('string key','std::string key')
|
|
integer=body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c','static bool Integer(')
|
|
integer=(integer.replace('string text','std::string text').replace('out int value','int& value').replace('text.IsEmpty()','text.empty()').replace('text.Length()','int(text.size())').replace('text.Substring(','text.substr(').replace('"0123456789".IndexOf(', 'std::string("0123456789").find(').replace('< 0) return false;','== std::string::npos) return false;').replace('text.ToInt()','std::stoi(text)'))
|
|
+selection=body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c','static bool Selection(')
|
|
+selection=selection.replace('out int ', 'int& ').replace('ERR_Settings.', '').replace('ERR_TimeService.', '').replace('ERR_EnvironmentService.', '')
|
|
+selection_rules='\n'.join(body(S,sig) for sig in ('static bool Randomizable(', 'static bool ValidSelection(', 'static string SelectionText(')).replace('value.ToString()', 'std::to_string(value)')
|
|
method=body(P,'protected void StingerSetting(')
|
|
-method=(method.replace('protected ','').replace('ERR_GameMode mode','ERR_GameMode* mode').replace('array<string>','Array<string>&').replace('mode.Settings().','mode->Settings()->').replace('ERR_CommandArguments.Integer','Integer').replace('mode->Settings()->Get(key).ToString()','std::to_string(mode->Settings()->Get(key))').replace('value.ToString()','std::to_string(value)').replace('int value;','int value=0;'))
|
|
+method=(method.replace('protected ','').replace('ERR_GameMode mode','ERR_GameMode* mode').replace('array<string>','Array<string>&').replace('mode.Settings().','mode->Settings()->').replace('ERR_CommandArguments.Integer','Integer').replace('ERR_CommandArguments.Selection','Selection').replace('ERR_Settings.SelectionText','SelectionText').replace('mode->Settings()->Get(key).ToString()','std::to_string(mode->Settings()->Get(key))').replace('value.ToString()','std::to_string(value)').replace('int value;','int value=0;'))
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <vector>
|
|
using string=std::string;
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}void Insert(T x){this->push_back(x);}};
|
|
-'''+valid+integer+r'''
|
|
+'''+valid+integer+selection_rules+r'''
|
|
+bool ParseClock(string,int&){return false;}bool ParseDate(string,int&){return false;}bool ParseProfile(string,int&){return false;}
|
|
+'''+selection+r'''
|
|
struct Settings{int chance=7,writes=0;bool fail=false;
|
|
int Get(string key){assert(key=="antiAirChancePercent");return chance;}
|
|
- bool Set(string key,int value){writes++;if(fail||!Valid(key,value))return false;chance=value;return true;}};
|
|
+ bool Set(string key,int value){writes++;if(fail||!ValidSelection(key,value))return false;chance=value;return true;}};
|
|
struct ERR_GameMode{struct Settings settings;struct Settings* Settings(){return &settings;}};
|
|
struct Provider{
|
|
'''+method+r'''
|
|
};
|
|
void Effect(const Array<string>& r){assert(r.back().find("have not rolled yet")!=string::npos&&r.back().find("no reroll, removal or replenishment")!=string::npos);}
|
|
int main(){
|
|
+ int parsed=0;assert(Selection("antiAirChancePercent","random",parsed)&&parsed==-1);
|
|
+ assert(SelectionText(parsed)=="Random");
|
|
ERR_GameMode mode;Provider p;Array<string> replies;
|
|
Array<string> show{"hq","stinger","show"};p.StingerSetting(&mode,show,replies);
|
|
assert(mode.settings.writes==0&&replies.back().find("antiAirChancePercent=7")!=string::npos);Effect(replies);
|
|
@@ -45,6 +52,15 @@
|
|
for(Array<string> malformed: {Array<string>{"hq","stinger"},Array<string>{"hq","stinger","set"},Array<string>{"hq","stinger","show","extra"}}){
|
|
p.StingerSetting(&mode,malformed,replies);assert(mode.settings.writes==writes&&replies.back().find("previous setting retained")!=string::npos);
|
|
}
|
|
+ // Same antiAirChancePercent selection as the menu and `hq aa` alias.
|
|
+ mode.settings.fail=false;setting[3]="random";p.StingerSetting(&mode,setting,replies);
|
|
+ assert(mode.settings.chance==-1&&replies.back().find("antiAirChancePercent=Random saved.")!=string::npos);Effect(replies);
|
|
+ p.StingerSetting(&mode,show,replies);assert(replies.back().find("antiAirChancePercent=Random.")!=string::npos);Effect(replies);
|
|
+ // Invalid raw sentinel and unsupported modes remain rejected; no reroll calls.
|
|
+ for(string bad:{"-1","random-day","random day","101"}){setting[3]=bad;p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==-1&&replies.back().find("previous setting retained")!=string::npos);}
|
|
+ mode.settings.fail=true;setting[3]="0";p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==-1);
|
|
+ mode.settings.fail=false;setting[3]="0";p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==0);
|
|
+ mode.settings.fail=true;setting[3]="random";p.StingerSetting(&mode,setting,replies);assert(mode.settings.chance==0&&replies.back().find("previous setting retained")!=string::npos);
|
|
}
|
|
''')
|
|
execute=body(P,'override bool Execute(')
|