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

refactor: make route() take a predicate for path_avoid #74301

Merged
merged 9 commits into from
Jun 18, 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
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 @@ -10035,18 +10035,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 @@ -3257,7 +3257,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 @@ -4508,9 +4508,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 @@ -7629,17 +7628,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 @@ -729,10 +730,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 @@ -3946,33 +3946,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 @@ -191,7 +191,7 @@ std::vector<tripoint> map::straight_route( const tripoint &f, const tripoint &t

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 @@ -205,16 +205,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 Down Expand Up @@ -242,17 +240,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 @@ -296,6 +284,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 @@ -557,9 +550,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
Loading