The Battle for Wesnoth  1.17.0-dev
highlighter.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2021
3  by Gabriel Morin <gabrielmorin (at) gmail (dot) 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 
16 /**
17  * @file
18  */
19 
20 #include <algorithm>
21 #include <iterator>
22 #include <functional>
23 
25 
26 #include "whiteboard/action.hpp"
27 #include "whiteboard/attack.hpp"
28 #include "whiteboard/manager.hpp"
29 #include "whiteboard/move.hpp"
30 #include "whiteboard/recall.hpp"
31 #include "whiteboard/recruit.hpp"
34 #include "whiteboard/utility.hpp"
35 
36 #include "arrow.hpp"
37 #include "config.hpp"
38 #include "fake_unit_ptr.hpp"
39 #include "game_board.hpp"
40 #include "game_display.hpp"
41 #include "game_errors.hpp"
42 #include "play_controller.hpp"
43 #include "resources.hpp"
44 #include "units/unit.hpp"
46 #include "units/map.hpp"
47 #include "utils/ranges.hpp"
48 
49 namespace wb
50 {
51 
53  : mouseover_hex_()
54  , exclusive_display_hexes_()
55  , owner_unit_()
56  , selection_candidate_()
57  , selected_action_()
58  , main_highlight_()
59  , secondary_highlights_()
60  , side_actions_(side_actions)
61 {
62 }
63 
65 {
66  try {
68  unhighlight();
69  }
70  } catch (...) {}
71 }
72 
74 {
75  clear();
76 
77  if(!hex.valid()) {
78  return;
79  }
80 
81  real_map ensure_real_map;
82  mouseover_hex_ = hex;
83  //if we're right over a unit, just highlight all of this unit's actions
85  if(it != get_unit_map().end()) {
87 
88  if(resources::gameboard->get_team(it->side()).get_side_actions()->unit_has_actions(*it)) {
90  }
91 
92  //commented code below is to also select the first action of this unit as
93  //the main highlight; it doesn't fit too well in the UI
94 // side_actions::iterator action_it = side_actions_->find_first_action_of(*it);
95 // if(action_it != side_actions_->end()) {
96 // main_highlight_ = *action_it;
97 // }
98  }
99 
100  //Set the execution/deletion/bump targets.
101  if(owner_unit_) {
102  side_actions::iterator itor = side_actions_->find_first_action_of(*owner_unit_);
103  if(itor != side_actions_->end()) {
104  selected_action_ = *itor;
105  }
106  }
107 
108  //Overwrite the above selected_action_ if we find a better one
109  if(side_actions_->empty()) {
110  return;
111  }
113  /**@todo "is_numbering_hex" is not the "correct" criterion by which to
114  * select the highlighted/selected action. It's just convenient for me
115  * to use at the moment since it happens to coincide with the "correct"
116  * criterion, which is to use find_main_highlight.*/
117  if(act->is_numbering_hex(hex)) {
118  selected_action_ = act;
119  break;
120  }
121  }
122 }
123 
125 {
126  unhighlight();
127  main_highlight_.reset();
128  owner_unit_.reset();
129  secondary_highlights_.clear();
130  selected_action_.reset();
131 }
132 
134 {
135  //Find main action to highlight if any, as well as owner unit
137 
138  if(action_ptr main = main_highlight_.lock()) {
139  //Highlight main highlight
140  highlight_main_visitor hm_visitor(*this);
141  main->accept(hm_visitor);
142  }
143 
144  if(owner_unit_) {
145  //Find secondary actions to highlight
147 
148  //Make sure owner unit is the only one displayed in its hex
150  exclusive_display_hexes_.insert(owner_unit_->get_location());
151 
152  if(!secondary_highlights_.empty()) {
153  //Highlight secondary highlights
154  highlight_secondary_visitor hs_visitor(*this);
156  if(action_ptr action = weak.lock()) {
157  action->accept(hs_visitor);
158  }
159  }
160  }
161  }
162 }
163 
165 {
166  unhighlight_visitor uh_visitor(*this);
167 
168  //unhighlight main highlight
169  if(action_ptr main = main_highlight_.lock()) {
170  main->accept(uh_visitor);
171  }
172 
173  //unhighlight secondary highlights
175  if(action_ptr action = weak.lock()) {
176  action->accept(uh_visitor);
177  }
178  }
179 
180  //unhide other units if needed
183  }
184  exclusive_display_hexes_.clear();
185 }
186 
188 {
189  //Last action with a fake unit always gets normal appearance
190  if(move->get_fake_unit()) {
191  side_actions& sa = *resources::gameboard->teams().at(move->team_index()).get_side_actions().get();
192 
193  side_actions::iterator last_action = sa.find_last_action_of(move->get_unit_id());
194  side_actions::iterator second_to_last_action = last_action != sa.end() && last_action != sa.begin() ? last_action - 1 : sa.end();
195 
196  bool this_is_last_action = last_action != sa.end() && move == *last_action;
197  bool last_action_has_fake_unit = last_action != sa.end() && (*last_action)->get_fake_unit();
198  bool this_is_second_to_last_action = (second_to_last_action != sa.end() && move == *second_to_last_action);
199 
200  if(this_is_last_action || (this_is_second_to_last_action && !last_action_has_fake_unit)) {
201  move->get_fake_unit()->anim_comp().set_standing(true);
202  }
203  }
204 }
205 
207 {
208  // Even if we already found an owner_unit_ in the mouseover hex,
209  // action destination hexes usually take priority over that
210  assert(main_highlight_.expired());
211  //@todo re-enable the following assert once I find out what happends to
212  // viewing side assignments after victory
213  //assert(side_actions_->team_index() == display::get_singleton()->viewing_team());
214 
216  if(action_ptr main = main_highlight_.lock()) {
217  owner_unit_ = main->get_unit();
218  }
219 }
220 
222 {
223  assert(owner_unit_);
224  assert(secondary_highlights_.empty());
225 
226  if(owner_unit_ == nullptr) {
227  return;
228  }
229 
230  // List all the actions of owner_unit_
231  std::deque<action_ptr> actions = find_actions_of(*owner_unit_);
232 
233  // Remove main_highlight_ if present
234  actions.erase(std::remove(actions.begin(), actions.end(), main_highlight_.lock()), actions.end());
235 
236  // Copy in secondary_highlights_
237  std::copy(actions.begin(), actions.end(), std::back_inserter(secondary_highlights_));
238 }
239 
240 
242 {
243  if(action_ptr locked = selected_action_.lock()) {
244  return *side_actions_->find_first_action_of(locked->get_unit_id());
245  } else {
246  return action_ptr();
247  }
248 }
250 {
251  if(action_ptr locked = selected_action_.lock()) {
252  return *side_actions_->find_last_action_of(locked->get_unit_id());
253  } else {
254  return action_ptr();
255  }
256 }
257 
259 {
260  return selected_action_.lock();
261 }
262 
264 {
265  if(owner_unit_) {
266  return owner_unit_;
267  } else {
268  return selection_candidate_;
269  }
270 }
271 
273 {
274  if(move->get_arrow()) {
275  move->set_arrow_brightness(move::ARROW_BRIGHTNESS_FOCUS);
276  }
277  if(move->get_fake_unit()) {
278  // TODO: find some highlight animation
279  move->get_fake_unit()->anim_comp().set_ghosted(true);
280  //Make sure the fake unit is the only one displayed in its hex
281  display::get_singleton()->add_exclusive_draw(move->get_fake_unit()->get_location(), *move->get_fake_unit());
282  highlighter_.exclusive_display_hexes_.insert(move->get_fake_unit()->get_location());
283 
284  highlighter_.last_action_redraw(move);
285  }
286 }
287 
289 {
290  // TODO: highlight the attack indicator
291  visit(std::static_pointer_cast<move>(attack));
292 }
293 
295 {
296  if(recruit->get_fake_unit()) {
297  // TODO: find some suitable effect for mouseover on planned recruit.
298 
299  //Make sure the fake unit is the only one displayed in its hex
300  display::get_singleton()->add_exclusive_draw(recruit->get_fake_unit()->get_location(), *recruit->get_fake_unit());
301  highlighter_.exclusive_display_hexes_.insert(recruit->get_fake_unit()->get_location());
302  }
303 }
304 
306 {
307  if(move->get_arrow()) {
308  move->set_arrow_brightness(move::ARROW_BRIGHTNESS_HIGHLIGHTED);
309  }
310  if(move->get_fake_unit()) {
311  move->get_fake_unit()->anim_comp().set_ghosted(true);
312  //Make sure the fake unit is the only one displayed in its hex
313  display::get_singleton()->add_exclusive_draw(move->get_fake_unit()->get_location(), *move->get_fake_unit());
314  highlighter_.exclusive_display_hexes_.insert(move->get_fake_unit()->get_location());
315 
316  highlighter_.last_action_redraw(move);
317  }
318 }
319 
321 {
322  visit(std::static_pointer_cast<move>(attack));
323 }
324 
326 {
327  if(move->get_arrow()) {
328  move->set_arrow_brightness(move::ARROW_BRIGHTNESS_STANDARD);
329  }
330  if(move->get_fake_unit()) {
331  move->get_fake_unit()->anim_comp().set_disabled_ghosted(false);
332 
333  highlighter_.last_action_redraw(move);
334  }
335 }
336 
338 {
339  visit(std::static_pointer_cast<move>(attack));
340 }
341 
343 {
344  if(recall->get_fake_unit()) {
345  //@todo: find some suitable effect for mouseover on planned recall.
346 
347  //Make sure the fake unit is the only one displayed in its hex
348  display::get_singleton()->add_exclusive_draw(recall->get_fake_unit()->get_location(), *recall->get_fake_unit());
349  highlighter_.exclusive_display_hexes_.insert(recall->get_fake_unit()->get_location());
350  }
351 }
353 {
354  assert(resources::gameboard);
355  return resources::gameboard->units();
356 }
357 
358 } // end namespace wb
container::iterator iterator
void remove()
Removes a tip.
Definition: tooltip.cpp:175
iterator end()
Returns the iterator for the position after the last executed action within the actions queue...
Arrows destined to be drawn on the map.
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:92
action_ptr get_delete_target()
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:85
side_actions_ptr side_actions_
Definition: highlighter.hpp:91
std::deque< action_ptr > find_actions_of(const unit &target)
Find the actions of an unit.
Definition: utility.cpp:227
virtual const unit_map & units() const override
Definition: game_board.hpp:112
weak_action_ptr main_highlight_
Definition: highlighter.hpp:88
unit_ptr owner_unit_
Definition: highlighter.hpp:84
void find_main_highlight()
std::shared_ptr< side_actions > side_actions_ptr
Definition: typedefs.hpp:66
weak_action_ptr selected_action_
Definition: highlighter.hpp:87
auto reversed_view(T &container)
Definition: ranges.hpp:28
std::shared_ptr< attack > attack_ptr
Definition: typedefs.hpp:70
void find_secondary_highlights()
map_location mouseover_hex_
Definition: highlighter.hpp:82
unit_map & get_unit_map()
Definitions for the interface to Wesnoth Markup Language (WML).
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
int main(int argc, char **argv)
Definition: SDLMain.mm:115
unit_ptr selection_candidate_
Definition: highlighter.hpp:85
std::shared_ptr< recruit > recruit_ptr
Definition: typedefs.hpp:72
highlighter(side_actions_ptr side_actions)
Definition: highlighter.cpp:52
secondary_highlights_t secondary_highlights_
Definition: highlighter.hpp:89
virtual ~highlighter()
Definition: highlighter.cpp:64
bool valid() const
Definition: location.hpp:89
game_board * gameboard
Definition: resources.cpp:21
std::shared_ptr< action > action_ptr
Definition: typedefs.hpp:62
iterator find_last_action_of(const unit &unit, iterator start_position)
Finds the last action that belongs to this unit, starting the search backwards from the specified pos...
Encapsulates the map of the game.
Definition: location.hpp:38
unit_iterator find(std::size_t id)
Definition: map.cpp:310
pointer get_shared_ptr() const
This is exactly the same as operator-> but it&#39;s slightly more readable, and can replace &*iter syntax...
Definition: map.hpp:218
void set_mouseover_hex(const map_location &hex)
Definition: highlighter.cpp:73
iterator begin()
Returns the iterator for the first (executed earlier) action within the actions queue.
bool add_exclusive_draw(const map_location &loc, unit &unit)
Allows a unit to request to be the only one drawn in its hex.
Definition: display.cpp:428
std::shared_ptr< move > move_ptr
Definition: typedefs.hpp:68
std::weak_ptr< action > weak_action_ptr
Definition: typedefs.hpp:64
action_ptr get_bump_target()
unit_ptr get_selection_target()
std::set< map_location > exclusive_display_hexes_
Definition: highlighter.hpp:83
Container associating units to locations.
Definition: map.hpp:98
std::shared_ptr< recall > recall_ptr
Definition: typedefs.hpp:74
void last_action_redraw(move_ptr)
Redraw the given move action when needed.
virtual void accept(visitor &v)=0
Ensures that the real unit map is active for the duration of the struct&#39;s life.
Definition: manager.hpp:283
action_ptr get_execute_target()
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:33
action_ptr find_action_at(map_location hex, team_filter team_filter)
Find the first action occurring on a given hex.
Definition: utility.cpp:203
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex...
Definition: move.hpp:35
Definition: display.hpp:49
std::string remove_exclusive_draw(const map_location &loc)
Cancels an exclusive draw request.
Definition: display.cpp:441
static game_display * get_singleton()