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 
442  do_init_side();
443 }
444 
446 {
447  set_scontext_synced sync;
448  log_scope("player turn");
449  // In case we might end up calling sync:network during the side turn events,
450  // and we don't want do_init_side to be called when a player drops.
451  gamestate_->init_side_done() = true;
452  init_side_done_now_ = true;
453 
454  const std::string turn_num = std::to_string(turn());
455  const std::string side_num = std::to_string(current_side());
456 
457  gamestate().gamedata_.get_variable("side_number") = current_side();
458 
459  // We might have skipped some sides because they were empty so it is not enough to check for side_num==1
460  if(!gamestate().tod_manager_.has_turn_event_fired())
461  {
462  pump().fire("turn_" + turn_num);
463  pump().fire("new_turn");
465  }
466 
467  pump().fire("side_turn");
468  pump().fire("side_" + side_num + "_turn");
469  pump().fire("side_turn_" + turn_num);
470  pump().fire("side_" + side_num + "_turn_" + turn_num);
471 
472  // We want to work out if units for this player should get healed,
473  // and the player should get income now.
474  // Healing/income happen if it's not the first turn of processing,
475  // or if we are loading a game.
476  if (turn() > 1) {
479 
480  // If the expense is less than the number of villages owned
481  // times the village support capacity,
482  // then we don't have to pay anything at all
483  int expense = gamestate().board_.side_upkeep(current_side()) -
484  current_team().support();
485  if(expense > 0) {
486  current_team().spend_gold(expense);
487  }
488  }
489  if (do_healing()) {
491  }
492  // Do healing on every side turn except the very first side turn.
493  // (1.14 and earlier did healing whenever turn >= 2.)
494  set_do_healing(true);
495  // Set resting now after the healing has been done.
496  for(unit &patient : resources::gameboard->units()) {
497  if(patient.side() == current_side()) {
498  patient.set_resting(true);
499  }
500  }
501 
502  // Prepare the undo stack.
504 
505  pump().fire("turn_refresh");
506  pump().fire("side_" + side_num + "_turn_refresh");
507  pump().fire("turn_" + turn_num + "_refresh");
508  pump().fire("side_" + side_num + "_turn_" + turn_num + "_refresh");
509 
510  // Make sure vision is accurate.
512  init_side_end();
513  check_victory();
514  sync.do_final_checkup();
515 }
516 
518 {
520 
521  if (current_side() == 1 || !init_side_done_now_)
523 
524  if (!is_skipping_replay()){
525  gui_->invalidate_all();
526  }
527 
528  if (!is_skipping_replay() && current_team().get_scroll_to_leader() && !map_start_.valid()){
529  gui_->scroll_to_leader(current_side(), game_display::ONSCREEN,false);
530  }
532  whiteboard_manager_->on_init_side();
533 }
534 
536 {
537  config cfg = level_;
538 
539  cfg["replay_pos"] = saved_game_.get_replay().get_pos();
540  gamestate().write(cfg);
541 
542  gui_->write(cfg.add_child("display"));
543 
544  //Write the soundsources.
545  soundsources_manager_->write_sourcespecs(cfg);
546 
547  gui_->labels().write(cfg);
549 
550  return cfg;
551 }
552 
554 {
555  whiteboard_manager_->on_finish_side_turn(current_side());
556 
557  { //Block for set_scontext_synced
558  set_scontext_synced sync(1);
559  // Ending the turn commits all moves.
560  undo_stack().clear();
562  const std::string turn_num = std::to_string(turn());
563  const std::string side_num = std::to_string(current_side());
564 
565  // Clear shroud, in case units had been slowed for the turn.
567 
568  pump().fire("side_turn_end");
569  pump().fire("side_"+ side_num + "_turn_end");
570  pump().fire("side_turn_" + turn_num + "_end");
571  pump().fire("side_" + side_num + "_turn_" + turn_num + "_end");
572  // This is where we refog, after all of a side's events are done.
574  check_victory();
575  sync.do_final_checkup();
576  }
577 
579  gamestate_->init_side_done() = false;
580 }
581 
583 {
584  set_scontext_synced sync(2);
585  const std::string turn_num = std::to_string(turn());
586  pump().fire("turn_end");
587  pump().fire("turn_" + turn_num + "_end");
588  sync.do_final_checkup();
589 }
590 
592 {
593  // If we aren't using fog/shroud, this is easy :)
594  if(current_team().uses_fog() == false && current_team().uses_shroud() == false)
595  return true;
596 
597  // See if any enemies are visible
598  for (const unit& u : gamestate().board_.units()) {
599  if (current_team().is_enemy(u.side()) && !gui_->fogged(u.get_location())) {
600  return true;
601  }
602  }
603 
604  return false;
605 }
606 
608 {
609  if(menu_handler_.get_textbox().active() == false) {
610  return;
611  }
612 
613  const std::string str = menu_handler_.get_textbox().box()->text();
614  const unsigned int team_num = current_side();
615  events::mouse_handler& mousehandler = mouse_handler_;
616 
617  switch(menu_handler_.get_textbox().mode()) {
618  case gui::TEXTBOX_SEARCH:
621  break;
624  menu_handler_.get_textbox().close(*gui_); //need to close that one after executing do_speak() !
625  break;
629  break;
630  case gui::TEXTBOX_AI:
632  menu_handler_.do_ai_formula(str, team_num, mousehandler);
633  break;
634  default:
636  ERR_DP << "unknown textbox mode" << std::endl;
637  }
638 }
639 
641 {
643 
644  std::set<std::string> dictionary;
645  switch(mode) {
646  case gui::TEXTBOX_SEARCH:
647  {
648  for (const unit& u : gamestate().board_.units()){
649  const map_location& loc = u.get_location();
650  if(!gui_->fogged(loc) &&
651  !(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
652  dictionary.insert(u.name());
653  }
654  //TODO List map labels
655  break;
656  }
658  {
659  std::vector<std::string> commands = menu_handler_.get_commands_list();
660  dictionary.insert(commands.begin(), commands.end());
661  FALLTHROUGH; // we also want player names from the next case
662  }
664  {
665  for (const team& t : gamestate().board_.teams()) {
666  if(!t.is_empty())
667  dictionary.insert(t.current_player());
668  }
669 
670  // Add observers
671  for (const std::string& o : gui_->observers()){
672  dictionary.insert(o);
673  }
674 
675  // Add nicks who whispered you
676  for (const std::string& w : gui_->get_chat_manager().whisperers()){
677  dictionary.insert(w);
678  }
679 
680  // Add nicks from friendlist
681  const std::map<std::string, std::string> friends = preferences::get_acquaintances_nice("friend");
682 
683  for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter){
684  dictionary.insert((*iter).first);
685  }
686 
687  //Exclude own nick from tab-completion.
688  //NOTE why ?
689  dictionary.erase(preferences::login());
690  break;
691  }
692 
693  default:
694  ERR_DP << "unknown textbox mode" << std::endl;
695  } //switch(mode)
696 
697  menu_handler_.get_textbox().tab(dictionary);
698 }
699 
701 {
702  assert(gamestate().board_.has_team(current_side()));
704 }
705 
707 {
708  assert(gamestate().board_.has_team(current_side()));
710 }
711 
712 /// @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
713 static int modulo(int num, int mod, int min)
714 {
715  assert(mod > 0);
716  int n = (num - min) % mod;
717  if (n < 0)
718  n += mod;
719  //n is now in [0, mod)
720  n = n + min;
721  return n;
722  // the following properties are easy to verify:
723  // 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
724  // 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
725 }
726 
727 bool play_controller::is_team_visible(int team_num, bool observer) const
728 {
729  const team& t = gamestate().board_.get_team(team_num);
730  if(observer) {
731  return !t.get_disallow_observers() && !t.is_empty();
732  }
733  else {
734  return t.is_local_human() && !t.is_idle();
735  }
736 }
737 
739 {
740  assert(current_side() <= static_cast<int>(gamestate().board_.teams().size()));
741  const int num_teams = gamestate().board_.teams().size();
742  const bool is_observer = this->is_observer();
743 
744  for(int i = 0; i < num_teams; i++) {
745  const int team_num = modulo(current_side() - i, num_teams, 1);
746  if(is_team_visible(team_num, is_observer)) {
747  return team_num;
748  }
749  }
750  return 0;
751 }
752 
754 {
755  return mouse_handler_;
756 }
757 
758 std::shared_ptr<wb::manager> play_controller::get_whiteboard() const
759 {
760  return whiteboard_manager_;
761 }
762 
764 {
765  return saved_game_.mp_settings();
766 }
767 
769 {
770  return saved_game_.classification();
771 }
772 
774 {
775  return *gui_;
776 }
777 
779 {
780  return !menu_handler_.get_textbox().active();
781 }
782 
784 {
785  if(event.key.keysym.sym == SDLK_ESCAPE) {
787  } else if(event.key.keysym.sym == SDLK_TAB) {
788  tab();
789  } else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
790  enter_textbox();
791  }
792 }
793 
794 void play_controller::process_keydown_event(const SDL_Event& event)
795 {
796  if (event.key.keysym.sym == SDLK_TAB) {
797  whiteboard_manager_->set_invert_behavior(true);
798  }
799 }
800 
801 void play_controller::process_keyup_event(const SDL_Event& event)
802 {
803  // If the user has pressed 1 through 9, we want to show
804  // how far the unit can move in that many turns
805  if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9') {
806  const int new_path_turns = (event.type == SDL_KEYDOWN) ?
807  event.key.keysym.sym - '1' : 0;
808 
809  if(new_path_turns != mouse_handler_.get_path_turns()) {
810  mouse_handler_.set_path_turns(new_path_turns);
811 
813 
814  if(u.valid()) {
815  // if it's not the unit's turn, we reset its moves
816  unit_movement_resetter move_reset(*u, u->side() != current_side());
817 
819  true, gamestate().board_.teams_[gui_->viewing_team()],
821 
822  gui_->highlight_reach(mouse_handler_.current_paths());
823  } else {
825  }
826 
827  }
828  } else if (event.key.keysym.sym == SDLK_TAB) {
829  CKey keys;
830  if (!keys[SDLK_TAB]) {
831  whiteboard_manager_->set_invert_behavior(false);
832  }
833  }
834 }
835 
837  assert(replay_);
838  return *replay_.get();
839 }
840 
842 {
844  // Saving while an event is running isn't supported
845  // because it may lead to expired event handlers being saved.
846  assert(!gamestate().events_manager_->is_event_running());
847 
849  scoped_savegame_snapshot snapshot(*this);
852  } else {
854  }
855 }
856 
857 void play_controller::save_game_auto(const std::string& filename)
858 {
861 
862  scoped_savegame_snapshot snapshot(*this);
864  save.save_game_automatic(false, filename);
865  }
866 }
867 
869 {
874  } else {
876  }
877 }
878 
879 void play_controller::save_replay_auto(const std::string& filename)
880 {
884  save.save_game_automatic(false, filename);
885  }
886 }
887 
889 {
893  } else {
895  }
896 }
897 
899 {
901  load.load_game_ingame();
902 }
903 
905 {
907  undo_stack().undo();
908 }
909 
911 {
913  undo_stack().redo();
914 }
915 
917 {
919 }
920 
922 {
924 }
925 
926 const std::string& play_controller::select_music(bool victory) const
927 {
928  const std::vector<std::string>& music_list = victory
929  ? (gamestate_->get_game_data()->get_victory_music().empty() ? game_config::default_victory_music : gamestate_->get_game_data()->get_victory_music())
930  : (gamestate_->get_game_data()->get_defeat_music().empty() ? game_config::default_defeat_music : gamestate_->get_game_data()->get_defeat_music());
931 
932  if(music_list.empty()) {
933  // Since this function returns a reference, we can't return a temporary empty string.
934  static const std::string empty_str = "";
935  return empty_str;
936  }
937 
938  return music_list[randomness::rng::default_instance().get_random_int(0, music_list.size()-1)];
939 }
940 
942 {
943  if(linger_)
944  {
945  return;
946  }
947 
948  if (is_regular_game_end()) {
949  return;
950  }
951  bool continue_level, found_player, found_network_player, invalidate_all;
952  std::set<unsigned> not_defeated;
953 
954  gamestate().board_.check_victory(continue_level, found_player, found_network_player, invalidate_all, not_defeated, remove_from_carryover_on_defeat_);
955 
956  if (invalidate_all) {
957  gui_->invalidate_all();
958  }
959 
960  if (continue_level) {
961  return ;
962  }
963 
964  if (found_player || found_network_player) {
965  pump().fire("enemies_defeated");
966  if (is_regular_game_end()) {
967  return;
968  }
969  }
970 
971  DBG_EE << "victory_when_enemies_defeated: " << victory_when_enemies_defeated_ << std::endl;
972  DBG_EE << "found_player: " << found_player << std::endl;
973  DBG_EE << "found_network_player: " << found_network_player << std::endl;
974 
975  if (!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
976  // This level has asked not to be ended by this condition.
977  return;
978  }
979 
980  if (gui_->video().non_interactive()) {
981  LOG_AIT << "winner: ";
982  for (unsigned l : not_defeated) {
984  if (ai.empty()) ai = "default ai";
985  LOG_AIT << l << " (using " << ai << ") ";
986  }
987  LOG_AIT << std::endl;
988  ai_testing::log_victory(not_defeated);
989  }
990 
991  DBG_EE << "throwing end level exception..." << std::endl;
992  //Also proceed to the next scenario when another player survived.
993  end_level_data el_data;
994  el_data.proceed_to_next_level = found_player || found_network_player;
995  el_data.is_victory = found_player;
996  set_end_level_data(el_data);
997 }
998 
999 void play_controller::process_oos(const std::string& msg) const
1000 {
1001  if (gui_->video().non_interactive()) {
1002  throw game::game_error(msg);
1003  }
1005 
1006  std::stringstream message;
1007  message << _("The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1008  message << "\n\n" << _("Error details:") << "\n\n" << msg;
1009 
1010  scoped_savegame_snapshot snapshot(*this);
1012  save.save_game_interactive(message.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
1013 }
1014 
1015 void play_controller::update_gui_to_player(const int team_index, const bool observe)
1016 {
1017  gui_->set_team(team_index, observe);
1018  gui_->recalculate_minimap();
1019  gui_->invalidate_all();
1020 }
1021 
1023 {
1024  scoped_savegame_snapshot snapshot(*this);
1027 }
1028 
1029 void play_controller::do_consolesave(const std::string& filename)
1030 {
1031  scoped_savegame_snapshot snapshot(*this);
1033  save.save_game_automatic(true, filename);
1034 }
1035 
1037 {
1038  //note: this writes to level_ if this is not a replay.
1040 }
1041 
1043 {
1044  return gamestate().events_manager_->pump();
1045 }
1046 
1048 {
1049  return ticks_;
1050 }
1051 
1053 {
1054  return soundsources_manager_.get();
1055 }
1056 
1058 {
1059  return plugins_context_.get();
1060 }
1061 
1063 {
1064  return hotkey_handler_.get();
1065 }
1066 
1068 {
1069  if(linger_ || !gamestate_->init_side_done() || gamestate().gamedata_.phase() != game_data::PLAY) {
1070  return true;
1071  }
1072  const team& t = current_team();
1073  return !t.is_local_human() || !t.is_proxy_human();
1074 }
1075 
1077 {
1079  return;
1080  }
1081  try
1082  {
1083  play_slice();
1084  }
1085  catch(const return_to_play_side_exception&)
1086  {
1087  assert(should_return_to_play_side());
1088  }
1089 }
1090 
1092 {
1093  fire_preload();
1094 
1095  if(!gamestate().start_event_fired_)
1096  {
1097  gamestate().start_event_fired_ = true;
1101 
1102  set_scontext_synced sync;
1103 
1104  fire_prestart();
1105  if (is_regular_game_end()) {
1106  return;
1107  }
1108 
1109  for (const team& t : gamestate().board_.teams()) {
1110  actions::clear_shroud(t.side(), false, false);
1111  }
1112 
1113  init_gui();
1114  LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";
1115 
1116  fire_start();
1117  if (is_regular_game_end()) {
1118  return;
1119  }
1120  sync.do_final_checkup();
1121  gui_->recalculate_minimap();
1122  // Initialize countdown clock.
1123  for (const team& t : gamestate().board_.teams())
1124  {
1126  t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
1127  }
1128  }
1129  }
1130  else
1131  {
1132  init_gui();
1134  gui_->recalculate_minimap();
1135  }
1136 }
1137 
1139 {
1140  const team& viewing_team = get_teams_const()[gui_->viewing_team()];
1141  return gui_->viewing_team() == gui_->playing_team() && !events::commands_disabled && viewing_team.is_local_human() && !is_lingering() && !is_browsing();
1142 }
1143 
1144 std::set<std::string> play_controller::all_players() const
1145 {
1146  std::set<std::string> res = gui_->observers();
1147  for (const team& t : get_teams_const())
1148  {
1149  if (t.is_human()) {
1150  res.insert(t.current_player());
1151  }
1152  }
1153  return res;
1154 }
1155 
1157 {
1158  //check for team-specific items in the scenario
1159  gui_->parse_team_overlays();
1160  do {
1162  {
1163  save_blocker blocker;
1165  if(is_regular_game_end()) {
1166  return;
1167  }
1168  }
1169  // This flag can be set by derived classes (in overridden functions).
1170  player_type_changed_ = false;
1171 
1172  statistics::reset_turn_stats(gamestate().board_.get_team(current_side()).save_id_or_number());
1173 
1174  play_side_impl();
1175 
1176  if(is_regular_game_end()) {
1177  return;
1178  }
1179 
1180  } while (player_type_changed_);
1181  // Keep looping if the type of a team (human/ai/networked)
1182  // has changed mid-turn
1183  sync_end_turn();
1184 }
1185 
1187 {
1188  whiteboard_manager_->on_gamestate_change();
1189  gui_->new_turn();
1190  gui_->invalidate_game_status();
1191 
1192  LOG_NG << "turn: " << turn() << "\n";
1193 
1194  if(gui_->video().non_interactive()) {
1195  LOG_AIT << "Turn " << turn() << ":" << std::endl;
1196  }
1197 
1198  int last_player_number = gamestate_->player_number_;
1199  int next_player_number = gamestate_->next_player_number_;
1200 
1201  while(gamestate_->player_number_ <= static_cast<int>(gamestate().board_.teams().size())) {
1202  gamestate_->next_player_number_ = gamestate_->player_number_ + 1;
1203  next_player_number = gamestate_->next_player_number_;
1204  last_player_number = gamestate_->player_number_;
1205 
1206  // If a side is empty skip over it.
1207  if (!current_team().is_empty()) {
1208  init_side_begin();
1209  if(gamestate_->init_side_done()) {
1210  // This is the case in a reloaded game where the side was initialized before saving the game.
1211  init_side_end();
1212  }
1213 
1215  play_side();
1216  //ignore any changes to next_player_number_ that happen after the [end_turn] is sended to the server, otherwise we will get OOS.
1217  next_player_number = gamestate_->next_player_number_;
1218  assert(next_player_number <= 2 * static_cast<int>(gamestate().board_.teams().size()));
1219  if(is_regular_game_end()) {
1220  return;
1221  }
1222  //note: play_side() send the [end_turn] to the sever and finish_side_turn() callsie the side turn end events.
1223  // this means that during the side turn end events the clients think it is still the last sides turn while
1224  // the server thinks that it is already the next plyers turn. i don'T think this is a problem though.
1225  finish_side_turn();
1226  if(is_regular_game_end()) {
1227  return;
1228  }
1229  if(gui_->video().non_interactive()) {
1230  LOG_AIT << " Player " << current_side() << ": " <<
1231  current_team().villages().size() << " Villages" <<
1232  std::endl;
1234  }
1235  }
1236 
1237  gamestate_->player_number_ = next_player_number;
1238  }
1239  // If the loop exits due to the last team having been processed.
1240  gamestate_->player_number_ = last_player_number;
1241 
1242  finish_turn();
1243 
1244  // Time has run out
1245  check_time_over();
1246 
1247  if (!is_regular_game_end()) {
1248  gamestate_->player_number_ = modulo(next_player_number, gamestate().board_.teams().size(), 1);
1249  }
1250 }
1251 
1253 {
1254  const bool time_left = gamestate().tod_manager_.next_turn(&gamestate().gamedata_);
1255 
1256  if(!time_left) {
1257  LOG_NG << "firing time over event...\n";
1259  pump().fire("time_over");
1260  LOG_NG << "done firing time over event...\n";
1261  // If turns are added while handling 'time over' event.
1262  if (gamestate().tod_manager_.is_time_left()) {
1263  return;
1264  }
1265 
1266  if(gui_->video().non_interactive()) {
1267  LOG_AIT << "time over (draw)\n";
1269  }
1270 
1271  check_victory();
1272  if (is_regular_game_end()) {
1273  return;
1274  }
1275  end_level_data e;
1276  e.proceed_to_next_level = false;
1277  e.is_victory = false;
1278  set_end_level_data(e);
1279  }
1280 }
1281 
1283  : controller_(controller)
1284 {
1286 }
1287 
1289 {
1291 }
1292 
1294 {
1295  const team& t = gamestate().board_.teams()[gui_->viewing_team()];
1296  static const std::string no_objectives(_("No objectives available"));
1297  std::string objectives = utils::interpolate_variables_into_string(t.objectives(), *gamestate_->get_game_data());
1298  gui2::show_transient_message(get_scenario_name(), (objectives.empty() ? no_objectives : objectives), "", true);
1300 }
1301 
1303 {
1305  const std::shared_ptr<gui::button> skip_animation_button = get_display().find_action_button("skip-animation");
1306  if (skip_animation_button) {
1307  skip_animation_button->set_check(skip_replay_);
1308  }
1309 }
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:802
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: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 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:151
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:504
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: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: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: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:1771
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: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:701
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: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: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:522
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: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()