The Battle for Wesnoth  1.15.1+dev
replay_controller.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 - 2018 by the Battle for Wesnoth Project
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #include "replay_controller.hpp"
15 
16 #include "game_config_manager.hpp"
17 #include "gettext.hpp"
18 #include "log.hpp"
19 #include "replay.hpp"
20 #include "resources.hpp"
22 
23 static lg::log_domain log_engine("engine");
24 #define DBG_NG LOG_STREAM(debug, log_engine)
25 
26 static lg::log_domain log_replay("replay");
27 #define DBG_REPLAY LOG_STREAM(debug, log_replay)
28 #define LOG_REPLAY LOG_STREAM(info, log_replay)
29 #define ERR_REPLAY LOG_STREAM(err, log_replay)
30 
31 namespace
32 {
33 struct replay_play_nostop : public replay_controller::replay_stop_condition
34 {
35  replay_play_nostop() {}
36  virtual bool should_stop() { return false; }
37 };
38 
39 struct replay_play_moves : public replay_controller::replay_stop_condition
40 {
41  int moves_todo_;
42  replay_play_moves(int moves_todo) : moves_todo_(moves_todo) {}
43  virtual void move_done() { --moves_todo_; }
44  virtual bool should_stop() { return moves_todo_ == 0; }
45 };
46 
47 struct replay_play_turn : public replay_controller::replay_stop_condition
48 {
49  int turn_begin_;
50  int turn_current_;
51  replay_play_turn(int turn_begin) : turn_begin_(turn_begin), turn_current_(turn_begin) {}
52  virtual void new_side_turn(int , int turn) { turn_current_ = turn; }
53  virtual bool should_stop() { return turn_begin_ != turn_current_; }
54 };
55 
56 struct replay_play_side : public replay_controller::replay_stop_condition
57 {
58  bool next_side_;
59  replay_play_side() : next_side_(false) {}
60  virtual void new_side_turn(int , int) { next_side_ = true; }
61  virtual bool should_stop() { return next_side_; }
62 };
63 }
64 
65 replay_controller::replay_controller(play_controller& controller, bool control_view, const std::shared_ptr<config>& reset_state, const std::function<void()>& on_end_replay)
66  : controller_(controller)
67  , stop_condition_(new replay_stop_condition())
68  , disabler_()
69  , vision_()
70  , reset_state_(reset_state)
71  , on_end_replay_(on_end_replay)
72  , return_to_play_side_(false)
73 {
74  if(control_view) {
76  }
80 }
82 {
85  }
90 }
92 {
94  if (const config &res = theme_cfg.child("resolution"))
95  {
96  if (const config &replay_theme_cfg = res.child("replay")) {
97  controller_.get_display().get_theme().modify(replay_theme_cfg);
98  }
99  //Make sure we get notified if the theme is redrawn completely. That way we have
100  //a chance to restore the replay controls of the theme as well.
102  }
103 }
104 
106 {
109 }
110 
112 {
113  stop_condition_.reset(new replay_play_turn(controller_.gamestate().tod_manager_.turn()));
115 }
116 
118 {
119  stop_condition_.reset(new replay_play_side());
121 }
122 
124 {
125  stop_condition_.reset(new replay_play_moves(1));
127 }
128 
129 //move all sides till stop/end
131 {
132  stop_condition_.reset(new replay_play_nostop());
134 }
135 
137 {
142 }
143 
145 {
148 }
149 
151 {
152  // this is only attached to one event - the theme_reset_event
153  if(name == "theme_reset") {
155  }
156  if(std::shared_ptr<gui::button> skip_animation_button = controller_.get_display().find_action_button("skip-animation")) {
157  skip_animation_button->set_check(controller_.is_skipping_replay());
158  }
159 }
160 
162 {
163  return resources::recorder->at_end();
164 }
165 
167 {
169  while(!return_to_play_side_ && !static_cast<playsingle_controller&>(controller_).get_player_type_changed())
170  {
171  if(!stop_condition_->should_stop())
172  {
173  if(resources::recorder->at_end()) {
174  //Gather more replay data
175  on_end_replay_();
176  }
177  else {
178  REPLAY_RETURN res = do_replay(true);
179  if(res == REPLAY_FOUND_END_MOVE) {
180  stop_condition_->move_done();
181  }
182  if(res == REPLAY_FOUND_END_TURN) {
183  return res;
184  }
185  if(res == REPLAY_RETURN_AT_END) {
186  stop_replay();
187  }
188  if(res == REPLAY_FOUND_INIT_TURN)
189  {
191  }
192  }
193  controller_.play_slice(false);
194 
195  // Update the buttons once, on the transition from not-stopped to stopped.
196  if(stop_condition_->should_stop()) {
198  }
199  }
200  else
201  {
202  // Don't move the update_enabled_buttons() call here. This play_slice() should block
203  // until the next event occurs, but on X11/Linux update_enabled_buttons() seems to put
204  // an event in the queue, turning this into a busy loop.
205  controller_.play_slice(true);
206  }
207  }
208  return REPLAY_FOUND_END_MOVE;
209 }
211 {
212  hotkey::HOTKEY_COMMAND command = cmd.id;
213 
214  switch(command) {
216  return true;
220  return is_controlling_view();
221  //commands we only can do before the end of the replay
223  return !recorder_at_end();
228  //we have one events_disabler when starting the replay_controller and a second when entering the synced context.
229  return should_stop() && (events::commands_disabled <= 1 ) && !recorder_at_end();
232  default:
233  assert(false);
234  return false;
235  }
236 }
237 
239 {
240  vision_ = SHOW_ALL;
241  update_teams();
242 }
243 
245 {
247  update_teams();
248 }
249 
251 {
253  update_teams();
254 }
255 
257 {
260  update_gui();
261 }
262 
264 {
265  assert(vision_);
267 }
268 
270 {
271  return vision_ == SHOW_ALL;
272 }
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
std::function< void()> on_end_replay_
boost::optional< REPLAY_VISION > vision_
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
HOTKEY_COMMAND id
the names are strange: the "hotkey::HOTKEY_COMMAND" is named id, and the string to identify the objec...
theme & get_theme()
Definition: display.hpp:379
replay_controller(play_controller &controller, bool control_view, const std::shared_ptr< config > &reset_state, const std::function< void()> &on_end_replay=nop)
bool is_skipping_replay() const
static lg::log_domain log_engine("engine")
game_display & get_display() override
Get a reference to a display member a derived class uses.
bool at_end() const
Definition: replay.cpp:626
int first_human_team_
Definition: game_state.hpp:72
void redraw_everything()
Invalidates entire screen, including all tiles and sidebar.
Definition: display.cpp:2375
Stores all information related to functions that can be bound to hotkeys.
virtual void play_slice(bool is_delay_enabled=true)
Replay control code.
REPLAY_RETURN do_replay(bool one_move)
Definition: replay.cpp:677
bool recorder_at_end() const
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.hpp:622
void handle_generic_event(const std::string &name) override
REPLAY_RETURN
Definition: replay.hpp:153
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
std::unique_ptr< replay_stop_condition > stop_condition_
static game_config_manager * get()
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:616
events::generic_event & theme_reset_event()
Definition: theme.hpp:282
void update_enabled_buttons()
Refresh the states of the replay-control buttons, this will cause the hotkey framework to query can_e...
void modify(const config &cfg)
Definition: theme.cpp:827
tod_manager tod_manager_
Definition: game_state.hpp:47
replay * recorder
Definition: resources.cpp:28
std::string theme() const
void create_buttons()
Definition: display.cpp:850
REPLAY_RETURN play_side_impl()
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:2968
void update_gui_to_player(const int team_index, const bool observe=false)
Changes the UI for this client to the passed side index.
bool allow_reset_replay() const
virtual bool attach_handler(observer *obs)
bool can_execute_command(const hotkey::hotkey_command &cmd, int index) const
static lg::log_domain log_replay("replay")
Game configuration data as global variables.
Definition: build_info.cpp:49
game_state & gamestate()
play_controller & controller_
bool is_controlling_view() const
Standard logging facilities (interface).
int current_side() const
Returns the number of the side whose turn it is.
virtual bool detach_handler(observer *obs)
int turn() const
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
void invalidate_theme()
Definition: display.hpp:402
bool should_stop() const