The Battle for Wesnoth  1.19.15+dev
hotkey_handler_sp.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2025
3  by Chris Beck <render787@gmail.com>
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 
17 
18 #include "filesystem.hpp" // for get_saves_dir()
19 #include "font/standard_colors.hpp"
20 #include "formula/string_utils.hpp"
21 #include "gui/dialogs/message.hpp"
23 #include "hotkey/hotkey_item.hpp"
24 #include "map/label.hpp"
25 #include "play_controller.hpp"
27 #include "whiteboard/manager.hpp"
30 #include "map/map.hpp"
31 #include "save_index.hpp"
32 #include "saved_game.hpp"
33 #include "savegame.hpp"
34 #include "resources.hpp"
35 #include "replay.hpp"
36 
37 #include "units/unit.hpp"
38 
39 #include <boost/algorithm/string/predicate.hpp>
40 
41 namespace balg = boost::algorithm;
42 
45  , playsingle_controller_(pc)
46  , whiteboard_manager_(pc.get_whiteboard())
47 {}
48 
50 
51 bool playsingle_controller::hotkey_handler::is_observer() const { return playsingle_controller_.is_observer(); }
52 
54  if (!browse())
55  menu_handler_.recruit(play_controller_.current_side(), mouse_handler_.get_last_hex());
56  else if (whiteboard_manager_->is_active())
57  menu_handler_.recruit(gui()->viewing_team().side(), mouse_handler_.get_last_hex());
58 }
59 
61  if (!browse())
62  menu_handler_.repeat_recruit(play_controller_.current_side(), mouse_handler_.get_last_hex());
63  else if (whiteboard_manager_->is_active())
64  menu_handler_.repeat_recruit(gui()->viewing_team().side(), mouse_handler_.get_last_hex());
65 }
66 
68  if (!browse())
69  menu_handler_.recall(play_controller_.current_side(), mouse_handler_.get_last_hex());
70  else if (whiteboard_manager_->is_active())
71  menu_handler_.recall(gui()->viewing_team().side(), mouse_handler_.get_last_hex());
72 }
73 
75  menu_handler_.toggle_shroud_updates(gui()->viewing_team().side());
76 }
77 
79  menu_handler_.update_shroud_now(gui()->viewing_team().side());
80 }
81 
83  playsingle_controller_.end_turn();
84 }
85 
88 }
89 
92 }
93 
96 }
97 
100 }
101 
104 }
105 
108 }
109 
112 }
113 
115  menu_handler_.continue_move(mouse_handler_, play_controller_.current_side());
116 }
117 
119  if (!browse())
120  menu_handler_.unit_hold_position(mouse_handler_, play_controller_.current_side());
121 }
122 
124  if (!browse())
125  menu_handler_.end_unit_turn(mouse_handler_, play_controller_.current_side());
126 }
127 
130 }
131 
134 }
135 
138 }
139 
142 }
143 
146 }
147 
149  whiteboard_manager_->set_active(!whiteboard_manager_->is_active());
150 
151  if (whiteboard_manager_->is_active()) {
153  utils::string_map symbols;
154  symbols["hotkey"] = hk;
155 
156  gui()->announce(_("Planning mode activated!") + std::string("\n") + VGETTEXT("(press $hotkey to deactivate)", symbols), font::NORMAL_COLOR);
157  } else {
158  gui()->announce(_("Planning mode deactivated!"), font::NORMAL_COLOR);
159  }
160  //@todo Stop printing whiteboard help in the chat once we have better documentation/help
161  whiteboard_manager_->print_help_once();
162 }
163 
165  whiteboard_manager_->contextual_execute();
166 }
167 
169  whiteboard_manager_->execute_all_actions();
170 }
171 
173  whiteboard_manager_->contextual_delete();
174 }
175 
177 {
178  whiteboard_manager_->contextual_bump_up_action();
179 }
180 
182 {
183  whiteboard_manager_->contextual_bump_down_action();
184 }
185 
187 {
188  const unit* curr_unit;
190  { wb::future_map future; //start planned unit map scope
191  curr_unit = &*menu_handler_.current_unit();
192  loc = curr_unit->get_location();
193  } // end planned unit map scope
194  whiteboard_manager_->save_suppose_dead(*curr_unit,loc);
195 }
196 
198 {
199  switch(cmd.hotkey_command) {
201  return hotkey::on_if(whiteboard_manager_->is_active());
202  default:
204  }
205 }
206 
208 {
210  bool res = true;
211  int prefixlen = wml_menu_hotkey_prefix.length();
212  switch (command){
213  case hotkey::HOTKEY_NULL:
214  case hotkey::HOTKEY_WML:
215  {
216  if(cmd.id.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0) {
217  game_events::wmi_manager::item_ptr item = gamestate().get_wml_menu_items().get_item(std::string(cmd.id.substr(prefixlen)));
218  if(!item) {
219  return false;
220  }
221  return !item->is_synced() || play_controller_.can_use_synced_wml_menu();
222  }
224 
225  }
227  return !events::commands_disabled || (playsingle_controller_.is_replay() && events::commands_disabled < 2);
230  return !browse() && !linger() && !events::commands_disabled;
234  return (!browse() || whiteboard_manager_->is_active()) && !linger() && !events::commands_disabled;
236  //playmp_controller::hotkey_handler checks whether we are the host.
237  return (!browse() || linger()) && !events::commands_disabled;
238 
240  return !linger()
241  && (gui()->viewing_team().uses_fog() || gui()->viewing_team().uses_shroud())
242  && gui()->viewing_team_is_playing()
243  && gui()->viewing_team().is_local_human()
246  return !linger()
247  && gui()->viewing_team_is_playing()
248  && gui()->viewing_team().is_local_human()
250  && gui()->viewing_team().auto_shroud_updates() == false;
251 
252  // Commands we can only do if in debug mode
257  return !events::commands_disabled && game_config::debug && play_controller_.get_map().on_board(mouse_handler_.get_last_hex()) && play_controller_.current_team().is_local();
258 
260  res = !is_observer();
261  break;
264  const terrain_label *label = gui()->labels().get_label(mouse_handler_.get_last_hex());
265  res = !events::commands_disabled && play_controller_.get_map().on_board(mouse_handler_.get_last_hex())
266  && !gui()->shrouded(mouse_handler_.get_last_hex())
267  && !is_observer()
268  && (!label || !label->immutable());
269  break;
270  }
272  if(browse() || events::commands_disabled)
273  return false;
274 
276  && (menu_handler_.current_unit()->move_interrupted()))
277  return true;
278  const unit_map::const_iterator i = play_controller_.get_units().find(mouse_handler_.get_selected_hex());
279  if (!i.valid()) return false;
280  return i->move_interrupted();
281  }
283  return !is_observer();
286  return whiteboard_manager_->can_enable_execution_hotkeys() && !events::commands_disabled && !browse();
288  return whiteboard_manager_->can_enable_modifier_hotkeys();
291  return whiteboard_manager_->can_enable_reorder_hotkeys();
293  {
294  //@todo re-enable this once we figure out a decent UI for suppose_dead
295  //@todo when re-enabling this, change 'true' to 'false' in master_hotkey_list for this hotkey
296  return false;
297  }
298 
309  return playsingle_controller_.get_replay_controller() && playsingle_controller_.get_replay_controller()->can_execute_command(cmd);
311  return playsingle_controller_.is_replay() && (!playsingle_controller_.is_networked_mp() || resources::recorder->at_end());
312  default:
314  }
315  return res;
316 }
317 
318 void playsingle_controller::hotkey_handler::load_autosave(const std::string& filename, bool start_replay)
319 {
321  try {
323  } catch(const game::load_game_failed& e) {
324  gui2::show_error_message(_("The file you have tried to load is corrupt") + "\n\n" + e.what());
325  return;
326  }
327 
328  // TODO: look into loading autosaves by resetting the gamestate. Since we're going
329  // back a turn, we don't strictly need to exit the game and reload the game config.
330  // Perhaps we could neverage the replay system directly instead of autosave files?
331  if(!start_replay) {
332 #ifdef __cpp_designated_initializers
333  throw savegame::load_game_exception({ .load_config = std::move(savegame) });
334 #else
336  payload.load_config = std::move(savegame);
337  throw savegame::load_game_exception(std::move(payload));
338 #endif
339  }
340 
341  if(savegame.child_or_empty("snapshot")["replay_pos"].to_int(-1) < 0 ) {
342  gui2::show_error_message(_("The file you have tried to load has no replay information."));
343  return;
344  }
345  if(!playsingle_controller_.get_saved_game().get_replay().is_ancestor(savegame.child_or_empty("replay"))) {
346  gui2::show_error_message(_("The file you have tried to load is not from the current session."));
347  return;
348  }
349 
350  auto res = std::make_shared<config>(savegame.child_or_empty("snapshot"));
351  auto stats = std::make_shared<config>(savegame.child_or_empty("statistics"));
352  throw reset_gamestate_exception(res, stats, false);
353 }
354 
356 {
357  if(!playsingle_controller_.is_networked_mp()) {
359  }
360  playsingle_controller_.set_player_type_changed();
361 }
map_location loc
Definition: move.cpp:172
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
void label_terrain(mouse_handler &mousehandler, bool team_only)
void update_shroud_now(int side_num)
virtual void clear_messages() override
void recall(int side_num, const map_location &last_hex)
void create_unit(mouse_handler &mousehandler)
Creates a unit (in debug mode via hotkey or context menu).
void unit_hold_position(mouse_handler &mousehandler, int side_num)
void end_unit_turn(mouse_handler &mousehandler, int side_num)
void change_side(mouse_handler &mousehandler)
void toggle_shroud_updates(int side_num)
void recruit(int side_num, const map_location &last_hex)
void continue_move(mouse_handler &mousehandler, int side_num)
void repeat_recruit(int side_num, const map_location &last_hex)
void kill_unit(mouse_handler &mousehandler)
unit_map::iterator current_unit()
map_location get_selected_hex() const
const map_location & get_last_hex() const
std::shared_ptr< wml_menu_item > item_ptr
wml_menu_item pointers
Definition: wmi_manager.hpp:44
item_ptr get_item(const std::string &id) const
Gets the menu item with the specified ID.
game_events::wmi_manager & get_wml_menu_items()
Definition: game_state.cpp:383
virtual hotkey::action_state get_action_state(const hotkey::ui_command &) const override
virtual bool can_execute_command(const hotkey::ui_command &command) const override
Check if a command can be executed.
events::menu_handler menu_handler_
bool is_observer() const
game_state & gamestate()
events::mouse_handler mouse_handler_
std::shared_ptr< wb::manager > whiteboard_manager_
virtual void toggle_shroud_updates() override
virtual void whiteboard_suppose_dead() override
hotkey_handler(playsingle_controller &, saved_game &)
virtual hotkey::action_state get_action_state(const hotkey::ui_command &) const override
virtual bool can_execute_command(const hotkey::ui_command &cmd) const override
Check if a command can be executed.
virtual void whiteboard_delete_action() override
virtual void whiteboard_execute_action() override
virtual void label_terrain(bool) override
virtual void load_autosave(const std::string &filename, bool start_replay=false) override
virtual void whiteboard_bump_up_action() override
virtual void whiteboard_bump_down_action() override
virtual void whiteboard_execute_all_actions() override
bool at_end() const
Definition: replay.cpp:631
void delete_upcoming_commands()
Definition: replay.cpp:174
Exception used to signal that the user has decided to abort a game, and to load another game instead.
Definition: savegame.hpp:88
To store label data Class implements logic for rendering.
Definition: label.hpp:111
This class represents a single unit of a specific type.
Definition: unit.hpp:132
Declarations for File-IO.
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:1032
static std::string _(const char *str)
Definition: gettext.hpp:97
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1443
std::string label
What to show in the filter's drop-down list.
Definition: manager.cpp:201
An extension of play_controller::hotkey_handler, which has support for SP wesnoth features like white...
Declarations for a class that implements WML-defined (right-click) menu items.
std::string get_saves_dir()
const color_t NORMAL_COLOR
const bool & debug
Definition: game_config.cpp:95
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
Definition: message.cpp:201
General purpose widgets.
std::string get_names(const std::string &id)
Returns a comma-separated string of hotkey names.
action_state on_if(bool condition)
Returns action_state::on if condition is true, else action_state::off.
const hotkey_command & get_hotkey_command(std::string_view command)
Returns the hotkey_command with the given id.
@ HOTKEY_TELEPORT_UNIT
@ HOTKEY_END_UNIT_TURN
@ HOTKEY_WB_EXECUTE_ALL_ACTIONS
@ HOTKEY_WB_SUPPOSE_DEAD
@ HOTKEY_REPLAY_PLAY
@ HOTKEY_SAVE_GAME
@ HOTKEY_UPDATE_SHROUD
@ HOTKEY_REPEAT_RECRUIT
@ HOTKEY_REPLAY_STOP
@ HOTKEY_KILL_UNIT
@ HOTKEY_LABEL_TEAM_TERRAIN
@ HOTKEY_UNIT_HOLD_POSITION
@ HOTKEY_REPLAY_NEXT_TURN
@ HOTKEY_REPLAY_SHOW_EVERYTHING
@ HOTKEY_REPLAY_SHOW_TEAM1
@ HOTKEY_LABEL_TERRAIN
@ HOTKEY_CLEAR_LABELS
@ HOTKEY_CONTINUE_MOVE
@ HOTKEY_WB_EXECUTE_ACTION
@ HOTKEY_CHANGE_SIDE
@ HOTKEY_DELAY_SHROUD
@ HOTKEY_WB_BUMP_UP_ACTION
@ HOTKEY_CREATE_UNIT
@ HOTKEY_REPLAY_EXIT
@ HOTKEY_REPLAY_NEXT_SIDE
@ HOTKEY_REPLAY_NEXT_MOVE
@ HOTKEY_REPLAY_RESET
@ HOTKEY_WB_TOGGLE
@ HOTKEY_REPLAY_SKIP_ANIMATION
@ HOTKEY_WB_BUMP_DOWN_ACTION
@ HOTKEY_REPLAY_SHOW_EACH
@ HOTKEY_WB_DELETE_ACTION
replay * recorder
Definition: resources.cpp:28
config read_save_file(const std::string &dir, const std::string &name)
Read the complete config information out of a savefile.
Definition: save_index.cpp:300
std::map< std::string, t_string > string_map
Replay control code.
std::string filename
Filename.
Error used when game loading fails.
Definition: game_errors.hpp:31
Used as the main parameter for can_execute_command/do_execute_command These functions are used to exe...
hotkey::HOTKEY_COMMAND hotkey_command
The hotkey::HOTKEY_COMMAND associated with this action, HOTKEY_NULL for actions that don't allow hotk...
std::string id
The string command, never empty, describes the action uniquely.
Encapsulates the map of the game.
Definition: location.hpp:46
config load_config
Config information of the savefile to be loaded.
Definition: savegame.hpp:76
bool valid() const
Definition: map.hpp:273
Applies the planned unit map for the duration of the struct's life.
Definition: manager.hpp:253
Declarations for a container for wml_menu_item.
#define e