40 #define ERR_PF LOG_STREAM(err, log_engine)
66 const bool do_shroud = shroud_check && shroud_check->
uses_shroud();
67 std::set<map_location> pending_tiles_to_check, tiles_checked;
68 pending_tiles_to_check.insert(loc);
70 for (
int distance = 0; distance < 50; ++distance) {
71 if (pending_tiles_to_check.empty())
74 std::set<map_location> tiles_checking;
75 tiles_checking.swap(pending_tiles_to_check);
80 if ( do_shroud && shroud_check->
shrouded(l) )
84 const bool pass_check_and_unreachable = pass_check
92 if (pass_check_and_unreachable && distance > 10)
continue;
94 if (units.
find(l) == units.
end() && !pass_check_and_unreachable)
return l;
100 if (tiles_checked.find(l2) == tiles_checked.end() &&
101 tiles_checking.find(l2) == tiles_checking.end())
103 pending_tiles_to_check.insert(l2);
107 tiles_checked.swap(tiles_checking);
135 const team& viewing_team,
bool see_all)
155 struct findroute_node {
164 findroute_node(
int moves,
int turns,
const map_location &prev_loc,
unsigned search_count)
178 bool operator<(
const findroute_node& o)
const
187 struct findroute_indexer {
191 findroute_indexer(
int a,
int b) :
w(a),
h(
b) { }
193 unsigned operator()(
int x,
int y)
const {
195 "Pathfind: Location not on board");
196 return x +
static_cast<unsigned>(y)*
w;
199 return (*
this)(loc.
x, loc.
y);
204 static_cast<int>(
index%
w),
205 static_cast<int>(
index/
w));
209 return this->on_board(loc.
x, loc.
y);
211 inline bool on_board(
int x,
int y)
const {
212 return (x >= 0) && (x <
w) && (y >= 0) && (y <
h);
219 struct findroute_comp {
220 const std::vector<findroute_node>&
nodes;
223 findroute_comp(
const std::vector<findroute_node>&
n) :
nodes(
n) { }
225 bool operator()(
int l,
int r)
const {
274 const unit * teleporter,
const team * current_team,
275 const unit * skirmisher,
const team * viewing_team,
276 const std::map<map_location, int> * jamming_map=
nullptr,
277 std::vector<std::pair<int, int>> *
full_cost_map=
nullptr,
bool check_vision=
false)
281 const bool see_all = viewing_team ==
nullptr;
284 if ( viewing_team ==
nullptr )
293 static std::vector<findroute_node>
nodes;
294 static unsigned search_counter = 0;
298 if ( search_counter == 0 ) {
303 nodes.resize(
static_cast<size_t>(map.
w()) * map.
h());
304 findroute_comp node_comp(
nodes);
305 findroute_indexer
index(map.
w(), map.
h());
307 assert(
index.on_board(origin));
312 if (
full_cost_map->size() !=
static_cast<unsigned>(map.
w() * map.
h()) )
316 (*full_cost_map)[
index(origin)].first = 0;
317 (*full_cost_map)[
index(origin)].second += 1;
322 int xmin = origin.
x, xmax = origin.
x, ymin = origin.
y, ymax = origin.
y;
330 std::vector<unsigned> hexes_to_process(1,
index(origin));
332 while ( !hexes_to_process.empty() ) {
334 const unsigned cur_index = hexes_to_process.front();
336 const findroute_node& current =
nodes[cur_index];
338 std::pop_heap(hexes_to_process.begin(), hexes_to_process.end(), node_comp);
339 hexes_to_process.pop_back();
342 std::vector<map_location> adj_locs(6);
346 auto off_board_it = std::partition(adj_locs.begin(), adj_locs.end(), [&
index](
map_location loc){
347 return index.on_board(loc);
350 if(edges !=
nullptr){
351 edges->insert(off_board_it, adj_locs.end());
354 adj_locs.erase(off_board_it, adj_locs.end());
358 adj_locs.insert(adj_locs.end(), allowed_teleports.begin(), allowed_teleports.end());
360 for (
int i = adj_locs.size()-1;
i >= 0; --
i ) {
363 const unsigned next_index =
index(next_hex);
364 findroute_node & next =
nodes[next_index];
371 if ( next.search_num == search_counter )
380 const std::map<map_location, int>::const_iterator jam_it =
381 jamming_map->find(next_hex);
382 if ( jam_it != jamming_map->end() )
383 cost += jam_it->second;
387 next.moves_left = current.moves_left - cost;
388 next.turns_left = current.turns_left;
389 if ( next.moves_left < 0 ) {
392 next.moves_left = max_moves - cost;
394 if ( next.moves_left < 0 || next.turns_left < 0 ) {
396 if ( edges !=
nullptr )
397 edges->insert(next_hex);
401 if ( current_team ) {
406 if ( edges !=
nullptr )
407 edges->insert(next_hex);
411 if ( skirmisher && next.moves_left > 0 &&
412 enemy_zoc(*current_team, next_hex, *viewing_team, see_all) &&
418 if ( !see_all && viewing_team && current_team && viewing_team != current_team && viewing_team->
shrouded(next_hex) ) {
426 (*full_cost_map)[next_index].first = 0;
427 int summed_cost = (
turns_left - next.turns_left + 1) * max_moves - next.moves_left;
429 (*full_cost_map)[next_index].second += 1;
433 next.search_num = search_counter;
436 hexes_to_process.push_back(next_index);
437 std::push_heap(hexes_to_process.begin(), hexes_to_process.end(), node_comp);
441 if ( next_hex.
x < xmin )
443 else if ( xmax < next_hex.
x )
445 if ( next_hex.
y < ymin )
447 else if ( ymax < next_hex.
y )
460 destinations.reserve(nb_dest);
461 for (
int x = xmin; x <= xmax; ++x) {
462 for (
int y = ymin; y <= ymax; ++y)
465 if (
n.search_num == search_counter ) {
468 destinations.push_back(
s);
480 const_iterator
i = std::lower_bound(begin(), end(), loc,
step_compare);
481 if (
i != end() &&
i->curr != loc)
return end();
488 if (
i != end() &&
i->curr == loc)
return;
499 std::vector<map_location>
path;
500 if (!j->prev.valid()) {
501 path.push_back(j->curr);
503 const_iterator
i = j;
507 path.push_back(
i->curr);
508 }
while (
i->prev.valid());
510 std::reverse(
path.begin(),
path.end());
516 return find(loc) != end();
533 bool allow_teleport,
const team &viewing_team,
534 int additional_turns,
bool see_all,
bool ignore_units)
547 allow_teleport ? &u :
nullptr,
549 force_ignore_zoc ?
nullptr : &u,
550 see_all ?
nullptr : &viewing_team
552 }
catch(
const std::out_of_range&) {
577 const std::map<map_location, int>& jamming_map)
580 const int sight_range = viewer.
vision();
588 0,
destinations, &
edges, &viewer,
nullptr,
nullptr, &viewing_team, &jamming_map,
nullptr,
true);
605 const std::map<map_location, int>& jamming_map)
617 destinations, &
edges, &*u,
nullptr,
nullptr, &viewing_team, &jamming_map,
nullptr,
true);
622 destinations, &
edges,
nullptr,
nullptr,
nullptr,
nullptr, &jamming_map,
nullptr,
true);
644 const int jamming_range = jammer.
jamming();
650 0,
destinations,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
675 std::vector<map_location>::const_iterator
i = rt.
steps.begin();
677 for (;
i !=rt.
steps.end(); ++
i) {
678 bool last_step = (
i+1 == rt.
steps.end());
686 if (last_step || zoc || move_cost > movement) {
702 total_costs += movement;
707 total_costs += movement;
709 if(move_cost > movement) {
714 zoc =
enemy_zoc(unit_team, *(
i + 1), viewing_team)
718 total_costs += movement;
721 movement -= move_cost;
722 total_costs += move_cost;
726 if(update_move_cost) {
733 const std::vector<team>& teams,
const gamemap& map,
734 bool ignore_unit,
bool ignore_defense,
bool see_all)
735 :
unit_(u), viewing_team_(
t), teams_(teams), map_(map),
736 movement_left_(
unit_.movement_left()),
737 total_movement_(
unit_.total_movement()),
738 ignore_unit_(ignore_unit), ignore_defense_(ignore_defense),
754 VALIDATE(terrain_cost >= 1,
_(
"Terrain with a movement cost less than 1 encountered."));
759 int remaining_movement =
movement_left_ -
static_cast<int>(so_far);
760 if (remaining_movement < 0) {
768 int other_unit_subcost = 0;
770 const unit *other_unit =
785 other_unit_subcost = 1;
796 if (remaining_movement < terrain_cost) {
797 move_cost += remaining_movement;
806 move_cost += remaining_movement;
809 move_cost += terrain_cost;
820 return move_cost + (defense_subcost + other_unit_subcost) / 10000.0;
824 : movement_type_(mt), movement_left_(movement_left),
825 total_movement_(total_movement), viewing_team_(
t), map_(map)
841 int remaining_movement =
movement_left_ -
static_cast<int>(so_far);
842 if (remaining_movement < 0)
847 if (remaining_movement < terrain_cost) {
848 move_cost += remaining_movement;
851 move_cost += terrain_cost;
858 :
unit_(u), map_(map)
890 bool allow_teleport,
const team &viewing_team,
891 bool see_all,
bool ignore_units)
892 :force_ignore_zoc_(force_ignore_zoc), allow_teleport_(allow_teleport),
893 viewing_team_(viewing_team), see_all_(see_all), ignore_units_(ignore_units)
896 cost_map = std::vector<std::pair<int, int>>(
static_cast<size_t>(map.
w()) * map.
h(), std::pair(-1, 0));
905 bool allow_teleport,
const team &viewing_team,
906 bool see_all,
bool ignore_units)
907 :force_ignore_zoc_(force_ignore_zoc), allow_teleport_(allow_teleport),
908 viewing_team_(viewing_team), see_all_(see_all), ignore_units_(ignore_units)
911 cost_map = std::vector<std::pair<int, int>>(
static_cast<size_t>(map.
w()) * map.
h(), std::pair(-1, 0));
941 }
catch(
const std::out_of_range&) {
959 u->set_location(origin);
973 assert(
cost_map.size() ==
static_cast<unsigned>(map.
w() * map.
h()));
976 return std::pair(-1, 0);
1002 if (
p.second == 0) {
1005 return static_cast<double>(
p.first) /
p.second;
const team & viewing_team() const
static display * get_singleton()
Returns the display object if a display object exists.
virtual const std::vector< team > & teams() const override
unit * get_visible_unit(const map_location &loc, const team ¤t_team, bool see_all=false)
virtual const unit_map & units() const override
virtual const gamemap & map() const override
int w() const
Effective map width.
int h() const
Effective map height.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Encapsulates the map of the game.
bool is_village(const map_location &loc) const
bool is_castle(const map_location &loc) const
A const-only interface for how many (movement, vision, or "jamming") points a unit needs for each hex...
int cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost associated with the given terrain.
The basic "size" of the unit - flying, small land, large land, etc.
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
const terrain_costs & get_jamming() const
int movement_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to move through the indicated terrain.
const terrain_costs & get_movement() const
const terrain_costs & get_vision() const
const std::unordered_set< map_location > & get_adjacents(map_location loc) const
This class stores all the data for a single 'side' (in game nomenclature).
bool is_enemy(int n) const
bool owns_village(const map_location &loc) const
bool shrouded(const map_location &loc) const
bool fogged(const map_location &loc) const
Container associating units to locations.
unit_iterator find(std::size_t id)
A single unit type that the player may recruit.
This class represents a single unit of a specific type.
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
map_display and display: classes which take care of displaying the map and game-data on the screen.
static bool operator<(const placing_info &a, const placing_info &b)
static std::string _(const char *str)
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Checks whether this unit currently possesses or is affected by a given ability.
bool invisible(const map_location &loc, bool see_all=true) const
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
int side() const
The side this unit belongs to.
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
bool emits_zoc() const
Tests whether the unit has a zone-of-control, considering incapacitated.
int jamming() const
Gets the unit's jamming points.
const map_location & get_location() const
The current map location this unit is at.
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
const movetype & movement_type() const
Get the unit's movement type.
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
int total_movement() const
The maximum moves this unit has.
int vision() const
Gets the unit's vision points.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Standard logging facilities (interface).
static void find_routes(const map_location &origin, const movetype::terrain_costs &costs, bool slowed, int moves_left, int max_moves, int turns_left, paths::dest_vect &destinations, std::set< map_location > *edges, const unit *teleporter, const team *current_team, const unit *skirmisher, const team *viewing_team, const std::map< map_location, int > *jamming_map=nullptr, std::vector< std::pair< int, int >> *full_cost_map=nullptr, bool check_vision=false)
Creates a list of routes that a unit can traverse from the provided location.
map_location find_vacant_castle(const unit &leader)
Wrapper for find_vacant_tile() when looking for a vacant castle tile near a leader.
static bool step_compare(const paths::step &a, const map_location &b)
bool enemy_zoc(const team ¤t_team, const map_location &loc, const team &viewing_team, bool see_all)
Determines if a given location is in an enemy zone of control.
marked_route mark_route(const plain_route &rt, bool update_move_cost)
Add marks on a route rt assuming that the unit located at the first hex of rt travels along it.
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units, bool check_vision)
map_location find_vacant_tile(const map_location &loc, VACANT_TILE_TYPE vacancy, const unit *pass_check, const team *shroud_check, const game_board *board)
Function that will find a location on the board that is as near to loc as possible,...
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::string & insert(std::string &str, const std::size_t pos, const std::string &insert)
Insert a UTF-8 string at the specified position.
std::string::const_iterator iterator
static lg::log_domain log_engine("engine")
const std::vector< findroute_node > & nodes
This module contains various pathfinding functions and utilities.
std::shared_ptr< unit > unit_ptr
Encapsulates the map of the game.
static const map_location & null_location()
static double getNoPathValue()
virtual double cost(const map_location &loc, const double so_far) const
dummy_path_calculator(const unit &u, const gamemap &map)
emergency_path_calculator(const unit &u, const gamemap &map)
virtual double cost(const map_location &loc, const double so_far) const
Structure which uses find_routes() to build a cost map This maps each hex to a the movements a unit w...
const bool force_ignore_zoc_
full_cost_map(const unit &u, bool force_ignore_zoc, bool allow_teleport, const team &viewing_team, bool see_all=true, bool ignore_units=true)
Constructs a cost-map.
double get_average_cost_at(map_location loc) const
Accessor for the costs.
void add_unit(const unit &u, bool use_max_moves=true)
Adds a units cost map to cost_map (increments the elements in cost_map)
const team & viewing_team_
int get_cost_at(map_location loc) const
Accessor for the costs.
std::pair< int, int > get_pair_at(map_location loc) const
Accessor for the cost/reach-amount pairs.
std::vector< std::pair< int, int > > cost_map
const bool allow_teleport_
jamming_path(const unit &jammer, const map_location &loc)
Construct a list of jammed hexes for a unit.
virtual ~jamming_path()
Default destructor.
Structure which holds a single route and marks for special events.
virtual double cost(const map_location &loc, const double so_far) const
move_type_path_calculator(const movetype &mt, int movement_left, int total_movement, const team &t, const gamemap &map)
const int total_movement_
const team & viewing_team_
const movetype & movement_type_
Ordered vector of possible destinations.
std::vector< map_location > get_path(const const_iterator &) const
Returns the path going from the source point (included) to the destination point j (excluded).
void insert(const map_location &)
bool contains(const map_location &) const
const_iterator find(const map_location &) const
Object which contains all the possible locations a unit can move to, with associated best routes to t...
virtual ~paths()
Virtual destructor (default processing).
Structure which holds a single route between one location and another.
std::vector< map_location > steps
shortest_path_calculator(const unit &u, const team &t, const std::vector< team > &teams, const gamemap &map, bool ignore_unit=false, bool ignore_defense_=false, bool see_all=false)
bool const ignore_defense_
const std::vector< team > & teams_
const int total_movement_
virtual double cost(const map_location &loc, const double so_far) const
const team & viewing_team_
std::set< map_location > edges
The edges are the non-destination hexes bordering the destinations.
virtual ~vision_path()
Default destructor.
vision_path(const unit &viewer, const map_location &loc, const std::map< map_location, int > &jamming_map)
Constructs a list of vision paths for a unit.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
static map_location::direction n
static map_location::direction s
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE(cond, message)
The macro to use for the validation of WML.