Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2024-03-17 01:25:55 +07:00
164 changed files with 9321 additions and 6017 deletions
+1
View File
@@ -27,6 +27,7 @@
* API removals:
* \li AIError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
* \li AIInfo::CONFIG_RANDOM, no longer used.
* \li AIInfo::AddSettings random_deviation is no longer used.
*
* Other changes:
* \li AIGroupList accepts an optional filter function
+1
View File
@@ -93,6 +93,7 @@
* API removals:
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
* \li GSInfo::CONFIG_RANDOM, no longer used.
* \li GSInfo::AddSettings random_deviation is no longer used.
*
* Other changes:
* \li GSGroupList accepts an optional filter function
-6
View File
@@ -224,12 +224,6 @@ public:
* clamped in the range [MIN(int32_t), MAX(int32_t)] (inclusive).
* - default_value The default value. Required. The value will be
* clamped in the range [MIN(int32_t), MAX(int32_t)] (inclusive).
* - random_deviation If this property has a nonzero value, then the
* actual value of the setting in game will be randomised in the range
* [user_configured_value - random_deviation, user_configured_value + random_deviation] (inclusive).
* random_deviation sign is ignored and the value is clamped in the range [0, MAX(int32_t)] (inclusive).
* The randomisation will happen just before the Script start.
* Not allowed if the CONFIG_BOOLEAN flag is set, otherwise optional.
* - step_size The increase/decrease of the value every time the user
* clicks one of the up/down arrow buttons. Optional, default is 1.
* - flags Bitmask of some flags, see ScriptConfigFlags. Required.
+74 -50
View File
@@ -160,45 +160,62 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
std::string ScriptText::GetEncodedText()
{
StringIDList seen_ids;
ScriptTextList seen_texts;
ParamList params;
int param_count = 0;
std::string result;
auto output = std::back_inserter(result);
this->_FillParamList(params);
this->_GetEncodedText(output, param_count, seen_ids, params);
this->_FillParamList(params, seen_texts);
this->_GetEncodedText(output, param_count, params, true);
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
return result;
}
void ScriptText::_FillParamList(ParamList &params)
void ScriptText::_FillParamList(ParamList &params, ScriptTextList &seen_texts)
{
if (std::find(seen_texts.begin(), seen_texts.end(), this) != seen_texts.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", GetGameStringName(this->string)));
seen_texts.push_back(this);
for (int i = 0; i < this->paramc; i++) {
Param *p = &this->param[i];
params.emplace_back(this->string, i, p);
if (!std::holds_alternative<ScriptTextRef>(*p)) continue;
std::get<ScriptTextRef>(*p)->_FillParamList(params);
std::get<ScriptTextRef>(*p)->_FillParamList(params, seen_texts);
}
seen_texts.pop_back();
/* Fill with dummy parameters to match FormatString() behaviour. */
if (seen_texts.empty()) {
static Param dummy = 0;
int nb_extra = SCRIPT_TEXT_MAX_PARAMETERS - (int)params.size();
for (int i = 0; i < nb_extra; i++)
params.emplace_back(-1, i, &dummy);
}
}
void ScriptText::ParamCheck::Encode(std::back_insert_iterator<std::string> &output)
void ScriptText::ParamCheck::Encode(std::back_insert_iterator<std::string> &output, const char *cmd)
{
if (this->cmd == nullptr) this->cmd = cmd;
if (this->used) return;
if (std::holds_alternative<std::string>(*this->param)) fmt::format_to(output, ":\"{}\"", std::get<std::string>(*this->param));
if (std::holds_alternative<SQInteger>(*this->param)) fmt::format_to(output, ":{:X}", std::get<SQInteger>(*this->param));
if (std::holds_alternative<ScriptTextRef>(*this->param)) fmt::format_to(output, ":{:X}", this->owner);
if (std::holds_alternative<ScriptTextRef>(*this->param)) {
fmt::format_to(output, ":");
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", std::get<ScriptTextRef>(*this->param)->string);
}
this->used = true;
}
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids, ParamSpan args)
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args, bool first)
{
const std::string &name = GetGameStringName(this->string);
if (std::find(seen_ids.begin(), seen_ids.end(), this->string) != seen_ids.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", name));
seen_ids.push_back(this->string);
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string);
if (first) {
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string);
}
const StringParams &params = GetGameStringParams(this->string);
@@ -212,51 +229,58 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
auto skip_args = [&](size_t nb) { idx += nb; };
for (const StringParam &cur_param : params) {
switch (cur_param.type) {
case StringParam::UNUSED:
skip_args(cur_param.consumes);
break;
try {
switch (cur_param.type) {
case StringParam::UNUSED:
skip_args(cur_param.consumes);
break;
case StringParam::RAW_STRING: {
ParamCheck &p = *get_next_arg();
if (!std::holds_alternative<std::string>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
p.Encode(output);
break;
}
case StringParam::STRING: {
ParamCheck &p = *get_next_arg();
if (!std::holds_alternative<ScriptTextRef>(*p.param)){
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd));
p.Encode(output);
case StringParam::RAW_STRING:
{
ParamCheck &p = *get_next_arg();
p.Encode(output, cur_param.cmd);
if (p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<std::string>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
break;
}
int count = 0;
fmt::format_to(output, ":");
ScriptTextRef &ref = std::get<ScriptTextRef>(*p.param);
ref->_GetEncodedText(output, count, seen_ids, args.subspan(idx));
p.used = true;
if (++count != cur_param.consumes) {
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1));
/* Fill missing params if needed. */
for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0");
case StringParam::STRING:
{
ParamCheck &p = *get_next_arg();
p.Encode(output, cur_param.cmd);
if (p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<ScriptTextRef>(*p.param)) {
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd));
param_count++;
continue;
}
int count = 0;
ScriptTextRef &ref = std::get<ScriptTextRef>(*p.param);
ref->_GetEncodedText(output, count, args.subspan(idx), false);
if (++count != cur_param.consumes) {
ScriptLog::Warning(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1));
/* Fill missing params if needed. */
for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0");
}
skip_args(cur_param.consumes - 1);
break;
}
skip_args(cur_param.consumes - 1);
break;
default:
for (int i = 0; i < cur_param.consumes; i++) {
ParamCheck &p = *get_next_arg();
p.Encode(output, i == 0 ? cur_param.cmd : nullptr);
if (i == 0 && p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<SQInteger>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
}
}
default:
for (int i = 0; i < cur_param.consumes; i++) {
ParamCheck &p = *get_next_arg();
if (!std::holds_alternative<SQInteger>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
p.Encode(output);
}
param_count += cur_param.consumes;
} catch (int nb) {
param_count += nb;
ScriptLog::Warning(fmt::format("{}({}): Invalid parameter", name, param_count));
}
param_count += cur_param.consumes;
}
seen_ids.pop_back();
}
const std::string Text::GetDecodedText()
+10 -7
View File
@@ -129,7 +129,7 @@ public:
private:
using ScriptTextRef = ScriptObjectRef<ScriptText>;
using StringIDList = std::vector<StringID>;
using ScriptTextList = std::vector<ScriptText *>;
using Param = std::variant<SQInteger, std::string, ScriptTextRef>;
struct ParamCheck {
@@ -137,10 +137,11 @@ private:
int idx;
Param *param;
bool used;
const char *cmd;
ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param), used(false) {}
ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param), used(false), cmd(nullptr) {}
void Encode(std::back_insert_iterator<std::string> &output);
void Encode(std::back_insert_iterator<std::string> &output, const char *cmd);
};
using ParamList = std::vector<ParamCheck>;
@@ -155,17 +156,19 @@ private:
* The parameters are added as _GetEncodedText used to encode them
* before the addition of parameter validation.
* @param params The list of parameters to fill.
* @param seen_texts The list of seen ScriptText.
*/
void _FillParamList(ParamList &params);
void _FillParamList(ParamList &params, ScriptTextList &seen_texts);
/**
* Internal function for recursive calling this function over multiple
* instances, while writing in the same buffer.
* @param output The output to write the encoded text to.
* @param param_count The number of parameters that are in the string.
* @param seen_ids The list of seen StringID.
* @param param_count The number of parameters that are consumed by the string.
* @param args The parameters to be consumed.
* @param first Whether it's the first call in the recursion.
*/
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids, ParamSpan args);
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args, bool first);
/**
* Set a parameter, where the value is the first item on the stack.
-9
View File
@@ -123,15 +123,6 @@ void ScriptConfig::ResetEditableSettings(bool yet_to_start)
}
}
void ScriptConfig::AddRandomDeviation(CompanyID owner)
{
for (const auto &item : *this->GetConfigList()) {
if (item.random_deviation != 0) {
this->SetSetting(item.name, ScriptObject::GetRandomizer(owner).Next(item.random_deviation * 2 + 1) - item.random_deviation + this->GetSetting(item.name));
}
}
}
bool ScriptConfig::HasScript() const
{
return this->info != nullptr;
-6
View File
@@ -35,7 +35,6 @@ struct ScriptConfigItem {
int min_value = 0; ///< The minimal value this configuration setting can have.
int max_value = 1; ///< The maximal value this configuration setting can have.
int default_value = 0; ///< The default value of this configuration setting.
int random_deviation = 0; ///< The maximum random deviation from the default value.
int step_size = 1; ///< The step size in the gui.
ScriptConfigFlags flags = SCRIPTCONFIG_NONE; ///< Flags for the configuration setting.
LabelMapping labels; ///< Text labels for the integer values.
@@ -132,11 +131,6 @@ public:
*/
void ResetEditableSettings(bool yet_to_start);
/**
* Randomize all settings the Script requested to be randomized.
*/
void AddRandomDeviation(CompanyID owner);
/**
* Is this config attached to an Script? In other words, is there a Script
* that is assigned to this slot.
+8 -38
View File
@@ -379,18 +379,10 @@ struct ScriptSettingsWindow : public Window {
TextColour colour;
uint idx = 0;
if (config_item.description.empty()) {
if (this->slot != OWNER_DEITY && !Company::IsValidID(this->slot) && config_item.random_deviation != 0) {
str = STR_AI_SETTINGS_JUST_DEVIATION;
} else {
str = STR_JUST_STRING1;
}
str = STR_JUST_STRING1;
colour = TC_ORANGE;
} else {
if (this->slot != OWNER_DEITY && !Company::IsValidID(this->slot) && config_item.random_deviation != 0) {
str = STR_AI_SETTINGS_SETTING_DEVIATION;
} else {
str = STR_AI_SETTINGS_SETTING;
}
str = STR_AI_SETTINGS_SETTING;
colour = TC_LIGHT_BLUE;
SetDParamStr(idx++, config_item.description);
}
@@ -405,35 +397,13 @@ struct ScriptSettingsWindow : public Window {
DrawArrowButtons(br.left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, editable && current_value > config_item.min_value, editable && current_value < config_item.max_value);
}
if (this->slot == OWNER_DEITY || Company::IsValidID(this->slot) || config_item.random_deviation == 0) {
auto config_iterator = config_item.labels.find(current_value);
if (config_iterator != config_item.labels.end()) {
SetDParam(idx++, STR_JUST_RAW_STRING);
SetDParamStr(idx++, config_iterator->second);
} else {
SetDParam(idx++, STR_JUST_INT);
SetDParam(idx++, current_value);
}
auto config_iterator = config_item.labels.find(current_value);
if (config_iterator != config_item.labels.end()) {
SetDParam(idx++, STR_JUST_RAW_STRING);
SetDParamStr(idx++, config_iterator->second);
} else {
int min_deviated = std::max(config_item.min_value, current_value - config_item.random_deviation);
auto config_iterator = config_item.labels.find(min_deviated);
if (config_iterator != config_item.labels.end()) {
SetDParam(idx++, STR_JUST_RAW_STRING);
SetDParamStr(idx++, config_iterator->second);
} else {
SetDParam(idx++, STR_JUST_INT);
SetDParam(idx++, min_deviated);
}
int max_deviated = std::min(config_item.max_value, current_value + config_item.random_deviation);
config_iterator = config_item.labels.find(max_deviated);
if (config_iterator != config_item.labels.end()) {
SetDParam(idx++, STR_JUST_RAW_STRING);
SetDParamStr(idx++, config_iterator->second);
} else {
SetDParam(idx++, STR_JUST_INT);
SetDParam(idx++, max_deviated);
}
SetDParam(idx++, STR_JUST_INT);
SetDParam(idx++, current_value);
}
}
+3 -27
View File
@@ -87,9 +87,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
ScriptConfigItem config;
uint items = 0;
int easy_value = INT32_MIN;
int medium_value = INT32_MIN;
int hard_value = INT32_MIN;
/* Read the table, and find all properties we care about */
sq_pushnull(vm);
@@ -124,9 +122,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
config.max_value = ClampTo<int32_t>(res);
items |= 0x008;
} else if (key == "easy_value") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
easy_value = ClampTo<int32_t>(res);
// No longer parsed.
items |= 0x010;
} else if (key == "medium_value") {
SQInteger res;
@@ -134,9 +130,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
medium_value = ClampTo<int32_t>(res);
items |= 0x020;
} else if (key == "hard_value") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
hard_value = ClampTo<int32_t>(res);
// No longer parsed.
items |= 0x040;
} else if (key == "custom_value") {
// No longer parsed.
@@ -146,10 +140,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
config.default_value = ClampTo<int32_t>(res);
items |= 0x080;
} else if (key == "random_deviation") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
config.random_deviation = ClampTo<int32_t>(abs(res));
items |= 0x200;
// No longer parsed.
} else if (key == "step_size") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
@@ -179,27 +170,12 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
}
config.default_value = medium_value;
/* If not boolean and no random deviation set, calculate it based on easy/hard difference. */
if ((config.flags & SCRIPTCONFIG_BOOLEAN) == 0 && (items & 0x200) == 0) {
config.random_deviation = abs(hard_value - easy_value) / 2;
items |= 0x200;
}
items |= 0x080;
} else {
/* For compatibility, also act like the default sets the easy/medium/hard. */
items |= 0x010 | 0x020 | 0x040;
}
/* Don't allow both random_deviation and SCRIPTCONFIG_BOOLEAN to
* be set for the same config item. */
if ((items & 0x200) != 0 && (config.flags & SCRIPTCONFIG_BOOLEAN) != 0) {
this->engine->ThrowError("setting both random_deviation and CONFIG_BOOLEAN is not allowed");
return SQ_ERROR;
}
/* Reset the bit for random_deviation as it's optional. */
items &= ~0x200;
/* Make sure all properties are defined */
uint mask = (config.flags & SCRIPTCONFIG_BOOLEAN) ? 0x1F3 : 0x1FF;
if (items != mask) {