Skip to content

Commit

Permalink
refactor: make route() take a predicate for path_avoid (#74301)
Browse files Browse the repository at this point in the history
* refactor: make route() take a predicate for path_avoid

* no need to unclose start/end any more

* move check to child tile

* fix include order

* const function&

* inline

* null check

* fix vehicle_fake_part_test
  • Loading branch information
nornagon authored Jun 18, 2024
1 parent 46913cd commit d2d761f
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 111 deletions.
4 changes: 2 additions & 2 deletions src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ std::vector<tripoint_bub_ms> route_adjacent( const Character &you, const tripoin
const std::vector<tripoint_bub_ms> &sorted =
get_sorted_tiles_by_distance( you.pos_bub(), passable_tiles );

const std::unordered_set<tripoint> &avoid = you.get_path_avoid();
const auto &avoid = you.get_path_avoid();
for( const tripoint_bub_ms &tp : sorted ) {
std::vector<tripoint_bub_ms> route =
here.route( you.pos_bub(), tp, you.get_pathfinding_settings(), avoid );
Expand Down Expand Up @@ -745,7 +745,7 @@ static std::vector<tripoint_bub_ms> route_best_workbench(
return best_bench_multi_a > best_bench_multi_b;
};
std::stable_sort( sorted.begin(), sorted.end(), cmp );
const std::unordered_set<tripoint> &avoid = you.get_path_avoid();
const auto &avoid = you.get_path_avoid();
if( sorted.front() == you.pos_bub() ) {
// We are on the best tile
return {};
Expand Down
14 changes: 5 additions & 9 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10072,18 +10072,14 @@ float Character::adjust_for_focus( float amount ) const
return amount * ( effective_focus / 100.0f );
}

std::unordered_set<tripoint> Character::get_path_avoid() const
std::function<bool( const tripoint & )> Character::get_path_avoid() const
{
std::unordered_set<tripoint> ret;
for( npc &guy : g->all_npcs() ) {
if( sees( guy ) ) {
ret.insert( guy.pos() );
}
}

// TODO: Add known traps in a way that doesn't destroy performance

return ret;
return [this]( const tripoint & p ) {
Creature *critter = get_creature_tracker().creature_at( p, true );
return critter && critter->is_npc() && this->sees( *critter );
};
}

const pathfinding_settings &Character::get_pathfinding_settings() const
Expand Down
2 changes: 1 addition & 1 deletion src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -3265,7 +3265,7 @@ class Character : public Creature, public visitable
int run_cost( int base_cost, bool diag = false ) const;

const pathfinding_settings &get_pathfinding_settings() const override;
std::unordered_set<tripoint> get_path_avoid() const override;
std::function<bool( const tripoint & )> get_path_avoid() const override;
/**
* Get all hostile creatures currently visible to this player.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ class Creature : public viewer
/** Returns settings for pathfinding. */
virtual const pathfinding_settings &get_pathfinding_settings() const = 0;
/** Returns a set of points we do not want to path through. */
virtual std::unordered_set<tripoint> get_path_avoid() const = 0;
virtual std::function<bool( const tripoint & )> get_path_avoid() const = 0;

bool underwater;
void draw( const catacurses::window &w, const point_bub_ms &origin, bool inverted ) const;
Expand Down
18 changes: 7 additions & 11 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4528,9 +4528,8 @@ Creature *game::is_hostile_within( int distance, bool dangerous )
}

const pathfinding_settings pf_settings = pathfinding_settings{ 8, distance, distance * 2, 4, true, true, false, true, false, false };
static const std::unordered_set<tripoint> path_avoid = {};

if( !get_map().route( u.pos(), critter->pos(), pf_settings, path_avoid ).empty() ) {
if( !get_map().route( u.pos(), critter->pos(), pf_settings ).empty() ) {
return critter;
}
continue;
Expand Down Expand Up @@ -7649,17 +7648,14 @@ std::optional<std::vector<tripoint_bub_ms>> game::safe_route_to( Character &who,
}
};
route_t shortest_route;
std::unordered_set<tripoint> path_avoid;
for( const tripoint_bub_ms &p : points_in_radius( who.pos_bub(), 60 ) ) {
if( is_dangerous_tile( p.raw() ) ) {
path_avoid.insert( p.raw() );
}
}
for( const tripoint_bub_ms &p : here.points_in_radius( target, threshold, 0 ) ) {
if( path_avoid.count( p.raw() ) > 0 ) {
continue; // dont route to dangerous tiles
if( is_dangerous_tile( p.raw() ) ) {
continue;
}
const route_t route = here.route( who.pos_bub(), p, who.get_pathfinding_settings(), path_avoid );
const route_t route = here.route( who.pos_bub(), p,
who.get_pathfinding_settings(), [this]( const tripoint & p ) {
return is_dangerous_tile( p );
} );
if( route.empty() ) {
continue; // no route
}
Expand Down
9 changes: 7 additions & 2 deletions src/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "lightmap.h"
#include "line.h"
#include "lru_cache.h"
#include "map_iterator.h"
#include "map_selector.h"
#include "mapdata.h"
#include "maptile_fwd.h"
Expand Down Expand Up @@ -731,10 +732,14 @@ class map
// TODO: fix point types (remove the first overload)
std::vector<tripoint> route( const tripoint &f, const tripoint &t,
const pathfinding_settings &settings,
const std::unordered_set<tripoint> &pre_closed = {{ }} ) const;
const std::function<bool( const tripoint & )> &avoid = []( const tripoint & ) {
return false;
} ) const;
std::vector<tripoint_bub_ms> route( const tripoint_bub_ms &f, const tripoint_bub_ms &t,
const pathfinding_settings &settings,
const std::unordered_set<tripoint> &pre_closed = {{ }} ) const;
const std::function<bool( const tripoint & )> &avoid = []( const tripoint & ) {
return false;
} ) const;

// Get a straight route from f to t, only along non-rough terrain. Returns an empty vector
// if that is not possible.
Expand Down
5 changes: 1 addition & 4 deletions src/monmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1011,10 +1011,7 @@ void monster::move()
} else {
path = here.straight_route( pos(), local_dest );
if( !path.empty() ) {
std::unordered_set<tripoint> closed = get_path_avoid();
if( std::any_of( path.begin(), path.end(), [&closed]( const tripoint & p ) {
return closed.count( p );
} ) ) {
if( std::any_of( path.begin(), path.end(), get_path_avoid() ) ) {
path.clear();
}
}
Expand Down
44 changes: 20 additions & 24 deletions src/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3948,33 +3948,29 @@ const pathfinding_settings &monster::get_pathfinding_settings() const
return type->path_settings;
}

std::unordered_set<tripoint> monster::get_path_avoid() const
std::function<bool( const tripoint & )> monster::get_path_avoid() const
{
std::unordered_set<tripoint> ret;

map &here = get_map();
int radius = std::min( sight_range( here.ambient_light_at( pos_bub() ) ), 5 );

for( const tripoint &p : here.points_in_radius( pos(), radius ) ) {
if( !can_move_to( p ) ) {
if( bash_skill() <= 0 || !here.is_bashable( p ) ) {
ret.insert( p );
}
return [this]( const tripoint & p ) {
map &here = get_map();
// If we can't move there and can't bash it, don't path through it.
if( !can_move_to( p ) && ( bash_skill() <= 0 || !here.is_bashable( p ) ) ) {
return true;
}
}

if( has_flag( mon_flag_PRIORITIZE_TARGETS ) ) {
radius = 2;
} else if( has_flag( mon_flag_PATH_AVOID_DANGER ) ) {
radius = 1;
} else {
return ret;
}
for( Creature *critter : here.get_creatures_in_radius( pos(), radius ) ) {
ret.insert( critter->pos() );
}

return ret;
// Avoid nearby creatures if we have the flag.
int radius;
if( has_flag( mon_flag_PRIORITIZE_TARGETS ) ) {
radius = 2;
} else if( has_flag( mon_flag_PATH_AVOID_DANGER ) ) {
radius = 1;
} else {
return false;
}
if( rl_dist( p, pos() ) <= radius && get_creature_tracker().creature_at( p ) ) {
return true;
}
return false;
};
}

double monster::calculate_by_enchantment( double modify, enchant_vals::mod value,
Expand Down
2 changes: 1 addition & 1 deletion src/monster.h
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ class monster : public Creature
void on_load();

const pathfinding_settings &get_pathfinding_settings() const override;
std::unordered_set<tripoint> get_path_avoid() const override;
std::function<bool( const tripoint & )> get_path_avoid() const override;
double calculate_by_enchantment( double modify, enchant_vals::mod value,
bool round_output = false ) const;
private:
Expand Down
54 changes: 18 additions & 36 deletions src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3337,50 +3337,32 @@ const pathfinding_settings &npc::get_pathfinding_settings( bool no_bashing ) con
return *path_settings;
}

std::unordered_set<tripoint> npc::get_path_avoid() const
std::function<bool( const tripoint & )> npc::get_path_avoid() const
{
std::unordered_set<tripoint> ret;
for( Creature &critter : g->all_creatures() ) {
// TODO: Cache this somewhere
ret.insert( critter.pos() );
}
map &here = get_map();
if( rules.has_flag( ally_rule::avoid_doors ) ) {
for( const tripoint &p : here.points_in_radius( pos(), 30 ) ) {
if( here.open_door( *this, p, true, true ) ) {
ret.insert( p );
}
return [this]( const tripoint & p ) {
if( get_creature_tracker().creature_at( p ) ) {
return true;
}
}
if( rules.has_flag( ally_rule::avoid_locks ) ) {
for( const tripoint &p : here.points_in_radius( pos(), 30 ) ) {
if( doors::can_unlock_door( here, *this, tripoint_bub_ms( p ) ) ) {
ret.insert( p );
}
map &here = get_map();
if( rules.has_flag( ally_rule::avoid_doors ) && here.open_door( *this, p, true, true ) ) {
return true;
}
}
if( rules.has_flag( ally_rule::hold_the_line ) ) {
for( const tripoint &p : here.points_in_radius( get_player_character().pos(), 1 ) ) {
if( here.close_door( p, true, true ) || here.move_cost( p ) > 2 ) {
ret.insert( p );
}
if( rules.has_flag( ally_rule::avoid_locks ) &&
doors::can_unlock_door( here, *this, tripoint_bub_ms( p ) ) ) {
return true;
}
if( rules.has_flag( ally_rule::hold_the_line ) && ( here.close_door( p, true, true ) ||
here.move_cost( p ) > 2 ) ) {
return true;
}
}

for( const tripoint &p : here.points_in_radius( pos(), 6 ) ) {
if( sees_dangerous_field( p ) ) {
ret.insert( p );
return true;
}
}

// Why is this in path avoid if they can't move there at all?
for( const tripoint &p : here.points_in_radius( pos(), 6 ) ) {
if( !can_move_to_vehicle_tile( here.getglobal( p ) ) ) {
ret.insert( p );
return true;
}
}

return ret;
return false;
};
}

mfaction_id npc::get_monster_faction() const
Expand Down
2 changes: 1 addition & 1 deletion src/npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,7 @@ class npc : public Character

const pathfinding_settings &get_pathfinding_settings() const override;
const pathfinding_settings &get_pathfinding_settings( bool no_bashing ) const;
std::unordered_set<tripoint> get_path_avoid() const override;
std::function<bool( const tripoint & )> get_path_avoid() const override;

// Item discovery and fetching

Expand Down
27 changes: 10 additions & 17 deletions src/pathfinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ int map::extra_cost( const tripoint &cur, const tripoint &p, const pathfinding_s

std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
const pathfinding_settings &settings,
const std::unordered_set<tripoint> &pre_closed ) const
const std::function<bool( const tripoint & )> &avoid ) const
{
/* TODO: If the origin or destination is out of bound, figure out the closest
* in-bounds point and go to that, then to the real origin/destination.
Expand All @@ -365,16 +365,14 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
if( !inbounds( t ) ) {
tripoint clipped = t;
clip_to_bounds( clipped );
return route( f, clipped, settings, pre_closed );
return route( f, clipped, settings, avoid );
}
// First, check for a simple straight line on flat ground
// Except when the line contains a pre-closed tile - we need to do regular pathing then
if( f.z == t.z ) {
auto line_path = straight_route( f, t );
if( !line_path.empty() ) {
if( std::none_of( line_path.begin(), line_path.end(), [&pre_closed]( const tripoint & p ) {
return pre_closed.count( p );
} ) ) {
if( std::none_of( line_path.begin(), line_path.end(), avoid ) ) {
return line_path;
}
}
Expand All @@ -394,17 +392,7 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
clip_to_bounds( max.x, max.y, max.z );

pf.reset( min.z, max.z );
// Make NPCs not want to path through player
// But don't make player pathing stop working
for( const tripoint &p : pre_closed ) {
if( p.x >= min.x && p.x < max.x && p.y >= min.y && p.y < max.y ) {
pf.close_point( p );
}
}

// Start and end must not be closed
pf.unclose_point( f );
pf.unclose_point( t );
pf.add_point( 0, 0, f, f );

bool done = false;
Expand Down Expand Up @@ -447,6 +435,11 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,
continue;
}

if( p != t && avoid( p ) ) {
layer.closed[index] = true;
continue;
}

if( layer.closed[index] ) {
continue;
}
Expand Down Expand Up @@ -613,9 +606,9 @@ std::vector<tripoint> map::route( const tripoint &f, const tripoint &t,

std::vector<tripoint_bub_ms> map::route( const tripoint_bub_ms &f, const tripoint_bub_ms &t,
const pathfinding_settings &settings,
const std::unordered_set<tripoint> &pre_closed ) const
const std::function<bool( const tripoint & )> &avoid ) const
{
std::vector<tripoint> raw_result = route( f.raw(), t.raw(), settings, pre_closed );
std::vector<tripoint> raw_result = route( f.raw(), t.raw(), settings, avoid );
std::vector<tripoint_bub_ms> result;
std::transform( raw_result.begin(), raw_result.end(), std::back_inserter( result ),
[]( const tripoint & p ) {
Expand Down
3 changes: 1 addition & 2 deletions tests/vehicle_fake_part_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,7 @@ TEST_CASE( "vehicle_with_fake_obstacle_parts_block_movement", "[vehicle][vehicle
std::vector<tripoint_bub_ms> route = here.route(
tripoint_bub_ms( test_origin - point( 2, 0 ) ),
tripoint_bub_ms( test_origin + point( 2, 0 ) ),
you.get_pathfinding_settings(),
{} );
you.get_pathfinding_settings() );
REQUIRE( !route.empty() );
CAPTURE( route );
REQUIRE( route.size() == 7 );
Expand Down

0 comments on commit d2d761f

Please sign in to comment.