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