1 /* 2 Copyright (C) 2010 - 2018 by Gabriel Morin <gabrielmorin (at) gmail (dot) com> 3 Part of the Battle for Wesnoth Project https://www.wesnoth.org 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY. 11 12 See the COPYING file for more details. 13 */ 14 15 /** 16 * @file 17 */ 18 19 #pragma once 20 21 #include "side_actions.hpp" 22 23 #include "units/map.hpp" 24 25 #include <boost/dynamic_bitset.hpp> 26 27 class CKey; 28 class team; 29 30 namespace pathfind { 31 struct marked_route; 32 } 33 34 namespace wb { 35 36 class mapbuilder; 37 class highlighter; 38 39 /** 40 * This class is the frontend of the whiteboard framework for the rest of the Wesnoth code. 41 */ 42 class manager 43 { 44 friend struct future_map; 45 friend struct future_map_if_active; 46 friend struct real_map; 47 48 public: 49 manager(const manager&) = delete; 50 manager& operator=(const manager&) = delete; 51 52 manager(); 53 ~manager(); 54 55 void print_help_once(); 56 57 /** Determine whether the game is initialized and the current side has control of the game 58 * i.e. the whiteboard can take over 59 */ 60 bool can_modify_game_state() const; 61 /** Determine whether the whiteboard can be activated safely */ 62 bool can_activate() const; 63 /** Determine whether the whiteboard is activated. */ is_active() const64 bool is_active() const { return active_; } 65 /** Activates/Deactivates the whiteboard*/ 66 void set_active(bool active); 67 /** Called by the key that temporarily toggles the activated state when held */ 68 void set_invert_behavior(bool invert); 69 /** Prevents the whiteboard from changing its activation state, as long as the returned reference is held */ get_activation_state_lock()70 whiteboard_lock get_activation_state_lock() { return activation_state_lock_; } 71 72 /** Is the whiteboard in the process of executing an action? */ is_executing_actions() const73 bool is_executing_actions() const { return executing_actions_; } 74 75 /** Used to ask the whiteboard if its action execution hotkeys should be available to the user */ 76 bool can_enable_execution_hotkeys() const; 77 /** Used to ask the whiteboard if hotkeys affecting the action queue should be available to the user */ 78 bool can_enable_modifier_hotkeys() const; 79 /** Used to ask the whiteboard if its action reordering hotkeys should be available to the user */ 80 bool can_enable_reorder_hotkeys() const; 81 /** Used to ask permission to the wb to move a leader, to avoid invalidating planned recruits */ 82 bool allow_leader_to_move(const unit& leader) const; 83 /** @ return true if the whiteboard is ready to end turn. Triggers the execution of remaining planned actions. */ 84 bool allow_end_turn(); 85 /** 86 * The on_* methods below inform the whiteboard of specific events 87 */ 88 void on_init_side(); 89 void on_finish_side_turn(int side); 90 void on_mouseover_change(const map_location& hex); on_deselect_hex()91 void on_deselect_hex(){ erase_temp_move();} 92 void on_gamestate_change(); 93 void on_viewer_change(size_t team_index); 94 void on_change_controller(int side, const team& t); 95 void on_kill_unit(); 96 /** Handles various cleanup right before removing an action from the queue */ 97 void pre_delete_action(action_ptr action); 98 /** Handles various cleanup right after removing an action from the queue */ 99 void post_delete_action(action_ptr action); 100 101 /** Called by replay_network_sender to add whiteboard data to the outgoing network packets */ 102 void send_network_data(); 103 /** Called by turn_info::process_network_data() when network data needs to be processed */ 104 void process_network_data(const config&); 105 /** Adds a side_actions::net_cmd to net_buffer_[team_index], whereupon it will (later) be sent to all allies */ 106 void queue_net_cmd(size_t team_index, const side_actions::net_cmd&); 107 108 /** Whether the current side has actions in the first turn of its planned actions queue */ 109 static bool current_side_has_actions(); 110 111 /** Validates all actions of the current viewing side */ 112 void validate_viewer_actions(); 113 114 /** Whether the planned unit map is currently applied */ has_planned_unit_map() const115 bool has_planned_unit_map() const { return planned_unit_map_active_; } 116 117 118 /** 119 * Called from the display before drawing. 120 */ 121 void pre_draw(); 122 /** 123 * Called from the display after drawing. 124 */ 125 void post_draw(); 126 /** 127 * Called from the display when drawing hexes, to allow the whiteboard to 128 * add visual elements. Some visual elements such as arrows and fake units 129 * are not handled through this function, but separately registered with the display. 130 */ 131 void draw_hex(const map_location& hex); 132 133 /** Creates a temporary visual arrow, that follows the cursor, for move creation purposes */ 134 void create_temp_move(); 135 /** Informs whether an arrow is being displayed for move creation purposes */ has_temp_move() const136 bool has_temp_move() const { return route_ && !fake_units_.empty() && !move_arrows_.empty(); } 137 /** Erase the temporary arrow */ 138 void erase_temp_move(); 139 /** Creates a move action for the current side, and erases the temp move. 140 * The move action is inserted at the end of the queue, to be executed last. */ 141 void save_temp_move(); 142 /** @return an iterator to the unit that owns the temp move, resources::gameboard->units().end() if there's none. */ 143 unit_map::iterator get_temp_move_unit() const; 144 145 /** Creates an attack or attack-move action for the current side */ 146 void save_temp_attack(const map_location& attacker_loc, const map_location& defender_loc, int weapon_choice); 147 148 /** Creates a recruit action for the current side 149 * @return true if manager has saved a planned recruit */ 150 bool save_recruit(const std::string& name, int side_num, const map_location& recruit_hex); 151 152 /** Creates a recall action for the current side 153 * @return true if manager has saved a planned recall */ 154 bool save_recall(const unit& unit, int side_num, const map_location& recall_hex); 155 156 /** Creates a suppose-dead action for the current side */ 157 void save_suppose_dead(unit& curr_unit, const map_location& loc); 158 159 /** Executes first action in the queue for current side */ 160 void contextual_execute(); 161 /** Executes all actions for the current turn in sequence 162 * @return true if the there are no more actions left for this turn when the method returns */ 163 bool execute_all_actions(); 164 /** Deletes last action in the queue for current side */ 165 void contextual_delete(); 166 /** Moves the action determined by the UI toward the beginning of the queue */ 167 void contextual_bump_up_action(); 168 /** Moves the action determined by the UI toward the beginning of the queue */ 169 void contextual_bump_down_action(); 170 171 /** Get the highlight visitor instance in use by the manager */ get_highlighter()172 std::weak_ptr<highlighter> get_highlighter() { return highlighter_; } 173 174 /** Checks whether the whiteboard has any planned action on any team */ 175 bool has_actions() const; 176 /** Checks whether the specified unit has at least one planned action */ 177 bool unit_has_actions(unit const* unit) const; 178 179 /** Used to track gold spending per-side when building the planned unit map 180 * Is referenced by the top bar gold display */ 181 int get_spent_gold_for(int side); 182 183 /** Determines whether or not the undo_stack should be cleared. 184 * @todo When there are network allies, only clear the undo stack when we have set a preferences option */ 185 bool should_clear_undo() const; 186 187 /** Displays the whiteboard options dialog. */ 188 void options_dlg(); 189 190 private: 191 /** Transforms the unit map so that it now reflects the future state of things, 192 * i.e. when all planned actions will have been executed */ 193 void set_planned_unit_map(); 194 /** Restore the regular unit map */ 195 void set_real_unit_map(); 196 197 void validate_actions_if_needed(); 198 /** Called by all of the save_***() methods after they have added their action to the queue */ 199 void update_plan_hiding(size_t viewing_team); 200 void update_plan_hiding(); //same as above, but uses wb::viewer_team() as default argument 201 202 /** Tracks whether the whiteboard is active. */ 203 bool active_; 204 bool inverted_behavior_; 205 bool self_activate_once_; 206 #if 0 207 bool print_help_once_; 208 #endif 209 bool wait_for_side_init_; 210 bool planned_unit_map_active_; 211 /** Track whenever we're modifying actions, to avoid dual execution etc. */ 212 bool executing_actions_; 213 /** Track whether we're in the process of executing all actions */ 214 bool executing_all_actions_; 215 /** true if we're in the process of executing all action and should end turn once finished. */ 216 bool preparing_to_end_turn_; 217 /** Track whether the gamestate changed and we need to validate actions. */ 218 bool gamestate_mutated_; 219 220 /** Reference counted "lock" to allow preventing whiteboard activation state changes */ 221 whiteboard_lock activation_state_lock_; 222 /** Reference counted "lock" to prevent the building of the unit map at certain times */ 223 whiteboard_lock unit_map_lock_; 224 225 226 std::unique_ptr<mapbuilder> mapbuilder_; 227 std::shared_ptr<highlighter> highlighter_; 228 229 std::unique_ptr<pathfind::marked_route> route_; 230 231 std::vector<arrow_ptr> move_arrows_; 232 std::vector<fake_unit_ptr> fake_units_; 233 size_t temp_move_unit_underlying_id_; 234 235 const std::unique_ptr<CKey> key_poller_; 236 237 std::vector<map_location> hidden_unit_hexes_; 238 239 ///net_buffer_[i] = whiteboard network data to be sent "from" teams[i]. 240 std::vector<config> net_buffer_; 241 242 ///team_plans_hidden_[i] = whether or not to hide actions from teams[i]. 243 boost::dynamic_bitset<> team_plans_hidden_; 244 245 ///used to keep track of units owning planned moves for visual ghosting/unghosting 246 std::set<size_t> units_owning_moves_; 247 }; 248 249 /** Applies the planned unit map for the duration of the struct's life. 250 * Reverts to real unit map on destruction, unless planned unit map was already applied when the struct was created. */ 251 struct future_map 252 { 253 future_map(); 254 ~future_map(); 255 bool initial_planned_unit_map_; 256 }; 257 258 struct future_map_if 259 { 260 const std::unique_ptr<future_map> future_map_; 261 262 /** @param cond If true, applies the planned unit map for the duration of the struct's life and reverts to real unit map on destruction. 263 No effect if cond == false. 264 */ future_map_ifwb::future_map_if265 future_map_if(bool cond) 266 : future_map_(cond ? new future_map() : nullptr) 267 {} 268 }; 269 270 /** ONLY IF whiteboard is currently active, applies the planned unit map for the duration of the struct's life. 271 * Reverts to real unit map on destruction, unless planned unit map was already applied when the struct was created. */ 272 struct future_map_if_active 273 { 274 future_map_if_active(); 275 ~future_map_if_active(); 276 bool initial_planned_unit_map_; 277 bool whiteboard_active_; 278 }; 279 280 /** Ensures that the real unit map is active for the duration of the struct's life. 281 * On destruction reverts to planned unit map if it was active when the struct was created. */ 282 struct real_map 283 { 284 real_map(); 285 ~real_map(); 286 bool initial_planned_unit_map_; 287 whiteboard_lock unit_map_lock_; 288 }; 289 290 } // end namespace wb 291