1 // Copyright (C) 2008, 2009 Ben Asselstine
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU Library General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <sigc++/functors/mem_fun.h>
23 #include "game-lobby-dialog.h"
25 #include "glade-helpers.h"
26 #include "image-helpers.h"
27 #include "input-helpers.h"
28 #include "ucompose.hpp"
32 #include "playerlist.h"
33 #include "game-options-dialog.h"
34 #include "GraphicsCache.h"
35 #include "network_player.h"
36 #include "game-client.h"
37 #include "game-server.h"
38 #include "shieldsetlist.h"
39 #include "NextTurnNetworked.h"
40 #include "recently-played-game-list.h"
44 Glib::ustring player_type_to_string(guint32 type)
48 case Player::HUMAN: return HUMAN_PLAYER_TYPE;
49 case Player::AI_FAST: return EASY_PLAYER_TYPE;
50 case Player::AI_SMART: return HARD_PLAYER_TYPE;
51 case Player::NETWORKED: return NETWORKED_PLAYER_TYPE;
52 default: return NO_PLAYER_TYPE;
57 void GameLobbyDialog::update_city_map()
59 if (d_game_scenario->s_hidden_map == false)
63 citymap = new CityMap();
64 citymap->map_changed.connect
65 (sigc::mem_fun(this, &GameLobbyDialog::on_map_changed));
66 if (d_game_scenario->getRound() > 1)
69 citymap->draw(Playerlist::getActiveplayer());
74 map_image->property_file() =
75 File::getMiscFile("various/city_occupied.png");
79 void GameLobbyDialog::initDialog(GameScenario *gamescenario,
80 NextTurnNetworked *next_turn,
81 GameStation *game_station)
83 Shieldsetlist::getInstance()->instantiateImages();
84 d_game_scenario = gamescenario;
85 d_game_station = game_station;
86 d_next_turn = next_turn;
88 Glib::RefPtr<Gtk::Builder> xml
89 = Gtk::Builder::create_from_file(get_glade_path()
90 + "/game-lobby-dialog.ui");
92 xml->get_widget("dialog", dialog);
94 window_closed.connect(sigc::mem_fun(dialog, &Gtk::Dialog::hide));
96 xml->get_widget("player_treeview", player_treeview);
97 player_treeview->get_selection()->signal_changed().connect
98 (sigc::mem_fun(*this, &GameLobbyDialog::on_player_selected));
99 //player_treeview->get_selection()->set_mode(Gtk::SELECTION_NONE);
100 xml->get_widget("people_treeview", people_treeview);
101 people_treeview->property_headers_visible() = true;
102 xml->get_widget("play_button", play_button);
103 play_button->signal_clicked().connect
104 (sigc::mem_fun(this, &GameLobbyDialog::on_play_clicked));
105 xml->get_widget("cancel_button", cancel_button);
106 cancel_button->signal_clicked().connect
107 (sigc::mem_fun(this, &GameLobbyDialog::on_cancel_clicked));
108 xml->get_widget("map_image", map_image);
109 xml->get_widget("turn_label", turn_label);
110 xml->get_widget("scenario_name_label", scenario_name_label);
111 xml->get_widget("cities_label", cities_label);
112 xml->get_widget("chat_scrolledwindow", chat_scrolledwindow);
113 chat_scrolledwindow->property_hscrollbar_policy() = Gtk::POLICY_NEVER;
114 xml->get_widget("chat_textview", chat_textview);
115 xml->get_widget("chat_entry", chat_entry);
117 chat_entry->signal_key_release_event().connect_notify
118 (sigc::mem_fun(*this, &GameLobbyDialog::on_chat_key_pressed));
122 Gtk::EventBox *map_eventbox;
123 xml->get_widget("map_eventbox", map_eventbox);
124 xml->get_widget("show_options_button", show_options_button);
125 show_options_button->signal_clicked().connect
126 (sigc::mem_fun(*this, &GameLobbyDialog::on_show_options_clicked));
128 game_station->remote_player_moved.connect
129 (sigc::mem_fun(*this, &GameLobbyDialog::on_remote_player_ends_turn));
130 game_station->local_player_moved.connect
131 (sigc::mem_fun(*this, &GameLobbyDialog::on_local_player_ends_turn));
132 game_station->local_player_starts_move.connect
133 (sigc::mem_fun(*this, &GameLobbyDialog::on_local_player_starts_turn));
134 game_station->remote_participant_joins.connect
135 (sigc::mem_fun(*this, &GameLobbyDialog::on_remote_participant_joins));
136 game_station->remote_participant_departs.connect
137 (sigc::mem_fun(*this, &GameLobbyDialog::on_remote_participant_departs));
138 game_station->player_sits.connect
139 (sigc::mem_fun(*this, &GameLobbyDialog::on_player_sits));
140 game_station->player_stands.connect
141 (sigc::mem_fun(*this, &GameLobbyDialog::on_player_stands));
142 game_station->remote_player_named.connect
143 (sigc::mem_fun(*this, &GameLobbyDialog::on_remote_player_changes_name));
144 game_station->chat_message_received.connect
145 (sigc::mem_fun(*this, &GameLobbyDialog::on_chatted));
146 game_station->playerlist_reorder_received.connect
147 (sigc::mem_fun(*this, &GameLobbyDialog::on_reorder_playerlist));
148 game_station->remote_player_died.connect
149 (sigc::mem_fun(*this, &GameLobbyDialog::on_player_died));
150 game_station->local_player_died.connect
151 (sigc::mem_fun(*this, &GameLobbyDialog::on_player_died));
153 update_player_details();
156 people_list = Gtk::ListStore::create(people_columns);
157 // setup the player settings
158 people_treeview->set_model(people_list);
162 void GameLobbyDialog::update_buttons()
164 //if any types aren't networked, we can play.
165 //if all types are networked then we can't.
166 Gtk::TreeModel::Children kids = player_list->children();
167 for (Gtk::TreeModel::Children::iterator i = kids.begin();
168 i != kids.end(); i++)
170 Gtk::TreeModel::Row row = *i;
171 if (row[player_columns.type] != NETWORKED_PLAYER_TYPE)
173 play_button->set_sensitive(true);
177 play_button->set_sensitive(false);
181 GameLobbyDialog::update_player_details()
185 player_list->clear();
188 player_list = Gtk::ListStore::create(player_columns);
189 // setup the player settings
190 player_treeview->set_model(player_list);
192 player_treeview->remove_all_columns();
194 player_treeview->append_column("", player_columns.shield);
197 sitting_renderer.property_mode() = Gtk::CELL_RENDERER_MODE_EDITABLE;
198 sitting_renderer.property_activatable() = true;
199 sitting_renderer.signal_editing_started().connect
200 (sigc::mem_fun(*this, &GameLobbyDialog::on_sitting_changed));
201 sitting_column.set_cell_data_func
202 (sitting_renderer, sigc::mem_fun(*this, &GameLobbyDialog::cell_data_sitting));
203 player_treeview->append_column(sitting_column);
205 player_treeview->append_column(_("Person"), player_columns.person);
208 player_name_list = Gtk::ListStore::create(player_name_columns);
210 name_renderer.property_editable() = true;
212 name_renderer.signal_edited()
213 .connect(sigc::mem_fun(*this, &GameLobbyDialog::on_name_edited));
214 name_column.set_cell_data_func
215 ( name_renderer, sigc::mem_fun(*this, &GameLobbyDialog::cell_data_name));
216 player_treeview->append_column(name_column);
219 player_type_list = Gtk::ListStore::create(player_type_columns);
220 Gtk::TreeModel::iterator i;
221 i = player_type_list->append();
222 (*i)[player_type_columns.type] = HUMAN_PLAYER_TYPE;
223 i = player_type_list->append();
224 (*i)[player_type_columns.type] = EASY_PLAYER_TYPE;
225 i = player_type_list->append();
226 (*i)[player_type_columns.type] = HARD_PLAYER_TYPE;
227 i = player_type_list->append();
228 (*i)[player_type_columns.type] = NO_PLAYER_TYPE;
230 type_renderer.property_model() = player_type_list;
231 type_renderer.property_text_column() = 0;
232 type_renderer.property_has_entry() = false;
233 type_renderer.property_editable() = d_has_ops;
235 type_renderer.signal_edited()
236 .connect(sigc::mem_fun(*this, &GameLobbyDialog::on_type_edited));
237 type_column.set_cell_data_func
238 ( type_renderer, sigc::mem_fun(*this, &GameLobbyDialog::cell_data_type));
239 player_treeview->append_column(type_column);
241 //if it's this player's turn
242 player_treeview->append_column(_("Turn"), player_columns.turn);
244 Playerlist *pl = Playerlist::getInstance();
246 for (Playerlist::iterator i = pl->begin(), end = pl->end(); i != end; ++i)
249 if (player == pl->getNeutral())
251 if (player->isDead())
253 add_player(player_type_to_string(player->getType()), player->getName(),
258 void GameLobbyDialog::on_sitting_changed(Gtk::CellEditable *editable,
259 const Glib::ustring &path)
261 Gtk::TreeModel::iterator iter = player_treeview->get_model()->get_iter(path);
262 Playerlist *pl = Playerlist::getInstance();
264 //maybe we can't make other ppl stand up
265 if ((*iter)[player_columns.sitting] &&
266 (*iter)[player_columns.type] == NETWORKED_PLAYER_TYPE && d_has_ops == false)
269 player = pl->getPlayer((*iter)[player_columns.player_id]);
271 if (!(*iter)[player_columns.sitting])
272 player_sat_down.emit(player);
274 player_stood_up.emit(player);
277 GameLobbyDialog::GameLobbyDialog(GameScenario *game_scenario,
278 NextTurnNetworked *next_turn,
279 GameStation *game_station,
281 :name_column(_("Name"), name_renderer),
282 type_column(_("Type"), type_renderer),
283 sitting_column(_("Seated"), sitting_renderer)
286 initDialog(game_scenario, next_turn, game_station);
287 update_scenario_details();
290 GameLobbyDialog::~GameLobbyDialog()
297 void GameLobbyDialog::update_scenario_details()
301 s = String::ucompose("%1", d_game_scenario->getRound());
302 turn_label->set_text(s);
303 scenario_name_label->set_text(d_game_scenario->getName());
304 s = String::ucompose("%1", Citylist::getInstance()->size());
305 cities_label->set_text(s);
310 void GameLobbyDialog::set_parent_window(Gtk::Window &parent)
312 dialog->set_transient_for(parent);
313 //dialog->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
316 void GameLobbyDialog::hide()
321 void GameLobbyDialog::show()
327 void GameLobbyDialog::on_map_changed(Glib::RefPtr<Gdk::Pixmap> map)
329 map_image->property_pixmap() = map;
332 void GameLobbyDialog::on_show_options_clicked()
334 GameOptionsDialog gd(true);
338 void GameLobbyDialog::cell_data_type(Gtk::CellRenderer *renderer,
339 const Gtk::TreeIter& i)
341 dynamic_cast<Gtk::CellRendererText*>(renderer)->property_text()
342 = (*i)[player_columns.type];
345 void GameLobbyDialog::on_type_edited(const Glib::ustring &path,
346 const Glib::ustring &new_text)
348 (*player_list->get_iter(Gtk::TreePath(path)))[player_columns.type]
350 //fixme, make a player->changeType method, and send it as an action
353 void GameLobbyDialog::cell_data_name(Gtk::CellRenderer *renderer,
354 const Gtk::TreeIter& i)
356 Playerlist *pl = Playerlist::getInstance();
358 player = pl->getPlayer((*i)[player_columns.player_id]);
360 dynamic_cast<Gtk::CellRendererText*>(renderer)->property_text()
364 void GameLobbyDialog::on_name_edited(const Glib::ustring &path,
365 const Glib::ustring &new_text)
367 Playerlist *pl = Playerlist::getInstance();
369 Gtk::TreeModel::iterator iter = player_treeview->get_model()->get_iter(path);
370 if ((*iter)[player_columns.sitting] == false)
372 player = pl->getPlayer((*iter)[player_columns.player_id]);
374 player->rename(new_text);
375 (*player_list->get_iter(Gtk::TreePath(path)))[player_columns.name]
379 void GameLobbyDialog::cell_data_sitting(Gtk::CellRenderer *renderer,
380 const Gtk::TreeIter& i)
382 dynamic_cast<Gtk::CellRendererToggle*>(renderer)->set_active((*i)[player_columns.sitting]);
385 void GameLobbyDialog::add_player(const Glib::ustring &type,
386 const Glib::ustring &name, Player *player)
388 GraphicsCache *gc = GraphicsCache::getInstance();
389 Gtk::TreeIter i = player_list->append();
390 if (player == Playerlist::getInstance()->getActiveplayer())
391 (*i)[player_columns.turn] = gc->getCursorPic(GraphicsCache::SWORD)->to_pixbuf();
392 (*i)[player_columns.shield] = gc->getShieldPic(1, player)->to_pixbuf();
393 (*i)[player_columns.type] = type;
394 (*i)[player_columns.name] = name;
395 (*i)[player_columns.player_id] = player->getId();
396 if (player->getType() == Player::NETWORKED)
398 //do we have the particpant?
399 if (dynamic_cast<NetworkPlayer*>(player)->isConnected() == true)
401 (*i)[player_columns.sitting] = true;
405 //otherwise, the player is not here to play.
406 (*i)[player_columns.sitting] = false;
411 (*i)[player_columns.sitting] = true;
416 void GameLobbyDialog::on_player_selected()
421 void GameLobbyDialog::on_remote_participant_joins(std::string nickname)
423 Gtk::TreeIter j = people_list->append();
424 (*j)[people_columns.nickname] = nickname;
427 void GameLobbyDialog::on_remote_participant_departs(std::string nickname)
429 //iterate through and remove the nickname
430 Gtk::TreeNodeChildren rows = people_list->children();
431 for(Gtk::TreeIter row = rows.begin(); row != rows.end(); ++row)
433 Gtk::TreeModel::Row my_row = *row;
434 if (my_row[people_columns.nickname] == nickname)
436 people_list->erase(row);
442 void GameLobbyDialog::on_player_sits(Player *p, std::string nickname)
446 Gtk::TreeModel::Children kids = player_list->children();
447 //look for the row that has the right player id.
448 for (Gtk::TreeModel::Children::iterator i = kids.begin();
449 i != kids.end(); i++)
451 Gtk::TreeModel::Row row = *i;
452 if (row[player_columns.player_id] == p->getId())
454 row[player_columns.sitting] = true;
455 row[player_columns.type] = player_type_to_string(p->getType());
456 row[player_columns.person] = nickname;
463 void GameLobbyDialog::on_player_stands(Player *p, std::string nickname)
467 Gtk::TreeModel::Children kids = player_list->children();
468 for (Gtk::TreeModel::Children::iterator i = kids.begin();
469 i != kids.end(); i++)
471 Gtk::TreeModel::Row row = *i;
472 if (row[player_columns.player_id] == p->getId())
474 row[player_columns.sitting] = false;
475 row[player_columns.person] = "";
476 row[player_columns.type] = player_type_to_string(p->getType());
483 void GameLobbyDialog::on_local_player_ends_turn(Player *p)
485 Gtk::TreeModel::Children kids = player_list->children();
486 for (Gtk::TreeModel::Children::iterator i = kids.begin();
487 i != kids.end(); i++)
489 Gtk::TreeModel::Row row = *i;
490 if (row[player_columns.player_id] == p->getId())
492 Glib::RefPtr<Gdk::Pixbuf> empty_pic
493 = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, 1, 1);
494 empty_pic->fill(0x00000000);
495 row[player_columns.turn] = empty_pic;
498 update_scenario_details();
500 void GameLobbyDialog::on_local_player_starts_turn(Player *p)
502 GraphicsCache *gc = GraphicsCache::getInstance();
503 Gtk::TreeModel::Children kids = player_list->children();
504 for (Gtk::TreeModel::Children::iterator i = kids.begin();
505 i != kids.end(); i++)
507 Gtk::TreeModel::Row row = *i;
508 Player *active = Playerlist::getActiveplayer();
509 if (row[player_columns.player_id] == active->getId())
510 (*i)[player_columns.turn] = gc->getCursorPic(GraphicsCache::SWORD)->to_pixbuf();
512 update_scenario_details();
515 void GameLobbyDialog::on_remote_player_ends_turn(Player *p)
517 if (GameServer::getInstance()->isListening() == false)
519 RecentlyPlayedGameList *rpgl = RecentlyPlayedGameList::getInstance();
520 rpgl->updateEntry(d_game_scenario);
521 rpgl->saveToFile(File::getSavePath() + "/recently-played.xml");
523 GraphicsCache *gc = GraphicsCache::getInstance();
524 Gtk::TreeModel::Children kids = player_list->children();
525 for (Gtk::TreeModel::Children::iterator i = kids.begin();
526 i != kids.end(); i++)
528 Gtk::TreeModel::Row row = *i;
529 if (row[player_columns.player_id] == p->getId())
531 Glib::RefPtr<Gdk::Pixbuf> empty_pic
532 = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, 1, 1);
533 empty_pic->fill(0x00000000);
534 row[player_columns.turn] = empty_pic;
536 Player *active = Playerlist::getActiveplayer();
537 if (row[player_columns.player_id] == active->getId())
538 (*i)[player_columns.turn] = gc->getCursorPic(GraphicsCache::SWORD)->to_pixbuf();
540 update_scenario_details();
543 void GameLobbyDialog::on_remote_player_changes_name(Player *p)
545 Gtk::TreeModel::Children kids = player_list->children();
546 for (Gtk::TreeModel::Children::iterator i = kids.begin();
547 i != kids.end(); i++)
549 Gtk::TreeModel::Row row = *i;
550 if (row[player_columns.player_id] == p->getId())
552 row[player_columns.name] = p->getName();
558 void GameLobbyDialog::on_play_clicked()
561 //we only get here on the first time play is clicked
562 //otherwise it just shows the form (Driver::start_network_game_requested)
563 start_network_game.emit(d_game_scenario, d_next_turn);
566 void GameLobbyDialog::on_cancel_clicked()
571 void GameLobbyDialog::on_chat_key_pressed(GdkEventKey *event)
573 if (event->keyval == 65293) //enter
575 if (chat_entry->get_text().length() > 0)
576 message_sent.emit(chat_entry->get_text());
577 chat_entry->set_text("");
582 void GameLobbyDialog::on_chatted(std::string nickname, std::string message)
584 std::string new_text;
585 new_text = chat_textview->get_buffer()->get_text() + "\n" + message;
586 chat_textview->get_buffer()->set_text(new_text);
587 chat_scrolledwindow->get_vadjustment()->set_value(chat_scrolledwindow->get_vadjustment()->get_upper());
590 void GameLobbyDialog::on_player_died(Player *p)
595 Gtk::TreeNodeChildren rows = player_list->children();
596 for(Gtk::TreeIter row = rows.begin(); row != rows.end(); ++row)
598 Gtk::TreeModel::Row my_row = *row;
599 if (my_row[player_columns.player_id] == p->getId())
601 player_list->erase(row);
607 void GameLobbyDialog::on_reorder_playerlist()
610 std::list<int> new_order;
611 Playerlist *pl = Playerlist::getInstance();
612 for (Playerlist::iterator it = pl->begin(); it != pl->end(); it++)
614 Gtk::TreeNodeChildren rows = player_list->children();
615 for(Gtk::TreeIter row = rows.begin(); row != rows.end(); ++row)
617 Gtk::TreeModel::Row my_row = *row;
618 if (my_row[player_columns.player_id] == (*it)->getId())
620 new_order.push_back(count);
626 player_list->reorder(new_order);
629 bool GameLobbyDialog::run()
631 Playerlist *pl = Playerlist::getInstance();
633 if (d_game_scenario->s_hidden_map == false)
636 citymap->draw(Playerlist::getActiveplayer());
639 people_treeview->remove_all_columns();
640 people_treeview->append_column(_("People"), people_columns.nickname);
641 if (GameServer::getInstance()->isListening() == false)
643 GameClient::getInstance()->request_seat_manifest();
644 Gtk::TreeIter j = people_list->append();
645 (*j)[people_columns.nickname] = "[" + GameClient::getInstance()->getNickname() + "]";
649 Gtk::TreeIter j = people_list->append();
650 (*j)[people_columns.nickname] = "[" + GameServer::getInstance()->getNickname() + "]";
651 //automatically seat the ai players
652 for (Playerlist::iterator i = pl->begin(), end = pl->end(); i != end; ++i)
655 if (player == pl->getNeutral())
657 if (player->isDead())
659 if (player->getType() == Player::HUMAN)
661 if (player->getType() == Player::NETWORKED)
664 player_sat_down.emit(player);
667 int response = dialog->run();
668 if (response == Gtk::RESPONSE_ACCEPT)
674 void GameLobbyDialog::player_is_unavailable(Player *p)
676 on_local_player_starts_turn(p);