From 34d7f01cccfbb4dcd09f0b68ded513f495fa69ed Mon Sep 17 00:00:00 2001 From: truebrain Date: Tue, 29 Nov 2011 23:26:35 +0000 Subject: (svn r23364) -Codechange: refactor AIConfig, moving it mostly to Scriptconfig --- src/ai/ai_config.cpp | 229 +++++++++++------------------------------ src/ai/ai_config.hpp | 141 ++++--------------------- src/ai/ai_core.cpp | 13 +-- src/ai/ai_gui.cpp | 29 +++--- src/ai/ai_info.cpp | 243 +++----------------------------------------- src/ai/ai_info.hpp | 71 +------------ src/ai/ai_instance.cpp | 1 + src/ai/api/ai_changelog.hpp | 6 +- 8 files changed, 120 insertions(+), 613 deletions(-) (limited to 'src/ai') diff --git a/src/ai/ai_config.cpp b/src/ai/ai_config.cpp index a5d656911..3f6b3c31b 100644 --- a/src/ai/ai_config.cpp +++ b/src/ai/ai_config.cpp @@ -14,101 +14,73 @@ #include "../core/random_func.hpp" #include "ai.hpp" #include "ai_config.hpp" - -void AIConfig::ChangeAI(const char *name, int version, bool force_exact_match, bool is_random_ai) -{ - free(this->name); - this->name = (name == NULL) ? NULL : strdup(name); - this->info = (name == NULL) ? NULL : AI::FindInfo(this->name, version, force_exact_match); - this->version = (info == NULL) ? -1 : info->GetVersion(); - this->is_random_ai = is_random_ai; - if (this->config_list != NULL) delete this->config_list; - this->config_list = (info == NULL) ? NULL : new AIConfigItemList(); - if (this->config_list != NULL) this->config_list->push_back(_start_date_config); - - /* The special casing for start_date is here to ensure that the - * start_date setting won't change even if you chose another AI. */ - int start_date = this->GetSetting("start_date"); - - for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) { - free((*it).first); - } - this->settings.clear(); - - this->SetSetting("start_date", start_date); - - if (_game_mode == GM_NORMAL && this->info != NULL) { - /* If we're in an existing game and the AI is changed, set all settings - * for the AI that have the random flag to a random value. */ - for (AIConfigItemList::const_iterator it = this->info->GetConfigList()->begin(); it != this->info->GetConfigList()->end(); it++) { - if ((*it).flags & AICONFIG_RANDOM) { - this->SetSetting((*it).name, InteractiveRandomRange((*it).max_value - (*it).min_value) + (*it).min_value); - } - } - this->AddRandomDeviation(); - } -} - -AIConfig::AIConfig(const AIConfig *config) +#include "ai_info.hpp" + +/** Configuration for AI start date, every AI has this setting. */ +ScriptConfigItem _start_date_config = { + "start_date", + "Number of days to start this AI after the previous one (give or take)", + AI::START_NEXT_MIN, + AI::START_NEXT_MAX, + AI::START_NEXT_MEDIUM, + AI::START_NEXT_EASY, + AI::START_NEXT_MEDIUM, + AI::START_NEXT_HARD, + AI::START_NEXT_DEVIATION, + 30, + SCRIPTCONFIG_NONE, + NULL +}; + +/* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source) { - this->name = (config->name == NULL) ? NULL : strdup(config->name); - this->info = config->info; - this->version = config->version; - this->config_list = NULL; - this->is_random_ai = config->is_random_ai; - - for (SettingValueList::const_iterator it = config->settings.begin(); it != config->settings.end(); it++) { - this->settings[strdup((*it).first)] = (*it).second; + AIConfig **config; + if (source == SSS_FORCE_NEWGAME || (source == SSS_DEFAULT && _game_mode == GM_MENU)) { + config = &_settings_newgame.ai_config[company]; + } else { + config = &_settings_game.ai_config[company]; } - this->AddRandomDeviation(); + if (*config == NULL) *config = new AIConfig(); + return *config; } -AIConfig::~AIConfig() +class AIInfo *AIConfig::GetInfo() const { - free(this->name); - this->ResetSettings(); - if (this->config_list != NULL) delete this->config_list; + return static_cast(ScriptConfig::GetInfo()); } -AIInfo *AIConfig::GetInfo() const +ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match) { - return this->info; + return static_cast(AI::FindInfo(name, version, force_exact_match)); } bool AIConfig::ResetInfo(bool force_exact_match) { - this->info = AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); + this->info = (ScriptInfo *)AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); return this->info != NULL; } -const AIConfigItemList *AIConfig::GetConfigList() +void AIConfig::PushExtraConfigList() { - if (this->info != NULL) return this->info->GetConfigList(); - if (this->config_list == NULL) { - this->config_list = new AIConfigItemList(); - this->config_list->push_back(_start_date_config); - } - return this->config_list; + this->config_list->push_back(_start_date_config); } -AIConfig *AIConfig::GetConfig(CompanyID company, AISettingSource source) +void AIConfig::ClearConfigList() { - AIConfig **config; - if (source == AISS_FORCE_NEWGAME || (source == AISS_DEFAULT && _game_mode == GM_MENU)) { - config = &_settings_newgame.ai_config[company]; - } else { - config = &_settings_game.ai_config[company]; - } - if (*config == NULL) *config = new AIConfig(); - return *config; + /* The special casing for start_date is here to ensure that the + * start_date setting won't change even if you chose another Script. */ + int start_date = this->GetSetting("start_date"); + + ScriptConfig::ClearConfigList(); + + this->SetSetting("start_date", start_date); } int AIConfig::GetSetting(const char *name) const { - SettingValueList::const_iterator it = this->settings.find(name); - /* Return the default value if the setting is not set, or if we are in a not-custom difficult level */ - if (it == this->settings.end() || GetGameSettings().difficulty.diff_level != 3) { - if (this->info == NULL) { + if (this->info == NULL) { + SettingValueList::const_iterator it = this->settings.find(name); + if (it == this->settings.end() || GetGameSettings().difficulty.diff_level != 3) { assert(strcmp("start_date", name) == 0); switch (GetGameSettings().difficulty.diff_level) { case 0: return AI::START_NEXT_EASY; @@ -118,115 +90,28 @@ int AIConfig::GetSetting(const char *name) const default: NOT_REACHED(); } } - return this->info->GetSettingDefaultValue(name); - } - return (*it).second; -} - -void AIConfig::SetSetting(const char *name, int value) -{ - /* You can only set ai specific settings if an AI is selected. */ - if (this->info == NULL && strcmp("start_date", name) != 0) return; - - if (this->info == NULL && strcmp("start_date", name) == 0) { - value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX); - } else { - const AIConfigItem *config_item = this->info->GetConfigItem(name); - if (config_item == NULL) return; - - value = Clamp(value, config_item->min_value, config_item->max_value); - } - SettingValueList::iterator it = this->settings.find(name); - if (it != this->settings.end()) { - (*it).second = value; - } else { - this->settings[strdup(name)] = value; + return (*it).second; } -} -void AIConfig::ResetSettings() -{ - for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) { - free((*it).first); - } - this->settings.clear(); -} - -void AIConfig::AddRandomDeviation() -{ - for (AIConfigItemList::const_iterator it = this->GetConfigList()->begin(); it != this->GetConfigList()->end(); it++) { - if ((*it).random_deviation != 0) { - this->SetSetting((*it).name, InteractiveRandomRange((*it).random_deviation * 2) - (*it).random_deviation + this->GetSetting((*it).name)); - } - } + return ScriptConfig::GetSetting(name); } -bool AIConfig::HasAI() const -{ - return this->info != NULL; -} - -bool AIConfig::IsRandomAI() const -{ - return this->is_random_ai; -} - -const char *AIConfig::GetName() const -{ - return this->name; -} - -int AIConfig::GetVersion() const +void AIConfig::SetSetting(const char *name, int value) { - return this->version; -} + if (this->info == NULL) { + if (strcmp("start_date", name) != 0) return; + value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX); -void AIConfig::StringToSettings(const char *value) -{ - char *value_copy = strdup(value); - char *s = value_copy; - - while (s != NULL) { - /* Analyze the string ('name=value,name=value\0') */ - char *item_name = s; - s = strchr(s, '='); - if (s == NULL) break; - if (*s == '\0') break; - *s = '\0'; - s++; - - char *item_value = s; - s = strchr(s, ','); - if (s != NULL) { - *s = '\0'; - s++; + SettingValueList::iterator it = this->settings.find(name); + if (it != this->settings.end()) { + (*it).second = value; + } else { + this->settings[strdup(name)] = value; } - this->SetSetting(item_name, atoi(item_value)); + return; } - free(value_copy); -} -void AIConfig::SettingsToString(char *string, size_t size) const -{ - string[0] = '\0'; - for (SettingValueList::const_iterator it = this->settings.begin(); it != this->settings.end(); it++) { - char no[10]; - snprintf(no, sizeof(no), "%d", (*it).second); - - /* Check if the string would fit in the destination */ - size_t needed_size = strlen((*it).first) + 1 + strlen(no) + 1; - /* If it doesn't fit, skip the next settings */ - if (size <= needed_size) break; - size -= needed_size; - - strcat(string, (*it).first); - strcat(string, "="); - strcat(string, no); - strcat(string, ","); - } - /* Remove the last ',', but only if at least one setting was saved. */ - size_t len = strlen(string); - if (len > 0) string[len - 1] = '\0'; + ScriptConfig::SetSetting(name, value); } diff --git a/src/ai/ai_config.hpp b/src/ai/ai_config.hpp index 3ed06d346..1e738d14b 100644 --- a/src/ai/ai_config.hpp +++ b/src/ai/ai_config.hpp @@ -11,48 +11,28 @@ #ifndef AI_CONFIG_HPP #define AI_CONFIG_HPP -#ifdef ENABLE_AI -#include -#include "ai_info.hpp" -#include "../core/string_compare_type.hpp" -#include "../company_type.h" - -/** - * AI settings for one company slot. - */ -class AIConfig { -private: - /** List with name=>value pairs of all AI-specific settings */ - typedef std::map SettingValueList; +#include "../script/script_config.hpp" +class AIConfig : public ScriptConfig { public: + /** + * Get the config of a company. + */ + static AIConfig *GetConfig(CompanyID company, ScriptSettingSource source = SSS_DEFAULT); + AIConfig() : - name(NULL), - version(-1), - info(NULL), - config_list(NULL), - is_random_ai(false) + ScriptConfig() {} - /** - * Create a new AI config that is a copy of an existing config. - * @param config The object to copy. - */ - AIConfig(const AIConfig *config); + AIConfig(const AIConfig *config) : + ScriptConfig(config) + {} - /** Delete an AI configuration. */ - ~AIConfig(); + class AIInfo *GetInfo() const; - /** - * Set another AI to be loaded in this slot. - * @param name The name of the AI. - * @param version The version of the AI to load, or -1 of latest. - * @param force_exact_match If true try to find the exact same version - * as specified. If false any compatible version is ok. - * @param is_random Is the AI chosen randomly? - */ - void ChangeAI(const char *name, int version = -1, bool force_exact_match = false, bool is_random = false); + /* virtual */ int GetSetting(const char *name) const; + /* virtual */ void SetSetting(const char *name, int value); /** * When ever the AI Scanner is reloaded, all infos become invalid. This @@ -64,95 +44,10 @@ public: */ bool ResetInfo(bool force_exact_match); - /** - * Get the AIInfo linked to this AIConfig. - */ - class AIInfo *GetInfo() const; - - /** - * Get the config list for this AIConfig. - */ - const AIConfigItemList *GetConfigList(); - - /** - * Where to get the config from, either default (depends on current game - * mode) or force either newgame or normal - */ - enum AISettingSource { - AISS_DEFAULT, ///< Get the AI config from the current game mode - AISS_FORCE_NEWGAME, ///< Get the newgame AI config - AISS_FORCE_GAME, ///< Get the AI config from the current game - }; - - /** - * Get the config of a company. - */ - static AIConfig *GetConfig(CompanyID company, AISettingSource source = AISS_DEFAULT); - - /** - * Get the value of a setting for this config. It might fallback to his - * 'info' to find the default value (if not set or if not-custom difficulty - * level). - * @return The (default) value of the setting, or -1 if the setting was not - * found. - */ - int GetSetting(const char *name) const; - - /** - * Set the value of a setting for this config. - */ - void SetSetting(const char *name, int value); - - /** - * Reset all settings to their default value. - */ - void ResetSettings(); - - /** - * Randomize all settings the AI requested to be randomized. - */ - void AddRandomDeviation(); - - /** - * Is this config attached to an AI? - */ - bool HasAI() const; - - /** - * Is the current AI a randomly chosen AI? - */ - bool IsRandomAI() const; - - /** - * Get the name of the AI. - */ - const char *GetName() const; - - /** - * Get the version of the AI. - */ - int GetVersion() const; - - /** - * Convert a string which is stored in the config file or savegames to - * custom settings of this AI. - */ - void StringToSettings(const char *value); - - /** - * Convert the custom settings to a string that can be stored in the config - * file or savegames. - */ - void SettingsToString(char *string, size_t size) const; - -private: - const char *name; ///< Name of the AI - int version; ///< Version of the AI - class AIInfo *info; ///< AIInfo object for related to this AI version - SettingValueList settings; ///< List with all setting=>value pairs that are configure for this AI - AIConfigItemList *config_list; ///< List with all settings defined by this AI - bool is_random_ai; ///< True if the AI in this slot was randomly chosen. +protected: + /* virtual */ void PushExtraConfigList(); + /* virtual */ void ClearConfigList(); + /* virtual */ ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match); }; -#endif /* ENABLE_AI */ #endif /* AI_CONFIG_HPP */ diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp index d6c0b7946..b314753d1 100644 --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -21,6 +21,7 @@ #include "ai_scanner.hpp" #include "ai_instance.hpp" #include "ai_config.hpp" +#include "ai_info.hpp" #include "ai.hpp" #include "../script/api/script_error.hpp" @@ -43,11 +44,11 @@ AIConfig *config = AIConfig::GetConfig(company); AIInfo *info = config->GetInfo(); - if (info == NULL || (rerandomise_ai && config->IsRandomAI())) { + if (info == NULL || (rerandomise_ai && config->IsRandom())) { info = AI::scanner_info->SelectRandomAI(); assert(info != NULL); /* Load default data and store the name in the settings */ - config->ChangeAI(info->GetName(), -1, false, true); + config->Change(info->GetName(), -1, false, true); } Backup cur_company(_current_company, company, FILE_LINE); @@ -181,10 +182,10 @@ * the AIConfig. If not, remove the AI from the list (which will assign * a random new AI on reload). */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - if (_settings_game.ai_config[c] != NULL && _settings_game.ai_config[c]->HasAI()) { + if (_settings_game.ai_config[c] != NULL && _settings_game.ai_config[c]->HasScript()) { if (!_settings_game.ai_config[c]->ResetInfo(true)) { DEBUG(ai, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName()); - _settings_game.ai_config[c]->ChangeAI(NULL); + _settings_game.ai_config[c]->Change(NULL); if (Company::IsValidAiID(c)) { /* The code belonging to an already running AI was deleted. We can only do * one thing here to keep everything sane and that is kill the AI. After @@ -198,10 +199,10 @@ Company::Get(c)->ai_info = _settings_game.ai_config[c]->GetInfo(); } } - if (_settings_newgame.ai_config[c] != NULL && _settings_newgame.ai_config[c]->HasAI()) { + if (_settings_newgame.ai_config[c] != NULL && _settings_newgame.ai_config[c]->HasScript()) { if (!_settings_newgame.ai_config[c]->ResetInfo(false)) { DEBUG(ai, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName()); - _settings_newgame.ai_config[c]->ChangeAI(NULL); + _settings_newgame.ai_config[c]->Change(NULL); } } } diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 2ef7d5db9..a71e018e9 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -28,6 +28,7 @@ #include "ai.hpp" #include "../script/api/script_log.hpp" #include "ai_config.hpp" +#include "ai_info.hpp" #include "ai_instance.hpp" #include "table/strings.h" @@ -71,7 +72,7 @@ struct AIListWindow : public Window { /* Try if we can find the currently selected AI */ this->selected = -1; - if (AIConfig::GetConfig(slot)->HasAI()) { + if (AIConfig::GetConfig(slot)->HasScript()) { AIInfo *info = AIConfig::GetConfig(slot)->GetInfo(); int i = 0; for (ScriptInfoList::const_iterator it = this->ai_info_list->begin(); it != this->ai_info_list->end(); it++, i++) { @@ -148,11 +149,11 @@ struct AIListWindow : public Window { void ChangeAI() { if (this->selected == -1) { - AIConfig::GetConfig(slot)->ChangeAI(NULL); + AIConfig::GetConfig(slot)->Change(NULL); } else { ScriptInfoList::const_iterator it = this->ai_info_list->begin(); for (int i = 0; i < this->selected; i++) it++; - AIConfig::GetConfig(slot)->ChangeAI((*it).second->GetName(), (*it).second->GetVersion()); + AIConfig::GetConfig(slot)->Change((*it).second->GetName(), (*it).second->GetVersion()); } SetWindowDirty(WC_GAME_OPTIONS, 0); } @@ -272,7 +273,7 @@ struct AISettingsWindow : public Window { int clicked_row; ///< The clicked row of settings. int line_height; ///< Height of a row in the matrix widget. Scrollbar *vscroll; ///< Cache of the vertical scrollbar. - typedef std::vector VisibleSettingsList; + typedef std::vector VisibleSettingsList; VisibleSettingsList visible_settings; ///< List of visible AI settings /** @@ -306,9 +307,9 @@ struct AISettingsWindow : public Window { { visible_settings.clear(); - AIConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); + ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); for (; it != this->ai_config->GetConfigList()->end(); it++) { - bool no_hide = (it->flags & AICONFIG_AI_DEVELOPER) == 0; + bool no_hide = (it->flags & SCRIPTCONFIG_DEVELOPER) == 0; if (no_hide || _settings_client.gui.ai_developer_tools) { visible_settings.push_back(&(*it)); } @@ -343,9 +344,9 @@ struct AISettingsWindow : public Window { int y = r.top; for (; this->vscroll->IsVisible(i) && it != visible_settings.end(); i++, it++) { - const AIConfigItem &config_item = **it; + const ScriptConfigItem &config_item = **it; int current_value = config->GetSetting((config_item).name); - bool editable = _game_mode == GM_MENU || !Company::IsValidID(this->slot) || (config_item.flags & AICONFIG_INGAME) != 0; + bool editable = _game_mode == GM_MENU || !Company::IsValidID(this->slot) || (config_item.flags & SCRIPTCONFIG_INGAME) != 0; StringID str; TextColour colour; @@ -359,7 +360,7 @@ struct AISettingsWindow : public Window { SetDParamStr(idx++, config_item.description); } - if ((config_item.flags & AICONFIG_BOOLEAN) != 0) { + if ((config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0) { DrawFrameRect(buttons_left, y + 2, buttons_left + 19, y + 10, (current_value != 0) ? COLOUR_GREEN : COLOUR_RED, (current_value != 0) ? FR_LOWERED : FR_NONE); SetDParam(idx++, current_value == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON); } else { @@ -403,10 +404,10 @@ struct AISettingsWindow : public Window { VisibleSettingsList::const_iterator it = this->visible_settings.begin(); for (int i = 0; i < num; i++) it++; - const AIConfigItem config_item = **it; - if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot) && (config_item.flags & AICONFIG_INGAME) == 0) return; + const ScriptConfigItem config_item = **it; + if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return; - bool bool_item = (config_item.flags & AICONFIG_BOOLEAN) != 0; + bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0; int x = pt.x - wid->pos_x; if (_current_text_dir == TD_RTL) x = wid->current_x - x; @@ -462,9 +463,9 @@ struct AISettingsWindow : public Window { virtual void OnQueryTextFinished(char *str) { if (StrEmpty(str)) return; - AIConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); + ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); for (int i = 0; i < this->clicked_row; i++) it++; - if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot) && (it->flags & AICONFIG_INGAME) == 0) return; + if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot) && (it->flags & SCRIPTCONFIG_INGAME) == 0) return; int32 value = atoi(str); this->ai_config->SetSetting((*it).name, value); this->CheckDifficultyLevel(); diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp index a56064e01..d43ff8f7d 100644 --- a/src/ai/ai_info.cpp +++ b/src/ai/ai_info.cpp @@ -23,22 +23,6 @@ /** Maximum number of operations allowed for getting a particular setting. */ static const int MAX_GET_SETTING_OPS = 100000; -/** Configuration for AI start date, every AI has this setting. */ -AIConfigItem _start_date_config = { - "start_date", - "Number of days to start this AI after the previous one (give or take)", - AI::START_NEXT_MIN, - AI::START_NEXT_MAX, - AI::START_NEXT_MEDIUM, - AI::START_NEXT_EASY, - AI::START_NEXT_MEDIUM, - AI::START_NEXT_HARD, - AI::START_NEXT_DEVIATION, - 30, - AICONFIG_NONE, - NULL -}; - /** * Check if the API version provided by the AI is supported. * @param api_version The API version as provided by the AI. @@ -61,11 +45,18 @@ template <> const char *GetClassName() { return "AIInfo"; } SQAIInfo.AddConstructor(engine, "x"); SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting"); SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels"); - SQAIInfo.DefSQConst(engine, AICONFIG_NONE, "AICONFIG_NONE"); - SQAIInfo.DefSQConst(engine, AICONFIG_RANDOM, "AICONFIG_RANDOM"); - SQAIInfo.DefSQConst(engine, AICONFIG_BOOLEAN, "AICONFIG_BOOLEAN"); - SQAIInfo.DefSQConst(engine, AICONFIG_INGAME, "AICONFIG_INGAME"); - SQAIInfo.DefSQConst(engine, AICONFIG_AI_DEVELOPER, "AICONFIG_AI_DEVELOPER"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER"); + + /* Pre 1.2 had an AI prefix */ + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "AICONFIG_NONE"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "AICONFIG_RANDOM"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "AICONFIG_BOOLEAN"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "AICONFIG_INGAME"); + SQAIInfo.PostRegister(engine); engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx"); engine->AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, 2, "tx"); @@ -81,15 +72,11 @@ template <> const char *GetClassName() { return "AIInfo"; } SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; - AIConfigItem config = _start_date_config; + ScriptConfigItem config = _start_date_config; config.name = strdup(config.name); config.description = strdup(config.description); - info->config_list.push_back(config); + info->config_list.push_front(config); - /* Check if we have settings */ - if (info->engine->MethodExists(*info->SQ_instance, "GetSettings")) { - if (!info->GetSettings()) return SQ_ERROR; - } if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) { if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_SETTING_OPS)) return SQ_ERROR; } else { @@ -141,11 +128,6 @@ template <> const char *GetClassName() { return "AIInfo"; } return 0; } -bool AIInfo::GetSettings() -{ - return this->engine->CallMethod(*this->SQ_instance, "GetSettings", NULL, MAX_GET_SETTING_OPS); -} - AIInfo::AIInfo() : min_loadable_version(0), use_as_random(false), @@ -155,18 +137,6 @@ AIInfo::AIInfo() : AIInfo::~AIInfo() { - /* Free all allocated strings */ - for (AIConfigItemList::iterator it = this->config_list.begin(); it != this->config_list.end(); it++) { - free((*it).name); - free((*it).description); - if (it->labels != NULL) { - for (LabelMapping::iterator it2 = (*it).labels->Begin(); it2 != (*it).labels->End(); it2++) { - free(it2->second); - } - delete it->labels; - } - } - this->config_list.clear(); free(this->api_version); } @@ -176,191 +146,6 @@ bool AIInfo::CanLoadFromVersion(int version) const return version >= this->min_loadable_version && version <= this->GetVersion(); } -SQInteger AIInfo::AddSetting(HSQUIRRELVM vm) -{ - AIConfigItem config; - memset(&config, 0, sizeof(config)); - config.max_value = 1; - config.step_size = 1; - uint items = 0; - - /* Read the table, and find all properties we care about */ - sq_pushnull(vm); - while (SQ_SUCCEEDED(sq_next(vm, -2))) { - const SQChar *sqkey; - if (SQ_FAILED(sq_getstring(vm, -2, &sqkey))) return SQ_ERROR; - const char *key = SQ2OTTD(sqkey); - - if (strcmp(key, "name") == 0) { - const SQChar *sqvalue; - if (SQ_FAILED(sq_getstring(vm, -1, &sqvalue))) return SQ_ERROR; - char *name = strdup(SQ2OTTD(sqvalue)); - char *s; - /* Don't allow '=' and ',' in configure setting names, as we need those - * 2 chars to nicely store the settings as a string. */ - while ((s = strchr(name, '=')) != NULL) *s = '_'; - while ((s = strchr(name, ',')) != NULL) *s = '_'; - config.name = name; - items |= 0x001; - } else if (strcmp(key, "description") == 0) { - const SQChar *sqdescription; - if (SQ_FAILED(sq_getstring(vm, -1, &sqdescription))) return SQ_ERROR; - config.description = strdup(SQ2OTTD(sqdescription)); - items |= 0x002; - } else if (strcmp(key, "min_value") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.min_value = res; - items |= 0x004; - } else if (strcmp(key, "max_value") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.max_value = res; - items |= 0x008; - } else if (strcmp(key, "easy_value") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.easy_value = res; - items |= 0x010; - } else if (strcmp(key, "medium_value") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.medium_value = res; - items |= 0x020; - } else if (strcmp(key, "hard_value") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.hard_value = res; - items |= 0x040; - } else if (strcmp(key, "random_deviation") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.random_deviation = res; - items |= 0x200; - } else if (strcmp(key, "custom_value") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.custom_value = res; - items |= 0x080; - } else if (strcmp(key, "step_size") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.step_size = res; - } else if (strcmp(key, "flags") == 0) { - SQInteger res; - if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; - config.flags = (AIConfigFlags)res; - items |= 0x100; - } else { - char error[1024]; - snprintf(error, sizeof(error), "unknown setting property '%s'", key); - this->engine->ThrowError(error); - return SQ_ERROR; - } - - sq_pop(vm, 2); - } - sq_pop(vm, 1); - - /* Don't allow both random_deviation and AICONFIG_RANDOM to - * be set for the same config item. */ - if ((items & 0x200) != 0 && (config.flags & AICONFIG_RANDOM) != 0) { - char error[1024]; - snprintf(error, sizeof(error), "Setting both random_deviation and AICONFIG_RANDOM is not allowed"); - this->engine->ThrowError(error); - 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 & AICONFIG_BOOLEAN) ? 0x1F3 : 0x1FF; - if (items != mask) { - char error[1024]; - snprintf(error, sizeof(error), "please define all properties of a setting (min/max not allowed for booleans)"); - this->engine->ThrowError(error); - return SQ_ERROR; - } - - this->config_list.push_back(config); - return 0; -} - -SQInteger AIInfo::AddLabels(HSQUIRRELVM vm) -{ - const SQChar *sq_setting_name; - if (SQ_FAILED(sq_getstring(vm, -2, &sq_setting_name))) return SQ_ERROR; - const char *setting_name = SQ2OTTD(sq_setting_name); - - AIConfigItem *config = NULL; - for (AIConfigItemList::iterator it = this->config_list.begin(); it != this->config_list.end(); it++) { - if (strcmp((*it).name, setting_name) == 0) config = &(*it); - } - - if (config == NULL) { - char error[1024]; - snprintf(error, sizeof(error), "Trying to add labels for non-defined setting '%s'", setting_name); - this->engine->ThrowError(error); - return SQ_ERROR; - } - if (config->labels != NULL) return SQ_ERROR; - - config->labels = new LabelMapping; - - /* Read the table and find all labels */ - sq_pushnull(vm); - while (SQ_SUCCEEDED(sq_next(vm, -2))) { - const SQChar *sq_key; - const SQChar *sq_label; - if (SQ_FAILED(sq_getstring(vm, -2, &sq_key))) return SQ_ERROR; - if (SQ_FAILED(sq_getstring(vm, -1, &sq_label))) return SQ_ERROR; - /* Because squirrel doesn't support identifiers starting with a digit, - * we skip the first character. */ - const char *key_string = SQ2OTTD(sq_key); - int key = atoi(key_string + 1); - const char *label = SQ2OTTD(sq_label); - - /* !Contains() prevents strdup from leaking. */ - if (!config->labels->Contains(key)) config->labels->Insert(key, strdup(label)); - - sq_pop(vm, 2); - } - sq_pop(vm, 1); - - return 0; -} - -const AIConfigItemList *AIInfo::GetConfigList() const -{ - return &this->config_list; -} - -const AIConfigItem *AIInfo::GetConfigItem(const char *name) const -{ - for (AIConfigItemList::const_iterator it = this->config_list.begin(); it != this->config_list.end(); it++) { - if (strcmp((*it).name, name) == 0) return &(*it); - } - return NULL; -} - -int AIInfo::GetSettingDefaultValue(const char *name) const -{ - for (AIConfigItemList::const_iterator it = this->config_list.begin(); it != this->config_list.end(); it++) { - if (strcmp((*it).name, name) != 0) continue; - /* The default value depends on the difficulty level */ - switch (GetGameSettings().difficulty.diff_level) { - case 0: return (*it).easy_value; - case 1: return (*it).medium_value; - case 2: return (*it).hard_value; - case 3: return (*it).custom_value; - default: NOT_REACHED(); - } - } - - /* There is no such setting */ - return -1; -} - AILibrary::~AILibrary() { diff --git a/src/ai/ai_info.hpp b/src/ai/ai_info.hpp index 82ca6f925..924ddd2e0 100644 --- a/src/ai/ai_info.hpp +++ b/src/ai/ai_info.hpp @@ -14,40 +14,8 @@ #ifdef ENABLE_AI -#include -#include "../core/smallmap_type.hpp" #include "../script/script_info.hpp" - -/** Bitmask of flags for AI settings. */ -enum AIConfigFlags { - AICONFIG_NONE = 0x0, ///< No flags set. - AICONFIG_RANDOM = 0x1, ///< When randomizing the AI, pick any value between min_value and max_value when on custom difficulty setting. - AICONFIG_BOOLEAN = 0x2, ///< This value is a boolean (either 0 (false) or 1 (true) ). - AICONFIG_INGAME = 0x4, ///< This setting can be changed while the AI is running. - AICONFIG_AI_DEVELOPER = 0x8, ///< This setting will only be visible when the ai development tools are active. -}; - -typedef SmallMap LabelMapping; ///< Map-type used to map the setting numbers to labels. - -/** Info about a single AI setting. */ -struct AIConfigItem { - const char *name; ///< The name of the configuration setting. - const char *description; ///< The description of the configuration setting. - int min_value; ///< The minimal value this configuration setting can have. - int max_value; ///< The maximal value this configuration setting can have. - int custom_value; ///< The default value on custom difficulty setting. - int easy_value; ///< The default value on easy difficulty setting. - int medium_value; ///< The default value on medium difficulty setting. - int hard_value; ///< The default value on hard difficulty setting. - int random_deviation; ///< The maximum random deviation from the default value. - int step_size; ///< The step size in the gui. - AIConfigFlags flags; ///< Flags for the configuration setting. - LabelMapping *labels; ///< Text labels for the integer values. -}; - -extern AIConfigItem _start_date_config; - -typedef std::list AIConfigItemList; ///< List of AIConfig items. +#include "../script/script_config.hpp" /** All static information from an AI like name, version, etc. */ class AIInfo : public ScriptInfo { @@ -70,41 +38,11 @@ public: */ static SQInteger DummyConstructor(HSQUIRRELVM vm); - /** - * Get the settings of the AI. - */ - bool GetSettings(); - - /** - * Get the config list for this AI. - */ - const AIConfigItemList *GetConfigList() const; - - /** - * Get the description of a certain ai config option. - */ - const AIConfigItem *GetConfigItem(const char *name) const; - /** * Check if we can start this AI. */ bool CanLoadFromVersion(int version) const; - /** - * Set a setting. - */ - SQInteger AddSetting(HSQUIRRELVM vm); - - /** - * Add labels for a setting. - */ - SQInteger AddLabels(HSQUIRRELVM vm); - - /** - * Get the default value for a setting. - */ - int GetSettingDefaultValue(const char *name) const; - /** * Use this AI as a random AI. */ @@ -116,10 +54,9 @@ public: const char *GetAPIVersion() const { return this->api_version; } private: - AIConfigItemList config_list; ///< List of settings from this AI. - int min_loadable_version; ///< The AI can load savegame data if the version is equal or greater than this. - bool use_as_random; ///< Should this AI be used when the user wants a "random AI"? - const char *api_version; ///< API version used by this AI. + int min_loadable_version; ///< The AI can load savegame data if the version is equal or greater than this. + bool use_as_random; ///< Should this AI be used when the user wants a "random AI"? + const char *api_version; ///< API version used by this AI. }; /** All static information from an AI library like name, version, etc. */ diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 940ba4eb3..11459f649 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -22,6 +22,7 @@ #include "../script/script_fatalerror.hpp" #include "../script/script_suspend.hpp" #include "../script/script_storage.hpp" +#include "ai_info.hpp" #include "ai_instance.hpp" /* Convert all AI related classes to Squirrel data. diff --git a/src/ai/api/ai_changelog.hpp b/src/ai/api/ai_changelog.hpp index 8e6a2afb7..99d892497 100644 --- a/src/ai/api/ai_changelog.hpp +++ b/src/ai/api/ai_changelog.hpp @@ -31,7 +31,7 @@ * \li AICompany::GetQuarterlyPerformanceRating * \li AICompany::GetQuarterlyCompanyValue * \li AIController::GetOpsTillSuspend - * \li AIInfo::AICONFIG_AI_DEVELOPER + * \li AIInfo::CONFIG_DEVELOPER * \li AIOrder::GetOrderRefit * \li AIOrder::IsRefitOrder * \li AIOrder::SetOrderRefit @@ -44,7 +44,9 @@ * * API renames: * \li AITown::GetLastMonthTransported to AITown::GetLastMonthSupplied to better - * reflect what it does + * reflect what it does. + * \li AIInfo has all its configure settings renamed from AICONFIG to just CONFIG + * like CONFIG_RANDOM. * * API removals: * \li AICompany::GetCompanyValue, use AICompany::GetQuarterlyCompanyValue instead. -- cgit v1.2.3-54-g00ecf