The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
move.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  * Movement.
18  */
19 
20 #include "move.hpp"
21 
22 #include "undo.hpp"
23 #include "vision.hpp"
24 
25 #include "config_assign.hpp"
26 #include "game_display.hpp"
27 #include "game_events/manager.hpp"
28 #include "game_events/pump.hpp"
29 #include "game_preferences.hpp"
30 #include "gettext.hpp"
31 #include "hotkey/hotkey_item.hpp"
33 #include "log.hpp"
34 #include "map/map.hpp"
35 #include "mouse_handler_base.hpp"
36 #include "pathfind/pathfind.hpp"
37 #include "replay.hpp"
38 #include "replay_helper.hpp"
39 #include "synced_context.hpp"
40 #include "play_controller.hpp"
41 #include "resources.hpp"
42 #include "units/udisplay.hpp"
43 #include "formula/string_utils.hpp"
44 #include "team.hpp"
45 #include "units/unit.hpp"
47 #include "whiteboard/manager.hpp"
48 
49 #include <deque>
50 #include <map>
51 #include <set>
52 
53 static lg::log_domain log_engine("engine");
54 #define DBG_NG LOG_STREAM(debug, log_engine)
55 
56 
57 namespace actions {
58 
59 
61 {
62  seen_friends_.push_back(u);
63 }
64 
65 
67 {
68  seen_enemies_.push_back(u);
69 }
70 
71 
73 {
74  return ambusher_;
75 }
76 
77 
79 {
80  return failed_teleport_;
81 }
82 
83 
84 const std::vector<unit_map::const_iterator>& move_unit_spectator::get_seen_enemies() const
85 {
86  return seen_enemies_;
87 }
88 
89 
90 const std::vector<unit_map::const_iterator>& move_unit_spectator::get_seen_friends() const
91 {
92  return seen_friends_;
93 }
94 
95 
97 {
98  return unit_;
99 }
100 
101 
103  : ambusher_(units.end()),failed_teleport_(units.end()),seen_enemies_(),seen_friends_(),unit_(units.end())
104 {
105 }
106 
107 
109 {
110 }
111 
113 {
114  ambusher_ = units.end();
115  failed_teleport_ = units.end();
116  seen_enemies_.clear();
117  seen_friends_.clear();
118  unit_ = units.end();
119 }
120 
121 
123 {
124  ambusher_ = u;
125 }
126 
127 
129 {
130  failed_teleport_ = u;
131 }
132 
133 
135 {
136  unit_ = u;
137 }
138 
139 
140 bool get_village(const map_location& loc, int side, bool *action_timebonus, bool fire_event)
141 {
142  std::vector<team> &teams = *resources::teams;
143  team *t = unsigned(side - 1) < teams.size() ? &teams[side - 1] : nullptr;
144  if (t && t->owns_village(loc)) {
145  return false;
146  }
147 
148  bool not_defeated = t && !resources::gameboard->team_is_defeated(*t);
149 
150  bool grants_timebonus = false;
151 
152  int old_owner_side = 0;
153  // We strip the village off all other sides, unless it is held by an ally
154  // and our side is already defeated (and thus we can't occupy it)
155  for(std::vector<team>::iterator i = teams.begin(); i != teams.end(); ++i) {
156  int i_side = i - teams.begin() + 1;
157  if (!t || not_defeated || t->is_enemy(i_side)) {
158  if(i->owns_village(loc)) {
159  old_owner_side = i_side;
160  i->lose_village(loc);
161  }
162  if (side != i_side && action_timebonus) {
163  grants_timebonus = true;
164  }
165  }
166  }
167 
168  if (!t) return false;
169 
170  if(grants_timebonus) {
172  *action_timebonus = true;
173  }
174 
175  if(not_defeated) {
176  if (resources::screen != nullptr) {
178  }
179  return t->get_village(loc, old_owner_side, fire_event ? resources::gamedata : nullptr);
180  }
181 
182  return false;
183 }
184 
185 
186 namespace { // Private helpers for move_unit()
187 
188  /// Helper class for move_unit().
189  class unit_mover : public boost::noncopyable {
190  typedef std::vector<map_location>::const_iterator route_iterator;
191 
192  public:
193  unit_mover(const std::vector<map_location> & route,
194  move_unit_spectator *move_spectator,
195  bool skip_sightings, bool skip_ally_sightings);
196  ~unit_mover();
197 
198  /// Determines how far along the route the unit can expect to move this turn.
199  bool check_expected_movement();
200  /// Attempts to move the unit along the expected path.
201  void try_actual_movement(bool show);
202  /// Does some bookkeeping and event firing, for use after movement.
203  void post_move(undo_list *undo_stack);
204  /// Shows the various on-screen messages, for use after movement.
205  void feedback() const;
206 
207  /// After checking expected movement, this is the expected path.
208  std::vector<map_location> expected_path() const
209  { return std::vector<map_location>(begin_, expected_end_); }
210  /// After moving, this is the final hex reached.
211  const map_location & final_hex() const
212  { return *move_loc_; }
213  /// The number of hexes actually entered.
214  size_t steps_travelled() const
215  { return move_loc_ - begin_; }
216  /// After moving, use this to detect if movement was less than expected.
217  bool stopped_early() const { return expected_end_ != real_end_; }
218  /// After moving, use this to detect if something happened that would
219  /// interrupt movement (even if movement ended for a different reason).
220  bool interrupted(bool include_end_of_move_events=true) const
221  {
222  return ambushed_ || blocked() || sighted_ || teleport_failed_ ||
223  (include_end_of_move_events ? event_mutated_ : event_mutated_mid_move_ ) ||
224  !move_it_.valid();
225  }
226 
227  private: // functions
228  /// Returns whether or not movement was blocked by a non-ambushing enemy.
229  bool blocked() const { return blocked_loc_ != map_location::null_location(); }
230  /// Checks the expected route for hidden units.
231  void cache_hidden_units(const route_iterator & start,
232  const route_iterator & stop);
233  /// Fires the enter_hex or exit_hex event and updates our data as needed.
234  bool fire_hex_event(const std::string & event_name,
235  const route_iterator & current,
236  const route_iterator & other);
237  /// AI moves are supposed to not change the "goto" order.
238  bool is_ai_move() const { return spectator_ != nullptr; }
239  /// Checks how far it appears we can move this turn.
240  route_iterator plot_turn(const route_iterator & start,
241  const route_iterator & stop);
242  /// Updates our stored info after a WML event might have changed something.
243  bool post_wml(const route_iterator & step);
244  bool post_wml() { return post_wml(full_end_); }
245  /// Fires the sighted events that were raised earlier.
246  bool pump_sighted(const route_iterator & from);
247  /// Returns the ambush alert (if any) for the given unit.
248  static std::string read_ambush_string(const unit & ambusher);
249  /// Reveals the unit at the indicated location.
250  void reveal_ambusher(const map_location & hex, bool update_alert=true);
251 
252  /// Returns whether or not undoing this move should be blocked.
253  bool undo_blocked() const
254  { return ambushed_ || blocked() || event_mutated_ || fog_changed_ ||
256 
257  // The remaining private functions are suggested to be inlined because
258  // each is used in only one place. (They are separate functions to ease
259  // code reading.)
260 
261  /// Checks for ambushers around @a hex, setting flags as appropriate.
262  inline void check_for_ambushers(const map_location & hex);
263  /// Makes sure the path is not obstructed by a unit.
264  inline bool check_for_obstructing_unit(const map_location & hex,
265  const map_location & prev_hex);
266  /// Moves the unit the next step.
267  inline bool do_move(const route_iterator & step_from,
268  const route_iterator & step_to,
269  unit_display::unit_mover & animator);
270  /// Clears fog/shroud and handles units being sighted.
271  inline void handle_fog(const map_location & hex, bool new_animation);
272  inline bool is_reasonable_stop(const map_location & hex) const;
273  /// Reveals the units stored in ambushers_ (and blocked_loc_).
274  inline void reveal_ambushers();
275  /// Makes sure the units in ambushers_ still exist.
276  inline void validate_ambushers();
277 
278  private: // data
279  // (The order of the fields is somewhat important for the constructor.)
280 
281  // Movement parameters (these decrease the number of parameters needed
282  // for individual functions).
283  move_unit_spectator * const spectator_;
284  const bool skip_sighting_;
287  // Needed to interface with unit_display::unit_mover.
288  const std::vector<map_location> & route_;
289 
290  // The route to traverse.
291  const route_iterator begin_;
292  const route_iterator full_end_; // The end of the plotted route.
293  route_iterator expected_end_; // The end of this turn's portion of the plotted route.
294  route_iterator ambush_limit_; // How far we can go before encountering hidden units, ignoring allied units.
295  route_iterator obstructed_; // Points to either full_end_ or a hex we cannot enter. This is used so that exit_hex can fire before we decide we cannot enter this hex.
296  route_iterator real_end_; // How far we actually can move this turn.
297 
298  // The unit that is moving.
300 
301  // This data stores the state from before the move started.
302  const int orig_side_;
303  const int orig_moves_;
306 
307  // This data tracks the current state as the move is in progress.
309  team * current_team_; // Will default to the original team if the moving unit becomes invalid.
311  route_iterator move_loc_; // Will point to the last moved-to location (in case the moving unit disappears).
312  size_t do_move_track_; // Tracks whether or not do_move() needs to update the displayed (fake) unit. Should only be touched by do_move() and the constructor.
313 
314  // Data accumulated while making the move.
316  map_location ambush_stop_; // Could be inaccurate if ambushed_ is false.
317  map_location blocked_loc_; // Location of a blocking, enemy, non-ambusher unit.
318  bool ambushed_;
321  bool event_mutated_mid_move_; // Cache of event_mutated_ from just before the end-of-move handling.
323  bool sighted_; // Records if sightings were made that could interrupt movement.
324  bool sighted_stop_; // Records if sightings were made that did interrupt movement (the same as sighted_ unless movement ended for another reason).
327  size_t enemy_count_;
330  std::vector<map_location> ambushers_;
331  std::deque<int> moves_left_; // The front value is what the moving unit's remaining moves should be set to after the next step through the route.
332 
333  shroud_clearer clearer_;
334  };
335 
336 
337  /// This constructor assumes @a route is not empty, and it will assert() that
338  /// there is a unit at route.front().
339  /// Iterators into @a route must remain valid for the life of this object.
340  /// It is assumed that move_spectator is only supplied for AI moves (only
341  /// affects whether or not gotos are changed).
342  unit_mover::unit_mover(const std::vector<map_location> & route,
343  move_unit_spectator *move_spectator,
344  bool skip_sightings, bool skip_ally_sightings) :
345  spectator_(move_spectator),
346  skip_sighting_(skip_sightings),
347  skip_ally_sighting_(skip_ally_sightings),
348  playing_team_is_viewing_(resources::screen->playing_team() ==
349  resources::screen->viewing_team()
350  || resources::screen->show_everything()),
351  route_(route),
352  begin_(route.begin()),
353  full_end_(route.end()),
357  real_end_(begin_),
358  // Unit information:
360  orig_side_(( assert(move_it_ != resources::units->end()),
361  move_it_->side() )),
362  orig_moves_(move_it_->movement_left()),
363  orig_dir_(move_it_->facing()),
364  goto_( is_ai_move() ? move_it_->get_goto() : route.back() ),
367  current_uses_fog_(current_team_->fog_or_shroud() &&
368  current_team_->auto_shroud_updates()),
369  move_loc_(begin_),
370  do_move_track_(resources::game_events->pump().wml_tracking()),
371  // The remaining fields are set to some sort of "zero state".
372  zoc_stop_(map_location::null_location()),
373  ambush_stop_(map_location::null_location()),
374  blocked_loc_(map_location::null_location()),
375  ambushed_(false),
376  show_ambush_alert_(false),
377  event_mutated_(false),
379  fog_changed_(false),
380  sighted_(false),
381  sighted_stop_(false),
382  teleport_failed_(false),
383  report_extra_hex_(false),
384  enemy_count_(0),
385  friend_count_(0),
386  ambush_string_(),
387  ambushers_(),
388  moves_left_(),
389  clearer_()
390  {
391  if ( !is_ai_move() )
392  // Clear the "goto" instruction during movement.
393  // (It will be reset in the destructor if needed.)
395  }
396 
397 
398  unit_mover::~unit_mover()
399  {
400  // Set the "goto" order? (Not if WML set it.)
401  if ( !is_ai_move() && move_it_.valid() &&
402  move_it_->get_goto() == map_location::null_location() )
403  {
404  // Only set the goto if movement was not complete and was not
405  // interrupted.
406  if ( real_end_ != full_end_ && !interrupted(false) ) // End-of-move-events do not cancel a goto. (Use case: tutorial S2.)
407  move_it_->set_goto(goto_);
408  }
409  }
410 
411 
412  // Private inlines:
413 
414  /**
415  * Checks for ambushers around @a hex, setting flags as appropriate.
416  */
417  inline void unit_mover::check_for_ambushers(const map_location & hex)
418  {
419  const unit_map &units = *resources::units;
420 
421  // Need to check each adjacent hex for hidden enemies.
422  map_location adjacent[6];
423  get_adjacent_tiles(hex, adjacent);
424  for ( int i = 0; i != 6; ++i )
425  {
426  const unit_map::const_iterator neighbor_it = units.find(adjacent[i]);
427 
428  if ( neighbor_it != units.end() &&
429  current_team_->is_enemy(neighbor_it->side()) &&
430  neighbor_it->invisible(adjacent[i]) )
431  {
432  // Ambushed!
433  ambushed_ = true;
434  ambush_stop_ = hex;
435  ambushers_.push_back(adjacent[i]);
436  }
437  }
438  }
439 
440 
441  /**
442  * Makes sure the path is not obstructed by a unit.
443  * @param hex The hex to check.
444  * @param prev_hex The previous hex in the route (used to detect a teleport).
445  * @return true if @a hex is obstructed.
446  */
447  inline bool unit_mover::check_for_obstructing_unit(const map_location & hex,
448  const map_location & prev_hex)
449  {
450  const unit_map::const_iterator blocking_unit = resources::units->find(hex);
451 
452  // If no unit, then the path is not obstructed.
453  if ( blocking_unit == resources::units->end() )
454  return false;
455 
456  if ( !tiles_adjacent(hex, prev_hex) ) {
457  // Cannot teleport to an occupied hex.
458  teleport_failed_ = true;
459  return true;
460  }
461 
462  if ( current_team_->is_enemy(blocking_unit->side()) ) {
463  // Trying to go through an enemy.
464  blocked_loc_ = hex;
465  return true;
466  }
467 
468  // If we get here, the unit does not interfere with movement.
469  return false;
470  }
471 
472 
473  /**
474  * Moves the unit the next step.
475  * @a step_to is the hex being moved to.
476  * @a step_from is the hex before that in the route.
477  * (The unit is actually at *move_loc_.)
478  * @a animator is the unit_display::unit_mover being used.
479  * @return whether or not we started a new animation.
480  */
481  inline bool unit_mover::do_move(const route_iterator & step_from,
482  const route_iterator & step_to,
483  unit_display::unit_mover & animator)
484  {
486 
487  // Adjust the movement even if we cannot move yet.
488  // We will eventually be able to move if nothing unexpected
489  // happens, and if something does happen, this movement is the
490  // cost to discover it.
491  move_it_->set_movement(moves_left_.front(), true);
492  moves_left_.pop_front();
493 
494  // Invalidate before moving so we invalidate neighbor hexes if needed.
495  move_it_->anim_comp().invalidate(disp);
496 
497  // Attempt actually moving.
498  // (Fails if *step_to is occupied).
499  std::pair<unit_map::iterator, bool> move_result =
500  resources::units->move(*move_loc_, *step_to);
501  if ( move_result.second )
502  {
503  // Update the moving unit.
504  move_it_ = move_result.first;
505  move_it_->set_facing(step_from->get_relative_dir(*step_to));
506  // Disable bars. The expectation here is that the animation
507  // unit_mover::finish() will clean after us at a later point. Ugly,
508  // but it works.
509  move_it_->anim_comp().set_standing(false);
510  disp.invalidate_unit_after_move(*move_loc_, *step_to);
511  disp.invalidate(*step_to);
512  move_loc_ = step_to;
513 
514  // Show this move.
515  const size_t current_tracking = resources::game_events->pump().wml_tracking();
516  animator.proceed_to(move_it_.get_shared_ptr(), step_to - begin_,
517  current_tracking != do_move_track_, false);
518  do_move_track_ = current_tracking;
519  disp.redraw_minimap();
520  }
521 
522  return move_result.second;
523  }
524 
525 
526  /**
527  * Clears fog/shroud and raises events for units being sighted.
528  * Only call this if the current team uses fog or shroud.
529  * @a hex is both the center of fog clearing and the filtered location of
530  * the moving unit when the sighted events will be fired.
531  */
532  inline void unit_mover::handle_fog(const map_location & hex,
533  bool new_animation)
534  {
535  // Clear the fog.
536  if ( clearer_.clear_unit(hex, *move_it_, *current_team_, nullptr,
538  !new_animation) )
539  {
540  clearer_.invalidate_after_clear();
541  fog_changed_ = true;
542  }
543 
544  // Check for sighted units?
545  if ( !skip_sighting_ ) {
546  sighted_ = enemy_count_ != 0 ;
547  }
549  {
550  sighted_ |= (friend_count_ != 0);
551  }
552  }
553 
554 
555  /**
556  * @return true if an unscheduled stop at @a hex is not likely to negatively
557  * impact the player's plans.
558  * (E.g. it would not kill movement by making an unintended village capture.)
559  */
560  inline bool unit_mover::is_reasonable_stop(const map_location & hex) const
561  {
562  // We cannot reasonably stop if move_it_ could not be moved to this
563  // hex (the hex was occupied by someone else).
564  if ( *move_loc_ != hex )
565  return false;
566 
567  // We can reasonably stop if the hex is not an unowned village.
568  return !resources::gameboard->map().is_village(hex) ||
570  }
571 
572 
573  /**
574  * Reveals the units stored in ambushers_ (and blocked_loc_).
575  * Also sets ambush_string_.
576  * May fire "sighted" events.
577  * Only call this if appropriate; this function does not itself check
578  * ambushed_ or blocked().
579  */
580  inline void unit_mover::reveal_ambushers()
581  {
582  // Reveal the blocking unit.
583  if ( blocked() )
584  reveal_ambusher(blocked_loc_, false);
585 
586  // Reveal ambushers.
587  for(const map_location & reveal : ambushers_) {
588  reveal_ambusher(reveal, true);
589  }
590 
591  // Default "Ambushed!" message?
592  if ( ambush_string_.empty() )
593  ambush_string_ = _("Ambushed!");
594 
595  // Update the display.
597  }
598 
599 
600  /**
601  * Makes sure the units in ambushers_ still exist.
602  */
603  inline void unit_mover::validate_ambushers()
604  {
605  const unit_map &units = *resources::units;
606 
607  // Loop through the previously-detected ambushers.
608  size_t i = 0;
609  while ( i != ambushers_.size() ) {
610  if ( units.count(ambushers_[i]) == 0 )
611  // Ambusher is gone.
612  ambushers_.erase(ambushers_.begin() + i);
613  else {
614  // Proceed to the next ambusher.
615  ++i;
616  }
617  }
618  }
619 
620 
621  // Private utilities:
622 
623  /**
624  * Checks the expected route for hidden units.
625  * This basically handles all the checks for surprises that can be done
626  * without visibly notifying a player. Thus this can be called at the
627  * start of movement and immediately after events, rather than tie up
628  * CPU time in the middle of animating a move.
629  *
630  * @param[in] start The beginning of the path to check.
631  * @param[in] stop The end of the path to check.
632  */
633  void unit_mover::cache_hidden_units(const route_iterator & start,
634  const route_iterator & stop)
635  {
636  // Clear the old cache.
639  teleport_failed_ = false;
640  // The ambush cache needs special treatment since we cannot re-detect
641  // an ambush if we are already at the ambushed location.
643  if ( ambushed_ ) {
644  validate_ambushers();
645  ambushed_ = !ambushers_.empty();
646  }
647  if ( !ambushed_ ) {
648  ambush_stop_ = map_location::null_location();
649  ambushers_.clear();
650  }
651 
652  // Update the shroud clearer.
653  clearer_.cache_units(current_uses_fog_ ? current_team_ : nullptr);
654 
655 
656  // Abort for null routes.
657  if ( start == stop ) {
659  return;
660  }
661 
662  // This loop will end with ambush_limit_ pointing one element beyond
663  // where the unit would be forced to stop by a hidden unit.
664  for ( ambush_limit_ = start+1; ambush_limit_ != stop; ++ambush_limit_ ) {
665  // Check if we need to stop in the previous hex.
666  if ( ambushed_ ) {
667  break;
668  }
669  // Check for being unable to enter this hex.
670  if ( check_for_obstructing_unit(*ambush_limit_, *(ambush_limit_-1)) ) {
671  // No replay check here? Makes some sense, I guess.
672  obstructed_ = ambush_limit_++; // The limit needs to be after obstructed_ in order for the latter to do anything.
673  break;
674  }
675 
676  // We can enter this hex.
677  // See if we are stopped in this hex.
678  check_for_ambushers(*ambush_limit_);
679  }
680  }
681 
682 
683  /**
684  * Fires the enter_hex or exit_hex event and updates our data as needed.
685  *
686  * @param[in] event_name The name of the event ("enter_hex" or "exit_hex").
687  * @param[in] current The currently occupied hex.
688  * @param[in] other The secondary hex to provide to the event.
689  *
690  * @return true if this event should interrupt movement.
691  * (This is also stored in event_mutated_.)
692  */
693  bool unit_mover::fire_hex_event(const std::string & event_name,
694  const route_iterator & current,
695  const route_iterator & other)
696  {
697  const size_t track = resources::game_events->pump().wml_tracking();
698  bool valid = true;
699 
700  const game_events::entity_location mover(*move_it_, *current);
701  const bool event = resources::game_events->pump().fire(event_name, mover, *other);
702 
703  if ( track != resources::game_events->pump().wml_tracking() )
704  // Some WML fired, so update our status.
705  valid = post_wml(current);
706 
707  if ( event || !valid )
708  event_mutated_ = true;
709 
710  return event || !valid;
711  }
712 
713 
714  /**
715  * Checks how far it appears we can move this turn.
716  *
717  * @param[in] start The beginning of the plotted path.
718  * @param[in] stop The end of the plotted path.
719  *
720  * @return An end iterator for the path that can be traversed this turn.
721  */
722  unit_mover::route_iterator unit_mover::plot_turn(const route_iterator & start,
723  const route_iterator & stop)
724  {
725  const gamemap &map = resources::gameboard->map();
726 
727  // Handle null routes.
728  if ( start == stop )
729  return start;
730 
731 
732  int remaining_moves = move_it_->movement_left();
734  moves_left_.clear();
735 
736  if ( start != begin_ ) {
737  // Check for being unable to leave the current hex.
738  if ( !move_it_->get_ability_bool("skirmisher", *start) &&
739  pathfind::enemy_zoc(*current_team_, *start, *current_team_) )
740  zoc_stop_ = *start;
741  }
742 
743  // This loop will end with end pointing one element beyond where the
744  // unit thinks it will stop (the usual notion of "end" for iterators).
745  route_iterator end = start + 1;
746  for ( ; end != stop; ++end )
747  {
748  // Break out of the loop if we cannot leave the previous hex.
750  break;
751  }
752  remaining_moves -= move_it_->movement_cost(map[*end]);
753  if ( remaining_moves < 0 ) {
754  break;
755  }
756 
757  // We can enter this hex. Record the cost.
758  moves_left_.push_back(remaining_moves);
759 
760  // Check for being unable to leave this hex.
761  if ( !move_it_->get_ability_bool("skirmisher", *end) &&
762  pathfind::enemy_zoc(*current_team_, *end, *current_team_) )
763  zoc_stop_ = *end;
764  }
765 
766  if ( true ) {
767  // Avoiding stopping on a (known) unit.
768  route_iterator min_end = start == begin_ ? start : start + 1;
769  while ( end != min_end && resources::gameboard->has_visible_unit(*(end-1), *current_team_) )
770  // Backtrack.
771  --end;
772  }
773 
774  return end;
775  }
776 
777 
778  /**
779  * Updates our stored info after a WML event might have changed something.
780  *
781  * @param step Indicates the position in the path where we might need to start recalculating movement.
782  * Set this to full_end_ (or do not supply it) to skip such recalculations (because movement has finished).
783  *
784  * @returns false if continuing is impossible (i.e. we lost the moving unit).
785  */
786  bool unit_mover::post_wml(const route_iterator & step)
787  {
788  // Re-find the moving unit.
790  const bool found = move_it_ != resources::units->end();
791 
792  // Update the current unit data.
793  current_side_ = found ? move_it_->side() : orig_side_;
794  current_team_ = &(*resources::teams)[current_side_-1];
795  current_uses_fog_ = current_team_->fog_or_shroud() &&
796  ( current_side_ != orig_side_ ||
797  current_team_->auto_shroud_updates() );
798 
799  // Update the path.
800  if ( found && step != full_end_ ) {
801  const route_iterator new_limit = plot_turn(step, expected_end_);
802  cache_hidden_units(step, new_limit);
803  // Just in case: length 0 paths become length 1 paths.
804  if ( ambush_limit_ == step )
805  ++ambush_limit_;
806  }
807 
808  return found;
809  }
810 
811 
812  /**
813  * Fires the sighted events that were raised earlier.
814  *
815  * @param[in] from Points to the hex the sighting unit currently occupies.
816  *
817  * @return true if this event should interrupt movement.
818  */
819  bool unit_mover::pump_sighted(const route_iterator & from)
820  {
821  const size_t track = resources::game_events->pump().wml_tracking();
822  bool valid = true;
823 
824  const bool event = clearer_.fire_events();
825 
826  if ( track != resources::game_events->pump().wml_tracking() )
827  // Some WML fired, so update our status.
828  valid = post_wml(from);
829 
830  if ( event || !valid )
831  event_mutated_ = true;
832 
833  return event || !valid;
834  }
835 
836 
837  /**
838  * Returns the ambush alert (if any) for the given unit.
839  */
840  std::string unit_mover::read_ambush_string(const unit & ambusher)
841  {
842  for(const unit_ability &hide : ambusher.get_abilities("hides"))
843  {
844  const std::string & ambush_string = (*hide.first)["alert"].str();
845  if ( !ambush_string.empty() )
846  return ambush_string;
847  }
848 
849  // No string found.
850  return std::string();
851  }
852 
853 
854  /**
855  * Reveals the unit at the indicated location.
856  * Can also update the current ambushed alert.
857  * May fire "sighted" events.
858  */
859  void unit_mover::reveal_ambusher(const map_location & hex, bool update_alert)
860  {
861  // Convenient alias:
862  unit_map &units = *resources::units;
864 
865  // Find the unit at the indicated location.
866  unit_map::iterator ambusher = units.find(hex);
867  if ( ambusher != units.end() ) {
868  // Prepare for sighted events.
869  std::vector<int> sight_cache(get_sides_not_seeing(*ambusher));
870  // Make sure the unit is visible (during sighted events, and in case
871  // we had to backtrack).
872  ambusher->set_state(unit::STATE_UNCOVERED, true);
873 
874  // Record this in the move spectator.
875  if ( spectator_ )
876  spectator_->set_ambusher(ambusher);
877 
878  // Override the default ambushed messge?
879  if ( update_alert ) {
880  // Observers don't get extra information.
881  if ( playing_team_is_viewing_ || !disp.fogged(hex) ) {
882  show_ambush_alert_ = true;
883  // We only support one custom ambush message; use the first one.
884  if ( ambush_string_.empty() )
885  ambush_string_ = read_ambush_string(*ambusher);
886  }
887  }
888 
889  // Make sure this hex is drawn correctly.
890  disp.invalidate(hex);
891  // Fire sighted events.
892  event_mutated_ |= actor_sighted(*ambusher, &sight_cache);
893  post_wml();
894  }
895  }
896 
897 
898  // Public interface:
899 
900  /**
901  * Determines how far along the route the unit can expect to move this turn.
902  * This is based solely on data known to the player, and will not plot a move
903  * that ends on another (known) unit.
904  * (For example, this prevents a player from plotting a multi-turn move that
905  * has this turn's movement ending on a (slower) unit, and thereby clearing
906  * fog as if the moving unit actually made it on top of that other unit.)
907  *
908  * @returns false if the expectation is to not move at all.
909  */
910  bool unit_mover::check_expected_movement()
911  {
912  expected_end_ = plot_turn(begin_, full_end_);
913  return expected_end_ != begin_;
914  }
915 
916 
917  /**
918  * Attempts to move the unit along the expected path.
919  * (This will do nothing unless check_expected_movement() was called first.)
920  *
921  * @param[in] show Set to false to suppress animations.
922  */
923  void unit_mover::try_actual_movement(bool show)
924  {
925  static const std::string enter_hex_str("enter hex");
926  static const std::string exit_hex_str("exit hex");
927 
928 
929  bool obstructed_stop = false;
930 
931 
932  // Check for hidden units along the expected path before we start
933  // animating and firing events.
934  cache_hidden_units(begin_, expected_end_);
935 
936  if ( begin_ != ambush_limit_ ) {
937  // Cache the moving unit's visibility.
938  std::vector<int> not_seeing = get_sides_not_seeing(*move_it_);
939 
940  // Prepare to animate.
941  unit_display::unit_mover animator(route_, show);
942  animator.start(move_it_.get_shared_ptr());
943 
944  // Traverse the route to the hex where we need to stop.
945  // Each iteration performs the move from real_end_-1 to real_end_.
946  for ( real_end_ = begin_+1; real_end_ != ambush_limit_; ++real_end_ ) {
947  const route_iterator step_from = real_end_ - 1;
948 
949  // See if we can leave *step_from.
950  // Already accounted for: ambusher
951  if ( event_mutated_ )
952  {
953  break;
954  }
955  if ( sighted_ && is_reasonable_stop(*step_from) )
956  {
957  sighted_stop_ = true;
958  break;
959  }
960  // Already accounted for: ZoC
961  // Already accounted for: movement cost
962  if ( fire_hex_event(exit_hex_str, step_from, real_end_) ) {
963  report_extra_hex_ = true;
964  break;
965  }
966  if ( real_end_ == obstructed_ ) {
967  // We did not check for being a replay when checking for an
968  // obstructed hex, so we do not check can_break here.
969  report_extra_hex_ = true;
970  obstructed_stop = true;
971  break;
972  }
973 
974  // We can leave *step_from. Make the move to *real_end_.
975  bool new_animation = do_move(step_from, real_end_, animator);
976  // Update the fog.
977  if ( current_uses_fog_ )
978  handle_fog(*real_end_, new_animation);
979  animator.wait_for_anims();
980 
981  // Fire the events for this step.
982  // (These return values are not checked since real_end_ still
983  // needs to be incremented. The event_mutated_ check will break
984  // us out of the loop if needed.)
985  fire_hex_event(enter_hex_str, real_end_, step_from);
986  // Sighted events only fire if we could stop due to sighting.
987  if ( is_reasonable_stop(*real_end_) )
988  pump_sighted(real_end_);
989  }//for
990  // Make sure any remaining sighted events get fired.
991  pump_sighted(real_end_-1);
992 
993  if ( move_it_.valid() ) {
994  // Finish animating.
995  animator.finish(move_it_.get_shared_ptr());
996  // Check for the moving unit being seen.
997  event_mutated_ |= actor_sighted(*move_it_, &not_seeing);
998  }
999  }//if
1000 
1001  // Some flags were set to indicate why we might stop.
1002  // Update those to reflect whether or not we got to them.
1004  if ( !obstructed_stop )
1006  teleport_failed_ = teleport_failed_ && obstructed_stop;
1007  // event_mutated_ does not get unset, regardless of other reasons
1008  // for stopping, but we do save its current value.
1010  }
1011 
1012 
1013  /**
1014  * Does some bookkeeping and event firing, for use after movement.
1015  * This includes village capturing and the undo stack.
1016  */
1017  void unit_mover::post_move(undo_list *undo_stack)
1018  {
1019  const map_location & final_loc = final_hex();
1020 
1021  int orig_village_owner = 0;
1022  bool action_time_bonus = false;
1023 
1024  // Reveal ambushers?
1025  if ( ambushed_ || blocked() )
1026  reveal_ambushers();
1027  else if ( teleport_failed_ && spectator_ )
1028  spectator_->set_failed_teleport(resources::units->find(*obstructed_));
1030 
1031  if ( move_it_.valid() ) {
1032  // Update the moving unit.
1033  move_it_->set_interrupted_move(
1034  sighted_stop_ && !resources::whiteboard->is_executing_actions() ?
1035  *(full_end_-1) :
1037  if ( ambushed_ || final_loc == zoc_stop_ )
1038  move_it_->set_movement(0, true);
1039 
1040  // Village capturing.
1041  if ( resources::gameboard->map().is_village(final_loc) ) {
1042  // Is this a capture?
1043  orig_village_owner = resources::gameboard->village_owner(final_loc) + 1;
1044  if ( orig_village_owner != current_side_) {
1045  // Captured. Zap movement and take over the village.
1046  move_it_->set_movement(0, true);
1047  event_mutated_ |= get_village(final_loc, current_side_, &action_time_bonus);
1048  post_wml();
1049  }
1050  }
1051  }
1052 
1053  // Finally, the moveto event.
1054  event_mutated_ |= resources::game_events->pump().fire("moveto", final_loc, *begin_);
1055  post_wml();
1056 
1057  // Record keeping.
1058  if ( spectator_ )
1059  spectator_->set_unit(move_it_);
1060  if ( undo_stack ) {
1061  const bool mover_valid = move_it_.valid();
1062 
1063  if ( mover_valid ) {
1064  // MP_COUNTDOWN: added param
1065  undo_stack->add_move(
1067  action_time_bonus, orig_village_owner, orig_dir_);
1068  }
1069 
1070  if ( !mover_valid || undo_blocked() ||
1071  (resources::whiteboard->is_active() && resources::whiteboard->should_clear_undo()) || !synced_context::can_undo())
1072  {
1073  undo_stack->clear();
1074  }
1075  }
1076 
1077  // Update the screen.
1080  }
1081 
1082 
1083  /**
1084  * Shows the various on-screen messages, for use after movement.
1085  */
1086  void unit_mover::feedback() const
1087  {
1088  // Alias some resources.
1090 
1091  bool redraw = false;
1092 
1093  // Multiple messages may be displayed simultaneously
1094  // this variable is used to keep them from overlapping
1095  std::string message_prefix = "";
1096 
1097  // Ambush feedback?
1098  if ( ambushed_ && show_ambush_alert_ ) {
1099  disp.announce(message_prefix + ambush_string_, font::BAD_COLOR);
1100  message_prefix += " \n";
1101  redraw = true;
1102  }
1103 
1104  // Failed teleport feedback?
1106  std::string teleport_string = _("Failed teleport! Exit not empty");
1107  disp.announce(message_prefix + teleport_string, font::BAD_COLOR);
1108  message_prefix += " \n";
1109  redraw = true;
1110  }
1111 
1112  // Sighted units feedback?
1113  if ( playing_team_is_viewing_ && (enemy_count_ != 0 || friend_count_ != 0) ) {
1114  // Create the message to display (depends on whether friends,
1115  // enemies, or both were sighted, and on how many of each).
1116  utils::string_map symbols;
1117  symbols["enemies"] = std::to_string(enemy_count_);
1118  symbols["friends"] = std::to_string(friend_count_);
1120  SDL_Color msg_color;
1121  if ( friend_count_ != 0 && enemy_count_ != 0 ) {
1122  // Both friends and enemies sighted -- neutral message.
1123  symbols["friendphrase"] = vngettext("Part of 'Units sighted! (...)' sentence^1 friendly", "$friends friendly", friend_count_, symbols);
1124  symbols["enemyphrase"] = vngettext("Part of 'Units sighted! (...)' sentence^1 enemy", "$enemies enemy", enemy_count_, symbols);
1125  message = vgettext("Units sighted! ($friendphrase, $enemyphrase)", symbols);
1126  msg_color = font::NORMAL_COLOR;
1127  } else if ( enemy_count_ != 0 ) {
1128  // Only enemies sighted -- bad message.
1129  message = vngettext("Enemy unit sighted!", "$enemies enemy units sighted!", enemy_count_, symbols);
1130  msg_color = font::BAD_COLOR;
1131  } else if ( friend_count_ != 0 ) {
1132  // Only friends sighted -- good message.
1133  message = vngettext("Friendly unit sighted", "$friends friendly units sighted", friend_count_, symbols);
1134  msg_color = font::GOOD_COLOR;
1135  }
1136 
1137  disp.announce(message_prefix + message, msg_color);
1138  message_prefix += " \n";
1139  redraw = true;
1140  }
1141 
1142  // Suggest "continue move"?
1143  if ( playing_team_is_viewing_ && sighted_stop_ && !resources::whiteboard->is_executing_actions() ) {
1144  // See if the "Continue Move" action has an associated hotkey
1146  if ( !name.empty() ) {
1147  utils::string_map symbols;
1148  symbols["hotkey"] = name;
1149  std::string message = vgettext("(press $hotkey to keep moving)", symbols);
1150  disp.announce(message_prefix + message, font::NORMAL_COLOR);
1151  message_prefix += " \n";
1152  redraw = true;
1153  }
1154  }
1155 
1156  // Update the screen.
1157  if ( redraw )
1158  disp.draw();
1159  }
1160 
1161 }//end anonymous namespace
1162 
1163 
1164 static size_t move_unit_internal(undo_list* undo_stack,
1165  bool show_move,
1166  bool* interrupted,
1167  unit_mover& mover)
1168 {
1169  const events::command_disabler disable_commands;
1170  // Default return value.
1171  if ( interrupted )
1172  *interrupted = false;
1173 
1174  // Attempt moving.
1175  mover.try_actual_movement(show_move);
1176 
1177  config co;
1178  config cn = config_of
1179  ("stopped_early", mover.stopped_early())
1180  ("final_hex_x", mover.final_hex().x + 1)
1181  ("final_hex_y", mover.final_hex().y + 1);
1182  bool matches_replay = checkup_instance->local_checkup(cn,co);
1183  if(!matches_replay)
1184  {
1185  replay::process_error("calculated movement destination (x="+ cn["final_hex_x"].str() + " y=" + cn["final_hex_y"].str() +
1186  ") didn't match the original destination(x="+ co["final_hex_x"].str() + " y=" + co["final_hex_y"].str() + ")\n");
1187 
1188  //TODO: move the unit by force to the desired destination with something like mover.reset_final_hex(co["x"], co["y"]);
1189  }
1190 
1191  // Bookkeeping, etc.
1192  // also fires the moveto event
1193  mover.post_move(undo_stack);
1194  if ( show_move )
1195  mover.feedback();
1196 
1197  // Set return value.
1198  if ( interrupted )
1199  *interrupted = mover.interrupted();
1200 
1201  return mover.steps_travelled();
1202 }
1203 
1204 /**
1205  * Moves a unit across the board.
1206  *
1207  * This function handles actual movement, checking terrain costs as well as
1208  * things that might interrupt movement (e.g. ambushes). If the full path
1209  * cannot be reached this turn, the remainder is stored as the unit's "goto"
1210  * instruction. (The unit itself is whatever unit is at the beginning of the
1211  * supplied path.)
1212  *
1213  * @param[in] steps The route to be traveled. The unit to be moved is at the beginning of this route.
1214  * @param undo_stack If supplied, then either this movement will be added to the stack or the stack will be cleared.
1215  * @param[in] continued_move If set to true, this is a continuation of an earlier move (movement is not interrupted should units be spotted).
1216  * @param[in] show_move Controls whether or not the movement is animated for the player.
1217  * @param[out] interrupted If supplied, then this is set to true if information was uncovered that warrants interrupting a chain of actions (and set to false otherwise).
1218  * @param[out] move_spectator If supplied, this will be given the information uncovered by the move (and the unit's "goto" instruction will be preserved).
1219  *
1220  * @returns The number of hexes entered. This can safely be used as an index
1221  * into @a steps to get the location where movement ended, provided
1222  * @a steps is not empty (the return value is guaranteed to be less
1223  * than steps.size() ).
1224  */
1225 size_t move_unit_and_record(const std::vector<map_location> &steps,
1226  undo_list* undo_stack,
1227  bool continued_move, bool show_move,
1228  bool* interrupted,
1229  move_unit_spectator* move_spectator)
1230 {
1231 
1232  // Avoid some silliness.
1233  if ( steps.size() < 2 || (steps.size() == 2 && steps.front() == steps.back()) ) {
1234  DBG_NG << "Ignoring a unit trying to jump on its hex at " <<
1235  ( steps.empty() ? map_location::null_location() : steps.front() ) << ".\n";
1236  return 0;
1237  }
1238  //if we have no fog activated then we always skip sighted
1239  if(resources::units->find(steps.front()) != resources::units->end())
1240  {
1241  const team &current_team = (*resources::teams)[
1242  resources::units->find(steps.front())->side() - 1];
1243  continued_move |= !current_team.fog_or_shroud();
1244  }
1245  const bool skip_ally_sighted = !preferences::interrupt_when_ally_sighted();
1246 
1247  // Evaluate this move.
1248  unit_mover mover(steps, move_spectator, continued_move, skip_ally_sighted);
1249  if ( !mover.check_expected_movement() )
1250  return 0;
1252  {
1253  /*
1254  enter the synced mode and do the actual movement.
1255  */
1256  resources::recorder->add_synced_command("move",replay_helper::get_movement(steps, continued_move, skip_ally_sighted));
1257  set_scontext_synced sync;
1258  size_t r = move_unit_internal(undo_stack, show_move, interrupted, mover);
1261  sync.do_final_checkup();
1262  return r;
1263  }
1264  else
1265  {
1266  //we are already in synced mode and don't need to reenter it again.
1267  return move_unit_internal(undo_stack, show_move, interrupted, mover);
1268  }
1269 }
1270 
1271 size_t move_unit_from_replay(const std::vector<map_location> &steps,
1272  undo_list* undo_stack,
1273  bool continued_move,bool skip_ally_sighted, bool show_move)
1274 {
1275  // Evaluate this move.
1276  unit_mover mover(steps, nullptr, continued_move,skip_ally_sighted);
1277  if ( !mover.check_expected_movement() )
1278  {
1279  replay::process_error("found corrupt movement in replay.");
1280  return 0;
1281  }
1282 
1283  return move_unit_internal(undo_stack, show_move, nullptr, mover);
1284 }
1285 
1286 
1287 }//namespace actions
play_controller * controller
Definition: resources.cpp:21
bool fog_changed_
Definition: move.cpp:322
void invalidate_unit_after_move(const map_location &src, const map_location &dst)
Same as invalidate_unit() if moving the displayed unit.
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.hpp:353
bool ambushed_
Definition: move.cpp:318
unit_iterator end()
Definition: map.hpp:311
map_location zoc_stop_
Definition: move.cpp:315
move_unit_spectator *const spectator_
Definition: move.cpp:283
size_t move_unit_and_record(const std::vector< map_location > &steps, undo_list *undo_stack, bool continued_move, bool show_move, bool *interrupted, move_unit_spectator *move_spectator)
Moves a unit across the board.
Definition: move.cpp:1225
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3536
void reset(const unit_map &units)
reset all locations to empty values
Definition: move.cpp:112
Definition: unit.hpp:95
bool sighted_stop_
Definition: move.cpp:324
Various functions implementing vision (through fog of war and shroud).
void do_final_checkup(bool dont_throw=false)
bool get_village(const map_location &loc, int side, bool *action_timebonus, bool fire_event)
Makes it so the village at the given location is owned by the given side.
Definition: move.cpp:140
size_t count(const map_location &loc) const
Definition: map.hpp:306
std::deque< int > moves_left_
Definition: move.cpp:331
const std::vector< unit_map::const_iterator > & get_seen_friends() const
get the locations of seen friends
Definition: move.cpp:90
bool owns_village(const map_location &loc) const
Definition: team.hpp:190
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
bool is_village(const map_location &loc) const
Definition: map.cpp:68
size_t do_move_track_
Definition: move.cpp:312
game_display * screen
Definition: resources.cpp:27
bool is_enemy(int n) const
Definition: team.hpp:247
route_iterator real_end_
Definition: move.cpp:296
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
const int orig_moves_
Definition: move.cpp:303
static config get_movement(const std::vector< map_location > &steps, bool skip_sighted, bool skip_ally_sighted)
Records a move that follows the provided steps.
unit_map::iterator move_it_
Definition: move.cpp:299
unit_map::const_iterator failed_teleport_
Definition: move.hpp:89
bool fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
Definition: pump.cpp:471
int village_owner(const map_location &loc) const
Given the location of a village, will return the 0-based index of the team that currently owns it...
Replay control code.
void check_victory()
Checks to see if a side has won.
virtual void draw()
Draws invalidated items.
Definition: display.cpp:2706
const unit * unit_
-file sdl_utils.hpp
const SDL_Color NORMAL_COLOR
Definition: font.cpp:564
GLdouble GLdouble t
Definition: glew.h:1366
bool team_is_defeated(const team &t) const
Calculates whether a team is defeated.
Definition: game_board.cpp:230
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.hpp:629
map_location ambush_stop_
Definition: move.cpp:316
void add_synced_command(const std::string &name, const config &command)
Definition: replay.cpp:241
static synced_state get_synced_state()
game_data * gamedata
Definition: resources.cpp:22
const std::vector< unit_map::const_iterator > & get_seen_enemies() const
get the locations of seen enemies
Definition: move.cpp:84
std::vector< unit_map::const_iterator > seen_friends_
Definition: move.hpp:91
const SDL_Color GOOD_COLOR
Definition: font.cpp:567
const unit_map::const_iterator & get_failed_teleport() const
get the location of a failed teleport
Definition: move.cpp:78
static std::vector< team > *& teams
Definition: team.cpp:50
static void clear_status_caches()
Clear the unit status cache for all units.
Definition: unit.cpp:610
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
route_iterator expected_end_
Definition: move.cpp:293
bool fog_or_shroud() const
Definition: team.hpp:317
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
bool event_mutated_mid_move_
Definition: move.cpp:321
GLuint GLuint end
Definition: glew.h:1221
std::map< std::string, t_string > string_map
bool sighted_
Definition: move.cpp:323
static lg::log_domain log_engine("engine")
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.hpp:314
void finish(unit_ptr u, map_location::DIRECTION dir=map_location::NDIRECTIONS)
Finishes the display of movement for the supplied unit.
Definition: udisplay.cpp:414
std::vector< team > * teams
Definition: resources.cpp:29
pointer get_shared_ptr() const
Definition: map.hpp:180
const SDL_Color BAD_COLOR
Definition: font.cpp:568
void add_seen_enemy(const unit_map::const_iterator &u)
add the location of new seen enemy
Definition: move.cpp:66
void proceed_to(unit_ptr u, size_t path_index, bool update=false, bool wait=true)
Visually moves a unit from the last hex we drew to the one specified by path_index.
Definition: udisplay.cpp:315
void set_failed_teleport(const unit_map::const_iterator &u)
set the location of a failed teleport
Definition: move.cpp:128
game_board * gameboard
Definition: resources.cpp:20
GLuint start
Definition: glew.h:1221
size_t wml_tracking()
This function can be used to detect when no WML/Lua has been executed.
Definition: pump.cpp:602
route_iterator move_loc_
Definition: move.cpp:311
Encapsulates the map of the game.
Definition: map.hpp:37
team * current_team_
Definition: move.cpp:309
bool show_ambush_alert_
Definition: move.cpp:319
checkup * checkup_instance
A class to encapsulate the steps of drawing a unit's move.
Definition: udisplay.hpp:47
static bool can_undo()
replay * recorder
Definition: resources.cpp:30
void wait_for_anims()
Waits for the final animation of the most recent proceed_to() to finish.
Definition: udisplay.cpp:387
void set_ambusher(const unit_map::const_iterator &u)
set the location of an ambusher
Definition: move.cpp:122
static const map_location & null_location()
Definition: location.hpp:195
unit_map::const_iterator ambusher_
Definition: move.hpp:88
game_events::manager * game_events
Definition: resources.cpp:24
void pump()
Definition: events.cpp:336
move_unit_spectator(const unit_map &units)
constructor
Definition: move.cpp:102
void show(CVideo &video, const std::string &window_id, const t_string &message, const tpoint &mouse)
Shows a tip.
Definition: tip.cpp:133
Encapsulates the map of the game.
Definition: location.hpp:38
std::vector< unit_map::const_iterator > seen_enemies_
Definition: move.hpp:90
Various functions related to moving units.
Domain specific events.
Definition: action_wml.cpp:93
static void process_error(const std::string &msg)
Definition: replay.cpp:198
size_t friend_count_
Definition: move.cpp:328
void maybe_throw_return_to_play_side()
const route_iterator begin_
Definition: move.cpp:291
std::vector< map_location > ambushers_
Definition: move.cpp:330
bool teleport_failed_
Definition: move.cpp:325
map_location blocked_loc_
Definition: move.cpp:317
const unit_map::const_iterator & get_ambusher() const
get the location of an ambusher
Definition: move.cpp:72
size_t move_unit_from_replay(const std::vector< map_location > &steps, undo_list *undo_stack, bool continued_move, bool skip_ally_sighted, bool show_move)
Moves a unit across the board.
Definition: move.cpp:1271
int current_side_
Definition: move.cpp:308
bool interrupt_when_ally_sighted()
std::pair< const config *, map_location > unit_ability
The things contained within a unit_ability_list.
Definition: unit.hpp:43
size_t enemy_count_
Definition: move.cpp:327
Define the game's event mechanism.
void start(unit_ptr u)
Initiates the display of movement for the supplied unit.
Definition: udisplay.cpp:244
std::string ambush_string_
Definition: move.cpp:329
const unit_map::const_iterator & get_unit() const
get new location of moved unit
Definition: move.cpp:96
size_t i
Definition: function.cpp:1057
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
const bool skip_sighting_
Definition: move.cpp:284
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
std::string get_names(std::string id)
Returns a comma-separated string of hotkey names.
bool fire_event(const tevent event, std::vector< std::pair< twidget *, tevent > > &event_chain, twidget *dispatcher, twidget *widget, F functor)
Helper function for fire_event.
std::pair< unit_iterator, bool > move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
Definition: map.cpp:79
unit_ability_list get_abilities(const std::string &tag_name, const map_location &loc) const
Definition: abilities.cpp:168
game_events::t_pump & pump()
Definition: manager.cpp:194
route_iterator ambush_limit_
Definition: move.cpp:294
std::string vgettext(const char *msgid, const utils::string_map &symbols)
GLuint const GLchar * name
Definition: glew.h:1782
virtual const gamemap & map() const
Definition: game_board.hpp:98
size_t erase(const map_location &l)
Erases the unit at location l, if any.
Definition: map.cpp:277
shroud_clearer clearer_
Definition: move.cpp:333
unit_map::const_iterator unit_
Definition: move.hpp:92
void set_unit(const unit_map::const_iterator &u)
set the iterator to moved unit
Definition: move.cpp:134
Class to store the actions that a player can undo and redo.
Definition: undo.hpp:38
void add_seen_friend(const unit_map::const_iterator &u)
add a location of a seen friend
Definition: move.cpp:60
bool find(E event, F functor)
Tests whether an event handler is available.
cl_event event
Definition: glew.h:3070
Various functions that implement the undoing (and redoing) of in-game commands.
void set_action_bonus_count(const int count)
Definition: team.hpp:219
Standard logging facilities (interface).
Container associating units to locations.
Definition: map.hpp:90
bool report_extra_hex_
Definition: move.cpp:326
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
bool event_mutated_
Definition: move.cpp:320
const bool playing_team_is_viewing_
Definition: move.cpp:286
const map_location goto_
Definition: move.cpp:305
boost::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:36
route_iterator obstructed_
Definition: move.cpp:295
std::string vngettext(const char *sing, const char *plur, int n, const utils::string_map &symbols)
bool current_uses_fog_
Definition: move.cpp:310
actions::undo_list * undo_stack
Definition: resources.cpp:34
unit_iterator find(size_t id)
Definition: map.cpp:285
bool valid() const
Definition: map.hpp:229
virtual bool local_checkup(const config &expected_data, config &real_data)=0
Compares data to the results calculated during the original game.
const route_iterator full_end_
Definition: move.cpp:292
const map_location::DIRECTION orig_dir_
Definition: move.cpp:304
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
int action_bonus_count() const
Definition: team.hpp:218
static size_t move_unit_internal(undo_list *undo_stack, bool show_move, bool *interrupted, unit_mover &mover)
Definition: move.cpp:1164
void announce(const std::string &msg, const SDL_Color &color=font::GOOD_COLOR)
Announce a message prominently.
Definition: display.cpp:1950
std::vector< int > get_sides_not_seeing(const unit &target)
Returns the sides that cannot currently see target.
Definition: vision.cpp:596
#define DBG_NG
Definition: move.cpp:54
const bool skip_ally_sighting_
Definition: move.cpp:285
This module contains various pathfinding functions and utilities.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
unit_map * units
Definition: resources.cpp:35
const int orig_side_
Definition: move.cpp:302
Display units performing various actions: moving, attacking, and dying.
bool enemy_zoc(team const &current_team, map_location const &loc, team const &viewing_team, bool see_all)
Determines if a given location is in an enemy zone of control.
Definition: pathfind.cpp:138
bool get_village(const map_location &, const int owner_side, game_data *fire_event)
Acquires a village from owner_side. Pointer fire_event should be the game_data for the game if it is ...
Definition: team.cpp:377
static const hotkey_command & get_command_by_command(HOTKEY_COMMAND command)
the execute_command argument was changed from HOTKEY_COMMAND to hotkey_command, to be able to call it...
const std::vector< map_location > & route_
Definition: move.cpp:288
const std::string valid
Little parts of regex templates used to parse Wml annoations.
virtual ~move_unit_spectator()
destructor
Definition: move.cpp:108