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