The Battle for Wesnoth  1.13.4+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 - 2016 by David White <[email protected]>
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 "vision.hpp"
21 
22 #include "move.hpp"
23 
24 #include "config.hpp"
25 #include "game_display.hpp"
26 #include "game_events/manager.hpp"
27 #include "game_events/pump.hpp"
28 #include "log.hpp"
29 #include "map/map.hpp"
30 #include "map/label.hpp"
31 #include "map/location.hpp"
32 #include "pathfind/pathfind.hpp"
33 #include "play_controller.hpp"
34 #include "resources.hpp"
35 #include "team.hpp"
36 #include "units/unit.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::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::teams)[viewer.side()-1]);
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_.push_back(sight_data(seen.underlying_id(), seen_loc,
163  sighter_id, sighter_loc));
164 }
165 
166 
167 /**
168  * Default constructor.
169  */
170 shroud_clearer::shroud_clearer() : jamming_(), sightings_(), view_team_(nullptr)
171 {}
172 
173 
174 /**
175  * Destructor.
176  * The purpose of explicitly defining this is so we can log an error if the
177  * sighted events were neither fired nor explicitly ignored.
178  */
180 {
181  if ( !sightings_.empty() ) {
182  ERR_NG << sightings_.size() << " sighted events were ignored." << std::endl;
183  }
184 }
185 
186 /**
187  * Causes this object's "jamming" map to be recalculated.
188  * This gets called as needed, and can also be manually invoked
189  * via cache_units().
190  * @param[in] new_team The team whose vision will be used. If nullptr, the
191  * jamming map will be cleared.
192  */
194 {
195  // Reset data.
196  jamming_.clear();
197  view_team_ = new_team;
198 
199  if ( view_team_ == nullptr )
200  return;
201 
202  // Build the map.
204 }
205 
206 
207 /**
208  * Clears shroud from a single location.
209  * This also records sighted events for later firing.
210  *
211  * In a few cases, this will also clear corner hexes that otherwise would
212  * not normally get cleared.
213  * @param tm The team whose fog/shroud is affected.
214  * @param loc The location to clear.
215  * @param view_loc The location viewer is assumed at (for sighted events).
216  * @param event_non_loc The unit at this location cannot be sighted
217  * (used to prevent a unit from sighting itself).
218  * @param viewer_id The underlying ID of the unit doing the sighting (for events).
219  * @param check_units If false, there is no checking for an uncovered unit.
220  * @param enemy_count Incremented if an enemy is uncovered.
221  * @param friend_count Incremented if a friend is uncovered.
222  * @param spectator Will be told if a unit is uncovered.
223  *
224  * @return whether or not information was uncovered (i.e. returns true if
225  * the specified location was fogged/ shrouded under shared vision/maps).
226  */
228  const map_location &view_loc,
229  const map_location &event_non_loc,
230  size_t viewer_id, bool check_units,
231  size_t &enemy_count, size_t &friend_count,
232  move_unit_spectator * spectator)
233 {
234  const gamemap &map = resources::gameboard->map();
235  // This counts as clearing a tile for the return value if it is on the
236  // board and currently fogged under shared vision. (No need to explicitly
237  // check for shrouded since shrouded implies fogged.)
238  bool was_fogged = tm.fogged(loc);
239  bool result = was_fogged && map.on_board(loc);
240 
241  // Clear the border as well as the board, so that the half-hexes
242  // at the edge can also be cleared of fog/shroud.
243  if ( map.on_board_with_border(loc) ) {
244  // Both functions should be executed so don't use || which
245  // uses short-cut evaluation.
246  // (This is different than the return value because shared vision does
247  // not apply here.)
248  if ( tm.clear_shroud(loc) | tm.clear_fog(loc) ) {
249  // If we are near a corner, the corner might also need to be cleared.
250  // This happens at the lower-left corner and at either the upper- or
251  // lower- right corner (depending on the width).
252 
253  // Lower-left corner:
254  if ( loc.x == 0 && loc.y == map.h()-1 ) {
255  const map_location corner(-1, map.h());
256  tm.clear_shroud(corner);
257  tm.clear_fog(corner);
258  }
259  // Lower-right corner, odd width:
260  else if ( is_odd(map.w()) && loc.x == map.w()-1 && loc.y == map.h()-1 ) {
261  const map_location corner(map.w(), map.h());
262  tm.clear_shroud(corner);
263  tm.clear_fog(corner);
264  }
265  // Upper-right corner, even width:
266  else if ( is_even(map.w()) && loc.x == map.w()-1 && loc.y == 0) {
267  const map_location corner(map.w(), -1);
268  tm.clear_shroud(corner);
269  tm.clear_fog(corner);
270  }
271  }
272  }
273 
274  // Possible screen invalidation.
275  if ( was_fogged ) {
277  // Need to also invalidate adjacent hexes to get rid of the
278  // "fog edge" graphics.
279  map_location adjacent[6];
280  get_adjacent_tiles(loc, adjacent);
281  for ( int i = 0; i != 6; ++i )
282  resources::screen->invalidate(adjacent[i]);
283  }
284 
285  // Check for units?
286  if ( result && check_units && loc != event_non_loc ) {
287  // Uncovered a unit?
289  if ( sight_it.valid() ) {
290  record_sighting(*sight_it, loc, viewer_id, view_loc);
291 
292  // Track this?
293  if ( !sight_it->get_state(unit::STATE_PETRIFIED) ) {
294  if ( tm.is_enemy(sight_it->side()) ) {
295  ++enemy_count;
296  if ( spectator )
297  spectator->add_seen_enemy(sight_it);
298  } else {
299  ++friend_count;
300  if ( spectator )
301  spectator->add_seen_friend(sight_it);
302  }
303  }
304  }
305  }
306 
307  return result;
308 }
309 
310 
311 /**
312  * Clears shroud (and fog) around the provided location for @a view_team
313  * based on @a sight_range, @a costs, and @a slowed.
314  * This will also record sighted events, which should be either fired or
315  * explicitly dropped. (The sighter is the unit with underlying id @a viewer_id.)
316  *
317  * This should only be called if delayed shroud updates is off.
318  * It is wasteful to call this if view_team uses neither fog nor shroud.
319  *
320  * @param real_loc The actual location of the viewing unit.
321  * (This is used to avoid having a unit sight itself.)
322  * @param known_units These locations are not checked for uncovered units.
323  * @param enemy_count Incremented for each enemy uncovered (excluding known_units).
324  * @param friend_count Incremented for each friend uncovered (excluding known_units).
325  * @param spectator Will be told of uncovered units (excluding known_units).
326  * @param instant If false, then drawing delays (used to make movement look better) are allowed.
327  *
328  * @return whether or not information was uncovered (i.e. returns true if any
329  * locations in visual range were fogged/shrouded under shared vision/maps).
330  */
331 bool shroud_clearer::clear_unit(const map_location &view_loc, team &view_team,
332  size_t viewer_id, int sight_range, bool slowed,
333  const movetype::terrain_costs & costs,
334  const map_location & real_loc,
335  const std::set<map_location>* known_units,
336  size_t * enemy_count, size_t * friend_count,
337  move_unit_spectator * spectator, bool instant)
338 {
339  // Give animations a chance to progress; see bug #20324.
340  if ( !instant && resources::screen )
341  resources::screen->draw(true);
342 
343  bool cleared_something = false;
344  // Dummy variables to make some logic simpler.
345  size_t enemies=0, friends=0;
346  if ( enemy_count == nullptr )
347  enemy_count = &enemies;
348  if ( friend_count == nullptr )
349  friend_count = &friends;
350 
351  // Make sure the jamming map is up-to-date.
352  if ( view_team_ != &view_team ) {
353  calculate_jamming(&view_team);
354  // Give animations a chance to progress; see bug #20324.
355  if ( !instant && resources::screen )
356  resources::screen->draw(true);
357  }
358 
359  // Determine the hexes to clear.
360  pathfind::vision_path sight(costs, slowed, sight_range, view_loc, jamming_);
361  // Give animations a chance to progress; see bug #20324.
362  if ( !instant && resources::screen )
363  resources::screen->draw(true);
364 
365  // Clear the fog.
366  for (const pathfind::paths::step &dest : sight.destinations) {
367  bool known = known_units && known_units->count(dest.curr) != 0;
368  if ( clear_loc(view_team, dest.curr, view_loc, real_loc, viewer_id, !known,
369  *enemy_count, *friend_count, spectator) )
370  cleared_something = true;
371  }
372  //TODO guard with game_config option
373  for (const map_location &dest : sight.edges) {
374  bool known = known_units && known_units->count(dest) != 0;
375  if ( clear_loc(view_team, dest, view_loc, real_loc, viewer_id, !known,
376  *enemy_count, *friend_count, spectator) )
377  cleared_something = true;
378  }
379 
380  return cleared_something;
381 }
382 
383 
384 /**
385  * Clears shroud (and fog) around the provided location for @a view_team
386  * as if @a viewer was standing there.
387  * This will also record sighted events, which should be either fired or
388  * explicitly dropped.
389  *
390  * This should only be called if delayed shroud updates is off.
391  * It is wasteful to call this if view_team uses neither fog nor shroud.
392  *
393  * @param known_units These locations are not checked for uncovered units.
394  * @param enemy_count Incremented for each enemy uncovered (excluding known_units).
395  * @param friend_count Incremented for each friend uncovered (excluding known_units).
396  * @param spectator Will be told of uncovered units (excluding known_units).
397  * @param instant If false, then drawing delays (used to make movement look better) are allowed.
398  *
399  * @return whether or not information was uncovered (i.e. returns true if any
400  * locations in visual range were fogged/shrouded under shared vision/maps).
401  */
403  const unit &viewer, team &view_team,
404  const std::set<map_location>* known_units,
405  size_t * enemy_count, size_t * friend_count,
406  move_unit_spectator * spectator, bool instant)
407 {
408  // This is just a translation to the more general interface. It is
409  // not inlined so that vision.hpp does not have to include unit.hpp.
410  return clear_unit(view_loc, view_team, viewer.underlying_id(),
411  viewer.vision(), viewer.get_state(unit::STATE_SLOWED),
412  viewer.movement_type().get_vision(), viewer.get_location(),
413  known_units, enemy_count, friend_count, spectator, instant);
414 }
415 
416 
417 /**
418  * Clears shroud (and fog) around the provided location for @a view_team
419  * as if @a viewer was standing there.
420  * This will also record sighted events, which should be either fired or
421  * explicitly dropped.
422  *
423  * This should only be called if delayed shroud updates is off.
424  * It is wasteful to call this if view_team uses neither fog nor shroud.
425  *
426  * @param instant If false, then drawing delays (used to make movement look better) are allowed.
427  *
428  * @return whether or not information was uncovered (i.e. returns true if any
429  * locations in visual range were fogged/shrouded under shared vision/maps).
430  */
431 bool shroud_clearer::clear_unit(const map_location &view_loc, team &view_team,
432  const clearer_info &viewer, bool instant)
433 {
434  // Locate the unit in question.
436  const map_location & real_loc = find_it == resources::units->end() ?
438  find_it->get_location();
439 
440  return clear_unit(view_loc, view_team, viewer.underlying_id,
441  viewer.sight_range, viewer.slowed, viewer.costs,
442  real_loc, nullptr, nullptr, nullptr, nullptr, instant);
443 }
444 
445 
446 /**
447  * Clears shroud (and fog) around the provided location as if @a viewer
448  * was standing there.
449  * This version of shroud_clearer::clear_unit() will abort if the viewer's
450  * team uses neither fog nor shroud. If @a can_delay is left as true, then
451  * this function also aborts on the viewing team's turn if delayed shroud
452  * updates is on. (Not supplying a team suggests that it would be inconvenient
453  * for the caller to check these.)
454  * In addition, if @a invalidate is left as true, invalidate_after_clear()
455  * will be called.
456  * Setting @a instant to false allows some drawing delays that are used to
457  * make movement look better.
458  *
459  * @return whether or not information was uncovered (i.e. returns true if any
460  * locations in visual range were fogged/shrouded under shared vision/maps).
461  */
462 bool shroud_clearer::clear_unit(const map_location &view_loc, const unit &viewer,
463  bool can_delay, bool invalidate, bool instant)
464 {
465  team & viewing_team = (*resources::teams)[viewer.side()-1];
466 
467  // Abort if there is nothing to clear.
468  if ( !viewing_team.fog_or_shroud() )
469  return false;
470  if ( can_delay && !viewing_team.auto_shroud_updates() &&
471  viewer.side() == resources::controller->current_side() )
472  return false;
473 
474  if ( !clear_unit(view_loc, viewer, viewing_team, instant) )
475  // Nothing uncovered.
476  return false;
477 
478  if ( invalidate )
480 
481  return true;
482 }
483 
484 
485 /**
486  * Clears shroud (and fog) at the provided location and its immediate neighbors.
487  * This is an aid for the [teleport] action, allowing the destination to be
488  * cleared before teleporting, while the unit's full visual range gets cleared
489  * after.
490  * The @a viewer is needed for correct firing of sighted events.
491  *
492  * @return whether or not information was uncovered (i.e. returns true if the
493  * locations in question were fogged/shrouded under shared vision/maps).
494  */
495 bool shroud_clearer::clear_dest(const map_location &dest, const unit &viewer)
496 {
497  team & viewing_team = (*resources::teams)[viewer.side()-1];
498  // A pair of dummy variables needed to simplify some logic.
499  size_t enemies, friends;
500 
501  // Abort if there is nothing to clear.
502  if ( !viewing_team.fog_or_shroud() )
503  return false;
504 
505  // Cache some values.
506  const map_location & real_loc = viewer.get_location();
507  const size_t viewer_id = viewer.underlying_id();
508 
509  // Clear the destination.
510  bool cleared_something = clear_loc(viewing_team, dest, dest, real_loc,
511  viewer_id, true, enemies, friends);
512 
513  // Clear the adjacent hexes (will be seen even if vision is 0, and the
514  // graphics do not work so well for an isolated cleared hex).
515  map_location adjacent[6];
516  get_adjacent_tiles(dest, adjacent);
517  for ( int i = 0; i != 6; ++i )
518  if ( clear_loc(viewing_team, adjacent[i], dest, real_loc, viewer_id,
519  true, enemies, friends) )
520  cleared_something = true;
521 
522  if ( cleared_something )
524 
525  return cleared_something;
526 }
527 
528 
529 /**
530  * Clears the record of sighted events from earlier fog/shroud clearing.
531  * This should be called if the events are to be ignored and not fired.
532  * (Non-cleared, non-fired events will be logged as an error.)
533  */
535 {
536  if ( !sightings_.empty() ) {
537  DBG_NG << sightings_.size() << " sighted events were dropped.\n";
538  }
539  sightings_.clear();
540 }
541 
542 
543 /**
544  * Fires the sighted events that were recorded by earlier fog/shroud clearing.
545  * @return true if the events have mutated the game state.
546  */
548 {
549  const unit_map & units = *resources::units;
550 
551  // Possible/probable quick abort.
552  if ( sightings_.empty() )
553  return false;
554 
555  // In case of exceptions, clear sightings_ before processing events.
556  std::vector<sight_data> sight_list;
557  sight_list.swap(sightings_);
558 
559  for (const sight_data & event : sight_list) {
560  // Try to locate the sighting unit.
561  unit_map::const_iterator find_it = units.find(event.sighter_id);
562  const map_location & sight_loc =
563  find_it == units.end() ? map_location::null_location() :
564  find_it->get_location();
565 
566  { // Raise the event based on the latest data.
568  game_events::entity_location(event.seen_loc, event.seen_id),
569  game_events::entity_location(sight_loc, event.sighter_id, event.sighter_loc));
570  }
571  }
572 
573  return resources::game_events->pump()();
574 }
575 
576 
577 /**
578  * The invalidations that should occur after invoking clear_unit().
579  * This is separate since clear_unit() might be invoked several
580  * times in a row, and the invalidations might only need to be done once.
581  */
583 {
587  // The tiles are invalidated as they are cleared, so no need
588  // to invalidate them here.
589 }
590 
591 
592 /**
593  * Returns the sides that cannot currently see @a target.
594  * (Used to cache visibility before a move.)
595  */
596 std::vector<int> get_sides_not_seeing(const unit & target)
597 {
598  const std::vector<team> & teams = *resources::teams;
599  std::vector<int> not_seeing;
600 
601  size_t team_size = teams.size();
602  for ( size_t i = 0; i != team_size; ++i)
603  if ( !target.is_visible_to_team(teams[i], resources::gameboard->map(), false) )
604  // not_see contains side numbers; i is a team index, so add 1.
605  not_seeing.push_back(i+1);
606 
607  return not_seeing;
608 }
609 
610 
611 /**
612  * Fires sighted events for the sides that can see @a target.
613  * If @a cache is supplied, only those sides might get events.
614  * If @a cache is nullptr, all sides might get events.
615  * This function is for the sighting *of* units that clear the shroud; it is
616  * the complement of shroud_clearer::fire_events(), which handles sighting *by*
617  * units that clear the shroud.
618  *
619  * See get_sides_not_seeing() for a way to obtain a cache.
620  *
621  * @returns true if an event has mutated the game state.
622  */
623 bool actor_sighted(const unit & target, const std::vector<int> * cache)
624 /* Current logic:
625  * 1) One event is fired per side that can see the target.
626  * 2) The second unit for the event is one that can see the target, if possible.
627  * 3) If no units on a side can see the target, a second unit is chosen as
628  * close as possible (but this behavior should not be relied on; it is
629  * subject to change at any time, should it become inconvenient).
630  * 4) A side with no units at all will not get a sighted event.
631  * 5) Sides that do not use fog or shroud CAN get sighted events.
632  */
633 {
634  const std::vector<team> & teams = *resources::teams;
635  const size_t teams_size = teams.size();
636  const map_location & target_loc = target.get_location();
637 
638  // Determine the teams that (probably) should get events.
639  std::vector<bool> needs_event(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->map(), 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::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::teams)[side - 1];
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::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::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::teams)[side - 1];
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::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:42
play_controller * controller
Definition: resources.cpp:21
bool uses_shroud() const
Definition: team.hpp:315
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:472
void recalculate_shroud()
Definition: label.cpp:285
Stores a set of terrain costs (for movement, vision, or "jamming").
Definition: movetype.hpp:88
bool is_visible_to_team(team const &team, gamemap const &map, bool const see_all=true) const
Definition: unit.cpp:2333
unit_iterator end()
Definition: map.hpp:311
const map_location & get_location() const
Definition: unit.hpp:286
std::vector< sight_data > sightings_
Definition: vision.hpp:137
void invalidate_game_status()
Function to invalidate the game status displayed on the sidebar.
Definition: display.hpp:299
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3536
bool get_state(const std::string &state) const
Definition: unit.cpp:1289
Definition: unit.hpp:95
size_t underlying_id() const
The unique internal ID of the unit.
Definition: unit.hpp:150
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:331
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:320
void write(config &cfg, const std::string &child_name="", bool merged=true) const
Writes our data to a config.
Definition: movetype.cpp:558
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:274
void refog()
Definition: team.hpp:322
game_display * screen
Definition: resources.cpp:27
bool is_enemy(int n) const
Definition: team.hpp:247
A refinement of paths for use when calculating jamming.
Definition: pathfind.hpp:123
bool actor_sighted(const unit &target, const std::vector< int > *cache)
Fires sighted events for the sides that can see target.
Definition: vision.cpp:623
bool is_odd(T num)
Definition: util.hpp:37
~shroud_clearer()
Destructor.
Definition: vision.cpp:179
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:100
int side() const
Definition: unit.hpp:201
clearer_info(const unit &viewer)
Constructor from a unit.
Definition: vision.cpp:102
virtual void draw()
Draws invalidated items.
Definition: display.cpp:2706
-file sdl_utils.hpp
void calculate_jamming(const team *new_team)
Causes this object's "jamming" map to be recalculated.
Definition: vision.cpp:193
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:495
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:227
static std::vector< team > *& teams
Definition: team.cpp:50
bool contains(const map_location &) const
Definition: pathfind.cpp:510
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
bool fog_or_shroud() const
Definition: team.hpp:317
GLuint64EXT * result
Definition: glew.h:10727
static lg::log_domain log_engine("engine")
bool auto_shroud_updates() const
Definition: team.hpp:335
int current_side() const
Returns the number of the side whose turn it is.
std::vector< team > * teams
Definition: resources.cpp:29
void add_seen_enemy(const unit_map::const_iterator &u)
add the location of new seen enemy
Definition: move.cpp:66
map_location curr
Definition: pathfind.hpp:88
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:357
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:623
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:105
terrain_costs & get_vision()
Definition: movetype.hpp:182
game_board * gameboard
Definition: resources.cpp:20
#define DBG_NG
Definition: vision.cpp:41
Encapsulates the map of the game.
Definition: map.hpp:37
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:705
config & add_child(const std::string &key)
Definition: config.cpp:743
static const map_location & null_location()
Definition: location.hpp:195
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:3525
game_events::manager * game_events
Definition: resources.cpp:24
Encapsulates the map of the game.
Definition: location.hpp:38
Various functions related to moving units.
void drop_events()
Erases the record of sighted events from earlier fog/shroud clearing.
Definition: vision.cpp:534
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:318
int h() const
Effective map height.
Definition: map.hpp:108
#define ERR_NG
Definition: vision.cpp:42
GLuint index
Definition: glew.h:1782
static tcache cache
Definition: minimap.cpp:139
Define the game's event mechanism.
size_t i
Definition: function.cpp:1057
bool fogged(const map_location &loc) const
Definition: team.cpp:575
A refinement of paths for use when calculating vision.
Definition: pathfind.hpp:106
void raise(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Definition: pump.cpp:480
game_events::t_pump & pump()
Definition: manager.cpp:194
virtual const gamemap & map() const
Definition: game_board.hpp:98
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:467
bool fire_events()
Fires the sighted events that were earlier recorded by fog/shroud clearing.
Definition: vision.cpp:547
const team * view_team_
Keeps track of the team associated with jamming_.
Definition: vision.hpp:139
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:60
cl_event event
Definition: glew.h:3070
bool uses_fog() const
Definition: team.hpp:316
const movetype & movement_type() const
Definition: unit.hpp:321
std::map< map_location, int > jamming_
Definition: vision.hpp:136
std::set< map_location > edges
The edges are the non-destination hexes bordering the destinations.
Definition: pathfind.hpp:117
Standard logging facilities (interface).
Container associating units to locations.
Definition: map.hpp:90
Class to encapsulate fog/shroud clearing and the resultant sighted events.
Definition: vision.hpp:58
map_labels & labels()
Definition: display.cpp:2773
unit_iterator find(size_t id)
Definition: map.cpp:285
bool valid() const
Definition: map.hpp:229
movetype::terrain_costs costs
Definition: vision.hpp:46
void invalidate_after_clear()
The invalidations that should occur after invoking clear_unit().
Definition: vision.cpp:582
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
shroud_clearer()
Default constructor.
Definition: vision.cpp:170
std::vector< int > get_sides_not_seeing(const unit &target)
Returns the sides that cannot currently see target.
Definition: vision.cpp:596
static const std::string sighted_str("sighted")
This module contains various pathfinding functions and utilities.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
unit_map * units
Definition: resources.cpp:35
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:173
GLenum target
Definition: glew.h:5190
bool is_even(T num)
Definition: util.hpp:34
int vision() const
Definition: unit.hpp:223