widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #00350
[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