The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
highlighter.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2016 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
3  Part of the Battle for Wesnoth Project http://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 
25 #include "highlighter.hpp"
26 
27 #include "action.hpp"
28 #include "attack.hpp"
29 #include "manager.hpp"
30 #include "move.hpp"
31 #include "recall.hpp"
32 #include "recruit.hpp"
33 #include "resources.hpp"
34 #include "side_actions.hpp"
35 #include "suppose_dead.hpp"
36 #include "utility.hpp"
37 
38 #include "arrow.hpp"
39 #include "config.hpp"
40 #include "fake_unit_ptr.hpp"
41 #include "game_board.hpp"
42 #include "game_display.hpp"
43 #include "game_errors.hpp"
44 #include "play_controller.hpp"
45 #include "resources.hpp"
46 #include "units/unit.hpp"
48 #include "units/map.hpp"
49 
50 namespace wb
51 {
52 
54  : mouseover_hex_()
55  , exclusive_display_hexes_()
56  , owner_unit_()
57  , selection_candidate_()
58  , selected_action_()
59  , main_highlight_()
60  , secondary_highlights_()
61  , side_actions_(side_actions)
62 {
63 }
64 
66 {
67  try {
69  unhighlight();
70  }
71  } catch (...) {}
72 }
73 
75 {
76  clear();
77 
78  if(!hex.valid()) {
79  return;
80  }
81 
82  real_map ensure_real_map;
83  mouseover_hex_ = hex;
84  //if we're right over a unit, just highlight all of this unit's actions
86  if(it != get_unit_map().end()) {
88 
89  if(resources::teams->at(it->side()-1).get_side_actions()->unit_has_actions(*it)) {
91  }
92 
93  //commented code below is to also select the first action of this unit as
94  //the main highlight; it doesn't fit too well in the UI
95 // side_actions::iterator action_it = side_actions_->find_first_action_of(*it);
96 // if(action_it != side_actions_->end()) {
97 // main_highlight_ = *action_it;
98 // }
99  }
100 
101  //Set the execution/deletion/bump targets.
102  if(owner_unit_) {
103  side_actions::iterator itor = side_actions_->find_first_action_of(*owner_unit_);
104  if(itor != side_actions_->end()) {
106  }
107  }
108 
109  //Overwrite the above selected_action_ if we find a better one
110  if(side_actions_->empty()) {
111  return;
112  }
113  for(action_ptr act : boost::adaptors::reverse(*side_actions_)) {
114  /**@todo "is_numbering_hex" is not the "correct" criterion by which to
115  * select the hightlighted/selected action. It's just convenient for me
116  * to use at the moment since it happens to coincide with the "correct"
117  * criterion, which is to use find_main_highlight.*/
118  if(act->is_numbering_hex(hex)) {
119  selected_action_ = act;
120  break;
121  }
122  }
123 }
124 
126 {
127  unhighlight();
128  main_highlight_.reset();
129  owner_unit_.reset();
130  secondary_highlights_.clear();
131  selected_action_.reset();
132 }
133 
135 {
136  //Find main action to highlight if any, as well as owner unit
138 
139  if(action_ptr main = main_highlight_.lock()) {
140  //Highlight main highlight
141  highlight_main_visitor hm_visitor(*this);
142  main->accept(hm_visitor);
143  }
144 
145  if(owner_unit_) {
146  //Find secondary actions to highlight
148 
149  //Make sure owner unit is the only one displayed in its hex
151  exclusive_display_hexes_.insert(owner_unit_->get_location());
152 
153  if(!secondary_highlights_.empty()) {
154  //Highlight secondary highlights
155  highlight_secondary_visitor hs_visitor(*this);
157  if(action_ptr action = weak.lock()) {
158  action->accept(hs_visitor);
159  }
160  }
161  }
162  }
163 }
164 
166 {
167  unhighlight_visitor uh_visitor(*this);
168 
169  //unhighlight main highlight
170  if(action_ptr main = main_highlight_.lock()) {
171  main->accept(uh_visitor);
172  }
173 
174  //unhighlight secondary highlights
176  if(action_ptr action = weak.lock()) {
177  action->accept(uh_visitor);
178  }
179  }
180 
181  //unhide other units if needed
184  }
185  exclusive_display_hexes_.clear();
186 }
187 
189 {
190  //Last action with a fake unit always gets normal appearance
191  if(move->get_fake_unit()) {
192  side_actions& sa = *resources::teams->at(move->team_index()).get_side_actions();
193  side_actions::iterator last_action = sa.find_last_action_of(*(move->get_unit()));
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() == resources::screen->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()));
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()));
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  resources::screen->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 
285  }
286 }
287 
289 {
290  ///@todo: highlight the attack indicator
291  visit(boost::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  resources::screen->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  resources::screen->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(boost::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(boost::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  resources::screen->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::units);
355  return *resources::units;
356 }
357 
358 } // end namespace wb
container::iterator iterator
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.
action_ptr get_delete_target()
side_actions_ptr side_actions_
Definition: highlighter.hpp:89
weak_action_ptr main_highlight_
Definition: highlighter.hpp:86
boost::shared_ptr< action > action_ptr
Definition: typedefs.hpp:70
unit_ptr owner_unit_
Definition: highlighter.hpp:82
game_display * screen
Definition: resources.cpp:27
void find_main_highlight()
weak_action_ptr selected_action_
Definition: highlighter.hpp:85
void find_secondary_highlights()
map_location mouseover_hex_
Definition: highlighter.hpp:80
unit_map & get_unit_map()
Definitions for the interface to Wesnoth Markup Language (WML).
boost::weak_ptr< action > weak_action_ptr
Definition: typedefs.hpp:72
iterator find_last_action_of(unit const &unit, iterator start_position)
Finds the last action that belongs to this unit, starting the search backwards from the specified pos...
unit_ptr selection_candidate_
Definition: highlighter.hpp:83
static std::string at(const std::string &file, int line)
GLuint GLuint end
Definition: glew.h:1221
std::vector< team > * teams
Definition: resources.cpp:29
highlighter(side_actions_ptr side_actions)
Definition: highlighter.cpp:53
pointer get_shared_ptr() const
Definition: map.hpp:180
bool valid() const
Definition: location.hpp:69
secondary_highlights_t secondary_highlights_
Definition: highlighter.hpp:87
virtual ~highlighter()
Definition: highlighter.cpp:65
Encapsulates the map of the game.
Definition: location.hpp:38
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
void set_mouseover_hex(const map_location &hex)
Definition: highlighter.cpp:74
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:405
std::deque< action_ptr > find_actions_of(unit const &target)
Find the actions of an unit.
Definition: utility.cpp:209
int main(int argc, char **argv)
action_ptr get_bump_target()
unit_ptr get_selection_target()
std::set< map_location > exclusive_display_hexes_
Definition: highlighter.hpp:81
Container associating units to locations.
Definition: map.hpp:90
const std::string remove
remove directive
unit_iterator find(size_t id)
Definition: map.cpp:285
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's life.
Definition: manager.hpp:279
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 occuring on a given hex.
Definition: utility.cpp:185
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
unit_map * units
Definition: resources.cpp:35
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex...
Definition: move.hpp:33
Definition: display.hpp:47
std::string remove_exclusive_draw(const map_location &loc)
Cancels an exclusive draw request.
Definition: display.cpp:418