diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -788,6 +788,8 @@
+
+
diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -1587,6 +1587,12 @@
MD5
+
+ Script
+
+
+ Script
+
Script
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -2459,6 +2459,14 @@
Name="Script"
>
+
+
+
+
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -2456,6 +2456,14 @@
Name="Script"
>
+
+
+
+
diff --git a/source.list b/source.list
--- a/source.list
+++ b/source.list
@@ -553,6 +553,8 @@ 3rdparty/md5/md5.h
#if AI
# Script
+script/script_config.cpp
+script/script_config.hpp
script/script_fatalerror.hpp
script/script_info.cpp
script/script_info.hpp
diff --git a/src/ai/ai_config.cpp b/src/ai/ai_config.cpp
--- a/src/ai/ai_config.cpp
+++ b/src/ai/ai_config.cpp
@@ -14,87 +14,28 @@
#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();
- }
-}
+#include "ai_info.hpp"
-AIConfig::AIConfig(const AIConfig *config)
-{
- 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;
- }
- this->AddRandomDeviation();
-}
-
-AIConfig::~AIConfig()
-{
- free(this->name);
- this->ResetSettings();
- if (this->config_list != NULL) delete this->config_list;
-}
+/** 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
+};
-AIInfo *AIConfig::GetInfo() const
-{
- return this->info;
-}
-
-bool AIConfig::ResetInfo(bool force_exact_match)
-{
- this->info = AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match);
- return this->info != NULL;
-}
-
-const AIConfigItemList *AIConfig::GetConfigList()
-{
- 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;
-}
-
-AIConfig *AIConfig::GetConfig(CompanyID company, AISettingSource source)
+/* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source)
{
AIConfig **config;
- if (source == AISS_FORCE_NEWGAME || (source == AISS_DEFAULT && _game_mode == GM_MENU)) {
+ 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];
@@ -103,12 +44,43 @@ AIConfig *AIConfig::GetConfig(CompanyID
return *config;
}
+class AIInfo *AIConfig::GetInfo() const
+{
+ return static_cast(ScriptConfig::GetInfo());
+}
+
+ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match)
+{
+ return static_cast(AI::FindInfo(name, version, force_exact_match));
+}
+
+bool AIConfig::ResetInfo(bool force_exact_match)
+{
+ this->info = (ScriptInfo *)AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match);
+ return this->info != NULL;
+}
+
+void AIConfig::PushExtraConfigList()
+{
+ this->config_list->push_back(_start_date_config);
+}
+
+void AIConfig::ClearConfigList()
+{
+ /* 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 *nam
default: NOT_REACHED();
}
}
- return this->info->GetSettingDefaultValue(name);
+
+ return (*it).second;
}
- return (*it).second;
+
+ return ScriptConfig::GetSetting(name);
}
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) {
+ if (this->info == NULL) {
+ if (strcmp("start_date", name) != 0) return;
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;
}
- SettingValueList::iterator it = this->settings.find(name);
- if (it != this->settings.end()) {
- (*it).second = value;
- } else {
- this->settings[strdup(name)] = value;
- }
-}
-
-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));
- }
- }
-}
-
-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
-{
- return this->version;
+ ScriptConfig::SetSetting(name, value);
}
-
-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++;
- }
-
- this->SetSetting(item_name, atoi(item_value));
- }
- 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';
-}
diff --git a/src/ai/ai_config.hpp b/src/ai/ai_config.hpp
--- 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