The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
play_controller.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2016 by Joerg Hinrichs <[email protected]>
3  wesnoth playlevel Copyright (C) 2003 by David White <[email protected]>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Handle input via mouse & keyboard, events, schedule commands.
19  */
20 
21 #include "play_controller.hpp"
22 
23 #include "actions/create.hpp"
24 #include "actions/heal.hpp"
25 #include "actions/undo.hpp"
26 #include "actions/vision.hpp"
27 #include "ai/manager.hpp"
28 #include "ai/testing.hpp"
29 #include "dialogs.hpp"
30 #include "display_chat_manager.hpp"
31 #include "formula/string_utils.hpp"
32 #include "game_events/manager.hpp"
34 #include "game_events/pump.hpp"
35 #include "game_preferences.hpp"
36 #include "game_state.hpp"
37 #include "hotkey/hotkey_item.hpp"
39 #include "map/label.hpp"
40 #include "gettext.hpp"
43 #include "halo.hpp"
45 #include "log.hpp"
46 #include "pathfind/teleport.hpp"
47 #include "preferences_display.hpp"
48 #include "replay.hpp"
49 #include "reports.hpp"
50 #include "resources.hpp"
51 #include "savegame.hpp"
52 #include "saved_game.hpp"
53 #include "save_blocker.hpp"
56 #include "sound.hpp"
57 #include "soundsource.hpp"
58 #include "statistics.hpp"
59 #include "synced_context.hpp"
60 #include "terrain/type_data.hpp"
61 #include "tooltips.hpp"
62 #include "units/unit.hpp"
63 #include "units/id.hpp"
64 #include "whiteboard/manager.hpp"
65 #include "wml_exception.hpp"
66 
67 #include <boost/make_shared.hpp>
68 #include "utils/functional.hpp"
69 
70 static lg::log_domain log_aitesting("aitesting");
71 #define LOG_AIT LOG_STREAM(info, log_aitesting)
72 //If necessary, this define can be replaced with `#define LOG_AIT std::cout` to restore previous behavior
73 
74 static lg::log_domain log_engine("engine");
75 #define LOG_NG LOG_STREAM(info, log_engine)
76 #define DBG_NG LOG_STREAM(debug, log_engine)
77 
78 static lg::log_domain log_display("display");
79 #define ERR_DP LOG_STREAM(err, log_display)
80 
81 static lg::log_domain log_enginerefac("enginerefac");
82 #define LOG_RG LOG_STREAM(info, log_enginerefac)
83 
84 static lg::log_domain log_engine_enemies("engine/enemies");
85 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
86 
87 /**
88  * Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
89  */
90 static void copy_persistent(const config& src, config& dst)
91 {
92  typedef boost::container::flat_set<std::string> stringset;
93 
94  static stringset attrs = boost::assign::list_of
95  ("id")
96  ("theme")
97  ("next_scenario")
98  ("description")
99  ("name")
100  ("defeat_music")
101  ("victory_music")
102  ("victory_when_enemies_defeated")
103  ("remove_from_carryover_on_defeat")
104  ("disallow_recall")
105  ("experience_modifier")
106  ("require_scenario")
107  .convert_to_container<stringset>();
108 
109  static stringset tags = boost::assign::list_of
110  ("terrain_graphics")
111  ("lua")
112  .convert_to_container<stringset>();
113 
114  for (const std::string& attr : attrs)
115  {
116  dst[attr] = src[attr];
117  }
118 
119  for (const std::string& tag : tags)
120  {
121  dst.append_children(src, tag);
122  }
123 }
124 
125 static void clear_resources()
126 {
127  resources::controller = nullptr;
128  resources::filter_con = nullptr;
129  resources::gameboard = nullptr;
130  resources::gamedata = nullptr;
131  resources::game_events = nullptr;
132  resources::lua_kernel = nullptr;
133  resources::persist = nullptr;
134  resources::screen = nullptr;
135  resources::soundsources = nullptr;
136  resources::teams = nullptr;
137  resources::tod_manager = nullptr;
138  resources::tunnels = nullptr;
139  resources::undo_stack = nullptr;
140  resources::recorder = nullptr;
141  resources::units = nullptr;
142  resources::whiteboard.reset();
143  resources::classification = nullptr;
144  resources::mp_settings = nullptr;
145 }
146 
148  const config& game_config, const tdata_cache& tdata,
149  CVideo& video, bool skip_replay)
150  : controller_base(game_config, video)
151  , observer()
153  , ticks_(SDL_GetTicks())
154  , tdata_(tdata)
155  , gamestate_()
156  , level_()
157  , saved_game_(state_of_game)
158  , tooltips_manager_()
159  , whiteboard_manager_()
160  , plugins_context_()
161  , labels_manager_()
162  , help_manager_(&game_config)
163  , mouse_handler_(nullptr, *this)
164  , menu_handler_(nullptr, *this, game_config)
165  , hotkey_handler_(new hotkey_handler(*this, saved_game_))
166  , soundsources_manager_()
167  , persist_()
168  , gui_()
169  , xp_mod_(new unit_experience_accelerator(level["experience_modifier"].to_int(100)))
170  , statistics_context_(new statistics::scenario_context(level["name"]))
171  , replay_(new replay(state_of_game.get_replay()))
172  , skip_replay_(skip_replay)
173  , linger_(false)
174  , init_side_done_now_(false)
175  , victory_when_enemies_defeated_(level["victory_when_enemies_defeated"].to_bool(true))
176  , remove_from_carryover_on_defeat_(level["remove_from_carryover_on_defeat"].to_bool(true))
177  , victory_music_()
178  , defeat_music_()
179  , scope_()
180  , ignore_replay_errors_(false)
181  , player_type_changed_(false)
182 {
183  copy_persistent(level, level_);
184 
185  resources::controller = this;
188 
191 
193 
194  // Setup victory and defeat music
195  set_victory_music_list(level_["victory_music"]);
196  set_defeat_music_list(level_["defeat_music"]);
197 
201  try {
202  init(video, level);
203  } catch (...) {
204  clear_resources();
205  throw;
206  }
207 }
208 
210 {
212  clear_resources();
213 }
214 
216 {
217  void operator()(const config&)
218  {
220  }
221 };
222 
224 {
225 
226  gui2::tloadscreen::display(video, [this, &video, &level]() {
227  gui2::tloadscreen::progress("load level");
228 
229  LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl;
230  gamestate_.reset(new game_state(level, *this, tdata_));
231 
240 
241  gamestate_->init(level, *this);
243 
244  LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl;
245  gui2::tloadscreen::progress("init whiteboard");
246  whiteboard_manager_.reset(new wb::manager());
248 
249  LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl;
250  gui2::tloadscreen::progress("load units");
252 
253  LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl;
254  gui2::tloadscreen::progress("init theme");
255  const config& theme_cfg = controller_base::get_theme(game_config_, level["theme"]);
256 
257  LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl;
258  gui2::tloadscreen::progress("build terrain");
259  gui_.reset(new game_display(gamestate().board_, video, whiteboard_manager_, *gamestate().reports_, gamestate().tod_manager_, theme_cfg, level));
260  if (!gui_->video().faked()) {
262  gui_->get_theme().modify_label("time-icon", _ ("time left for current turn"));
263  else
264  gui_->get_theme().modify_label("time-icon", _ ("current local time"));
265  }
266 
267  gui2::tloadscreen::progress("init display");
268  mouse_handler_.set_gui(gui_.get());
269  menu_handler_.set_gui(gui_.get());
270  resources::screen = gui_.get();
271 
272  LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl;
273 
274  LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl;
275  // This *needs* to be created before the show_intro and show_map_scene
276  // as that functions use the manager state_of_game
277  // Has to be done before registering any events!
279  gui2::tloadscreen::progress("init lua");
281 
282  if(gamestate().first_human_team_ != -1) {
283  gui_->set_team(gamestate().first_human_team_);
284  }
285  else if(is_observer()) {
286  // Find first team that is allowed to be observed.
287  // If not set here observer would be without fog until
288  // the first turn of observable side
289  size_t i;
290  for (i=0;i < gamestate().board_.teams().size();++i)
291  {
292  if (!gamestate().board_.teams()[i].get_disallow_observers())
293  {
294  gui_->set_team(i);
295  }
296  }
297  }
298 
299  init_managers();
300  gui2::tloadscreen::progress("start game");
301  //loadscreen_manager->reset();
303  gamestate().lua_kernel_->initialize(level);
304 
305  plugins_context_.reset(new plugins_context("Game"));
306  plugins_context_->set_callback("save_game", std::bind(&play_controller::save_game_auto, this, std::bind(get_str, std::placeholders::_1, "filename" )), true);
307  plugins_context_->set_callback("save_replay", std::bind(&play_controller::save_replay_auto, this, std::bind(get_str, std::placeholders::_1, "filename" )), true);
308  plugins_context_->set_callback("quit", throw_end_level(), false);
309  });
310  //Do this after the loadingscreen, so that ita happens in the main thread.
311  gui_->join();
312 }
313 
314 void play_controller::reset_gamestate(const config& level, int replay_pos)
315 {
316  resources::gameboard = nullptr;
317  resources::gamedata = nullptr;
318  resources::teams = nullptr;
319  resources::tod_manager = nullptr;
320  resources::units = nullptr;
321  resources::filter_con = nullptr;
322  resources::lua_kernel = nullptr;
323  resources::game_events = nullptr;
324  resources::tunnels = nullptr;
325  resources::undo_stack = nullptr;
326 
327  gamestate_.reset(new game_state(level, *this, tdata_));
336 
337  gamestate_->init(level, *this);
341 
342  gui_->reset_tod_manager(gamestate().tod_manager_);
343  gui_->reset_reports(*gamestate().reports_);
344  gui_->change_display_context(&gamestate().board_);
345  saved_game_.get_replay().set_pos(replay_pos);
347  gamestate().lua_kernel_->initialize(level);
348 }
349 
351 {
352  LOG_NG << "initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
354  tooltips_manager_.reset(new tooltips::manager(gui_->video()));
356 
358  LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
359 }
360 
362 {
363  // Run initialization scripts, even if loading from a snapshot.
364  gamestate().gamedata_.get_variable("turn_number") = int(turn());
365  pump().fire("preload");
366 }
367 
369 {
370  // pre-start events must be executed before any GUI operation,
371  // as those may cause the display to be refreshed.
372  update_locker lock_display(gui_->video());
374 
375  // Fire these right before prestart events, to catch only the units sides
376  // have started with.
377  for (const unit& u : gamestate().board_.units()) {
378  pump().fire("unit placed", map_location(u.get_location()));
379  }
380 
381  pump().fire("prestart");
382  // prestart event may modify start turn with WML, reflect any changes.
383  gamestate().gamedata_.get_variable("turn_number") = int(turn());
384 }
385 
387 {
389  pump().fire("start");
390  // start event may modify start turn with WML, reflect any changes.
391  gamestate().gamedata_.get_variable("turn_number") = int(turn());
393  // prestart and start events may modify the initial gold amount,
394  // reflect any changes.
395  for (team& tm : gamestate().board_.teams_)
396  {
397  tm.set_start_gold(tm.gold());
398  }
399  gamestate_->init_side_done() = false;
401 }
402 
404 {
405  gui_->begin_game();
406  gui_->update_tod();
407 }
408 
410 {
412 
413  // If we are observers we move to watch next team if it is allowed
414  if ((is_observer() && !current_team().get_disallow_observers())
415  || (current_team().is_local_human() && !this->is_replay()))
416  {
418  }
419 
420  gui_->set_playing_team(size_t(current_side() - 1));
421 
423 }
424 
426 {
427  //
428  // We do side init only if not done yet for a local side when we are not replaying.
429  // For all other sides it is recorded in replay and replay handler has to handle
430  // calling do_init_side() functions.
431  //
432  if (gamestate_->init_side_done() || !current_team().is_local() || gamestate().gamedata_.phase() != game_data::PLAY || is_replay() || !replay_->at_end()) {
433  return;
434  }
435 
437  do_init_side();
438 }
439 
441 {
442  set_scontext_synced sync;
443  log_scope("player turn");
444  // In case we might end up calling sync:network during the side turn events,
445  // and we don't want do_init_side to be called when a player drops.
446  gamestate_->init_side_done() = true;
447  init_side_done_now_ = true;
448 
449  const std::string turn_num = std::to_string(turn());
450  const std::string side_num = std::to_string(current_side());
451 
452  gamestate().gamedata_.get_variable("side_number") = current_side();
453 
454  // We might have skipped some sides because they were empty so it is not enough to check for side_num==1
455  if(!gamestate().tod_manager_.has_turn_event_fired())
456  {
457  pump().fire("turn " + turn_num);
458  pump().fire("new turn");
460  }
461 
462  pump().fire("side turn");
463  pump().fire("side " + side_num + " turn");
464  pump().fire("side turn " + turn_num);
465  pump().fire("side " + side_num + " turn " + turn_num);
466 
467  // We want to work out if units for this player should get healed,
468  // and the player should get income now.
469  // Healing/income happen if it's not the first turn of processing,
470  // or if we are loading a game.
471  if (turn() > 1) {
474 
475  // If the expense is less than the number of villages owned
476  // times the village support capacity,
477  // then we don't have to pay anything at all
478  int expense = gamestate().board_.side_upkeep(current_side()) -
479  current_team().support();
480  if(expense > 0) {
481  current_team().spend_gold(expense);
482  }
483 
485  }
486 
487  // Prepare the undo stack.
489 
490  pump().fire("turn refresh");
491  pump().fire("side " + side_num + " turn refresh");
492  pump().fire("turn " + turn_num + " refresh");
493  pump().fire("side " + side_num + " turn " + turn_num + " refresh");
494 
495  // Make sure vision is accurate.
497  init_side_end();
498  check_victory();
499  sync.do_final_checkup();
500 }
501 
503 {
505 
506  if (current_side() == 1 || !init_side_done_now_)
508 
509  if (!is_skipping_replay()){
510  gui_->invalidate_all();
511  }
512 
513  if (!is_skipping_replay() && current_team().get_scroll_to_leader()){
514  gui_->scroll_to_leader(current_side(), game_display::ONSCREEN,false);
515  }
516  whiteboard_manager_->on_init_side();
517 }
518 
520 {
521  config cfg = level_;
522 
523  cfg["replay_pos"] = saved_game_.get_replay().get_pos();
524  gamestate().write(cfg);
525 
526  gui_->write(cfg.add_child("display"));
527 
528  //Write the soundsources.
529  soundsources_manager_->write_sourcespecs(cfg);
530 
531  gui_->labels().write(cfg);
533 
534  return cfg;
535 }
536 
538 {
539  whiteboard_manager_->on_finish_side_turn(current_side());
540 
541  { //Block for set_scontext_synced
542  set_scontext_synced sync(1);
543  // Ending the turn commits all moves.
544  undo_stack().clear();
546  const std::string turn_num = std::to_string(turn());
547  const std::string side_num = std::to_string(current_side());
548 
549  // Clear shroud, in case units had been slowed for the turn.
551 
552  pump().fire("side turn end");
553  pump().fire("side "+ side_num + " turn end");
554  pump().fire("side turn " + turn_num + " end");
555  pump().fire("side " + side_num + " turn " + turn_num + " end");
556  // This is where we refog, after all of a side's events are done.
558  check_victory();
559  sync.do_final_checkup();
560  }
561 
564  gamestate_->init_side_done() = false;
565 }
566 
568 {
569  set_scontext_synced sync(2);
570  const std::string turn_num = std::to_string(turn());
571  pump().fire("turn end");
572  pump().fire("turn " + turn_num + " end");
573  sync.do_final_checkup();
574 }
575 
577 {
578  // If we aren't using fog/shroud, this is easy :)
579  if(current_team().uses_fog() == false && current_team().uses_shroud() == false)
580  return true;
581 
582  // See if any enemies are visible
583  for (const unit& u : gamestate().board_.units()) {
584  if (current_team().is_enemy(u.side()) && !gui_->fogged(u.get_location())) {
585  return true;
586  }
587  }
588 
589  return false;
590 }
591 
593 {
594  if(menu_handler_.get_textbox().active() == false) {
595  return;
596  }
597 
598  const std::string str = menu_handler_.get_textbox().box()->text();
599  const unsigned int team_num = current_side();
600  events::mouse_handler& mousehandler = mouse_handler_;
601 
602  switch(menu_handler_.get_textbox().mode()) {
603  case gui::TEXTBOX_SEARCH:
606  break;
609  menu_handler_.get_textbox().close(*gui_); //need to close that one after executing do_speak() !
610  break;
614  break;
615  case gui::TEXTBOX_AI:
617  menu_handler_.do_ai_formula(str, team_num, mousehandler);
618  break;
619  default:
621  ERR_DP << "unknown textbox mode" << std::endl;
622  }
623 }
624 
626 {
628 
629  std::set<std::string> dictionary;
630  switch(mode) {
631  case gui::TEXTBOX_SEARCH:
632  {
633  for (const unit& u : gamestate().board_.units()){
634  const map_location& loc = u.get_location();
635  if(!gui_->fogged(loc) &&
636  !(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
637  dictionary.insert(u.name());
638  }
639  //TODO List map labels
640  break;
641  }
643  {
644  std::vector<std::string> commands = menu_handler_.get_commands_list();
645  dictionary.insert(commands.begin(), commands.end());
646  // no break here, we also want player names from the next case
647  }
649  {
650  for (const team& t : gamestate().board_.teams()) {
651  if(!t.is_empty())
652  dictionary.insert(t.current_player());
653  }
654 
655  // Add observers
656  for (const std::string& o : gui_->observers()){
657  dictionary.insert(o);
658  }
659 
660  // Add nicks who whispered you
661  for (const std::string& w : gui_->get_chat_manager().whisperers()){
662  dictionary.insert(w);
663  }
664 
665  // Add nicks from friendlist
666  const std::map<std::string, std::string> friends = preferences::get_acquaintances_nice("friend");
667 
668  for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter){
669  dictionary.insert((*iter).first);
670  }
671 
672  //Exclude own nick from tab-completion.
673  //NOTE why ?
674  dictionary.erase(preferences::login());
675  break;
676  }
677 
678  default:
679  ERR_DP << "unknown textbox mode" << std::endl;
680  } //switch(mode)
681 
682  menu_handler_.get_textbox().tab(dictionary);
683 }
684 
686 {
687  assert(current_side() > 0 && current_side() <= int(gamestate().board_.teams().size()));
688  return gamestate().board_.teams_[current_side() - 1];
689 }
690 
692 {
693  assert(current_side() > 0 && current_side() <= int(gamestate().board_.teams().size()));
694  return gamestate().board_.teams()[current_side() - 1];
695 }
696 
697 /// @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
698 static int modulo(int num, int mod, int min)
699 {
700  assert(mod > 0);
701  int n = (num - min) % mod;
702  if (n < 0)
703  n += mod;
704  //n is now in [0, mod)
705  n = n + min;
706  return n;
707  // the folowing properties are easy to verify:
708  // 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
709  // 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
710 }
711 
712 bool play_controller::is_team_visible(int team_num, bool observer) const
713 {
714  const team& t = gamestate().board_.teams()[team_num - 1];
715  if(observer) {
716  return !t.get_disallow_observers() && !t.is_empty();
717  }
718  else {
719  return t.is_local_human() && !t.is_idle();
720  }
721 }
722 
724 {
725  assert(current_side() <= int(gamestate().board_.teams().size()));
726  const int num_teams = gamestate().board_.teams().size();
727  const bool is_observer = this->is_observer();
728 
729  for(int i = 0; i < num_teams; i++) {
730  const int team_num = modulo(current_side() - i, num_teams, 1);
731  if(is_team_visible(team_num, is_observer)) {
732  return team_num;
733  }
734  }
735  return 0;
736 }
737 
739 {
740  return mouse_handler_;
741 }
742 
744 {
745  return whiteboard_manager_;
746 }
747 
749 {
750  return saved_game_.mp_settings();
751 }
752 
754 {
755  return saved_game_.classification();
756 }
757 
759 {
760  return *gui_;
761 }
762 
764 {
765  return !menu_handler_.get_textbox().active();
766 }
767 
769 {
770  if(event.key.keysym.sym == SDLK_ESCAPE) {
772  } else if(event.key.keysym.sym == SDLK_TAB) {
773  tab();
774  } else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
775  enter_textbox();
776  }
777 }
778 
780 {
781  if (event.key.keysym.sym == SDLK_TAB) {
782  whiteboard_manager_->set_invert_behavior(true);
783  }
784 }
785 
787 {
788  // If the user has pressed 1 through 9, we want to show
789  // how far the unit can move in that many turns
790  if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '7') {
791  const int new_path_turns = (event.type == SDL_KEYDOWN) ?
792  event.key.keysym.sym - '1' : 0;
793 
794  if(new_path_turns != mouse_handler_.get_path_turns()) {
795  mouse_handler_.set_path_turns(new_path_turns);
796 
798 
799  if(u.valid()) {
800  // if it's not the unit's turn, we reset its moves
801  unit_movement_resetter move_reset(*u, u->side() != current_side());
802 
804  true, gamestate().board_.teams_[gui_->viewing_team()],
806 
807  gui_->highlight_reach(mouse_handler_.current_paths());
808  } else {
810  }
811 
812  }
813  } else if (event.key.keysym.sym == SDLK_TAB) {
814  static CKey keys;
815  if (!keys[SDLK_TAB]) {
816  whiteboard_manager_->set_invert_behavior(false);
817  }
818  }
819 }
820 
822 {
825  scoped_savegame_snapshot snapshot(*this);
827  save.save_game_interactive(gui_->video(), "", gui::OK_CANCEL);
828  } else {
830  }
831 }
832 
834 {
837 
838  scoped_savegame_snapshot snapshot(*this);
840  save.save_game_automatic(gui_->video(), false, filename);
841  }
842 }
843 
845 {
849  save.save_game_interactive(gui_->video(), "", gui::OK_CANCEL);
850  } else {
852  }
853 }
854 
856 {
860  save.save_game_automatic(gui_->video(), false, filename);
861  }
862 }
863 
865 {
869  } else {
871  }
872 }
873 
875 {
877  load.load_game();
878 }
879 
881 {
883  undo_stack().undo();
884 }
885 
887 {
889  undo_stack().redo();
890 }
891 
893 {
895 }
896 
898 {
900 }
901 
902 namespace {
903  static const std::string empty_str = "";
904 }
905 
907 {
908  if(victory_music_.empty())
909  return empty_str;
910  return victory_music_[rand() % victory_music_.size()];
911 }
912 
914 {
915  if(defeat_music_.empty())
916  return empty_str;
917  return defeat_music_[rand() % defeat_music_.size()];
918 }
919 
921 {
923  if(victory_music_.empty())
925 }
926 
928 {
929  defeat_music_ = utils::split(list);
930  if(defeat_music_.empty())
932 }
933 
935 {
936  if(linger_)
937  {
938  return;
939  }
940 
941  if (is_regular_game_end()) {
942  return;
943  }
944  bool continue_level, found_player, found_network_player, invalidate_all;
945  std::set<unsigned> not_defeated;
946 
947  gamestate().board_.check_victory(continue_level, found_player, found_network_player, invalidate_all, not_defeated, remove_from_carryover_on_defeat_);
948 
949  if (invalidate_all) {
950  gui_->invalidate_all();
951  }
952 
953  if (continue_level) {
954  return ;
955  }
956 
957  if (found_player || found_network_player) {
958  pump().fire("enemies defeated");
959  if (is_regular_game_end()) {
960  return;
961  }
962  }
963 
964  DBG_EE << "victory_when_enemies_defeated: " << victory_when_enemies_defeated_ << std::endl;
965  DBG_EE << "found_player: " << found_player << std::endl;
966  DBG_EE << "found_network_player: " << found_network_player << std::endl;
967 
968  if (!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
969  // This level has asked not to be ended by this condition.
970  return;
971  }
972 
973  if (gui_->video().non_interactive()) {
974  LOG_AIT << "winner: ";
975  for (unsigned l : not_defeated) {
977  if (ai.empty()) ai = "default ai";
978  LOG_AIT << l << " (using " << ai << ") ";
979  }
980  LOG_AIT << std::endl;
981  ai_testing::log_victory(not_defeated);
982  }
983 
984  DBG_EE << "throwing end level exception..." << std::endl;
985  //Also proceed to the next scenario when another player survived.
986  end_level_data el_data;
987  el_data.proceed_to_next_level = found_player || found_network_player;
988  el_data.is_victory = found_player;
989  set_end_level_data(el_data);
990 }
991 
993 {
994  if (gui_->video().non_interactive()) {
995  throw game::game_error(msg);
996  }
998 
999  std::stringstream message;
1000  message << _("The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1001  message << "\n\n" << _("Error details:") << "\n\n" << msg;
1002 
1003  scoped_savegame_snapshot snapshot(*this);
1005  save.save_game_interactive(gui_->video(), message.str(), gui::YES_NO); // can throw quit_game_exception
1006 }
1007 
1008 void play_controller::update_gui_to_player(const int team_index, const bool observe)
1009 {
1010  gui_->set_team(team_index, observe);
1011  gui_->recalculate_minimap();
1012  gui_->invalidate_all();
1013  gui_->draw(true,true);
1014 }
1015 
1017 {
1018  scoped_savegame_snapshot snapshot(*this);
1021 }
1022 
1024 {
1025  scoped_savegame_snapshot snapshot(*this);
1027  save.save_game_automatic(gui_->video(), true, filename);
1028 }
1029 
1031 {
1032  //note: this writes to level_ if this is not a replay.
1034 }
1035 
1037 {
1038  return gamestate().events_manager_->pump();
1039 }
1040 
1042 {
1043  return ticks_;
1044 }
1045 
1047 {
1048  return soundsources_manager_.get();
1049 }
1050 
1052 {
1053  return plugins_context_.get();
1054 }
1055 
1057 {
1058  return hotkey_handler_.get();
1059 }
1060 
1062 {
1063  if(linger_ || !gamestate_->init_side_done() || gamestate().gamedata_.phase() != game_data::PLAY) {
1064  return true;
1065  }
1066  const team& t = current_team();
1067  return !t.is_local_human() || !t.is_proxy_human();
1068 }
1069 
1071 {
1073  return;
1074  }
1075  try
1076  {
1077  play_slice();
1078  }
1079  catch(const return_to_play_side_exception&)
1080  {
1081  assert(should_return_to_play_side());
1082  }
1083 }
1084 
1086 {
1087  fire_preload();
1088 
1089  if(!gamestate().start_event_fired_)
1090  {
1091  gamestate().start_event_fired_ = true;
1094 
1095  set_scontext_synced sync;
1096 
1097  fire_prestart();
1098  if (is_regular_game_end()) {
1099  return;
1100  }
1101 
1102  for ( int side = gamestate().board_.teams().size(); side != 0; --side )
1103  actions::clear_shroud(side, false, false);
1104 
1105  init_gui();
1106  LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";
1107 
1109  fire_start();
1110  if (is_regular_game_end()) {
1111  return;
1112  }
1113  sync.do_final_checkup();
1114  gui_->recalculate_minimap();
1115  // Initialize countdown clock.
1116  for (const team& t : gamestate().board_.teams())
1117  {
1119  t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
1120  }
1121  }
1122  }
1123  else
1124  {
1125  init_gui();
1128  gui_->recalculate_minimap();
1129  }
1130 }
1131 
1133 {
1134  const team& viewing_team = get_teams_const()[gui_->viewing_team()];
1135  return gui_->viewing_team() == gui_->playing_team() && !events::commands_disabled && viewing_team.is_local_human() && !is_lingering() && !is_browsing();
1136 }
1137 
1138 std::set<std::string> play_controller::all_players() const
1139 {
1140  std::set<std::string> res = gui_->observers();
1141  for (const team& t : get_teams_const())
1142  {
1143  if (t.is_human()) {
1144  res.insert(t.current_player());
1145  }
1146  }
1147  return res;
1148 }
1149 
1151 {
1152  //check for team-specific items in the scenario
1153  gui_->parse_team_overlays();
1154  do {
1156  {
1157  save_blocker blocker;
1159  if(is_regular_game_end()) {
1160  return;
1161  }
1162  }
1163  // This flag can be set by derived classes (in overridden functions).
1164  player_type_changed_ = false;
1165 
1166  statistics::reset_turn_stats(gamestate().board_.teams()[current_side() - 1].save_id());
1167 
1168  play_side_impl();
1169 
1170  if(is_regular_game_end()) {
1171  return;
1172  }
1173 
1174  } while (player_type_changed_);
1175  // Keep looping if the type of a team (human/ai/networked)
1176  // has changed mid-turn
1177  sync_end_turn();
1178 }
1179 
1181 {
1182  whiteboard_manager_->on_gamestate_change();
1183  gui_->new_turn();
1184  gui_->invalidate_game_status();
1186 
1187  LOG_NG << "turn: " << turn() << "\n";
1188 
1189  if(gui_->video().non_interactive()) {
1190  LOG_AIT << "Turn " << turn() << ":" << std::endl;
1191  }
1192 
1193  for (; gamestate_->player_number_ <= int(gamestate().board_.teams().size()); ++gamestate_->player_number_)
1194  {
1195  // If a side is empty skip over it.
1196  if (current_team().is_empty()) {
1197  continue;
1198  }
1199  init_side_begin();
1200  if(gamestate_->init_side_done()) {
1201  // This is the case in a reloaded game where the side was initialized before saving the game.
1202  init_side_end();
1203  }
1204 
1206  play_side();
1207  if(is_regular_game_end()) {
1208  return;
1209  }
1210  finish_side_turn();
1211  if(is_regular_game_end()) {
1212  return;
1213  }
1214  if(gui_->video().non_interactive()) {
1215  LOG_AIT << " Player " << current_side() << ": " <<
1216  current_team().villages().size() << " Villages" <<
1217  std::endl;
1219  }
1220  }
1221  // If the loop exits due to the last team having been processed.
1222  gamestate_->player_number_ = gamestate().board_.teams().size();
1223 
1224  finish_turn();
1225 
1226  // Time has run out
1227  check_time_over();
1228 }
1229 
1231 {
1232  const bool time_left = gamestate().tod_manager_.next_turn(&gamestate().gamedata_);
1233 
1234  if(!time_left) {
1235  LOG_NG << "firing time over event...\n";
1237  pump().fire("time over");
1238  LOG_NG << "done firing time over event...\n";
1239  // If turns are added while handling 'time over' event.
1240  if (gamestate().tod_manager_.is_time_left()) {
1241  return;
1242  }
1243 
1244  if(gui_->video().non_interactive()) {
1245  LOG_AIT << "time over (draw)\n";
1247  }
1248 
1249  check_victory();
1250  if (is_regular_game_end()) {
1251  return;
1252  }
1253  end_level_data e;
1254  e.proceed_to_next_level = false;
1255  e.is_victory = false;
1256  set_end_level_data(e);
1257  }
1258 }
1259 
1261  : controller_(controller)
1262 {
1264 }
1265 
1267 {
1268  controller_.saved_game_.remove_snapshot();
1269 }
static const config & get_theme(const config &game_config, std::string theme_name)
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:226
play_controller * controller
Definition: resources.cpp:21
play_controller(const config &level, saved_game &state_of_game, const config &game_config, const tdata_cache &tdata, CVideo &video, bool skip_replay)
void do_search(const std::string &new_search)
bool is_local() const
Definition: team.hpp:261
void set_current_paths(const pathfind::paths &new_paths)
events::mouse_handler & get_mouse_handler_base()
Get a reference to a mouse handler member a derived class uses.
static void log_turn_start(unsigned int side)
Definition: testing.cpp:35
static void log_turn_end(unsigned int side)
Definition: testing.cpp:40
void set_preference_display_settings()
::tod_manager * tod_manager
Definition: resources.cpp:31
PHASE phase() const
Definition: game_data.hpp:78
bool is_team_visible(int team_num, bool observer) const
static lg::log_domain log_engine_enemies("engine/enemies")
int ticks() const
map_location last_selected
the last location where a select event fired.
Definition: game_data.hpp:85
int get_path_turns() const
The class for loading a savefile.
Definition: savegame.hpp:36
void save_replay_auto(const std::string &filename)
Definition: unit.hpp:95
bool victory_when_enemies_defeated_
While any instance of this class exists, attempts to save the game via any call to play_controller wi...
game_classification * classification
Definition: resources.cpp:37
GLint level
Definition: glew.h:1220
bool can_redo() const
Various functions implementing vision (through fog of war and shroud).
const mp_game_settings & get_mp_settings()
void do_final_checkup(bool dont_throw=false)
boost::scoped_ptr< plugins_context > plugins_context_
events::mouse_handler mouse_handler_
static void copy_persistent(const config &src, config &dst)
Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
const mp_game_settings * mp_settings
Definition: resources.cpp:38
virtual void process_oos(const std::string &msg) const
Asks the user whether to continue on an OOS error.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
bool get_disallow_observers() const
Definition: team.hpp:337
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Definition: tod_manager.hpp:56
replay_recorder_base & get_replay()
Definition: saved_game.hpp:116
Definition: video.hpp:58
std::string default_victory_music
Definition: game_config.cpp:68
Class for autosaves.
Definition: savegame.hpp:219
void set_scope_active(scope s, bool set)
game_display * screen
Definition: resources.cpp:27
static void log_victory(std::set< unsigned int > teams)
Definition: testing.cpp:81
static void on_unblock(play_controller *controller, void(play_controller::*callback)())
std::string sounds
List of "ambient" sounds associated with this time_of_day, Played at the beginning of turn...
Definition: time_of_day.hpp:95
const int INFINITE_AUTO_SAVES
bool is_enemy(int n) const
Definition: team.hpp:247
bool save_game_interactive(CVideo &video, const std::string &message, gui::DIALOG_TYPE dialog_type)
Save a game interactively through the savegame dialog.
Definition: savegame.cpp:366
void do_command(const std::string &str)
virtual void update_viewing_player()=0
gui::floating_textbox & get_textbox()
void new_turn()
Definition: team.hpp:209
void set_gui(game_display *gui)
Definition: menu_events.hpp:50
void undo()
Undoes the top action on the undo stack.
Definition: undo.cpp:362
bool can_use_synced_wml_menu() const
void process_focus_keydown_event(const SDL_Event &event)
Process keydown (only when the general map display does not have focus).
static lg::log_domain log_aitesting("aitesting")
Gather statistics important for AI testing and output them.
boost::scoped_ptr< pathfind::manager > pathfind_manager_
Definition: game_state.hpp:51
bool fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
Definition: pump.cpp:471
void play_slice(bool is_delay_enabled=true)
#define LOG_AIT
boost::scoped_ptr< hotkey_handler > hotkey_handler_
void new_side_turn(int side)
Performs some initializations and error checks when starting a new side-turn.
Definition: undo.cpp:268
static lg::log_domain log_engine("engine")
virtual const std::vector< team > & teams() const
Definition: game_board.hpp:97
Class for "normal" midgame saves.
Definition: savegame.hpp:188
Replay control code.
persist_manager * persist
Definition: resources.cpp:26
void check_victory()
Checks to see if a side has won.
boost::scoped_ptr< soundsource::manager > soundsources_manager_
GLenum src
Definition: glew.h:2392
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:451
bool is_skipping_replay() const
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:540
void init(CVideo &video, const config &level)
static void log_draw()
Definition: testing.cpp:75
static lg::log_domain log_display("display")
void write_music_play_list(config &snapshot)
Definition: sound.cpp:644
#define DBG_EE
bool is_proxy_human() const
Definition: team.hpp:283
GLenum mode
Definition: glew.h:2390
static void clear_resources()
This file implements all the hotkey handling and menu details for play controller.
GLdouble GLdouble t
Definition: glew.h:1366
void select_hex(const map_location &hex, const bool browse, const bool highlight=true, const bool fire_event=true)
persist_manager persist_
const std::string & select_victory_music() const
const tdata_cache & tdata_
bool can_undo() const
True if there are actions that can be undone.
Definition: undo.hpp:91
void reset_turn_stats(const std::string &save_id)
Definition: statistics.cpp:522
void process_keydown_event(const SDL_Event &event)
Process keydown (always).
map_location get_selected_hex() const
#define ERR_DP
game_data * gamedata
Definition: resources.cpp:22
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
Definition: game_data.cpp:70
events::menu_handler menu_handler_
GLdouble l
Definition: glew.h:6966
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:818
void process_keyup_event(const SDL_Event &event)
Process keyup (always).
bool enemies_visible() const
void set_phase(PHASE phase)
Definition: game_data.hpp:79
boost::scoped_ptr< game_lua_kernel > lua_kernel_
Definition: game_state.hpp:53
An exception-safe means of making sure that unblock() gets called after try_block().
int side_upkeep(int side_num) const
void do_consolesave(const std::string &filename)
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:48
saved_game & saved_game_
std::vector< std::string > defeat_music_
unit_map units_
Definition: game_board.hpp:63
game_events::t_pump & pump()
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:57
scoped_savegame_snapshot(const play_controller &controller)
void init_side()
Definition: replay.cpp:218
std::string default_defeat_music
Definition: game_config.cpp:68
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
static int modulo(int num, int mod, int min)
void throw_quit_game_exception()
void save_game_auto(const std::string &filename)
int current_side() const
Returns the number of the side whose turn it is.
bool add_start_if_not_there_yet()
Definition: replay.cpp:638
std::vector< team > * teams
Definition: resources.cpp:29
std::vector< team > teams_
Definition: game_board.hpp:58
bool is_regular_game_end() const
void update_savegame_snapshot() const
void set_path_turns(const int path_turns)
virtual void check_time_over()
Implements a quit confirmation dialog.
filter_context * filter_con
Definition: resources.cpp:23
boost::scoped_ptr< game_events::manager > events_manager_
Definition: game_state.hpp:54
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
size_t turn() const
void add_color_info(const config &v)
virtual bool should_return_to_play_side()
bool ignore_replay_errors
Definition: game_config.cpp:63
GLenum GLenum dst
Definition: glew.h:2392
game_board * gameboard
Definition: resources.cpp:20
This class is the frontend of the whiteboard framework for the rest of the Wesnoth code...
Definition: manager.hpp:43
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:705
GLuint num
Definition: glew.h:2552
config & add_child(const std::string &key)
Definition: config.cpp:743
virtual void init_gui()
void maybe_do_init_side()
Called by turn_info::process_network_data() or init_side() to call do_init_side() if necessary...
tod_manager tod_manager_
Definition: game_state.hpp:50
bool is_local_human() const
Definition: team.hpp:267
Object which temporarily resets a unit's movement.
Definition: unit.hpp:561
Managing the AIs lifecycle - headers.
replay * recorder
Definition: resources.cpp:30
bool is_lingering() const
void check_victory(bool &, bool &, bool &, bool &, std::set< unsigned > &, bool)
Definition: game_board.cpp:101
void set_gui(game_display *gui)
void spend_gold(const int amount)
Definition: team.hpp:213
bool is_observer() const
std::set< std::string > all_players() const
static const map_location & null_location()
Definition: location.hpp:195
bool can_redo() const
True if there are actions that can be redone.
Definition: undo.hpp:93
Error used for any general game error, e.g.
Definition: game_errors.hpp:46
const std::set< map_location > & villages() const
Definition: team.hpp:189
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
static void display(CVideo &video, std::function< void()> f)
Definition: loadscreen.cpp:181
game_events::manager * game_events
Definition: resources.cpp:24
bool is_browsing() const override
void deactivate_all_scopes()
void raise_draw_event()
Definition: events.cpp:565
virtual plugins_context * get_plugins_context()
Get (optionally) a plugins context a derived class uses.
hotkey::command_executor * get_hotkey_command_executor()
Get (optionally) a command executor to handle context menu events.
void update_gui_to_player(const int team_index, const bool observe=false)
Changes the UI for this client to the passed side index.
void do_init_side()
Called by replay handler or init_side() to do actual work for turn change.
Encapsulates the map of the game.
Definition: location.hpp:38
void calculate_healing(int side, bool update_display)
Calculates healing for all units for the given side.
Definition: heal.cpp:294
std::string login()
virtual ~play_controller()
Various functions related to the creation of units (recruits, recalls, and placed units)...
void set_end_level_data(const end_level_data &data)
GLuint res
Definition: glew.h:9258
static void progress(const char *stage_name=nullptr)
Definition: loadscreen.cpp:128
void end_turn(int pnum)
Definition: game_board.cpp:77
void write(config &cfg) const
Definition: game_state.cpp:229
soundsource::manager * soundsources
Definition: resources.cpp:28
void redo()
Redoes the top action on the redo stack.
Definition: undo.cpp:413
Game configuration data as global variables.
Definition: build_info.cpp:38
unit_map::iterator selected_unit()
static std::string get_active_ai_identifier_for_side(side_number side)
Gets AI algorithm identifier for active AI of the given side.
Definition: manager.cpp:744
const config & game_config_
void operator()(const config &)
void reset_gamestate(const config &level, int replay_pos)
Define the game's event mechanism.
void encounter_all_content(const game_board &gameboard_)
#define log_scope(description)
Definition: log.hpp:185
const util::scoped_ptr< gui::textbox > & box() const
size_t i
Definition: function.cpp:1057
void tab(const std::set< std::string > &dictionary)
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:112
bool proceed_to_next_level
whether to proceed to the next scenario, equals is_victory in sp.
const std::vector< team > & get_teams_const() const
boost::scoped_ptr< tooltips::manager > tooltips_manager_
void turn_event_fired()
game_data gamedata_
Definition: game_state.hpp:48
Additional information on the game outcome which can be provided by WML.
int support() const
Calculate total support capacity, based on support_per_village.
Definition: team.hpp:208
actions::undo_list & undo_stack()
std::map< std::string, std::string > get_acquaintances_nice(const std::string &filter)
void set_defeat_music_list(const std::string &list)
static void save(LexState *ls, int c)
Definition: llex.cpp:51
static lg::log_domain log_enginerefac("enginerefac")
std::string observer
Definition: game_config.cpp:84
Class for replay saves (either manually or automatically).
Definition: savegame.hpp:206
compression::format save_compression_format()
const game_classification & get_classification()
bool clear_shroud(int side, bool reset_fog, bool fire_events)
Function that will clear shroud (and fog) based on current unit positions.
Definition: vision.cpp:754
static bool try_block()
boost::scoped_ptr< game_state > gamestate_
void set_game_display(game_display *)
Definition: game_state.cpp:224
GLclampd n
Definition: glew.h:5903
boost::shared_ptr< wb::manager > get_whiteboard()
n_unit::id_manager & unit_id_manager()
Definition: game_board.hpp:91
game_state & gamestate()
bool is_empty() const
Definition: team.hpp:259
Various functions that implement healing of units (when a side turn starts).
cl_event event
Definition: glew.h:3070
game_classification & classification()
Definition: saved_game.hpp:54
bool have_keyboard_focus()
Derived classes should override this to return false when arrow keys should not scroll the map...
game_board board_
Definition: game_state.hpp:49
boost::shared_ptr< wb::manager > whiteboard_manager_
config to_config() const
Builds the snapshot config from members and their respective configs.
Various functions that implement the undoing (and redoing) of in-game commands.
bool is_idle() const
Definition: team.hpp:285
virtual bool is_replay()
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
Definition: savegame.cpp:586
game_display & get_display()
Get a reference to a display member a derived class uses.
const std::function< std::string(const config &, const std::string &) > get_str
Definition: context.cpp:121
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition: pathfind.hpp:71
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
config * get_next_action()
Definition: replay.cpp:598
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
void fire_preload()
preload events cannot be synced
void new_turn(int pnum)
Definition: game_board.cpp:69
void set_victory_music_list(const std::string &list)
void reset_fake()
Definition: id.cpp:56
boost::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:36
boost::scoped_ptr< game_display > gui_
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
#define e
std::vector< std::string > victory_music_
actions::undo_list * undo_stack
Definition: resources.cpp:34
const std::string & select_defeat_music() const
bool valid() const
Definition: map.hpp:229
void set_side(int side_number)
virtual soundsource::manager * get_soundsource_man()
Get (optionally) a soundsources manager a derived class uses.
bool next_turn(game_data *vars)
Function to move to the next turn.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:27
const pathfind::paths & current_paths() const
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:58
void delete_all_wml_hotkeys()
deletes all wml hotkeys, should be called after a game has ended
std::vector< std::string > get_commands_list()
void close(game_display &gui)
pathfind::manager * tunnels
Definition: resources.cpp:33
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool save_game_automatic(CVideo &video, bool ask_for_overwrite=false, const std::string &filename="")
Saves a game without user interaction, unless the file exists and it should be asked to overwrite it...
Definition: savegame.cpp:350
unit_map * units
Definition: resources.cpp:35
virtual void check_objectives()=0
bool can_undo() const
int find_last_visible_team() const
returns 0 if no such team was found.
virtual void play_side_impl()
bool start_event_fired_
Definition: game_state.hpp:64
boost::scoped_ptr< replay > replay_
bool init_side_done_now_
Whether we did init sides in this session (false = we did init sides before we reloaded the game)...
bool remove_from_carryover_on_defeat_
TEXTBOX_MODE mode() const
void do_ai_formula(const std::string &str, int side_num, mouse_handler &mousehandler)
#define LOG_NG
virtual void sync_end_turn()