The Battle for Wesnoth  1.15.1+dev
play_controller.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2018 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
3  wesnoth playlevel Copyright (C) 2003 by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Handle input via mouse & keyboard, events, schedule commands.
19  */
20 
21 #include "play_controller.hpp"
22 
23 #include "actions/create.hpp"
24 #include "actions/heal.hpp"
25 #include "actions/undo.hpp"
26 #include "actions/vision.hpp"
27 #include "ai/manager.hpp"
28 #include "ai/testing.hpp"
30 #include "display_chat_manager.hpp"
31 #include "formula/string_utils.hpp"
33 #include "game_events/pump.hpp"
34 #include "preferences/game.hpp"
35 #include "game_state.hpp"
36 #include "hotkey/hotkey_item.hpp"
38 #include "map/label.hpp"
39 #include "gettext.hpp"
43 #include "log.hpp"
44 #include "pathfind/teleport.hpp"
45 #include "preferences/display.hpp"
46 #include "random.hpp"
47 #include "replay.hpp"
48 #include "reports.hpp"
49 #include "resources.hpp"
50 #include "savegame.hpp"
51 #include "saved_game.hpp"
52 #include "save_blocker.hpp"
55 #include "sound.hpp"
56 #include "soundsource.hpp"
57 #include "statistics.hpp"
58 #include "synced_context.hpp"
59 #include "terrain/type_data.hpp"
60 #include "tooltips.hpp"
61 #include "units/unit.hpp"
62 #include "units/id.hpp"
63 #include "whiteboard/manager.hpp"
64 
65 #include "utils/functional.hpp"
66 
67 static lg::log_domain log_aitesting("aitesting");
68 #define LOG_AIT LOG_STREAM(info, log_aitesting)
69 //If necessary, this define can be replaced with `#define LOG_AIT std::cout` to restore previous behavior
70 
71 static lg::log_domain log_engine("engine");
72 #define LOG_NG LOG_STREAM(info, log_engine)
73 #define DBG_NG LOG_STREAM(debug, log_engine)
74 
75 static lg::log_domain log_display("display");
76 #define ERR_DP LOG_STREAM(err, log_display)
77 
78 static lg::log_domain log_enginerefac("enginerefac");
79 #define LOG_RG LOG_STREAM(info, log_enginerefac)
80 
81 static lg::log_domain log_engine_enemies("engine/enemies");
82 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
83 
84 /**
85  * Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
86  */
87 static void copy_persistent(const config& src, config& dst)
88 {
89  static const std::set<std::string> attrs {
90  "description",
91  "name",
92  "victory_when_enemies_defeated",
93  "remove_from_carryover_on_defeat",
94  "disallow_recall",
95  "experience_modifier",
96  "require_scenario"};
97 
98  static const std::set<std::string> tags {
99  "terrain_graphics",
100  "unit_type_fix",
101  "lua"};
102 
103  for (const std::string& attr : attrs)
104  {
105  dst[attr] = src[attr];
106  }
107 
108  for (const std::string& tag : tags)
109  {
110  dst.append_children(src, tag);
111  }
112 }
113 
114 static void clear_resources()
115 {
116  resources::controller = nullptr;
117  resources::filter_con = nullptr;
118  resources::gameboard = nullptr;
119  resources::gamedata = nullptr;
120  resources::game_events = nullptr;
121  resources::lua_kernel = nullptr;
122  resources::persist = nullptr;
123  resources::soundsources = nullptr;
124  resources::tod_manager = nullptr;
125  resources::tunnels = nullptr;
126  resources::undo_stack = nullptr;
127  resources::recorder = nullptr;
128  resources::whiteboard.reset();
129  resources::classification = nullptr;
130 }
131 
133  const ter_data_cache& tdata, bool skip_replay)
134  : controller_base()
135  , observer()
137  , ticks_(SDL_GetTicks())
138  , tdata_(tdata)
139  , gamestate_()
140  , level_()
141  , saved_game_(state_of_game)
142  , tooltips_manager_()
143  , whiteboard_manager_()
144  , plugins_context_()
145  , labels_manager_()
146  , help_manager_(&game_config_)
147  , mouse_handler_(nullptr, *this)
148  , menu_handler_(nullptr, *this)
149  , hotkey_handler_(new hotkey_handler(*this, saved_game_))
150  , soundsources_manager_()
151  , persist_()
152  , gui_()
153  , xp_mod_(new unit_experience_accelerator(level["experience_modifier"].to_int(100)))
154  , statistics_context_(new statistics::scenario_context(level["name"]))
155  , replay_(new replay(state_of_game.get_replay()))
156  , skip_replay_(skip_replay)
157  , skip_story_(state_of_game.skip_story())
158  , linger_(false)
159  , init_side_done_now_(false)
160  , map_start_()
161  , victory_when_enemies_defeated_(level["victory_when_enemies_defeated"].to_bool(true))
162  , remove_from_carryover_on_defeat_(level["remove_from_carryover_on_defeat"].to_bool(true))
163  , victory_music_()
164  , defeat_music_()
165  , scope_()
166  , ignore_replay_errors_(false)
167  , player_type_changed_(false)
168 {
169  copy_persistent(level, level_);
170 
171  for(const config& unit_type_fix : level_.child_range("unit_type_fix")) {
172  unit_types.apply_scenario_fix(unit_type_fix);
173  }
174  resources::controller = this;
177 
179 
181 
185  try {
186  init(level);
187  } catch (...) {
188  clear_resources();
189  throw;
190  }
191 }
192 
194 {
197  clear_resources();
198 }
199 
201 {
202  void operator()(const config&) const
203  {
205  }
206 };
207 
209 {
210  gui2::dialogs::loading_screen::display([this, &level]() {
212 
213  LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl;
214  gamestate_.reset(new game_state(level, *this, tdata_));
215 
223 
224  gamestate_->ai_manager_.add_observer(this);
225  gamestate_->init(level, *this);
227 
228  LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl;
230  whiteboard_manager_.reset(new wb::manager());
232 
233  LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl;
236 
237  LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl;
239  const config& theme_cfg = controller_base::get_theme(game_config_, theme());
240 
241  LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl;
243  gui_.reset(new game_display(gamestate().board_, whiteboard_manager_, *gamestate().reports_, theme_cfg, level));
244  map_start_ = map_location(level.child_or_empty("display").child_or_empty("location"));
245  if (!gui_->video().faked()) {
247  gui_->get_theme().modify_label("time-icon", _ ("time left for current turn"));
248  else
249  gui_->get_theme().modify_label("time-icon", _ ("current local time"));
250  }
251 
253  mouse_handler_.set_gui(gui_.get());
254  menu_handler_.set_gui(gui_.get());
255 
256  LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl;
257 
258  LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl;
259  // This *needs* to be created before the show_intro and show_map_scene
260  // as that functions use the manager state_of_game
261  // Has to be done before registering any events!
264 
265  if(gamestate().first_human_team_ != -1) {
266  gui_->set_team(gamestate().first_human_team_);
267  }
268  else if(is_observer()) {
269  // Find first team that is allowed to be observed.
270  // If not set here observer would be without fog until
271  // the first turn of observable side
272  for (const team& t : gamestate().board_.teams())
273  {
274  if (!t.get_disallow_observers())
275  {
276  gui_->set_team(t.side() - 1);
277  }
278  }
279  }
280 
281  init_managers();
283  //loadscreen_manager->reset();
285  gamestate().lua_kernel_->load_game(level);
286 
287  plugins_context_.reset(new plugins_context("Game"));
288  plugins_context_->set_callback("save_game", [this](const config& cfg) { save_game_auto(cfg["filename"]); }, true);
289  plugins_context_->set_callback("save_replay", [this](const config& cfg) { save_replay_auto(cfg["filename"]); }, true);
290  plugins_context_->set_callback("quit", throw_end_level(), false);
291  plugins_context_->set_accessor_string("scenario_name", [this](config) { return get_scenario_name(); });
292  });
293  //Do this after the loadingscreen, so that ita happens in the main thread.
294  gui_->join();
295 }
296 
297 void play_controller::reset_gamestate(const config& level, int replay_pos)
298 {
299  resources::gameboard = nullptr;
300  resources::gamedata = nullptr;
301  resources::tod_manager = nullptr;
302  resources::filter_con = nullptr;
303  resources::lua_kernel = nullptr;
304  resources::game_events = nullptr;
305  resources::tunnels = nullptr;
306  resources::undo_stack = nullptr;
307 
308  gui_->labels().set_team(nullptr);
309 
310  /* First destroy the old game state, then create the new one.
311  This is necessary to ensure that while the old AI manager is being destroyed,
312  all its member objects access the old manager instead of the new. */
313  gamestate_.reset();
314  gamestate_.reset(new game_state(level, *this, tdata_));
322 
323  gamestate_->ai_manager_.add_observer(this);
324  gamestate_->init(level, *this);
327 
328  gui_->reset_reports(*gamestate().reports_);
329  gui_->change_display_context(&gamestate().board_);
330  saved_game_.get_replay().set_pos(replay_pos);
332  gamestate().lua_kernel_->load_game(level);
333 }
334 
336 {
337  LOG_NG << "initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
341 
343  LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks()) << std::endl;
344 }
345 
347 {
348  // Run initialization scripts, even if loading from a snapshot.
349  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
350  pump().fire("preload");
351 }
352 
354 {
355  // pre-start events must be executed before any GUI operation,
356  // as those may cause the display to be refreshed.
357  update_locker lock_display(gui_->video());
359 
360  // Fire these right before prestart events, to catch only the units sides
361  // have started with.
362  for (const unit& u : gamestate().board_.units()) {
363  pump().fire("unit_placed", map_location(u.get_location()));
364  }
365 
366  pump().fire("prestart");
367  // prestart event may modify start turn with WML, reflect any changes.
368  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
369 }
370 
372 {
373  const config cfg("side", gui_->viewing_side());
374  gamestate().lua_kernel_->run_wml_action("show_objectives", vconfig(cfg),
375  game_events::queued_event("_from_interface", "", map_location(), map_location(), config()));
376 }
377 
379 {
381  pump().fire("start");
382 
383  skip_story_ = false; // Show [message]s from now on even with --campaign-skip-story
384 
385  // start event may modify start turn with WML, reflect any changes.
386  gamestate().gamedata_.get_variable("turn_number") = static_cast<int>(turn());
387 
390  // prestart and start events may modify the initial gold amount,
391  // reflect any changes.
392  for (team& tm : gamestate().board_.teams_)
393  {
394  tm.set_start_gold(tm.gold());
395  }
396  gamestate_->init_side_done() = false;
398 }
399 
401 {
402  gui_->begin_game();
403  gui_->update_tod();
404 }
405 
407 {
409 
410  // If we are observers we move to watch next team if it is allowed
411  if ((is_observer() && !current_team().get_disallow_observers())
412  || (current_team().is_local_human() && !this->is_replay()))
413  {
415  }
416 
417  gui_->set_playing_team(std::size_t(current_side() - 1));
418 
420 }
421 
423 {
424  //
425  // We do side init only if not done yet for a local side when we are not replaying.
426  // For all other sides it is recorded in replay and replay handler has to handle
427  // calling do_init_side() functions.
428  //
429  if (gamestate_->init_side_done()) {
430  // We already executed do_init_side this can for example happe if we reload a game,
431  // but also if we changed control of a side during it's turn
432  return;
433  }
434  if (!current_team().is_local()) {
435  // We are in a mp game and execute do_init_side as soon as we receive [init_side] from the current player
436  // (see replay.cpp)
437  return;
438  }
439 
440  if (is_replay()) {
441  // We are in a replay and execute do_init_side as soon as we reach the next [init_side] in the replay data
442  // (see replay.cpp)
443  return;
444  }
445 
446  if (current_team().is_idle()) {
447  // In this case it can happen that we just gave control of this side to another player so doing init_side
448  // could lead to errors since we no longer own this side from the servers perspective.
449  // (see playturn.cpp)
450  return;
451  }
452 
454  do_init_side();
455 }
456 
458 {
459  set_scontext_synced sync;
460  log_scope("player turn");
461  // In case we might end up calling sync:network during the side turn events,
462  // and we don't want do_init_side to be called when a player drops.
463  gamestate_->init_side_done() = true;
464  init_side_done_now_ = true;
465 
466  const std::string turn_num = std::to_string(turn());
467  const std::string side_num = std::to_string(current_side());
468 
469  gamestate().gamedata_.get_variable("side_number") = current_side();
470 
471  // We might have skipped some sides because they were empty so it is not enough to check for side_num==1
472  if(!gamestate().tod_manager_.has_turn_event_fired())
473  {
474  pump().fire("turn_" + turn_num);
475  pump().fire("new_turn");
477  }
478 
479  pump().fire("side_turn");
480  pump().fire("side_" + side_num + "_turn");
481  pump().fire("side_turn_" + turn_num);
482  pump().fire("side_" + side_num + "_turn_" + turn_num);
483 
484  // We want to work out if units for this player should get healed,
485  // and the player should get income now.
486  // Healing/income happen if it's not the first turn of processing,
487  // or if we are loading a game.
488  if (turn() > 1) {
491 
492  // If the expense is less than the number of villages owned
493  // times the village support capacity,
494  // then we don't have to pay anything at all
495  int expense = gamestate().board_.side_upkeep(current_side()) -
496  current_team().support();
497  if(expense > 0) {
498  current_team().spend_gold(expense);
499  }
500  }
501  if (do_healing()) {
503  }
504  // Do healing on every side turn except the very first side turn.
505  // (1.14 and earlier did healing whenever turn >= 2.)
506  set_do_healing(true);
507  // Set resting now after the healing has been done.
508  for(unit &patient : resources::gameboard->units()) {
509  if(patient.side() == current_side()) {
510  patient.set_resting(true);
511  }
512  }
513 
514  // Prepare the undo stack.
516 
517  pump().fire("turn_refresh");
518  pump().fire("side_" + side_num + "_turn_refresh");
519  pump().fire("turn_" + turn_num + "_refresh");
520  pump().fire("side_" + side_num + "_turn_" + turn_num + "_refresh");
521 
522  // Make sure vision is accurate.
524  init_side_end();
525  check_victory();
526  sync.do_final_checkup();
527 }
528 
530 {
532 
533  if (current_side() == 1 || !init_side_done_now_)
535 
536  if (!is_skipping_replay()){
537  gui_->invalidate_all();
538  }
539 
540  if (!is_skipping_replay() && current_team().get_scroll_to_leader() && !map_start_.valid()){
541  gui_->scroll_to_leader(current_side(), game_display::ONSCREEN,false);
542  }
544  whiteboard_manager_->on_init_side();
545 }
546 
548 {
549  config cfg = level_;
550 
551  cfg["replay_pos"] = saved_game_.get_replay().get_pos();
552  gamestate().write(cfg);
553 
554  gui_->write(cfg.add_child("display"));
555 
556  //Write the soundsources.
557  soundsources_manager_->write_sourcespecs(cfg);
558 
559  gui_->labels().write(cfg);
561 
562  return cfg;
563 }
564 
566 {
567  whiteboard_manager_->on_finish_side_turn(current_side());
568 
569  { //Block for set_scontext_synced
570  set_scontext_synced sync(1);
571  // Ending the turn commits all moves.
572  undo_stack().clear();
574  const std::string turn_num = std::to_string(turn());
575  const std::string side_num = std::to_string(current_side());
576 
577  // Clear shroud, in case units had been slowed for the turn.
579 
580  pump().fire("side_turn_end");
581  pump().fire("side_"+ side_num + "_turn_end");
582  pump().fire("side_turn_" + turn_num + "_end");
583  pump().fire("side_" + side_num + "_turn_" + turn_num + "_end");
584  // This is where we refog, after all of a side's events are done.
586  check_victory();
587  sync.do_final_checkup();
588  }
589 
591  gamestate_->init_side_done() = false;
592 }
593 
595 {
596  set_scontext_synced sync(2);
597  const std::string turn_num = std::to_string(turn());
598  pump().fire("turn_end");
599  pump().fire("turn_" + turn_num + "_end");
600  sync.do_final_checkup();
601 }
602 
604 {
605  // If we aren't using fog/shroud, this is easy :)
606  if(current_team().uses_fog() == false && current_team().uses_shroud() == false)
607  return true;
608 
609  // See if any enemies are visible
610  for (const unit& u : gamestate().board_.units()) {
611  if (current_team().is_enemy(u.side()) && !gui_->fogged(u.get_location())) {
612  return true;
613  }
614  }
615 
616  return false;
617 }
618 
620 {
621  if(menu_handler_.get_textbox().active() == false) {
622  return;
623  }
624 
625  const std::string str = menu_handler_.get_textbox().box()->text();
626  const unsigned int team_num = current_side();
627  events::mouse_handler& mousehandler = mouse_handler_;
628 
629  switch(menu_handler_.get_textbox().mode()) {
630  case gui::TEXTBOX_SEARCH:
633  break;
636  menu_handler_.get_textbox().close(*gui_); //need to close that one after executing do_speak() !
637  break;
641  break;
642  case gui::TEXTBOX_AI:
644  menu_handler_.do_ai_formula(str, team_num, mousehandler);
645  break;
646  default:
648  ERR_DP << "unknown textbox mode" << std::endl;
649  }
650 }
651 
653 {
655 
656  std::set<std::string> dictionary;
657  switch(mode) {
658  case gui::TEXTBOX_SEARCH:
659  {
660  for (const unit& u : gamestate().board_.units()){
661  const map_location& loc = u.get_location();
662  if(!gui_->fogged(loc) &&
663  !(gamestate().board_.teams()[gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
664  dictionary.insert(u.name());
665  }
666  //TODO List map labels
667  break;
668  }
670  {
671  std::vector<std::string> commands = menu_handler_.get_commands_list();
672  dictionary.insert(commands.begin(), commands.end());
673  FALLTHROUGH; // we also want player names from the next case
674  }
676  {
677  for (const team& t : gamestate().board_.teams()) {
678  if(!t.is_empty())
679  dictionary.insert(t.current_player());
680  }
681 
682  // Add observers
683  for (const std::string& o : gui_->observers()){
684  dictionary.insert(o);
685  }
686 
687  // Add nicks who whispered you
688  for (const std::string& w : gui_->get_chat_manager().whisperers()){
689  dictionary.insert(w);
690  }
691 
692  // Add nicks from friendlist
693  const std::map<std::string, std::string> friends = preferences::get_acquaintances_nice("friend");
694 
695  for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter){
696  dictionary.insert((*iter).first);
697  }
698 
699  //Exclude own nick from tab-completion.
700  //NOTE why ?
701  dictionary.erase(preferences::login());
702  break;
703  }
704 
705  default:
706  ERR_DP << "unknown textbox mode" << std::endl;
707  } //switch(mode)
708 
709  menu_handler_.get_textbox().tab(dictionary);
710 }
711 
713 {
714  assert(gamestate().board_.has_team(current_side()));
716 }
717 
719 {
720  assert(gamestate().board_.has_team(current_side()));
722 }
723 
724 /// @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
725 static int modulo(int num, int mod, int min)
726 {
727  assert(mod > 0);
728  int n = (num - min) % mod;
729  if (n < 0)
730  n += mod;
731  //n is now in [0, mod)
732  n = n + min;
733  return n;
734  // the following properties are easy to verify:
735  // 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
736  // 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
737 }
738 
739 bool play_controller::is_team_visible(int team_num, bool observer) const
740 {
741  const team& t = gamestate().board_.get_team(team_num);
742  if(observer) {
743  return !t.get_disallow_observers() && !t.is_empty();
744  }
745  else {
746  return t.is_local_human() && !t.is_idle();
747  }
748 }
749 
751 {
752  assert(current_side() <= static_cast<int>(gamestate().board_.teams().size()));
753  const int num_teams = gamestate().board_.teams().size();
754  const bool is_observer = this->is_observer();
755 
756  for(int i = 0; i < num_teams; i++) {
757  const int team_num = modulo(current_side() - i, num_teams, 1);
758  if(is_team_visible(team_num, is_observer)) {
759  return team_num;
760  }
761  }
762  return 0;
763 }
764 
766 {
767  return mouse_handler_;
768 }
769 
770 std::shared_ptr<wb::manager> play_controller::get_whiteboard() const
771 {
772  return whiteboard_manager_;
773 }
774 
776 {
777  return saved_game_.mp_settings();
778 }
779 
781 {
782  return saved_game_.classification();
783 }
784 
786 {
787  return *gui_;
788 }
789 
791 {
792  return !menu_handler_.get_textbox().active();
793 }
794 
796 {
797  if(event.key.keysym.sym == SDLK_ESCAPE) {
799  } else if(event.key.keysym.sym == SDLK_TAB) {
800  tab();
801  } else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
802  enter_textbox();
803  }
804 }
805 
806 void play_controller::process_keydown_event(const SDL_Event& event)
807 {
808  if (event.key.keysym.sym == SDLK_TAB) {
809  whiteboard_manager_->set_invert_behavior(true);
810  }
811 }
812 
813 void play_controller::process_keyup_event(const SDL_Event& event)
814 {
815  // If the user has pressed 1 through 9, we want to show
816  // how far the unit can move in that many turns
817  if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9') {
818  const int new_path_turns = (event.type == SDL_KEYDOWN) ?
819  event.key.keysym.sym - '1' : 0;
820 
821  if(new_path_turns != mouse_handler_.get_path_turns()) {
822  mouse_handler_.set_path_turns(new_path_turns);
823 
825 
826  if(u.valid()) {
827  // if it's not the unit's turn, we reset its moves
828  unit_movement_resetter move_reset(*u, u->side() != current_side());
829 
831  true, gamestate().board_.teams_[gui_->viewing_team()],
833 
834  gui_->highlight_reach(mouse_handler_.current_paths());
835  } else {
837  }
838 
839  }
840  } else if (event.key.keysym.sym == SDLK_TAB) {
841  CKey keys;
842  if (!keys[SDLK_TAB]) {
843  whiteboard_manager_->set_invert_behavior(false);
844  }
845  }
846 }
847 
849  assert(replay_);
850  return *replay_.get();
851 }
852 
854 {
856  // Saving while an event is running isn't supported
857  // because it may lead to expired event handlers being saved.
858  assert(!gamestate().events_manager_->is_event_running());
859 
861  scoped_savegame_snapshot snapshot(*this);
864  } else {
866  }
867 }
868 
869 void play_controller::save_game_auto(const std::string& filename)
870 {
873 
874  scoped_savegame_snapshot snapshot(*this);
876  save.save_game_automatic(false, filename);
877  }
878 }
879 
881 {
886  } else {
888  }
889 }
890 
891 void play_controller::save_replay_auto(const std::string& filename)
892 {
896  save.save_game_automatic(false, filename);
897  }
898 }
899 
901 {
905  } else {
907  }
908 }
909 
911 {
913  load.load_game_ingame();
914 }
915 
917 {
919  undo_stack().undo();
920 }
921 
923 {
925  undo_stack().redo();
926 }
927 
929 {
931 }
932 
934 {
936 }
937 
938 const std::string& play_controller::select_music(bool victory) const
939 {
940  const std::vector<std::string>& music_list = victory
941  ? (gamestate_->get_game_data()->get_victory_music().empty() ? game_config::default_victory_music : gamestate_->get_game_data()->get_victory_music())
942  : (gamestate_->get_game_data()->get_defeat_music().empty() ? game_config::default_defeat_music : gamestate_->get_game_data()->get_defeat_music());
943 
944  if(music_list.empty()) {
945  // Since this function returns a reference, we can't return a temporary empty string.
946  static const std::string empty_str = "";
947  return empty_str;
948  }
949 
950  return music_list[randomness::rng::default_instance().get_random_int(0, music_list.size()-1)];
951 }
952 
954 {
955  if(linger_)
956  {
957  return;
958  }
959 
960  if (is_regular_game_end()) {
961  return;
962  }
963  bool continue_level, found_player, found_network_player, invalidate_all;
964  std::set<unsigned> not_defeated;
965 
966  gamestate().board_.check_victory(continue_level, found_player, found_network_player, invalidate_all, not_defeated, remove_from_carryover_on_defeat_);
967 
968  if (invalidate_all) {
969  gui_->invalidate_all();
970  }
971 
972  if (continue_level) {
973  return ;
974  }
975 
976  if (found_player || found_network_player) {
977  pump().fire("enemies_defeated");
978  if (is_regular_game_end()) {
979  return;
980  }
981  }
982 
983  DBG_EE << "victory_when_enemies_defeated: " << victory_when_enemies_defeated_ << std::endl;
984  DBG_EE << "found_player: " << found_player << std::endl;
985  DBG_EE << "found_network_player: " << found_network_player << std::endl;
986 
987  if (!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
988  // This level has asked not to be ended by this condition.
989  return;
990  }
991 
992  if (gui_->video().non_interactive()) {
993  LOG_AIT << "winner: ";
994  for (unsigned l : not_defeated) {
996  if (ai.empty()) ai = "default ai";
997  LOG_AIT << l << " (using " << ai << ") ";
998  }
999  LOG_AIT << std::endl;
1000  ai_testing::log_victory(not_defeated);
1001  }
1002 
1003  DBG_EE << "throwing end level exception..." << std::endl;
1004  //Also proceed to the next scenario when another player survived.
1005  end_level_data el_data;
1006  el_data.proceed_to_next_level = found_player || found_network_player;
1007  el_data.is_victory = found_player;
1008  set_end_level_data(el_data);
1009 }
1010 
1011 void play_controller::process_oos(const std::string& msg) const
1012 {
1013  if (gui_->video().non_interactive()) {
1014  throw game::game_error(msg);
1015  }
1017 
1018  std::stringstream message;
1019  message << _("The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1020  message << "\n\n" << _("Error details:") << "\n\n" << msg;
1021 
1022  scoped_savegame_snapshot snapshot(*this);
1024  save.save_game_interactive(message.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
1025 }
1026 
1027 void play_controller::update_gui_to_player(const int team_index, const bool observe)
1028 {
1029  gui_->set_team(team_index, observe);
1030  gui_->recalculate_minimap();
1031  gui_->invalidate_all();
1032 }
1033 
1035 {
1036  scoped_savegame_snapshot snapshot(*this);
1039 }
1040 
1041 void play_controller::do_consolesave(const std::string& filename)
1042 {
1043  scoped_savegame_snapshot snapshot(*this);
1045  save.save_game_automatic(true, filename);
1046 }
1047 
1049 {
1050  //note: this writes to level_ if this is not a replay.
1052 }
1053 
1055 {
1056  return gamestate().events_manager_->pump();
1057 }
1058 
1060 {
1061  return ticks_;
1062 }
1063 
1065 {
1066  return soundsources_manager_.get();
1067 }
1068 
1070 {
1071  return plugins_context_.get();
1072 }
1073 
1075 {
1076  return hotkey_handler_.get();
1077 }
1078 
1080 {
1081  if(linger_ || !gamestate_->init_side_done() || gamestate().gamedata_.phase() != game_data::PLAY) {
1082  return true;
1083  }
1084  const team& t = current_team();
1085  return !t.is_local_human() || !t.is_proxy_human();
1086 }
1087 
1089 {
1091  return;
1092  }
1093  try
1094  {
1095  play_slice();
1096  }
1097  catch(const return_to_play_side_exception&)
1098  {
1099  assert(should_return_to_play_side());
1100  }
1101 }
1102 
1104 {
1105  fire_preload();
1106 
1107  if(!gamestate().start_event_fired_)
1108  {
1109  gamestate().start_event_fired_ = true;
1113 
1114  set_scontext_synced sync;
1115 
1116  fire_prestart();
1117  if (is_regular_game_end()) {
1118  return;
1119  }
1120 
1121  for (const team& t : gamestate().board_.teams()) {
1122  actions::clear_shroud(t.side(), false, false);
1123  }
1124 
1125  init_gui();
1126  LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";
1127 
1128  fire_start();
1129  if (is_regular_game_end()) {
1130  return;
1131  }
1132  sync.do_final_checkup();
1133  gui_->recalculate_minimap();
1134  // Initialize countdown clock.
1135  for (const team& t : gamestate().board_.teams())
1136  {
1138  t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
1139  }
1140  }
1141  }
1142  else
1143  {
1144  init_gui();
1146  gui_->recalculate_minimap();
1147  }
1148 }
1149 
1151 {
1152  const team& viewing_team = get_teams_const()[gui_->viewing_team()];
1153  return gui_->viewing_team() == gui_->playing_team() && !events::commands_disabled && viewing_team.is_local_human() && !is_lingering() && !is_browsing();
1154 }
1155 
1156 std::set<std::string> play_controller::all_players() const
1157 {
1158  std::set<std::string> res = gui_->observers();
1159  for (const team& t : get_teams_const())
1160  {
1161  if (t.is_human()) {
1162  res.insert(t.current_player());
1163  }
1164  }
1165  return res;
1166 }
1167 
1169 {
1170  //check for team-specific items in the scenario
1171  gui_->parse_team_overlays();
1172  do {
1174  {
1175  save_blocker blocker;
1177  if(is_regular_game_end()) {
1178  return;
1179  }
1180  }
1181  // This flag can be set by derived classes (in overridden functions).
1182  player_type_changed_ = false;
1183 
1184  statistics::reset_turn_stats(gamestate().board_.get_team(current_side()).save_id_or_number());
1185 
1186  play_side_impl();
1187 
1188  if(is_regular_game_end()) {
1189  return;
1190  }
1191 
1192  } while (player_type_changed_);
1193  // Keep looping if the type of a team (human/ai/networked)
1194  // has changed mid-turn
1195  sync_end_turn();
1196 }
1197 
1199 {
1200  whiteboard_manager_->on_gamestate_change();
1201  gui_->new_turn();
1202  gui_->invalidate_game_status();
1203 
1204  LOG_NG << "turn: " << turn() << "\n";
1205 
1206  if(gui_->video().non_interactive()) {
1207  LOG_AIT << "Turn " << turn() << ":" << std::endl;
1208  }
1209 
1210  int last_player_number = gamestate_->player_number_;
1211  int next_player_number = gamestate_->next_player_number_;
1212 
1213  while(gamestate_->player_number_ <= static_cast<int>(gamestate().board_.teams().size())) {
1214  gamestate_->next_player_number_ = gamestate_->player_number_ + 1;
1215  next_player_number = gamestate_->next_player_number_;
1216  last_player_number = gamestate_->player_number_;
1217 
1218  // If a side is empty skip over it.
1219  if (!current_team().is_empty()) {
1220  init_side_begin();
1221  if(gamestate_->init_side_done()) {
1222  // This is the case in a reloaded game where the side was initialized before saving the game.
1223  init_side_end();
1224  }
1225 
1227  play_side();
1228  //ignore any changes to next_player_number_ that happen after the [end_turn] is sended to the server, otherwise we will get OOS.
1229  next_player_number = gamestate_->next_player_number_;
1230  assert(next_player_number <= 2 * static_cast<int>(gamestate().board_.teams().size()));
1231  if(is_regular_game_end()) {
1232  return;
1233  }
1234  //note: play_side() send the [end_turn] to the sever and finish_side_turn() callsie the side turn end events.
1235  // this means that during the side turn end events the clients think it is still the last sides turn while
1236  // the server thinks that it is already the next plyers turn. i don'T think this is a problem though.
1237  finish_side_turn();
1238  if(is_regular_game_end()) {
1239  return;
1240  }
1241  if(gui_->video().non_interactive()) {
1242  LOG_AIT << " Player " << current_side() << ": " <<
1243  current_team().villages().size() << " Villages" <<
1244  std::endl;
1246  }
1247  }
1248 
1249  gamestate_->player_number_ = next_player_number;
1250  }
1251  // If the loop exits due to the last team having been processed.
1252  gamestate_->player_number_ = last_player_number;
1253 
1254  finish_turn();
1255 
1256  // Time has run out
1257  check_time_over();
1258 
1259  if (!is_regular_game_end()) {
1260  gamestate_->player_number_ = modulo(next_player_number, gamestate().board_.teams().size(), 1);
1261  }
1262 }
1263 
1265 {
1266  const bool time_left = gamestate().tod_manager_.next_turn(&gamestate().gamedata_);
1267 
1268  if(!time_left) {
1269  LOG_NG << "firing time over event...\n";
1271  pump().fire("time_over");
1272  LOG_NG << "done firing time over event...\n";
1273  // If turns are added while handling 'time over' event.
1274  if (gamestate().tod_manager_.is_time_left()) {
1275  return;
1276  }
1277 
1278  if(gui_->video().non_interactive()) {
1279  LOG_AIT << "time over (draw)\n";
1281  }
1282 
1283  check_victory();
1284  if (is_regular_game_end()) {
1285  return;
1286  }
1287  end_level_data e;
1288  e.proceed_to_next_level = false;
1289  e.is_victory = false;
1290  set_end_level_data(e);
1291  }
1292 }
1293 
1295  : controller_(controller)
1296 {
1298 }
1299 
1301 {
1303 }
1304 
1306 {
1307  const team& t = gamestate().board_.teams()[gui_->viewing_team()];
1308  static const std::string no_objectives(_("No objectives available"));
1309  std::string objectives = utils::interpolate_variables_into_string(t.objectives(), *gamestate_->get_game_data());
1310  gui2::show_transient_message(get_scenario_name(), (objectives.empty() ? no_objectives : objectives), "", true);
1312 }
1313 
1315 {
1317  const std::shared_ptr<gui::button> skip_animation_button = get_display().find_action_button("skip-animation");
1318  if (skip_animation_button) {
1319  skip_animation_button->set_check(skip_replay_);
1320  }
1321 }
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:803
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:258
hotkey::command_executor * get_hotkey_command_executor() override
Optionally get a command executor to handle context menu events.
void reset_objectives_changed() const
Definition: team.hpp:238
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with &#39;$&#39; in the string &#39;str&#39; with the equivalent ...
map_location last_selected
the last location where a select event fired.
Definition: game_data.hpp:89
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
The class for loading a savefile.
Definition: savegame.hpp:96
std::unique_ptr< game_lua_kernel > lua_kernel_
Definition: game_state.hpp:50
void refresh_objectives() const
Reevaluate [show_if] conditions and build a new objectives string.
void save_replay_auto(const std::string &filename)
int find_last_visible_team() const
returns 0 if no such team was found.
const ter_data_cache & tdata_
This class represents a single unit of a specific type.
Definition: unit.hpp:99
std::unique_ptr< game_display > gui_
bool victory_when_enemies_defeated_
While any instance of this class exists, attempts to save the game via any call to play_controller wi...
game_classification * classification
Definition: resources.cpp:34
Various functions implementing vision (through fog of war and shroud).
const mp_game_settings & get_mp_settings()
void do_final_checkup(bool dont_throw=false)
events::mouse_handler mouse_handler_
static manager & get_singleton()
Definition: manager.hpp:150
static void copy_persistent(const config &src, config &dst)
Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
std::unique_ptr< plugins_context > plugins_context_
bool is_skipping_replay() const
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
Definition: tips.cpp:35
std::unique_ptr< replay > replay_
game_display & get_display() override
Get a reference to a display member a derived class uses.
replay_recorder_base & get_replay()
Definition: saved_game.hpp:121
Class for autosaves.
Definition: savegame.hpp:266
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:190
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:284
const pathfind::paths & current_paths() const
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup, const bool restore_background)
Shows a transient message to the user.
void do_command(const std::string &str)
void set_do_healing(bool do_healing)
static void progress(loading_stage stage=loading_stage::none)
virtual void update_viewing_player()=0
gui::floating_textbox & get_textbox()
void new_turn()
Definition: team.hpp:204
void set_gui(game_display *gui)
Definition: menu_events.hpp:52
virtual soundsource::manager * get_soundsource_man() override
Get (optionally) a soundsources manager a derived class uses.
void undo()
Undoes the top action on the undo stack.
Definition: undo.cpp:348
static lg::log_domain log_aitesting("aitesting")
Gather statistics important for AI testing and output them.
unit_type_data unit_types
Definition: types.cpp:1525
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:239
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:1458
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:519
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:241
static void log_draw()
Definition: testing.cpp:75
bool save_game_interactive(const std::string &message, DIALOG_TYPE dialog_type)
Save a game interactively through the savegame dialog.
Definition: savegame.cpp:353
static lg::log_domain log_display("display")
void write_music_play_list(config &snapshot)
Definition: sound.cpp: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:214
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
static int modulo(int num, int mod, int min)
team & get_team(int i)
Definition: game_board.hpp:104
void throw_quit_game_exception()
void save_game_auto(const std::string &filename)
bool add_start_if_not_there_yet()
Definition: replay.cpp:656
void set_path_turns(const int path_turns)
virtual void check_time_over()
bool can_redo() const
True if there are actions that can be redone.
Definition: undo.hpp:95
Implements a quit confirmation dialog.
config to_config() const
Builds the snapshot config from members and their respective configs.
filter_context * filter_con
Definition: resources.cpp:23
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Definition: tod_manager.hpp:54
bool valid() const
Definition: location.hpp:93
bool ignore_replay_errors
int side_upkeep(int side_num) const
TEXTBOX_MODE mode() const
game_board * gameboard
Definition: resources.cpp:20
This class is the frontend of the whiteboard framework for the rest of the Wesnoth code...
Definition: manager.hpp:42
bool is_regular_game_end() const
void init(const config &level)
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:705
virtual void init_gui()
void maybe_do_init_side()
Called by turn_info::process_network_data() or init_side() to call do_init_side() if necessary...
bool is_enemy(int n) const
Definition: team.hpp:243
tod_manager tod_manager_
Definition: game_state.hpp:47
Object which temporarily resets a unit&#39;s movement.
Definition: unit.hpp:1858
bool load_game_ingame()
Load a game without providing any information.
Definition: savegame.cpp:119
std::unique_ptr< pathfind::manager > pathfind_manager_
Definition: game_state.hpp:48
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
std::string theme() const
replay * recorder
Definition: resources.cpp:28
void check_victory(bool &, bool &, bool &, bool &, std::set< unsigned > &, bool)
Definition: game_board.cpp:96
void set_gui(game_display *gui)
void spend_gold(const int amount)
Definition: team.hpp:208
std::shared_ptr< wb::manager > get_whiteboard() const
An object which will lock the display for the duration of its lifetime.
Definition: video.hpp:279
Error used for any general game error, e.g.
Definition: game_errors.hpp:46
game_events::manager * game_events
Definition: resources.cpp:24
bool is_browsing() const override
void deactivate_all_scopes()
bool is_observer() const
void update_gui_to_player(const int team_index, const bool observe=false)
Changes the UI for this client to the passed side index.
void do_init_side()
Called by replay handler or init_side() to do actual work for turn change.
Encapsulates the map of the game.
Definition: location.hpp:42
void calculate_healing(int side, bool update_display)
Calculates healing for all units for the given side.
Definition: heal.cpp:292
std::string login()
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:33
virtual ~play_controller()
bool is_proxy_human() const
Definition: team.hpp:282
Various functions related to the creation of units (recruits, recalls, and placed units)...
int support() const
Calculate total support capacity, based on support_per_village.
Definition: team.hpp:203
void set_end_level_data(const end_level_data &data)
void end_turn(int pnum)
Definition: game_board.cpp:72
int get_path_turns() const
std::size_t i
Definition: function.cpp:933
soundsource::manager * soundsources
Definition: resources.cpp:27
const std::string & select_music(bool victory) const
void redo()
Redoes the top action on the redo stack.
Definition: undo.cpp:404
map_location map_start_
unit_map::iterator selected_unit()
std::string get_active_ai_identifier_for_side(side_number side)
Gets AI algorithm identifier for active AI of the given side.
Definition: manager.cpp:685
const config & game_config_
void reset_gamestate(const config &level, int replay_pos)
const t_string & objectives() const
Definition: team.hpp:240
std::shared_ptr< wb::manager > whiteboard_manager_
bool is_team_visible(int team_num, bool observer) const
Define the game&#39;s event mechanism.
void encounter_all_content(const game_board &gameboard_)
Definition: game.cpp: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:248
static void save(LexState *ls, int c)
Definition: llex.cpp:57
bool can_redo() const
static lg::log_domain log_enginerefac("enginerefac")
std::string observer
bool is_local() const
Definition: team.hpp:260
Class for replay saves (either manually or automatically).
Definition: savegame.hpp:253
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:338
static void display(std::function< void()> f)
void set_game_display(game_display *)
Definition: game_state.cpp:234
bool is_local_human() const
Definition: team.hpp:266
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
const std::unique_ptr< gui::textbox > & box() const
game_state & gamestate()
double t
Definition: astarsearch.cpp:64
Various functions that implement healing of units (when a side turn starts).
game_classification & classification()
Definition: saved_game.hpp:55
game_board board_
Definition: game_state.hpp:46
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Various functions that implement the undoing (and redoing) of in-game commands.
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
Definition: savegame.cpp:568
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:1492
static const map_location & null_location()
Definition: location.hpp:85
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
config * get_next_action()
Definition: replay.cpp:613
std::set< std::string > all_players() const
void fire_preload()
preload events cannot be synced
virtual plugins_context * get_plugins_context() override
Get (optionally) a plugins context a derived class uses.
void new_turn(int pnum)
Definition: game_board.cpp:64
#define e
actions::undo_list * undo_stack
Definition: resources.cpp:32
std::size_t turn() const
void update_savegame_snapshot() const
void remove_snapshot()
Definition: saved_game.cpp:537
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:453
const std::vector< team > & get_teams_const() const
void set_side(int side_number)
bool next_turn(game_data *vars)
Function to move to the next turn.
PHASE phase() const
Definition: game_data.hpp:76
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
game_classification & get_classification()
bool valid() const
Definition: map.hpp:276
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:27
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:59
void delete_all_wml_hotkeys()
deletes all wml hotkeys, should be called after a game has ended
std::vector< std::string > get_commands_list()
void write(config &cfg) const
Definition: game_state.cpp:239
static map_location::DIRECTION n
const std::set< map_location > & villages() const
Definition: team.hpp:184
void close(game_display &gui)
pathfind::manager * tunnels
Definition: resources.cpp:31
bool can_undo() const
True if there are actions that can be undone.
Definition: undo.hpp:93
static rng & default_instance()
Definition: random.cpp:73
virtual void check_objectives()=0
bool save_game_automatic(bool ask_for_overwrite=false, const std::string &filename="")
Saves a game without user interaction, unless the file exists and it should be asked to overwrite it...
Definition: savegame.cpp:337
virtual void play_side_impl()
bool start_event_fired_
Definition: game_state.hpp:64
void show_objectives() const
bool init_side_done_now_
Whether we did init sides in this session (false = we did init sides before we reloaded the game)...
bool remove_from_carryover_on_defeat_
play_controller(const config &level, saved_game &state_of_game, const ter_data_cache &tdata, bool skip_replay)
void do_ai_formula(const std::string &str, int side_num, mouse_handler &mousehandler)
#define LOG_NG
std::shared_ptr< terrain_type_data > ter_data_cache
virtual void sync_end_turn()