← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~shevonar/widelands/feature-random-tribe-and-AI into lp:widelands

 

Shevonar has proposed merging lp:~shevonar/widelands/feature-random-tribe-and-AI into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #722757 in widelands: "Play as a random tribe"
  https://bugs.launchpad.net/widelands/+bug/722757
  Bug #771379 in widelands: "Play against a random AI strength (defensive, aggressive, normal)"
  https://bugs.launchpad.net/widelands/+bug/771379
  Bug #853217 in widelands: "start multiplayer game with all slots closed"
  https://bugs.launchpad.net/widelands/+bug/853217

For more details, see:
https://code.launchpad.net/~shevonar/widelands/feature-random-tribe-and-AI/+merge/75897

Adds a random option for tribes and AI-tactics in singleplayer and multiplayer mode.
Fixes bug #853217
-- 
https://code.launchpad.net/~shevonar/widelands/feature-random-tribe-and-AI/+merge/75897
Your team Widelands Developers is requested to review the proposed merge of lp:~shevonar/widelands/feature-random-tribe-and-AI into lp:widelands.
=== modified file 'ChangeLog'
--- ChangeLog	2011-09-04 19:44:46 +0000
+++ ChangeLog	2011-09-18 13:52:27 +0000
@@ -9,6 +9,8 @@
 - Added a new win condition "endless game (no fog)" with completely
   visible map from the beginning on.
 - Added a multiplayer scenario
+- Added feature to play as a random tribe or against a random tribe or 
+  random AI.
 - Improved dedicated server functionality:
     * added functionality to save the game on the server via chat command.
     * added functionality to set up a password for the server.
@@ -24,6 +26,7 @@
 - Fixed bug #795457: focus in chat window
 - Fixed bug #808008: Delete outdated data when updating Widelands on Windows
 - Fixed bug #805089: Check client in chat commands, when first mentioned.
+- Fixed bug #853217: start multiplayer game with all slots closed
 
 ### Build 16
 - Many new graphics, new sounds.

=== added file 'pics/ai_Random.png'
Binary files pics/ai_Random.png	1970-01-01 00:00:00 +0000 and pics/ai_Random.png	2011-09-18 13:52:27 +0000 differ
=== added file 'pics/random.png'
Binary files pics/random.png	1970-01-01 00:00:00 +0000 and pics/random.png	2011-09-18 13:52:27 +0000 differ
=== modified file 'src/gamesettings.h'
--- src/gamesettings.h	2011-08-26 08:59:21 +0000
+++ src/gamesettings.h	2011-09-18 13:52:27 +0000
@@ -40,7 +40,9 @@
 	uint8_t     initialization_index;
 	std::string name;
 	std::string tribe;
+	bool random_tribe;
 	std::string ai; /**< Preferred AI provider for this player */
+	bool random_ai;
 	Widelands::TeamNumber team;
 	bool closeable; // only used in multiplayer scenario maps
 	uint8_t shared_in; // the number of the player that uses this player's starting position
@@ -136,9 +138,9 @@
 		 bool                savegame = false)
 		= 0;
 	virtual void setPlayerState    (uint8_t number, PlayerSettings::State) = 0;
-	virtual void setPlayerAI       (uint8_t number, std::string const &) = 0;
+	virtual void setPlayerAI       (uint8_t number, std::string const &, bool const random_ai = false) = 0;
 	virtual void nextPlayerState   (uint8_t number) = 0;
-	virtual void setPlayerTribe    (uint8_t number, std::string const &) = 0;
+	virtual void setPlayerTribe    (uint8_t number, std::string const &, bool const random_tribe = false) = 0;
 	virtual void setPlayerInit     (uint8_t number, uint8_t index) = 0;
 	virtual void setPlayerName     (uint8_t number, std::string const &) = 0;
 	virtual void setPlayer         (uint8_t number, PlayerSettings) = 0;

=== modified file 'src/network/netclient.cc'
--- src/network/netclient.cc	2011-08-26 08:59:21 +0000
+++ src/network/netclient.cc	2011-09-18 13:52:27 +0000
@@ -396,7 +396,7 @@
 	// client is not allowed to do this
 }
 
-void NetClient::setPlayerAI(uint8_t, std::string const &)
+void NetClient::setPlayerAI(uint8_t, std::string const &, bool const random_ai)
 {
 	// client is not allowed to do this
 }
@@ -412,7 +412,7 @@
 	s.send(d->sock);
 }
 
-void NetClient::setPlayerTribe(uint8_t number, const std::string & tribe)
+void NetClient::setPlayerTribe(uint8_t number, const std::string & tribe, bool const random_tribe)
 {
 	if ((number != d->settings.playernum) && !m_dedicated_access)
 		return;
@@ -421,6 +421,7 @@
 	s.Unsigned8(NETCMD_SETTING_CHANGETRIBE);
 	s.Unsigned8(number);
 	s.String(tribe);
+	s.Unsigned8(random_tribe ? 1 : 0);
 	s.send(d->sock);
 }
 
@@ -562,8 +563,10 @@
 	player.state = static_cast<PlayerSettings::State>(packet.Unsigned8());
 	player.name = packet.String();
 	player.tribe = packet.String();
+	player.random_tribe = packet.Unsigned8() == 1;
 	player.initialization_index = packet.Unsigned8();
 	player.ai = packet.String();
+	player.random_ai = packet.Unsigned8() == 1;
 	player.team = packet.Unsigned8();
 	player.shared_in = packet.Unsigned8();
 }

=== modified file 'src/network/netclient.h'
--- src/network/netclient.h	2011-08-26 08:59:21 +0000
+++ src/network/netclient.h	2011-09-18 13:52:27 +0000
@@ -76,9 +76,9 @@
 		 uint32_t maxplayers,
 		 bool savegame = false);
 	virtual void setPlayerState    (uint8_t number, PlayerSettings::State state);
-	virtual void setPlayerAI       (uint8_t number, std::string const & ai);
+	virtual void setPlayerAI       (uint8_t number, std::string const & ai, bool const random_ai = false);
 	virtual void nextPlayerState   (uint8_t number);
-	virtual void setPlayerTribe    (uint8_t number, std::string const & tribe);
+	virtual void setPlayerTribe    (uint8_t number, std::string const & tribe, bool const random_tribe = false);
 	virtual void setPlayerInit     (uint8_t number, uint8_t index);
 	virtual void setPlayerName     (uint8_t number, std::string const & name);
 	virtual void setPlayer         (uint8_t number, PlayerSettings ps);

=== modified file 'src/network/nethost.cc'
--- src/network/nethost.cc	2011-08-28 16:49:49 +0000
+++ src/network/nethost.cc	2011-09-18 13:52:27 +0000
@@ -152,7 +152,7 @@
 					if ((*(it - 1))->name == h->settings().players.at(number).ai)
 						break;
 				} while (it != impls.end());
-				if (it == impls.end()) {
+				if (settings().players.at(number).random_ai) {
 					setPlayerAI(number, std::string());
 					setPlayerName(number, std::string());
 					// Do not share a player in savegames or scenarios
@@ -173,6 +173,12 @@
 						} else
 							newstate = PlayerSettings::stateClosed;
 					}
+				} else if (it == impls.end()) {
+					uint8_t random = (std::rand() % impls.size()); // Choose a random AI
+					it = impls.begin() + random;
+					setPlayerAI(number, (*it)->name, true);
+					newstate = PlayerSettings::stateComputer;
+					break;
 				} else {
 					setPlayerAI(number, (*it)->name);
 					newstate = PlayerSettings::stateComputer;
@@ -193,7 +199,7 @@
 		h->setPlayerState(number, newstate, true);
 	}
 
-	virtual void setPlayerTribe(uint8_t const number, std::string const & tribe)
+	virtual void setPlayerTribe(uint8_t const number, std::string const & tribe, bool const random_tribe)
 	{
 		if (number >= h->settings().players.size())
 			return;
@@ -207,8 +213,9 @@
 			 ||
 			 settings().players.at(number).state == PlayerSettings::stateOpen // For savegame loading
 			)
-			h->setPlayerTribe(number, tribe);
+			h->setPlayerTribe(number, tribe, random_tribe);
 	}
+
 	virtual void setPlayerTeam(uint8_t number, Widelands::TeamNumber team)
 	{
 		if (number >= h->settings().players.size())
@@ -239,8 +246,9 @@
 		h->setPlayerInit(number, index);
 	}
 
-	virtual void setPlayerAI(uint8_t number, std::string const & name) {
-		h->setPlayerAI(number, name);
+	virtual void setPlayerAI(uint8_t number, std::string const & name,
+			bool const random_ai = false) {
+		h->setPlayerAI(number, name, random_ai);
 	}
 
 	virtual void setPlayerName(uint8_t const number, std::string const & name) {
@@ -1301,11 +1309,15 @@
 	if (d->game)
 		return false;
 	// all players must be connected to a controller (human/ai) or be closed.
+	// but not all should be closed!
+	bool one_not_closed = false;
 	for (size_t i = 0; i < d->settings.players.size(); ++i) {
+		if (d->settings.players.at(i).state != PlayerSettings::stateClosed)
+			one_not_closed = true;
 		if (d->settings.players.at(i).state == PlayerSettings::stateOpen)
 			return false;
 	}
-	return true;
+	return one_not_closed;
 }
 
 void NetHost::setMap
@@ -1356,9 +1368,11 @@
 		player.state                = PlayerSettings::stateOpen;
 		player.name                 = "";
 		player.tribe                = d->settings.tribes.at(0).name;
+		player.random_tribe         = false;
 		player.initialization_index = 0;
 		player.team                 = 0;
 		player.ai                   = "";
+		player.random_ai            = false;
 		player.closeable            = false;
 		player.shared_in            = 0;
 
@@ -1469,19 +1483,28 @@
 }
 
 
-void NetHost::setPlayerTribe(uint8_t const number, std::string const & tribe)
+void NetHost::setPlayerTribe(uint8_t const number, std::string const & tribe, bool const random_tribe)
 {
 	if (number >= d->settings.players.size())
 		return;
 
 	PlayerSettings & player = d->settings.players.at(number);
 
-	if (player.tribe == tribe)
+	if (player.tribe == tribe && player.random_tribe == random_tribe)
 		return;
 
+	std::string actual_tribe = tribe;
+	player.random_tribe = random_tribe;
+
+	if(random_tribe) {
+		uint8_t num_tribes = d->settings.tribes.size();
+		uint8_t random = (std::rand() % num_tribes);
+		actual_tribe = d->settings.tribes.at(random).name;
+	}
+
 	container_iterate_const(std::vector<TribeBasicInfo>, d->settings.tribes, i)
 		if (i.current->name == player.tribe) {
-			player.tribe = tribe;
+			player.tribe = actual_tribe;
 			if (i.current->initializations.size() <= player.initialization_index)
 				player.initialization_index = 0;
 
@@ -1530,13 +1553,14 @@
 }
 
 
-void NetHost::setPlayerAI(uint8_t number, std::string const & name)
+void NetHost::setPlayerAI(uint8_t number, std::string const & name, bool const random_ai)
 {
 	if (number >= d->settings.players.size())
 		return;
 
 	PlayerSettings & player = d->settings.players.at(number);
 	player.ai = name;
+	player.random_ai = random_ai;
 
 	// Broadcast changes
 	SendPacket s;
@@ -1769,8 +1793,10 @@
 	packet.Unsigned8(static_cast<uint8_t>(player.state));
 	packet.String(player.name);
 	packet.String(player.tribe);
+	packet.Unsigned8(player.random_tribe ? 1 : 0);
 	packet.Unsigned8(player.initialization_index);
 	packet.String(player.ai);
+	packet.Unsigned8(player.random_ai ? 1 : 0);
 	packet.Unsigned8(player.team);
 	packet.Unsigned8(player.shared_in);
 }
@@ -2430,7 +2456,9 @@
 				// Only valid if the server is dedicated and the client was granted access
 				if (!client.dedicated_access)
 					throw DisconnectException(_("Client has no access to other player's settings."));
-			setPlayerTribe(num, r.String());
+			std::string tribe = r.String();
+			bool random_tribe = r.Unsigned8() == 1;
+			setPlayerTribe(num, tribe, random_tribe);
 		}
 		break;
 

=== modified file 'src/network/nethost.h'
--- src/network/nethost.h	2011-08-28 16:49:49 +0000
+++ src/network/nethost.h	2011-09-18 13:52:27 +0000
@@ -67,9 +67,9 @@
 		 uint32_t            maxplayers,
 		 bool                savegame = false);
 	void setPlayerState    (uint8_t number, PlayerSettings::State state, bool host = false);
-	void setPlayerTribe    (uint8_t number, std::string const & tribe);
+	void setPlayerTribe    (uint8_t number, std::string const & tribe, bool const random_tribe = false);
 	void setPlayerInit     (uint8_t number, uint8_t index);
-	void setPlayerAI       (uint8_t number, std::string const & name);
+	void setPlayerAI       (uint8_t number, std::string const & name, bool const random_ai = false);
 	void setPlayerName     (uint8_t number, std::string const & name);
 	void setPlayer         (uint8_t number, PlayerSettings);
 	void setPlayerNumber   (uint8_t number);

=== modified file 'src/network/network_player_settings_backend.cc'
--- src/network/network_player_settings_backend.cc	2011-08-25 11:27:28 +0000
+++ src/network/network_player_settings_backend.cc	2011-09-18 13:52:27 +0000
@@ -43,15 +43,27 @@
 		return;
 
 	if (settings.players.at(id).state != PlayerSettings::stateShared) {
-		std::string const & currenttribe = settings.players.at(id).tribe;
+		PlayerSettings const & player = settings.players.at(id);
+		std::string const & currenttribe = player.tribe;
 		std::string nexttribe = settings.tribes.at(0).name;
+		uint32_t num_tribes = settings.tribes.size();
+		bool random_tribe = false;
 
-		for (uint32_t i = 0; i < settings.tribes.size() - 1; ++i)
-			if (settings.tribes[i].name == currenttribe) {
-				nexttribe = settings.tribes.at(i + 1).name;
-				break;
+		if (player.random_tribe) {
+			nexttribe = settings.tribes.at(0).name;
+		} else if (player.tribe == settings.tribes.at(num_tribes - 1).name) {
+			nexttribe = "Random";
+			random_tribe = true;
+		} else {
+			for (uint32_t i = 0; i < num_tribes - 1; ++i) {
+				if (settings.tribes[i].name == currenttribe) {
+					nexttribe = settings.tribes.at(i + 1).name;
+					break;
+				}
 			}
-		s->setPlayerTribe(id, nexttribe);
+		}
+
+		s->setPlayerTribe(id, nexttribe, random_tribe);
 	} else {
 		// This button is temporarily used to select the player that uses this starting position
 		uint8_t sharedplr = settings.players.at(id).shared_in;
@@ -144,7 +156,8 @@
 			toggle_tribe(id);
 
 		if (shared_in_tribe[id] != settings.players.at(player.shared_in - 1).tribe) {
-			s->setPlayerTribe(id, settings.players.at(player.shared_in - 1).tribe);
+			s->setPlayerTribe(id, settings.players.at(player.shared_in - 1).tribe,
+					settings.players.at(player.shared_in - 1).random_tribe);
 			shared_in_tribe[id] = settings.players.at(id).tribe;
 		}
 	}

=== modified file 'src/network/network_protocol.h'
--- src/network/network_protocol.h	2011-08-26 08:59:21 +0000
+++ src/network/network_protocol.h	2011-09-18 13:52:27 +0000
@@ -28,7 +28,7 @@
 	 * The current version of the in-game network protocol. Client and host
 	 * protocol versions must match.
 	 */
-	NETWORK_PROTOCOL_VERSION = 19,
+	NETWORK_PROTOCOL_VERSION = 20,
 
 	/**
 	 * The default interval (in milliseconds) in which the host issues
@@ -271,6 +271,7 @@
 	 * to a different tribe. Payload is
 	 * \li Unsigned8: player number
 	 * \li String:    name of tribe
+	 * \li bool:      random_tribe
 	 *
 	 * The client must not assume that the host will accept this request.
 	 * The host may or may not send a \ref NETCMD_SETTING_ALLPLAYERS or

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2011-07-07 16:47:45 +0000
+++ src/wlapplication.cc	2011-09-18 13:52:27 +0000
@@ -1845,6 +1845,7 @@
 			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);
@@ -1854,8 +1855,10 @@
 			if (player.state == PlayerSettings::stateComputer) {
 				Computer_Player::ImplementationVector const & impls =
 					Computer_Player::getImplementations();
-				if (impls.size() > 1)
+				if (impls.size() > 1) {
 					player.ai = impls.at(0)->name;
+					player.random_ai = false;
+				}
 			}
 			++oldplayers;
 		}
@@ -1873,10 +1876,13 @@
 		s.players[number].state = state;
 	}
 
-	virtual void setPlayerAI(uint8_t const number, std::string const & ai) {
-		if (number < s.players.size())
+	virtual void setPlayerAI(uint8_t const number, std::string const & 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;
@@ -1891,23 +1897,38 @@
 				if ((*(it - 1))->name == s.players[number].ai)
 					break;
 			} while (it != impls.end());
-			if (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;
+				uint8_t random = (std::rand() % impls.size()); // Choose a random AI
+				it = impls.begin() + random;
+			}
 			s.players[number].ai = (*it)->name;
 		}
 
 		s.players[number].state = PlayerSettings::stateComputer;
 	}
 
-	virtual void setPlayerTribe(uint8_t const number, std::string const & tribe)
+	virtual void setPlayerTribe(uint8_t const number, std::string const & 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 = tribe;
+				s.players[number].tribe = actual_tribe;
 				if
 					(i.current->initializations.size()
 					 <=
@@ -1915,6 +1936,7 @@
 					player.initialization_index = 0;
 			}
 	}
+
 	virtual void setPlayerInit(uint8_t const number, uint8_t const index) {
 		if (number >= s.players.size())
 			return;

=== modified file 'src/wui/multiplayersetupgroup.cc'
--- src/wui/multiplayersetupgroup.cc	2011-08-25 11:48:39 +0000
+++ src/wui/multiplayersetupgroup.cc	2011-09-18 13:52:27 +0000
@@ -293,8 +293,13 @@
 					pic += "novalue.png";
 				} else {
 					title = _("AI: ");
-					title += _(player.ai);
-					pic += "ai_" + player.ai + ".png";
+					if(player.random_ai) {
+						title += _("random");
+						pic += "ai_random.png";
+					} else {
+						title += _(player.ai);
+						pic += "ai_" + player.ai + ".png";
+					}
 				}
 			} else { // PlayerSettings::stateHuman
 				title = _("Human");
@@ -302,20 +307,30 @@
 			}
 			type->set_tooltip(title.c_str());
 			type->set_pic(g_gr->get_picture(PicMod_UI, pic));
-			std::string tribepath("tribes/" + player.tribe);
-			if (!m_tribenames[player.tribe].size()) {
-				// get tribes name and picture
-				Profile prof
-					((tribepath + "/conf").c_str(), 0, "tribe_" + player.tribe);
-				Section & global = prof.get_safe_section("tribe");
-				m_tribenames[player.tribe] = global.get_safe_string("name");
-				m_tribepics[player.tribe] =
-					g_gr->get_picture
-						(PicMod_UI,
-						 (tribepath + "/") + global.get_safe_string("icon"));
+			if(player.random_tribe) {
+				std::string random = _("random");
+				if(!m_tribenames["random"].size()) {
+					m_tribepics[random] =
+						g_gr->get_picture(PicMod_UI, "pics/random.png");
+				}
+				tribe->set_tooltip(random.c_str());
+				tribe->set_pic(m_tribepics[random]);
+			} else {
+				std::string tribepath("tribes/" + player.tribe);
+				if (!m_tribenames[player.tribe].size()) {
+					// get tribes name and picture
+					Profile prof
+						((tribepath + "/conf").c_str(), 0, "tribe_" + player.tribe);
+					Section & global = prof.get_safe_section("tribe");
+					m_tribenames[player.tribe] = global.get_safe_string("name");
+					m_tribepics[player.tribe] =
+						g_gr->get_picture
+							(PicMod_UI,
+							 (tribepath + "/") + global.get_safe_string("icon"));
+				}
+				tribe->set_tooltip(m_tribenames[player.tribe].c_str());
+				tribe->set_pic(m_tribepics[player.tribe]);
 			}
-			tribe->set_tooltip(m_tribenames[player.tribe].c_str());
-			tribe->set_pic(m_tribepics[player.tribe]);
 			tribe->set_flat(false);
 
 			if (player.team) {

=== modified file 'src/wui/playerdescrgroup.cc'
--- src/wui/playerdescrgroup.cc	2010-12-04 23:11:18 +0000
+++ src/wui/playerdescrgroup.cc	2011-09-18 13:52:27 +0000
@@ -170,7 +170,11 @@
 					title = _("Computer");
 				else {
 					title = _("AI: ");
-					title += _(player.ai);
+					if(player.random_ai) {
+						title += _("random");
+					} else {
+						title += _(player.ai);
+					}
 				}
 			} else { // PlayerSettings::stateHuman
 				title = _("Human");
@@ -184,7 +188,12 @@
 				Section & global = prof.get_safe_section("tribe");
 				m_tribenames[player.tribe] = global.get_safe_string("name");
 			}
-			d->btnPlayerTribe->set_title(m_tribenames[player.tribe]);
+			if (player.random_tribe) {
+				d->btnPlayerTribe->set_title(_("random"));
+			} else {
+				d->btnPlayerTribe->set_title(m_tribenames[player.tribe]);
+			}
+
 			{
 				i18n::Textdomain td(tribepath); // for translated initialisation
 				container_iterate_const
@@ -256,17 +265,27 @@
 	if (d->plnum >= settings.players.size())
 		return;
 
-	std::vector<PlayerSettings> pl = settings.players;
-	std::string const & currenttribe = pl.at(d->plnum).tribe;
+	PlayerSettings const & player = settings.players.at(d->plnum);
+	std::string const & currenttribe = player.tribe;
 	std::string nexttribe = settings.tribes.at(0).name;
+	bool random_tribe = false;
+	uint32_t num_tribes = settings.tribes.size();
 
-	for (uint32_t i = 0; i < settings.tribes.size() - 1; ++i)
-		if (settings.tribes[i].name == currenttribe) {
-			nexttribe = settings.tribes.at(i + 1).name;
-			break;
+	if (player.random_tribe) {
+		nexttribe = settings.tribes.at(0).name;
+	} else if (player.tribe == settings.tribes.at(num_tribes - 1).name) {
+		nexttribe = "Random";
+		random_tribe = true;
+	} else {
+		for (uint32_t i = 0; i < num_tribes - 1; ++i) {
+			if (settings.tribes[i].name == currenttribe) {
+				nexttribe = settings.tribes.at(i + 1).name;
+				break;
+			}
 		}
-
-	d->settings->setPlayerTribe(d->plnum, nexttribe);
+	}
+	
+	d->settings->setPlayerTribe(d->plnum, nexttribe, random_tribe);
 }
 
 /**


Follow ups