initial commit, lordsawar source, slightly modified
[lordsawar] / src / gui / game-lobby-dialog.cpp
1 //  Copyright (C) 2008, 2009 Ben Asselstine
2 //
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.
7 //
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.
12 //
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 
16 //  02110-1301, USA.
17
18 #include <config.h>
19
20 #include <gtkmm.h>
21 #include <sigc++/functors/mem_fun.h>
22
23 #include "game-lobby-dialog.h"
24
25 #include "glade-helpers.h"
26 #include "image-helpers.h"
27 #include "input-helpers.h"
28 #include "ucompose.hpp"
29 #include "defs.h"
30 #include "File.h"
31 #include "citylist.h"
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"
41
42 namespace
43 {
44     Glib::ustring player_type_to_string(guint32 type)
45     {
46         switch (type)
47         {
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;
53         }
54     }
55 }
56
57 void GameLobbyDialog::update_city_map()
58 {
59   if (d_game_scenario->s_hidden_map == false)
60     {
61       if (citymap)
62         delete citymap;
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)
67         {
68           citymap->resize();
69           citymap->draw(Playerlist::getActiveplayer());
70         }
71     }
72   else
73     {
74       map_image->property_file() = 
75         File::getMiscFile("various/city_occupied.png");
76     }
77 }
78
79 void GameLobbyDialog::initDialog(GameScenario *gamescenario, 
80                                  NextTurnNetworked *next_turn,
81                                  GameStation *game_station)
82 {
83   Shieldsetlist::getInstance()->instantiateImages();
84   d_game_scenario = gamescenario;
85   d_game_station = game_station;
86   d_next_turn = next_turn;
87   citymap = NULL;
88     Glib::RefPtr<Gtk::Builder> xml
89         = Gtk::Builder::create_from_file(get_glade_path()
90                                     + "/game-lobby-dialog.ui");
91
92     xml->get_widget("dialog", dialog);
93     decorate(dialog);
94     window_closed.connect(sigc::mem_fun(dialog, &Gtk::Dialog::hide));
95
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);
116
117     chat_entry->signal_key_release_event().connect_notify
118           (sigc::mem_fun(*this, &GameLobbyDialog::on_chat_key_pressed));
119
120     update_city_map();
121
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));
127
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));
152
153     update_player_details();
154     update_buttons();
155
156     people_list = Gtk::ListStore::create(people_columns);
157     // setup the player settings
158     people_treeview->set_model(people_list);
159
160 }
161
162 void GameLobbyDialog::update_buttons()
163 {
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++)
169     {
170       Gtk::TreeModel::Row row = *i;
171       if (row[player_columns.type] != NETWORKED_PLAYER_TYPE)
172         {
173           play_button->set_sensitive(true);
174           return;
175         }
176     }
177   play_button->set_sensitive(false);
178 }
179
180 void
181 GameLobbyDialog::update_player_details()
182 {
183   if (player_list)
184     {
185       player_list->clear();
186       player_list.reset();
187     }
188   player_list = Gtk::ListStore::create(player_columns);
189   // setup the player settings
190   player_treeview->set_model(player_list);
191
192   player_treeview->remove_all_columns();
193
194   player_treeview->append_column("", player_columns.shield);
195
196   //the sitting toggle
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);
204
205   player_treeview->append_column(_("Person"), player_columns.person);
206
207   // the name column
208   player_name_list = Gtk::ListStore::create(player_name_columns);
209
210   name_renderer.property_editable() = true;
211
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);
217
218   // the type 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;
229
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;
234
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);
240
241   //if it's this player's turn
242   player_treeview->append_column(_("Turn"), player_columns.turn);
243
244   Playerlist *pl = Playerlist::getInstance();
245
246   for (Playerlist::iterator i = pl->begin(), end = pl->end(); i != end; ++i)
247     {
248       Player *player = *i;
249       if (player == pl->getNeutral())
250         continue;
251       if (player->isDead())
252         continue;
253       add_player(player_type_to_string(player->getType()), player->getName(), 
254                  player);
255     }
256 }
257
258 void GameLobbyDialog::on_sitting_changed(Gtk::CellEditable *editable,
259                                          const Glib::ustring &path)
260 {
261   Gtk::TreeModel::iterator iter = player_treeview->get_model()->get_iter(path);
262   Playerlist *pl = Playerlist::getInstance();
263   Player *player;
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)
267     return;
268
269   player = pl->getPlayer((*iter)[player_columns.player_id]);
270
271   if (!(*iter)[player_columns.sitting])
272     player_sat_down.emit(player);
273   else
274     player_stood_up.emit(player);
275 }
276
277 GameLobbyDialog::GameLobbyDialog(GameScenario *game_scenario, 
278                                  NextTurnNetworked *next_turn, 
279                                  GameStation *game_station,
280                                  bool has_ops)
281 :name_column(_("Name"), name_renderer),
282     type_column(_("Type"), type_renderer),
283     sitting_column(_("Seated"), sitting_renderer)
284 {
285   d_has_ops = has_ops;
286   initDialog(game_scenario, next_turn, game_station);
287   update_scenario_details();
288 }
289
290 GameLobbyDialog::~GameLobbyDialog()
291 {
292   if (citymap)
293     delete citymap;
294   delete dialog;
295 }
296
297 void GameLobbyDialog::update_scenario_details()
298 {
299
300   Glib::ustring s;
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);
306
307   update_city_map();
308 }
309
310 void GameLobbyDialog::set_parent_window(Gtk::Window &parent)
311 {
312   dialog->set_transient_for(parent);
313   //dialog->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
314 }
315
316 void GameLobbyDialog::hide()
317 {
318   dialog->hide();
319 }
320
321 void GameLobbyDialog::show()
322 {
323   dialog->show_all();
324   return;
325 }
326
327 void GameLobbyDialog::on_map_changed(Glib::RefPtr<Gdk::Pixmap> map)
328 {
329   map_image->property_pixmap() = map;
330 }
331
332 void GameLobbyDialog::on_show_options_clicked()
333 {
334   GameOptionsDialog gd(true);
335   gd.run();
336 }
337
338 void GameLobbyDialog::cell_data_type(Gtk::CellRenderer *renderer,
339                                      const Gtk::TreeIter& i)
340 {
341   dynamic_cast<Gtk::CellRendererText*>(renderer)->property_text()
342     = (*i)[player_columns.type];
343 }
344
345 void GameLobbyDialog::on_type_edited(const Glib::ustring &path,
346                                      const Glib::ustring &new_text)
347 {
348   (*player_list->get_iter(Gtk::TreePath(path)))[player_columns.type]
349     = new_text;
350   //fixme, make a player->changeType method, and send it as an action
351 }
352
353 void GameLobbyDialog::cell_data_name(Gtk::CellRenderer *renderer,
354                                      const Gtk::TreeIter& i)
355 {
356   Playerlist *pl = Playerlist::getInstance();
357   Player *player;
358   player = pl->getPlayer((*i)[player_columns.player_id]);
359
360   dynamic_cast<Gtk::CellRendererText*>(renderer)->property_text()
361     = player->getName();
362 }
363
364 void GameLobbyDialog::on_name_edited(const Glib::ustring &path,
365                                      const Glib::ustring &new_text)
366 {
367   Playerlist *pl = Playerlist::getInstance();
368   Player *player;
369   Gtk::TreeModel::iterator iter = player_treeview->get_model()->get_iter(path);
370   if ((*iter)[player_columns.sitting] == false)
371     return;
372   player = pl->getPlayer((*iter)[player_columns.player_id]);
373
374   player->rename(new_text);
375   (*player_list->get_iter(Gtk::TreePath(path)))[player_columns.name]
376     = new_text;
377 }
378
379 void GameLobbyDialog::cell_data_sitting(Gtk::CellRenderer *renderer,
380                                         const Gtk::TreeIter& i)
381 {
382   dynamic_cast<Gtk::CellRendererToggle*>(renderer)->set_active((*i)[player_columns.sitting]);
383 }
384
385 void GameLobbyDialog::add_player(const Glib::ustring &type,
386                                  const Glib::ustring &name, Player *player)
387 {
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)
397     {
398       //do we have the particpant?
399       if (dynamic_cast<NetworkPlayer*>(player)->isConnected() == true)
400         {
401           (*i)[player_columns.sitting] = true;
402         }
403       else
404         {
405           //otherwise, the player is not here to play.
406           (*i)[player_columns.sitting] = false;
407         }
408     }
409   else
410     {
411       (*i)[player_columns.sitting] = true;
412     }
413
414 }
415
416 void GameLobbyDialog::on_player_selected()
417 {
418
419 }
420
421 void GameLobbyDialog::on_remote_participant_joins(std::string nickname)
422 {
423   Gtk::TreeIter j = people_list->append();
424   (*j)[people_columns.nickname] = nickname;
425 }
426
427 void GameLobbyDialog::on_remote_participant_departs(std::string nickname)
428 {
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)
432     {
433       Gtk::TreeModel::Row my_row = *row;
434       if (my_row[people_columns.nickname] == nickname)
435         {
436           people_list->erase(row);
437           return;
438         }
439     }
440 }
441
442 void GameLobbyDialog::on_player_sits(Player *p, std::string nickname)
443 {
444   if (!p)
445     return;
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++)
450     {
451       Gtk::TreeModel::Row row = *i;
452       if (row[player_columns.player_id] == p->getId())
453         {
454           row[player_columns.sitting] = true;
455           row[player_columns.type] = player_type_to_string(p->getType());
456           row[player_columns.person] = nickname;
457           update_buttons();
458           return;
459         }
460     }
461 }
462
463 void GameLobbyDialog::on_player_stands(Player *p, std::string nickname)
464 {
465   if (!p)
466     return;
467   Gtk::TreeModel::Children kids = player_list->children();
468   for (Gtk::TreeModel::Children::iterator i = kids.begin(); 
469        i != kids.end(); i++)
470     {
471       Gtk::TreeModel::Row row = *i;
472       if (row[player_columns.player_id] == p->getId())
473         {
474           row[player_columns.sitting] = false;
475           row[player_columns.person] = "";
476           row[player_columns.type] = player_type_to_string(p->getType());
477           update_buttons();
478           return;
479         }
480     }
481 }
482
483 void GameLobbyDialog::on_local_player_ends_turn(Player *p)
484 {
485   Gtk::TreeModel::Children kids = player_list->children();
486   for (Gtk::TreeModel::Children::iterator i = kids.begin(); 
487        i != kids.end(); i++)
488     {
489       Gtk::TreeModel::Row row = *i;
490       if (row[player_columns.player_id] == p->getId())
491         {
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;
496         }
497     }
498   update_scenario_details();
499 }
500 void GameLobbyDialog::on_local_player_starts_turn(Player *p)
501 {
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++)
506     {
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();
511     }
512   update_scenario_details();
513 }
514
515 void GameLobbyDialog::on_remote_player_ends_turn(Player *p)
516 {
517   if (GameServer::getInstance()->isListening() == false)
518     {
519       RecentlyPlayedGameList *rpgl = RecentlyPlayedGameList::getInstance();
520       rpgl->updateEntry(d_game_scenario);
521       rpgl->saveToFile(File::getSavePath() + "/recently-played.xml");
522     }
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++)
527     {
528       Gtk::TreeModel::Row row = *i;
529       if (row[player_columns.player_id] == p->getId())
530         {
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;
535         }
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();
539     }
540   update_scenario_details();
541 }
542
543 void GameLobbyDialog::on_remote_player_changes_name(Player *p)
544 {
545   Gtk::TreeModel::Children kids = player_list->children();
546   for (Gtk::TreeModel::Children::iterator i = kids.begin(); 
547        i != kids.end(); i++)
548     {
549       Gtk::TreeModel::Row row = *i;
550       if (row[player_columns.player_id] == p->getId())
551         {
552           row[player_columns.name] = p->getName();
553           return;
554         }
555     }
556 }
557
558 void GameLobbyDialog::on_play_clicked()
559 {
560   hide();
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);
564 }
565
566 void GameLobbyDialog::on_cancel_clicked()
567 {
568   hide();
569 }
570
571 void GameLobbyDialog::on_chat_key_pressed(GdkEventKey *event)
572 {
573   if (event->keyval == 65293) //enter
574     {
575       if (chat_entry->get_text().length() > 0)
576         message_sent.emit(chat_entry->get_text());
577       chat_entry->set_text("");
578     }
579   return;
580 }
581
582 void GameLobbyDialog::on_chatted(std::string nickname, std::string message)
583 {
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());
588 }
589
590 void GameLobbyDialog::on_player_died(Player *p)
591 {
592   if (!p)
593     return;
594
595   Gtk::TreeNodeChildren rows = player_list->children();
596   for(Gtk::TreeIter row = rows.begin(); row != rows.end(); ++row)
597     {
598       Gtk::TreeModel::Row my_row = *row;
599       if (my_row[player_columns.player_id] == p->getId())
600         {
601           player_list->erase(row);
602           return;
603         }
604     }
605 }
606
607 void GameLobbyDialog::on_reorder_playerlist()
608 {
609   int count = 0;
610   std::list<int> new_order;
611   Playerlist *pl = Playerlist::getInstance();
612   for (Playerlist::iterator it = pl->begin(); it != pl->end(); it++)
613     {
614       Gtk::TreeNodeChildren rows = player_list->children();
615       for(Gtk::TreeIter row = rows.begin(); row != rows.end(); ++row)
616         {
617           Gtk::TreeModel::Row my_row = *row;
618           if (my_row[player_columns.player_id] == (*it)->getId())
619             {
620               new_order.push_back(count);
621               count++;
622               break;
623             }
624         }
625     }
626   player_list->reorder(new_order);
627 }
628
629 bool GameLobbyDialog::run()
630 {
631   Playerlist *pl = Playerlist::getInstance();
632
633   if (d_game_scenario->s_hidden_map == false)
634     {
635       citymap->resize();
636       citymap->draw(Playerlist::getActiveplayer());
637     }
638
639   people_treeview->remove_all_columns();
640   people_treeview->append_column(_("People"), people_columns.nickname);
641   if (GameServer::getInstance()->isListening() == false)
642     {
643       GameClient::getInstance()->request_seat_manifest();
644       Gtk::TreeIter j = people_list->append();
645       (*j)[people_columns.nickname] = "[" + GameClient::getInstance()->getNickname() + "]";
646     }
647   else
648     {
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)
653         {
654           Player *player = *i;
655           if (player == pl->getNeutral())
656             continue;
657           if (player->isDead())
658             continue;
659           if (player->getType() == Player::HUMAN)
660             continue;
661           if (player->getType() == Player::NETWORKED)
662             continue;
663
664           player_sat_down.emit(player);
665         }
666     }
667   int response = dialog->run();
668   if (response == Gtk::RESPONSE_ACCEPT)
669     return true;
670   else
671     return false;
672 }
673
674 void GameLobbyDialog::player_is_unavailable(Player *p)
675 {
676   on_local_player_starts_turn(p);
677 }