Update to 14.0-beta1
This commit is contained in:
+4
-26
@@ -11,30 +11,13 @@
|
||||
#define AI_HPP
|
||||
|
||||
#include "../script/api/script_event_types.hpp"
|
||||
#include "../core/string_compare_type.hpp"
|
||||
#include "ai_scanner.hpp"
|
||||
#include <map>
|
||||
|
||||
/** A list that maps AI names to their AIInfo object. */
|
||||
typedef std::map<const char *, class ScriptInfo *, StringCompare> ScriptInfoList;
|
||||
|
||||
/**
|
||||
* Main AI class. Contains all functions needed to start, stop, save and load AIs.
|
||||
*/
|
||||
class AI {
|
||||
public:
|
||||
/**
|
||||
* The default months AIs start after each other.
|
||||
*/
|
||||
enum StartNext {
|
||||
START_NEXT_EASY = DAYS_IN_YEAR * 2,
|
||||
START_NEXT_MEDIUM = DAYS_IN_YEAR,
|
||||
START_NEXT_HARD = DAYS_IN_YEAR / 2,
|
||||
START_NEXT_MIN = 0,
|
||||
START_NEXT_MAX = 3600,
|
||||
START_NEXT_DEVIATION = 60,
|
||||
};
|
||||
|
||||
/**
|
||||
* Is it possible to start a new AI company?
|
||||
* @return True if a new AI company can be started.
|
||||
@@ -128,23 +111,18 @@ public:
|
||||
*/
|
||||
static void Save(CompanyID company);
|
||||
|
||||
/**
|
||||
* Get the number of days before the next AI should start.
|
||||
*/
|
||||
static int GetStartNextTime();
|
||||
|
||||
/** Wrapper function for AIScanner::GetAIConsoleList */
|
||||
static std::string GetConsoleList(bool newest_only = false);
|
||||
static void GetConsoleList(std::back_insert_iterator<std::string> &output_iterator, bool newest_only);
|
||||
/** Wrapper function for AIScanner::GetAIConsoleLibraryList */
|
||||
static std::string GetConsoleLibraryList();
|
||||
static void GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator);
|
||||
/** Wrapper function for AIScanner::GetAIInfoList */
|
||||
static const ScriptInfoList *GetInfoList();
|
||||
/** Wrapper function for AIScanner::GetUniqueAIInfoList */
|
||||
static const ScriptInfoList *GetUniqueInfoList();
|
||||
/** Wrapper function for AIScanner::FindInfo */
|
||||
static class AIInfo *FindInfo(const char *name, int version, bool force_exact_match);
|
||||
static class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
/** Wrapper function for AIScanner::FindLibrary */
|
||||
static class AILibrary *FindLibrary(const char *library, int version);
|
||||
static class AILibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
/**
|
||||
* Rescans all searchpaths for available AIs. If a used AI is no longer
|
||||
|
||||
+3
-94
@@ -16,34 +16,10 @@
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/** Configuration for AI start date, every AI has this setting. */
|
||||
ScriptConfigItem _start_date_config = {
|
||||
"start_date",
|
||||
"", // STR_AI_SETTINGS_START_DELAY
|
||||
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,
|
||||
nullptr,
|
||||
false
|
||||
};
|
||||
|
||||
AIConfig::AIConfig(const AIConfig *config) : ScriptConfig(config)
|
||||
{
|
||||
/* Override start_date as per AIConfig::AddRandomDeviation().
|
||||
* This is necessary because the ScriptConfig constructor will instead call
|
||||
* ScriptConfig::AddRandomDeviation(). */
|
||||
int start_date = config->GetSetting("start_date");
|
||||
this->SetSetting("start_date", start_date != 0 ? std::max(1, this->GetSetting("start_date")) : 0);
|
||||
}
|
||||
|
||||
/* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source)
|
||||
{
|
||||
assert(company < MAX_COMPANIES);
|
||||
|
||||
AIConfig **config;
|
||||
if (source == SSS_FORCE_NEWGAME || (source == SSS_DEFAULT && _game_mode == GM_MENU)) {
|
||||
config = &_settings_newgame.ai_config[company];
|
||||
@@ -59,7 +35,7 @@ class AIInfo *AIConfig::GetInfo() const
|
||||
return static_cast<class AIInfo *>(ScriptConfig::GetInfo());
|
||||
}
|
||||
|
||||
ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
ScriptInfo *AIConfig::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return static_cast<ScriptInfo *>(AI::FindInfo(name, version, force_exact_match));
|
||||
}
|
||||
@@ -69,70 +45,3 @@ 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 != nullptr;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (this->info == nullptr) {
|
||||
SettingValueList::const_iterator it = this->settings.find(name);
|
||||
if (it == this->settings.end()) {
|
||||
assert(strcmp("start_date", name) == 0);
|
||||
switch (GetGameSettings().script.settings_profile) {
|
||||
case SP_EASY: return AI::START_NEXT_EASY;
|
||||
case SP_MEDIUM: return AI::START_NEXT_MEDIUM;
|
||||
case SP_HARD: return AI::START_NEXT_HARD;
|
||||
case SP_CUSTOM: return AI::START_NEXT_MEDIUM;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
return ScriptConfig::GetSetting(name);
|
||||
}
|
||||
|
||||
void AIConfig::SetSetting(const char *name, int value)
|
||||
{
|
||||
if (this->info == nullptr) {
|
||||
if (strcmp("start_date", name) != 0) return;
|
||||
value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX);
|
||||
|
||||
SettingValueList::iterator it = this->settings.find(name);
|
||||
if (it != this->settings.end()) {
|
||||
(*it).second = value;
|
||||
} else {
|
||||
this->settings[stredup(name)] = value;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptConfig::SetSetting(name, value);
|
||||
}
|
||||
|
||||
void AIConfig::AddRandomDeviation()
|
||||
{
|
||||
int start_date = this->GetSetting("start_date");
|
||||
|
||||
ScriptConfig::AddRandomDeviation();
|
||||
|
||||
/* start_date = 0 is a special case, where random deviation does not occur.
|
||||
* If start_date was not already 0, then a minimum value of 1 must apply. */
|
||||
this->SetSetting("start_date", start_date != 0 ? std::max(1, this->GetSetting("start_date")) : 0);
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@ public:
|
||||
ScriptConfig()
|
||||
{}
|
||||
|
||||
AIConfig(const AIConfig *config);
|
||||
AIConfig(const AIConfig *config) :
|
||||
ScriptConfig(config)
|
||||
{}
|
||||
|
||||
class AIInfo *GetInfo() const;
|
||||
|
||||
int GetSetting(const char *name) const override;
|
||||
void SetSetting(const char *name, int value) override;
|
||||
void AddRandomDeviation() override;
|
||||
|
||||
/**
|
||||
* When ever the AI Scanner is reloaded, all infos become invalid. This
|
||||
* function tells AIConfig about this.
|
||||
@@ -43,9 +41,7 @@ public:
|
||||
bool ResetInfo(bool force_exact_match);
|
||||
|
||||
protected:
|
||||
void PushExtraConfigList() override;
|
||||
void ClearConfigList() override;
|
||||
ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override;
|
||||
ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) override;
|
||||
};
|
||||
|
||||
#endif /* AI_CONFIG_HPP */
|
||||
|
||||
+20
-32
@@ -48,6 +48,7 @@
|
||||
/* Load default data and store the name in the settings */
|
||||
config->Change(info->GetName(), -1, false, true);
|
||||
}
|
||||
if (rerandomise_ai) config->AddRandomDeviation();
|
||||
config->AnchorUnchangeableSettings();
|
||||
|
||||
Backup<CompanyID> cur_company(_current_company, company, FILE_LINE);
|
||||
@@ -62,7 +63,7 @@
|
||||
|
||||
cur_company.Restore();
|
||||
|
||||
InvalidateWindowData(WC_AI_DEBUG, 0, -1);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,18 +83,16 @@
|
||||
PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index));
|
||||
cur_company.Change(c->index);
|
||||
c->ai_instance->GameLoop();
|
||||
/* Occasionally collect garbage; every 255 ticks do one company.
|
||||
* Effectively collecting garbage once every two months per AI. */
|
||||
if ((AI::frame_counter & 255) == 0 && (CompanyID)GB(AI::frame_counter, 8, 4) == c->index) {
|
||||
c->ai_instance->CollectGarbage();
|
||||
}
|
||||
} else {
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + c->index));
|
||||
}
|
||||
}
|
||||
cur_company.Restore();
|
||||
|
||||
/* Occasionally collect garbage; every 255 ticks do one company.
|
||||
* Effectively collecting garbage once every two months per AI. */
|
||||
if ((AI::frame_counter & 255) == 0) {
|
||||
CompanyID cid = (CompanyID)GB(AI::frame_counter, 8, 4);
|
||||
if (Company::IsValidAiID(cid)) Company::Get(cid)->ai_instance->CollectGarbage();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ uint AI::GetTick()
|
||||
@@ -115,8 +114,8 @@
|
||||
|
||||
cur_company.Restore();
|
||||
|
||||
InvalidateWindowData(WC_AI_DEBUG, 0, -1);
|
||||
CloseWindowById(WC_AI_SETTINGS, company);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, -1);
|
||||
CloseWindowById(WC_SCRIPT_SETTINGS, company);
|
||||
}
|
||||
|
||||
/* static */ void AI::Pause(CompanyID company)
|
||||
@@ -210,7 +209,7 @@
|
||||
if (_settings_game.ai_config[c] != nullptr && _settings_game.ai_config[c]->HasScript()) {
|
||||
if (!_settings_game.ai_config[c]->ResetInfo(true)) {
|
||||
Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName());
|
||||
_settings_game.ai_config[c]->Change(nullptr);
|
||||
_settings_game.ai_config[c]->Change(std::nullopt);
|
||||
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
|
||||
@@ -227,7 +226,7 @@
|
||||
if (_settings_newgame.ai_config[c] != nullptr && _settings_newgame.ai_config[c]->HasScript()) {
|
||||
if (!_settings_newgame.ai_config[c]->ResetInfo(false)) {
|
||||
Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName());
|
||||
_settings_newgame.ai_config[c]->Change(nullptr);
|
||||
_settings_newgame.ai_config[c]->Change(std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,25 +290,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ int AI::GetStartNextTime()
|
||||
/* static */ void AI::GetConsoleList(std::back_insert_iterator<std::string> &output_iterator, bool newest_only)
|
||||
{
|
||||
/* Find the first company which doesn't exist yet */
|
||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
||||
if (!Company::IsValidID(c)) return AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->GetSetting("start_date");
|
||||
}
|
||||
|
||||
/* Currently no AI can be started, check again in a year. */
|
||||
return DAYS_IN_YEAR;
|
||||
AI::scanner_info->GetConsoleList(output_iterator, newest_only);
|
||||
}
|
||||
|
||||
/* static */ std::string AI::GetConsoleList(bool newest_only)
|
||||
/* static */ void AI::GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator)
|
||||
{
|
||||
return AI::scanner_info->GetConsoleList(newest_only);
|
||||
}
|
||||
|
||||
/* static */ std::string AI::GetConsoleLibraryList()
|
||||
{
|
||||
return AI::scanner_library->GetConsoleList(true);
|
||||
AI::scanner_library->GetConsoleList(output_iterator, true);
|
||||
}
|
||||
|
||||
/* static */ const ScriptInfoList *AI::GetInfoList()
|
||||
@@ -322,12 +310,12 @@
|
||||
return AI::scanner_info->GetUniqueInfoList();
|
||||
}
|
||||
|
||||
/* static */ AIInfo *AI::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
/* static */ AIInfo *AI::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return AI::scanner_info->FindInfo(name, version, force_exact_match);
|
||||
}
|
||||
|
||||
/* static */ AILibrary *AI::FindLibrary(const char *library, int version)
|
||||
/* static */ AILibrary *AI::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return AI::scanner_library->FindLibrary(library, version);
|
||||
}
|
||||
@@ -340,9 +328,9 @@
|
||||
AI::scanner_library->RescanDir();
|
||||
ResetConfig();
|
||||
|
||||
InvalidateWindowData(WC_AI_LIST, 0, 1);
|
||||
SetWindowClassesDirty(WC_AI_DEBUG);
|
||||
InvalidateWindowClassesData(WC_AI_SETTINGS);
|
||||
InvalidateWindowData(WC_SCRIPT_LIST, 0, 1);
|
||||
SetWindowClassesDirty(WC_SCRIPT_DEBUG);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_SETTINGS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+127
-1310
File diff suppressed because it is too large
Load Diff
@@ -10,13 +10,6 @@
|
||||
#ifndef AI_GUI_HPP
|
||||
#define AI_GUI_HPP
|
||||
|
||||
#include "../company_type.h"
|
||||
|
||||
void ShowAIListWindow(CompanyID slot);
|
||||
Window* ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY);
|
||||
void ShowAIConfigWindow();
|
||||
void ShowScriptTextfileWindow(TextfileType file_type, CompanyID slot);
|
||||
void ShowAIDebugWindowIfAIError();
|
||||
void InitializeAIGui();
|
||||
|
||||
#endif /* AI_GUI_HPP */
|
||||
|
||||
+16
-37
@@ -15,7 +15,6 @@
|
||||
#include "../debug.h"
|
||||
#include "../string_func.h"
|
||||
#include "../rev.h"
|
||||
#include <set>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -23,34 +22,34 @@
|
||||
* Check if the API version provided by the AI is supported.
|
||||
* @param api_version The API version as provided by the AI.
|
||||
*/
|
||||
static bool CheckAPIVersion(const char *api_version)
|
||||
static bool CheckAPIVersion(const std::string &api_version)
|
||||
{
|
||||
static const std::set<std::string> versions = { "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13" };
|
||||
static const std::set<std::string> versions = { "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" };
|
||||
return versions.find(api_version) != versions.end();
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef GetClassName
|
||||
#endif /* _WIN32 */
|
||||
template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
template <> const char *GetClassName<AIInfo, ScriptType::AI>() { return "AIInfo"; }
|
||||
|
||||
/* static */ void AIInfo::RegisterAPI(Squirrel *engine)
|
||||
{
|
||||
/* Create the AIInfo class, and add the RegisterAI function */
|
||||
DefSQClass<AIInfo, ST_AI> SQAIInfo("AIInfo");
|
||||
DefSQClass<AIInfo, ScriptType::AI> SQAIInfo("AIInfo");
|
||||
SQAIInfo.PreRegister(engine);
|
||||
SQAIInfo.AddConstructor<void (AIInfo::*)(), 1>(engine, "x");
|
||||
SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting");
|
||||
SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_RANDOM"); // Deprecated, mapped to NONE.
|
||||
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_NONE, "AICONFIG_RANDOM"); // Deprecated, mapped to NONE.
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "AICONFIG_BOOLEAN");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "AICONFIG_INGAME");
|
||||
|
||||
@@ -69,31 +68,26 @@ template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
SQInteger res = ScriptInfo::Constructor(vm, info);
|
||||
if (res != 0) return res;
|
||||
|
||||
ScriptConfigItem config = _start_date_config;
|
||||
config.name = stredup(config.name);
|
||||
config.description = stredup(config.description);
|
||||
info->config_list.push_front(config);
|
||||
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) {
|
||||
if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) 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_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->min_loadable_version = info->GetVersion();
|
||||
}
|
||||
/* When there is an UseAsRandomAI function, call it. */
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "UseAsRandomAI")) {
|
||||
if (!info->engine->CallBoolMethod(*info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "UseAsRandomAI")) {
|
||||
if (!info->engine->CallBoolMethod(info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->use_as_random = true;
|
||||
}
|
||||
/* Try to get the API version the AI is written for. */
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) {
|
||||
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "GetAPIVersion")) {
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!CheckAPIVersion(info->api_version)) {
|
||||
Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion());
|
||||
return SQ_ERROR;
|
||||
}
|
||||
} else {
|
||||
info->api_version = stredup("0.7");
|
||||
info->api_version = "0.7";
|
||||
}
|
||||
|
||||
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
|
||||
@@ -109,15 +103,11 @@ template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
SQUserPointer instance;
|
||||
sq_getinstanceup(vm, 2, &instance, nullptr);
|
||||
AIInfo *info = (AIInfo *)instance;
|
||||
info->api_version = nullptr;
|
||||
info->api_version = fmt::format("{}.{}", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));
|
||||
|
||||
SQInteger res = ScriptInfo::Constructor(vm, info);
|
||||
if (res != 0) return res;
|
||||
|
||||
char buf[8];
|
||||
seprintf(buf, lastof(buf), "%d.%d", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));
|
||||
info->api_version = stredup(buf);
|
||||
|
||||
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
|
||||
sq_setinstanceup(vm, 2, nullptr);
|
||||
/* Register the AI to the base system */
|
||||
@@ -127,16 +117,10 @@ template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
|
||||
AIInfo::AIInfo() :
|
||||
min_loadable_version(0),
|
||||
use_as_random(false),
|
||||
api_version(nullptr)
|
||||
use_as_random(false)
|
||||
{
|
||||
}
|
||||
|
||||
AIInfo::~AIInfo()
|
||||
{
|
||||
free(this->api_version);
|
||||
}
|
||||
|
||||
bool AIInfo::CanLoadFromVersion(int version) const
|
||||
{
|
||||
if (version == -1) return true;
|
||||
@@ -144,11 +128,6 @@ bool AIInfo::CanLoadFromVersion(int version) const
|
||||
}
|
||||
|
||||
|
||||
AILibrary::~AILibrary()
|
||||
{
|
||||
free(this->category);
|
||||
}
|
||||
|
||||
/* static */ void AILibrary::RegisterAPI(Squirrel *engine)
|
||||
{
|
||||
/* Create the AILibrary class, and add the RegisterLibrary function */
|
||||
@@ -169,7 +148,7 @@ AILibrary::~AILibrary()
|
||||
}
|
||||
|
||||
/* Cache the category */
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
delete library;
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
+5
-7
@@ -16,7 +16,6 @@
|
||||
class AIInfo : public ScriptInfo {
|
||||
public:
|
||||
AIInfo();
|
||||
~AIInfo();
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -46,19 +45,18 @@ public:
|
||||
/**
|
||||
* Get the API version this AI is written for.
|
||||
*/
|
||||
const char *GetAPIVersion() const { return this->api_version; }
|
||||
const std::string &GetAPIVersion() const { return this->api_version; }
|
||||
|
||||
private:
|
||||
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.
|
||||
std::string api_version; ///< API version used by this AI.
|
||||
};
|
||||
|
||||
/** All static information from an AI library like name, version, etc. */
|
||||
class AILibrary : public ScriptInfo {
|
||||
public:
|
||||
AILibrary() : ScriptInfo(), category(nullptr) {};
|
||||
~AILibrary();
|
||||
AILibrary() : ScriptInfo() {};
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -73,10 +71,10 @@ public:
|
||||
/**
|
||||
* Get the category this library is in.
|
||||
*/
|
||||
const char *GetCategory() const { return this->category; }
|
||||
const std::string &GetCategory() const { return this->category; }
|
||||
|
||||
private:
|
||||
const char *category; ///< The category this library is in.
|
||||
std::string category; ///< The category this library is in.
|
||||
};
|
||||
|
||||
#endif /* AI_INFO_HPP */
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include "../script/squirrel_class.hpp"
|
||||
|
||||
#include "ai_config.hpp"
|
||||
#include "ai_gui.hpp"
|
||||
#include "ai.hpp"
|
||||
|
||||
#include "../script/script_storage.hpp"
|
||||
#include "../script/script_cmd.h"
|
||||
#include "../script/script_gui.h"
|
||||
#include "ai_info.hpp"
|
||||
#include "ai_instance.hpp"
|
||||
|
||||
@@ -64,13 +64,13 @@ void AIInstance::Died()
|
||||
/* Intro is not supposed to use AI, but it may have 'dummy' AI which instant dies. */
|
||||
if (_game_mode == GM_MENU) return;
|
||||
|
||||
ShowAIDebugWindow(_current_company);
|
||||
ShowScriptDebugWindow(_current_company);
|
||||
|
||||
const AIInfo *info = AIConfig::GetConfig(_current_company, AIConfig::SSS_FORCE_GAME)->GetInfo();
|
||||
if (info != nullptr) {
|
||||
ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING);
|
||||
|
||||
if (info->GetURL() != nullptr) {
|
||||
if (!info->GetURL().empty()) {
|
||||
ScriptLog::Info("Please report the error to the following URL:");
|
||||
ScriptLog::Info(info->GetURL());
|
||||
}
|
||||
@@ -80,16 +80,15 @@ void AIInstance::Died()
|
||||
void AIInstance::LoadDummyScript()
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this->engine);
|
||||
extern void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type);
|
||||
Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI");
|
||||
}
|
||||
|
||||
int AIInstance::GetSetting(const char *name)
|
||||
int AIInstance::GetSetting(const std::string &name)
|
||||
{
|
||||
return AIConfig::GetConfig(_current_company)->GetSetting(name);
|
||||
}
|
||||
|
||||
ScriptInfo *AIInstance::FindLibrary(const char *library, int version)
|
||||
ScriptInfo *AIInstance::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return (ScriptInfo *)AI::FindLibrary(library, version);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ public:
|
||||
*/
|
||||
void Initialize(class AIInfo *info);
|
||||
|
||||
int GetSetting(const char *name) override;
|
||||
ScriptInfo *FindLibrary(const char *library, int version) override;
|
||||
int GetSetting(const std::string &name) override;
|
||||
ScriptInfo *FindLibrary(const std::string &library, int version) override;
|
||||
|
||||
private:
|
||||
void RegisterAPI() override;
|
||||
|
||||
+20
-31
@@ -14,6 +14,7 @@
|
||||
#include "../core/random_func.hpp"
|
||||
|
||||
#include "../script/squirrel_class.hpp"
|
||||
#include "../script/api/script_object.hpp"
|
||||
#include "ai_info.hpp"
|
||||
#include "ai_scanner.hpp"
|
||||
|
||||
@@ -34,7 +35,6 @@ void AIScannerInfo::Initialize()
|
||||
|
||||
/* Create the dummy AI */
|
||||
this->main_script = "%_dummy";
|
||||
extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir);
|
||||
Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
|
||||
}
|
||||
|
||||
@@ -48,9 +48,9 @@ AIScannerInfo::~AIScannerInfo()
|
||||
delete this->info_dummy;
|
||||
}
|
||||
|
||||
void AIScannerInfo::GetScriptName(ScriptInfo *info, char *name, const char *last)
|
||||
std::string AIScannerInfo::GetScriptName(ScriptInfo *info)
|
||||
{
|
||||
seprintf(name, last, "%s", info->GetName());
|
||||
return info->GetName();
|
||||
}
|
||||
|
||||
void AIScannerInfo::RegisterAPI(class Squirrel *engine)
|
||||
@@ -77,12 +77,7 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
}
|
||||
|
||||
/* Find a random AI */
|
||||
uint pos;
|
||||
if (_networking) {
|
||||
pos = InteractiveRandomRange(num_random_ais);
|
||||
} else {
|
||||
pos = RandomRange(num_random_ais);
|
||||
}
|
||||
uint pos = ScriptObject::GetRandomizer(OWNER_NONE).Next(num_random_ais);
|
||||
|
||||
/* Find the Nth item from the array */
|
||||
ScriptInfoList::const_iterator it = this->info_single_list.begin();
|
||||
@@ -97,39 +92,35 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
#undef GetAIInfo
|
||||
}
|
||||
|
||||
AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match)
|
||||
AIInfo *AIScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
if (this->info_list.size() == 0) return nullptr;
|
||||
if (nameParam == nullptr) return nullptr;
|
||||
if (this->info_list.empty()) return nullptr;
|
||||
if (name.empty()) return nullptr;
|
||||
|
||||
char ai_name[1024];
|
||||
strecpy(ai_name, nameParam, lastof(ai_name));
|
||||
strtolower(ai_name);
|
||||
|
||||
if (versionParam == -1) {
|
||||
if (version == -1) {
|
||||
/* We want to load the latest version of this AI; so find it */
|
||||
if (this->info_single_list.find(ai_name) != this->info_single_list.end()) return static_cast<AIInfo *>(this->info_single_list[ai_name]);
|
||||
auto it = this->info_single_list.find(name);
|
||||
if (it != this->info_single_list.end()) return static_cast<AIInfo *>(it->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (force_exact_match) {
|
||||
/* Try to find a direct 'name.version' match */
|
||||
char ai_name_tmp[1024];
|
||||
seprintf(ai_name_tmp, lastof(ai_name_tmp), "%s.%d", ai_name, versionParam);
|
||||
strtolower(ai_name_tmp);
|
||||
if (this->info_list.find(ai_name_tmp) != this->info_list.end()) return static_cast<AIInfo *>(this->info_list[ai_name_tmp]);
|
||||
std::string name_with_version = fmt::format("{}.{}", name, version);
|
||||
auto it = this->info_list.find(name_with_version);
|
||||
if (it != this->info_list.end()) return static_cast<AIInfo *>(it->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AIInfo *info = nullptr;
|
||||
int version = -1;
|
||||
int highest_version = -1;
|
||||
|
||||
/* See if there is a compatible AI which goes by that name, with the highest
|
||||
* version which allows loading the requested version */
|
||||
for (const auto &item : this->info_list) {
|
||||
AIInfo *i = static_cast<AIInfo *>(item.second);
|
||||
if (strcasecmp(ai_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
|
||||
version = item.second->GetVersion();
|
||||
if (StrEqualsIgnoreCase(name, i->GetName()) && i->CanLoadFromVersion(version) && (highest_version == -1 || i->GetVersion() > highest_version)) {
|
||||
highest_version = item.second->GetVersion();
|
||||
info = i;
|
||||
}
|
||||
}
|
||||
@@ -143,10 +134,10 @@ void AIScannerLibrary::Initialize()
|
||||
ScriptScanner::Initialize("AIScanner");
|
||||
}
|
||||
|
||||
void AIScannerLibrary::GetScriptName(ScriptInfo *info, char *name, const char *last)
|
||||
std::string AIScannerLibrary::GetScriptName(ScriptInfo *info)
|
||||
{
|
||||
AILibrary *library = static_cast<AILibrary *>(info);
|
||||
seprintf(name, last, "%s.%s", library->GetCategory(), library->GetInstanceName());
|
||||
return fmt::format("{}.{}", library->GetCategory(), library->GetInstanceName());
|
||||
}
|
||||
|
||||
void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
|
||||
@@ -154,12 +145,10 @@ void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
|
||||
AILibrary::RegisterAPI(engine);
|
||||
}
|
||||
|
||||
AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version)
|
||||
AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
/* Internally we store libraries as 'library.version' */
|
||||
char library_name[1024];
|
||||
seprintf(library_name, lastof(library_name), "%s.%d", library, version);
|
||||
strtolower(library_name);
|
||||
std::string library_name = fmt::format("{}.{}", library, version);
|
||||
|
||||
/* Check if the library + version exists */
|
||||
ScriptInfoList::iterator it = this->info_list.find(library_name);
|
||||
|
||||
@@ -27,12 +27,12 @@ public:
|
||||
|
||||
/**
|
||||
* Check if we have an AI by name and version available in our list.
|
||||
* @param nameParam The name of the AI.
|
||||
* @param versionParam The version of the AI, or -1 if you want the latest.
|
||||
* @param name The name of the AI.
|
||||
* @param version The version of the AI, or -1 if you want the latest.
|
||||
* @param force_exact_match Only match name+version, never latest.
|
||||
* @return nullptr if no match found, otherwise the AI that matched.
|
||||
*/
|
||||
class AIInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match);
|
||||
class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
|
||||
/**
|
||||
* Set the Dummy AI.
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
void SetDummyAI(class AIInfo *info);
|
||||
|
||||
protected:
|
||||
void GetScriptName(ScriptInfo *info, char *name, const char *last) override;
|
||||
std::string GetScriptName(ScriptInfo *info) override;
|
||||
const char *GetFileName() const override { return PATHSEP "info.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_DIR; }
|
||||
const char *GetScannerName() const override { return "AIs"; }
|
||||
@@ -60,10 +60,10 @@ public:
|
||||
* @param version The version the library should have.
|
||||
* @return The library if found, nullptr otherwise.
|
||||
*/
|
||||
class AILibrary *FindLibrary(const char *library, int version);
|
||||
class AILibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
protected:
|
||||
void GetScriptName(ScriptInfo *info, char *name, const char *last) override;
|
||||
std::string GetScriptName(ScriptInfo *info) override;
|
||||
const char *GetFileName() const override { return PATHSEP "library.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_LIBRARY_DIR; }
|
||||
const char *GetScannerName() const override { return "AI Libraries"; }
|
||||
|
||||
Reference in New Issue
Block a user