The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
highlighter.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2010 - 2025
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 <utility>
23
25
26#include "whiteboard/action.hpp"
27#include "whiteboard/attack.hpp"
29#include "whiteboard/move.hpp"
30#include "whiteboard/recall.hpp"
34
35#include "fake_unit_ptr.hpp"
36#include "game_board.hpp"
37#include "game_display.hpp"
38#include "resources.hpp"
39#include "units/unit.hpp"
41#include "units/map.hpp"
42#include "utils/general.hpp"
43#include "utils/ranges.hpp"
44
45namespace wb
46{
47
49 : mouseover_hex_()
50 , exclusive_display_hexes_()
51 , owner_unit_()
52 , selection_candidate_()
53 , selected_action_()
54 , main_highlight_()
55 , secondary_highlights_()
56 , side_actions_(std::move(side_actions))
57{
58}
59
61{
62 try {
65 }
66 } catch (...) {}
67}
68
70{
71 clear();
72
73 if(!hex.valid()) {
74 return;
75 }
76
77 real_map ensure_real_map;
78 mouseover_hex_ = hex;
79 //if we're right over a unit, just highlight all of this unit's actions
81 if(it != get_unit_map().end()) {
83
84 if(resources::gameboard->get_team(it->side()).get_side_actions()->unit_has_actions(*it)) {
86 }
87
88 //commented code below is to also select the first action of this unit as
89 //the main highlight; it doesn't fit too well in the UI
90// side_actions::iterator action_it = side_actions_->find_first_action_of(*it);
91// if(action_it != side_actions_->end()) {
92// main_highlight_ = *action_it;
93// }
94 }
95
96 //Set the execution/deletion/bump targets.
97 if(owner_unit_) {
98 side_actions::iterator itor = side_actions_->find_first_action_of(*owner_unit_);
99 if(itor != side_actions_->end()) {
100 selected_action_ = *itor;
101 }
102 }
103
104 //Overwrite the above selected_action_ if we find a better one
105 if(side_actions_->empty()) {
106 return;
107 }
109 /**@todo "is_numbering_hex" is not the "correct" criterion by which to
110 * select the highlighted/selected action. It's just convenient for me
111 * to use at the moment since it happens to coincide with the "correct"
112 * criterion, which is to use find_main_highlight.*/
113 if(act->is_numbering_hex(hex)) {
114 selected_action_ = act;
115 break;
116 }
117 }
118}
119
121{
122 unhighlight();
123 main_highlight_.reset();
124 owner_unit_.reset();
125 secondary_highlights_.clear();
126 selected_action_.reset();
127}
128
130{
131 //Find main action to highlight if any, as well as owner unit
133
134 if(action_ptr main = main_highlight_.lock()) {
135 //Highlight main highlight
136 highlight_main_visitor hm_visitor(*this);
137 main->accept(hm_visitor);
138 }
139
140 if(owner_unit_) {
141 //Find secondary actions to highlight
143
144 //Make sure owner unit is the only one displayed in its hex
146 exclusive_display_hexes_.insert(owner_unit_->get_location());
147
148 if(!secondary_highlights_.empty()) {
149 //Highlight secondary highlights
150 highlight_secondary_visitor hs_visitor(*this);
152 if(action_ptr action = weak.lock()) {
153 action->accept(hs_visitor);
154 }
155 }
156 }
157 }
158}
159
161{
162 unhighlight_visitor uh_visitor(*this);
163
164 //unhighlight main highlight
165 if(action_ptr main = main_highlight_.lock()) {
166 main->accept(uh_visitor);
167 }
168
169 //unhighlight secondary highlights
171 if(action_ptr action = weak.lock()) {
172 action->accept(uh_visitor);
173 }
174 }
175
176 //unhide other units if needed
179 }
181}
182
184{
185 //Last action with a fake unit always gets normal appearance
186 if(move->get_fake_unit()) {
187 side_actions& sa = *resources::gameboard->teams().at(move->team_index()).get_side_actions().get();
188
190 side_actions::iterator second_to_last_action = last_action != sa.end() && last_action != sa.begin() ? last_action - 1 : sa.end();
191
192 bool this_is_last_action = last_action != sa.end() && move == *last_action;
193 bool last_action_has_fake_unit = last_action != sa.end() && (*last_action)->get_fake_unit();
194 bool this_is_second_to_last_action = (second_to_last_action != sa.end() && move == *second_to_last_action);
195
196 if(this_is_last_action || (this_is_second_to_last_action && !last_action_has_fake_unit)) {
197 move->get_fake_unit()->anim_comp().set_standing(true);
198 }
199 }
200}
201
203{
204 // Even if we already found an owner_unit_ in the mouseover hex,
205 // action destination hexes usually take priority over that
206 assert(main_highlight_.expired());
207 //@todo re-enable the following assert once I find out what happends to
208 // viewing side assignments after victory
209 //assert(side_actions_->team_index() == display::get_singleton()->viewing_team());
210
212 if(action_ptr main = main_highlight_.lock()) {
213 owner_unit_ = main->get_unit();
214 }
215}
216
218{
219 assert(owner_unit_);
220 assert(secondary_highlights_.empty());
221
222 if(owner_unit_ == nullptr) {
223 return;
224 }
225
226 // List all the actions of owner_unit_
227 std::deque<action_ptr> actions = find_actions_of(*owner_unit_);
228
229 // Remove main_highlight_ if present
231
232 // Copy in secondary_highlights_
233 std::copy(actions.begin(), actions.end(), std::back_inserter(secondary_highlights_));
234}
235
236
238{
239 if(action_ptr locked = selected_action_.lock()) {
240 return *side_actions_->find_first_action_of(locked->get_unit_id());
241 } else {
242 return action_ptr();
243 }
244}
246{
247 if(action_ptr locked = selected_action_.lock()) {
248 return *side_actions_->find_last_action_of(locked->get_unit_id());
249 } else {
250 return action_ptr();
251 }
252}
253
258
260{
261 if(owner_unit_) {
262 return owner_unit_;
263 } else {
265 }
266}
267
269{
270 if(move->get_arrow()) {
272 }
273 if(move->get_fake_unit()) {
274 // TODO: find some highlight animation
275 move->get_fake_unit()->anim_comp().set_ghosted(true);
276 //Make sure the fake unit is the only one displayed in its hex
278 highlighter_.exclusive_display_hexes_.insert(move->get_fake_unit()->get_location());
279
281 }
282}
283
285{
286 // TODO: highlight the attack indicator
287 visit(std::static_pointer_cast<move>(attack));
288}
289
291{
292 if(recruit->get_fake_unit()) {
293 // TODO: find some suitable effect for mouseover on planned recruit.
294
295 //Make sure the fake unit is the only one displayed in its hex
297 highlighter_.exclusive_display_hexes_.insert(recruit->get_fake_unit()->get_location());
298 }
299}
300
302{
303 if(move->get_arrow()) {
305 }
306 if(move->get_fake_unit()) {
307 move->get_fake_unit()->anim_comp().set_ghosted(true);
308 //Make sure the fake unit is the only one displayed in its hex
310 highlighter_.exclusive_display_hexes_.insert(move->get_fake_unit()->get_location());
311
312 highlighter_.last_action_redraw(move);
313 }
314}
315
317{
318 visit(std::static_pointer_cast<move>(attack));
319}
320
322{
323 if(move->get_arrow()) {
325 }
326 if(move->get_fake_unit()) {
327 move->get_fake_unit()->anim_comp().set_disabled_ghosted(false);
328
329 highlighter_.last_action_redraw(move);
330 }
331}
332
334{
335 visit(std::static_pointer_cast<move>(attack));
336}
337
339{
340 if(recall->get_fake_unit()) {
341 //@todo: find some suitable effect for mouseover on planned recall.
342
343 //Make sure the fake unit is the only one displayed in its hex
345 highlighter_.exclusive_display_hexes_.insert(recall->get_fake_unit()->get_location());
346 }
347}
353
354} // end namespace wb
bool add_exclusive_draw(const map_location &loc, const unit &unit)
Allows a unit to request to be the only one drawn in its hex.
Definition display.cpp:366
std::string remove_exclusive_draw(const map_location &loc)
Cancels an exclusive draw request.
Definition display.cpp:373
static display * get_singleton()
Returns the display object if a display object exists.
Definition display.hpp:102
virtual const std::vector< team > & teams() const override
virtual const unit_map & units() const override
static game_display * get_singleton()
Container associating units to locations.
Definition map.hpp:98
unit_iterator find(std::size_t id)
Definition map.cpp:302
Abstract base class for all the whiteboard planned actions.
Definition action.hpp:34
std::size_t team_index() const
Returns the index of the team that owns this action.
Definition action.hpp:84
virtual void accept(visitor &v)=0
virtual ~highlighter()
side_actions_ptr side_actions_
void find_main_highlight()
std::set< map_location > exclusive_display_hexes_
action_ptr get_bump_target()
secondary_highlights_t secondary_highlights_
unit_ptr selection_candidate_
action_ptr get_execute_target()
void set_mouseover_hex(const map_location &hex)
map_location mouseover_hex_
void last_action_redraw(const move_ptr &)
Redraw the given move action when needed.
unit_ptr owner_unit_
highlighter(side_actions_ptr side_actions)
unit_map & get_unit_map()
action_ptr get_delete_target()
weak_action_ptr selected_action_
unit_ptr get_selection_target()
void find_secondary_highlights()
weak_action_ptr main_highlight_
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex.
Definition move.hpp:36
virtual std::size_t get_unit_id() const
Returns the id of the unit targeted by this action.
Definition move.hpp:59
void set_arrow_brightness(ARROW_BRIGHTNESS x) const
Definition move.hpp:98
virtual fake_unit_ptr get_fake_unit()
Definition move.hpp:61
virtual arrow_ptr get_arrow()
Definition move.hpp:77
@ ARROW_BRIGHTNESS_FOCUS
Definition move.hpp:97
@ ARROW_BRIGHTNESS_STANDARD
Definition move.hpp:97
@ ARROW_BRIGHTNESS_HIGHLIGHTED
Definition move.hpp:97
virtual fake_unit_ptr get_fake_unit()
Definition recall.hpp:68
virtual fake_unit_ptr get_fake_unit()
Definition recruit.hpp:73
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
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...
iterator begin()
Returns the iterator for the first (executed earlier) action within the actions queue.
container::iterator iterator
iterator end()
Returns the iterator for the position after the last executed action within the actions queue.
game_board * gameboard
Definition resources.cpp:20
STL namespace.
constexpr auto reverse
Definition ranges.hpp:44
std::size_t erase(Container &container, const Value &value)
Convenience wrapper for using std::remove on a container.
Definition general.hpp:119
Definition display.hpp:45
std::shared_ptr< recruit > recruit_ptr
Definition typedefs.hpp:72
std::weak_ptr< action > weak_action_ptr
Definition typedefs.hpp:64
std::shared_ptr< move > move_ptr
Definition typedefs.hpp:68
std::shared_ptr< action > action_ptr
Definition typedefs.hpp:62
std::shared_ptr< attack > attack_ptr
Definition typedefs.hpp:70
action_ptr find_action_at(map_location hex, const team_filter &team_filter)
Find the first action occurring on a given hex.
Definition utility.cpp:193
std::shared_ptr< side_actions > side_actions_ptr
Definition typedefs.hpp:66
std::deque< action_ptr > find_actions_of(const unit &target)
Find the actions of an unit.
Definition utility.cpp:217
std::shared_ptr< recall > recall_ptr
Definition typedefs.hpp:74
std::shared_ptr< unit > unit_ptr
Definition ptr.hpp:26
int main(int, char **)
Definition sdl3.cpp:25
Encapsulates the map of the game.
Definition location.hpp:46
bool valid() const
Definition location.hpp:111
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
Definition map.hpp:217
Ensures that the real unit map is active for the duration of the struct's life.
Definition manager.hpp:284