The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
vision.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
3 by David White <dave@whitevine.net>
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 * Sighting.
19 */
20
21#include "actions/vision.hpp"
22
23#include "actions/move.hpp"
24
25#include "config.hpp"
26#include "game_events/pump.hpp"
27#include "log.hpp"
28#include "map/map.hpp"
29#include "map/label.hpp"
30#include "map/location.hpp"
31#include "pathfind/pathfind.hpp"
32#include "play_controller.hpp"
33#include "resources.hpp"
34#include "team.hpp"
35#include "units/unit.hpp"
36
37
38
39static lg::log_domain log_engine("engine");
40#define DBG_NG LOG_STREAM(debug, log_engine)
41#define ERR_NG LOG_STREAM(err, log_engine)
42
43
44static const std::string sighted_str("sighted");
45
46
47void actions::create_jamming_map(std::map<map_location, int> & jamming,
48 const team & view_team)
49{
50 // Reset the map.
51 jamming.clear();
52
53 // Build the map.
54 for (const unit &u : resources::gameboard->units())
55 {
56 if ( u.jamming() < 1 || !view_team.is_enemy(u.side()) )
57 continue;
58
59 pathfind::jamming_path jam_path(u, u.get_location());
60 for (const pathfind::paths::step& st : jam_path.destinations) {
61 if ( jamming[st.curr] < st.move_left )
62 jamming[st.curr] = st.move_left;
63 }
64 }
65}
66
67
68/**
69 * Determines if @a loc is within @a viewer's visual range.
70 * This is a moderately expensive function (vision is recalculated
71 * with each call), so avoid using it heavily.
72 * If @a jamming is left as nullptr, the jamming map is also calculated
73 * with each invocation.
74 */
75static bool can_see(const unit & viewer, const map_location & loc,
76 const std::map<map_location, int> * jamming = nullptr)
77{
78 // Make sure we have a "jamming" map.
79 std::map<map_location, int> local_jamming;
80 if ( jamming == nullptr ) {
81 actions::create_jamming_map(local_jamming, resources::gameboard->get_team(viewer.side()));
82 jamming = &local_jamming;
83 }
84
85 // Determine which hexes this unit can see.
86 pathfind::vision_path sight(viewer, viewer.get_location(), *jamming);
87
88 return sight.destinations.contains(loc) || sight.edges.count(loc) != 0;
89}
90
91
92namespace actions {
93
94
95/**
96 * Constructor from a unit.
97 */
99 underlying_id(viewer.underlying_id()),
100 sight_range(viewer.vision()),
101 slowed(viewer.get_state(unit::STATE_SLOWED)),
102 costs(viewer.movement_type().get_vision().make_standalone())
103{
104}
105
106/**
107 * Constructor from a config.
108 */
110 underlying_id(cfg["underlying_id"].to_size_t()),
111 sight_range(cfg["vision"].to_int()),
112 slowed(cfg.child_or_empty("status")["slowed"].to_bool()),
113 costs(movetype::read_terrain_costs(cfg.child_or_empty("vision_costs")))
114{
115}
116
117/**
118 * Writes to a config.
119 */
121{
122 // The key and tag names are intended to mirror those used by [unit]
123 // (so a clearer_info can be constructed from a unit's config).
124 cfg["underlying_id"] = underlying_id;
125 cfg["vision"] = sight_range;
126 if ( slowed )
127 cfg.add_child("status")["slowed"] = true;
128 costs->write(cfg, "vision_costs");
129}
130
131
132/**
133 * A record of a sighting event.
134 * Records the unit doing a sighting, the location of that unit at the
135 * time of the sighting, and the location of the sighted unit.
136 */
138 sight_data(std::size_t viewed_id, const map_location & viewed_loc,
139 std::size_t viewer_id, const map_location & viewer_loc) :
140 seen_id(viewed_id), seen_loc(viewed_loc),
141 sighter_id(viewer_id), sighter_loc(viewer_loc)
142 {}
143
144 std::size_t seen_id;
146 std::size_t sighter_id;
148};
149
150
151/**
152 * Convenience wrapper for adding sighting data to the sightings_ vector.
153 */
155 const unit & seen, const map_location & seen_loc,
156 std::size_t sighter_id, const map_location & sighter_loc)
157{
158 sightings_.emplace_back(seen.underlying_id(), seen_loc, sighter_id, sighter_loc);
159}
160
161
162/**
163 * Default constructor.
164 */
165shroud_clearer::shroud_clearer() : jamming_(), sightings_(), view_team_(nullptr)
166{}
167
168
169/**
170 * Destructor.
171 * The purpose of explicitly defining this is so we can log an error if the
172 * sighted events were neither fired nor explicitly ignored.
173 */
175{
176 if ( !sightings_.empty() ) {
177 ERR_NG << sightings_.size() << " sighted events were ignored.";
178 }
179}
180
181/**
182 * Causes this object's "jamming" map to be recalculated.
183 * This gets called as needed, and can also be manually invoked
184 * via cache_units().
185 * @param[in] new_team The team whose vision will be used. If nullptr, the
186 * jamming map will be cleared.
187 */
189{
190 // Reset data.
191 jamming_.clear();
192 view_team_ = new_team;
193
194 if ( view_team_ == nullptr )
195 return;
196
197 // Build the map.
199}
200
201
202/**
203 * Clears shroud from a single location.
204 * This also records sighted events for later firing.
205 *
206 * In a few cases, this will also clear corner hexes that otherwise would
207 * not normally get cleared.
208 * @param tm The team whose fog/shroud is affected.
209 * @param loc The location to clear.
210 * @param view_loc The location viewer is assumed at (for sighted events).
211 * @param event_non_loc The unit at this location cannot be sighted
212 * (used to prevent a unit from sighting itself).
213 * @param viewer_id The underlying ID of the unit doing the sighting (for events).
214 * @param check_units If false, there is no checking for an uncovered unit.
215 * @param enemy_count Incremented if an enemy is uncovered.
216 * @param friend_count Incremented if a friend is uncovered.
217 * @param spectator Will be told if a unit is uncovered.
218 *
219 * @return whether or not information was uncovered (i.e. returns true if
220 * the specified location was fogged/ shrouded under shared vision/maps).
221 */
223 const map_location &view_loc,
224 const map_location &event_non_loc,
225 std::size_t viewer_id, bool check_units,
226 std::size_t &enemy_count, std::size_t &friend_count,
227 move_unit_spectator * spectator)
228{
229 const gamemap &map = resources::gameboard->map();
230 // This counts as clearing a tile for the return value if it is on the
231 // board and currently fogged under shared vision. (No need to explicitly
232 // check for shrouded since shrouded implies fogged.)
233 bool was_fogged = tm.fogged(loc);
234 bool result = was_fogged && map.on_board(loc);
235
236 // Clear the border as well as the board, so that the half-hexes
237 // at the edge can also be cleared of fog/shroud.
238 if ( map.on_board_with_border(loc) ) {
239 // Both functions should be executed so don't use || which uses short-cut evaluation.
240 // (This is different than the return value because shared vision does not apply here.)
241 bool clear_shroud = tm.clear_shroud(loc);
242 bool clear_fog = tm.clear_fog(loc);
243 if ( clear_shroud || clear_fog ) {
244 // If we are near a corner, the corner might also need to be cleared.
245 // This happens at the lower-left corner and at either the upper- or
246 // lower- right corner (depending on the width).
247
248 // Lower-left corner:
249 if ( loc.x == 0 && loc.y == map.h()-1 ) {
250 const map_location corner(-1, map.h());
251 tm.clear_shroud(corner);
252 tm.clear_fog(corner);
253 }
254 // Lower-right corner, odd width:
255 else if ( is_odd(map.w()) && loc.x == map.w()-1 && loc.y == map.h()-1 ) {
256 const map_location corner(map.w(), map.h());
257 tm.clear_shroud(corner);
258 tm.clear_fog(corner);
259 }
260 // Upper-right corner, even width:
261 else if ( is_even(map.w()) && loc.x == map.w()-1 && loc.y == 0) {
262 const map_location corner(map.w(), -1);
263 tm.clear_shroud(corner);
264 tm.clear_fog(corner);
265 }
266 }
267 }
268
269 // Possible screen invalidation.
270 if ( was_fogged ) {
272 // Need to also invalidate adjacent hexes to get rid of the "fog edge" graphics.
273 for(const map_location& adj : get_adjacent_tiles(loc)) {
275 }
276 }
277
278 // Check for units?
279 if ( result && check_units && loc != event_non_loc ) {
280 // Uncovered a unit?
282 if ( sight_it.valid() ) {
283 record_sighting(*sight_it, loc, viewer_id, view_loc);
284
285 // Track this?
286 if ( !sight_it->get_state(unit::STATE_PETRIFIED) ) {
287 if ( tm.is_enemy(sight_it->side()) ) {
288 ++enemy_count;
289 if ( spectator )
290 spectator->add_seen_enemy(sight_it);
291 } else {
292 ++friend_count;
293 if ( spectator )
294 spectator->add_seen_friend(sight_it);
295 }
296 }
297 }
298 }
299
300 return result;
301}
302
303
304/**
305 * Clears shroud (and fog) around the provided location for @a view_team
306 * based on @a sight_range, @a costs, and @a slowed.
307 * This will also record sighted events, which should be either fired or
308 * explicitly dropped. (The sighter is the unit with underlying id @a viewer_id.)
309 *
310 * This should only be called if delayed shroud updates is off.
311 * It is wasteful to call this if view_team uses neither fog nor shroud.
312 *
313 * @param view_loc The location to clear fog from.
314 * @param view_team The team who will have the fog cleared from their map.
315 * @param viewer_id The underlying ID of the unit doing the sighting (for events).
316 * @param sight_range
317 * @param slowed Whether the unit is slowed.
318 * @param costs The terrain costs for the unit.
319 * @param real_loc The actual location of the viewing unit.
320 * (This is used to avoid having a unit sight itself.)
321 * @param known_units These locations are not checked for uncovered units.
322 * @param enemy_count Incremented for each enemy uncovered (excluding known_units).
323 * @param friend_count Incremented for each friend uncovered (excluding known_units).
324 * @param spectator Will be told of uncovered units (excluding known_units).
325 * @param instant If false, then drawing delays (used to make movement look better) are allowed.
326 *
327 * @return whether or not information was uncovered (i.e. returns true if any
328 * locations in visual range were fogged/shrouded under shared vision/maps).
329 */
330bool shroud_clearer::clear_unit(const map_location &view_loc, team &view_team,
331 std::size_t viewer_id, int sight_range, bool slowed,
332 const movetype::terrain_costs & costs,
333 const map_location & real_loc,
334 const std::set<map_location>* known_units,
335 std::size_t * enemy_count, std::size_t * friend_count,
336 move_unit_spectator * spectator, bool /*instant*/)
337{
338 bool cleared_something = false;
339 // Dummy variables to make some logic simpler.
340 std::size_t enemies=0, friends=0;
341 if ( enemy_count == nullptr )
342 enemy_count = &enemies;
343 if ( friend_count == nullptr )
344 friend_count = &friends;
345
346 // Make sure the jamming map is up-to-date.
347 if ( view_team_ != &view_team ) {
348 calculate_jamming(&view_team);
349 }
350
351 // Determine the hexes to clear.
352 pathfind::vision_path sight(costs, slowed, sight_range, view_loc, jamming_);
353
354 // Clear the fog.
355 for (const pathfind::paths::step &dest : sight.destinations) {
356 bool known = known_units && known_units->count(dest.curr) != 0;
357 if ( clear_loc(view_team, dest.curr, view_loc, real_loc, viewer_id, !known,
358 *enemy_count, *friend_count, spectator) )
359 cleared_something = true;
360 }
361 //TODO guard with game_config option
362 for (const map_location &dest : sight.edges) {
363 bool known = known_units && known_units->count(dest) != 0;
364 if ( clear_loc(view_team, dest, view_loc, real_loc, viewer_id, !known,
365 *enemy_count, *friend_count, spectator) )
366 cleared_something = true;
367 }
368
369 return cleared_something;
370}
371
372
373/**
374 * Clears shroud (and fog) around the provided location for @a view_team
375 * as if @a viewer was standing there.
376 * This will also record sighted events, which should be either fired or
377 * explicitly dropped.
378 *
379 * This should only be called if delayed shroud updates is off.
380 * It is wasteful to call this if view_team uses neither fog nor shroud.
381 *
382 * @param view_loc The location to clear fog from.
383 * @param viewer The unit whose vision range will be used to clear the fog.
384 * @param view_team The team who will have the fog cleared from their map.
385 * @param known_units These locations are not checked for uncovered units.
386 * @param enemy_count Incremented for each enemy uncovered (excluding known_units).
387 * @param friend_count Incremented for each friend uncovered (excluding known_units).
388 * @param spectator Will be told of uncovered units (excluding known_units).
389 * @param instant If false, then drawing delays (used to make movement look better) are allowed.
390 *
391 * @return whether or not information was uncovered (i.e. returns true if any
392 * locations in visual range were fogged/shrouded under shared vision/maps).
393 */
395 const unit &viewer, team &view_team,
396 const std::set<map_location>* known_units,
397 std::size_t * enemy_count, std::size_t * friend_count,
398 move_unit_spectator * spectator, bool instant)
399{
400 // This is just a translation to the more general interface. It is
401 // not inlined so that vision.hpp does not have to include unit.hpp.
402 return clear_unit(view_loc, view_team, viewer.underlying_id(),
403 viewer.vision(), viewer.get_state(unit::STATE_SLOWED),
404 viewer.movement_type().get_vision(), viewer.get_location(),
405 known_units, enemy_count, friend_count, spectator, instant);
406}
407
408
409/**
410 * Clears shroud (and fog) around the provided location for @a view_team
411 * as if @a viewer was standing there.
412 * This will also record sighted events, which should be either fired or
413 * explicitly dropped.
414 *
415 * This should only be called if delayed shroud updates is off.
416 * It is wasteful to call this if view_team uses neither fog nor shroud.
417 *
418 * @param view_loc The location to clear fog from.
419 * @param viewer The unit whose vision range will be used to clear the fog.
420 * @param view_team The team who will have the fog cleared from their map.
421 * @param instant If false, then drawing delays (used to make movement look better) are allowed.
422 *
423 * @return whether or not information was uncovered (i.e. returns true if any
424 * locations in visual range were fogged/shrouded under shared vision/maps).
425 */
426bool shroud_clearer::clear_unit(const map_location &view_loc, team &view_team,
427 const clearer_info &viewer, bool instant)
428{
429 // Locate the unit in question.
431 const map_location & real_loc = find_it == resources::gameboard->units().end() ?
433 find_it->get_location();
434
435 return clear_unit(view_loc, view_team, viewer.underlying_id,
436 viewer.sight_range, viewer.slowed, *viewer.costs,
437 real_loc, nullptr, nullptr, nullptr, nullptr, instant);
438}
439
440
441/**
442 * Clears shroud (and fog) around the provided location as if @a viewer
443 * was standing there.
444 * This version of shroud_clearer::clear_unit() will abort if the viewer's
445 * team uses neither fog nor shroud. If @a can_delay is left as true, then
446 * this function also aborts on the viewing team's turn if delayed shroud
447 * updates is on. (Not supplying a team suggests that it would be inconvenient
448 * for the caller to check these.)
449 * In addition, if @a invalidate is left as true, invalidate_after_clear()
450 * will be called.
451 * Setting @a instant to false allows some drawing delays that are used to
452 * make movement look better.
453 *
454 * @return whether or not information was uncovered (i.e. returns true if any
455 * locations in visual range were fogged/shrouded under shared vision/maps).
456 */
457bool shroud_clearer::clear_unit(const map_location &view_loc, const unit &viewer,
458 bool can_delay, bool invalidate, bool instant)
459{
460 team & viewing_team = resources::gameboard->get_team(viewer.side());
461
462 // Abort if there is nothing to clear.
463 if ( !viewing_team.fog_or_shroud() )
464 return false;
465 if ( can_delay && !viewing_team.auto_shroud_updates() &&
467 return false;
468
469 if ( !clear_unit(view_loc, viewer, viewing_team, instant) )
470 // Nothing uncovered.
471 return false;
472
473 if ( invalidate )
475
476 return true;
477}
478
479
480/**
481 * Clears shroud (and fog) at the provided location and its immediate neighbors.
482 * This is an aid for the [teleport] action, allowing the destination to be
483 * cleared before teleporting, while the unit's full visual range gets cleared
484 * after.
485 * The @a viewer is needed for correct firing of sighted events.
486 *
487 * @return whether or not information was uncovered (i.e. returns true if the
488 * locations in question were fogged/shrouded under shared vision/maps).
489 */
490bool shroud_clearer::clear_dest(const map_location &dest, const unit &viewer)
491{
492 team & viewing_team = resources::gameboard->get_team(viewer.side());
493 // A pair of dummy variables needed to simplify some logic.
494 std::size_t enemies, friends;
495
496 // Abort if there is nothing to clear.
497 if ( !viewing_team.fog_or_shroud() )
498 return false;
499
500 // Cache some values.
501 const map_location & real_loc = viewer.get_location();
502 const std::size_t viewer_id = viewer.underlying_id();
503
504 // Clear the destination.
505 bool cleared_something = clear_loc(viewing_team, dest, dest, real_loc,
506 viewer_id, true, enemies, friends);
507
508 // Clear the adjacent hexes (will be seen even if vision is 0, and the
509 // graphics do not work so well for an isolated cleared hex).
510 for(const map_location& adj : get_adjacent_tiles(dest)) {
511 if(clear_loc(viewing_team, adj, dest, real_loc, viewer_id, true, enemies, friends)) {
512 cleared_something = true;
513 }
514 }
515
516 if ( cleared_something )
518
519 return cleared_something;
520}
521
522
523/**
524 * Clears the record of sighted events from earlier fog/shroud clearing.
525 * This should be called if the events are to be ignored and not fired.
526 * (Non-cleared, non-fired events will be logged as an error.)
527 */
529{
530 if ( !sightings_.empty() ) {
531 DBG_NG << sightings_.size() << " sighted events were dropped.";
532 }
533 sightings_.clear();
534}
535
536
537/**
538 * Fires the sighted events that were recorded by earlier fog/shroud clearing.
539 * @return true if the events have mutated the game state.
540 */
542{
543 const unit_map & units = resources::gameboard->units();
544
545 // Possible/probable quick abort.
546 if ( sightings_.empty() )
548
549 // In case of exceptions, clear sightings_ before processing events.
550 std::vector<sight_data> sight_list;
551 sight_list.swap(sightings_);
552
553 for (const sight_data & event : sight_list) {
554 // Try to locate the sighting unit.
555 unit_map::const_iterator find_it = units.find(event.sighter_id);
556 const map_location & sight_loc =
557 find_it == units.end() ? map_location::null_location() :
558 find_it->get_location();
559
560 { // Raise the event based on the latest data.
562 game_events::entity_location(event.seen_loc, event.seen_id),
563 game_events::entity_location(sight_loc, event.sighter_id, event.sighter_loc));
564 }
565 }
566
567 return resources::game_events->pump()();
568}
569
570
571/**
572 * The invalidations that should occur after invoking clear_unit().
573 * This is separate since clear_unit() might be invoked several
574 * times in a row, and the invalidations might only need to be done once.
575 */
577{
581 // The tiles are invalidated as they are cleared, so no need
582 // to invalidate them here.
583}
584
585
586/**
587 * Returns the sides that cannot currently see @a target.
588 * (Used to cache visibility before a move.)
589 */
590std::vector<int> get_sides_not_seeing(const unit & target)
591{
592 std::vector<int> not_seeing;
593 for(const team& t : resources::gameboard->teams()) {
594 if(!target.is_visible_to_team(t, false)) {
595 not_seeing.push_back(t.side());
596 }
597 }
598
599 return not_seeing;
600}
601
602/**
603 * Fires sighted events for the sides that can see @a target.
604 * If @a cache is supplied, only those sides might get events.
605 * If @a cache is nullptr, all sides might get events.
606 * This function is for the sighting *of* units that clear the shroud; it is
607 * the complement of shroud_clearer::fire_events(), which handles sighting *by*
608 * units that clear the shroud.
609 *
610 * See get_sides_not_seeing() for a way to obtain a cache.
611 *
612 * @returns true if an event has mutated the game state.
613 */
614game_events::pump_result_t actor_sighted(const unit & target, const std::vector<int> * cache)
615/* Current logic:
616 * 1) One event is fired per side that can see the target.
617 * 2) The second unit for the event is one that can see the target, if possible.
618 * 3) If no units on a side can see the target, a second unit is chosen as
619 * close as possible (but this behavior should not be relied on; it is
620 * subject to change at any time, should it become inconvenient).
621 * 4) A side with no units at all will not get a sighted event.
622 * 5) Sides that do not use fog or shroud CAN get sighted events.
623 */
624{
625 const std::vector<team> & teams = resources::gameboard->teams();
626 const std::size_t teams_size = teams.size();
627 const map_location & target_loc = target.get_location();
628
629 // Determine the teams that (probably) should get events.
630 boost::dynamic_bitset<> needs_event;
631 needs_event.resize(teams_size, cache == nullptr);
632 if ( cache != nullptr ) {
633 // Flag just the sides in the cache as needing events.
634 for (int side : *cache)
635 needs_event[side-1] = true;
636 }
637 // Exclude the target's own team.
638 needs_event[target.side()-1] = false;
639 // Exclude those teams that cannot see the target.
640 for ( std::size_t i = 0; i != teams_size; ++i )
641 needs_event[i] = needs_event[i] && target.is_visible_to_team(teams[i], false);
642
643 // Cache "jamming".
644 std::vector< std::map<map_location, int>> jamming_cache(teams_size);
645 for ( std::size_t i = 0; i != teams_size; ++i )
646 if ( needs_event[i] )
647 create_jamming_map(jamming_cache[i], teams[i]);
648
649 // Look for units that can be used as the second unit in sighted events.
650 std::vector<const unit *> second_units(teams_size, nullptr);
651 std::vector<std::size_t> distances(teams_size, std::numeric_limits<unsigned>::max());
652 for (const unit & viewer : resources::gameboard->units()) {
653 const std::size_t index = viewer.side() - 1;
654 // Does viewer belong to a team for which we still need a unit?
655 if ( needs_event[index] && distances[index] != 0 ) {
656 if ( can_see(viewer, target_loc, &jamming_cache[index]) ) {
657 // Definitely use viewer as the second unit.
658 second_units[index] = &viewer;
659 distances[index] = 0;
660 }
661 else {
662 // Consider viewer as a backup if it is close.
663 std::size_t viewer_distance =
664 distance_between(target_loc, viewer.get_location());
665 if ( viewer_distance < distances[index] ) {
666 second_units[index] = &viewer;
667 distances[index] = viewer_distance;
668 }
669 }
670 }
671 }
672
673 // Raise events for the appropriate teams.
674 const game_events::entity_location target_entity(target);
675 for ( std::size_t i = 0; i != teams_size; ++i )
676 if ( second_units[i] != nullptr ) {
678 }
679
680 // Fire the events and return.
681 return resources::game_events->pump()();
682}
683
684
685/**
686 * Function that recalculates the fog of war.
687 *
688 * This is used at the end of a turn and for the defender at the end of
689 * combat. As a back-up, it is also called when clearing shroud at the
690 * beginning of a turn.
691 * This function does nothing if the indicated side does not use fog.
692 * This function ignores the "delayed shroud updates" setting.
693 * The display is invalidated as needed.
694 *
695 * @param[in] side The side whose fog will be recalculated.
696 */
697void recalculate_fog(int side)
698{
700
701 if (!tm.uses_fog())
702 return;
703
704 // Exclude currently seen units from sighted events.
705 std::set<map_location> visible_locs;
706 for (const unit &u : resources::gameboard->units()) {
707 const map_location & u_location = u.get_location();
708
709 if ( !tm.fogged(u_location) )
710 visible_locs.insert(u_location);
711 }
712
713 tm.refog();
714 // Invalidate the screen before clearing the shroud.
715 // This speeds up the invalidations within clear_shroud_unit().
717
718 shroud_clearer clearer;
719 for (const unit &u : resources::gameboard->units())
720 {
721 if ( u.side() == side )
722 clearer.clear_unit(u.get_location(), u, tm, &visible_locs);
723 }
724 // Update the screen.
725 clearer.invalidate_after_clear();
726
727 // Fire any sighted events we picked up.
728 clearer.fire_events();
729}
730
731
732/**
733 * Function that will clear shroud (and fog) based on current unit positions.
734 *
735 * This will not re-fog hexes unless reset_fog is set to true.
736 * This function will do nothing if the side uses neither shroud nor fog.
737 * This function ignores the "delayed shroud updates" setting.
738 * The display is invalidated as needed.
739 *
740 * @param[in] side The side whose shroud (and fog) will be cleared.
741 * @param[in] reset_fog If set to true, the fog will also be recalculated
742 * (refogging hexes that can no longer be seen).
743 * @param[in] fire_events If set to false, sighted events will not be fired.
744 * @returns true if some shroud/fog is actually cleared away.
745 */
746bool clear_shroud(int side, bool reset_fog, bool fire_events)
747{
749 if (!tm.uses_shroud() && !tm.uses_fog())
750 return false;
751
752 bool result = false;
753
754 shroud_clearer clearer;
755 for (const unit &u : resources::gameboard->units())
756 {
757 if ( u.side() == side )
758 result |= clearer.clear_unit(u.get_location(), u, tm);
759 }
760 // Update the screen.
761 if ( result )
762 clearer.invalidate_after_clear();
763
764 // Sighted events.
765 if ( fire_events )
766 clearer.fire_events();
767 else
768 clearer.drop_events();
769
770 if ( reset_fog ) {
771 // Note: This will not reveal any new tiles, so result is not affected.
772 // Also, we do not have to check fire_events at this point.
773 recalculate_fog(side);
774 }
775
776 return result;
777}
778
779}//namespace actions
map_location loc
Definition move.cpp:172
Various functions related to moving units.
#define ERR_NG
#define DBG_NG
double t
void add_seen_friend(const unit_map::const_iterator &u)
add a location of a seen friend
Definition move.cpp:60
void add_seen_enemy(const unit_map::const_iterator &u)
add the location of new seen enemy
Definition move.cpp:66
Class to encapsulate fog/shroud clearing and the resultant sighted events.
Definition vision.hpp:72
void record_sighting(const unit &seen, const map_location &seen_loc, std::size_t sighter_id, const map_location &sighter_loc)
Convenience wrapper for adding sighting data to the sightings_ vector.
Definition vision.cpp:154
bool clear_loc(team &tm, const map_location &loc, const map_location &view_loc, const map_location &event_non_loc, std::size_t viewer_id, bool check_units, std::size_t &enemy_count, std::size_t &friend_count, move_unit_spectator *spectator=nullptr)
Clears shroud from a single location.
Definition vision.cpp:222
void invalidate_after_clear()
The invalidations that should occur after invoking clear_unit().
Definition vision.cpp:576
void drop_events()
Erases the record of sighted events from earlier fog/shroud clearing.
Definition vision.cpp:528
const team * view_team_
Keeps track of the team associated with jamming_.
Definition vision.hpp:168
void calculate_jamming(const team *new_team)
Causes this object's "jamming" map to be recalculated.
Definition vision.cpp:188
std::vector< sight_data > sightings_
Definition vision.hpp:166
shroud_clearer()
Default constructor.
Definition vision.cpp:165
~shroud_clearer()
Destructor.
Definition vision.cpp:174
std::map< map_location, int > jamming_
Definition vision.hpp:165
bool clear_dest(const map_location &dest, const unit &viewer)
Clears shroud (and fog) at the provided location and its immediate neighbors.
Definition vision.cpp:490
game_events::pump_result_t fire_events()
Fires the sighted events that were earlier recorded by fog/shroud clearing.
Definition vision.cpp:541
bool clear_unit(const map_location &view_loc, team &view_team, std::size_t viewer_id, int sight_range, bool slowed, const movetype::terrain_costs &costs, const map_location &real_loc, const std::set< map_location > *known_units=nullptr, std::size_t *enemy_count=nullptr, std::size_t *friend_count=nullptr, move_unit_spectator *spectator=nullptr, bool instant=true)
Clears shroud (and fog) around the provided location for view_team based on sight_range,...
Definition vision.cpp:330
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
config & add_child(std::string_view key)
Definition config.cpp:436
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition display.cpp:1465
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition display.cpp:2927
void invalidate_game_status()
Function to invalidate the game status displayed on the sidebar.
Definition display.hpp:308
map_labels & labels()
Definition display.cpp:2392
void invalidate_all()
Function to invalidate all tiles.
Definition display.cpp:2920
static display * get_singleton()
Returns the display object if a display object exists.
Definition display.hpp:102
virtual const gamemap & map() const override
virtual const std::vector< team > & teams() const override
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
team & get_team(int i)
virtual const unit_map & units() const override
game_events::wml_event_pump & pump()
Definition manager.cpp:257
void raise(const std::string &event, const std::string &id, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Definition pump.cpp:416
int w() const
Effective map width.
Definition map.hpp:50
int h() const
Effective map height.
Definition map.hpp:53
bool on_board_with_border(const map_location &loc) const
Definition map.cpp:352
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition map.cpp:347
Encapsulates the map of the game.
Definition map.hpp:176
void recalculate_shroud()
Definition label.cpp:279
A const-only interface for how many (movement, vision, or "jamming") points a unit needs for each hex...
Definition movetype.hpp:53
The basic "size" of the unit - flying, small land, large land, etc.
Definition movetype.hpp:44
const terrain_costs & get_vision() const
Definition movetype.hpp:267
int current_side() const
Returns the number of the side whose turn it is.
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
bool uses_shroud() const
Definition team.hpp:344
bool clear_shroud(const map_location &loc)
Definition team.hpp:347
bool fog_or_shroud() const
Definition team.hpp:346
bool auto_shroud_updates() const
Definition team.hpp:366
void refog()
Definition team.hpp:351
bool clear_fog(const map_location &loc)
Definition team.hpp:349
bool is_enemy(int n) const
Definition team.hpp:270
bool uses_fog() const
Definition team.hpp:345
bool fogged(const map_location &loc) const
Definition team.cpp:645
Container associating units to locations.
Definition map.hpp:98
unit_iterator end()
Definition map.hpp:428
unit_iterator find(std::size_t id)
Definition map.cpp:302
This class represents a single unit of a specific type.
Definition unit.hpp:39
Definitions for the interface to Wesnoth Markup Language (WML).
const config * cfg
bool is_visible_to_team(const team &team, bool const see_all=true) const
Definition unit.cpp:2683
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition unit.cpp:1446
int side() const
The side this unit belongs to.
Definition unit.hpp:249
std::size_t underlying_id() const
This unit's unique internal ID.
Definition unit.hpp:298
@ STATE_SLOWED
Definition unit.hpp:775
@ STATE_PETRIFIED
The unit is poisoned - it loses health each turn.
Definition unit.hpp:777
const map_location & get_location() const
The current map location this unit is at.
Definition unit.hpp:1327
const movetype & movement_type() const
Get the unit's movement type.
Definition unit.hpp:1400
int vision() const
Gets the unit's vision points.
Definition unit.hpp:1370
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition location.cpp:584
void get_adjacent_tiles(const map_location &a, utils::span< map_location, 6 > res)
Function which, given a location, will place all adjacent locations in res.
Definition location.cpp:513
Standard logging facilities (interface).
constexpr bool is_even(T num)
Definition math.hpp:31
constexpr bool is_odd(T num)
Definition math.hpp:34
std::vector< int > get_sides_not_seeing(const unit &target)
Returns the sides that cannot currently see target.
Definition vision.cpp:590
bool clear_shroud(int side, bool reset_fog, bool fire_events)
Function that will clear shroud (and fog) based on current unit positions.
Definition vision.cpp:746
game_events::pump_result_t actor_sighted(const unit &target, const std::vector< int > *cache)
Fires sighted events for the sides that can see target.
Definition vision.cpp:614
void create_jamming_map(std::map< map_location, int > &jamming, const team &view_team)
Helper function that creates the map of enemy anti-vision that's needed when creating a pathfinding::...
Definition vision.cpp:47
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition vision.cpp:697
std::tuple< bool, bool > pump_result_t
Definition fwd.hpp:29
game_board * gameboard
Definition resources.cpp:20
game_events::manager * game_events
Definition resources.cpp:24
play_controller * controller
Definition resources.cpp:21
This module contains various pathfinding functions and utilities.
Define the game's event mechanism.
std::unordered_map< std::string, cache_item > cache
Definition sound.cpp:146
Class that stores the part of a unit's data that is needed for fog clearing.
Definition vision.hpp:53
void write(config &cfg) const
Writes to a config.
Definition vision.cpp:120
std::size_t underlying_id
Definition vision.hpp:54
clearer_info(const unit &viewer)
Constructor from a unit.
Definition vision.cpp:98
std::unique_ptr< movetype::terrain_costs > costs
costs is always non-null, all of the constructors initialize it
Definition vision.hpp:58
A record of a sighting event.
Definition vision.cpp:137
sight_data(std::size_t viewed_id, const map_location &viewed_loc, std::size_t viewer_id, const map_location &viewer_loc)
Definition vision.cpp:138
Encapsulates the map of the game.
Definition location.hpp:46
static const map_location & null_location()
Definition location.hpp:103
A refinement of paths for use when calculating jamming.
Definition pathfind.hpp:124
bool contains(const map_location &) const
Definition pathfind.cpp:514
dest_vect destinations
Definition pathfind.hpp:101
A refinement of paths for use when calculating vision.
Definition pathfind.hpp:108
std::set< map_location > edges
The edges are the non-destination hexes bordering the destinations.
Definition pathfind.hpp:117
bool valid() const
Definition map.hpp:273
static lg::log_domain log_engine("engine")
static bool can_see(const unit &viewer, const map_location &loc, const std::map< map_location, int > *jamming=nullptr)
Determines if loc is within viewer's visual range.
Definition vision.cpp:75
static const std::string sighted_str("sighted")
Various functions implementing vision (through fog of war and shroud).
#define i