void overmapbuffer::fix_npcs( overmap &new_overmap ) { // First step: move all npcs that are located outside of the given overmap // into a separate container. After that loop, new_overmap.npcs is no // accessed anymore! decltype( overmap::npcs ) to_relocate; for( auto it = new_overmap.npcs.begin(); it != new_overmap.npcs.end(); ) { npc &np = **it; const tripoint npc_omt_pos = np.global_omt_location(); const point npc_om_pos = omt_to_om_copy( npc_omt_pos.x, npc_omt_pos.y ); const point &loc = new_overmap.pos(); if( npc_om_pos == loc ) { // Nothing to do ++it; continue; } to_relocate.push_back( *it ); it = new_overmap.npcs.erase( it ); } // Second step: put them back where they belong. This step involves loading // new overmaps (via `get`), which does in turn call this function for the // newly loaded overmaps. This in turn may move NPCs from the second overmap // back into the first overmap. This messes up the iteration of it. The // iteration is therefore done in a separate step above (which does *not* // involve loading new overmaps). for( auto &ptr : to_relocate ) { npc &np = *ptr; const tripoint npc_omt_pos = np.global_omt_location(); const point npc_om_pos = omt_to_om_copy( npc_omt_pos.x, npc_omt_pos.y ); const point &loc = new_overmap.pos(); if( !has( npc_om_pos.x, npc_om_pos.y ) ) { // This can't really happen without save editing // We have no sane option here, just place the NPC on the edge debugmsg( "NPC %s is out of bounds, on non-generated overmap %d,%d", np.name.c_str(), loc.x, loc.y ); point npc_sm = om_to_sm_copy( npc_om_pos ); point min = om_to_sm_copy( loc ); point max = om_to_sm_copy( loc + point( 1, 1 ) ) - point( 1, 1 ); npc_sm.x = clamp( npc_sm.x, min.x, max.x ); npc_sm.y = clamp( npc_sm.y, min.y, max.y ); np.spawn_at_sm( npc_sm.x, npc_sm.y, np.posz() ); new_overmap.npcs.push_back( ptr ); continue; } // Simplest case: just move the pointer get( npc_om_pos.x, npc_om_pos.y ).insert_npc( ptr ); } }
radio_tower_reference create_radio_tower_reference( overmap &om, radio_tower &t, const tripoint ¢er ) { // global submap coordinates, same as center is const point pos = point( t.x, t.y ) + om_to_sm_copy( om.pos() ); const int strength = t.strength - rl_dist( tripoint( pos, 0 ), center ); return radio_tower_reference{ &om, &t, pos, strength }; }
void overmapbuffer::signal_hordes( const tripoint ¢er, const int sig_power ) { const auto radius = sig_power; for( auto &om : get_overmaps_near( center, radius ) ) { const point abs_pos_om = om_to_sm_copy( om->pos() ); const tripoint rel_pos( center.x - abs_pos_om.x, center.y - abs_pos_om.y, center.z ); // overmap::signal_hordes expects a coordinate relative to the overmap, this is easier // for processing as the monster group stores is location as relative coordinates, too. om->signal_hordes( rel_pos, sig_power ); } }
city_reference overmapbuffer::closest_city( const tripoint ¢er ) { // a whole overmap (because it's in submap coordinates, OMAPX is overmap terrain coordinates) auto const radius = OMAPX * 2; // Starting with distance = INT_MAX, so the first city is already closer city_reference result{ nullptr, nullptr, tripoint( 0, 0, 0 ), INT_MAX }; for( auto &om : get_overmaps_near( center, radius ) ) { const auto abs_pos_om = om_to_sm_copy( om->pos() ); for( auto &city : om->cities ) { const auto rel_pos_city = omt_to_sm_copy( point( city.x, city.y ) ); // TODO: Z-level cities. This 0 has to be here until mapgen understands non-0 zlev cities const auto abs_pos_city = tripoint( abs_pos_om + rel_pos_city, 0 ); const auto distance = rl_dist( abs_pos_city, center ); const city_reference cr{ om, &city, abs_pos_city, distance }; if( distance < result.distance ) { result = cr; } else if( distance == result.distance && result.city->s < city.s ) { result = cr; } } } return result; }
std::vector<city_reference> overmapbuffer::get_cities_near( const tripoint &location, int radius ) { std::vector<city_reference> result; for( const auto om : get_overmaps_near( location, radius ) ) { const auto abs_pos_om = om_to_sm_copy( om->pos() ); result.reserve( result.size() + om->cities.size() ); std::transform( om->cities.begin(), om->cities.end(), std::back_inserter( result ), [&]( city & element ) { const auto rel_pos_city = omt_to_sm_copy( element.pos ); const auto abs_pos_city = tripoint( rel_pos_city + abs_pos_om, 0 ); const auto distance = rl_dist( abs_pos_city, location ); return city_reference{ &element, abs_pos_city, distance }; } ); } std::sort( result.begin(), result.end(), []( const city_reference & lhs, const city_reference & rhs ) { return lhs.get_distance_from_bounds() < rhs.get_distance_from_bounds(); } ); return result; }