Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace pf_special with a scoped enum (PathfindingFlag) and add more flags #76026

Merged
merged 1 commit into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 23 additions & 13 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10932,7 +10932,7 @@ void map::update_pathfinding_cache( const tripoint &p ) const
return;
}
pathfinding_cache &cache = get_pathfinding_cache( p.z );
pf_special cur_value = PF_NORMAL;
PathfindingFlags cur_value = PathfindingFlag::Ground;

const_maptile tile = maptile_at_internal( p );

Expand All @@ -10946,39 +10946,49 @@ void map::update_pathfinding_cache( const tripoint &p ) const
const int cost = move_cost_internal( furniture, terrain, field, veh, part );

if( cost > 2 ) {
cur_value |= PF_SLOW;
cur_value |= PathfindingFlag::Slow;
} else if( cost <= 0 ) {
cur_value |= PF_WALL;
cur_value |= PathfindingFlag::Obstacle;
if( terrain.has_flag( ter_furn_flag::TFLAG_CLIMBABLE ) ) {
cur_value |= PF_CLIMBABLE;
cur_value |= PathfindingFlag::Climbable;
}
}

if( veh != nullptr ) {
cur_value |= PF_VEHICLE;
cur_value |= PathfindingFlag::Vehicle;
}

for( const auto &fld : tile.get_field() ) {
const field_entry &cur = fld.second;
if( cur.is_dangerous() ) {
cur_value |= PF_FIELD;
cur_value |= PathfindingFlag::DangerousField;
}
}

if( ( !tile.get_trap_t().is_benign() || !terrain.trap.obj().is_benign() ) &&
!here.has_vehicle_floor( p ) ) {
cur_value |= PF_TRAP;
cur_value |= PathfindingFlag::DangerousTrap;
}

if( terrain.has_flag( ter_furn_flag::TFLAG_GOES_DOWN ) ||
terrain.has_flag( ter_furn_flag::TFLAG_GOES_UP ) ||
terrain.has_flag( ter_furn_flag::TFLAG_RAMP ) || terrain.has_flag( ter_furn_flag::TFLAG_RAMP_UP ) ||
terrain.has_flag( ter_furn_flag::TFLAG_RAMP_DOWN ) ) {
cur_value |= PF_UPDOWN;
if( terrain.has_flag( ter_furn_flag::TFLAG_GOES_UP ) ) {
cur_value |= PathfindingFlag::GoesUp;
}

if( terrain.has_flag( ter_furn_flag::TFLAG_GOES_DOWN ) ) {
cur_value |= PathfindingFlag::GoesDown;
}

if( terrain.has_flag( ter_furn_flag::TFLAG_RAMP ) ||
terrain.has_flag( ter_furn_flag::TFLAG_RAMP_UP ) ) {
cur_value |= PathfindingFlag::GoesUp | PathfindingFlag::RampUp;
}

if( terrain.has_flag( ter_furn_flag::TFLAG_RAMP_DOWN ) ) {
cur_value |= PathfindingFlag::GoesDown | PathfindingFlag::RampDown;
}

if( terrain.has_flag( ter_furn_flag::TFLAG_SHARP ) && !here.has_vehicle_floor( p ) ) {
cur_value |= PF_SHARP;
cur_value |= PathfindingFlag::Sharp;
}

cache.special[p.x][p.y] = cur_value;
Expand Down
8 changes: 4 additions & 4 deletions src/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ template<typename T>
struct weighted_int_list;
struct field_proc_data;

enum pf_special : int;
class PathfindingFlags;

using relic_procgen_id = string_id<relic_procgen_data>;

Expand Down Expand Up @@ -814,17 +814,17 @@ class map
// Includes climbing, bashing and opening doors.
int cost_to_pass( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
const pathfinding_settings &settings,
pf_special p_special ) const;
PathfindingFlags p_special ) const;
// Pathfinding cost helper that computes the cost of moving into |p|
// from |cur| based on perceived danger.
// Includes moving through traps.
int cost_to_avoid( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
const pathfinding_settings &settings,
pf_special p_special ) const;
PathfindingFlags p_special ) const;
// Sum of cost_to_pass and cost_to_avoid.
int extra_cost( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
const pathfinding_settings &settings,
pf_special p_special ) const;
PathfindingFlags p_special ) const;
public:

// Vehicles: Common to 2D and 3D
Expand Down
34 changes: 20 additions & 14 deletions src/pathfinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ static bool vertical_move_destination( const map &m, ter_furn_flag flag, tripoin
{
const pathfinding_cache &pf_cache = m.get_pathfinding_cache_ref( t.z );
for( const point &p : closest_points_first( t.xy(), SEEX ) ) {
if( pf_cache.special[p.x][p.y] & PF_UPDOWN ) {
if( pf_cache.special[p.x][p.y] & ( PathfindingFlag::GoesDown | PathfindingFlag::GoesUp ) ) {
const tripoint t2( p, t.z );
if( m.has_flag( flag, t2 ) ) {
t = t2;
Expand Down Expand Up @@ -195,7 +195,9 @@ std::vector<tripoint_bub_ms> map::straight_route( const tripoint_bub_ms &f,
const pathfinding_cache &pf_cache = get_pathfinding_cache_ref( f.z() );
// Check all points for any special case (including just hard terrain)
if( std::any_of( ret.begin(), ret.end(), [&pf_cache]( const tripoint_bub_ms & p ) {
constexpr pf_special non_normal = PF_SLOW | PF_WALL | PF_VEHICLE | PF_TRAP | PF_SHARP;
constexpr PathfindingFlags non_normal = PathfindingFlag::Slow |
PathfindingFlag::Obstacle | PathfindingFlag::Vehicle | PathfindingFlag::DangerousTrap |
PathfindingFlag::Sharp;
return pf_cache.special[p.x()][p.y()] & non_normal;
} ) ) {
ret.clear();
Expand All @@ -208,9 +210,11 @@ static constexpr int PF_IMPASSABLE = -1;
static constexpr int PF_IMPASSABLE_FROM_HERE = -2;
int map::cost_to_pass( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
const pathfinding_settings &settings,
pf_special p_special ) const
PathfindingFlags p_special ) const
{
constexpr pf_special non_normal = PF_SLOW | PF_WALL | PF_VEHICLE | PF_TRAP | PF_SHARP;
constexpr PathfindingFlags non_normal = PathfindingFlag::Slow |
PathfindingFlag::Obstacle | PathfindingFlag::Vehicle | PathfindingFlag::DangerousTrap |
PathfindingFlag::Sharp;
if( !( p_special & non_normal ) ) {
// Boring flat dirt - the most common case above the ground
return 2;
Expand All @@ -220,7 +224,7 @@ int map::cost_to_pass( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
return PF_IMPASSABLE;
}

if( settings.avoid_sharp && ( p_special & PF_SHARP ) ) {
if( settings.avoid_sharp && ( p_special & PathfindingFlag::Sharp ) ) {
return PF_IMPASSABLE;
}

Expand Down Expand Up @@ -288,7 +292,7 @@ int map::cost_to_pass( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
}

// If we can climb it, great!
if( climb_cost > 0 && p_special & PF_CLIMBABLE ) {
if( climb_cost > 0 && p_special & PathfindingFlag::Climbable ) {
return climb_cost;
}

Expand Down Expand Up @@ -328,9 +332,9 @@ int map::cost_to_pass( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
}

int map::cost_to_avoid( const tripoint_bub_ms & /*cur*/, const tripoint_bub_ms &p,
const pathfinding_settings &settings, pf_special p_special ) const
const pathfinding_settings &settings, PathfindingFlags p_special ) const
{
if( settings.avoid_traps && ( p_special & PF_TRAP ) ) {
if( settings.avoid_traps && ( p_special & PathfindingFlag::DangerousTrap ) ) {
const const_maptile &tile = maptile_at_internal( p );
const ter_t &terrain = tile.get_ter_t();
const trap &ter_trp = terrain.trap.obj();
Expand All @@ -342,7 +346,7 @@ int map::cost_to_avoid( const tripoint_bub_ms & /*cur*/, const tripoint_bub_ms &
}
}

if( settings.avoid_dangerous_fields && ( p_special & PF_FIELD ) ) {
if( settings.avoid_dangerous_fields && ( p_special & PathfindingFlag::DangerousField ) ) {
// We'll walk through even known-dangerous fields if we absolutely have to.
return 500;
}
Expand All @@ -352,7 +356,7 @@ int map::cost_to_avoid( const tripoint_bub_ms & /*cur*/, const tripoint_bub_ms &

int map::extra_cost( const tripoint_bub_ms &cur, const tripoint_bub_ms &p,
const pathfinding_settings &settings,
pf_special p_special ) const
PathfindingFlags p_special ) const
{
int pass_cost = cost_to_pass( tripoint_bub_ms( cur ), tripoint_bub_ms( p ), settings, p_special );
if( pass_cost < 0 ) {
Expand Down Expand Up @@ -436,7 +440,7 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
layer.closed[parent_index] = true;

const pathfinding_cache &pf_cache = get_pathfinding_cache_ref( cur.z );
const pf_special cur_special = pf_cache.special[cur.x][cur.y];
const PathfindingFlags cur_special = pf_cache.special[cur.x][cur.y];

// 7 3 5
// 1 . 2
Expand Down Expand Up @@ -464,7 +468,7 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
// Penalize for diagonals or the path will look "unnatural"
int newg = layer.gscore[parent_index] + ( ( cur.x != p.x && cur.y != p.y ) ? 1 : 0 );

const pf_special p_special = pf_cache.special[p.x][p.y];
const PathfindingFlags p_special = pf_cache.special[p.x][p.y];
const int cost = extra_cost( tripoint_bub_ms( cur ), tripoint_bub_ms( p ), settings, p_special );
if( cost < 0 ) {
if( cost == PF_IMPASSABLE ) {
Expand All @@ -477,7 +481,7 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
// Special case: pathfinders that avoid traps can avoid ledges by
// climbing down. This can't be covered by |extra_cost| because it
// can add a new point to the search.
if( settings.avoid_traps && ( p_special & PF_TRAP ) ) {
if( settings.avoid_traps && ( p_special & PathfindingFlag::DangerousTrap ) ) {
const const_maptile &tile = maptile_at_internal( p );
const ter_t &terrain = tile.get_ter_t();
const trap &ter_trp = terrain.trap.obj();
Expand Down Expand Up @@ -505,7 +509,9 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
pf.add_point( newg, newg + 2 * rl_dist( p, t ), cur, p );
}

if( !( cur_special & PF_UPDOWN ) || !settings.allow_climb_stairs ) {
// TODO: We should be able to go up ramps even if we can't climb stairs.
if( !( cur_special & ( PathfindingFlag::GoesUp | PathfindingFlag::GoesDown ) ) ||
!settings.allow_climb_stairs ) {
// The part below is only for z-level pathing
continue;
}
Expand Down
121 changes: 100 additions & 21 deletions src/pathfinding.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,117 @@
#include "game_constants.h"
#include "mdarray.h"

enum pf_special : int {
PF_NORMAL = 0x00, // Plain boring tile (grass, dirt, floor etc.)
PF_SLOW = 0x01, // Tile with move cost >2
PF_WALL = 0x02, // Unpassable ter/furn/vehicle
PF_VEHICLE = 0x04, // Any vehicle tile (passable or not)
PF_FIELD = 0x08, // Dangerous field
PF_TRAP = 0x10, // Dangerous trap
PF_UPDOWN = 0x20, // Stairs, ramp etc.
PF_CLIMBABLE = 0x40, // 0 move cost but can be climbed on examine
PF_SHARP = 0x80, // sharp items (barbed wire, etc)
// An attribute of a particular map square that is of interest in pathfinding.
// Has a maximum of 32 members. For more, the datatype underlying PathfindingFlags
// needs to be increased.
enum class PathfindingFlag : uint8_t {
Ground = 0, // Can walk on
Slow, // Move cost > 2
Swimmable, // Can swim in
Air, // Empty air
Unsheltered, // Outside and above ground level
Obstacle, // Something stopping us, might be bashable.
Bashable, // Something bashable.
Impassable, // Impassable obstacle.
Vehicle, // Vehicle tile (passable or not)
DangerousField, // Dangerous field
DangerousTrap, // Dangerous trap (i.e. not flagged benign)
GoesUp, // Valid stairs up
GoesDown, // Valid stairs down
RampUp, // Valid ramp up
RampDown, // Valid ramp down
Climbable, // Obstacle but can be climbed on examine
Sharp, // Sharp items (barbed wire, etc)
Door, // A door (any kind)
InsideDoor, // A door that can be opened from the inside only
LockedDoor, // A locked door
Pit, // A pit you can fall into / climb out of.
DeepWater, // Deep water.
Burrowable, // Can burrow into
HardGround, // Can not dig & burrow intotiny = 1,
RestrictTiny, // Tiny cannot enter
RestrictSmall, // Small cannot enter
RestrictMedium, // Medium cannot enter
RestrictLarge, // Large cannot enter
RestrictHuge, // Huge cannot enter
Lava, // Lava terrain
};

constexpr pf_special operator | ( pf_special lhs, pf_special rhs )
class PathfindingFlags
{
return static_cast<pf_special>( static_cast< int >( lhs ) | static_cast< int >( rhs ) );
public:
constexpr PathfindingFlags() = default;

// NOLINTNEXTLINE(google-explicit-constructor)
constexpr PathfindingFlags( PathfindingFlag flag ) : flags_( uint32_t{ 1 } << static_cast<uint8_t>
( flag ) ) {}

constexpr void set_union( PathfindingFlags flags ) {
flags_ |= flags.flags_;
}
constexpr void set_intersect( PathfindingFlags flags ) {
flags_ &= flags.flags_;
}
constexpr void set_clear( PathfindingFlags flags ) {
flags_ &= ~flags.flags_;
}

constexpr void clear() {
flags_ = 0;
}

constexpr bool is_set( PathfindingFlag flag ) const {
return flags_ & ( uint32_t{ 1 } << static_cast<uint8_t>( flag ) );
}
constexpr bool is_set( PathfindingFlags flags ) const {
return ( flags_ & flags.flags_ ) == flags.flags_;
}

constexpr bool is_any_set() const {
return flags_;
}

constexpr explicit operator bool() const {
return is_any_set();
}

constexpr PathfindingFlags &operator|=( PathfindingFlags flags ) {
set_union( flags );
return *this;
}

constexpr PathfindingFlags &operator&=( PathfindingFlags flags ) {
set_intersect( flags );
return *this;
}

private:
uint32_t flags_ = 0;
};

constexpr PathfindingFlags operator|( PathfindingFlags lhs, PathfindingFlags rhs )
{
return lhs |= rhs;
}

constexpr PathfindingFlags operator&( PathfindingFlags lhs, PathfindingFlags rhs )
{
return lhs &= rhs;
}

constexpr pf_special operator & ( pf_special lhs, pf_special rhs )
constexpr PathfindingFlags operator|( PathfindingFlags lhs, PathfindingFlag rhs )
{
return static_cast<pf_special>( static_cast< int >( lhs ) & static_cast< int >( rhs ) );
return lhs |= rhs;
}

inline pf_special &operator |= ( pf_special &lhs, pf_special rhs )
constexpr PathfindingFlags operator&( PathfindingFlags lhs, PathfindingFlag rhs )
{
lhs = static_cast<pf_special>( static_cast< int >( lhs ) | static_cast< int >( rhs ) );
return lhs;
return lhs &= rhs;
}

inline pf_special &operator &= ( pf_special &lhs, pf_special rhs )
constexpr PathfindingFlags operator |( const PathfindingFlag &a, const PathfindingFlag &b )
{
lhs = static_cast<pf_special>( static_cast< int >( lhs ) & static_cast< int >( rhs ) );
return lhs;
return PathfindingFlags( a ) | PathfindingFlags( b );
}

struct pathfinding_cache {
Expand All @@ -46,7 +125,7 @@ struct pathfinding_cache {
bool dirty = false;
std::unordered_set<point> dirty_points;

cata::mdarray<pf_special, point_bub_ms> special;
cata::mdarray<PathfindingFlags, point_bub_ms> special;
};

struct pathfinding_settings {
Expand Down
Loading