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 https://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"
30 #include "display_chat_manager.hpp"
31 #include "formula/string_utils.hpp"
33 #include "game_events/pump.hpp"
34 #include "preferences/game.hpp"
35 #include "game_state.hpp"
36 #include "hotkey/hotkey_item.hpp"
38 #include "map/label.hpp"
39 #include "gettext.hpp"
43 #include "log.hpp"
44 #include "pathfind/teleport.hpp"
45 #include "preferences/display.hpp"
46 #include "random.hpp"
47 #include "replay.hpp"
48 #include "reports.hpp"
49 #include "resources.hpp"
50 #include "savegame.hpp"
51 #include "saved_game.hpp"
52 #include "save_blocker.hpp"
55 #include "sound.hpp"
56 #include "soundsource.hpp"
57 #include "statistics.hpp"
58 #include "synced_context.hpp"
59 #include "terrain/type_data.hpp"
60 #include "tooltips.hpp"
61 #include "units/unit.hpp"
62 #include "units/id.hpp"
63 #include "whiteboard/manager.hpp"
64 
65 #include "utils/functional.hpp"
66 
67 static lg::log_domain log_aitesting("aitesting");
68 #define LOG_AIT LOG_STREAM(info, log_aitesting)
69 //If necessary, this define can be replaced with `#define LOG_AIT std::cout` to restore previous behavior
70 
71 static lg::log_domain log_engine("engine");
72 #define LOG_NG LOG_STREAM(info, log_engine)
73 #define DBG_NG LOG_STREAM(debug, log_engine)
74 
75 static lg::log_domain log_display("display");
76 #define ERR_DP LOG_STREAM(err, log_display)
77 
78 static lg::log_domain log_enginerefac("enginerefac");
79 #define LOG_RG LOG_STREAM(info, log_enginerefac)
80 
81 static lg::log_domain log_engine_enemies("engine/enemies");
82 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
83 
84 /**
85  * Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
86  */
87 static void copy_persistent(const config& src, config& dst)
88 {
89  static const std::set<std::string> attrs {
90  "description",
91  "name",
92  "victory_when_enemies_defeated",
93  "remove_from_carryover_on_defeat",
94  "disallow_recall",
95  "experience_modifier",
96  "require_scenario"};
97 
98  static const std::set<std::string> tags {
99  "terrain_graphics",
100  "lua"};
101 
102  for (const std::string& attr : attrs)
103  {
104  dst[attr] = src[attr];
105  }
106 
107  for (const std::string& tag : tags)
108  {
109  dst.append_children(src, tag);
110  }
111 }
112 
113 static void clear_resources()
114 {
115  resources::controller = nullptr;
116  resources::filter_con = nullptr;
117  resources::gameboard = nullptr;
118  resources::gamedata = nullptr;
119  resources::game_events = nullptr;
120  resources::lua_kernel = nullptr;
121  resources::persist = nullptr;
122  resources::soundsources = nullptr;
123  resources::tod_manager = nullptr;
124  resources::tunnels = nullptr;
125  resources::undo_stack = nullptr;
126  resources::recorder = nullptr;
127  resources::whiteboard.reset();
128  resources::classification = nullptr;
129 }
130 
132  const ter_data_cache& tdata, bool skip_replay)
133  : controller_base()
134  , observer()
136  , ticks_(SDL_GetTicks())
137  , tdata_(tdata)
138  , gamestate_()
139  , level_()
140  , saved_game_(state_of_game)
141  , tooltips_manager_()
142  , whiteboard_manager_()
143  , plugins_context_()
144  , labels_manager_()
145  , help_manager_(&game_config_)
146  , mouse_handler_(nullptr, *this)
147  , menu_handler_(nullptr, *this)
148  , hotkey_handler_(new hotkey_handler(*this, saved_game_))
149  , soundsources_manager_()
150  , persist_()
151  , gui_()
152  , xp_mod_(new unit_experience_accelerator(level["experience_modifier"].to_int(100)))
153  , statistics_context_(new statistics::scenario_context(level["name"]))
154  , replay_(new replay(state_of_game.get_replay()))
155  , skip_replay_(skip_replay)
156  , skip_story_(state_of_game.skip_story())
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;
173 
175 
177 
181  try {
182  init(level);
183  } catch (...) {
184  clear_resources();
185  throw;
186  }
187 }
188 
190 {
192  clear_resources();
193 }
194 
196 {
197  void operator()(const config&) const
198  {
200  }
201 };
202 
204 {
205  gui2::dialogs::loading_screen::display([this, &level]() {
207 
208  LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl;
209  gamestate_.reset(new game_state(level, *this, tdata_));
210 
218 
219  gamestate_->ai_manager_.add_observer(this);
220  gamestate_->init(level, *this);
222 
223  LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl;
225  whiteboard_manager_.reset(new wb::manager());
227 
228  LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl;
231 
232  LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl;
234  const config& theme_cfg = controller_base::get_theme(game_config_, theme());
235 
236  LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl;
238  gui_.reset(new game_display(gamestate().board_, whiteboard_manager_, *gamestate().reports_, theme_cfg, level));
239  map_start_ = map_location(level.child_or_empty("display").child_or_empty("location"));
240  if (!gui_->video().faked()) {
242  gui_->get_theme().modify_label("time-icon", _ ("time left for current turn"));
243  else
244  gui_->get_theme().modify_label("time-icon", _ ("current local time"));
245  }
246 
248  mouse_handler_.set_gui(gui_.get());
249  menu_handler_.set_gui(gui_.get());
250 
251  LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl;
252 
253  LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl;
254  // This *needs* to be created before the show_intro and show_map_scene
255  // as that functions use the manager state_of_game
256  // Has to be done before registering any events!
259 
260  if(gamestate().first_human_team_ != -1) {
261  gui_->set_team(gamestate().first_human_team_);
262  }
263  else if(is_observer()) {
264  // Find first team that is allowed to be observed.
265  // If not set here observer would be without fog until
266  // the first turn of observable side
267  for (const team& t : gamestate().board_.teams())
268  {
269  if (!t.get_disallow_observers())
270  {
271  gui_->set_team(t.side() - 1);
272  }
273  }
274  }
275 
276  init_managers();
278  //loadscreen_manager->reset();
280  gamestate().lua_kernel_->load_game(level);
281 
282  plugins_context_.reset(new plugins_context("Game"));
283  plugins_context_->set_callback("save_game", [this](const config& cfg) { save_game_auto(cfg["filename"]); }, true);
284  plugins_context_->set_callback("save_replay", [this](const config& cfg) { save_replay_auto(cfg["filename"]); }, true);
285  plugins_context_->set_callback("quit", throw_end_level(), false);
286  plugins_context_->set_accessor_string("scenario_name", [this](config) { return get_scenario_name(); });
287  });
288  //Do this after the loadingscreen, so that ita happens in the main thread.
289  gui_->join();
290 }
291 
292 void play_controller::reset_gamestate(const config& level, int replay_pos)
293 {
294  resources::gameboard = nullptr;
295  resources::gamedata = nullptr;
296  resources::tod_manager = nullptr;
297  resources::filter_con = nullptr;
298  resources::lua_kernel = nullptr;
299  resources::game_events = nullptr;
300  resources::tunnels = nullptr;
301  resources::undo_stack = nullptr;
302 
303  gui_->labels().set_team(nullptr);
304 
305  /* First destroy the old game state, then create the new one.
306  This is necessary to ensure that while the old AI manager is being destroyed,
307  all its member objects access the old manager instead of the new. */
308  gamestate_.reset();
309  gamestate_.reset(new game_state(level, *this, tdata_));
317 
318  gamestate_->ai_manager_.add_observer(this);
319  gamestate_->init(level, *this);
322 
323  gui_->reset_reports(*gamestate().reports_);
324  gui_->change_display_context(&gamestate().board_);
325  saved_game_.get_replay().set_pos(replay_pos);
327  gamestate().lua_kernel_->load_game(level);
328 }
329 
331 {
332  LOG_NG << "initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
336 
338  LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
339 }
340 
342 {
343  // Run initialization scripts, even if loading from a snapshot.
344  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
345  pump().fire("preload");
346 }
347 
349 {
350  // pre-start events must be executed before any GUI operation,
351  // as those may cause the display to be refreshed.
352  update_locker lock_display(gui_->video());
354 
355  // Fire these right before prestart events, to catch only the units sides
356  // have started with.
357  for (const unit& u : gamestate().board_.units()) {
358  pump().fire("unit_placed", map_location(u.get_location()));
359  }
360 
361  pump().fire("prestart");
362  // prestart event may modify start turn with WML, reflect any changes.
363  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
364 }
365 
367 {
368  const config cfg("side", gui_->viewing_side());
369  gamestate().lua_kernel_->run_wml_action("show_objectives", vconfig(cfg),
370  game_events::queued_event("_from_interface", "", map_location(), map_location(), config()));
371 }
372 
374 {
376  pump().fire("start");
377 
378  skip_story_ = false; // Show [message]s from now on even with --campaign-skip-story
379 
380  // start event may modify start turn with WML, reflect any changes.
381  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
382 
385  // prestart and start events may modify the initial gold amount,
386  // reflect any changes.
387  for (team& tm : gamestate().board_.teams_)
388  {
389  tm.set_start_gold(tm.gold());
390  }
391  gamestate_->init_side_done() = false;
393 }
394 
396 {
397  gui_->begin_game();
398  gui_->update_tod();
399 }
400 
402 {
404 
405  // If we are observers we move to watch next team if it is allowed
406  if ((is_observer() && !current_team().get_disallow_observers())
407  || (current_team().is_local_human() && !this->is_replay()))
408  {
410  }
411 
412  gui_->set_playing_team(std::size_t(current_side() - 1));
413 
415 }
416 
418 {
419  //
420  // We do side init only if not done yet for a local side when we are not replaying.
421  // For all other sides it is recorded in replay and replay handler has to handle
422  // calling do_init_side() functions.
423  //
424  if (gamestate_->init_side_done()) {
425  // We already executed do_init_side this can for example happe if we reload a game,
426  // but also if we changed control of a side during it's turn
427  return;
428  }
429  if (!current_team().is_local()) {
430  // We are in a mp game and execute do_init_side as soon as we receive [init_side] from the current player
431  // (see replay.cpp)
432  return;
433  }
434 
435  if (is_replay()) {
436  // We are in a replay and execute do_init_side as soon as we reach the next [init_side] in the replay data
437  // (see replay.cpp)
438  return;
439  }
440 
441  if (current_team().is_idle()) {
442  // In this case it can happen that we just gave control of this side to another player so doing init_side
443  // could lead to errors since we no longer own this side from the servers perspective.
444  // (see playturn.cpp)
445  return;
446  }
447 
449  do_init_side();
450 }
451 
453 {
454  set_scontext_synced sync;
455  log_scope("player turn");
456  // In case we might end up calling sync:network during the side turn events,
457  // and we don't want do_init_side to be called when a player drops.
458  gamestate_->init_side_done() = true;
459  init_side_done_now_ = true;
460 
461  const std::string turn_num = std::to_string(turn());
462  const std::string side_num = std::to_string(current_side());
463 
464  gamestate().gamedata_.get_variable("side_number") = current_side();
465 
466  // We might have skipped some sides because they were empty so it is not enough to check for side_num==1
467  if(!gamestate().tod_manager_.has_turn_event_fired())
468  {
469  pump().fire("turn_" + turn_num);
470  pump().fire("new_turn");
472  }
473 
474  pump().fire("side_turn");
475  pump().fire("side_" + side_num + "_turn");
476  pump().fire("side_turn_" + turn_num);
477  pump().fire("side_" + side_num + "_turn_" + turn_num);
478 
479  // We want to work out if units for this player should get healed,
480  // and the player should get income now.
481  // Healing/income happen if it's not the first turn of processing,
482  // or if we are loading a game.
483  if (turn() > 1) {
486 
487  // If the expense is less than the number of villages owned
488  // times the village support capacity,
489  // then we don't have to pay anything at all
490  int expense = gamestate().board_.side_upkeep(current_side()) -
491  current_team().support();
492  if(expense > 0) {
493  current_team().spend_gold(expense);
494  }
495  }
496  if (do_healing()) {
498  }
499  // Do healing on every side turn except the very first side turn.
500  // (1.14 and earlier did healing whenever turn >= 2.)
501  set_do_healing(true);
502  // Set resting now after the healing has been done.
503  for(unit &patient : resources::gameboard->units()) {
504  if(patient.side() == current_side()) {
505  patient.set_resting(true);
506  }
507  }
508 
509  // Prepare the undo stack.
511 
512  pump().fire("turn_refresh");
513  pump().fire("side_" + side_num + "_turn_refresh");
514  pump().fire("turn_" + turn_num + "_refresh");
515  pump().fire("side_" + side_num + "_turn_" + turn_num + "_refresh");
516 
517  // Make sure vision is accurate.
519  init_side_end();
520  check_victory();
521  sync.do_final_checkup();
522 }
523 
525 {
527 
528  if (current_side() == 1 || !init_side_done_now_)
530 
531  if (!is_skipping_replay()){
532  gui_->invalidate_all();
533  }
534 
535  if (!is_skipping_replay() && current_team().get_scroll_to_leader() && !map_start_.valid()){
536  gui_->scroll_to_leader(current_side(), game_display::ONSCREEN,false);
537  }
539  whiteboard_manager_->on_init_side();
540 }
541 
543 {
544  config cfg = level_;
545 
546  cfg["replay_pos"] = saved_game_.get_replay().get_pos();
547  gamestate().write(cfg);
548 
549  gui_->write(cfg.add_child("display"));
550 
551  //Write the soundsources.
552  soundsources_manager_->write_sourcespecs(cfg);
553 
554  gui_->labels().write(cfg);
556 
557  return cfg;
558 }
559 
561 {
562  whiteboard_manager_->on_finish_side_turn(current_side());
563 
564  { //Block for set_scontext_synced
565  set_scontext_synced sync(1);
566  // Ending the turn commits all moves.
567  undo_stack().clear();
569  const std::string turn_num = std::to_string(turn());
570  const std::string side_num = std::to_string(current_side());
571 
572  // Clear shroud, in case units had been slowed for the turn.
574 
575  pump().fire("side_turn_end");
576  pump().fire("side_"+ side_num + "_turn_end");
577  pump().fire("side_turn_" + turn_num + "_end");
578  pump().fire("side_" + side_num + "_turn_" + turn_num + "_end");
579  // This is where we refog, after all of a side's events are done.
581  check_victory();
582  sync.do_final_checkup();
583  }
584 
586  gamestate_->init_side_done() = false;
587 }
588 
590 {
591  set_scontext_synced sync(2);
592  const std::string turn_num = std::to_string(turn());
593  pump().fire("turn_end");
594  pump().fire("turn_" + turn_num + "_end");
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  // See if any enemies are visible
605  for (const unit& u : gamestate().board_.units()) {
606  if (current_team().is_enemy(u.side()) && !gui_->fogged(u.get_location())) {
607  return true;
608  }
609  }
610 
611  return false;
612 }
613 
615 {
616  if(menu_handler_.get_textbox().active() == false) {
617  return;
618  }
619 
620  const std::string str = menu_handler_.get_textbox().box()->text();
621  const unsigned int team_num = current_side();
622  events::mouse_handler& mousehandler = mouse_handler_;
623 
624  switch(menu_handler_.get_textbox().mode()) {
625  case gui::TEXTBOX_SEARCH:
628  break;
631  menu_handler_.get_textbox().close(*gui_); //need to close that one after executing do_speak() !
632  break;
636  break;
637  case gui::TEXTBOX_AI:
639  menu_handler_.do_ai_formula(str, team_num, mousehandler);
640  break;
641  default:
643  ERR_DP << "unknown textbox mode" << std::endl;
644  }
645 }
646 
648 {
650 
651  std::set<std::string> dictionary;
652  switch(mode) {
653  case gui::TEXTBOX_SEARCH:
654  {
655  for (const unit& u : gamestate().board_.units()){
656  const map_location& loc = u.get_location();
657  if(!gui_->fogged(loc) &&
658  !(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
659  dictionary.insert(u.name());
660  }
661  //TODO List map labels
662  break;
663  }
665  {
666  std::vector<std::string> commands = menu_handler_.get_commands_list();
667  dictionary.insert(commands.begin(), commands.end());
668  FALLTHROUGH; // we also want player names from the next case
669  }
671  {
672  for (const team& t : gamestate().board_.teams()) {
673  if(!t.is_empty())
674  dictionary.insert(t.current_player());
675  }
676 
677  // Add observers
678  for (const std::string& o : gui_->observers()){
679  dictionary.insert(o);
680  }
681 
682  // Add nicks who whispered you
683  for (const std::string& w : gui_->get_chat_manager().whisperers()){
684  dictionary.insert(w);
685  }
686 
687  // Add nicks from friendlist
688  const std::map<std::string, std::string> friends = preferences::get_acquaintances_nice("friend");
689 
690  for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter){
691  dictionary.insert((*iter).first);
692  }
693 
694  //Exclude own nick from tab-completion.
695  //NOTE why ?
696  dictionary.erase(preferences::login());
697  break;
698  }
699 
700  default:
701  ERR_DP << "unknown textbox mode" << std::endl;
702  } //switch(mode)
703 
704  menu_handler_.get_textbox().tab(dictionary);
705 }
706 
708 {
709  assert(gamestate().board_.has_team(current_side()));
711 }
712 
714 {
715  assert(gamestate().board_.has_team(current_side()));
717 }
718 
719 /// @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
720 static int modulo(int num, int mod, int min)
721 {
722  assert(mod > 0);
723  int n = (num - min) % mod;
724  if (n < 0)
725  n += mod;
726  //n is now in [0, mod)
727  n = n + min;
728  return n;
729  // the following properties are easy to verify:
730  // 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
731  // 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
732 }
733 
734 bool play_controller::is_team_visible(int team_num, bool observer) const
735 {
736  const team& t = gamestate().board_.get_team(team_num);
737  if(observer) {
738  return !t.get_disallow_observers() && !t.is_empty();
739  }
740  else {
741  return t.is_local_human() && !t.is_idle();
742  }
743 }
744 
746 {
747  assert(current_side() <= static_cast<int>(gamestate().board_.teams().size()));
748  const int num_teams = gamestate().board_.teams().size();
749  const bool is_observer = this->is_observer();
750 
751  for(int i = 0; i < num_teams; i++) {
752  const int team_num = modulo(current_side() - i, num_teams, 1);
753  if(is_team_visible(team_num, is_observer)) {
754  return team_num;
755  }
756  }
757  return 0;
758 }
759 
761 {
762  return mouse_handler_;
763 }
764 
765 std::shared_ptr<wb::manager> play_controller::get_whiteboard() const
766 {
767  return whiteboard_manager_;
768 }
769 
771 {
772  return saved_game_.mp_settings();
773 }
774 
776 {
777  return saved_game_.classification();
778 }
779 
781 {
782  return *gui_;
783 }
784 
786 {
787  return !menu_handler_.get_textbox().active();
788 }
789 
791 {
792  if(event.key.keysym.sym == SDLK_ESCAPE) {
794  } else if(event.key.keysym.sym == SDLK_TAB) {
795  tab();
796  } else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
797  enter_textbox();
798  }
799 }
800 
801 void play_controller::process_keydown_event(const SDL_Event& event)
802 {
803  if (event.key.keysym.sym == SDLK_TAB) {
804  whiteboard_manager_->set_invert_behavior(true);
805  }
806 }
807 
808 void play_controller::process_keyup_event(const SDL_Event& event)
809 {
810  // If the user has pressed 1 through 9, we want to show
811  // how far the unit can move in that many turns
812  if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9') {
813  const int new_path_turns = (event.type == SDL_KEYDOWN) ?
814  event.key.keysym.sym - '1' : 0;
815 
816  if(new_path_turns != mouse_handler_.get_path_turns()) {
817  mouse_handler_.set_path_turns(new_path_turns);
818 
820 
821  if(u.valid()) {
822  // if it's not the unit's turn, we reset its moves
823  unit_movement_resetter move_reset(*u, u->side() != current_side());
824 
826  true, gamestate().board_.teams_[gui_->viewing_team()],
828 
829  gui_->highlight_reach(mouse_handler_.current_paths());
830  } else {
832  }
833 
834  }
835  } else if (event.key.keysym.sym == SDLK_TAB) {
836  CKey keys;
837  if (!keys[SDLK_TAB]) {
838  whiteboard_manager_->set_invert_behavior(false);
839  }
840  }
841 }
842 
844  assert(replay_);
845  return *replay_.get();
846 }
847 
849 {
851  // Saving while an event is running isn't supported
852  // because it may lead to expired event handlers being saved.
853  assert(!gamestate().events_manager_->is_event_running());
854 
856  scoped_savegame_snapshot snapshot(*this);
859  } else {
861  }
862 }
863 
864 void play_controller::save_game_auto(const std::string& filename)
865 {
868 
869  scoped_savegame_snapshot snapshot(*this);
871  save.save_game_automatic(false, filename);
872  }
873 }
874 
876 {
881  } else {
883  }
884 }
885 
886 void play_controller::save_replay_auto(const std::string& filename)
887 {
891  save.save_game_automatic(false, filename);
892  }
893 }
894 
896 {
900  } else {
902  }
903 }
904 
906 {
908  load.load_game_ingame();
909 }
910 
912 {
914  undo_stack().undo();
915 }
916 
918 {
920  undo_stack().redo();
921 }
922 
924 {
926 }
927 
929 {
931 }
932 
933 const std::string& play_controller::select_music(bool victory) const
934 {
935  const std::vector<std::string>& music_list = victory
936  ? (gamestate_->get_game_data()->get_victory_music().empty() ? game_config::default_victory_music : gamestate_->get_game_data()->get_victory_music())
937  : (gamestate_->get_game_data()->get_defeat_music().empty() ? game_config::default_defeat_music : gamestate_->get_game_data()->get_defeat_music());
938 
939  if(music_list.empty()) {
940  // Since this function returns a reference, we can't return a temporary empty string.
941  static const std::string empty_str = "";
942  return empty_str;
943  }
944 
945  return music_list[randomness::rng::default_instance().get_random_int(0, music_list.size()-1)];
946 }
947 
949 {
950  if(linger_)
951  {
952  return;
953  }
954 
955  if (is_regular_game_end()) {
956  return;
957  }
958  bool continue_level, found_player, found_network_player, invalidate_all;
959  std::set<unsigned> not_defeated;
960 
961  gamestate().board_.check_victory(continue_level, found_player, found_network_player, invalidate_all, not_defeated, remove_from_carryover_on_defeat_);
962 
963  if (invalidate_all) {
964  gui_->invalidate_all();
965  }
966 
967  if (continue_level) {
968  return ;
969  }
970 
971  if (found_player || found_network_player) {
972  pump().fire("enemies_defeated");
973  if (is_regular_game_end()) {
974  return;
975  }
976  }
977 
978  DBG_EE << "victory_when_enemies_defeated: " << victory_when_enemies_defeated_ << std::endl;
979  DBG_EE << "found_player: " << found_player << std::endl;
980  DBG_EE << "found_network_player: " << found_network_player << std::endl;
981 
982  if (!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
983  // This level has asked not to be ended by this condition.
984  return;
985  }
986 
987  if (gui_->video().non_interactive()) {
988  LOG_AIT << "winner: ";
989  for (unsigned l : not_defeated) {
991  if (ai.empty()) ai = "default ai";
992  LOG_AIT << l << " (using " << ai << ") ";
993  }
994  LOG_AIT << std::endl;
995  ai_testing::log_victory(not_defeated);
996  }
997 
998  DBG_EE << "throwing end level exception..." << std::endl;
999  //Also proceed to the next scenario when another player survived.
1000  end_level_data el_data;
1001  el_data.proceed_to_next_level = found_player || found_network_player;
1002  el_data.is_victory = found_player;
1003  set_end_level_data(el_data);
1004 }
1005 
1006 void play_controller::process_oos(const std::string& msg) const
1007 {
1008  if (gui_->video().non_interactive()) {
1009  throw game::game_error(msg);
1010  }
1012 
1013  std::stringstream message;
1014  message << _("The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1015  message << "\n\n" << _("Error details:") << "\n\n" << msg;
1016 
1017  scoped_savegame_snapshot snapshot(*this);
1019  save.save_game_interactive(message.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
1020 }
1021 
1022 void play_controller::update_gui_to_player(const int team_index, const bool observe)
1023 {
1024  gui_->set_team(team_index, observe);
1025  gui_->recalculate_minimap();
1026  gui_->invalidate_all();
1027 }
1028 
1030 {
1031  scoped_savegame_snapshot snapshot(*this);
1034 }
1035 
1036 void play_controller::do_consolesave(const std::string& filename)
1037 {
1038  scoped_savegame_snapshot snapshot(*this);
1040  save.save_game_automatic(true, filename);
1041 }
1042 
1044 {
1045  //note: this writes to level_ if this is not a replay.
1047 }
1048 
1050 {
1051  return gamestate().events_manager_->pump();
1052 }
1053 
1055 {
1056  return ticks_;
1057 }
1058 
1060 {
1061  return soundsources_manager_.get();
1062 }
1063 
1065 {
1066  return plugins_context_.get();
1067 }
1068 
1070 {
1071  return hotkey_handler_.get();
1072 }
1073 
1075 {
1076  if(linger_ || !gamestate_->init_side_done() || gamestate().gamedata_.phase() != game_data::PLAY) {
1077  return true;
1078  }
1079  const team& t = current_team();
1080  return !t.is_local_human() || !t.is_proxy_human();
1081 }
1082 
1084 {
1086  return;
1087  }
1088  try
1089  {
1090  play_slice();
1091  }
1092  catch(const return_to_play_side_exception&)
1093  {
1094  assert(should_return_to_play_side());
1095  }
1096 }
1097 
1099 {
1100  fire_preload();
1101 
1102  if(!gamestate().start_event_fired_)
1103  {
1104  gamestate().start_event_fired_ = true;
1108 
1109  set_scontext_synced sync;
1110 
1111  fire_prestart();
1112  if (is_regular_game_end()) {
1113  return;
1114  }
1115 
1116  for (const team& t : gamestate().board_.teams()) {
1117  actions::clear_shroud(t.side(), false, false);
1118  }
1119 
1120  init_gui();
1121  LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";
1122 
1123  fire_start();
1124  if (is_regular_game_end()) {
1125  return;
1126  }
1127  sync.do_final_checkup();
1128  gui_->recalculate_minimap();
1129  // Initialize countdown clock.
1130  for (const team& t : gamestate().board_.teams())
1131  {
1133  t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
1134  }
1135  }
1136  }
1137  else
1138  {
1139  init_gui();
1141  gui_->recalculate_minimap();
1142  }
1143 }
1144 
1146 {
1147  const team& viewing_team = get_teams_const()[gui_->viewing_team()];
1148  return gui_->viewing_team() == gui_->playing_team() && !events::commands_disabled && viewing_team.is_local_human() && !is_lingering() && !is_browsing();
1149 }
1150 
1151 std::set<std::string> play_controller::all_players() const
1152 {
1153  std::set<std::string> res = gui_->observers();
1154  for (const team& t : get_teams_const())
1155  {
1156  if (t.is_human()) {
1157  res.insert(t.current_player());
1158  }
1159  }
1160  return res;
1161 }
1162 
1164 {
1165  //check for team-specific items in the scenario
1166  gui_->parse_team_overlays();
1167  do {
1169  {
1170  save_blocker blocker;
1172  if(is_regular_game_end()) {
1173  return;
1174  }
1175  }
1176  // This flag can be set by derived classes (in overridden functions).
1177  player_type_changed_ = false;
1178 
1179  statistics::reset_turn_stats(gamestate().board_.get_team(current_side()).save_id_or_number());
1180 
1181  play_side_impl();
1182 
1183  if(is_regular_game_end()) {
1184  return;
1185  }
1186 
1187  } while (player_type_changed_);
1188  // Keep looping if the type of a team (human/ai/networked)
1189  // has changed mid-turn
1190  sync_end_turn();
1191 }
1192 
1194 {
1195  whiteboard_manager_->on_gamestate_change();
1196  gui_->new_turn();
1197  gui_->invalidate_game_status();
1198 
1199  LOG_NG << "turn: " << turn() << "\n";
1200 
1201  if(gui_->video().non_interactive()) {
1202  LOG_AIT << "Turn " << turn() << ":" << std::endl;
1203  }
1204 
1205  int last_player_number = gamestate_->player_number_;
1206  int next_player_number = gamestate_->next_player_number_;
1207 
1208  while(gamestate_->player_number_ <= static_cast<int>(gamestate().board_.teams().size())) {
1209  gamestate_->next_player_number_ = gamestate_->player_number_ + 1;
1210  next_player_number = gamestate_->next_player_number_;
1211  last_player_number = gamestate_->player_number_;
1212 
1213  // If a side is empty skip over it.
1214  if (!current_team().is_empty()) {
1215  init_side_begin();
1216  if(gamestate_->init_side_done()) {
1217  // This is the case in a reloaded game where the side was initialized before saving the game.
1218  init_side_end();
1219  }
1220 
1222  play_side();
1223  //ignore any changes to next_player_number_ that happen after the [end_turn] is sended to the server, otherwise we will get OOS.
1224  next_player_number = gamestate_->next_player_number_;
1225  assert(next_player_number <= 2 * static_cast<int>(gamestate().board_.teams().size()));
1226  if(is_regular_game_end()) {
1227  return;
1228  }
1229  //note: play_side() send the [end_turn] to the sever and finish_side_turn() callsie the side turn end events.
1230  // this means that during the side turn end events the clients think it is still the last sides turn while
1231  // the server thinks that it is already the next plyers turn. i don'T think this is a problem though.
1232  finish_side_turn();
1233  if(is_regular_game_end()) {
1234  return;
1235  }
1236  if(gui_->video().non_interactive()) {
1237  LOG_AIT << " Player " << current_side() << ": " <<
1238  current_team().villages().size() << " Villages" <<
1239  std::endl;
1241  }
1242  }
1243 
1244  gamestate_->player_number_ = next_player_number;
1245  }
1246  // If the loop exits due to the last team having been processed.
1247  gamestate_->player_number_ = last_player_number;
1248 
1249  finish_turn();
1250 
1251  // Time has run out
1252  check_time_over();
1253 
1254  if (!is_regular_game_end()) {
1255  gamestate_->player_number_ = modulo(next_player_number, gamestate().board_.teams().size(), 1);
1256  }
1257 }
1258 
1260 {
1261  const bool time_left = gamestate().tod_manager_.next_turn(&gamestate().gamedata_);
1262 
1263  if(!time_left) {
1264  LOG_NG << "firing time over event...\n";
1266  pump().fire("time_over");
1267  LOG_NG << "done firing time over event...\n";
1268  // If turns are added while handling 'time over' event.
1269  if (gamestate().tod_manager_.is_time_left()) {
1270  return;
1271  }
1272 
1273  if(gui_->video().non_interactive()) {
1274  LOG_AIT << "time over (draw)\n";
1276  }
1277 
1278  check_victory();
1279  if (is_regular_game_end()) {
1280  return;
1281  }
1282  end_level_data e;
1283  e.proceed_to_next_level = false;
1284  e.is_victory = false;
1285  set_end_level_data(e);
1286  }
1287 }
1288 
1290  : controller_(controller)
1291 {
1293 }
1294 
1296 {
1298 }
1299 
1301 {
1302  const team& t = gamestate().board_.teams()[gui_->viewing_team()];
1303  static const std::string no_objectives(_("No objectives available"));
1304  std::string objectives = utils::interpolate_variables_into_string(t.objectives(), *gamestate_->get_game_data());
1305  gui2::show_transient_message(get_scenario_name(), (objectives.empty() ? no_objectives : objectives), "", true);
1307 }
1308 
1310 {
1312  const std::shared_ptr<gui::button> skip_animation_button = get_display().find_action_button("skip-animation");
1313  if (skip_animation_button) {
1314  skip_animation_button->set_check(skip_replay_);
1315  }
1316 }
static const config & get_theme(const config &game_config, std::string theme_name)
std::shared_ptr< gui::button > find_action_button(const std::string &id)
Retrieves a pointer to a theme UI button.
Definition: display.cpp:804
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 do_search(const std::string &new_search)
void set_current_paths(const pathfind::paths &new_paths)
int autosavemax()
Definition: game.cpp:808
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:258
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:238
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:89
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 refresh_objectives() const
Reevaluate [show_if] conditions and build a new objectives string.
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:150
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_
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:284
const pathfind::paths & current_paths() const
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, const bool restore_background)
Shows a transient message to the user.
void do_command(const std::string &str)
void set_do_healing(bool do_healing)
static void progress(loading_stage stage=loading_stage::none)
virtual void update_viewing_player()=0
gui::floating_textbox & get_textbox()
void new_turn()
Definition: team.hpp:204
void set_gui(game_display *gui)
Definition: menu_events.hpp:52
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
bool do_healing() const
void check_victory()
Checks to see if a side has won.
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:505
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:241
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:813
#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
void process_focus_keydown_event(const SDL_Event &event) override
Process keydown (only when the general map display does not have focus).
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
bool have_keyboard_focus() override
Derived classes should override this to return false when arrow keys should not scroll the map...
events::menu_handler menu_handler_
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:980
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:214
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
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:656
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:95
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
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
TEXTBOX_MODE mode() 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:705
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:243
tod_manager tod_manager_
Definition: game_state.hpp:47
Object which temporarily resets a unit&#39;s movement.
Definition: unit.hpp:1856
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 TODO: Refactor history handling and internal commands...
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:208
std::shared_ptr< wb::manager > get_whiteboard() const
An object which will lock the display for the duration of its lifetime.
Definition: video.hpp:279
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()
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:282
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:203
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:404
map_location map_start_
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:685
const config & game_config_
void reset_gamestate(const config &level, int replay_pos)
const t_string & objectives() const
Definition: team.hpp:240
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:1022
#define log_scope(description)
Definition: log.hpp:186
void tab(const std::set< std::string > &dictionary)
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:234
static void save(LexState *ls, int c)
Definition: llex.cpp:57
bool can_redo() const
static lg::log_domain log_enginerefac("enginerefac")
std::string observer
bool is_local() const
Definition: team.hpp:260
Class for replay saves (either manually or automatically).
Definition: savegame.hpp:256
config & add_child(config_key_type key)
Definition: config.cpp:476
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:486
compression::format save_compression_format()
Definition: game.cpp:871
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()
bool get_disallow_observers() const
Definition: team.hpp:338
static void display(std::function< void()> f)
void set_game_display(game_display *)
Definition: game_state.cpp:234
bool is_local_human() const
Definition: team.hpp:266
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
const std::unique_ptr< gui::textbox > & box() const
game_state & gamestate()
double t
Definition: astarsearch.cpp:64
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
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
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:613
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:523
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:453
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:92
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:239
static map_location::DIRECTION n
const std::set< map_location > & villages() const
Definition: team.hpp:184
void close(game_display &gui)
pathfind::manager * tunnels
Definition: resources.cpp:31
bool can_undo() const
True if there are actions that can be undone.
Definition: undo.hpp:93
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:64
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_
play_controller(const config &level, saved_game &state_of_game, const ter_data_cache &tdata, bool skip_replay)
void do_ai_formula(const std::string &str, int side_num, mouse_handler &mousehandler)
#define LOG_NG
std::shared_ptr< terrain_type_data > ter_data_cache
virtual void sync_end_turn()