The Battle for Wesnoth  1.15.1+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 <boost/range/adaptor/reversed.hpp>
22 
23 #include "utils/functional.hpp"
24 
26 
27 #include "whiteboard/action.hpp"
28 #include "whiteboard/attack.hpp"
29 #include "whiteboard/manager.hpp"
30 #include "whiteboard/move.hpp"
31 #include "whiteboard/recall.hpp"
32 #include "whiteboard/recruit.hpp"
35 #include "whiteboard/utility.hpp"
36 
37 #include "arrow.hpp"
38 #include "config.hpp"
39 #include "fake_unit_ptr.hpp"
40 #include "game_board.hpp"
41 #include "game_display.hpp"
42 #include "game_errors.hpp"
43 #include "play_controller.hpp"
44 #include "resources.hpp"
45 #include "units/unit.hpp"
47 #include "units/map.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:189
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:88
action_ptr get_delete_target()
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
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:114
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
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).
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:52
secondary_highlights_t secondary_highlights_
Definition: highlighter.hpp:88
virtual ~highlighter()
Definition: highlighter.cpp:64
bool valid() const
Definition: location.hpp:93
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:42
unit_iterator find(std::size_t id)
Definition: map.cpp:311
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:220
void set_mouseover_hex(const map_location &hex)
Definition: highlighter.cpp:73
int main()
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:399
std::shared_ptr< move > move_ptr
Definition: typedefs.hpp:67
std::weak_ptr< action > weak_action_ptr
Definition: typedefs.hpp:63
boost::intrusive_ptr< unit > unit_ptr
Definition: ptr.hpp:29
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:99
std::shared_ptr< recall > recall_ptr
Definition: typedefs.hpp:73
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
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:32
Definition: display.hpp:48
std::string remove_exclusive_draw(const map_location &loc)
Cancels an exclusive draw request.
Definition: display.cpp:412
static game_display * get_singleton()