changeset 18408:c4286df1c22a draft

(svn r23244) -Feature: if the installation is ananas, try to get the b without b installed
author rubidium <rubidium@openttd.org>
date Thu, 17 Nov 2011 21:17:17 +0000
parents 587c70b39535
children a0ce65d4271b
files projects/openttd_vs100.vcxproj projects/openttd_vs100.vcxproj.filters projects/openttd_vs80.vcproj projects/openttd_vs90.vcproj source.list src/bootstrap_gui.cpp src/lang/english.txt src/openttd.cpp src/openttd.h src/window.cpp src/window_type.h
diffstat 11 files changed, 314 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -635,6 +635,7 @@
     <ClCompile Include="..\src\aircraft_gui.cpp" />
     <ClCompile Include="..\src\airport_gui.cpp" />
     <ClCompile Include="..\src\autoreplace_gui.cpp" />
+    <ClCompile Include="..\src\bootstrap_gui.cpp" />
     <ClCompile Include="..\src\bridge_gui.cpp" />
     <ClCompile Include="..\src\build_vehicle_gui.cpp" />
     <ClCompile Include="..\src\cheat_gui.cpp" />
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -1125,6 +1125,9 @@
     <ClCompile Include="..\src\autoreplace_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\bootstrap_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\bridge_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -1823,6 +1823,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\bootstrap_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\bridge_gui.cpp"
 				>
 			</File>
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -1820,6 +1820,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\bootstrap_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\bridge_gui.cpp"
 				>
 			</File>
--- a/source.list
+++ b/source.list
@@ -387,6 +387,7 @@
 aircraft_gui.cpp
 airport_gui.cpp
 autoreplace_gui.cpp
+bootstrap_gui.cpp
 bridge_gui.cpp
 build_vehicle_gui.cpp
 cheat_gui.cpp
new file mode 100644
--- /dev/null
+++ b/src/bootstrap_gui.cpp
@@ -0,0 +1,269 @@
+/* $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 bootstrap_gui.cpp Barely used user interface for bootstrapping OpenTTD, i.e. downloading the required content. */
+
+#include "stdafx.h"
+#include "base_media_base.h"
+#include "blitter/factory.hpp"
+#include "core/geometry_func.hpp"
+#include "fileio_func.h"
+#include "fontcache.h"
+#include "gfx_func.h"
+#include "network/network.h"
+#include "network/network_content_gui.h"
+#include "openttd.h"
+#include "strings_func.h"
+#include "video/video_driver.hpp"
+#include "window_func.h"
+#include "window_gui.h"
+
+#include "table/strings.h"
+
+/** Widgets for the background window to prevent smearing. */
+static const struct NWidgetPart _background_widgets[] = {
+	NWidget(WWT_PANEL, COLOUR_DARK_BLUE, 0), SetResize(1, 1),
+};
+
+/**
+ * Window description for the background window to prevent smearing.
+ */
+static const WindowDesc _background_desc(
+	WDP_MANUAL, 0, 0,
+	WC_BOOTSTRAP, WC_NONE,
+	0,
+	_background_widgets, lengthof(_background_widgets)
+);
+
+/** The background for the game. */
+class BootstrapBackground : public Window {
+public:
+	BootstrapBackground() : Window()
+	{
+		this->InitNested(&_background_desc, 0);
+		CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
+		ResizeWindow(this, _screen.width, _screen.height);
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE);
+		GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER);
+	}
+};
+
+/** Nested widgets for the download window. */
+static const NWidgetPart _nested_boostrap_download_status_window_widgets[] = {
+	NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+	NWidget(WWT_PANEL, COLOUR_GREY, NCDSWW_BACKGROUND),
+		NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30),
+	EndContainer(),
+};
+
+/** Window description for the download window */
+static const WindowDesc _bootstrap_download_status_window_desc(
+	WDP_CENTER, 0, 0,
+	WC_NETWORK_STATUS_WINDOW, WC_NONE,
+	WDF_MODAL,
+	_nested_boostrap_download_status_window_widgets, lengthof(_nested_boostrap_download_status_window_widgets)
+);
+
+
+/** Window for showing the download status of content */
+struct BootstrapContentDownloadStatusWindow : public BaseNetworkContentDownloadStatusWindow {
+public:
+	/** Simple call the constructor of the superclass. */
+	BootstrapContentDownloadStatusWindow() : BaseNetworkContentDownloadStatusWindow(&_bootstrap_download_status_window_desc)
+	{
+	}
+
+	virtual void OnDownloadComplete(ContentID cid)
+	{
+		/* We have completed downloading. We can trigger finding the right set now. */
+		BaseGraphics::FindSets();
+
+		/* And continue going into the menu. */
+		_game_mode = GM_MENU;
+
+		/* _exit_game is used to break out of the outer video driver's MainLoop. */
+		_exit_game = true;
+		delete this;
+	}
+};
+
+/** Widgets in the query window. */
+enum BootstrapAskForDownloadWidgets {
+	BAFDW_QUESTION, ///< The question whether to download.
+	BAFDW_YES,      ///< An affirmative answer to the question.
+	BAFDW_NO,       ///< An negative answer to the question.
+};
+
+/** The widgets for the query. It has no close box as that sprite does not exist yet. */
+static const NWidgetPart _bootstrap_query_widgets[] = {
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY),
+		NWidget(WWT_PANEL, COLOUR_GREY, BAFDW_QUESTION), EndContainer(),
+		NWidget(NWID_HORIZONTAL),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BAFDW_YES), SetDataTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD, STR_NULL),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BAFDW_NO), SetDataTip(STR_MISSING_GRAPHICS_NO_QUIT, STR_NULL),
+		EndContainer(),
+	EndContainer(),
+};
+
+/** The window description for the query. */
+static const WindowDesc _bootstrap_query_desc(
+	WDP_CENTER, 0, 0,
+	WC_CONFIRM_POPUP_QUERY, WC_NONE,
+	WDF_UNCLICK_BUTTONS,
+	_bootstrap_query_widgets, lengthof(_bootstrap_query_widgets)
+);
+
+/** The window for the query. It can't use the generic query window as that uses sprites that don't exist yet. */
+class BootstrapAskForDownloadWindow : public Window, ContentCallback {
+	Dimension button_size; ///< The dimension of the button
+
+public:
+	/** Start listening to the content client events. */
+	BootstrapAskForDownloadWindow() : Window()
+	{
+		this->InitNested(&_bootstrap_query_desc);
+		_network_content_client.AddCallback(this);
+	}
+
+	/** Stop listening to the content client events. */
+	~BootstrapAskForDownloadWindow()
+	{
+		_network_content_client.RemoveCallback(this);
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		/* We cache the button size. This is safe as no reinit can happen here. */
+		if (this->button_size.width == 0) {
+			this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT));
+			this->button_size.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT;
+			this->button_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM;
+		}
+
+		switch (widget) {
+			case BAFDW_QUESTION:
+				/* The question is twice as wide as the buttons, and determine the height based on the width. */
+				size->width = this->button_size.width * 2;
+				size->height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT) + WD_FRAMETEXT_BOTTOM + WD_FRAMETEXT_TOP;
+				break;
+
+			case BAFDW_YES:
+			case BAFDW_NO:
+				*size = this->button_size;
+				break;
+		}
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		if (widget != 0) return;
+
+		DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMETEXT_TOP, r.bottom - WD_FRAMETEXT_BOTTOM, STR_MISSING_GRAPHICS_SET_MESSAGE, TC_FROMSTRING, SA_CENTER);
+	}
+
+	virtual void OnClick(Point pt, int widget, int click_count)
+	{
+		switch (widget) {
+			case BAFDW_YES:
+				/* We got permission to connect! Yay! */
+				_network_content_client.Connect();
+				break;
+
+			case BAFDW_NO:
+				_exit_game = true;
+				break;
+
+			default:
+				break;
+		}
+	}
+
+	virtual void OnConnect(bool success)
+	{
+		/* Once connected, request the metadata. */
+		_network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
+	}
+
+	virtual void OnReceiveContentInfo(const ContentInfo *ci)
+	{
+		/* And once the meta data is received, start downloading it. */
+		_network_content_client.Select(ci->id);
+		new BootstrapContentDownloadStatusWindow();
+		delete this;
+	}
+};
+
+/**
+ * Handle all procedures for bootstrapping OpenTTD without a base grapics set.
+ * This requires all kinds of trickery that is needed to avoid the use of
+ * sprites from the base graphics set which are pretty interwoven.
+ * @return True if a base set exists, otherwise false.
+ */
+bool HandleBootstrap()
+{
+	if (BaseGraphics::GetUsedSet() != NULL) return true;
+
+	/* No user interface, bail out with an error. */
+	if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
+
+	/* If there is no network or no freetype, then there is nothing we can do. Go straight to failure. */
+#if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) && !defined(__APPLE__)
+	if (!_network_available) goto failure;
+
+	/* First tell the game we're bootstrapping. */
+	_game_mode = GM_BOOTSTRAP;
+
+	/* Initialise the freetype font code. */
+	InitializeUnicodeGlyphMap();
+	/* Next "force" finding a suitable freetype font as the local font is missing. */
+	CheckForMissingGlyphsInLoadedLanguagePack(false);
+
+	/* Initialise the palette. The biggest step is 'faking' some recolour sprites.
+	 * This way the mauve and gray colours work and we can show the user interface. */
+	GfxInitPalettes();
+	static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
+	for (uint i = 0; i != 16; i++) {
+		for (int j = 0; j < 8; j++) {
+			_colour_gradient[i][j] = offsets[i] + j;
+		}
+	}
+
+	/* Finally ask the question. */
+	new BootstrapBackground();
+	new BootstrapAskForDownloadWindow();
+
+	/* Process the user events. */
+	_video_driver->MainLoop();
+
+	/* _exit_game is used to get out of the video driver's main loop.
+	 * In case GM_BOOTSTRAP is still set we did not exit it via the
+	 * "download complete" event, so it was a manual exit. Obey it. */
+	_exit_game = _game_mode == GM_BOOTSTRAP;
+	if (_exit_game) return false;
+
+	/* Try to probe the graphics. Should work this time. */
+	if (!BaseGraphics::SetSet(NULL)) goto failure;
+
+	/* Finally we can continue heading for the menu. */
+	_game_mode = GM_MENU;
+	return true;
+#endif
+
+	/* Failure to get enough working to get a graphics set. */
+failure:
+	usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 4.1 of readme.txt.");
+	return false;
+}
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1875,6 +1875,11 @@
 STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE          :{WHITE}... file not writable
 STR_CONTENT_ERROR_COULD_NOT_EXTRACT                             :{WHITE}Could not decompress the downloaded file
 
+STR_MISSING_GRAPHICS_SET_CAPTION                                :{WHITE}Missing graphics
+STR_MISSING_GRAPHICS_SET_MESSAGE                                :{BLACK}OpenTTD requires graphics to function but none could be found. Do you allow OpenTTD to download and install these graphics?
+STR_MISSING_GRAPHICS_YES_DOWNLOAD                               :{BLACK}Yes, download the graphics
+STR_MISSING_GRAPHICS_NO_QUIT                                    :{BLACK}No, quit OpenTTD
+
 # Transparency settings window
 STR_TRANSPARENCY_CAPTION                                        :{WHITE}Transparency Options
 STR_TRANSPARENT_SIGNS_TOOLTIP                                   :{BLACK}Toggle transparency for station signs. Ctrl+Click to lock
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -79,6 +79,7 @@
 void MusicLoop();
 void ResetMusic();
 void CallWindowTickEvent();
+bool HandleBootstrap();
 
 extern void SetDifficultyLevel(int mode, DifficultySettings *gm_opt);
 extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
@@ -297,7 +298,8 @@
 
 	PoolBase::Clean(PT_ALL);
 
-	ResetNewGRFData();
+	/* No NewGRFs were loaded when it was still bootstrapping. */
+	if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
 
 	/* Close all and any open filehandles */
 	FioCloseAll();
@@ -717,10 +719,8 @@
 	free(sounds_set);
 
 	if (graphics_set == NULL && BaseGraphics::ini_set != NULL) graphics_set = strdup(BaseGraphics::ini_set);
-	if (!BaseGraphics::SetSet(graphics_set)) {
-		StrEmpty(graphics_set) ?
-			usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 4.1 of readme.txt.") :
-			usererror("Failed to select requested graphics set '%s'", graphics_set);
+	if (!BaseGraphics::SetSet(graphics_set) && !StrEmpty(graphics_set)) {
+		usererror("Failed to select requested graphics set '%s'", graphics_set);
 	}
 	free(graphics_set);
 
@@ -739,7 +739,7 @@
 	if (blitter == NULL && _ini_blitter != NULL) blitter = strdup(_ini_blitter);
 	_blitter_autodetected = StrEmpty(blitter);
 	/* If we have a 32 bpp base set, try to select the 32 bpp blitter first, but only if we autoprobe the blitter. */
-	if (!_blitter_autodetected || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP || BlitterFactoryBase::SelectBlitter("32bpp-anim") == NULL) {
+	if (!_blitter_autodetected || BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP || BlitterFactoryBase::SelectBlitter("32bpp-anim") == NULL) {
 		if (BlitterFactoryBase::SelectBlitter(blitter) == NULL) {
 			StrEmpty(blitter) ?
 				usererror("Failed to autoprobe blitter") :
@@ -780,12 +780,14 @@
 	/* Initialize the zoom level of the screen to normal */
 	_screen.zoom = ZOOM_LVL_NORMAL;
 
+	NetworkStartUp(); // initialize network-core
+
+	if (!HandleBootstrap()) goto exit;
+
 	/* restore saved music volume */
 	_music_driver->SetVolume(_settings_client.music.music_vol);
 	_video_driver->ClaimMousePointer();
 
-	NetworkStartUp(); // initialize network-core
-
 #if defined(ENABLE_NETWORK)
 	if (debuglog_conn != NULL && _network_available) {
 		const char *not_used = NULL;
@@ -825,6 +827,7 @@
 		SaveToHighScore();
 	}
 
+exit:
 	/* Reset windowing system, stop drivers, free used memory, ... */
 	ShutdownGame();
 
@@ -841,7 +844,7 @@
 
 void HandleExitGameRequest()
 {
-	if (_game_mode == GM_MENU) { // do not ask to quit on the main screen
+	if (_game_mode == GM_MENU || _game_mode == GM_BOOTSTRAP) { // do not ask to quit on the main screen
 		_exit_game = true;
 	} else if (_settings_client.gui.autosave_on_exit) {
 		DoExitSave();
@@ -1317,6 +1320,15 @@
 
 void GameLoop()
 {
+	if (_game_mode == GM_BOOTSTRAP) {
+#ifdef ENABLE_NETWORK
+		/* Check for UDP stuff */
+		if (_network_available) NetworkUDPGameLoop();
+#endif
+		InputLoop();
+		return;
+	}
+
 	ProcessAsyncSaveFinish();
 
 	/* autosave game? */
--- a/src/openttd.h
+++ b/src/openttd.h
@@ -19,6 +19,7 @@
 	GM_MENU,
 	GM_NORMAL,
 	GM_EDITOR,
+	GM_BOOTSTRAP
 };
 
 /** Mode which defines what mode we're switching to. */
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -2786,6 +2786,10 @@
 		/* XXX - this probably needs something more sane. For example specifying
 		 * in a 'backup'-desc that the window should always be centered. */
 		switch (w->window_class) {
+			case WC_BOOTSTRAP:
+				ResizeWindow(w, neww, newh);
+				continue;
+
 			case WC_MAIN_TOOLBAR:
 				ResizeWindow(w, min(neww, *_preferred_toolbar_size) - w->width, 0);
 
--- a/src/window_type.h
+++ b/src/window_type.h
@@ -84,6 +84,7 @@
 	WC_CHEATS,
 	WC_PERFORMANCE_DETAIL,
 	WC_CONSOLE,
+	WC_BOOTSTRAP,
 	WC_EXTRA_VIEW_PORT,
 	WC_CLIENT_LIST,
 	WC_NETWORK_STATUS_WINDOW,