Mercurial > hg > openttd
changeset 18758:456d0db1f47b draft
(svn r23606) -Add: GameScanner, to auto-detect game scripts, and wire it in the console
author | truebrain <truebrain@openttd.org> |
---|---|
date | Mon, 19 Dec 2011 20:55:56 +0000 |
parents | 8fb3d74f1cd1 |
children | 6aad245298be |
files | projects/openttd_vs100.vcxproj projects/openttd_vs100.vcxproj.filters projects/openttd_vs80.vcproj projects/openttd_vs90.vcproj source.list src/console_cmds.cpp src/game/game.hpp src/game/game_config.cpp src/game/game_config.hpp src/game/game_core.cpp src/game/game_info.cpp src/game/game_info.hpp src/game/game_instance.cpp src/game/game_instance.hpp src/game/game_scanner.cpp src/game/game_scanner.hpp src/openttd.cpp src/settings_type.h |
diffstat | 18 files changed, 610 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -914,9 +914,15 @@ <ClInclude Include="..\src\ai\ai_scanner.hpp" /> <ClInclude Include="..\src\script\api\ai_changelog.hpp" /> <ClInclude Include="..\src\game\game.hpp" /> + <ClCompile Include="..\src\game\game_config.cpp" /> + <ClInclude Include="..\src\game\game_config.hpp" /> <ClCompile Include="..\src\game\game_core.cpp" /> + <ClCompile Include="..\src\game\game_info.cpp" /> + <ClInclude Include="..\src\game\game_info.hpp" /> <ClCompile Include="..\src\game\game_instance.cpp" /> <ClInclude Include="..\src\game\game_instance.hpp" /> + <ClCompile Include="..\src\game\game_scanner.cpp" /> + <ClInclude Include="..\src\game\game_scanner.hpp" /> <ClInclude Include="..\src\script\api\script_accounting.hpp" /> <ClInclude Include="..\src\script\api\script_airport.hpp" /> <ClInclude Include="..\src\script\api\script_base.hpp" />
--- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -1968,15 +1968,33 @@ <ClInclude Include="..\src\game\game.hpp"> <Filter>Game Core</Filter> </ClInclude> + <ClCompile Include="..\src\game\game_config.cpp"> + <Filter>Game Core</Filter> + </ClCompile> + <ClInclude Include="..\src\game\game_config.hpp"> + <Filter>Game Core</Filter> + </ClInclude> <ClCompile Include="..\src\game\game_core.cpp"> <Filter>Game Core</Filter> </ClCompile> + <ClCompile Include="..\src\game\game_info.cpp"> + <Filter>Game Core</Filter> + </ClCompile> + <ClInclude Include="..\src\game\game_info.hpp"> + <Filter>Game Core</Filter> + </ClInclude> <ClCompile Include="..\src\game\game_instance.cpp"> <Filter>Game Core</Filter> </ClCompile> <ClInclude Include="..\src\game\game_instance.hpp"> <Filter>Game Core</Filter> </ClInclude> + <ClCompile Include="..\src\game\game_scanner.cpp"> + <Filter>Game Core</Filter> + </ClCompile> + <ClInclude Include="..\src\game\game_scanner.hpp"> + <Filter>Game Core</Filter> + </ClInclude> <ClInclude Include="..\src\script\api\script_accounting.hpp"> <Filter>Script API</Filter> </ClInclude>
--- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -2983,10 +2983,26 @@ > </File> <File + RelativePath=".\..\src\game\game_config.cpp" + > + </File> + <File + RelativePath=".\..\src\game\game_config.hpp" + > + </File> + <File RelativePath=".\..\src\game\game_core.cpp" > </File> <File + RelativePath=".\..\src\game\game_info.cpp" + > + </File> + <File + RelativePath=".\..\src\game\game_info.hpp" + > + </File> + <File RelativePath=".\..\src\game\game_instance.cpp" > </File> @@ -2994,6 +3010,14 @@ RelativePath=".\..\src\game\game_instance.hpp" > </File> + <File + RelativePath=".\..\src\game\game_scanner.cpp" + > + </File> + <File + RelativePath=".\..\src\game\game_scanner.hpp" + > + </File> </Filter> <Filter Name="Script API"
--- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -2980,10 +2980,26 @@ > </File> <File + RelativePath=".\..\src\game\game_config.cpp" + > + </File> + <File + RelativePath=".\..\src\game\game_config.hpp" + > + </File> + <File RelativePath=".\..\src\game\game_core.cpp" > </File> <File + RelativePath=".\..\src\game\game_info.cpp" + > + </File> + <File + RelativePath=".\..\src\game\game_info.hpp" + > + </File> + <File RelativePath=".\..\src\game\game_instance.cpp" > </File> @@ -2991,6 +3007,14 @@ RelativePath=".\..\src\game\game_instance.hpp" > </File> + <File + RelativePath=".\..\src\game\game_scanner.cpp" + > + </File> + <File + RelativePath=".\..\src\game\game_scanner.hpp" + > + </File> </Filter> <Filter Name="Script API"
--- a/source.list +++ b/source.list @@ -688,9 +688,15 @@ # Game Core game/game.hpp +game/game_config.cpp +game/game_config.hpp game/game_core.cpp +game/game_info.cpp +game/game_info.hpp game/game_instance.cpp game/game_instance.hpp +game/game_scanner.cpp +game/game_scanner.hpp # Script API script/api/script_accounting.hpp
--- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -37,6 +37,7 @@ #include "newgrf.h" #include "console_func.h" #include "engine_base.h" +#include "game/game.hpp" #ifdef ENABLE_NETWORK #include "table/strings.h" @@ -1105,6 +1106,16 @@ return true; } +DEF_CONSOLE_CMD(ConListGame) +{ + char buf[4096]; + Game::GetConsoleList(buf, lastof(buf)); + + PrintLineByLine(buf); + + return true; +} + DEF_CONSOLE_CMD(ConStartAI) { if (argc == 0 || argc > 3) { @@ -1895,6 +1906,8 @@ IConsoleCmdRegister("start_ai", ConStartAI); IConsoleCmdRegister("stop_ai", ConStopAI); + IConsoleCmdRegister("list_game", ConListGame); + /* networking functions */ #ifdef ENABLE_NETWORK /* Content downloading is only available with ZLIB */
--- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -12,6 +12,12 @@ #ifndef GAME_HPP #define GAME_HPP +#include "../core/string_compare_type.hpp" +#include <map> + +/** A list that maps AI names to their AIInfo object. */ +typedef std::map<const char *, class ScriptInfo *, StringCompare> ScriptInfoList; + /** * Main Game class. Contains all functions needed to start, stop, save and load Game Scripts. */ @@ -30,16 +36,30 @@ /** * Uninitialize the Game system. */ - static void Uninitialize(); + static void Uninitialize(bool keepConfig); /** * Get the current GameScript instance. */ static class GameInstance *GetGameInstance() { return Game::instance; } + static void Rescan(); + static void ResetConfig(); + + /** Wrapper function for GameScanner::GetConsoleList */ + static char *GetConsoleList(char *p, const char *last, bool newest_only = false); + /** Wrapper function for GameScanner::GetInfoList */ + static const ScriptInfoList *GetInfoList(); + /** Wrapper function for GameScanner::GetUniqueInfoList */ + static const ScriptInfoList *GetUniqueInfoList(); + /** Wrapper function for GameScannerInfo::FindInfo */ + static class GameInfo *FindInfo(const char *name, int version, bool force_exact_match); + private: - static uint frame_counter; ///< Tick counter for the Game code. - static class GameInstance *instance; ///< Instance to the current active Game. + static uint frame_counter; ///< Tick counter for the Game code. + static class GameInstance *instance; ///< Instance to the current active Game. + static class GameScannerInfo *scanner; ///< Scanner for Game scripts. + static class GameInfo *info; ///< Current selected GameInfo. }; #endif /* GAME_HPP */
new file mode 100644 --- /dev/null +++ b/src/game/game_config.cpp @@ -0,0 +1,45 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file game_config.cpp Implementation of GameConfig. */ + +#include "../stdafx.h" +#include "../settings_type.h" +#include "../core/random_func.hpp" +#include "game.hpp" +#include "game_config.hpp" +#include "game_info.hpp" + +/* static */ GameConfig *GameConfig::GetConfig(ScriptSettingSource source) +{ + GameConfig **config; + if (source == SSS_FORCE_NEWGAME || (source == SSS_DEFAULT && _game_mode == GM_MENU)) { + config = &_settings_newgame.game_config; + } else { + config = &_settings_game.game_config; + } + if (*config == NULL) *config = new GameConfig(); + return *config; +} + +class GameInfo *GameConfig::GetInfo() const +{ + return static_cast<class GameInfo *>(ScriptConfig::GetInfo()); +} + +ScriptInfo *GameConfig::FindInfo(const char *name, int version, bool force_exact_match) +{ + return static_cast<ScriptInfo *>(Game::FindInfo(name, version, force_exact_match)); +} + +bool GameConfig::ResetInfo(bool force_exact_match) +{ + this->info = (ScriptInfo *)Game::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); + return this->info != NULL; +}
new file mode 100644 --- /dev/null +++ b/src/game/game_config.hpp @@ -0,0 +1,48 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file game_config.hpp GameConfig stores the configuration settings of every Game. */ + +#ifndef GAME_CONFIG_HPP +#define GAME_CONFIG_HPP + +#include "../script/script_config.hpp" + +class GameConfig : public ScriptConfig { +public: + /** + * Get the config of a company. + */ + static GameConfig *GetConfig(ScriptSettingSource source = SSS_DEFAULT); + + GameConfig() : + ScriptConfig() + {} + + GameConfig(const GameConfig *config) : + ScriptConfig(config) + {} + + class GameInfo *GetInfo() const; + + /** + * When ever the Game Scanner is reloaded, all infos become invalid. This + * function tells GameConfig about this. + * @param force_exact_match If true try to find the exact same version + * as specified. If false any version is ok. + * @return \c true if the reset was successful, \c false if the Game was no longer + * found. + */ + bool ResetInfo(bool force_exact_match); + +protected: + /* virtual */ ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match); +}; + +#endif /* GAME_CONFIG_HPP */
--- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -12,18 +12,26 @@ #include "../stdafx.h" #include "../command_func.h" #include "../core/backup_type.hpp" +#include "../core/bitmath_func.hpp" #include "../company_base.h" #include "../company_func.h" #include "../network/network.h" +#include "../window_func.h" +#include "../fileio_func.h" #include "game.hpp" +#include "game_scanner.hpp" +#include "game_config.hpp" #include "game_instance.hpp" /* static */ uint Game::frame_counter = 0; +/* static */ GameInfo *Game::info = NULL; /* static */ GameInstance *Game::instance = NULL; +/* static */ GameScannerInfo *Game::scanner = NULL; /* static */ void Game::GameLoop() { if (_networking && !_network_server) return; + if (Game::instance == NULL) return; Game::frame_counter++; @@ -40,25 +48,112 @@ /* static */ void Game::Initialize() { - if (Game::instance != NULL) Game::Uninitialize(); + if (Game::instance != NULL) Game::Uninitialize(true); Game::frame_counter = 0; + + if (Game::scanner == NULL) { + TarScanner::DoScan(TarScanner::GAME); + Game::scanner = new GameScannerInfo(); + Game::scanner->Initialize(); + } + if (Game::instance == NULL) { /* Clients shouldn't start GameScripts */ if (_networking && !_network_server) return; + GameConfig *config = GameConfig::GetConfig(); + GameInfo *info = config->GetInfo(); + if (info == NULL) return; + Backup<CompanyByte> cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); + Game::info = info; Game::instance = new GameInstance(); - Game::instance->Initialize(); + Game::instance->Initialize(info); cur_company.Restore(); + + InvalidateWindowData(WC_AI_DEBUG, 0, -1); + } +} + +/* static */ void Game::Uninitialize(bool keepConfig) +{ + delete Game::instance; + Game::instance = NULL; + + if (keepConfig) { + Rescan(); + } else { + delete Game::scanner; + Game::scanner = NULL; + + if (_settings_game.game_config != NULL) { + delete _settings_game.game_config; + _settings_game.game_config = NULL; + } + if (_settings_newgame.game_config != NULL) { + delete _settings_newgame.game_config; + _settings_newgame.game_config = NULL; + } } } -/* static */ void Game::Uninitialize() +/* static */ void Game::ResetConfig() +{ + /* Check for both newgame as current game if we can reload the GameInfo insde + * the GameConfig. If not, remove the Game from the list. */ + if (_settings_game.game_config != NULL && _settings_game.game_config->HasScript()) { + if (!_settings_game.game_config->ResetInfo(true)) { + DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_game.game_config->GetName()); + _settings_game.game_config->Change(NULL); + if (Game::instance != NULL) { + delete Game::instance; + Game::instance = NULL; + } + } else if (Game::instance != NULL) { + Game::info = _settings_game.game_config->GetInfo(); + } + } + if (_settings_newgame.game_config != NULL && _settings_newgame.game_config->HasScript()) { + if (!_settings_newgame.game_config->ResetInfo(false)) { + DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_newgame.game_config->GetName()); + _settings_newgame.game_config->Change(NULL); + } + } +} + +/* static */ void Game::Rescan() { - delete Game::instance; - Game::instance = NULL; + TarScanner::DoScan(TarScanner::GAME); + + Game::scanner->RescanDir(); + ResetConfig(); + + InvalidateWindowData(WC_AI_LIST, 0, 1); + SetWindowClassesDirty(WC_AI_DEBUG); + SetWindowDirty(WC_AI_SETTINGS, 0); +} + + +/* static */ char *Game::GetConsoleList(char *p, const char *last, bool newest_only) +{ + return Game::scanner->GetConsoleList(p, last, newest_only); } + +/* static */ const ScriptInfoList *Game::GetInfoList() +{ + return Game::scanner->GetInfoList(); +} + +/* static */ const ScriptInfoList *Game::GetUniqueInfoList() +{ + return Game::scanner->GetUniqueInfoList(); +} + +/* static */ GameInfo *Game::FindInfo(const char *name, int version, bool force_exact_match) +{ + return Game::scanner->FindInfo(name, version, force_exact_match); +}
new file mode 100644 --- /dev/null +++ b/src/game/game_info.cpp @@ -0,0 +1,101 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file game_info.cpp Implementation of GameInfo */ + +#include "../stdafx.h" + +#include "../script/squirrel_helper.hpp" +#include "../script/squirrel_class.hpp" +#include "game_info.hpp" +#include "game_scanner.hpp" +#include "../settings_type.h" +#include "../debug.h" +#include "../rev.h" +#include "game.hpp" + +/** + * Check if the API version provided by the Game is supported. + * @param api_version The API version as provided by the Game. + */ +static bool CheckAPIVersion(const char *api_version) +{ + return strcmp(api_version, "1.2") == 0; +} + +#if defined(WIN32) +#undef GetClassName +#endif /* WIN32 */ +template <> const char *GetClassName<GameInfo, ST_GS>() { return "GSInfo"; } + +/* static */ void GameInfo::RegisterAPI(Squirrel *engine) +{ + /* Create the GSInfo class, and add the RegisterGS function */ + DefSQClass<GameInfo, ST_GS> SQGSInfo("GSInfo"); + SQGSInfo.PreRegister(engine); + SQGSInfo.AddConstructor<void (GameInfo::*)(), 1>(engine, "x"); + SQGSInfo.DefSQAdvancedMethod(engine, &GameInfo::AddSetting, "AddSetting"); + SQGSInfo.DefSQAdvancedMethod(engine, &GameInfo::AddLabels, "AddLabels"); + SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE"); + SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM"); + SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN"); + SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME"); + SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER"); + + SQGSInfo.PostRegister(engine); + engine->AddMethod("RegisterGS", &GameInfo::Constructor, 2, "tx"); +} + +/* static */ SQInteger GameInfo::Constructor(HSQUIRRELVM vm) +{ + /* Get the GameInfo */ + SQUserPointer instance = NULL; + if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, 0)) || instance == NULL) return sq_throwerror(vm, _SC("Pass an instance of a child class of GameInfo to RegisterGame")); + GameInfo *info = (GameInfo *)instance; + + SQInteger res = ScriptInfo::Constructor(vm, info); + if (res != 0) return res; + + 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(); + } + + /* Try to get the API version the AI is written for. */ + if (!info->CheckMethod("GetAPIVersion")) return SQ_ERROR; + if (!info->engine->CallStringMethodStrdup(*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 (%s.%d): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); + return SQ_ERROR; + } + + /* Remove the link to the real instance, else it might get deleted by RegisterGame() */ + sq_setinstanceup(vm, 2, NULL); + /* Register the Game to the base system */ + info->GetScanner()->RegisterScript(info); + return 0; +} + +GameInfo::GameInfo() : + min_loadable_version(0), + api_version(NULL) +{ +} + +GameInfo::~GameInfo() +{ + free(this->api_version); +} + +bool GameInfo::CanLoadFromVersion(int version) const +{ + if (version == -1) return true; + return version >= this->min_loadable_version && version <= this->GetVersion(); +}
new file mode 100644 --- /dev/null +++ b/src/game/game_info.hpp @@ -0,0 +1,49 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file game_info.hpp GameInfo keeps track of all information of an Game, like Author, Description, ... */ + +#ifndef GAME_INFO_HPP +#define GAME_INFO_HPP + +#include "../script/script_info.hpp" +#include "../script/script_config.hpp" + +/** All static information from an Game like name, version, etc. */ +class GameInfo : public ScriptInfo { +public: + GameInfo(); + ~GameInfo(); + + /** + * Register the functions of this class. + */ + static void RegisterAPI(Squirrel *engine); + + /** + * Create an Game, using this GameInfo as start-template. + */ + static SQInteger Constructor(HSQUIRRELVM vm); + + /** + * Check if we can start this Game. + */ + bool CanLoadFromVersion(int version) const; + + /** + * Get the API version this Game is written for. + */ + const char *GetAPIVersion() const { return this->api_version; } + +private: + int min_loadable_version; ///< The Game can load savegame data if the version is equal or greater than this. + const char *api_version; ///< API version used by this Game. +}; + +#endif /* GAME_INFO_HPP */
--- a/src/game/game_instance.cpp +++ b/src/game/game_instance.cpp @@ -16,6 +16,8 @@ #include "../script/squirrel_class.hpp" #include "../script/script_storage.hpp" +#include "game_config.hpp" +#include "game_info.hpp" #include "game_instance.hpp" #include "game.hpp" @@ -35,12 +37,12 @@ ScriptInstance("GS") {} -void GameInstance::Initialize() +void GameInstance::Initialize(GameInfo *info) { /* Register the GameController */ SQGSController_Register(this->engine); - ScriptInstance::Initialize("test/main.nut", "TestGame"); + ScriptInstance::Initialize(info->GetMainScript(), info->GetInstanceName()); } void GameInstance::RegisterAPI() @@ -61,7 +63,7 @@ int GameInstance::GetSetting(const char *name) { - return NULL; + return GameConfig::GetConfig()->GetSetting(name); } ScriptInfo *GameInstance::FindLibrary(const char *library, int version)
--- a/src/game/game_instance.hpp +++ b/src/game/game_instance.hpp @@ -21,8 +21,9 @@ /** * Initialize the script and prepare it for its first run. + * @param info The GameInfo to start. */ - void Initialize(); + void Initialize(class GameInfo *info); /* virtual */ int GetSetting(const char *name); /* virtual */ ScriptInfo *FindLibrary(const char *library, int version);
new file mode 100644 --- /dev/null +++ b/src/game/game_scanner.cpp @@ -0,0 +1,89 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file game_scanner.cpp allows scanning Game scripts */ + +#include "../stdafx.h" +#include "../debug.h" +#include "../fileio_func.h" +#include "../network/network.h" +#include "../core/random_func.hpp" + +#include "../script/squirrel_class.hpp" +#include "game_info.hpp" +#include "game_scanner.hpp" +#include "../script/api/script_controller.hpp" + + +GameScannerInfo::GameScannerInfo() : + ScriptScanner() +{ +} + +void GameScannerInfo::Initialize() +{ + ScriptScanner::Initialize("GSScanner"); +} + +void GameScannerInfo::GetScriptName(ScriptInfo *info, char *name, int len) +{ + snprintf(name, len, "%s", info->GetName()); +} + +void GameScannerInfo::RegisterAPI(class Squirrel *engine) +{ + GameInfo::RegisterAPI(engine); +} + +GameInfo *GameScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match) +{ + if (this->info_list.size() == 0) return NULL; + if (nameParam == NULL) return NULL; + + char game_name[1024]; + ttd_strlcpy(game_name, nameParam, sizeof(game_name)); + strtolower(game_name); + + GameInfo *info = NULL; + int version = -1; + + if (versionParam == -1) { + /* We want to load the latest version of this Game script; so find it */ + if (this->info_single_list.find(game_name) != this->info_single_list.end()) return static_cast<GameInfo *>(this->info_single_list[game_name]); + + /* If we didn't find a match Game script, maybe the user included a version */ + char *e = strrchr(game_name, '.'); + if (e == NULL) return NULL; + *e = '\0'; + e++; + versionParam = atoi(e); + /* FALL THROUGH, like we were calling this function with a version. */ + } + + if (force_exact_match) { + /* Try to find a direct 'name.version' match */ + char game_name_tmp[1024]; + snprintf(game_name_tmp, sizeof(game_name_tmp), "%s.%d", game_name, versionParam); + strtolower(game_name_tmp); + if (this->info_list.find(game_name_tmp) != this->info_list.end()) return static_cast<GameInfo *>(this->info_list[game_name_tmp]); + } + + /* See if there is a compatible Game script which goes by that name, with the highest + * version which allows loading the requested version */ + ScriptInfoList::iterator it = this->info_list.begin(); + for (; it != this->info_list.end(); it++) { + GameInfo *i = static_cast<GameInfo *>((*it).second); + if (strcasecmp(game_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) { + version = (*it).second->GetVersion(); + info = i; + } + } + + return info; +}
new file mode 100644 --- /dev/null +++ b/src/game/game_scanner.hpp @@ -0,0 +1,40 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file game_scanner.hpp declarations of the class for Game scanner */ + +#ifndef GAME_SCANNER_HPP +#define GAME_SCANNER_HPP + +#include "../script/script_scanner.hpp" + +class GameScannerInfo : public ScriptScanner { +public: + GameScannerInfo(); + + /* virtual */ void Initialize(); + + /** + * Check if we have a game by name and version available in our list. + * @param nameParam The name of the game script. + * @param versionParam The versionof the game script, or -1 if you want the latest. + * @param force_exact_match Only match name+version, never latest. + * @return NULL if no match found, otherwise the game script that matched. + */ + class GameInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match); + +protected: + /* virtual */ void GetScriptName(ScriptInfo *info, char *name, int len); + /* virtual */ const char *GetFileName() const { return PATHSEP "info.nut"; } + /* virtual */ Subdirectory GetDirectory() const { return GAME_DIR; } + /* virtual */ const char *GetScannerName() const { return "Game Scripts"; } + /* virtual */ void RegisterAPI(class Squirrel *engine); +}; + +#endif /* GAME_SCANNER_HPP */
--- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -63,6 +63,7 @@ #include "newgrf.h" #include "misc/getoptdata.h" #include "game/game.hpp" +#include "game/game_config.hpp" #include "town.h" @@ -204,6 +205,11 @@ p = AI::GetConsoleList(p, lastof(buf), true); AI::Uninitialize(true); + /* We need to initialize the GameScript, so it finds the GSs */ + Game::Initialize(); + p = Game::GetConsoleList(p, lastof(buf), true); + Game::Uninitialize(true); + /* ShowInfo put output to stderr, but version information should go * to stdout; this is the only exception */ #if !defined(WIN32) && !defined(WIN64) @@ -287,7 +293,7 @@ /* stop the scripts */ AI::Uninitialize(false); - Game::Uninitialize(); + Game::Uninitialize(false); /* Uninitialize variables that are allocated dynamically */ GamelogReset(); @@ -347,6 +353,9 @@ delete _settings_game.ai_config[c]; } } + if (_settings_game.game_config != NULL) { + delete _settings_game.game_config; + } /* Copy newgame settings to active settings. * Also initialise old settings needed for savegame conversion. */ @@ -359,6 +368,10 @@ _settings_game.ai_config[c] = new AIConfig(_settings_newgame.ai_config[c]); } } + _settings_game.game_config = NULL; + if (_settings_newgame.game_config != NULL) { + _settings_game.game_config = new GameConfig(_settings_newgame.game_config); + } } void OpenBrowser(const char *url) @@ -402,6 +415,7 @@ TarScanner::DoScan(TarScanner::SCENARIO); AI::Initialize(); + Game::Initialize(); /* We want the new (correct) NewGRF count to survive the loading. */ uint last_newgrf_count = _settings_client.gui.last_newgrf_count; @@ -411,6 +425,7 @@ * reading the configuration file, recalculate that now. */ UpdateNewGRFConfigPalette(); + Game::Uninitialize(true); AI::Uninitialize(true); CheckConfig(); LoadFromHighScore();
--- a/src/settings_type.h +++ b/src/settings_type.h @@ -455,6 +455,7 @@ AISettings ai; ///< what may the AI do? ScriptSettings script; ///< settings for scripts class AIConfig *ai_config[MAX_COMPANIES]; ///< settings per company + class GameConfig *game_config; ///< settings for gamescript PathfinderSettings pf; ///< settings for all pathfinders OrderSettings order; ///< settings related to orders VehicleSettings vehicle; ///< options for vehicles