The Battle for Wesnoth  1.17.0-dev
playsingle_controller.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2021
3  by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
4  Copyright (C) 2003 by David White <dave@whitevine.net>
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 /**
18  * @file
19  * Logic for single-player game.
20  */
21 
23 
24 #include "actions/undo.hpp"
25 #include "ai/manager.hpp"
26 #include "ai/testing.hpp"
27 #include "display_chat_manager.hpp"
28 #include "events.hpp"
29 #include "formula/string_utils.hpp"
30 #include "game_end_exceptions.hpp"
31 #include "game_events/pump.hpp"
32 #include "gettext.hpp"
36 #include "hotkey/hotkey_item.hpp"
37 #include "log.hpp"
38 #include "map/label.hpp"
39 #include "map/map.hpp"
40 #include "playturn.hpp"
41 #include "preferences/game.hpp"
42 #include "random_deterministic.hpp"
43 #include "replay_helper.hpp"
44 #include "resources.hpp"
45 #include "savegame.hpp"
47 #include "sound.hpp"
48 #include "soundsource.hpp"
49 #include "statistics.hpp"
50 #include "synced_context.hpp"
51 #include "units/unit.hpp"
53 #include "whiteboard/manager.hpp"
54 
55 #include <boost/dynamic_bitset.hpp>
56 
57 static lg::log_domain log_aitesting("ai/testing");
58 #define LOG_AIT LOG_STREAM(info, log_aitesting)
59 // If necessary, this define can be replaced with `#define LOG_AIT std::cout` to restore previous behavior
60 
61 static lg::log_domain log_engine("engine");
62 #define ERR_NG LOG_STREAM(err, log_engine)
63 #define LOG_NG LOG_STREAM(info, log_engine)
64 
65 static lg::log_domain log_enginerefac("enginerefac");
66 #define LOG_RG LOG_STREAM(info, log_enginerefac)
67 
68 playsingle_controller::playsingle_controller(const config& level, saved_game& state_of_game, bool skip_replay)
69  : play_controller(level, state_of_game, skip_replay)
70  , cursor_setter_(cursor::NORMAL)
71  , textbox_info_()
72  , replay_sender_(*resources::recorder)
73  , network_reader_([this](config& cfg) { return receive_from_wesnothd(cfg); })
76  , skip_next_turn_(false)
77  , ai_fallback_(false)
79 {
80  // upgrade hotkey handler to the sp (whiteboard enabled) version
81  hotkey_handler_ = std::make_unique<hotkey_handler>(*this, saved_game_);
82 
83  // game may need to start in linger mode
85 
86  plugins_context_->set_accessor_string("level_result", std::bind(&playsingle_controller::describe_result, this));
87  plugins_context_->set_accessor_int("turn", std::bind(&play_controller::turn, this));
88 }
89 
91 {
92  if(!is_regular_game_end()) {
93  return "NONE";
94  } else if(get_end_level_data().is_victory) {
95  return "VICTORY";
96  } else {
97  return "DEFEAT";
98  }
99 }
100 
102 {
103  LOG_NG << "Initializing GUI... " << (SDL_GetTicks() - ticks()) << "\n";
105 
106  // Scroll to the starting position of the first team. If there is a
107  // human team, use that team; otherwise use team 1. If the map defines
108  // a starting position for the selected team, scroll to that tile. Note
109  // this often does not matter since many scenario start with messages,
110  // which will usually scroll to the speaker. Also note that the map
111  // does not necessarily define the starting positions. While usually
112  // best to use the map, the scenarion may explicitly set the positions,
113  // overriding those found in the map (if any).
114  if(map_start_.valid()) {
115  gui_->scroll_to_tile(map_start_, game_display::WARP, false);
116  LOG_NG << "Found good stored ui location " << map_start_ << "\n";
117  } else {
118  int scroll_team = gamestate().first_human_team_ + 1;
119  if(scroll_team == 0) {
120  scroll_team = 1;
121  }
122 
123  map_location loc(get_map().starting_position(scroll_team));
124  if((loc.x >= 0) && (loc.y >= 0)) {
125  gui_->scroll_to_tile(loc, game_display::WARP);
126  LOG_NG << "Found bad stored ui location " << map_start_ << " using side starting location " << loc << "\n";
127  } else {
128  LOG_NG << "Found bad stored ui location\n";
129  }
130  }
131 
132  update_locker lock_display(gui_->video(), is_skipping_replay());
134 }
135 
137 {
138  // At the beginning of the scenario, save a snapshot as replay_start
139  if(saved_game_.replay_start().empty()) {
141  }
142 
143  start_game();
144 
146  // This won't cause errors later but we should notify the user about it in case he didn't knew it.
148  // TODO: find a better title
149  _("Game Error"),
150  _("This multiplayer game uses an alternative random mode, if you don't know what this message means, then "
151  "most likely someone is cheating or someone reloaded a corrupt game."));
152  }
153 
154  return;
155 }
156 
158 {
159  LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks()) << "\n";
160 
162  if(get_teams().empty()) {
163  ERR_NG << "Playing game with 0 teams." << std::endl;
164  }
165 
166  while(true) {
167  try {
168  play_turn();
169  if(is_regular_game_end()) {
171  return;
172  }
173  } catch(const reset_gamestate_exception& ex) {
174  //
175  // TODO:
176  //
177  // The MP replay feature still doesn't work properly (causes OOS)
178  // because:
179  //
180  // 1) The undo stack is not reset along with the gamestate (fixed).
181  // 2) The server_request_number_ is not reset along with the
182  // gamestate (fixed).
183  // 3) chat and other unsynced actions are inserted in the middle of
184  // the replay bringing the replay_pos in unorder (fixed).
185  // 4) untracked changes in side controllers are lost when resetting
186  // gamestate (fixed).
187  // 5) The game should have a stricter check for whether the loaded
188  // game is actually a parent of this game.
189  // 6) If an action was undone after a game was saved it can cause
190  // OOS if the undone action is in the snapshot of the saved
191  // game (luckily this is never the case for autosaves).
192  //
193  boost::dynamic_bitset<> local_players;
194  local_players.resize(get_teams().size(), true);
195  // Preserve side controllers, because we won't get the side controoller updates again when replaying.
196  for(std::size_t i = 0; i < local_players.size(); ++i) {
197  local_players[i] = get_teams()[i].is_local();
198  }
199 
200  if(ex.start_replay) {
201  // MP "Back to turn"
203  } else {
204  // SP replay
206  }
207 
208  reset_gamestate(*ex.level, (*ex.level)["replay_pos"]);
209 
210  for(std::size_t i = 0; i < local_players.size(); ++i) {
211  resources::gameboard->teams()[i].set_local(local_players[i]);
212  }
213 
215 
216  if(replay_controller_ == nullptr) {
217  replay_controller_ = std::make_unique<replay_controller>(*this, false, ex.level, [this]() { on_replay_end(false); });
218  }
219 
220  if(ex.start_replay) {
221  replay_controller_->play_replay();
222  }
223  }
224  } // end for loop
225 }
226 
228 {
229  LOG_NG << "in playsingle_controller::play_scenario()...\n";
230 
231  // Start music.
232  for(const config& m : level.child_range("music")) {
233  sound::play_music_config(m, true);
234  }
235 
237 
239  // Combine all the [story] tags into a single config. Handle this here since
240  // storyscreen::controller doesn't have a default constructor.
241  config cfg;
242  for(const auto& iter : level.child_range("story")) {
243  cfg.append_children(iter);
244  }
245 
246  if(!cfg.empty()) {
248  }
249  }
250 
251  gui_->labels().read(level);
252 
253  // Read sound sources
254  assert(soundsources_manager_ != nullptr);
255  for(const config& s : level.child_range("sound_source")) {
256  try {
258  soundsources_manager_->add(spec);
259  } catch(const bad_lexical_cast&) {
260  ERR_NG << "Error when parsing sound_source config: bad lexical cast." << std::endl;
261  ERR_NG << "sound_source config was: " << s.debug() << std::endl;
262  ERR_NG << "Skipping this sound source..." << std::endl;
263  }
264  }
265 
266  LOG_NG << "entering try... " << (SDL_GetTicks() - ticks()) << "\n";
267 
268  try {
270  // clears level config;
272 
273  if(!is_regular_game_end() && !linger_) {
275  }
276 
278  exit(0);
279  }
280  const bool is_victory = get_end_level_data().is_victory;
281 
282  if(gamestate().gamedata_.phase() <= game_data::PRESTART) {
283  gui_->video().clear_screen();
284  }
285 
287 
288  const end_level_data& end_level = get_end_level_data();
289 
290  if(get_teams().empty()) {
291  // store persistent teams
293 
294  // this is probably only a story scenario, i.e. has its endlevel in the prestart event
295  return LEVEL_RESULT::VICTORY;
296  }
297 
298  if(linger_) {
299  LOG_NG << "resuming from loaded linger state...\n";
300  // as carryover information is stored in the snapshot, we have to re-store it after loading a linger state
302  if(!is_observer()) {
304  }
305 
306  return LEVEL_RESULT::VICTORY;
307  }
308 
309  pump().fire(is_victory ? "local_victory" : "local_defeat");
310 
311  { // Block for set_scontext_synced_base
313  pump().fire(end_level.proceed_to_next_level ? "victory" : "defeat");
314  pump().fire("scenario_end");
315  }
316 
317  if(end_level.proceed_to_next_level) {
319  }
320 
321  if(is_observer()) {
322  gui2::show_transient_message(_("Game Over"), _("The game is over."));
323  return LEVEL_RESULT::OBSERVER_END;
324  }
325 
326  // If we're a player, and the result is victory/defeat, then send
327  // a message to notify the server of the reason for the game ending.
329  "info", config {
330  "type", "termination",
331  "condition", "game over",
332  "result", is_victory ? "victory" : "defeat",
333  },
334  });
335 
336  // Play victory music once all victory events
337  // are finished, if we aren't observers and the
338  // carryover dialog isn't disabled.
339  //
340  // Some scenario authors may use 'continue'
341  // result for something that is not story-wise
342  // a victory, so let them use [music] tags
343  // instead should they want special music.
344  const std::string& end_music = select_music(is_victory);
345  if((!is_victory || end_level.transient.carryover_report) && !end_music.empty()) {
347  sound::play_music_once(end_music);
348  }
349 
351 
352  LEVEL_RESULT res = LEVEL_RESULT::string_to_enum(end_level.test_result);
353  if(res == LEVEL_RESULT::TEST_NOT_SET) {
354  return is_victory ? LEVEL_RESULT::VICTORY : LEVEL_RESULT::DEFEAT;
355  } else {
356  return res;
357  }
358  } catch(const savegame::load_game_exception&) {
359  // Loading a new game is effectively a quit.
360  saved_game_.clear();
361  throw;
362  } catch(const wesnothd_error& e) {
363  scoped_savegame_snapshot snapshot(*this);
365  if(e.message == "") {
367  _("A network disconnection has occurred, and the game cannot continue. Do you want to save the game?"),
369  } else {
371  _("This game has been ended.\nReason: ") + e.message + _("\nDo you want to save the game?"),
373  }
374 
375  if(dynamic_cast<const ingame_wesnothd_error*>(&e)) {
376  return LEVEL_RESULT::QUIT;
377  } else {
378  throw;
379  }
380  }
381 }
382 
384 {
385  while(!should_return_to_play_side()) {
387  SDL_Delay(10);
388  }
389 }
390 
392 {
393  if(!skip_next_turn_) {
395  }
396 
397  if(replay_controller_.get() != nullptr) {
398  init_side_done_now_ = false;
399 
400  REPLAY_RETURN res = replay_controller_->play_side_impl();
401  if(res == REPLAY_FOUND_END_TURN) {
403  }
404 
406  replay_controller_.reset();
407  }
408  } else if((current_team().is_local_human() && current_team().is_proxy_human())) {
409  LOG_NG << "is human...\n";
410  // If a side is dead end the turn, but play at least side=1's
411  // turn in case all sides are dead
412  if(gamestate().board_.side_units(current_side()) == 0 && !(get_units().empty() && current_side() == 1)) {
414  }
415 
417 
418  if(end_turn_ == END_TURN_NONE) {
419  play_human_turn();
420  }
421 
424  }
425 
426  LOG_NG << "human finished turn...\n";
427  } else if(current_team().is_local_ai() || (current_team().is_local_human() && current_team().is_droid())) {
428  play_ai_turn();
429  } else if(current_team().is_network()) {
431  } else if(current_team().is_local_human() && current_team().is_idle()) {
432  end_turn_enable(false);
435 
436  if(end_turn_ == END_TURN_NONE) {
437  play_idle_loop();
438  }
439  } else {
440  // we should have skipped over empty controllers before so this shouldn't be possible
441  ERR_NG << "Found invalid side controller " << current_team().controller().to_string() << " ("
442  << current_team().proxy_controller().to_string() << ") for side " << current_team().side() << "\n";
443  }
444 }
445 
447 {
448  log_scope("player turn");
449  assert(!linger_);
451  return;
452  }
453 
455  scoped_savegame_snapshot snapshot(*this);
458  }
459 
460  if(preferences::turn_bell()) {
462  }
463 }
464 
466 {
468  blindfold b(*gui_, true); // apply a blindfold for the duration of this dialog
469  gui_->redraw_everything();
470  gui_->recalculate_minimap();
471  std::string message = _("It is now $name|’s turn");
472  utils::string_map symbols;
473  symbols["name"] = gamestate().board_.get_team(current_side()).side_name();
474  message = utils::interpolate_variables_into_string(message, &symbols);
475  gui2::show_transient_message("", message);
476  }
477 }
478 
480 {
482  return;
483  }
484 
485  try {
487  } catch(const return_to_play_side_exception&) {
488  }
489 }
490 
492 {
494 
496  execute_gotos();
497  }
498 
499  end_turn_enable(true);
500 
501  while(!should_return_to_play_side()) {
504  }
505 }
506 
508 {
509  LOG_NG << "beginning end-of-scenario linger\n";
510  linger_ = true;
511 
512  // If we need to set the status depending on the completion state
513  // the key to it is here.
514  gui_->set_game_mode(game_display::LINGER);
515 
516  // Make all of the able-to-move units' orbs consistently red
518 
519  // change the end-turn button text to its alternate label
520  gui_->get_theme().refresh_title2("button-endturn", "title2");
521  gui_->invalidate_theme();
522  gui_->redraw_everything();
523 
524  try {
525  // Same logic as single-player human turn, but
526  // *not* the same as multiplayer human turn.
527  end_turn_enable(true);
529  while(end_turn_ == END_TURN_NONE) {
530  play_slice();
531  }
532  } catch(const savegame::load_game_exception&) {
533  // Loading a new game is effectively a quit.
534  saved_game_.clear();
535  throw;
536  }
537 
538  // revert the end-turn button text to its normal label
539  gui_->get_theme().refresh_title2("button-endturn", "title");
540  gui_->invalidate_theme();
541  gui_->redraw_everything();
542  gui_->set_game_mode(game_display::RUNNING);
543 
544  LOG_NG << "ending end-of-scenario linger\n";
545 }
546 
548 {
549  gui_->enable_menu("endturn", enable);
551 }
552 
554 {
555  // Clear moves from the GUI.
556  gui_->set_route(nullptr);
557  gui_->unhighlight_reach();
558 }
559 
561 {
562  LOG_NG << "is ai...\n";
563 
564  end_turn_enable(false);
565  gui_->recalculate_minimap();
566 
567  const cursor::setter cursor_setter(cursor::WAIT);
568 
569  // Correct an oddball case where a human could have left delayed shroud
570  // updates on before giving control to the AI. (The AI does not bother
571  // with the undo stack, so it cannot delay shroud updates.)
572  team& cur_team = current_team();
573  if(!cur_team.auto_shroud_updates()) {
574  // We just took control, so the undo stack is empty. We still need
575  // to record this change for the replay though.
577  }
578 
579  undo_stack().clear();
581 
582  try {
583  try {
586  }
587  } catch(const return_to_play_side_exception&) {
588  } catch(const fallback_ai_to_human_exception&) {
590  player_type_changed_ = true;
591  ai_fallback_ = true;
592  }
593  } catch(...) {
595  throw;
596  }
597 
600  }
601 
603  gui_->recalculate_minimap();
604  gui_->invalidate_unit();
605  gui_->invalidate_game_status();
606  gui_->invalidate_all();
607 }
608 
609 /**
610  * Will handle sending a networked notification in descendent classes.
611  */
613 {
614  gui_->get_chat_manager().add_chat_message(std::time(nullptr), "Wesnoth", 0,
615  "This side is in an idle state. To proceed with the game, the host must assign it to another controller.",
617 }
618 
619 /**
620  * Will handle networked turns in descendent classes.
621  */
623 {
624  // There should be no networked sides in single-player.
625  ERR_NG << "Networked team encountered by playsingle_controller." << std::endl;
626 }
627 
628 void playsingle_controller::handle_generic_event(const std::string& name)
629 {
630  if(name == "ai_user_interact") {
631  play_slice(false);
632  }
633 }
634 
636 {
637  if(linger_) {
639  } else if(!is_browsing() && menu_handler_.end_turn(current_side())) {
641  }
642 }
643 
645 {
646  skip_next_turn_ = true;
648 }
649 
651 {
652  if(!get_teams().empty()) {
653  const team& t = get_teams()[gui_->viewing_team()];
654 
656  show_objectives();
657  }
658  }
659 }
660 
662 {
663  // mouse_handler expects at least one team for linger mode to work.
664  assert(is_regular_game_end());
665  if(get_end_level_data().transient.linger_mode && !get_teams().empty()) {
666  linger();
667  }
668 }
669 
671 {
672  // We cannot add [end_turn] to the recorder while executing another action.
674 
675  if(end_turn_ == END_TURN_REQUIRED && current_team().is_local()) {
676  // TODO: we should also send this immediately.
677  resources::recorder->end_turn(gamestate_->next_player_number_);
679  }
680 
681  assert(end_turn_ == END_TURN_SYNCED);
682  skip_next_turn_ = false;
683 
684  if(ai_fallback_) {
685  current_team().make_ai();
686  ai_fallback_ = false;
687  }
688 }
689 
691 {
692  if(replay_controller_ && replay_controller_->is_controlling_view()) {
693  replay_controller_->update_viewing_player();
694  } else if(int side_num = play_controller::find_last_visible_team()) {
695  // Update viewing team in case it has changed during the loop.
696  if(side_num != gui_->viewing_side()) {
697  update_gui_to_player(side_num - 1);
698  }
699  }
700 }
701 
703 {
704  if(replay_controller_ && replay_controller_->allow_reset_replay()) {
705  replay_controller_->stop_replay();
706  throw reset_gamestate_exception(replay_controller_->get_reset_state(), {}, false);
707  } else {
708  ERR_NG << "received invalid reset replay\n";
709  }
710 }
711 
713 {
714  replay_controller_ = std::make_unique<replay_controller>(
715  *this,
717  std::make_shared<config>(saved_game_.get_replay_starting_point()),
718  std::bind(&playsingle_controller::on_replay_end, this, is_unit_test)
719  );
720 
721  if(is_unit_test) {
722  replay_controller_->play_replay();
723  }
724 }
725 
727 {
729  return true;
730  } else if(end_turn_ == END_TURN_NONE || replay_controller_.get() != 0 || current_team().is_network()) {
731  return false;
732  } else {
733  return true;
734  }
735 }
736 
738 {
739  if(is_networked_mp()) {
741  } else if(is_unit_test) {
742  replay_controller_->return_to_play_side();
743  if(!is_regular_game_end()) {
745  e.proceed_to_next_level = false;
746  e.is_victory = false;
748  }
749  }
750 }
bool disable_auto_moves()
Definition: general.cpp:949
void empty_playlist()
Definition: sound.cpp:612
void end_turn(int next_player_number)
Definition: replay.cpp:302
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:221
void set_all_units_user_end_turn()
Definition: game_board.cpp:86
An error occurred during when trying to communicate with the wesnothd server.
static lg::log_domain log_aitesting("ai/testing")
int autosavemax()
Definition: game.cpp:805
std::unique_ptr< soundsource::manager > soundsources_manager_
bool turn_bell()
Definition: general.cpp:645
static void display(const std::string &scenario_name, const config &story)
static bool run_and_store(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
hotkey::command_executor * get_hotkey_command_executor() override
Optionally get a command executor to handle context menu events.
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 ...
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:85
void heal_all_survivors()
Definition: game_board.cpp:93
std::map< std::string, t_string > string_map
int find_last_visible_team() const
returns 0 if no such team was found.
std::unique_ptr< game_display > gui_
const unit_map & get_units() const
events::mouse_handler mouse_handler_
static manager & get_singleton()
Definition: manager.hpp:145
std::unique_ptr< plugins_context > plugins_context_
bool is_network() const
Definition: team.hpp:274
config & replay_start()
Definition: saved_game.hpp:123
bool is_skipping_replay() const
const std::string & side_name() const
Definition: team.hpp:320
Exception used to escape form the ai or ui code to playsingle_controller::play_side.
virtual void play_side_impl() override
Class for autosaves.
Definition: savegame.hpp:279
game_events::wml_event_pump & pump()
const int INFINITE_AUTO_SAVES
Definition: game.hpp:208
std::unique_ptr< hotkey_handler > hotkey_handler_
int first_human_team_
Definition: game_state.hpp:75
child_itors child_range(config_key_type key)
Definition: config.cpp:344
virtual void init_gui() override
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.
bool objectives_changed() const
Definition: team.hpp:253
PROCESS_DATA_RESULT sync_network()
Definition: playturn.cpp:62
static config get_auto_shroud(bool turned_on)
Records that the player has toggled automatic shroud updates.
Gather statistics important for AI testing and output them.
And endturn was required eigher by the player, by the ai or by [end_turn].
void clear()
Definition: saved_game.cpp:792
void enable_replay(bool is_unit_test=false)
virtual void play_slice(bool is_delay_enabled=true)
const gamemap & get_map() const
Class for "normal" midgame saves.
Definition: savegame.hpp:252
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:558
void play_music_once(const std::string &file)
Definition: sound.cpp:603
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:223
static void log_game_end()
Definition: testing.cpp:103
Contains the exception interfaces used to signal completion of a scenario, campaign or turn...
bool save_game_interactive(const std::string &message, DIALOG_TYPE dialog_type)
Save a game interactively through the savegame dialog.
Definition: savegame.cpp:384
static std::string _(const char *str)
Definition: gettext.hpp:93
persist_manager persist_
void reset_current_scenario()
Reset the stats of the current scenario to the beginning.
Definition: statistics.cpp:797
void send_data()
Definition: playturn.cpp:81
An extension of play_controller::hotkey_handler, which has support for SP wesnoth features like white...
events::menu_handler menu_handler_
virtual void do_idle_notification()
Will handle sending a networked notification in descendent classes.
playsingle_controller(const config &level, saved_game &state_of_game, bool skip_replay)
#define b
void make_human()
Definition: team.hpp:285
std::unique_ptr< game_state > gamestate_
REPLAY_RETURN
Definition: replay.hpp:156
no linger overlay, show fog and shroud.
std::string turn_bell
saved_game & saved_game_
void end_turn_enable(bool enable)
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:72
bool end_turn(int side_num)
virtual void check_objectives() override
virtual bool should_return_to_play_side() const override
team & get_team(int i)
Definition: game_board.hpp:97
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
std::string test_result
result to use if this is a unit test
bool disable_autosave
bool has_human_sides() const
Definition: game_state.hpp:76
config to_config() const
Builds the snapshot config from members and their respective configs.
bool valid() const
Definition: location.hpp:89
game_board * gameboard
Definition: resources.cpp:21
bool is_regular_game_end() const
std::vector< team > & get_teams()
std::shared_ptr< config > stats_
virtual void init_gui()
void read_stats(const config &cfg)
Definition: statistics.cpp:773
std::string describe_result() const
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
#define LOG_NG
replay * recorder
Definition: resources.cpp:29
void play_turn(side_number side)
Plays a turn for the specified side using its active AI.
Definition: manager.cpp:724
static lg::log_domain log_enginerefac("enginerefac")
bool carryover_report
Should a summary of the scenario outcome be displayed?
An object which will lock the display for the duration of its lifetime.
Definition: video.hpp:299
virtual void play_network_turn()
Will handle networked turns in descendent classes.
static void log_game_start()
Definition: testing.cpp:91
LEVEL_RESULT play_scenario(const config &level)
bool is_browsing() const override
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.
Encapsulates the map of the game.
Definition: location.hpp:38
void on_replay_end(bool is_unit_test)
bool auto_shroud_updates() const
Definition: team.hpp:351
void make_ai()
Definition: team.hpp:286
Sound source info class.
void set_end_level_data(const end_level_data &data)
Exception used to signal that the user has decided to abortt a game, and to load another game instead...
Definition: savegame.hpp:83
transient_end_level transient
virtual bool is_networked_mp() const
const config & get_replay_starting_point()
Definition: saved_game.cpp:587
std::size_t i
Definition: function.cpp:967
const std::string & select_music(bool victory) const
map_location map_start_
void execute_gotos(mouse_handler &mousehandler, int side_num)
#define ERR_NG
static map_location::DIRECTION s
std::unique_ptr< replay_controller > replay_controller_
void reset_gamestate(const config &level, int replay_pos)
Define the game&#39;s event mechanism.
#define log_scope(description)
Definition: log.hpp:218
bool empty() const
Definition: map.hpp:446
bool proceed_to_next_level
whether to proceed to the next scenario, equals is_victory in sp.
t_string get_scenario_name() const
Additional information on the game outcome which can be provided by WML.
actions::undo_list & undo_stack()
const end_level_data & get_end_level_data() const
static void save(LexState *ls, int c)
Definition: llex.cpp:57
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:481
virtual bool receive_from_wesnothd(config &) const
void update_viewing_player() override
compression::format save_compression_format()
Definition: game.cpp:857
void play_bell(const std::string &files)
Definition: sound.cpp:1036
game_state & gamestate()
double t
Definition: astarsearch.cpp:65
playturn_network_adapter network_reader_
void play_music_config(const config &music_node, bool allow_interrupt_current_track, int i)
Definition: sound.cpp:705
game_classification & classification()
Definition: saved_game.hpp:55
PROXY_CONTROLLER proxy_controller() const
Definition: team.hpp:294
game_board board_
Definition: game_state.hpp:47
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:609
int current_side() const
Returns the number of the side whose turn it is.
bool is_skipping_story() const
replay_network_sender replay_sender_
std::string message
Definition: exceptions.hpp:30
std::shared_ptr< config > level
#define e
std::size_t turn() const
void commit_music_changes()
Definition: sound.cpp:823
void remove_snapshot()
Definition: saved_game.cpp:576
int side() const
Definition: team.hpp:200
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
static lg::log_domain log_engine("engine")
bool turn_dialog()
Definition: game.cpp:430
Thrown when a lexical_cast fails.
bool empty() const
Definition: config.cpp:941
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
virtual void handle_generic_event(const std::string &name) override
An [end_turn] was added to the replay.
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)...
CONTROLLER controller() const
Definition: team.hpp:267