From 949ecdfb095dc4874b0527b29f3455f5b26b54cf Mon Sep 17 00:00:00 2001 From: Ivan Zaitsev Date: Tue, 8 Dec 2020 13:04:18 -0800 Subject: [PATCH] improve npc overmap travel: (#45896) * recalculate goal when it's not reachable * still look for needs if CITY_SIZE=0 * change `overmap_location::terrains` type to `flat_set`, refactor `npc::set_omt_destination` --- src/game.cpp | 12 +++++++++++- src/npcmove.cpp | 30 +++++++++++++++--------------- src/overmap_location.cpp | 15 ++++----------- src/overmap_location.h | 8 +++++--- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 16843dd7d433b..3d5c40288a2da 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -4661,6 +4661,7 @@ void game::overmap_npc_move() travelling_npcs.push_back( npc_to_add ); } } + bool npcs_need_reload = false; for( auto &elem : travelling_npcs ) { if( elem->has_omt_destination() ) { if( !elem->omt_path.empty() && rl_dist( elem->omt_path.back(), elem->global_omt_location() ) > 2 ) { @@ -4669,6 +4670,9 @@ void game::overmap_npc_move() } if( elem->omt_path.empty() ) { elem->omt_path = overmap_buffer.get_npc_path( elem->global_omt_location(), elem->goal ); + if( elem->omt_path.empty() ) { // goal is unreachable, reset it + elem->goal = npc::no_goal_point; + } } else { if( elem->omt_path.back() == elem->global_omt_location() ) { elem->omt_path.pop_back(); @@ -4676,10 +4680,16 @@ void game::overmap_npc_move() // TODO: fix point types elem->travel_overmap( project_to( elem->omt_path.back() ).raw() ); + npcs_need_reload = true; } - reload_npcs(); + } else if( calendar::once_every( 1_hours ) && one_in( 3 ) ) { + // travelling destination is reached/not set, try different one + elem -> set_omt_destination(); } } + if( npcs_need_reload ) { + reload_npcs(); + } } /* Knockback target at t by force number of tiles in direction from s to t diff --git a/src/npcmove.cpp b/src/npcmove.cpp index fc4db819e694c..33254936d9e9d 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -4084,40 +4084,40 @@ void npc::set_omt_destination() // We need that, otherwise find_closest won't work properly surface_omt_loc.z() = 0; - // also, don't bother looking if the CITY_SIZE is 0, just go somewhere at random - const int city_size = get_option( "CITY_SIZE" ); - if( city_size == 0 ) { - goal = surface_omt_loc + point( rng( -90, 90 ), rng( -90, 90 ) ); - return; - } - decide_needs(); if( needs.empty() ) { // We don't need anything in particular. needs.push_back( need_none ); + + // also, don't bother looking if the CITY_SIZE is 0, just go somewhere at random + const int city_size = get_option( "CITY_SIZE" ); + if( city_size == 0 ) { + goal = surface_omt_loc + point( rng( -90, 90 ), rng( -90, 90 ) ); + return; + } } std::string dest_type; for( const auto &fulfill : needs ) { // look for the closest occurence of any of that locations terrain types - std::vector loc_list = get_location_for( fulfill )->get_all_terrains(); - std::shuffle( loc_list.begin(), loc_list.end(), rng_get_engine() ); omt_find_params find_params; - std::vector> temp_types; - for( const oter_type_id &elem : loc_list ) { + for( const oter_type_str_id &elem : get_location_for( fulfill )->get_all_terrains() ) { std::pair temp_pair; - temp_pair.first = elem.id().str(); + temp_pair.first = elem.str(); temp_pair.second = ot_match_type::type; - temp_types.push_back( temp_pair ); + find_params.types.push_back( temp_pair ); } + // note: no shuffle of `find_params.types` is needed, because `find_closest` + // disregards `types` order anyway, and already returns random result among + // those having equal minimal distance find_params.search_range = 75; - find_params.types = temp_types; find_params.existing_only = false; goal = overmap_buffer.find_closest( surface_omt_loc, find_params ); - omt_path = overmap_buffer.get_npc_path( surface_omt_loc, goal ); + omt_path.clear(); if( goal != overmap::invalid_tripoint ) { omt_path = overmap_buffer.get_npc_path( surface_omt_loc, goal ); } if( !omt_path.empty() ) { + dest_type = overmap_buffer.ter( goal )->get_type_id().str(); break; } } diff --git a/src/overmap_location.cpp b/src/overmap_location.cpp index b30fa62647abc..3fa4f7f17110d 100644 --- a/src/overmap_location.cpp +++ b/src/overmap_location.cpp @@ -33,10 +33,7 @@ const overmap_location &string_id::obj() const bool overmap_location::test( const int_id &oter ) const { - return std::any_of( terrains.cbegin(), terrains.cend(), - [ &oter ]( const oter_type_str_id & type ) { - return oter->type_is( type ); - } ); + return terrains.count( oter->get_type_id() ); } oter_type_id overmap_location::get_random_terrain() const @@ -53,13 +50,9 @@ void overmap_location::load( const JsonObject &jo, const std::string & ) } } -std::vector overmap_location::get_all_terrains() const +const cata::flat_set &overmap_location::get_all_terrains() const { - std::vector ret; - for( const oter_type_str_id &elem : terrains ) { - ret.push_back( elem ); - } - return ret; + return terrains; } void overmap_location::check() const @@ -81,7 +74,7 @@ void overmap_location::finalize() oter_flags check_flag = it->second; for( const oter_t &ter_elem : overmap_terrains::get_all() ) { if( ter_elem.has_flag( check_flag ) ) { - terrains.push_back( ter_elem.get_type_id() ); + terrains.insert( ter_elem.get_type_id() ); } } } diff --git a/src/overmap_location.h b/src/overmap_location.h index 8128cc9f27b74..fcf4062fe498a 100644 --- a/src/overmap_location.h +++ b/src/overmap_location.h @@ -6,6 +6,7 @@ #include #include +#include "flat_set.h" #include "int_id.h" #include "string_id.h" #include "type_id.h" @@ -15,22 +16,23 @@ struct oter_t; struct overmap_location { public: + using TerrColType = cata::flat_set; + void load( const JsonObject &jo, const std::string &src ); void check() const; void finalize(); // Test if oter meets the terrain restrictions. bool test( const int_id &oter ) const; - std::vector get_all_terrains() const; + const TerrColType &get_all_terrains() const; oter_type_id get_random_terrain() const; - public: // Used by generic_factory string_id id; bool was_loaded = false; private: - std::vector terrains; + TerrColType terrains; std::vector flags; };