The Battle for Wesnoth  1.15.2+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 "save_blocker.hpp"
51 #include "save_index.hpp"
52 #include "saved_game.hpp"
53 #include "savegame.hpp"
56 #include "sound.hpp"
57 #include "soundsource.hpp"
58 #include "statistics.hpp"
59 #include "synced_context.hpp"
60 #include "terrain/type_data.hpp"
61 #include "tooltips.hpp"
62 #include "units/unit.hpp"
63 #include "units/id.hpp"
64 #include "whiteboard/manager.hpp"
65 
66 #include "utils/functional.hpp"
67 
68 static lg::log_domain log_aitesting("aitesting");
69 #define LOG_AIT LOG_STREAM(info, log_aitesting)
70 //If necessary, this define can be replaced with `#define LOG_AIT std::cout` to restore previous behavior
71 
72 static lg::log_domain log_engine("engine");
73 #define LOG_NG LOG_STREAM(info, log_engine)
74 #define DBG_NG LOG_STREAM(debug, log_engine)
75 
76 static lg::log_domain log_display("display");
77 #define ERR_DP LOG_STREAM(err, log_display)
78 
79 static lg::log_domain log_enginerefac("enginerefac");
80 #define LOG_RG LOG_STREAM(info, log_enginerefac)
81 
82 static lg::log_domain log_engine_enemies("engine/enemies");
83 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
84 
85 /**
86  * Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
87  */
88 static void copy_persistent(const config& src, config& dst)
89 {
90  static const std::set<std::string> attrs {
91  "description",
92  "name",
93  "victory_when_enemies_defeated",
94  "remove_from_carryover_on_defeat",
95  "disallow_recall",
96  "experience_modifier",
97  "require_scenario"};
98 
99  static const std::set<std::string> tags {
100  "terrain_graphics",
101  "modify_unit_type",
102  "lua"};
103 
104  for (const std::string& attr : attrs)
105  {
106  dst[attr] = src[attr];
107  }
108 
109  for (const std::string& tag : tags)
110  {
111  dst.append_children(src, tag);
112  }
113 }
114 
115 static void clear_resources()
116 {
117  resources::controller = nullptr;
118  resources::filter_con = nullptr;
119  resources::gameboard = nullptr;
120  resources::gamedata = nullptr;
121  resources::game_events = nullptr;
122  resources::lua_kernel = nullptr;
123  resources::persist = nullptr;
124  resources::soundsources = nullptr;
125  resources::tod_manager = nullptr;
126  resources::tunnels = nullptr;
127  resources::undo_stack = nullptr;
128  resources::recorder = nullptr;
129  resources::whiteboard.reset();
130  resources::classification = nullptr;
131 }
132 
134  const ter_data_cache& tdata, bool skip_replay)
135  : controller_base()
136  , observer()
138  , ticks_(SDL_GetTicks())
139  , tdata_(tdata)
140  , gamestate_()
141  , level_()
142  , saved_game_(state_of_game)
143  , tooltips_manager_()
144  , whiteboard_manager_()
145  , plugins_context_()
146  , labels_manager_()
147  , help_manager_(&game_config_)
148  , mouse_handler_(nullptr, *this)
149  , menu_handler_(nullptr, *this)
150  , hotkey_handler_(new hotkey_handler(*this, saved_game_))
151  , soundsources_manager_()
152  , persist_()
153  , gui_()
154  , xp_mod_(new unit_experience_accelerator(level["experience_modifier"].to_int(100)))
155  , statistics_context_(new statistics::scenario_context(level["name"]))
156  , replay_(new replay(state_of_game.get_replay()))
157  , skip_replay_(skip_replay)
158  , skip_story_(state_of_game.skip_story())
159  , linger_(false)
160  , init_side_done_now_(false)
161  , map_start_()
162  , victory_when_enemies_defeated_(level["victory_when_enemies_defeated"].to_bool(true))
163  , remove_from_carryover_on_defeat_(level["remove_from_carryover_on_defeat"].to_bool(true))
164  , victory_music_()
165  , defeat_music_()
166  , scope_()
167  , ignore_replay_errors_(false)
168  , player_type_changed_(false)
169 {
170  copy_persistent(level, level_);
171 
172  for(const config& modify_unit_type : level_.child_range("modify_unit_type")) {
173  unit_types.apply_scenario_fix(modify_unit_type);
174  }
175  resources::controller = this;
178 
180 
182 
186  try {
187  init(level);
188  } catch (...) {
189  clear_resources();
190  throw;
191  }
192 }
193 
195 {
198  clear_resources();
199 }
200 
202 {
203  void operator()(const config&) const
204  {
206  }
207 };
208 
210 {
211  gui2::dialogs::loading_screen::display([this, &level]() {
213 
214  LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl;
215  gamestate_.reset(new game_state(level, *this, tdata_));
216 
224 
225  gamestate_->ai_manager_.add_observer(this);
226  gamestate_->init(level, *this);
228 
229  LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl;
231  whiteboard_manager_.reset(new wb::manager());
233 
234  LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl;
237 
238  LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl;
240  const config& theme_cfg = controller_base::get_theme(game_config_, theme());
241 
242  LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl;
244  gui_.reset(new game_display(gamestate().board_, whiteboard_manager_, *gamestate().reports_, theme_cfg, level));
245  map_start_ = map_location(level.child_or_empty("display").child_or_empty("location"));
246  if (!gui_->video().faked()) {
248  gui_->get_theme().modify_label("time-icon", _ ("time left for current turn"));
249  else
250  gui_->get_theme().modify_label("time-icon", _ ("current local time"));
251  }
252 
254  mouse_handler_.set_gui(gui_.get());
255  menu_handler_.set_gui(gui_.get());
256 
257  LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl;
258 
259  LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl;
260  // This *needs* to be created before the show_intro and show_map_scene
261  // as that functions use the manager state_of_game
262  // Has to be done before registering any events!
265 
266  if(gamestate().first_human_team_ != -1) {
267  gui_->set_team(gamestate().first_human_team_);
268  }
269  else if(is_observer()) {
270  // Find first team that is allowed to be observed.
271  // If not set here observer would be without fog until
272  // the first turn of observable side
273  for (const team& t : gamestate().board_.teams())
274  {
275  if (!t.get_disallow_observers())
276  {
277  gui_->set_team(t.side() - 1);
278  }
279  }
280  }
281 
282  init_managers();
284  //loadscreen_manager->reset();
286  gamestate().lua_kernel_->load_game(level);
287 
288  plugins_context_.reset(new plugins_context("Game"));
289  plugins_context_->set_callback("save_game", [this](const config& cfg) { save_game_auto(cfg["filename"]); }, true);
290  plugins_context_->set_callback("save_replay", [this](const config& cfg) { save_replay_auto(cfg["filename"]); }, true);
291  plugins_context_->set_callback("quit", throw_end_level(), false);
292  plugins_context_->set_accessor_string("scenario_name", [this](config) { return get_scenario_name(); });
293  });
294  //Do this after the loadingscreen, so that ita happens in the main thread.
295  gui_->join();
296 }
297 
298 void play_controller::reset_gamestate(const config& level, int replay_pos)
299 {
300  resources::gameboard = nullptr;
301  resources::gamedata = nullptr;
302  resources::tod_manager = nullptr;
303  resources::filter_con = nullptr;
304  resources::lua_kernel = nullptr;
305  resources::game_events = nullptr;
306  resources::tunnels = nullptr;
307  resources::undo_stack = nullptr;
308 
309  gui_->labels().set_team(nullptr);
310 
311  /* First destroy the old game state, then create the new one.
312  This is necessary to ensure that while the old AI manager is being destroyed,
313  all its member objects access the old manager instead of the new. */
314  gamestate_.reset();
315  gamestate_.reset(new game_state(level, *this, tdata_));
323 
324  gamestate_->ai_manager_.add_observer(this);
325  gamestate_->init(level, *this);
328 
329  gui_->reset_reports(*gamestate().reports_);
330  gui_->change_display_context(&gamestate().board_);
331  saved_game_.get_replay().set_pos(replay_pos);
333  gamestate().lua_kernel_->load_game(level);
334 }
335 
337 {
338  LOG_NG << "initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
342 
344  LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
345 }
346 
348 {
349  // Run initialization scripts, even if loading from a snapshot.
350  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
351  pump().fire("preload");
352 }
353 
355 {
356  // pre-start events must be executed before any GUI operation,
357  // as those may cause the display to be refreshed.
358  update_locker lock_display(gui_->video());
360 
361  // Fire these right before prestart events, to catch only the units sides
362  // have started with.
363  for (const unit& u : gamestate().board_.units()) {
364  pump().fire("unit_placed", map_location(u.get_location()));
365  }
366 
367  pump().fire("prestart");
368  // prestart event may modify start turn with WML, reflect any changes.
369  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
370 }
371 
373 {
374  const config cfg("side", gui_->viewing_side());
375  gamestate().lua_kernel_->run_wml_action("show_objectives", vconfig(cfg),
376  game_events::queued_event("_from_interface", "", map_location(), map_location(), config()));
377 }
378 
380 {
382  pump().fire("start");
383 
384  skip_story_ = false; // Show [message]s from now on even with --campaign-skip-story
385 
386  // start event may modify start turn with WML, reflect any changes.
387  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
388 
391  // prestart and start events may modify the initial gold amount,
392  // reflect any changes.
393  for (team& tm : gamestate().board_.teams_)
394  {
395  tm.set_start_gold(tm.gold());
396  }
397  gamestate_->init_side_done() = false;
399 }
400 
402 {
403  gui_->begin_game();
404  gui_->update_tod();
405 }
406 
408 {
410 
411  // If we are observers we move to watch next team if it is allowed
412  if ((is_observer() && !current_team().get_disallow_observers())
413  || (current_team().is_local_human() && !this->is_replay()))
414  {
416  }
417 
418  gui_->set_playing_team(std::size_t(current_side() - 1));
419 
421 }
422 
424 {
425  //
426  // We do side init only if not done yet for a local side when we are not replaying.
427  // For all other sides it is recorded in replay and replay handler has to handle
428  // calling do_init_side() functions.
429  //
430  if (gamestate_->init_side_done()) {
431  // We already executed do_init_side this can for example happe if we reload a game,
432  // but also if we changed control of a side during it's turn
433  return;
434  }
435  if (!current_team().is_local()) {
436  // We are in a mp game and execute do_init_side as soon as we receive [init_side] from the current player
437  // (see replay.cpp)
438  return;
439  }
440 
441  if (is_replay()) {
442  // We are in a replay and execute do_init_side as soon as we reach the next [init_side] in the replay data
443  // (see replay.cpp)
444  return;
445  }
446 
447  if (current_team().is_idle()) {
448  // In this case it can happen that we just gave control of this side to another player so doing init_side
449  // could lead to errors since we no longer own this side from the servers perspective.
450  // (see playturn.cpp)
451  return;
452  }
453 
455  do_init_side();
456 }
457 
459 {
460  set_scontext_synced sync;
461  log_scope("player turn");
462  // In case we might end up calling sync:network during the side turn events,
463  // and we don't want do_init_side to be called when a player drops.
464  gamestate_->init_side_done() = true;
465  init_side_done_now_ = true;
466 
467  const std::string turn_num = std::to_string(turn());
468  const std::string side_num = std::to_string(current_side());
469 
470  gamestate().gamedata_.get_variable("side_number") = current_side();
471 
472  // We might have skipped some sides because they were empty so it is not enough to check for side_num==1
473  if(!gamestate().tod_manager_.has_turn_event_fired())
474  {
475  pump().fire("turn_" + turn_num);
476  pump().fire("new_turn");
478  }
479 
480  pump().fire("side_turn");
481  pump().fire("side_" + side_num + "_turn");
482  pump().fire("side_turn_" + turn_num);
483  pump().fire("side_" + side_num + "_turn_" + turn_num);
484 
485  // We want to work out if units for this player should get healed,
486  // and the player should get income now.
487  // Healing/income happen if it's not the first turn of processing,
488  // or if we are loading a game.
489  if (turn() > 1) {
492 
493  // If the expense is less than the number of villages owned
494  // times the village support capacity,
495  // then we don't have to pay anything at all
496  int expense = gamestate().board_.side_upkeep(current_side()) -
497  current_team().support();
498  if(expense > 0) {
499  current_team().spend_gold(expense);
500  }
501  }
502  if (do_healing()) {
504  }
505  // Do healing on every side turn except the very first side turn.
506  // (1.14 and earlier did healing whenever turn >= 2.)
507  set_do_healing(true);
508  // Set resting now after the healing has been done.
509  for(unit &patient : resources::gameboard->units()) {
510  if(patient.side() == current_side()) {
511  patient.set_resting(true);
512  }
513  }
514 
515  // Prepare the undo stack.
517 
518  pump().fire("turn_refresh");
519  pump().fire("side_" + side_num + "_turn_refresh");
520  pump().fire("turn_" + turn_num + "_refresh");
521  pump().fire("side_" + side_num + "_turn_" + turn_num + "_refresh");
522 
523  // Make sure vision is accurate.
525  init_side_end();
526  check_victory();
527  sync.do_final_checkup();
528 }
529 
531 {
533 
534  if (current_side() == 1 || !init_side_done_now_)
536 
537  if (!is_skipping_replay()){
538  gui_->invalidate_all();
539  }
540 
541  if (!is_skipping_replay() && current_team().get_scroll_to_leader() && !map_start_.valid()){
542  gui_->scroll_to_leader(current_side(), game_display::ONSCREEN,false);
543  }
545  whiteboard_manager_->on_init_side();
546 }
547 
549 {
550  config cfg = level_;
551 
552  cfg["replay_pos"] = saved_game_.get_replay().get_pos();
553  gamestate().write(cfg);
554 
555  gui_->write(cfg.add_child("display"));
556 
557  //Write the soundsources.
558  soundsources_manager_->write_sourcespecs(cfg);
559 
560  gui_->labels().write(cfg);
562 
563  return cfg;
564 }
565 
567 {
568  whiteboard_manager_->on_finish_side_turn(current_side());
569 
570  { //Block for set_scontext_synced
571  set_scontext_synced sync(1);
572  // Ending the turn commits all moves.
573  undo_stack().clear();
575  const std::string turn_num = std::to_string(turn());
576  const std::string side_num = std::to_string(current_side());
577 
578  // Clear shroud, in case units had been slowed for the turn.
580 
581  pump().fire("side_turn_end");
582  pump().fire("side_"+ side_num + "_turn_end");
583  pump().fire("side_turn_" + turn_num + "_end");
584  pump().fire("side_" + side_num + "_turn_" + turn_num + "_end");
585  // This is where we refog, after all of a side's events are done.
587  check_victory();
588  sync.do_final_checkup();
589  }
590 
592  gamestate_->init_side_done() = false;
593 }
594 
596 {
597  set_scontext_synced sync(2);
598  const std::string turn_num = std::to_string(turn());
599  pump().fire("turn_end");
600  pump().fire("turn_" + turn_num + "_end");
601  sync.do_final_checkup();
602 }
603 
605 {
606  // If we aren't using fog/shroud, this is easy :)
607  if(current_team().uses_fog() == false && current_team().uses_shroud() == false)
608  return true;
609 
610  // See if any enemies are visible
611  for (const unit& u : gamestate().board_.units()) {
612  if (current_team().is_enemy(u.side()) && !gui_->fogged(u.get_location())) {
613  return true;
614  }
615  }
616 
617  return false;
618 }
619 
621 {
622  if(menu_handler_.get_textbox().active() == false) {
623  return;
624  }
625 
626  const std::string str = menu_handler_.get_textbox().box()->text();
627  const unsigned int team_num = current_side();
628  events::mouse_handler& mousehandler = mouse_handler_;
629 
630  switch(menu_handler_.get_textbox().mode()) {
631  case gui::TEXTBOX_SEARCH:
634  break;
637  menu_handler_.get_textbox().close(*gui_); //need to close that one after executing do_speak() !
638  break;
642  break;
643  case gui::TEXTBOX_AI:
645  menu_handler_.do_ai_formula(str, team_num, mousehandler);
646  break;
647  default:
649  ERR_DP << "unknown textbox mode" << std::endl;
650  }
651 }
652 
654 {
656 
657  std::set<std::string> dictionary;
658  switch(mode) {
659  case gui::TEXTBOX_SEARCH:
660  {
661  for (const unit& u : gamestate().board_.units()){
662  const map_location& loc = u.get_location();
663  if(!gui_->fogged(loc) &&
664  !(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
665  dictionary.insert(u.name());
666  }
667  //TODO List map labels
668  break;
669  }
671  {
672  std::vector<std::string> commands = menu_handler_.get_commands_list();
673  dictionary.insert(commands.begin(), commands.end());
674  FALLTHROUGH; // we also want player names from the next case
675  }
677  {
678  for (const team& t : gamestate().board_.teams()) {
679  if(!t.is_empty())
680  dictionary.insert(t.current_player());
681  }
682 
683  // Add observers
684  for (const std::string& o : gui_->observers()){
685  dictionary.insert(o);
686  }
687 
688  // Add nicks who whispered you
689  for (const std::string& w : gui_->get_chat_manager().whisperers()){
690  dictionary.insert(w);
691  }
692 
693  // Add nicks from friendlist
694  const std::map<std::string, std::string> friends = preferences::get_acquaintances_nice("friend");
695 
696  for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter){
697  dictionary.insert((*iter).first);
698  }
699 
700  //Exclude own nick from tab-completion.
701  //NOTE why ?
702  dictionary.erase(preferences::login());
703  break;
704  }
705 
706  default:
707  ERR_DP << "unknown textbox mode" << std::endl;
708  } //switch(mode)
709 
710  menu_handler_.get_textbox().tab(dictionary);
711 }
712 
714 {
715  assert(gamestate().board_.has_team(current_side()));
717 }
718 
720 {
721  assert(gamestate().board_.has_team(current_side()));
723 }
724 
725 /// @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
726 static int modulo(int num, int mod, int min)
727 {
728  assert(mod > 0);
729  int n = (num - min) % mod;
730  if (n < 0)
731  n += mod;
732  //n is now in [0, mod)
733  n = n + min;
734  return n;
735  // the following properties are easy to verify:
736  // 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
737  // 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
738 }
739 
740 bool play_controller::is_team_visible(int team_num, bool observer) const
741 {
742  const team& t = gamestate().board_.get_team(team_num);
743  if(observer) {
744  return !t.get_disallow_observers() && !t.is_empty();
745  }
746  else {
747  return t.is_local_human() && !t.is_idle();
748  }
749 }
750 
752 {
753  assert(current_side() <= static_cast<int>(gamestate().board_.teams().size()));
754  const int num_teams = gamestate().board_.teams().size();
755  const bool is_observer = this->is_observer();
756 
757  for(int i = 0; i < num_teams; i++) {
758  const int team_num = modulo(current_side() - i, num_teams, 1);
759  if(is_team_visible(team_num, is_observer)) {
760  return team_num;
761  }
762  }
763  return 0;
764 }
765 
767 {
768  return mouse_handler_;
769 }
770 
771 std::shared_ptr<wb::manager> play_controller::get_whiteboard() const
772 {
773  return whiteboard_manager_;
774 }
775 
777 {
778  return saved_game_.mp_settings();
779 }
780 
782 {
783  return saved_game_.classification();
784 }
785 
787 {
788  return *gui_;
789 }
790 
792 {
793  return !menu_handler_.get_textbox().active();
794 }
795 
797 {
798  if(event.key.keysym.sym == SDLK_ESCAPE) {
800  } else if(event.key.keysym.sym == SDLK_TAB) {
801  tab();
802  } else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
803  enter_textbox();
804  }
805 }
806 
807 void play_controller::process_keydown_event(const SDL_Event& event)
808 {
809  if (event.key.keysym.sym == SDLK_TAB) {
810  whiteboard_manager_->set_invert_behavior(true);
811  }
812 }
813 
814 void play_controller::process_keyup_event(const SDL_Event& event)
815 {
816  // If the user has pressed 1 through 9, we want to show
817  // how far the unit can move in that many turns
818  if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9') {
819  const int new_path_turns = (event.type == SDL_KEYDOWN) ?
820  event.key.keysym.sym - '1' : 0;
821 
822  if(new_path_turns != mouse_handler_.get_path_turns()) {
823  mouse_handler_.set_path_turns(new_path_turns);
824 
826 
827  if(u.valid()) {
828  // if it's not the unit's turn, we reset its moves
829  unit_movement_resetter move_reset(*u, u->side() != current_side());
830 
832  true, gamestate().board_.teams_[gui_->viewing_team()],
834 
835  gui_->highlight_reach(mouse_handler_.current_paths());
836  } else {
838  }
839 
840  }
841  } else if (event.key.keysym.sym == SDLK_TAB) {
842  CKey keys;
843  if (!keys[SDLK_TAB]) {
844  whiteboard_manager_->set_invert_behavior(false);
845  }
846  }
847 }
848 
850  assert(replay_);
851  return *replay_.get();
852 }
853 
855 {
857  // Saving while an event is running isn't supported
858  // because it may lead to expired event handlers being saved.
859  assert(!gamestate().events_manager_->is_event_running());
860 
862  scoped_savegame_snapshot snapshot(*this);
865  } else {
867  }
868 }
869 
870 void play_controller::save_game_auto(const std::string& filename)
871 {
874 
875  scoped_savegame_snapshot snapshot(*this);
877  save.save_game_automatic(false, filename);
878  }
879 }
880 
882 {
887  } else {
889  }
890 }
891 
892 void play_controller::save_replay_auto(const std::string& filename)
893 {
897  save.save_game_automatic(false, filename);
898  }
899 }
900 
902 {
906  } else {
908  }
909 }
910 
912 {
914  load.load_game_ingame();
915 }
916 
918 {
920  undo_stack().undo();
921 }
922 
924 {
926  undo_stack().redo();
927 }
928 
930 {
932 }
933 
935 {
937 }
938 
939 const std::string& play_controller::select_music(bool victory) const
940 {
941  const std::vector<std::string>& music_list = victory
942  ? (gamestate_->get_game_data()->get_victory_music().empty() ? game_config::default_victory_music : gamestate_->get_game_data()->get_victory_music())
943  : (gamestate_->get_game_data()->get_defeat_music().empty() ? game_config::default_defeat_music : gamestate_->get_game_data()->get_defeat_music());
944 
945  if(music_list.empty()) {
946  // Since this function returns a reference, we can't return a temporary empty string.
947  static const std::string empty_str = "";
948  return empty_str;
949  }
950 
951  return music_list[randomness::rng::default_instance().get_random_int(0, music_list.size()-1)];
952 }
953 
955 {
956  if(linger_)
957  {
958  return;
959  }
960 
961  if (is_regular_game_end()) {
962  return;
963  }
964  bool continue_level, found_player, found_network_player, invalidate_all;
965  std::set<unsigned> not_defeated;
966 
967  gamestate().board_.check_victory(continue_level, found_player, found_network_player, invalidate_all, not_defeated, remove_from_carryover_on_defeat_);
968 
969  if (invalidate_all) {
970  gui_->invalidate_all();
971  }
972 
973  if (continue_level) {
974  return ;
975  }
976 
977  if (found_player || found_network_player) {
978  pump().fire("enemies_defeated");
979  if (is_regular_game_end()) {
980  return;
981  }
982  }
983 
984  DBG_EE << "victory_when_enemies_defeated: " << victory_when_enemies_defeated_ << std::endl;
985  DBG_EE << "found_player: " << found_player << std::endl;
986  DBG_EE << "found_network_player: " << found_network_player << std::endl;
987 
988  if (!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
989  // This level has asked not to be ended by this condition.
990  return;
991  }
992 
993  if (gui_->video().non_interactive()) {
994  LOG_AIT << "winner: ";
995  for (unsigned l : not_defeated) {
997  if (ai.empty()) ai = "default ai";
998  LOG_AIT << l << " (using " << ai << ") ";
999  }
1000  LOG_AIT << std::endl;
1001  ai_testing::log_victory(not_defeated);
1002  }
1003 
1004  DBG_EE << "throwing end level exception..." << std::endl;
1005  //Also proceed to the next scenario when another player survived.
1006  end_level_data el_data;
1007  el_data.proceed_to_next_level = found_player || found_network_player;
1008  el_data.is_victory = found_player;
1009  set_end_level_data(el_data);
1010 }
1011 
1012 void play_controller::process_oos(const std::string& msg) const
1013 {
1014  if (gui_->video().non_interactive()) {
1015  throw game::game_error(msg);
1016  }
1018 
1019  std::stringstream message;
1020  message << _("The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1021  message << "\n\n" << _("Error details:") << "\n\n" << msg;
1022 
1023  scoped_savegame_snapshot snapshot(*this);
1025  save.save_game_interactive(message.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
1026 }
1027 
1028 void play_controller::update_gui_to_player(const int team_index, const bool observe)
1029 {
1030  gui_->set_team(team_index, observe);
1031  gui_->recalculate_minimap();
1032  gui_->invalidate_all();
1033 }
1034 
1036 {
1037  scoped_savegame_snapshot snapshot(*this);
1040 }
1041 
1042 void play_controller::do_consolesave(const std::string& filename)
1043 {
1044  scoped_savegame_snapshot snapshot(*this);
1046  save.save_game_automatic(true, filename);
1047 }
1048 
1050 {
1051  //note: this writes to level_ if this is not a replay.
1053 }
1054 
1056 {
1057  return gamestate().events_manager_->pump();
1058 }
1059 
1061 {
1062  return ticks_;
1063 }
1064 
1066 {
1067  return soundsources_manager_.get();
1068 }
1069 
1071 {
1072  return plugins_context_.get();
1073 }
1074 
1076 {
1077  return hotkey_handler_.get();
1078 }
1079 
1081 {
1082  if(linger_ || !gamestate_->init_side_done() || gamestate().gamedata_.phase() != game_data::PLAY) {
1083  return true;
1084  }
1085  const team& t = current_team();
1086  return !t.is_local_human() || !t.is_proxy_human();
1087 }
1088 
1090 {
1092  return;
1093  }
1094  try
1095  {
1096  play_slice();
1097  }
1098  catch(const return_to_play_side_exception&)
1099  {
1100  assert(should_return_to_play_side());
1101  }
1102 }
1103 
1105 {
1106  fire_preload();
1107 
1108  if(!gamestate().start_event_fired_)
1109  {
1110  gamestate().start_event_fired_ = true;
1114 
1115  set_scontext_synced sync;
1116 
1117  fire_prestart();
1118  if (is_regular_game_end()) {
1119  return;
1120  }
1121 
1122  for (const team& t : gamestate().board_.teams()) {
1123  actions::clear_shroud(t.side(), false, false);
1124  }
1125 
1126  init_gui();
1127  LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";
1128 
1129  fire_start();
1130  if (is_regular_game_end()) {
1131  return;
1132  }
1133  sync.do_final_checkup();
1134  gui_->recalculate_minimap();
1135  // Initialize countdown clock.
1136  for (const team& t : gamestate().board_.teams())
1137  {
1139  t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
1140  }
1141  }
1142  }
1143  else
1144  {
1145  init_gui();
1147  gui_->recalculate_minimap();
1148  }
1149 }
1150 
1152 {
1153  const team& viewing_team = get_teams_const()[gui_->viewing_team()];
1154  return gui_->viewing_team() == gui_->playing_team() && !events::commands_disabled && viewing_team.is_local_human() && !is_lingering() && !is_browsing();
1155 }
1156 
1157 std::set<std::string> play_controller::all_players() const
1158 {
1159  std::set<std::string> res = gui_->observers();
1160  for (const team& t : get_teams_const())
1161  {
1162  if (t.is_human()) {
1163  res.insert(t.current_player());
1164  }
1165  }
1166  return res;
1167 }
1168 
1170 {
1171  //check for team-specific items in the scenario
1172  gui_->parse_team_overlays();
1173  do {
1175  {
1176  save_blocker blocker;
1178  if(is_regular_game_end()) {
1179  return;
1180  }
1181  }
1182  // This flag can be set by derived classes (in overridden functions).
1183  player_type_changed_ = false;
1184 
1185  statistics::reset_turn_stats(gamestate().board_.get_team(current_side()).save_id_or_number());
1186 
1187  play_side_impl();
1188 
1189  if(is_regular_game_end()) {
1190  return;
1191  }
1192 
1193  } while (player_type_changed_);
1194  // Keep looping if the type of a team (human/ai/networked)
1195  // has changed mid-turn
1196  sync_end_turn();
1197 }
1198 
1200 {
1201  whiteboard_manager_->on_gamestate_change();
1202  gui_->new_turn();
1203  gui_->invalidate_game_status();
1204 
1205  LOG_NG << "turn: " << turn() << "\n";
1206 
1207  if(gui_->video().non_interactive()) {
1208  LOG_AIT << "Turn " << turn() << ":" << std::endl;
1209  }
1210 
1211  int last_player_number = gamestate_->player_number_;
1212  int next_player_number = gamestate_->next_player_number_;
1213 
1214  while(gamestate_->player_number_ <= static_cast<int>(gamestate().board_.teams().size())) {
1215  gamestate_->next_player_number_ = gamestate_->player_number_ + 1;
1216  next_player_number = gamestate_->next_player_number_;
1217  last_player_number = gamestate_->player_number_;
1218 
1219  // If a side is empty skip over it.
1220  if (!current_team().is_empty()) {
1221  init_side_begin();
1222  if(gamestate_->init_side_done()) {
1223  // This is the case in a reloaded game where the side was initialized before saving the game.
1224  init_side_end();
1225  }
1226 
1228  play_side();
1229  //ignore any changes to next_player_number_ that happen after the [end_turn] is sended to the server, otherwise we will get OOS.
1230  next_player_number = gamestate_->next_player_number_;
1231  assert(next_player_number <= 2 * static_cast<int>(gamestate().board_.teams().size()));
1232  if(is_regular_game_end()) {
1233  return;
1234  }
1235  //note: play_side() send the [end_turn] to the sever and finish_side_turn() callsie the side turn end events.
1236  // this means that during the side turn end events the clients think it is still the last sides turn while
1237  // the server thinks that it is already the next plyers turn. i don'T think this is a problem though.
1238  finish_side_turn();
1239  if(is_regular_game_end()) {
1240  return;
1241  }
1242  if(gui_->video().non_interactive()) {
1243  LOG_AIT << " Player " << current_side() << ": " <<
1244  current_team().villages().size() << " Villages" <<
1245  std::endl;
1247  }
1248  }
1249 
1250  gamestate_->player_number_ = next_player_number;
1251  }
1252  // If the loop exits due to the last team having been processed.
1253  gamestate_->player_number_ = last_player_number;
1254 
1255  finish_turn();
1256 
1257  // Time has run out
1258  check_time_over();
1259 
1260  if (!is_regular_game_end()) {
1261  gamestate_->player_number_ = modulo(next_player_number, gamestate().board_.teams().size(), 1);
1262  }
1263 }
1264 
1266 {
1267  const bool time_left = gamestate().tod_manager_.next_turn(&gamestate().gamedata_);
1268 
1269  if(!time_left) {
1270  LOG_NG << "firing time over event...\n";
1272  pump().fire("time_over");
1273  LOG_NG << "done firing time over event...\n";
1274  // If turns are added while handling 'time over' event.
1275  if (gamestate().tod_manager_.is_time_left()) {
1276  return;
1277  }
1278 
1279  if(gui_->video().non_interactive()) {
1280  LOG_AIT << "time over (draw)\n";
1282  }
1283 
1284  check_victory();
1285  if (is_regular_game_end()) {
1286  return;
1287  }
1288  end_level_data e;
1289  e.proceed_to_next_level = false;
1290  e.is_victory = false;
1291  set_end_level_data(e);
1292  }
1293 }
1294 
1296  : controller_(controller)
1297 {
1299 }
1300 
1302 {
1304 }
1305 
1307 {
1308  const team& t = gamestate().board_.teams()[gui_->viewing_team()];
1309  static const std::string no_objectives(_("No objectives available"));
1310  std::string objectives = utils::interpolate_variables_into_string(t.objectives(), *gamestate_->get_game_data());
1311  gui2::show_transient_message(get_scenario_name(), (objectives.empty() ? no_objectives : objectives), "", true);
1313 }
1314 
1316 {
1318  const std::shared_ptr<gui::button> skip_animation_button = get_display().find_action_button("skip-animation");
1319  if (skip_animation_button) {
1320  skip_animation_button->set_check(skip_replay_);
1321  }
1322 }
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:826
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:833
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:259
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:108
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.
static std::shared_ptr< save_index_class > default_saves_dir()
Returns an instance for managing saves in filesystem::get_saves_dir()
Definition: save_index.cpp:188
replay_recorder_base & get_replay()
Definition: saved_game.hpp:121
Class for autosaves.
Definition: savegame.hpp:288
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:192
bool enemies_visible() const
child_itors child_range(config_key_type key)
Definition: config.cpp:362
void process_keydown_event(const SDL_Event &event) override
Process keydown (always).
bool is_idle() const
Definition: team.hpp:285
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:53
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.
unit_type_data unit_types
Definition: types.cpp:1529
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:261
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.
void apply_scenario_fix(const config &cfg)
Definition: types.cpp:1462
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:520
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:371
static lg::log_domain log_display("display")
void write_music_play_list(config &snapshot)
Definition: sound.cpp:820
#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:683
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:988
bool can_undo() const
void set_phase(PHASE phase)
Definition: game_data.hpp:77
std::unique_ptr< game_state > gamestate_
An exception-safe means of making sure that unblock() gets called after try_block().
void do_consolesave(const std::string &filename)
bool is_lingering() const
map_location get_selected_hex() const
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
saved_game & saved_game_
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
scoped_savegame_snapshot(const play_controller &controller)
void init_side()
Definition: replay.cpp:215
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp: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:657
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:1914
bool load_game_ingame()
Load a game without providing any information.
Definition: savegame.cpp:121
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:105
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:283
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:1036
#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:245
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:261
Class for replay saves (either manually or automatically).
Definition: savegame.hpp:275
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:885
bool is_replay() const
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:340
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:267
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.
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
Definition: savegame.cpp:587
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
void remove_scenario_fixes()
Definition: types.cpp:1496
static const map_location & null_location()
Definition: location.hpp:85
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
config * get_next_action()
Definition: replay.cpp:614
std::set< std::string > all_players() const
void fire_preload()
preload events cannot be synced
virtual plugins_context * get_plugins_context() override
Get (optionally) a plugins context a derived class uses.
void new_turn(int pnum)
Definition: game_board.cpp:64
#define e
actions::undo_list * undo_stack
Definition: resources.cpp:32
std::size_t turn() const
void update_savegame_snapshot() const
void remove_snapshot()
Definition: saved_game.cpp:538
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:68
game_classification & get_classification()
bool valid() const
Definition: map.hpp:276
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:27
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:59
void delete_all_wml_hotkeys()
deletes all wml hotkeys, should be called after a game has ended
std::vector< std::string > get_commands_list()
void write(config &cfg) const
Definition: game_state.cpp: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:355
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()