The Battle for Wesnoth  1.15.7+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/advancement.hpp"
24 #include "actions/create.hpp"
25 #include "actions/heal.hpp"
26 #include "actions/undo.hpp"
27 #include "actions/vision.hpp"
28 #include "ai/manager.hpp"
29 #include "ai/testing.hpp"
31 #include "display_chat_manager.hpp"
32 #include "floating_label.hpp"
33 #include "formula/string_utils.hpp"
35 #include "game_events/pump.hpp"
36 #include "preferences/game.hpp"
37 #include "game_state.hpp"
38 #include "hotkey/hotkey_item.hpp"
40 #include "map/label.hpp"
41 #include "game_errors.hpp"
42 #include "gettext.hpp"
46 #include "log.hpp"
47 #include "pathfind/teleport.hpp"
48 #include "preferences/display.hpp"
49 #include "random.hpp"
50 #include "replay.hpp"
51 #include "reports.hpp"
52 #include "resources.hpp"
53 #include "save_blocker.hpp"
54 #include "save_index.hpp"
55 #include "saved_game.hpp"
56 #include "savegame.hpp"
59 #include "sound.hpp"
60 #include "soundsource.hpp"
61 #include "statistics.hpp"
62 #include "synced_context.hpp"
63 #include "terrain/type_data.hpp"
64 #include "tooltips.hpp"
65 #include "units/unit.hpp"
66 #include "units/types.hpp"
67 #include "units/id.hpp"
68 #include "whiteboard/manager.hpp"
69 
70 #include "utils/functional.hpp"
71 
72 static lg::log_domain log_aitesting("ai/testing");
73 #define LOG_AIT LOG_STREAM(info, log_aitesting)
74 //If necessary, this define can be replaced with `#define LOG_AIT std::cout` to restore previous behavior
75 
76 static lg::log_domain log_engine("engine");
77 #define LOG_NG LOG_STREAM(info, log_engine)
78 #define DBG_NG LOG_STREAM(debug, log_engine)
79 #define ERR_NG LOG_STREAM(err, log_engine)
80 
81 static lg::log_domain log_display("display");
82 #define ERR_DP LOG_STREAM(err, log_display)
83 
84 static lg::log_domain log_enginerefac("enginerefac");
85 #define LOG_RG LOG_STREAM(info, log_enginerefac)
86 
87 static lg::log_domain log_engine_enemies("engine/enemies");
88 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
89 
90 /**
91  * Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
92  */
93 static void copy_persistent(const config& src, config& dst)
94 {
95  static const std::set<std::string> attrs {
96  "description",
97  "name",
98  "victory_when_enemies_defeated",
99  "remove_from_carryover_on_defeat",
100  "disallow_recall",
101  "experience_modifier",
102  "require_scenario",
103  "loaded_resources"
104  };
105 
106  static const std::set<std::string> tags {
107  "terrain_graphics",
108  "modify_unit_type",
109  "lua"};
110 
111  for (const std::string& attr : attrs)
112  {
113  dst[attr] = src[attr];
114  }
115 
116  for (const std::string& tag : tags)
117  {
118  dst.append_children(src, tag);
119  }
120 }
121 
122 static void clear_resources()
123 {
124  resources::controller = nullptr;
125  resources::filter_con = nullptr;
126  resources::gameboard = nullptr;
127  resources::gamedata = nullptr;
128  resources::game_events = nullptr;
129  resources::lua_kernel = nullptr;
130  resources::persist = nullptr;
131  resources::soundsources = nullptr;
132  resources::tod_manager = nullptr;
133  resources::tunnels = nullptr;
134  resources::undo_stack = nullptr;
135  resources::recorder = nullptr;
136  resources::whiteboard.reset();
137  resources::classification = nullptr;
138 }
139 
141  const ter_data_cache& tdata, bool skip_replay)
142  : controller_base()
143  , observer()
145  , ticks_(SDL_GetTicks())
146  , tdata_(tdata)
147  , gamestate_()
148  , level_()
149  , saved_game_(state_of_game)
150  , tooltips_manager_()
151  , whiteboard_manager_()
152  , plugins_context_()
153  , labels_manager_(new font::floating_label_context())
154  , help_manager_(&game_config_)
155  , mouse_handler_(nullptr, *this)
156  , menu_handler_(nullptr, *this)
157  , hotkey_handler_(new hotkey_handler(*this, saved_game_))
158  , soundsources_manager_()
159  , persist_()
160  , gui_()
161  , xp_mod_(new unit_experience_accelerator(level["experience_modifier"].to_int(100)))
162  , statistics_context_(new statistics::scenario_context(level["name"]))
163  , replay_(new replay(state_of_game.get_replay()))
164  , skip_replay_(skip_replay)
165  , skip_story_(state_of_game.skip_story())
166  , linger_(false)
167  , init_side_done_now_(false)
168  , map_start_()
169  , victory_when_enemies_defeated_(level["victory_when_enemies_defeated"].to_bool(true))
170  , remove_from_carryover_on_defeat_(level["remove_from_carryover_on_defeat"].to_bool(true))
171  , victory_music_()
172  , defeat_music_()
173  , scope_()
174  , ignore_replay_errors_(false)
175  , player_type_changed_(false)
176 {
177  copy_persistent(level, level_);
178 
179  for(const config& modify_unit_type : level_.child_range("modify_unit_type")) {
180  unit_types.apply_scenario_fix(modify_unit_type);
181  }
182  resources::controller = this;
185 
187 
189 
193  try {
194  init(level);
195  } catch (...) {
196  clear_resources();
197  throw;
198  }
199 }
200 
202 {
205  clear_resources();
206 }
207 
209 {
210  void operator()(const config&) const
211  {
213  }
214 };
215 
217 {
218  gui2::dialogs::loading_screen::display([this, &level]() {
220 
221  LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl;
222  gamestate_.reset(new game_state(level, *this, tdata_));
223 
231 
232  gamestate_->ai_manager_.add_observer(this);
233  gamestate_->init(level, *this);
235 
236  LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl;
238  whiteboard_manager_.reset(new wb::manager());
240 
241  LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl;
244 
245  LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl;
247  const config& theme_cfg = controller_base::get_theme(game_config_, theme());
248 
249  LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl;
251  gui_.reset(new game_display(gamestate().board_, whiteboard_manager_, *gamestate().reports_, theme_cfg, level));
252  map_start_ = map_location(level.child_or_empty("display").child_or_empty("location"));
253  if (!gui_->video().faked()) {
255  gui_->get_theme().modify_label("time-icon", _ ("time left for current turn"));
256  else
257  gui_->get_theme().modify_label("time-icon", _ ("current local time"));
258  }
259 
261  mouse_handler_.set_gui(gui_.get());
262  menu_handler_.set_gui(gui_.get());
263 
264  LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl;
265 
266  LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl;
267  // This *needs* to be created before the show_intro and show_map_scene
268  // as that functions use the manager state_of_game
269  // Has to be done before registering any events!
272 
273  if(gamestate().first_human_team_ != -1) {
274  gui_->set_team(gamestate().first_human_team_);
275  }
276  else if(is_observer()) {
277  // Find first team that is allowed to be observed.
278  // If not set here observer would be without fog until
279  // the first turn of observable side
280  for (const team& t : gamestate().board_.teams())
281  {
282  if (!t.get_disallow_observers())
283  {
284  gui_->set_team(t.side() - 1);
285  }
286  }
287  }
288 
289  init_managers();
291  //loadscreen_manager->reset();
293  gamestate().lua_kernel_->load_game(level);
294 
295  plugins_context_.reset(new plugins_context("Game"));
296  plugins_context_->set_callback("save_game", [this](const config& cfg) { save_game_auto(cfg["filename"]); }, true);
297  plugins_context_->set_callback("save_replay", [this](const config& cfg) { save_replay_auto(cfg["filename"]); }, true);
298  plugins_context_->set_callback("quit", throw_end_level(), false);
299  plugins_context_->set_accessor_string("scenario_name", [this](config) { return get_scenario_name(); });
300  });
301  //Do this after the loadingscreen, so that ita happens in the main thread.
302  gui_->join();
303 }
304 
305 void play_controller::reset_gamestate(const config& level, int replay_pos)
306 {
307  resources::gameboard = nullptr;
308  resources::gamedata = nullptr;
309  resources::tod_manager = nullptr;
310  resources::filter_con = nullptr;
311  resources::lua_kernel = nullptr;
312  resources::game_events = nullptr;
313  resources::tunnels = nullptr;
314  resources::undo_stack = nullptr;
315 
316  gui_->labels().set_team(nullptr);
317 
318  /* First destroy the old game state, then create the new one.
319  This is necessary to ensure that while the old AI manager is being destroyed,
320  all its member objects access the old manager instead of the new. */
321  gamestate_.reset();
322  gamestate_.reset(new game_state(level, *this, tdata_));
330 
331  gamestate_->ai_manager_.add_observer(this);
332  gamestate_->init(level, *this);
335 
336  gui_->reset_reports(*gamestate().reports_);
337  gui_->change_display_context(&gamestate().board_);
338  saved_game_.get_replay().set_pos(replay_pos);
340  gamestate().lua_kernel_->load_game(level);
341 }
342 
344 {
345  LOG_NG << "initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
349 
351  LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
352 }
353 
355 {
356  // Run initialization scripts, even if loading from a snapshot.
357  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
358  pump().fire("preload");
359 }
360 
362 {
363  // pre-start events must be executed before any GUI operation,
364  // as those may cause the display to be refreshed.
365  update_locker lock_display(gui_->video());
367 
368  // Fire these right before prestart events, to catch only the units sides
369  // have started with.
370  for (const unit& u : gamestate().board_.units()) {
371  pump().fire("unit_placed", map_location(u.get_location()));
372  }
373 
374  pump().fire("prestart");
375  // prestart event may modify start turn with WML, reflect any changes.
376  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
377 }
378 
380 {
381  const config cfg("side", gui_->viewing_side());
382  gamestate().lua_kernel_->run_wml_action("show_objectives", vconfig(cfg),
383  game_events::queued_event("_from_interface", "", map_location(), map_location(), config()));
384 }
385 
387 {
389  pump().fire("start");
390 
391  skip_story_ = false; // Show [message]s from now on even with --campaign-skip-story
392 
393  // start event may modify start turn with WML, reflect any changes.
394  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
395 
398  // prestart and start events may modify the initial gold amount,
399  // reflect any changes.
400  for (team& tm : gamestate().board_.teams_)
401  {
402  tm.set_start_gold(tm.gold());
403  }
404  gamestate_->init_side_done() = false;
406 }
407 
409 {
410  gui_->begin_game();
411  gui_->update_tod();
412 }
413 
415 {
417 
418  // If we are observers we move to watch next team if it is allowed
419  if ((is_observer() && !current_team().get_disallow_observers())
420  || (current_team().is_local_human() && !this->is_replay()))
421  {
423  }
424 
425  gui_->set_playing_team(std::size_t(current_side() - 1));
426 
428 }
429 
431 {
432  //
433  // We do side init only if not done yet for a local side when we are not replaying.
434  // For all other sides it is recorded in replay and replay handler has to handle
435  // calling do_init_side() functions.
436  //
437  if (gamestate_->init_side_done()) {
438  // We already executed do_init_side this can for example happe if we reload a game,
439  // but also if we changed control of a side during it's turn
440  return;
441  }
442  if (!current_team().is_local()) {
443  // We are in a mp game and execute do_init_side as soon as we receive [init_side] from the current player
444  // (see replay.cpp)
445  return;
446  }
447 
448  if (is_replay()) {
449  // We are in a replay and execute do_init_side as soon as we reach the next [init_side] in the replay data
450  // (see replay.cpp)
451  return;
452  }
453 
454  if (current_team().is_idle()) {
455  // In this case it can happen that we just gave control of this side to another player so doing init_side
456  // could lead to errors since we no longer own this side from the servers perspective.
457  // (see playturn.cpp)
458  return;
459  }
460 
462  do_init_side();
463 }
464 
466 {
467  set_scontext_synced sync;
468  log_scope("player turn");
469  // In case we might end up calling sync:network during the side turn events,
470  // and we don't want do_init_side to be called when a player drops.
471  gamestate_->init_side_done() = true;
472  init_side_done_now_ = true;
473 
474  const std::string turn_num = std::to_string(turn());
475  const std::string side_num = std::to_string(current_side());
476 
477  gamestate().gamedata_.get_variable("side_number") = current_side();
478 
479  // We might have skipped some sides because they were empty so it is not enough to check for side_num==1
480  if(!gamestate().tod_manager_.has_turn_event_fired())
481  {
482  pump().fire("turn_" + turn_num);
483  pump().fire("new_turn");
485  }
486 
487  pump().fire("side_turn");
488  pump().fire("side_" + side_num + "_turn");
489  pump().fire("side_turn_" + turn_num);
490  pump().fire("side_" + side_num + "_turn_" + turn_num);
491 
492  // We want to work out if units for this player should get healed,
493  // and the player should get income now.
494  // Healing/income happen if it's not the first turn of processing,
495  // or if we are loading a game.
496  if (turn() > 1) {
499 
500  // If the expense is less than the number of villages owned
501  // times the village support capacity,
502  // then we don't have to pay anything at all
503  int expense = gamestate().board_.side_upkeep(current_side()) -
504  current_team().support();
505  if(expense > 0) {
506  current_team().spend_gold(expense);
507  }
508  }
509  if (do_healing()) {
511  }
512  // Do healing on every side turn except the very first side turn.
513  // (1.14 and earlier did healing whenever turn >= 2.)
514  set_do_healing(true);
515  // Set resting now after the healing has been done.
516  for(unit &patient : resources::gameboard->units()) {
517  if(patient.side() == current_side()) {
518  patient.set_resting(true);
519  }
520  }
521 
522  // Prepare the undo stack.
524 
525  pump().fire("turn_refresh");
526  pump().fire("side_" + side_num + "_turn_refresh");
527  pump().fire("turn_" + turn_num + "_refresh");
528  pump().fire("side_" + side_num + "_turn_" + turn_num + "_refresh");
529 
530  // Make sure vision is accurate.
532  {
533  const auto& active_mods = get_saved_game().classification().active_mods;
534  bool delay_advancements = std::find(active_mods.begin(), active_mods.end(), "delay_advancements") != active_mods.end();
535 
536  for(unit &u : resources::gameboard->units()) {
537  if(delay_advancements && u.side() == current_side()) {
538  advance_unit_at(u.get_location());
539  }
540  }
541  }
542  init_side_end();
543  check_victory();
544  sync.do_final_checkup();
545 }
546 
548 {
550 
551  if (current_side() == 1 || !init_side_done_now_)
553 
554  if (!is_skipping_replay()){
555  gui_->invalidate_all();
556  }
557 
558  if (!is_skipping_replay() && current_team().get_scroll_to_leader() && !map_start_.valid()){
559  gui_->scroll_to_leader(current_side(), game_display::ONSCREEN,false);
560  }
562  whiteboard_manager_->on_init_side();
563 }
564 
566 {
567  config cfg = level_;
568 
569  cfg["replay_pos"] = saved_game_.get_replay().get_pos();
570  gamestate().write(cfg);
571 
572  gui_->write(cfg.add_child("display"));
573 
574  //Write the soundsources.
575  soundsources_manager_->write_sourcespecs(cfg);
576 
577  gui_->labels().write(cfg);
579 
580  return cfg;
581 }
582 
584 {
585  whiteboard_manager_->on_finish_side_turn(current_side());
586 
587  { //Block for set_scontext_synced
588  set_scontext_synced sync(1);
589  // Ending the turn commits all moves.
590  undo_stack().clear();
592  const std::string turn_num = std::to_string(turn());
593  const std::string side_num = std::to_string(current_side());
594 
595  // Clear shroud, in case units had been slowed for the turn.
597 
598  pump().fire("side_turn_end");
599  pump().fire("side_"+ side_num + "_turn_end");
600  pump().fire("side_turn_" + turn_num + "_end");
601  pump().fire("side_" + side_num + "_turn_" + turn_num + "_end");
602  // This is where we refog, after all of a side's events are done.
604  check_victory();
605  sync.do_final_checkup();
606  }
607 
609  gamestate_->init_side_done() = false;
610 }
611 
613 {
614  set_scontext_synced sync(2);
615  const std::string turn_num = std::to_string(turn());
616  pump().fire("turn_end");
617  pump().fire("turn_" + turn_num + "_end");
618  sync.do_final_checkup();
619 }
620 
622 {
623  // If we aren't using fog/shroud, this is easy :)
624  if(current_team().uses_fog() == false && current_team().uses_shroud() == false)
625  return true;
626 
627  // See if any enemies are visible
628  for (const unit& u : gamestate().board_.units()) {
629  if (current_team().is_enemy(u.side()) && !gui_->fogged(u.get_location())) {
630  return true;
631  }
632  }
633 
634  return false;
635 }
636 
638 {
639  if(menu_handler_.get_textbox().active() == false) {
640  return;
641  }
642 
643  const std::string str = menu_handler_.get_textbox().box()->text();
644  const unsigned int team_num = current_side();
645  events::mouse_handler& mousehandler = mouse_handler_;
646 
647  switch(menu_handler_.get_textbox().mode()) {
648  case gui::TEXTBOX_SEARCH:
651  break;
654  menu_handler_.get_textbox().close(*gui_); //need to close that one after executing do_speak() !
655  break;
659  break;
660  case gui::TEXTBOX_AI:
662  menu_handler_.do_ai_formula(str, team_num, mousehandler);
663  break;
664  default:
666  ERR_DP << "unknown textbox mode" << std::endl;
667  }
668 }
669 
671 {
673 
674  std::set<std::string> dictionary;
675  switch(mode) {
676  case gui::TEXTBOX_SEARCH:
677  {
678  for (const unit& u : gamestate().board_.units()){
679  const map_location& loc = u.get_location();
680  if(!gui_->fogged(loc) &&
681  !(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
682  dictionary.insert(u.name());
683  }
684  //TODO List map labels
685  break;
686  }
688  {
689  std::vector<std::string> commands = menu_handler_.get_commands_list();
690  dictionary.insert(commands.begin(), commands.end());
691  FALLTHROUGH; // we also want player names from the next case
692  }
694  {
695  for (const team& t : gamestate().board_.teams()) {
696  if(!t.is_empty())
697  dictionary.insert(t.current_player());
698  }
699 
700  // Add observers
701  for (const std::string& o : gui_->observers()){
702  dictionary.insert(o);
703  }
704 
705  // Add nicks who whispered you
706  for (const std::string& w : gui_->get_chat_manager().whisperers()){
707  dictionary.insert(w);
708  }
709 
710  // Add nicks from friendlist
711  const std::map<std::string, std::string> friends = preferences::get_acquaintances_nice("friend");
712 
713  for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter){
714  dictionary.insert((*iter).first);
715  }
716 
717  //Exclude own nick from tab-completion.
718  //NOTE why ?
719  dictionary.erase(preferences::login());
720  break;
721  }
722 
723  default:
724  ERR_DP << "unknown textbox mode" << std::endl;
725  } //switch(mode)
726 
727  menu_handler_.get_textbox().tab(dictionary);
728 }
729 
731 {
732  if(gamestate().board_.teams().size() == 0) {
733  throw game::game_error("The scenario has no sides defined");
734  }
735  assert(gamestate().board_.has_team(current_side()));
737 }
738 
740 {
741  if(gamestate().board_.teams().size() == 0) {
742  throw game::game_error("The scenario has no sides defined");
743  }
744  assert(gamestate().board_.has_team(current_side()));
746 }
747 
748 bool play_controller::is_team_visible(int team_num, bool observer) const
749 {
750  const team& t = gamestate().board_.get_team(team_num);
751  if(observer) {
752  return !t.get_disallow_observers() && !t.is_empty();
753  }
754  else {
755  return t.is_local_human() && !t.is_idle();
756  }
757 }
758 
760 {
761  assert(current_side() <= static_cast<int>(gamestate().board_.teams().size()));
762  const int num_teams = gamestate().board_.teams().size();
763  const bool is_observer = this->is_observer();
764 
765  for(int i = 0; i < num_teams; i++) {
766  const int team_num = modulo(current_side() - i, num_teams, 1);
767  if(is_team_visible(team_num, is_observer)) {
768  return team_num;
769  }
770  }
771  return 0;
772 }
773 
775 {
776  return mouse_handler_;
777 }
778 
779 std::shared_ptr<wb::manager> play_controller::get_whiteboard() const
780 {
781  return whiteboard_manager_;
782 }
783 
785 {
786  return saved_game_.mp_settings();
787 }
788 
790 {
791  return saved_game_.classification();
792 }
793 
795 {
796  return *gui_;
797 }
798 
800 {
801  return !menu_handler_.get_textbox().active();
802 }
803 
805 {
806  if(event.key.keysym.sym == SDLK_ESCAPE) {
808  } else if(event.key.keysym.sym == SDLK_TAB) {
809  tab();
810  } else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
811  enter_textbox();
812  }
813 }
814 
815 void play_controller::process_keydown_event(const SDL_Event& event)
816 {
817  if (event.key.keysym.sym == SDLK_TAB) {
818  whiteboard_manager_->set_invert_behavior(true);
819  }
820 }
821 
822 void play_controller::process_keyup_event(const SDL_Event& event)
823 {
824  // If the user has pressed 1 through 9, we want to show
825  // how far the unit can move in that many turns
826  if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9') {
827  const int new_path_turns = (event.type == SDL_KEYDOWN) ?
828  event.key.keysym.sym - '1' : 0;
829 
830  if(new_path_turns != mouse_handler_.get_path_turns()) {
831  mouse_handler_.set_path_turns(new_path_turns);
832 
834 
835  if(u.valid()) {
836  // if it's not the unit's turn, we reset its moves
837  unit_movement_resetter move_reset(*u, u->side() != current_side());
838 
840  true, gamestate().board_.teams_[gui_->viewing_team()],
842 
843  gui_->highlight_reach(mouse_handler_.current_paths());
844  } else {
846  }
847 
848  }
849  } else if (event.key.keysym.sym == SDLK_TAB) {
850  CKey keys;
851  if (!keys[SDLK_TAB]) {
852  whiteboard_manager_->set_invert_behavior(false);
853  }
854  }
855 }
856 
858  assert(replay_);
859  return *replay_.get();
860 }
861 
863 {
865  // Saving while an event is running isn't supported
866  // because it may lead to expired event handlers being saved.
867  assert(!gamestate().events_manager_->is_event_running());
868 
870  scoped_savegame_snapshot snapshot(*this);
873  } else {
875  }
876 }
877 
879 {
882 
883  scoped_savegame_snapshot snapshot(*this);
885  save.save_game_automatic(false, filename);
886  }
887 }
888 
890 {
895  } else {
897  }
898 }
899 
901 {
905  save.save_game_automatic(false, filename);
906  }
907 }
908 
910 {
914  } else {
916  }
917 }
918 
920 {
922  load.load_game_ingame();
923 }
924 
926 {
928  undo_stack().undo();
929 }
930 
932 {
934  undo_stack().redo();
935 }
936 
938 {
940 }
941 
943 {
945 }
946 
947 const std::string& play_controller::select_music(bool victory) const
948 {
949  const std::vector<std::string>& music_list = victory
950  ? (gamestate_->get_game_data()->get_victory_music().empty() ? game_config::default_victory_music : gamestate_->get_game_data()->get_victory_music())
951  : (gamestate_->get_game_data()->get_defeat_music().empty() ? game_config::default_defeat_music : gamestate_->get_game_data()->get_defeat_music());
952 
953  if(music_list.empty()) {
954  // Since this function returns a reference, we can't return a temporary empty string.
955  static const std::string empty_str = "";
956  return empty_str;
957  }
958 
959  return music_list[randomness::rng::default_instance().get_random_int(0, music_list.size()-1)];
960 }
961 
963 {
964  if(linger_)
965  {
966  return;
967  }
968 
969  if (is_regular_game_end()) {
970  return;
971  }
972  bool continue_level, found_player, found_network_player, invalidate_all;
973  std::set<unsigned> not_defeated;
974 
975  gamestate().board_.check_victory(continue_level, found_player, found_network_player, invalidate_all, not_defeated, remove_from_carryover_on_defeat_);
976 
977  if (invalidate_all) {
978  gui_->invalidate_all();
979  }
980 
981  if (continue_level) {
982  return ;
983  }
984 
985  if (found_player || found_network_player) {
986  pump().fire("enemies_defeated");
987  if (is_regular_game_end()) {
988  return;
989  }
990  }
991 
992  DBG_EE << "victory_when_enemies_defeated: " << victory_when_enemies_defeated_ << std::endl;
993  DBG_EE << "found_player: " << found_player << std::endl;
994  DBG_EE << "found_network_player: " << found_network_player << std::endl;
995 
996  if (!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
997  // This level has asked not to be ended by this condition.
998  return;
999  }
1000 
1001  if (gui_->video().non_interactive()) {
1002  LOG_AIT << "winner: ";
1003  for (unsigned l : not_defeated) {
1005  if (ai.empty()) ai = "default ai";
1006  LOG_AIT << l << " (using " << ai << ") ";
1007  }
1008  LOG_AIT << std::endl;
1009  ai_testing::log_victory(not_defeated);
1010  }
1011 
1012  DBG_EE << "throwing end level exception..." << std::endl;
1013  //Also proceed to the next scenario when another player survived.
1014  end_level_data el_data;
1015  el_data.proceed_to_next_level = found_player || found_network_player;
1016  el_data.is_victory = found_player;
1017  set_end_level_data(el_data);
1018 }
1019 
1021 {
1022  if (gui_->video().non_interactive()) {
1023  throw game::game_error(msg);
1024  }
1026 
1027  std::stringstream message;
1028  message << _("The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1029  message << "\n\n" << _("Error details:") << "\n\n" << msg;
1030 
1031  scoped_savegame_snapshot snapshot(*this);
1033  save.save_game_interactive(message.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
1034 }
1035 
1036 void play_controller::update_gui_to_player(const int team_index, const bool observe)
1037 {
1038  gui_->set_team(team_index, observe);
1039  gui_->recalculate_minimap();
1040  gui_->invalidate_all();
1041 }
1042 
1044 {
1045  scoped_savegame_snapshot snapshot(*this);
1048 }
1049 
1051 {
1052  scoped_savegame_snapshot snapshot(*this);
1054  save.save_game_automatic(true, filename);
1055 }
1056 
1058 {
1059  //note: this writes to level_ if this is not a replay.
1061 }
1062 
1064 {
1065  return gamestate().events_manager_->pump();
1066 }
1067 
1069 {
1070  return ticks_;
1071 }
1072 
1074 {
1075  return soundsources_manager_.get();
1076 }
1077 
1079 {
1080  return plugins_context_.get();
1081 }
1082 
1084 {
1085  return hotkey_handler_.get();
1086 }
1087 
1089 {
1090  if(linger_ || !gamestate_->init_side_done() || gamestate().gamedata_.phase() != game_data::PLAY) {
1091  return true;
1092  }
1093  const team& t = current_team();
1094  return !t.is_local_human() || !t.is_proxy_human();
1095 }
1096 
1098 {
1100  return;
1101  }
1102  try
1103  {
1104  play_slice();
1105  }
1106  catch(const return_to_play_side_exception&)
1107  {
1108  assert(should_return_to_play_side());
1109  }
1110 }
1111 
1113 {
1114  fire_preload();
1115 
1116  if(!gamestate().start_event_fired_)
1117  {
1118  gamestate().start_event_fired_ = true;
1122 
1123  set_scontext_synced sync;
1124 
1125  fire_prestart();
1126  if (is_regular_game_end()) {
1127  return;
1128  }
1129 
1130  for (const team& t : gamestate().board_.teams()) {
1131  actions::clear_shroud(t.side(), false, false);
1132  }
1133 
1134  init_gui();
1135  LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";
1136 
1137  fire_start();
1138  if (is_regular_game_end()) {
1139  return;
1140  }
1141  sync.do_final_checkup();
1142  gui_->recalculate_minimap();
1143  // Initialize countdown clock.
1144  for (const team& t : gamestate().board_.teams())
1145  {
1147  t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
1148  }
1149  }
1150  }
1151  else
1152  {
1153  init_gui();
1155  gui_->recalculate_minimap();
1156  }
1157 }
1158 
1160 {
1161  const team& viewing_team = get_teams_const()[gui_->viewing_team()];
1162  return gui_->viewing_team() == gui_->playing_team() && !events::commands_disabled && viewing_team.is_local_human() && !is_lingering() && !is_browsing();
1163 }
1164 
1165 std::set<std::string> play_controller::all_players() const
1166 {
1167  std::set<std::string> res = gui_->observers();
1168  for (const team& t : get_teams_const())
1169  {
1170  if (t.is_human()) {
1171  res.insert(t.current_player());
1172  }
1173  }
1174  return res;
1175 }
1176 
1178 {
1179  //check for team-specific items in the scenario
1180  gui_->parse_team_overlays();
1181  do {
1183  {
1184  save_blocker blocker;
1186  if(is_regular_game_end()) {
1187  return;
1188  }
1189  }
1190  // This flag can be set by derived classes (in overridden functions).
1191  player_type_changed_ = false;
1192 
1193  statistics::reset_turn_stats(gamestate().board_.get_team(current_side()).save_id_or_number());
1194 
1195  play_side_impl();
1196 
1197  if(is_regular_game_end()) {
1198  return;
1199  }
1200 
1201  } while (player_type_changed_);
1202  // Keep looping if the type of a team (human/ai/networked)
1203  // has changed mid-turn
1204  sync_end_turn();
1205 }
1206 
1208 {
1209  whiteboard_manager_->on_gamestate_change();
1210  gui_->new_turn();
1211  gui_->invalidate_game_status();
1212 
1213  LOG_NG << "turn: " << turn() << "\n";
1214 
1215  if(gui_->video().non_interactive()) {
1216  LOG_AIT << "Turn " << turn() << ":" << std::endl;
1217  }
1218 
1219  int last_player_number = gamestate_->player_number_;
1220  int next_player_number = gamestate_->next_player_number_;
1221 
1222  while(gamestate_->player_number_ <= static_cast<int>(gamestate().board_.teams().size())) {
1223  gamestate_->next_player_number_ = gamestate_->player_number_ + 1;
1224  next_player_number = gamestate_->next_player_number_;
1225  last_player_number = gamestate_->player_number_;
1226 
1227  // If a side is empty skip over it.
1228  if (!current_team().is_empty()) {
1229  init_side_begin();
1230  if(gamestate_->init_side_done()) {
1231  // This is the case in a reloaded game where the side was initialized before saving the game.
1232  init_side_end();
1233  }
1234 
1236  play_side();
1237  //ignore any changes to next_player_number_ that happen after the [end_turn] is sended to the server, otherwise we will get OOS.
1238  next_player_number = gamestate_->next_player_number_;
1239  assert(next_player_number <= 2 * static_cast<int>(gamestate().board_.teams().size()));
1240  if(is_regular_game_end()) {
1241  return;
1242  }
1243  //note: play_side() send the [end_turn] to the sever and finish_side_turn() callsie the side turn end events.
1244  // this means that during the side turn end events the clients think it is still the last sides turn while
1245  // the server thinks that it is already the next plyers turn. i don'T think this is a problem though.
1246  finish_side_turn();
1247  if(is_regular_game_end()) {
1248  return;
1249  }
1250  if(gui_->video().non_interactive()) {
1251  LOG_AIT << " Player " << current_side() << ": " <<
1252  current_team().villages().size() << " Villages" <<
1253  std::endl;
1255  }
1256  }
1257 
1258  gamestate_->player_number_ = next_player_number;
1259  }
1260  // If the loop exits due to the last team having been processed.
1261  gamestate_->player_number_ = last_player_number;
1262 
1263  finish_turn();
1264 
1265  // Time has run out
1266  check_time_over();
1267 
1268  if (!is_regular_game_end()) {
1269  gamestate_->player_number_ = modulo(next_player_number, gamestate().board_.teams().size(), 1);
1270  }
1271 }
1272 
1274 {
1275  const bool time_left = gamestate().tod_manager_.next_turn(&gamestate().gamedata_);
1276 
1277  if(!time_left) {
1278  LOG_NG << "firing time over event...\n";
1280  pump().fire("time_over");
1281  LOG_NG << "done firing time over event...\n";
1282  // If turns are added while handling 'time over' event.
1283  if (gamestate().tod_manager_.is_time_left()) {
1284  return;
1285  }
1286 
1287  if(gui_->video().non_interactive()) {
1288  LOG_AIT << "time over (draw)\n";
1290  }
1291 
1292  check_victory();
1293  if (is_regular_game_end()) {
1294  return;
1295  }
1296  end_level_data e;
1297  e.proceed_to_next_level = false;
1298  e.is_victory = false;
1299  set_end_level_data(e);
1300  }
1301 }
1302 
1304  : controller_(controller)
1305 {
1307 }
1308 
1310 {
1312 }
1313 
1315 {
1316  const team& t = gamestate().board_.teams()[gui_->viewing_team()];
1317  static const std::string no_objectives(_("No objectives available"));
1318  std::string objectives = utils::interpolate_variables_into_string(t.objectives(), *gamestate_->get_game_data());
1319  gui2::show_transient_message(get_scenario_name(), (objectives.empty() ? no_objectives : objectives), "", true);
1321 }
1322 
1324 {
1326  const std::shared_ptr<gui::button> skip_animation_button = get_display().find_action_button("skip-animation");
1327  if (skip_animation_button) {
1328  skip_animation_button->set_check(skip_replay_);
1329  }
1330 }
std::shared_ptr< gui::button > find_action_button(const std::string &id)
Retrieves a pointer to a theme UI button.
Definition: display.cpp:827
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:822
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:109
saved_game & get_saved_game()
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:129
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)
Note: Specific to sdl_ttf.
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_
static game_config_view wrap(const config &cfg)
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:123
Class for autosaves.
Definition: savegame.hpp:289
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
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:54
static const config & get_theme(const game_config_view &game_config, std::string theme_name)
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
Gather statistics important for AI testing and output them.
unit_type_data unit_types
Definition: types.cpp:1378
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:262
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:1311
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:559
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:241
std::string str
Definition: statement.cpp:110
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:373
static lg::log_domain log_display("display")
void write_music_play_list(config &snapshot)
Definition: sound.cpp:851
#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:684
void process_focus_keydown_event(const SDL_Event &event) override
Process keydown (only when the general map display does not have focus).
#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:1020
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:59
scoped_savegame_snapshot(const play_controller &controller)
void init_side()
Definition: replay.cpp:215
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:100
team & get_team(int i)
Definition: game_board.hpp:104
void throw_quit_game_exception()
void save_game_auto(const std::string &filename)
Various functions that implement advancements of units.
bool add_start_if_not_there_yet()
Definition: replay.cpp:657
std::vector< std::string > active_mods
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:1942
bool load_game_ingame()
Load a game without providing any information.
Definition: savegame.cpp:123
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
static void add_color_info(const game_config_view &v, bool build_defaults)
An object which will lock the display for the duration of its lifetime.
Definition: video.hpp:296
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:694
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:1025
#define log_scope(description)
Definition: log.hpp:208
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:244
void advance_unit_at(const advance_unit_params &params)
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:276
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:874
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:241
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).
const game_config_view & game_config_
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:44
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:593
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:1345
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
static lg::log_domain log_aitesting("ai/testing")
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:577
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:246
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:357
virtual void play_side_impl()
bool start_event_fired_
Definition: game_state.hpp:64
T modulo(T num, int mod, T min=0)
Definition: math.hpp:61
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()