← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/moved-classes into lp:widelands

 

Shevonar has proposed merging lp:~widelands-dev/widelands/moved-classes into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/moved-classes/+merge/212302

Moved classes from wlapplication.cc to own files.
-- 
https://code.launchpad.net/~widelands-dev/widelands/moved-classes/+merge/212302
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/moved-classes into lp:widelands.
=== removed file 'src/gamecontroller.cc'
--- src/gamecontroller.cc	2014-02-22 18:04:02 +0000
+++ src/gamecontroller.cc	1970-01-01 00:00:00 +0000
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2008-2009 by the Widelands Development Team
- *
- * This program 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; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include "gamecontroller.h"
-
-#include "computer_player.h"
-#include "logic/game.h"
-#include "logic/player.h"
-#include "logic/playercommand.h"
-#include "logic/playersmanager.h"
-#include "profile/profile.h"
-#include "wlapplication.h"
-
-struct SinglePlayerGameController : public GameController {
-	SinglePlayerGameController
-		(Widelands::Game &, bool useai, Widelands::Player_Number local);
-	~SinglePlayerGameController();
-
-	void think() override;
-	void sendPlayerCommand(Widelands::PlayerCommand &) override;
-	int32_t getFrametime() override;
-	std::string getGameDescription() override;
-
-	uint32_t realSpeed() override;
-	uint32_t desiredSpeed() override;
-	void setDesiredSpeed(uint32_t speed) override;
-	bool isPaused() override;
-	void setPaused(bool paused) override;
-	void report_result(uint8_t player, Widelands::PlayerEndResult result, const std::string & info) override;
-
-private:
-	Widelands::Game & m_game;
-	bool m_useai;
-	int32_t m_lastframe;
-	int32_t m_time;
-	uint32_t m_speed; ///< current game speed, in milliseconds per second
-	bool m_paused;
-	uint32_t m_player_cmdserial;
-	Widelands::Player_Number m_local;
-	std::vector<Computer_Player *> m_computerplayers;
-};
-
-SinglePlayerGameController::SinglePlayerGameController
-	(Widelands::Game        &       game,
-	 bool                     const useai,
-	 Widelands::Player_Number const local)
-	: m_game          (game),
-	m_useai           (useai),
-	m_lastframe       (WLApplication::get()->get_time()),
-	m_time            (m_game.get_gametime()),
-	m_speed(1000),
-	m_paused(false),
-	m_player_cmdserial(0),
-	m_local           (local)
-{
-}
-
-SinglePlayerGameController::~SinglePlayerGameController()
-{
-	for (uint32_t i = 0; i < m_computerplayers.size(); ++i)
-		delete m_computerplayers[i];
-	m_computerplayers.clear();
-}
-
-void SinglePlayerGameController::think()
-{
-	int32_t const curtime = WLApplication::get()->get_time();
-	int32_t frametime = curtime - m_lastframe;
-	m_lastframe = curtime;
-
-	// prevent crazy frametimes
-	if (frametime < 0)
-		frametime = 0;
-	else if (frametime > 1000)
-		frametime = 1000;
-
-	frametime = frametime * realSpeed() / 1000;
-
-	m_time = m_game.get_gametime() + frametime;
-
-	if (m_useai && m_game.is_loaded()) {
-		const Widelands::Player_Number nr_players = m_game.map().get_nrplayers();
-		iterate_players_existing(p, nr_players, m_game, plr)
-			if (p != m_local) {
-
-				if (p > m_computerplayers.size())
-					m_computerplayers.resize(p);
-				if (!m_computerplayers[p - 1])
-					m_computerplayers[p - 1] =
-						Computer_Player::getImplementation
-							(plr->getAI())->instantiate(m_game, p);
-				m_computerplayers[p - 1]->think();
-			}
-	}
-}
-
-void SinglePlayerGameController::sendPlayerCommand
-	(Widelands::PlayerCommand & pc)
-{
-	pc.set_cmdserial(++m_player_cmdserial);
-	m_game.enqueue_command (&pc);
-}
-
-int32_t SinglePlayerGameController::getFrametime()
-{
-	return m_time - m_game.get_gametime();
-}
-
-std::string SinglePlayerGameController::getGameDescription()
-{
-	return "singleplayer";
-}
-
-uint32_t SinglePlayerGameController::realSpeed()
-{
-	if (m_paused)
-		return 0;
-	else
-		return m_speed;
-}
-
-uint32_t SinglePlayerGameController::desiredSpeed()
-{
-	return m_speed;
-}
-
-void SinglePlayerGameController::setDesiredSpeed(uint32_t const speed)
-{
-	m_speed = speed;
-}
-
-bool SinglePlayerGameController::isPaused()
-{
-	return m_paused;
-}
-
-void SinglePlayerGameController::setPaused(bool paused)
-{
-	m_paused = paused;
-}
-
-void SinglePlayerGameController::report_result
-	(uint8_t p_nr, Widelands::PlayerEndResult result, const std::string & info)
-{
-	Widelands::PlayerEndStatus pes;
-	Widelands::Player* player = m_game.get_player(p_nr);
-	assert(player);
-	pes.player = player->player_number();
-	pes.time = m_game.get_gametime();
-	pes.result = result;
-	pes.info = info;
-	m_game.player_manager()->add_player_end_status(pes);
-}
-
-GameController * GameController::createSinglePlayer
-	(Widelands::Game        &       game,
-	 bool                     const cpls,
-	 Widelands::Player_Number const local)
-{
-	SinglePlayerGameController* spgc =  new SinglePlayerGameController(game, cpls, local);
-	return spgc;
-}

=== modified file 'src/gamecontroller.h'
--- src/gamecontroller.h	2013-09-22 18:01:36 +0000
+++ src/gamecontroller.h	2014-03-22 21:22:56 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2011, 2013 by the Widelands Development Team
+ * Copyright (C) 2008-2011, 2013, 2014 by the Widelands Development Team
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -40,7 +40,8 @@
  * vs. multiplayer vs. replay issues and have a \ref GameController
  * handle all that.
  */
-struct GameController {
+class GameController {
+public:
 	virtual ~GameController() {}
 
 	virtual void think() = 0;
@@ -83,15 +84,6 @@
 	}
 
 	/**
-	 * Allocate a new \ref GameController suitable for normal singleplayer.
-	 * \param cpls is \c true when computer players should be generated
-	 * \return newly allocated \ref GameController object, must be freed
-	 * by the caller.
-	 */
-	static GameController * createSinglePlayer
-		(Widelands::Game &, bool cpls, Widelands::Player_Number local);
-
-	/**
 	 * Report a player result once he has left the game. This may be done through lua
 	 * by the win_condition scripts.
 	 * \param player : the player idx;

=== modified file 'src/logic/game.cc'
--- src/logic/game.cc	2014-03-16 20:55:15 +0000
+++ src/logic/game.cc	2014-03-22 21:22:56 +0000
@@ -32,7 +32,6 @@
 #include "economy/economy.h"
 #include "game_io/game_loader.h"
 #include "game_io/game_preload_data_packet.h"
-#include "gamecontroller.h"
 #include "gamesettings.h"
 #include "graphic/graphic.h"
 #include "i18n.h"
@@ -57,6 +56,7 @@
 #include "profile/profile.h"
 #include "scripting/scripting.h"
 #include "sound/sound_handler.h"
+#include "sp_gamecontroller.h"
 #include "timestring.h"
 #include "ui_basic/progresswindow.h"
 #include "upcast.h"
@@ -255,7 +255,7 @@
 	maploader->load_map_complete(*this, true);
 	maploader.reset();
 
-	set_game_controller(GameController::createSinglePlayer(*this, true, 1));
+	set_game_controller(new SinglePlayerGameController(*this, true, 1));
 	try {
 		bool const result = run(&loaderUI, NewSPScenario, script_to_run, false);
 		delete m_ctrl;
@@ -412,7 +412,7 @@
 	// Store the filename for further saves
 	save_handler().set_current_filename(filename);
 
-	set_game_controller(GameController::createSinglePlayer(*this, true, player_nr));
+	set_game_controller(new SinglePlayerGameController(*this, true, player_nr));
 	try {
 		bool const result = run(&loaderUI, Loaded, script_to_run, false);
 		delete m_ctrl;

=== added file 'src/replay_gamecontroller.h'
--- src/replay_gamecontroller.h	1970-01-01 00:00:00 +0000
+++ src/replay_gamecontroller.h	2014-03-22 21:22:56 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef REPLAY_GAME_CONTROLLER_H
+#define REPLAY_GAME_CONTROLLER_H
+
+#include "gamecontroller.h"
+#include "wlapplication.h"
+#include "logic/widelands.h"
+#include "ui_basic/messagebox.h"
+
+class ReplayGameController : public GameController {
+public:
+	ReplayGameController(Widelands::Game & game, const std::string & filename) :
+		m_game     (game),
+		m_lastframe(WLApplication::get()->get_time()),
+		m_time     (m_game.get_gametime()),
+		m_speed    (1000),
+		m_paused   (false)
+	{
+		m_game.set_game_controller(this);
+
+		// We have to create an empty map, otherwise nothing will load properly
+		game.set_map(new Widelands::Map);
+		m_replayreader.reset(new Widelands::ReplayReader(m_game, filename));
+	}
+
+	struct Cmd_ReplayEnd : public Widelands::Command {
+		Cmd_ReplayEnd (int32_t const _duetime) : Widelands::Command(_duetime) {}
+		virtual void execute (Widelands::Game & game) {
+			game.gameController()->setDesiredSpeed(0);
+			UI::WLMessageBox mmb
+				(game.get_ibase(),
+				 _("End of replay"),
+				 _
+				 	("The end of the replay has been reached and the game has "
+				 	 "been paused. You may unpause the game and continue watching "
+				 	 "if you want to."),
+				 UI::WLMessageBox::OK);
+			mmb.run();
+		}
+		virtual uint8_t id() const {return QUEUE_CMD_REPLAYEND;}
+	};
+
+	void think() {
+		int32_t curtime = WLApplication::get()->get_time();
+		int32_t frametime = curtime - m_lastframe;
+		m_lastframe = curtime;
+
+		// prevent crazy frametimes
+		if (frametime < 0)
+			frametime = 0;
+		else if (frametime > 1000)
+			frametime = 1000;
+
+		frametime = frametime * realSpeed() / 1000;
+
+		m_time = m_game.get_gametime() + frametime;
+
+		if (m_replayreader) {
+			while
+				(Widelands::Command * const cmd =
+				 	m_replayreader->GetNextCommand(m_time))
+				m_game.enqueue_command(cmd);
+
+			if (m_replayreader->EndOfReplay()) {
+				m_replayreader.reset(nullptr);
+				m_game.enqueue_command
+					(new Cmd_ReplayEnd(m_time = m_game.get_gametime()));
+			}
+		}
+	}
+
+	void sendPlayerCommand(Widelands::PlayerCommand &)
+	{
+		throw wexception("Trying to send a player command during replay");
+	}
+	int32_t getFrametime() {
+		return m_time - m_game.get_gametime();
+	}
+	std::string getGameDescription() {
+		return "replay";
+	}
+	uint32_t realSpeed() {return m_paused ? 0 : m_speed;}
+	uint32_t desiredSpeed() {return m_speed;}
+	void setDesiredSpeed(uint32_t const speed) {m_speed = speed;}
+	bool isPaused() {return m_paused;}
+	void setPaused(bool const paused) {m_paused = paused;}
+
+private:
+	Widelands::Game & m_game;
+	std::unique_ptr<Widelands::ReplayReader> m_replayreader;
+	int32_t m_lastframe;
+	int32_t m_time;
+	uint32_t m_speed;
+	bool m_paused;
+};
+
+#endif

=== added file 'src/sp_game_settings_provider.h'
--- src/sp_game_settings_provider.h	1970-01-01 00:00:00 +0000
+++ src/sp_game_settings_provider.h	2014-03-22 21:22:56 +0000
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2014 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef SP_GAME_SETTINGS_PROVIDE_H
+#define SP_GAME_SETTINGS_PROVIDE_H
+
+#include "gamesettings.h"
+#include "logic/tribe.h"
+
+// The settings provider for normal singleplayer games:
+// The user can change everything, except that they are themselves human.
+struct SinglePlayerGameSettingsProvider : public GameSettingsProvider {
+	SinglePlayerGameSettingsProvider() {
+		s.tribes = Widelands::Tribe_Descr::get_all_tribe_infos();
+		s.scenario = false;
+		s.multiplayer = false;
+		s.playernum = 0;
+	}
+
+	virtual void setScenario(bool const set) {s.scenario = set;}
+
+	virtual const GameSettings & settings() {return s;}
+
+	virtual bool canChangeMap() {return true;}
+	virtual bool canChangePlayerState(uint8_t number) {
+		return (!s.scenario & (number != s.playernum));
+	}
+	virtual bool canChangePlayerTribe(uint8_t) {return !s.scenario;}
+	virtual bool canChangePlayerInit (uint8_t) {return !s.scenario;}
+	virtual bool canChangePlayerTeam(uint8_t) {return !s.scenario;}
+
+	virtual bool canLaunch() {
+		return s.mapname.size() != 0 && s.players.size() >= 1;
+	}
+
+	virtual std::string getMap() {
+		return s.mapfilename;
+	}
+
+	virtual void setMap
+		(const std::string &       mapname,
+		 const std::string &       mapfilename,
+		 uint32_t            const maxplayers,
+		 bool                const savegame)
+	{
+		s.mapname = mapname;
+		s.mapfilename = mapfilename;
+		s.savegame = savegame;
+
+		uint32_t oldplayers = s.players.size();
+		s.players.resize(maxplayers);
+
+		while (oldplayers < maxplayers) {
+			PlayerSettings & player = s.players[oldplayers];
+			player.state = (oldplayers == 0) ? PlayerSettings::stateHuman :
+				PlayerSettings::stateComputer;
+			player.tribe                = s.tribes.at(0).name;
+			player.random_tribe         = false;
+			player.initialization_index = 0;
+			char buf[200];
+			snprintf(buf, sizeof(buf), "%s %u", _("Player"), oldplayers + 1);
+			player.name = buf;
+			player.team = 0;
+			// Set default computerplayer ai type
+			if (player.state == PlayerSettings::stateComputer) {
+				const Computer_Player::ImplementationVector & impls =
+					Computer_Player::getImplementations();
+				if (impls.size() > 1) {
+					player.ai = impls.at(0)->name;
+					player.random_ai = false;
+				}
+			}
+			++oldplayers;
+		}
+	}
+
+	virtual void setPlayerState
+		(uint8_t const number, PlayerSettings::State state)
+	{
+		if (number == s.playernum || number >= s.players.size())
+			return;
+
+		if (state == PlayerSettings::stateOpen)
+			state = PlayerSettings::stateComputer;
+
+		s.players[number].state = state;
+	}
+
+	virtual void setPlayerAI(uint8_t const number, const std::string & ai, bool const random_ai) {
+		if (number < s.players.size()) {
+			s.players[number].ai = ai;
+			s.players[number].random_ai = random_ai;
+		}
+	}
+
+	virtual void nextPlayerState(uint8_t const number) {
+		if (number == s.playernum || number >= s.players.size())
+			return;
+
+		const Computer_Player::ImplementationVector & impls =
+			Computer_Player::getImplementations();
+		if (impls.size() > 1) {
+			Computer_Player::ImplementationVector::const_iterator it =
+				impls.begin();
+			do {
+				++it;
+				if ((*(it - 1))->name == s.players[number].ai)
+					break;
+			} while (it != impls.end());
+			if (s.players[number].random_ai) {
+				s.players[number].random_ai = false;
+				it = impls.begin();
+			} else if (it == impls.end()) {
+				s.players[number].random_ai = true;
+				do {
+					uint8_t random = (std::rand() % impls.size()); // Choose a random AI
+					it = impls.begin() + random;
+				} while ((*it)->name == "None");
+			}
+			s.players[number].ai = (*it)->name;
+		}
+
+		s.players[number].state = PlayerSettings::stateComputer;
+	}
+
+	virtual void setPlayerTribe(uint8_t const number, const std::string & tribe, bool const random_tribe)
+	{
+		if (number >= s.players.size())
+			return;
+
+		std::string actual_tribe = tribe;
+		PlayerSettings & player = s.players[number];
+		player.random_tribe = random_tribe;
+
+		if (random_tribe) {
+			uint8_t num_tribes = s.tribes.size();
+			uint8_t random = (std::rand() % num_tribes);
+			actual_tribe = s.tribes.at(random).name;
+		}
+
+		container_iterate_const(std::vector<TribeBasicInfo>, s.tribes, i)
+			if (i.current->name == player.tribe) {
+				s.players[number].tribe = actual_tribe;
+				if
+					(i.current->initializations.size()
+					 <=
+					 player.initialization_index)
+					player.initialization_index = 0;
+			}
+	}
+
+	virtual void setPlayerInit(uint8_t const number, uint8_t const index) {
+		if (number >= s.players.size())
+			return;
+
+		container_iterate_const(std::vector<TribeBasicInfo>, s.tribes, i)
+			if (i.current->name == s.players[number].tribe) {
+				if (index < i.current->initializations.size())
+					s.players[number].initialization_index = index;
+				return;
+			}
+		assert(false);
+	}
+
+	virtual void setPlayerTeam(uint8_t number, Widelands::TeamNumber team) {
+		if (number < s.players.size())
+			s.players[number].team = team;
+	}
+
+	virtual void setPlayerCloseable(uint8_t, bool) {
+		// nothing to do
+	}
+
+	virtual void setPlayerShared(uint8_t, uint8_t) {
+		// nothing to do
+	}
+
+	virtual void setPlayerName(uint8_t const number, const std::string & name) {
+		if (number < s.players.size())
+			s.players[number].name = name;
+	}
+
+	virtual void setPlayer(uint8_t const number, PlayerSettings const ps) {
+		if (number < s.players.size())
+			s.players[number] = ps;
+	}
+
+	virtual void setPlayerNumber(uint8_t const number) {
+		if (number >= s.players.size())
+			return;
+		PlayerSettings const position = settings().players.at(number);
+		PlayerSettings const player = settings().players.at(settings().playernum);
+		if
+			(number < settings().players.size() and
+			 (position.state == PlayerSettings::stateOpen or
+			  position.state == PlayerSettings::stateComputer))
+		{
+			setPlayer(number, player);
+			setPlayer(settings().playernum, position);
+			s.playernum = number;
+		}
+	}
+
+	virtual std::string getWinCondition() {return s.win_condition;}
+	virtual void setWinCondition(std::string wc) {s.win_condition = wc;}
+	virtual void nextWinCondition() {assert(false);} // not implemented - feel free to do so, if you need it.
+
+private:
+	GameSettings s;
+};
+
+#endif

=== added file 'src/sp_gamecontroller.cc'
--- src/sp_gamecontroller.cc	1970-01-01 00:00:00 +0000
+++ src/sp_gamecontroller.cc	2014-03-22 21:22:56 +0000
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include "sp_gamecontroller.h"
+
+#include "computer_player.h"
+#include "logic/game.h"
+#include "logic/player.h"
+#include "logic/playercommand.h"
+#include "logic/playersmanager.h"
+#include "profile/profile.h"
+#include "wlapplication.h"
+
+
+SinglePlayerGameController::SinglePlayerGameController
+	(Widelands::Game        &       game,
+	 bool                     const useai,
+	 Widelands::Player_Number const local)
+	: m_game          (game),
+	m_useai           (useai),
+	m_lastframe       (WLApplication::get()->get_time()),
+	m_time            (m_game.get_gametime()),
+	m_speed
+		(g_options.pull_section("global").get_natural
+		 	("speed_of_new_game", 1000)),
+	m_paused(false),
+	m_player_cmdserial(0),
+	m_local           (local)
+{
+}
+
+SinglePlayerGameController::~SinglePlayerGameController()
+{
+	for (uint32_t i = 0; i < m_computerplayers.size(); ++i)
+		delete m_computerplayers[i];
+	m_computerplayers.clear();
+}
+
+void SinglePlayerGameController::think()
+{
+	int32_t const curtime = WLApplication::get()->get_time();
+	int32_t frametime = curtime - m_lastframe;
+	m_lastframe = curtime;
+
+	// prevent crazy frametimes
+	if (frametime < 0)
+		frametime = 0;
+	else if (frametime > 1000)
+		frametime = 1000;
+
+	frametime = frametime * realSpeed() / 1000;
+
+	m_time = m_game.get_gametime() + frametime;
+
+	if (m_useai && m_game.is_loaded()) {
+		const Widelands::Player_Number nr_players = m_game.map().get_nrplayers();
+		iterate_players_existing(p, nr_players, m_game, plr)
+			if (p != m_local) {
+
+				if (p > m_computerplayers.size())
+					m_computerplayers.resize(p);
+				if (!m_computerplayers[p - 1])
+					m_computerplayers[p - 1] =
+						Computer_Player::getImplementation
+							(plr->getAI())->instantiate(m_game, p);
+				m_computerplayers[p - 1]->think();
+			}
+	}
+}
+
+void SinglePlayerGameController::sendPlayerCommand
+	(Widelands::PlayerCommand & pc)
+{
+	pc.set_cmdserial(++m_player_cmdserial);
+	m_game.enqueue_command (&pc);
+}
+
+int32_t SinglePlayerGameController::getFrametime()
+{
+	return m_time - m_game.get_gametime();
+}
+
+std::string SinglePlayerGameController::getGameDescription()
+{
+	return "singleplayer";
+}
+
+uint32_t SinglePlayerGameController::realSpeed()
+{
+	if (m_paused)
+		return 0;
+	else
+		return m_speed;
+}
+
+uint32_t SinglePlayerGameController::desiredSpeed()
+{
+	return m_speed;
+}
+
+void SinglePlayerGameController::setDesiredSpeed(uint32_t const speed)
+{
+	m_speed = speed;
+}
+
+bool SinglePlayerGameController::isPaused()
+{
+	return m_paused;
+}
+
+void SinglePlayerGameController::setPaused(bool paused)
+{
+	m_paused = paused;
+}
+
+void SinglePlayerGameController::report_result
+	(uint8_t p_nr, Widelands::PlayerEndResult result, const std::string & info)
+{
+	Widelands::PlayerEndStatus pes;
+	Widelands::Player* player = m_game.get_player(p_nr);
+	assert(player);
+	pes.player = player->player_number();
+	pes.time = m_game.get_gametime();
+	pes.result = result;
+	pes.info = info;
+	m_game.player_manager()->add_player_end_status(pes);
+}

=== added file 'src/sp_gamecontroller.h'
--- src/sp_gamecontroller.h	1970-01-01 00:00:00 +0000
+++ src/sp_gamecontroller.h	2014-03-22 21:22:56 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef SP_GAMECONTROLLER_H
+#define SP_GAMECONTROLLER_H
+
+#include "gamecontroller.h"
+
+#include "computer_player.h"
+
+class SinglePlayerGameController : public GameController {
+public:
+	SinglePlayerGameController
+		(Widelands::Game &, bool useai, Widelands::Player_Number local);
+	~SinglePlayerGameController();
+
+	void think() override;
+	void sendPlayerCommand(Widelands::PlayerCommand &) override;
+	int32_t getFrametime() override;
+	std::string getGameDescription() override;
+
+	uint32_t realSpeed() override;
+	uint32_t desiredSpeed() override;
+	void setDesiredSpeed(uint32_t speed) override;
+	bool isPaused() override;
+	void setPaused(bool paused) override;
+	void report_result(uint8_t player, Widelands::PlayerEndResult result, const std::string & info) override;
+
+private:
+	Widelands::Game & m_game;
+	bool m_useai;
+	int32_t m_lastframe;
+	int32_t m_time;
+	uint32_t m_speed; ///< current game speed, in milliseconds per second
+	bool m_paused;
+	uint32_t m_player_cmdserial;
+	Widelands::Player_Number m_local;
+	std::vector<Computer_Player *> m_computerplayers;
+};
+
+#endif

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2014-03-20 14:44:00 +0000
+++ src/wlapplication.cc	2014-03-22 21:22:56 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2013 by the Widelands Development Team
+ * Copyright (C) 2006-2014 by the Widelands Development Team
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -59,7 +59,10 @@
 #include "network/netclient.h"
 #include "network/nethost.h"
 #include "profile/profile.h"
+#include "replay_gamecontroller.h"
 #include "sound/sound_handler.h"
+#include "sp_game_settings_provider.h"
+#include "sp_gamecontroller.h"
 #include "timestring.h"
 #include "ui_basic/messagebox.h"
 #include "ui_basic/progresswindow.h"
@@ -514,6 +517,8 @@
 		// log ("SDL Video Window expose event: %i\n", ev.expose.type);
 		g_gr->update_fullscreen();
 		break;
+	default:
+		break;
 	}
 	return true;
 }
@@ -1612,212 +1617,6 @@
 	}
 }
 
-// The settings provider for normal singleplayer games:
-// The user can change everything, except that they are themselves human.
-struct SinglePlayerGameSettingsProvider : public GameSettingsProvider {
-	SinglePlayerGameSettingsProvider() {
-		s.tribes = Widelands::Tribe_Descr::get_all_tribe_infos();
-		s.scenario = false;
-		s.multiplayer = false;
-		s.playernum = 0;
-	}
-
-	virtual void setScenario(bool const set) override {s.scenario = set;}
-
-	virtual const GameSettings & settings() override {return s;}
-
-	virtual bool canChangeMap() override {return true;}
-	virtual bool canChangePlayerState(uint8_t number) override {
-		return (!s.scenario & (number != s.playernum));
-	}
-	virtual bool canChangePlayerTribe(uint8_t) override {return !s.scenario;}
-	virtual bool canChangePlayerInit (uint8_t) override {return !s.scenario;}
-	virtual bool canChangePlayerTeam(uint8_t) override {return !s.scenario;}
-
-	virtual bool canLaunch() override {
-		return s.mapname.size() != 0 && s.players.size() >= 1;
-	}
-
-	virtual std::string getMap() {
-		return s.mapfilename;
-	}
-
-	virtual void setMap
-		(const std::string &       mapname,
-		 const std::string &       mapfilename,
-		 uint32_t            const maxplayers,
-		 bool                const savegame) override
-	{
-		s.mapname = mapname;
-		s.mapfilename = mapfilename;
-		s.savegame = savegame;
-
-		uint32_t oldplayers = s.players.size();
-		s.players.resize(maxplayers);
-
-		while (oldplayers < maxplayers) {
-			PlayerSettings & player = s.players[oldplayers];
-			player.state = (oldplayers == 0) ? PlayerSettings::stateHuman :
-				PlayerSettings::stateComputer;
-			player.tribe                = s.tribes.at(0).name;
-			player.random_tribe         = false;
-			player.initialization_index = 0;
-			char buf[200];
-			snprintf(buf, sizeof(buf), "%s %u", _("Player"), oldplayers + 1);
-			player.name = buf;
-			player.team = 0;
-			// Set default computerplayer ai type
-			if (player.state == PlayerSettings::stateComputer) {
-				const Computer_Player::ImplementationVector & impls =
-					Computer_Player::getImplementations();
-				if (impls.size() > 1) {
-					player.ai = impls.at(0)->name;
-					player.random_ai = false;
-				}
-			}
-			++oldplayers;
-		}
-	}
-
-	virtual void setPlayerState
-		(uint8_t const number, PlayerSettings::State state) override
-	{
-		if (number == s.playernum || number >= s.players.size())
-			return;
-
-		if (state == PlayerSettings::stateOpen)
-			state = PlayerSettings::stateComputer;
-
-		s.players[number].state = state;
-	}
-
-	virtual void setPlayerAI(uint8_t const number, const std::string & ai, bool const random_ai) override {
-		if (number < s.players.size()) {
-			s.players[number].ai = ai;
-			s.players[number].random_ai = random_ai;
-		}
-	}
-
-	virtual void nextPlayerState(uint8_t const number) override {
-		if (number == s.playernum || number >= s.players.size())
-			return;
-
-		const Computer_Player::ImplementationVector & impls =
-			Computer_Player::getImplementations();
-		if (impls.size() > 1) {
-			Computer_Player::ImplementationVector::const_iterator it =
-				impls.begin();
-			do {
-				++it;
-				if ((*(it - 1))->name == s.players[number].ai)
-					break;
-			} while (it != impls.end());
-			if (s.players[number].random_ai) {
-				s.players[number].random_ai = false;
-				it = impls.begin();
-			} else if (it == impls.end()) {
-				s.players[number].random_ai = true;
-				do {
-					uint8_t random = (std::rand() % impls.size()); // Choose a random AI
-					it = impls.begin() + random;
-				} while ((*it)->name == "None");
-			}
-			s.players[number].ai = (*it)->name;
-		}
-
-		s.players[number].state = PlayerSettings::stateComputer;
-	}
-
-	virtual void setPlayerTribe
-		(uint8_t const number, const std::string & tribe, bool const random_tribe) override
-	{
-		if (number >= s.players.size())
-			return;
-
-		std::string actual_tribe = tribe;
-		PlayerSettings & player = s.players[number];
-		player.random_tribe = random_tribe;
-
-		if (random_tribe) {
-			uint8_t num_tribes = s.tribes.size();
-			uint8_t random = (std::rand() % num_tribes);
-			actual_tribe = s.tribes.at(random).name;
-		}
-
-		container_iterate_const(std::vector<TribeBasicInfo>, s.tribes, i)
-			if (i.current->name == player.tribe) {
-				s.players[number].tribe = actual_tribe;
-				if
-					(i.current->initializations.size()
-					 <=
-					 player.initialization_index)
-					player.initialization_index = 0;
-			}
-	}
-
-	virtual void setPlayerInit(uint8_t const number, uint8_t const index) override {
-		if (number >= s.players.size())
-			return;
-
-		container_iterate_const(std::vector<TribeBasicInfo>, s.tribes, i)
-			if (i.current->name == s.players[number].tribe) {
-				if (index < i.current->initializations.size())
-					s.players[number].initialization_index = index;
-				return;
-			}
-		assert(false);
-	}
-
-	virtual void setPlayerTeam(uint8_t number, Widelands::TeamNumber team) override {
-		if (number < s.players.size())
-			s.players[number].team = team;
-	}
-
-	virtual void setPlayerCloseable(uint8_t, bool) override {
-		// nothing to do
-	}
-
-	virtual void setPlayerShared(uint8_t, uint8_t) override {
-		// nothing to do
-	}
-
-	virtual void setPlayerName(uint8_t const number, const std::string & name) override {
-		if (number < s.players.size())
-			s.players[number].name = name;
-	}
-
-	virtual void setPlayer(uint8_t const number, PlayerSettings const ps) override {
-		if (number < s.players.size())
-			s.players[number] = ps;
-	}
-
-	virtual void setPlayerNumber(uint8_t const number) override {
-		if (number >= s.players.size())
-			return;
-		PlayerSettings const position = settings().players.at(number);
-		PlayerSettings const player = settings().players.at(settings().playernum);
-		if
-			(number < settings().players.size() and
-			 (position.state == PlayerSettings::stateOpen or
-			  position.state == PlayerSettings::stateComputer))
-		{
-			setPlayer(number, player);
-			setPlayer(settings().playernum, position);
-			s.playernum = number;
-		}
-	}
-
-	virtual std::string getWinCondition() override {return s.win_condition;}
-	virtual void setWinCondition(std::string wc) override {s.win_condition = wc;}
-	virtual void nextWinCondition() override // not implemented - feel free to do so, if you need it
-	{
-		assert(false);
-	}
-
-private:
-	GameSettings s;
-};
-
 /**
  * Handle the "New game" menu option: Configure a single player game and
  * run it.
@@ -1851,7 +1650,7 @@
 				(new Interactive_Player
 					(game, g_options.pull_section("global"), pn, false, false));
 			std::unique_ptr<GameController> ctrl
-				(GameController::createSinglePlayer(game, true, pn));
+				(new SinglePlayerGameController(game, true, pn));
 			UI::ProgressWindow loaderUI;
 			std::vector<std::string> tipstext;
 			tipstext.push_back("general_game");
@@ -1949,92 +1748,6 @@
 	return false;
 }
 
-struct ReplayGameController : public GameController {
-	ReplayGameController(Widelands::Game & game, const std::string & filename) :
-		m_game     (game),
-		m_lastframe(WLApplication::get()->get_time()),
-		m_time     (m_game.get_gametime()),
-		m_speed    (1000),
-		m_paused   (false)
-	{
-		m_game.set_game_controller(this);
-
-		// We have to create an empty map, otherwise nothing will load properly
-		game.set_map(new Widelands::Map);
-		m_replayreader.reset(new Widelands::ReplayReader(m_game, filename));
-	}
-
-	struct Cmd_ReplayEnd : public Widelands::Command {
-		Cmd_ReplayEnd (int32_t const _duetime) : Widelands::Command(_duetime) {}
-		virtual void execute (Widelands::Game & game) override {
-			game.gameController()->setDesiredSpeed(0);
-			UI::WLMessageBox mmb
-				(game.get_ibase(),
-				 _("End of replay"),
-				 _
-				 	("The end of the replay has been reached and the game has "
-				 	 "been paused. You may unpause the game and continue watching "
-				 	 "if you want to."),
-				 UI::WLMessageBox::OK);
-			mmb.run();
-		}
-		virtual uint8_t id() const override {return QUEUE_CMD_REPLAYEND;}
-	};
-
-	void think() override {
-		int32_t curtime = WLApplication::get()->get_time();
-		int32_t frametime = curtime - m_lastframe;
-		m_lastframe = curtime;
-
-		// prevent crazy frametimes
-		if (frametime < 0)
-			frametime = 0;
-		else if (frametime > 1000)
-			frametime = 1000;
-
-		frametime = frametime * realSpeed() / 1000;
-
-		m_time = m_game.get_gametime() + frametime;
-
-		if (m_replayreader) {
-			while
-				(Widelands::Command * const cmd =
-				 	m_replayreader->GetNextCommand(m_time))
-				m_game.enqueue_command(cmd);
-
-			if (m_replayreader->EndOfReplay()) {
-				m_replayreader.reset(nullptr);
-				m_game.enqueue_command
-					(new Cmd_ReplayEnd(m_time = m_game.get_gametime()));
-			}
-		}
-	}
-
-	void sendPlayerCommand(Widelands::PlayerCommand &) override
-	{
-		throw wexception("Trying to send a player command during replay");
-	}
-	int32_t getFrametime() override {
-		return m_time - m_game.get_gametime();
-	}
-	std::string getGameDescription() override {
-		return "replay";
-	}
-	uint32_t realSpeed() override {return m_paused ? 0 : m_speed;}
-	uint32_t desiredSpeed() override {return m_speed;}
-	void setDesiredSpeed(uint32_t const speed) override {m_speed = speed;}
-	bool isPaused() override {return m_paused;}
-	void setPaused(bool const paused) override {m_paused = paused;}
-
-private:
-	Widelands::Game & m_game;
-	std::unique_ptr<Widelands::ReplayReader> m_replayreader;
-	int32_t m_lastframe;
-	int32_t m_time;
-	uint32_t m_speed;
-	bool m_paused;
-};
-
 /**
  * Show the replay menu and play a replay.
  */


Follow ups