The Battle for Wesnoth  1.15.0-dev
play_controller.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2018 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
3  wesnoth playlevel Copyright (C) 2003 by David White <dave@whitevine.net>
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 "display_chat_manager.hpp"
30 #include "formula/string_utils.hpp"
32 #include "game_events/pump.hpp"
33 #include "game_state.hpp"
34 #include "gettext.hpp"
35 #include "gui/dialogs/game_ui.hpp"
38 #include "help/help.hpp"
41 #include "hotkey/hotkey_item.hpp"
42 #include "log.hpp"
43 #include "map/label.hpp"
44 #include "pathfind/teleport.hpp"
46 #include "preferences/display.hpp"
47 #include "preferences/game.hpp"
48 #include "random.hpp"
49 #include "replay.hpp"
50 #include "reports.hpp"
51 #include "resources.hpp"
52 #include "save_blocker.hpp"
53 #include "saved_game.hpp"
54 #include "savegame.hpp"
57 #include "sound.hpp"
58 #include "soundsource.hpp"
59 #include "statistics.hpp"
60 #include "synced_context.hpp"
61 #include "terrain/type_data.hpp"
62 #include "tooltips.hpp"
63 #include "units/id.hpp"
64 #include "units/unit.hpp"
65 #include "utils/functional.hpp"
66 #include "whiteboard/manager.hpp"
67 
68 static lg::log_domain log_aitesting("aitesting");
69 #define LOG_AIT LOG_STREAM(info, log_aitesting)
70 // If necessary, this define can be replaced with `#define LOG_AIT std::cout` to restore previous behavior
71 
72 static lg::log_domain log_engine("engine");
73 #define LOG_NG LOG_STREAM(info, log_engine)
74 #define DBG_NG LOG_STREAM(debug, log_engine)
75 
76 static lg::log_domain log_display("display");
77 #define ERR_DP LOG_STREAM(err, log_display)
78 
79 static lg::log_domain log_enginerefac("enginerefac");
80 #define LOG_RG LOG_STREAM(info, log_enginerefac)
81 
82 static lg::log_domain log_engine_enemies("engine/enemies");
83 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
84 
85 /**
86  * Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
87  */
88 static void copy_persistent(const config& src, config& dst)
89 {
90  static const std::set<std::string> attrs {
91  "description",
92  "name",
93  "victory_when_enemies_defeated",
94  "remove_from_carryover_on_defeat",
95  "disallow_recall",
96  "experience_modifier",
97  "require_scenario"
98  };
99 
100  static const std::set<std::string> tags{"terrain_graphics", "lua"};
101 
102  for(const std::string& attr : attrs) {
103  dst[attr] = src[attr];
104  }
105 
106  for(const std::string& tag : tags) {
107  dst.append_children(src, tag);
108  }
109 }
110 
111 static void clear_resources()
112 {
113  resources::controller = nullptr;
114  resources::filter_con = nullptr;
115  resources::gameboard = nullptr;
116  resources::gamedata = nullptr;
117  resources::game_events = nullptr;
118  resources::lua_kernel = nullptr;
119  resources::persist = nullptr;
120  resources::soundsources = nullptr;
121  resources::tod_manager = nullptr;
122  resources::tunnels = nullptr;
123  resources::undo_stack = nullptr;
124  resources::recorder = nullptr;
125  resources::whiteboard.reset();
126  resources::classification = nullptr;
127 }
128 
130  saved_game& state_of_game,
131  const config& game_config,
132  const ter_data_cache& tdata,
133  bool skip_replay)
134  : controller_base(game_config)
135  , observer()
137  , ticks_(SDL_GetTicks())
138  , tdata_(tdata)
139  , gamestate_()
140  , level_()
141  , saved_game_(state_of_game)
142  , tooltips_manager_()
143  , whiteboard_manager_()
144  , plugins_context_()
145  , labels_manager_()
146  , mouse_handler_(nullptr, *this)
147  , menu_handler_(nullptr, *this, game_config)
148  , hotkey_handler_(new hotkey_handler(*this, saved_game_))
149  , soundsources_manager_()
150  , persist_()
151  , gui_()
152  , ui_()
153  , xp_mod_(new unit_experience_accelerator(level["experience_modifier"].to_int(100)))
154  , statistics_context_(new statistics::scenario_context(level["name"]))
155  , replay_(new replay(state_of_game.get_replay()))
156  , skip_replay_(skip_replay)
157  , linger_(false)
158  , init_side_done_now_(false)
159  , map_start_()
160  , victory_when_enemies_defeated_(level["victory_when_enemies_defeated"].to_bool(true))
161  , remove_from_carryover_on_defeat_(level["remove_from_carryover_on_defeat"].to_bool(true))
162  , victory_music_()
163  , defeat_music_()
164  , scope_()
165  , ignore_replay_errors_(false)
166  , player_type_changed_(false)
167 {
168  copy_persistent(level, level_);
169 
170  resources::controller = this;
174 
176 
177  join();
178 
180 
183 
184  try {
185  init(level);
186  } catch(...) {
187  clear_resources();
188  throw;
189  }
190 }
191 
193 {
194  help::reset();
196  clear_resources();
197 }
198 
200 {
201  void operator()(const config&) const
202  {
204  }
205 };
206 
208 {
209  gui2::dialogs::loading_screen::display([this, &level]() {
211 
212  LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl;
213  gamestate_.reset(new game_state(level, *this, tdata_));
214 
222 
223  gamestate_->ai_manager_.add_observer(this);
224  gamestate_->init(level, *this);
225 
227 
228  LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl;
230  whiteboard_manager_.reset(new wb::manager());
232 
233  LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl;
236 
237  LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl;
239  const config& theme_cfg = controller_base::get_theme(game_config_, theme());
240 
241  LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl;
243 
244  gui_.reset(new game_display(gamestate().board_, whiteboard_manager_, theme_cfg, level));
245 
246  map_start_ = map_location(level.child_or_empty("display").child_or_empty("location"));
247 
248  if(!gui_->video().faked()) {
250  gui_->get_theme().modify_label("time-icon", _("time left for current turn"));
251  } else {
252  gui_->get_theme().modify_label("time-icon", _("current local time"));
253  }
254  }
255 
257 
258  mouse_handler_.set_gui(gui_.get());
259  menu_handler_.set_gui(gui_.get());
260 
261  LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl;
262  LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl;
263 
264  // This *needs* to be created before the show_intro and show_map_scene
265  // as that functions use the manager state_of_game
266  // Has to be done before registering any events!
269 
270  if(gamestate().first_human_team_ != -1) {
271  gui_->set_team(gamestate().first_human_team_);
272  } else if(is_observer()) {
273  // Find first team that is allowed to be observed.
274  // If not set here observer would be without fog until
275  // the first turn of observable side
276  for(const team& t : gamestate().board_.teams()) {
277  if(!t.get_disallow_observers()) {
278  gui_->set_team(t.side() - 1);
279  }
280  }
281  }
282 
283  init_managers();
285 
286  // loadscreen_manager->reset();
288  gamestate().lua_kernel_->load_game(level);
289 
290  plugins_context_.reset(new plugins_context("Game"));
291  plugins_context_->set_callback(
292  "save_game", [this](const config& cfg) { save_game_auto(cfg["filename"]); }, true);
293  plugins_context_->set_callback(
294  "save_replay", [this](const config& cfg) { save_replay_auto(cfg["filename"]); }, true);
295  plugins_context_->set_callback("quit", throw_end_level(), false);
296  plugins_context_->set_accessor_string("scenario_name", [this](config) { return get_scenario_name(); });
297  });
298 
299  // Do this after the loadingscreen, so that ita happens in the main thread.
300  gui_->join();
301 
303 }
304 
306 {
307  // Set member in the base class
308  ui_.reset(new gui2::dialogs::game_ui());
309  assert(ui_);
310 
311  ui_->show(true);
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::tod_manager = nullptr;
319  resources::filter_con = nullptr;
320  resources::lua_kernel = nullptr;
321  resources::game_events = nullptr;
322  resources::tunnels = nullptr;
323  resources::undo_stack = nullptr;
324 
325  gui_->labels().set_team(nullptr);
326 
327  // First destroy the old game state, then create the new one.
328  // This is necessary to ensure that while the old AI manager is being destroyed,
329  // all its member objects access the old manager instead of the new.
330  gamestate_.reset();
331  gamestate_.reset(new game_state(level, *this, tdata_));
339 
340  gamestate_->ai_manager_.add_observer(this);
341  gamestate_->init(level, *this);
344 
345  //gui_->reset_reports(*gamestate().reports_);
346  gui_->change_display_context(&gamestate().board_);
347 
348  saved_game_.get_replay().set_pos(replay_pos);
349 
351  gamestate().lua_kernel_->load_game(level);
352 }
353 
355 {
356  LOG_NG << "initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
360 
362  LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
363 }
364 
366 {
367  // Run initialization scripts, even if loading from a snapshot.
368  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
369  pump().fire("preload");
370 }
371 
373 {
374  // pre-start events must be executed before any GUI operation,
375  // as those may cause the display to be refreshed.
376  update_locker lock_display(gui_->video());
378 
379  // Fire these right before prestart events, to catch only the units sides
380  // have started with.
381  for(const unit& u : gamestate().board_.units()) {
382  pump().fire("unit_placed", map_location(u.get_location()));
383  }
384 
385  pump().fire("prestart");
386 
387  // prestart event may modify start turn with WML, reflect any changes.
388  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
389 }
390 
392 {
394  pump().fire("start");
395 
396  // start event may modify start turn with WML, reflect any changes.
397  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
398 
400 
401  // prestart and start events may modify the initial gold amount, reflect any changes.
402  for(team& tm : gamestate().board_.teams_) {
403  tm.set_start_gold(tm.gold());
404  }
405 
406  gamestate_->init_side_done() = false;
408 }
409 
411 {
412  gui_->begin_game();
413  gui_->update_tod();
414 }
415 
417 {
419 
420  // If we are observers we move to watch next team if it is allowed
421  if((is_observer() && !current_team().get_disallow_observers())
422  || (current_team().is_local_human() && !this->is_replay())) {
424  }
425 
426  gui_->set_playing_team(std::size_t(current_side() - 1));
427 
429 }
430 
432 {
433  //
434  // We do side init only if not done yet for a local side when we are not replaying.
435  // For all other sides it is recorded in replay and replay handler has to handle
436  // calling do_init_side() functions.
437  //
438  if(gamestate_->init_side_done()) {
439  // We already executed do_init_side this can for example happen if we reload a game,
440  // but also if we changed control of a side during it's turn
441  return;
442  }
443 
444  if(!current_team().is_local()) {
445  // We are in a mp game and execute do_init_side as soon as we receive [init_side] from the current player
446  // (see replay.cpp)
447  return;
448  }
449 
450  if(is_replay()) {
451  // We are in a replay and execute do_init_side as soon as we reach the next [init_side] in the replay data
452  // (see replay.cpp)
453  return;
454  }
455 
457  do_init_side();
458 }
459 
461 {
462  set_scontext_synced sync;
463  log_scope("player turn");
464 
465  // In case we might end up calling sync:network during the side turn events,
466  // and we don't want do_init_side to be called when a player drops.
467  gamestate_->init_side_done() = true;
468  init_side_done_now_ = true;
469 
470  const std::string turn_num = std::to_string(turn());
471  const std::string side_num = std::to_string(current_side());
472 
473  gamestate().gamedata_.get_variable("side_number") = current_side();
474 
475  // We might have skipped some sides because they were empty so it is not enough to check for side_num==1
476  if(!gamestate().tod_manager_.has_turn_event_fired()) {
477  pump().fire("turn_" + turn_num);
478  pump().fire("new_turn");
480  }
481 
482  pump().fire("side_turn");
483  pump().fire("side_" + side_num + "_turn");
484  pump().fire("side_turn_" + turn_num);
485  pump().fire("side_" + side_num + "_turn_" + turn_num);
486 
487  // We want to work out if units for this player should get healed,
488  // and the player should get income now.
489  // Healing/income happen if it's not the first turn of processing,
490  // or if we are loading a game.
491  if(turn() > 1) {
494 
495  // If the expense is less than the number of villages owned
496  // times the village support capacity,
497  // then we don't have to pay anything at all
498  int expense = gamestate().board_.side_upkeep(current_side()) - current_team().support();
499  if(expense > 0) {
500  current_team().spend_gold(expense);
501  }
502 
504  }
505 
506  // Prepare the undo stack.
508 
509  pump().fire("turn_refresh");
510  pump().fire("side_" + side_num + "_turn_refresh");
511  pump().fire("turn_" + turn_num + "_refresh");
512  pump().fire("side_" + side_num + "_turn_" + turn_num + "_refresh");
513 
514  // Make sure vision is accurate.
516 
517  init_side_end();
518  check_victory();
519  sync.do_final_checkup();
520 }
521 
523 {
525 
526  if(current_side() == 1 || !init_side_done_now_) {
528  }
529 
530  if(!is_skipping_replay() && current_team().get_scroll_to_leader() && !map_start_.valid()) {
531  gui_->scroll_to_leader(current_side(), game_display::ONSCREEN, false);
532  }
533 
535  whiteboard_manager_->on_init_side();
536 }
537 
539 {
540  config cfg = level_;
541 
542  cfg["replay_pos"] = saved_game_.get_replay().get_pos();
543  gamestate().write(cfg);
544 
545  gui_->write(cfg.add_child("display"));
546 
547  // Write the soundsources.
548  soundsources_manager_->write_sourcespecs(cfg);
549 
550  gui_->labels().write(cfg);
552 
553  return cfg;
554 }
555 
557 {
558  whiteboard_manager_->on_finish_side_turn(current_side());
559 
560  { // Block for set_scontext_synced
561  set_scontext_synced sync(1);
562  // Ending the turn commits all moves.
563  undo_stack().clear();
565 
566  const std::string turn_num = std::to_string(turn());
567  const std::string side_num = std::to_string(current_side());
568 
569  // Clear shroud, in case units had been slowed for the turn.
571 
572  pump().fire("side_turn_end");
573  pump().fire("side_" + side_num + "_turn_end");
574  pump().fire("side_turn_" + turn_num + "_end");
575  pump().fire("side_" + side_num + "_turn_" + turn_num + "_end");
576 
577  // This is where we refog, after all of a side's events are done.
579  check_victory();
580  sync.do_final_checkup();
581  }
582 
584  gamestate_->init_side_done() = false;
585 }
586 
588 {
589  set_scontext_synced sync(2);
590  const std::string turn_num = std::to_string(turn());
591 
592  pump().fire("turn_end");
593  pump().fire("turn_" + turn_num + "_end");
594 
595  sync.do_final_checkup();
596 }
597 
599 {
600  // If we aren't using fog/shroud, this is easy :)
601  if(current_team().uses_fog() == false && current_team().uses_shroud() == false) {
602  return true;
603  }
604 
605  // See if any enemies are visible
606  for(const unit& u : gamestate().board_.units()) {
607  if(current_team().is_enemy(u.side()) && !gui_->fogged(u.get_location())) {
608  return true;
609  }
610  }
611 
612  return false;
613 }
614 
615 // TODO: implement in GUI2 command console dialog
616 #if 0
617 void play_controller::tab()
618 {
619  gui::TEXTBOX_MODE mode = menu_handler_.get_textbox().mode();
620 
621  std::set<std::string> dictionary;
622  switch(mode) {
623  case gui::TEXTBOX_SEARCH:
624  {
625  for (const unit& u : gamestate().board_.units()){
626  const map_location& loc = u.get_location();
627  if(!gui_->fogged(loc) &&
628  !(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
629  dictionary.insert(u.name());
630  }
631  //TODO List map labels
632  break;
633  }
634  case gui::TEXTBOX_COMMAND:
635  {
636  std::vector<std::string> commands = menu_handler_.get_commands_list();
637  dictionary.insert(commands.begin(), commands.end());
638  FALLTHROUGH; // we also want player names from the next case
639  }
640  case gui::TEXTBOX_MESSAGE:
641  {
642  for (const team& t : gamestate().board_.teams()) {
643  if(!t.is_empty())
644  dictionary.insert(t.current_player());
645  }
646 
647  // Add observers
648  for (const std::string& o : gui_->observers()){
649  dictionary.insert(o);
650  }
651 
652  // Add nicks who whispered you
653  for (const std::string& w : gui_->get_chat_manager().whisperers()){
654  dictionary.insert(w);
655  }
656 
657  // Add nicks from friendlist
658  const std::map<std::string, std::string> friends = preferences::get_acquaintances_nice("friend");
659 
660  for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter){
661  dictionary.insert((*iter).first);
662  }
663 
664  //Exclude own nick from tab-completion.
665  //NOTE why ?
666  dictionary.erase(preferences::login());
667  break;
668  }
669 
670  default:
671  ERR_DP << "unknown textbox mode" << std::endl;
672  } //switch(mode)
673 
674  menu_handler_.get_textbox().tab(dictionary);
675 }
676 #endif
677 
679 {
680  assert(gamestate().board_.has_team(current_side()));
682 }
683 
685 {
686  assert(gamestate().board_.has_team(current_side()));
688 }
689 
690 /// @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
691 static int modulo(int num, int mod, int min)
692 {
693  assert(mod > 0);
694  int n = (num - min) % mod;
695  if(n < 0)
696  n += mod;
697  // n is now in [0, mod)
698  n = n + min;
699  return n;
700  // the following properties are easy to verify:
701  // 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
702  // 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
703 }
704 
705 bool play_controller::is_team_visible(int team_num, bool observer) const
706 {
707  const team& t = gamestate().board_.get_team(team_num);
708  if(observer) {
709  return !t.get_disallow_observers() && !t.is_empty();
710  } else {
711  return t.is_local_human() && !t.is_idle();
712  }
713 }
714 
716 {
717  assert(current_side() <= static_cast<int>(gamestate().board_.teams().size()));
718  const int num_teams = gamestate().board_.teams().size();
719  const bool is_observer = this->is_observer();
720 
721  for(int i = 0; i < num_teams; i++) {
722  const int team_num = modulo(current_side() - i, num_teams, 1);
723  if(is_team_visible(team_num, is_observer)) {
724  return team_num;
725  }
726  }
727  return 0;
728 }
729 
731 {
732  return mouse_handler_;
733 }
734 
735 std::shared_ptr<wb::manager> play_controller::get_whiteboard() const
736 {
737  return whiteboard_manager_;
738 }
739 
741 {
742  return saved_game_.mp_settings();
743 }
744 
746 {
747  return saved_game_.classification();
748 }
749 
751 {
752  return *gui_;
753 }
754 
755 void play_controller::process_keydown_event(const SDL_Event& event)
756 {
757  if(event.key.keysym.sym == SDLK_TAB) {
758  whiteboard_manager_->set_invert_behavior(true);
759  }
760 }
761 
762 void play_controller::process_keyup_event(const SDL_Event& event)
763 {
764  // If the user has pressed 1 through 9, we want to show
765  // how far the unit can move in that many turns
766  if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9') {
767  const int new_path_turns = (event.type == SDL_KEYDOWN) ? event.key.keysym.sym - '1' : 0;
768 
769  if(new_path_turns != mouse_handler_.get_path_turns()) {
770  mouse_handler_.set_path_turns(new_path_turns);
771 
773 
774  if(u.valid()) {
775  // if it's not the unit's turn, we reset its moves
776  unit_movement_resetter move_reset(*u, u->side() != current_side());
777 
779  gamestate().board_.teams_[gui_->viewing_team()], mouse_handler_.get_path_turns()));
780 
781  gui_->highlight_reach(mouse_handler_.current_paths());
782  } else {
784  }
785  }
786  } else if(event.key.keysym.sym == SDLK_TAB) {
787  CKey keys;
788  if(!keys[SDLK_TAB]) {
789  whiteboard_manager_->set_invert_behavior(false);
790  }
791  }
792 }
793 
795 {
796  assert(replay_);
797  return *replay_.get();
798 }
799 
801 {
803  // Saving while an event is running isn't supported
804  // because it may lead to expired event handlers being saved.
805  assert(!gamestate().events_manager_->is_event_running());
806 
808  scoped_savegame_snapshot snapshot(*this);
811  } else {
813  }
814 }
815 
816 void play_controller::save_game_auto(const std::string& filename)
817 {
820 
821  scoped_savegame_snapshot snapshot(*this);
823  save.save_game_automatic(false, filename);
824  }
825 }
826 
828 {
833  } else {
835  }
836 }
837 
838 void play_controller::save_replay_auto(const std::string& filename)
839 {
843  save.save_game_automatic(false, filename);
844  }
845 }
846 
848 {
852  } else {
854  }
855 }
856 
858 {
860  load.load_game_ingame();
861 }
862 
864 {
866  undo_stack().undo();
867 }
868 
870 {
872  undo_stack().redo();
873 }
874 
876 {
878 }
879 
881 {
883 }
884 
885 const std::string& play_controller::select_music(bool victory) const
886 {
887  const std::vector<std::string>& music_list = victory
888  ? (gamestate_->get_game_data()->get_victory_music().empty()
890  : gamestate_->get_game_data()->get_victory_music())
891  : (gamestate_->get_game_data()->get_defeat_music().empty()
893  : gamestate_->get_game_data()->get_defeat_music());
894 
895  if(music_list.empty()) {
896  // Since this function returns a reference, we can't return a temporary empty string.
897  static const std::string empty_str = "";
898  return empty_str;
899  }
900 
901  return music_list[randomness::rng::default_instance().get_random_int(0, music_list.size() - 1)];
902 }
903 
905 {
906  if(linger_) {
907  return;
908  }
909 
910  if(is_regular_game_end()) {
911  return;
912  }
913 
914  bool continue_level, found_player, found_network_player, invalidate_all;
915  std::set<unsigned> not_defeated;
916 
918  continue_level,
919  found_player,
920  found_network_player,
921  invalidate_all,
922  not_defeated,
924  );
925 
926  if(continue_level) {
927  return;
928  }
929 
930  if(found_player || found_network_player) {
931  pump().fire("enemies_defeated");
932 
933  if(is_regular_game_end()) {
934  return;
935  }
936  }
937 
938  DBG_EE << "victory_when_enemies_defeated: " << victory_when_enemies_defeated_ << std::endl;
939  DBG_EE << "found_player: " << found_player << std::endl;
940  DBG_EE << "found_network_player: " << found_network_player << std::endl;
941 
942  if(!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
943  // This level has asked not to be ended by this condition.
944  return;
945  }
946 
947  if(gui_->video().non_interactive()) {
948  LOG_AIT << "winner: ";
949 
950  for(unsigned l : not_defeated) {
952  if(ai.empty()) {
953  ai = "default ai";
954  }
955 
956  LOG_AIT << l << " (using " << ai << ") ";
957  }
958 
959  LOG_AIT << std::endl;
960  ai_testing::log_victory(not_defeated);
961  }
962 
963  DBG_EE << "throwing end level exception..." << std::endl;
964 
965  // Also proceed to the next scenario when another player survived.
966  end_level_data el_data;
967  el_data.proceed_to_next_level = found_player || found_network_player;
968  el_data.is_victory = found_player;
969  set_end_level_data(el_data);
970 }
971 
972 void play_controller::process_oos(const std::string& msg) const
973 {
974  if(gui_->video().non_interactive()) {
975  throw game::game_error(msg);
976  }
977 
979  return;
980  }
981 
982  std::stringstream message;
983  message << _("The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
984  message << "\n\n" << _("Error details:") << "\n\n" << msg;
985 
986  scoped_savegame_snapshot snapshot(*this);
988  save.save_game_interactive(message.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
989 }
990 
991 void play_controller::update_gui_to_player(const int team_index, const bool observe)
992 {
993  gui_->set_team(team_index, observe);
994  gui_->recalculate_minimap();
995 }
996 
998 {
999  scoped_savegame_snapshot snapshot(*this);
1002 }
1003 
1004 void play_controller::do_consolesave(const std::string& filename)
1005 {
1006  scoped_savegame_snapshot snapshot(*this);
1008  save.save_game_automatic(true, filename);
1009 }
1010 
1012 {
1013  // note: this writes to level_ if this is not a replay.
1015 }
1016 
1018 {
1019  return gamestate().events_manager_->pump();
1020 }
1021 
1023 {
1024  return ticks_;
1025 }
1026 
1028 {
1029  return soundsources_manager_.get();
1030 }
1031 
1033 {
1034  return plugins_context_.get();
1035 }
1036 
1038 {
1039  return hotkey_handler_.get();
1040 }
1041 
1043 {
1044  if(linger_ || !gamestate_->init_side_done() || gamestate().gamedata_.phase() != game_data::PLAY) {
1045  return true;
1046  }
1047 
1048  const team& t = current_team();
1049  return !t.is_local_human() || !t.is_proxy_human();
1050 }
1051 
1053 {
1055  return;
1056  }
1057 
1058  try {
1059  play_slice();
1060  } catch(const return_to_play_side_exception&) {
1061  assert(should_return_to_play_side());
1062  }
1063 }
1064 
1066 {
1067  fire_preload();
1068 
1069  if(!gamestate().start_event_fired_) {
1070  gamestate().start_event_fired_ = true;
1074 
1075  set_scontext_synced sync;
1076 
1077  fire_prestart();
1078 
1079  if(is_regular_game_end()) {
1080  return;
1081  }
1082 
1083  for(const team& t : gamestate().board_.teams()) {
1084  actions::clear_shroud(t.side(), false, false);
1085  }
1086 
1087  init_gui();
1088  LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";
1089 
1090  fire_start();
1091 
1092  if(is_regular_game_end()) {
1093  return;
1094  }
1095 
1096  sync.do_final_checkup();
1097  gui_->recalculate_minimap();
1098 
1099  // Initialize countdown clock.
1100  for(const team& t : gamestate().board_.teams()) {
1102  t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
1103  }
1104  }
1105  } else {
1106  init_gui();
1108  gui_->recalculate_minimap();
1109  }
1110 }
1111 
1113 {
1114  const team& viewing_team = get_teams_const()[gui_->viewing_team()];
1115  return gui_->viewing_team() == gui_->playing_team() && !events::commands_disabled && viewing_team.is_local_human()
1116  && !is_lingering() && !is_browsing();
1117 }
1118 
1119 std::set<std::string> play_controller::all_players() const
1120 {
1121  std::set<std::string> res = gui_->observers();
1122  for(const team& t : get_teams_const()) {
1123  if(t.is_human()) {
1124  res.insert(t.current_player());
1125  }
1126  }
1127 
1128  return res;
1129 }
1130 
1132 {
1133  do {
1135  {
1136  save_blocker blocker;
1138  if(is_regular_game_end()) {
1139  return;
1140  }
1141  }
1142 
1143  // This flag can be set by derived classes (in overridden functions).
1144  player_type_changed_ = false;
1145 
1146  statistics::reset_turn_stats(gamestate().board_.get_team(current_side()).save_id());
1147 
1148  play_side_impl();
1149 
1150  if(is_regular_game_end()) {
1151  return;
1152  }
1153 
1154  } while(player_type_changed_);
1155 
1156  // Keep looping if the type of a team (human/ai/networked) has changed mid-turn
1157  sync_end_turn();
1158 }
1159 
1161 {
1162  whiteboard_manager_->on_gamestate_change();
1163  gui_->new_turn();
1164 
1165  LOG_NG << "turn: " << turn() << "\n";
1166 
1167  if(gui_->video().non_interactive()) {
1168  LOG_AIT << "Turn " << turn() << ":" << std::endl;
1169  }
1170 
1171  int last_player_number = gamestate_->player_number_;
1172  int next_player_number = gamestate_->next_player_number_;
1173 
1174  while(gamestate_->player_number_ <= static_cast<int>(gamestate().board_.teams().size())) {
1175  gamestate_->next_player_number_ = gamestate_->player_number_ + 1;
1176  next_player_number = gamestate_->next_player_number_;
1177  last_player_number = gamestate_->player_number_;
1178 
1179  // If a side is empty skip over it.
1180  if(!current_team().is_empty()) {
1181  init_side_begin();
1182 
1183  if(gamestate_->init_side_done()) {
1184  // This is the case in a reloaded game where the side was initialized before saving the game.
1185  init_side_end();
1186  }
1187 
1189  play_side();
1190  // ignore any changes to next_player_number_ that happen after the [end_turn] is sent to the server,
1191  // otherwise we will get OOS.
1192  next_player_number = gamestate_->next_player_number_;
1193  assert(next_player_number <= 2 * static_cast<int>(gamestate().board_.teams().size()));
1194  if(is_regular_game_end()) {
1195  return;
1196  }
1197  // note: play_side() send the [end_turn] to the sever and finish_side_turn() calls the side turn end
1198  // events.
1199  // this means that during the side turn end events the clients think it is still the last sides turn
1200  // while the server thinks that it is already the next plyers turn. i don'T think this is a problem
1201  // though.
1202  finish_side_turn();
1203 
1204  if(is_regular_game_end()) {
1205  return;
1206  }
1207 
1208  if(gui_->video().non_interactive()) {
1209  LOG_AIT << " Player " << current_side() << ": " << current_team().villages().size() << " Villages"
1210  << std::endl;
1212  }
1213  }
1214 
1215  gamestate_->player_number_ = next_player_number;
1216  }
1217 
1218  // If the loop exits due to the last team having been processed.
1219  gamestate_->player_number_ = last_player_number;
1220 
1221  finish_turn();
1222 
1223  // Time has run out
1224  check_time_over();
1225 
1226  if(!is_regular_game_end()) {
1227  gamestate_->player_number_ = modulo(next_player_number, gamestate().board_.teams().size(), 1);
1228  }
1229 }
1230 
1232 {
1233  const bool time_left = gamestate().tod_manager_.next_turn(&gamestate().gamedata_);
1234 
1235  if(!time_left) {
1236  LOG_NG << "firing time over event...\n";
1237 
1239  pump().fire("time_over");
1240 
1241  LOG_NG << "done firing time over event...\n";
1242 
1243  // If turns are added while handling 'time over' event.
1244  if(gamestate().tod_manager_.is_time_left()) {
1245  return;
1246  }
1247 
1248  if(gui_->video().non_interactive()) {
1249  LOG_AIT << "time over (draw)\n";
1251  }
1252 
1253  check_victory();
1254 
1255  if(is_regular_game_end()) {
1256  return;
1257  }
1258 
1259  end_level_data e;
1260  e.proceed_to_next_level = false;
1261  e.is_victory = false;
1262  set_end_level_data(e);
1263  }
1264 }
1265 
1267  : controller_(controller)
1268 {
1270 }
1271 
1273 {
1275 }
1276 
1278 {
1279  const team& t = gamestate().board_.teams()[gui_->viewing_team()];
1280  static const std::string no_objectives(_("No objectives available"));
1281  std::string objectives = utils::interpolate_variables_into_string(t.objectives(), *gamestate_->get_game_data());
1282  gui2::show_transient_message(get_scenario_name(), (objectives.empty() ? no_objectives : objectives), "", true);
1284 }
1285 
1287 {
1289 #if 0
1290  const std::shared_ptr<gui::button> skip_animation_button = get_display().find_action_button("skip-animation");
1291  if(skip_animation_button) {
1292  skip_animation_button->set_check(skip_replay_);
1293  }
1294 #endif
1295 }
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:220
play_controller * controller
Definition: resources.cpp:21
std::vector< std::string > default_victory_music
void set_current_paths(const pathfind::paths &new_paths)
int autosavemax()
Definition: game.cpp:809
virtual bool should_return_to_play_side() const
std::unique_ptr< soundsource::manager > soundsources_manager_
void operator()(const config &) const
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()
Definition: display.cpp:44
::tod_manager * tod_manager
Definition: resources.cpp:29
static lg::log_domain log_engine_enemies("engine/enemies")
bool is_empty() const
Definition: team.hpp:256
hotkey::command_executor * get_hotkey_command_executor() override
Optionally get a command executor to handle context menu events.
void reset_objectives_changed() const
Definition: team.hpp:236
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with &#39;$&#39; in the string &#39;str&#39; with the equivalent ...
map_location last_selected
the last location where a select event fired.
Definition: game_data.hpp:83
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
The class for loading a savefile.
Definition: savegame.hpp:96
std::unique_ptr< game_lua_kernel > lua_kernel_
Definition: game_state.hpp:50
void save_replay_auto(const std::string &filename)
int find_last_visible_team() const
returns 0 if no such team was found.
const ter_data_cache & tdata_
This class represents a single unit of a specific type.
Definition: unit.hpp:99
std::unique_ptr< game_display > gui_
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:34
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)
events::mouse_handler mouse_handler_
static manager & get_singleton()
Definition: manager.hpp:152
static void copy_persistent(const config &src, config &dst)
Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
std::unique_ptr< plugins_context > plugins_context_
bool is_skipping_replay() const
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
Definition: tips.cpp:35
std::unique_ptr< replay > replay_
void reset()
Flags the help manager&#39;s contents for regeneration.
Definition: help.cpp:41
game_display & get_display() override
Get a reference to a display member a derived class uses.
replay_recorder_base & get_replay()
Definition: saved_game.hpp:121
Class for autosaves.
Definition: savegame.hpp:269
game_events::wml_event_pump & pump()
void set_scope_active(scope s, bool set)
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...
std::unique_ptr< hotkey_handler > hotkey_handler_
const int INFINITE_AUTO_SAVES
Definition: game.hpp:189
bool enemies_visible() const
void process_keydown_event(const SDL_Event &event) override
Process keydown (always).
bool is_idle() const
Definition: team.hpp:282
const pathfind::paths & current_paths() const
static void progress(loading_stage stage=loading_stage::none)
virtual void update_viewing_player()=0
void new_turn()
Definition: team.hpp:203
void set_gui(game_display *gui)
Definition: menu_events.hpp:51
virtual soundsource::manager * get_soundsource_man() override
Get (optionally) a soundsources manager a derived class uses.
void undo()
Undoes the top action on the undo stack.
Definition: undo.cpp:348
static lg::log_domain log_aitesting("aitesting")
Gather statistics important for AI testing and output them.
virtual void process_oos(const std::string &msg) const
Asks the user whether to continue on an OOS error.
virtual void play_slice(bool is_delay_enabled=true)
#define LOG_AIT
void new_side_turn(int side)
Performs some initializations and error checks when starting a new side-turn.
Definition: undo.cpp:262
static lg::log_domain log_engine("engine")
Class for "normal" midgame saves.
Definition: savegame.hpp:242
Replay control code.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
persist_manager * persist
Definition: resources.cpp:26
void check_victory()
Checks to see if a side has won.
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:503
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:245
static void log_draw()
Definition: testing.cpp:75
bool save_game_interactive(const std::string &message, DIALOG_TYPE dialog_type)
Save a game interactively through the savegame dialog.
Definition: savegame.cpp:353
static lg::log_domain log_display("display")
void write_music_play_list(config &snapshot)
Definition: sound.cpp:812
#define DBG_EE
void process_keyup_event(const SDL_Event &event) override
Process keyup (always).
static void clear_resources()
This file implements all the hotkey handling and menu details for play controller.
void select_hex(const map_location &hex, const bool browse, const bool highlight=true, const bool fire_event=true)
persist_manager persist_
void reset_turn_stats(const std::string &save_id)
Definition: statistics.cpp:546
static void add_color_info(const config &v, bool build_defaults)
#define ERR_DP
std::unique_ptr< tooltips::manager > tooltips_manager_
std::vector< std::string > default_defeat_music
const std::unique_ptr< game_events::manager > events_manager_
Definition: game_state.hpp:52
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:62
events::menu_handler menu_handler_
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:989
bool can_undo() const
void set_phase(PHASE phase)
Definition: game_data.hpp:77
std::unique_ptr< game_state > gamestate_
An exception-safe means of making sure that unblock() gets called after try_block().
void do_consolesave(const std::string &filename)
bool is_lingering() const
map_location get_selected_hex() const
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
saved_game & saved_game_
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
scoped_savegame_snapshot(const play_controller &controller)
void init_side()
Definition: replay.cpp:215
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
static int modulo(int num, int mod, int min)
team & get_team(int i)
Definition: game_board.hpp:104
void throw_quit_game_exception()
void save_game_auto(const std::string &filename)
bool add_start_if_not_there_yet()
Definition: replay.cpp:654
void set_path_turns(const int path_turns)
virtual void check_time_over()
bool can_redo() const
True if there are actions that can be redone.
Definition: undo.hpp:94
Implements a quit confirmation dialog.
config to_config() const
Builds the snapshot config from members and their respective configs.
filter_context * filter_con
Definition: resources.cpp:23
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
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:54
bool valid() const
Definition: location.hpp:93
bool ignore_replay_errors
int side_upkeep(int side_num) const
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:42
bool is_regular_game_end() const
void init(const config &level)
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:693
virtual void join()
Definition: events.cpp:237
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...
bool is_enemy(int n) const
Definition: team.hpp:241
tod_manager tod_manager_
Definition: game_state.hpp:47
Object which temporarily resets a unit&#39;s movement.
Definition: unit.hpp:1765
bool load_game_ingame()
Load a game without providing any information.
Definition: savegame.cpp:119
std::unique_ptr< pathfind::manager > pathfind_manager_
Definition: game_state.hpp:48
Managing the AIs lifecycle - headers.
std::string theme() const
replay * recorder
Definition: resources.cpp:28
void check_victory(bool &, bool &, bool &, bool &, std::set< unsigned > &, bool)
Definition: game_board.cpp:96
void set_gui(game_display *gui)
void spend_gold(const int amount)
Definition: team.hpp:207
std::shared_ptr< wb::manager > get_whiteboard() const
An object which will lock the display for the duration of its lifetime.
Definition: video.hpp:256
Error used for any general game error, e.g.
Definition: game_errors.hpp:46
game_events::manager * game_events
Definition: resources.cpp:24
bool is_browsing() const override
void deactivate_all_scopes()
virtual void initialize_and_show_ui() override
Creates and displays the HUD UI that accompanies this controller.
bool is_observer() const
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:42
void calculate_healing(int side, bool update_display)
Calculates healing for all units for the given side.
Definition: heal.cpp:292
std::string login()
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:33
virtual ~play_controller()
bool is_proxy_human() const
Definition: team.hpp:280
Various functions related to the creation of units (recruits, recalls, and placed units)...
int support() const
Calculate total support capacity, based on support_per_village.
Definition: team.hpp:202
void set_end_level_data(const end_level_data &data)
void end_turn(int pnum)
Definition: game_board.cpp:72
int get_path_turns() const
std::size_t i
Definition: function.cpp:933
soundsource::manager * soundsources
Definition: resources.cpp:27
const std::string & select_music(bool victory) const
void redo()
Redoes the top action on the redo stack.
Definition: undo.cpp:396
map_location map_start_
Game configuration data as global variables.
Definition: build_info.cpp:46
unit_map::iterator selected_unit()
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:712
const config & game_config_
void reset_gamestate(const config &level, int replay_pos)
const t_string & objectives() const
Definition: team.hpp:238
std::shared_ptr< wb::manager > whiteboard_manager_
bool is_team_visible(int team_num, bool observer) const
Define the game&#39;s event mechanism.
void encounter_all_content(const game_board &gameboard_)
Definition: game.cpp:1023
#define log_scope(description)
Definition: log.hpp:186
bool proceed_to_next_level
whether to proceed to the next scenario, equals is_victory in sp.
bool can_use_synced_wml_menu() const
void turn_event_fired()
t_string get_scenario_name() const
game_data gamedata_
Definition: game_state.hpp:45
int w
Additional information on the game outcome which can be provided by WML.
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
Definition: random.hpp:51
actions::undo_list & undo_stack()
std::map< std::string, std::string > get_acquaintances_nice(const std::string &filter)
Definition: game.cpp:235
static void save(LexState *ls, int c)
Definition: llex.cpp:57
bool can_redo() const
static lg::log_domain log_enginerefac("enginerefac")
std::unique_ptr< gui2::dialogs::game_ui > ui_
std::string observer
bool is_local() const
Definition: team.hpp:258
Class for replay saves (either manually or automatically).
Definition: savegame.hpp:256
config & add_child(config_key_type key)
Definition: config.cpp:479
pump_result_t 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:491
compression::format save_compression_format()
Definition: game.cpp:872
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:739
static bool try_block()
bool get_disallow_observers() const
Definition: team.hpp:336
static void display(std::function< void()> f)
void set_game_display(game_display *)
Definition: game_state.cpp:232
bool is_local_human() const
Definition: team.hpp:264
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
game_state & gamestate()
double t
Definition: astarsearch.cpp:63
Various functions that implement healing of units (when a side turn starts).
game_classification & classification()
Definition: saved_game.hpp:55
game_board board_
Definition: game_state.hpp:46
Various functions that implement the undoing (and redoing) of in-game commands.
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:581
int current_side() const
Returns the number of the side whose turn it is.
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition: pathfind.hpp:70
static const map_location & null_location()
Definition: location.hpp:85
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
config * get_next_action()
Definition: replay.cpp:614
std::set< std::string > all_players() const
void fire_preload()
preload events cannot be synced
virtual plugins_context * get_plugins_context() override
Get (optionally) a plugins context a derived class uses.
void new_turn(int pnum)
Definition: game_board.cpp:64
#define e
actions::undo_list * undo_stack
Definition: resources.cpp:32
std::size_t turn() const
void update_savegame_snapshot() const
void remove_snapshot()
Definition: saved_game.cpp:521
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:456
const std::vector< team > & get_teams_const() const
void set_side(int side_number)
bool next_turn(game_data *vars)
Function to move to the next turn.
PHASE phase() const
Definition: game_data.hpp:76
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
game_classification & get_classification()
bool valid() const
Definition: map.hpp:276
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:27
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:59
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 write(config &cfg) const
Definition: game_state.cpp:237
static map_location::DIRECTION n
const std::set< map_location > & villages() const
Definition: team.hpp:183
pathfind::manager * tunnels
Definition: resources.cpp:31
bool can_undo() const
True if there are actions that can be undone.
Definition: undo.hpp:92
static rng & default_instance()
Definition: random.cpp:73
virtual void check_objectives()=0
bool save_game_automatic(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:337
virtual void play_side_impl()
bool start_event_fired_
Definition: game_state.hpp:62
void show_objectives() const
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_
#define LOG_NG
play_controller(const config &level, saved_game &state_of_game, const config &game_config, const ter_data_cache &tdata, bool skip_replay)
std::shared_ptr< terrain_type_data > ter_data_cache
virtual void sync_end_turn()