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