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