The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
vision.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2017 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(size_t viewed_id, const map_location & viewed_loc,
143  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  size_t seen_id;
150  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  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  size_t viewer_id, bool check_units,
230  size_t &enemy_count, 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  // Possible screen invalidation.
274  if ( was_fogged ) {
276  // Need to also invalidate adjacent hexes to get rid of the
277  // "fog edge" graphics.
278  map_location adjacent[6];
279  get_adjacent_tiles(loc, adjacent);
280  for ( int i = 0; i != 6; ++i )
281  resources::screen->invalidate(adjacent[i]);
282  }
283 
284  // Check for units?
285  if ( result && check_units && loc != event_non_loc ) {
286  // Uncovered a unit?
288  if ( sight_it.valid() ) {
289  record_sighting(*sight_it, loc, viewer_id, view_loc);
290 
291  // Track this?
292  if ( !sight_it->get_state(unit::STATE_PETRIFIED) ) {
293  if ( tm.is_enemy(sight_it->side()) ) {
294  ++enemy_count;
295  if ( spectator )
296  spectator->add_seen_enemy(sight_it);
297  } else {
298  ++friend_count;
299  if ( spectator )
300  spectator->add_seen_friend(sight_it);
301  }
302  }
303  }
304  }
305 
306  return result;
307 }
308 
309 
310 /**
311  * Clears shroud (and fog) around the provided location for @a view_team
312  * based on @a sight_range, @a costs, and @a slowed.
313  * This will also record sighted events, which should be either fired or
314  * explicitly dropped. (The sighter is the unit with underlying id @a viewer_id.)
315  *
316  * This should only be called if delayed shroud updates is off.
317  * It is wasteful to call this if view_team uses neither fog nor shroud.
318  *
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  */
330 bool shroud_clearer::clear_unit(const map_location &view_loc, team &view_team,
331  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  size_t * enemy_count, size_t * friend_count,
336  move_unit_spectator * spectator, bool instant)
337 {
338  // Give animations a chance to progress; see bug #20324.
339  if ( !instant && resources::screen )
340  resources::screen->draw(true);
341 
342  bool cleared_something = false;
343  // Dummy variables to make some logic simpler.
344  size_t enemies=0, friends=0;
345  if ( enemy_count == nullptr )
346  enemy_count = &enemies;
347  if ( friend_count == nullptr )
348  friend_count = &friends;
349 
350  // Make sure the jamming map is up-to-date.
351  if ( view_team_ != &view_team ) {
352  calculate_jamming(&view_team);
353  // Give animations a chance to progress; see bug #20324.
354  if ( !instant && resources::screen )
355  resources::screen->draw(true);
356  }
357 
358  // Determine the hexes to clear.
359  pathfind::vision_path sight(costs, slowed, sight_range, view_loc, jamming_);
360  // Give animations a chance to progress; see bug #20324.
361  if ( !instant && resources::screen )
362  resources::screen->draw(true);
363 
364  // Clear the fog.
365  for (const pathfind::paths::step &dest : sight.destinations) {
366  bool known = known_units && known_units->count(dest.curr) != 0;
367  if ( clear_loc(view_team, dest.curr, view_loc, real_loc, viewer_id, !known,
368  *enemy_count, *friend_count, spectator) )
369  cleared_something = true;
370  }
371  //TODO guard with game_config option
372  for (const map_location &dest : sight.edges) {
373  bool known = known_units && known_units->count(dest) != 0;
374  if ( clear_loc(view_team, dest, view_loc, real_loc, viewer_id, !known,
375  *enemy_count, *friend_count, spectator) )
376  cleared_something = true;
377  }
378 
379  return cleared_something;
380 }
381 
382 
383 /**
384  * Clears shroud (and fog) around the provided location for @a view_team
385  * as if @a viewer was standing there.
386  * This will also record sighted events, which should be either fired or
387  * explicitly dropped.
388  *
389  * This should only be called if delayed shroud updates is off.
390  * It is wasteful to call this if view_team uses neither fog nor shroud.
391  *
392  * @param known_units These locations are not checked for uncovered units.
393  * @param enemy_count Incremented for each enemy uncovered (excluding known_units).
394  * @param friend_count Incremented for each friend uncovered (excluding known_units).
395  * @param spectator Will be told of uncovered units (excluding known_units).
396  * @param instant If false, then drawing delays (used to make movement look better) are allowed.
397  *
398  * @return whether or not information was uncovered (i.e. returns true if any
399  * locations in visual range were fogged/shrouded under shared vision/maps).
400  */
402  const unit &viewer, team &view_team,
403  const std::set<map_location>* known_units,
404  size_t * enemy_count, size_t * friend_count,
405  move_unit_spectator * spectator, bool instant)
406 {
407  // This is just a translation to the more general interface. It is
408  // not inlined so that vision.hpp does not have to include unit.hpp.
409  return clear_unit(view_loc, view_team, viewer.underlying_id(),
410  viewer.vision(), viewer.get_state(unit::STATE_SLOWED),
411  viewer.movement_type().get_vision(), viewer.get_location(),
412  known_units, enemy_count, friend_count, spectator, instant);
413 }
414 
415 
416 /**
417  * Clears shroud (and fog) around the provided location for @a view_team
418  * as if @a viewer was standing there.
419  * This will also record sighted events, which should be either fired or
420  * explicitly dropped.
421  *
422  * This should only be called if delayed shroud updates is off.
423  * It is wasteful to call this if view_team uses neither fog nor shroud.
424  *
425  * @param instant If false, then drawing delays (used to make movement look better) are allowed.
426  *
427  * @return whether or not information was uncovered (i.e. returns true if any
428  * locations in visual range were fogged/shrouded under shared vision/maps).
429  */
430 bool shroud_clearer::clear_unit(const map_location &view_loc, team &view_team,
431  const clearer_info &viewer, bool instant)
432 {
433  // Locate the unit in question.
435  const map_location & real_loc = find_it == resources::gameboard->units().end() ?
437  find_it->get_location();
438 
439  return clear_unit(view_loc, view_team, viewer.underlying_id,
440  viewer.sight_range, viewer.slowed, viewer.costs,
441  real_loc, nullptr, nullptr, nullptr, nullptr, instant);
442 }
443 
444 
445 /**
446  * Clears shroud (and fog) around the provided location as if @a viewer
447  * was standing there.
448  * This version of shroud_clearer::clear_unit() will abort if the viewer's
449  * team uses neither fog nor shroud. If @a can_delay is left as true, then
450  * this function also aborts on the viewing team's turn if delayed shroud
451  * updates is on. (Not supplying a team suggests that it would be inconvenient
452  * for the caller to check these.)
453  * In addition, if @a invalidate is left as true, invalidate_after_clear()
454  * will be called.
455  * Setting @a instant to false allows some drawing delays that are used to
456  * make movement look better.
457  *
458  * @return whether or not information was uncovered (i.e. returns true if any
459  * locations in visual range were fogged/shrouded under shared vision/maps).
460  */
461 bool shroud_clearer::clear_unit(const map_location &view_loc, const unit &viewer,
462  bool can_delay, bool invalidate, bool instant)
463 {
464  team & viewing_team = resources::gameboard->get_team(viewer.side());
465 
466  // Abort if there is nothing to clear.
467  if ( !viewing_team.fog_or_shroud() )
468  return false;
469  if ( can_delay && !viewing_team.auto_shroud_updates() &&
470  viewer.side() == resources::controller->current_side() )
471  return false;
472 
473  if ( !clear_unit(view_loc, viewer, viewing_team, instant) )
474  // Nothing uncovered.
475  return false;
476 
477  if ( invalidate )
479 
480  return true;
481 }
482 
483 
484 /**
485  * Clears shroud (and fog) at the provided location and its immediate neighbors.
486  * This is an aid for the [teleport] action, allowing the destination to be
487  * cleared before teleporting, while the unit's full visual range gets cleared
488  * after.
489  * The @a viewer is needed for correct firing of sighted events.
490  *
491  * @return whether or not information was uncovered (i.e. returns true if the
492  * locations in question were fogged/shrouded under shared vision/maps).
493  */
494 bool shroud_clearer::clear_dest(const map_location &dest, const unit &viewer)
495 {
496  team & viewing_team = resources::gameboard->get_team(viewer.side());
497  // A pair of dummy variables needed to simplify some logic.
498  size_t enemies, friends;
499 
500  // Abort if there is nothing to clear.
501  if ( !viewing_team.fog_or_shroud() )
502  return false;
503 
504  // Cache some values.
505  const map_location & real_loc = viewer.get_location();
506  const size_t viewer_id = viewer.underlying_id();
507 
508  // Clear the destination.
509  bool cleared_something = clear_loc(viewing_team, dest, dest, real_loc,
510  viewer_id, true, enemies, friends);
511 
512  // Clear the adjacent hexes (will be seen even if vision is 0, and the
513  // graphics do not work so well for an isolated cleared hex).
514  map_location adjacent[6];
515  get_adjacent_tiles(dest, adjacent);
516  for ( int i = 0; i != 6; ++i )
517  if ( clear_loc(viewing_team, adjacent[i], dest, real_loc, viewer_id,
518  true, enemies, friends) )
519  cleared_something = true;
520 
521  if ( cleared_something )
523 
524  return cleared_something;
525 }
526 
527 
528 /**
529  * Clears the record of sighted events from earlier fog/shroud clearing.
530  * This should be called if the events are to be ignored and not fired.
531  * (Non-cleared, non-fired events will be logged as an error.)
532  */
534 {
535  if ( !sightings_.empty() ) {
536  DBG_NG << sightings_.size() << " sighted events were dropped.\n";
537  }
538  sightings_.clear();
539 }
540 
541 
542 /**
543  * Fires the sighted events that were recorded by earlier fog/shroud clearing.
544  * @return true if the events have mutated the game state.
545  */
547 {
549 
550  // Possible/probable quick abort.
551  if ( sightings_.empty() )
553 
554  // In case of exceptions, clear sightings_ before processing events.
555  std::vector<sight_data> sight_list;
556  sight_list.swap(sightings_);
557 
558  for (const sight_data & event : sight_list) {
559  // Try to locate the sighting unit.
560  unit_map::const_iterator find_it = units.find(event.sighter_id);
561  const map_location & sight_loc =
562  find_it == units.end() ? map_location::null_location() :
563  find_it->get_location();
564 
565  { // Raise the event based on the latest data.
567  game_events::entity_location(event.seen_loc, event.seen_id),
568  game_events::entity_location(sight_loc, event.sighter_id, event.sighter_loc));
569  }
570  }
571 
572  return resources::game_events->pump()();
573 }
574 
575 
576 /**
577  * The invalidations that should occur after invoking clear_unit().
578  * This is separate since clear_unit() might be invoked several
579  * times in a row, and the invalidations might only need to be done once.
580  */
582 {
586  // The tiles are invalidated as they are cleared, so no need
587  // to invalidate them here.
588 }
589 
590 
591 /**
592  * Returns the sides that cannot currently see @a target.
593  * (Used to cache visibility before a move.)
594  */
595 std::vector<int> get_sides_not_seeing(const unit & target)
596 {
597  const std::vector<team> & teams = resources::gameboard->teams();
598  std::vector<int> not_seeing;
599 
600  size_t team_size = teams.size();
601  for ( size_t i = 0; i != team_size; ++i)
602  if ( !target.is_visible_to_team(teams[i], *resources::gameboard, false) )
603  // not_see contains side numbers; i is a team index, so add 1.
604  not_seeing.push_back(i+1);
605 
606  return not_seeing;
607 }
608 
609 
610 /**
611  * Fires sighted events for the sides that can see @a target.
612  * If @a cache is supplied, only those sides might get events.
613  * If @a cache is nullptr, all sides might get events.
614  * This function is for the sighting *of* units that clear the shroud; it is
615  * the complement of shroud_clearer::fire_events(), which handles sighting *by*
616  * units that clear the shroud.
617  *
618  * See get_sides_not_seeing() for a way to obtain a cache.
619  *
620  * @returns true if an event has mutated the game state.
621  */
622 game_events::pump_result_t actor_sighted(const unit & target, const std::vector<int> * cache)
623 /* Current logic:
624  * 1) One event is fired per side that can see the target.
625  * 2) The second unit for the event is one that can see the target, if possible.
626  * 3) If no units on a side can see the target, a second unit is chosen as
627  * close as possible (but this behavior should not be relied on; it is
628  * subject to change at any time, should it become inconvenient).
629  * 4) A side with no units at all will not get a sighted event.
630  * 5) Sides that do not use fog or shroud CAN get sighted events.
631  */
632 {
633  const std::vector<team> & teams = resources::gameboard->teams();
634  const size_t teams_size = teams.size();
635  const map_location & target_loc = target.get_location();
636 
637  // Determine the teams that (probably) should get events.
638  boost::dynamic_bitset<> needs_event;
639  needs_event.resize(teams_size, cache == nullptr);
640  if ( cache != nullptr ) {
641  // Flag just the sides in the cache as needing events.
642  for (int side : *cache)
643  needs_event[side-1] = true;
644  }
645  // Exclude the target's own team.
646  needs_event[target.side()-1] = false;
647  // Exclude those teams that cannot see the target.
648  for ( size_t i = 0; i != teams_size; ++i )
649  needs_event[i] = needs_event[i] && target.is_visible_to_team(teams[i], *resources::gameboard, false);
650 
651  // Cache "jamming".
652  std::vector< std::map<map_location, int> > jamming_cache(teams_size);
653  for ( size_t i = 0; i != teams_size; ++i )
654  if ( needs_event[i] )
655  create_jamming_map(jamming_cache[i], teams[i]);
656 
657  // Look for units that can be used as the second unit in sighted events.
658  std::vector<const unit *> second_units(teams_size, nullptr);
659  std::vector<size_t> distances(teams_size, UINT_MAX);
660  for (const unit & viewer : resources::gameboard->units()) {
661  const size_t index = viewer.side() - 1;
662  // Does viewer belong to a team for which we still need a unit?
663  if ( needs_event[index] && distances[index] != 0 ) {
664  if ( can_see(viewer, target_loc, &jamming_cache[index]) ) {
665  // Definitely use viewer as the second unit.
666  second_units[index] = &viewer;
667  distances[index] = 0;
668  }
669  else {
670  // Consider viewer as a backup if it is close.
671  size_t viewer_distance =
672  distance_between(target_loc, viewer.get_location());
673  if ( viewer_distance < distances[index] ) {
674  second_units[index] = &viewer;
675  distances[index] = viewer_distance;
676  }
677  }
678  }
679  }
680 
681  // Raise events for the appropriate teams.
682  const game_events::entity_location target_entity(target);
683  for ( size_t i = 0; i != teams_size; ++i )
684  if ( second_units[i] != nullptr ) {
685  resources::game_events->pump().raise(sighted_str, target_entity, game_events::entity_location(*second_units[i]));
686  }
687 
688  // Fire the events and return.
689  return resources::game_events->pump()();
690 }
691 
692 
693 /**
694  * Function that recalculates the fog of war.
695  *
696  * This is used at the end of a turn and for the defender at the end of
697  * combat. As a back-up, it is also called when clearing shroud at the
698  * beginning of a turn.
699  * This function does nothing if the indicated side does not use fog.
700  * This function ignores the "delayed shroud updates" setting.
701  * The display is invalidated as needed.
702  *
703  * @param[in] side The side whose fog will be recalculated.
704  */
705 void recalculate_fog(int side)
706 {
707  team &tm = resources::gameboard->get_team(side);
708 
709  if (!tm.uses_fog())
710  return;
711 
712  // Exclude currently seen units from sighted events.
713  std::set<map_location> visible_locs;
714  for (const unit &u : resources::gameboard->units()) {
715  const map_location & u_location = u.get_location();
716 
717  if ( !tm.fogged(u_location) )
718  visible_locs.insert(u_location);
719  }
720 
721  tm.refog();
722  // Invalidate the screen before clearing the shroud.
723  // This speeds up the invalidations within clear_shroud_unit().
725 
726  shroud_clearer clearer;
727  for (const unit &u : resources::gameboard->units())
728  {
729  if ( u.side() == side )
730  clearer.clear_unit(u.get_location(), u, tm, &visible_locs);
731  }
732  // Update the screen.
733  clearer.invalidate_after_clear();
734 
735  // Fire any sighted events we picked up.
736  clearer.fire_events();
737 }
738 
739 
740 /**
741  * Function that will clear shroud (and fog) based on current unit positions.
742  *
743  * This will not re-fog hexes unless reset_fog is set to true.
744  * This function will do nothing if the side uses neither shroud nor fog.
745  * This function ignores the "delayed shroud updates" setting.
746  * The display is invalidated as needed.
747  *
748  * @param[in] side The side whose shroud (and fog) will be cleared.
749  * @param[in] reset_fog If set to true, the fog will also be recalculated
750  * (refogging hexes that can no longer be seen).
751  * @param[in] fire_events If set to false, sighted events will not be fired.
752  * @returns true if some shroud/fog is actually cleared away.
753  */
754 bool clear_shroud(int side, bool reset_fog, bool fire_events)
755 {
756  team &tm = resources::gameboard->get_team(side);
757  if (!tm.uses_shroud() && !tm.uses_fog())
758  return false;
759 
760  bool result = false;
761 
762  shroud_clearer clearer;
763  for (const unit &u : resources::gameboard->units())
764  {
765  if ( u.side() == side )
766  result |= clearer.clear_unit(u.get_location(), u, tm);
767  }
768  // Update the screen.
769  if ( result )
770  clearer.invalidate_after_clear();
771 
772  // Sighted events.
773  if ( fire_events )
774  clearer.fire_events();
775  else
776  clearer.drop_events();
777 
778  if ( reset_fog ) {
779  // Note: This will not reveal any new tiles, so result is not affected.
780  // Also, we do not have to check fire_events at this point.
781  recalculate_fog(side);
782  }
783 
784  return result;
785 }
786 
787 
788 }//namespace actions
789 
Class that stores the part of a unit's data that is needed for fog clearing.
Definition: vision.hpp:41
play_controller * controller
Definition: resources.cpp:21
bool uses_shroud() const
Definition: team.hpp:312
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:374
void recalculate_shroud()
Definition: label.cpp:272
Stores a set of terrain costs (for movement, vision, or "jamming").
Definition: movetype.hpp:86
bool is_odd(T num)
Definition: math.hpp:35
virtual const unit_map & units() const
Definition: game_board.hpp:97
unit_iterator end()
Definition: map.hpp:415
std::vector< char_t > string
size_t index(const utf8::string &str, const size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
std::vector< sight_data > sightings_
Definition: vision.hpp:139
void invalidate_game_status()
Function to invalidate the game status displayed on the sidebar.
Definition: display.hpp:287
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3023
This class represents a single unit of a specific type.
Definition: unit.hpp:100
bool clear_unit(const map_location &view_loc, team &view_team, 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, size_t *enemy_count=nullptr, 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:330
A record of a sighting event.
Definition: vision.cpp:141
Various functions implementing vision (through fog of war and shroud).
bool clear_fog(const map_location &loc)
Definition: team.hpp:317
void write(config &cfg, const std::string &child_name="", bool merged=true) const
Writes our data to a config.
Definition: movetype.cpp:554
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.hpp:299
void refog()
Definition: team.hpp:319
game_display * screen
Definition: resources.cpp:27
bool is_enemy(int n) const
Definition: team.hpp:241
A refinement of paths for use when calculating jamming.
Definition: pathfind.hpp:122
~shroud_clearer()
Destructor.
Definition: vision.cpp:178
void record_sighting(const unit &seen, const map_location &seen_loc, size_t sighter_id, const map_location &sighter_loc)
Convenience wrapper for adding sighting data to the sightings_ vector.
Definition: vision.cpp:158
dest_vect destinations
Definition: pathfind.hpp:99
The unit is petrified - it cannot move or be attacked.
Definition: unit.hpp:722
virtual const std::vector< team > & teams() const
Definition: game_board.hpp:92
clearer_info(const unit &viewer)
Constructor from a unit.
Definition: vision.cpp:102
virtual void draw()
Draws invalidated items.
Definition: display.cpp:2476
-file sdl_utils.hpp
void calculate_jamming(const team *new_team)
Causes this object'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:494
bool clear_loc(team &tm, const map_location &loc, const map_location &view_loc, const map_location &event_non_loc, size_t viewer_id, bool check_units, size_t &enemy_count, size_t &friend_count, move_unit_spectator *spectator=nullptr)
Clears shroud from a single location.
Definition: vision.cpp:226
bool contains(const map_location &) const
Definition: pathfind.cpp:520
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:44
bool fog_or_shroud() const
Definition: team.hpp:314
team & get_team(int i)
Definition: game_board.hpp:94
game_events::pump_result_t fire_events()
Fires the sighted events that were earlier recorded by fog/shroud clearing.
Definition: vision.cpp:546
static lg::log_domain log_engine("engine")
bool auto_shroud_updates() const
Definition: team.hpp:332
int current_side() const
Returns the number of the side whose turn it is.
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:720
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1141
map_location curr
Definition: pathfind.hpp:87
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.hpp:382
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:610
bool is_even(T num)
Definition: math.hpp:32
sight_data(size_t viewed_id, const map_location &viewed_loc, size_t viewer_id, const map_location &viewer_loc)
Definition: vision.cpp:142
int w() const
Effective map width.
Definition: map.hpp:90
terrain_costs & get_vision()
Definition: movetype.hpp:180
game_board * gameboard
Definition: resources.cpp:20
#define DBG_NG
Definition: vision.cpp:41
size_t underlying_id() const
This unit's unique internal ID.
Definition: unit.hpp:296
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:705
static const map_location & null_location()
Definition: location.hpp:220
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:3013
game_events::manager * game_events
Definition: resources.cpp:24
Encapsulates the map of the game.
Definition: location.hpp:40
Various functions related to moving units.
void drop_events()
Erases the record of sighted events from earlier fog/shroud clearing.
Definition: vision.cpp:533
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:79
bool clear_shroud(const map_location &loc)
Definition: team.hpp:315
int h() const
Effective map height.
Definition: map.hpp:93
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:508
#define ERR_NG
Definition: vision.cpp:42
const movetype & movement_type() const
Get the unit's movement type.
Definition: unit.hpp:1214
int vision() const
Gets the unit's vision points.
Definition: unit.hpp:1184
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1289
static tcache cache
Definition: minimap.cpp:137
Define the game's event mechanism.
size_t i
Definition: function.cpp:933
bool fogged(const map_location &loc) const
Definition: team.cpp:640
A refinement of paths for use when calculating vision.
Definition: pathfind.hpp:105
config & add_child(config_key_type key)
Definition: config.cpp:456
virtual const gamemap & map() const
Definition: game_board.hpp:96
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:754
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:369
const team * view_team_
Keeps track of the team associated with jamming_.
Definition: vision.hpp:141
void write(config &cfg) const
Writes to a config.
Definition: vision.cpp:124
void add_seen_friend(const unit_map::const_iterator &u)
add a location of a seen friend
Definition: move.cpp:59
bool uses_fog() const
Definition: team.hpp:313
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
Standard logging facilities (interface).
Container associating units to locations.
Definition: map.hpp:99
bool is_visible_to_team(const team &team, const display_context &dc, bool const see_all=true) const
Definition: unit.cpp:2358
Class to encapsulate fog/shroud clearing and the resultant sighted events.
Definition: vision.hpp:57
map_labels & labels()
Definition: display.cpp:2534
game_events::wml_event_pump & pump()
Definition: manager.cpp:226
unit_iterator find(size_t id)
Definition: map.cpp:311
bool valid() const
Definition: map.hpp:276
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:581
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
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:595
static const std::string sighted_str("sighted")
This module contains various pathfinding functions and utilities.
unit_map * units
Definition: resources.cpp:34
int side() const
The side this unit belongs to.
Definition: unit.hpp:244
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:622