void talk_function::goto_location( npc &p )
{
    int i = 0;
    uilist selection_menu;
    selection_menu.text = string_format( _( "Select a destination" ) );
    std::vector<basecamp *> camps;
    tripoint destination;
    for( auto elem : g->u.camps ) {
        if( elem == p.global_omt_location() ) {
            continue;
        }
        cata::optional<basecamp *> camp = overmap_buffer.find_camp( elem.x, elem.y );
        if( !camp ) {
            continue;
        }
        basecamp *temp_camp = *camp;
        camps.push_back( temp_camp );
    }
    for( auto iter : camps ) {
        selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "%s at (%d, %d)" ), iter->camp_name(),
                                 iter->camp_omt_pos().x, iter->camp_omt_pos().y );
    }
    selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "My current location" ) );
    selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "Cancel" ) );
    selection_menu.selected = 0;
    selection_menu.query();
    auto index = selection_menu.ret;
    if( index < 0 || index > static_cast<int>( camps.size() + 1 ) ||
        index == static_cast<int>( camps.size() + 1 ) || index == UILIST_CANCEL ) {
        return;
    }
    if( index == static_cast<int>( camps.size() ) ) {
        destination = g->u.global_omt_location();
    } else {
        auto selected_camp = camps[index];
        destination = selected_camp->camp_omt_pos();
    }
    p.set_companion_mission( p.global_omt_location(), "TRAVELLER", "travelling", destination );
    p.mission = NPC_MISSION_TRAVELLING;
    p.chatbin.first_topic = "TALK_FRIEND_GUARD";
    p.goal = destination;
    p.guard_pos = npc::no_goal_point;
    p.set_attitude( NPCATT_NULL );
    return;
}
void talk_function::stop_guard( npc &p )
{
    if( p.mission != NPC_MISSION_GUARD_ALLY ) {
        p.set_attitude( NPCATT_NULL );
        p.mission = NPC_MISSION_NULL;
        return;
    }

    p.set_attitude( NPCATT_FOLLOW );
    add_msg( _( "%s begins to follow you." ), p.name );
    p.mission = NPC_MISSION_NULL;
    p.chatbin.first_topic = "TALK_FRIEND";
    p.goal = npc::no_goal_point;
    p.guard_pos = npc::no_goal_point;
    cata::optional<basecamp *> bcp = overmap_buffer.find_camp( p.global_omt_location().x,
                                     p.global_omt_location().y );
    if( bcp ) {
        basecamp *temp_camp = *bcp;
        temp_camp->validate_assignees();
    }
}
void talk_function::assign_guard( npc &p )
{
    if( !p.is_following() ) {
        p.mission = NPC_MISSION_GUARD;
        p.set_omt_destination();
        return;
    }

    if( p.is_travelling() ) {
        if( p.has_companion_mission() ) {
            p.reset_companion_mission();
        }
    }
    p.set_attitude( NPCATT_NULL );
    p.mission = NPC_MISSION_GUARD_ALLY;
    p.chatbin.first_topic = "TALK_FRIEND_GUARD";
    p.set_omt_destination();
    cata::optional<basecamp *> bcp = overmap_buffer.find_camp( p.global_omt_location().x,
                                     p.global_omt_location().y );
    if( bcp ) {
        basecamp *temp_camp = *bcp;
        temp_camp->validate_assignees();
        if( p.rules.has_flag( ally_rule::ignore_noise ) ) {
            //~ %1$s is the NPC's translated name, %2$s is the translated faction camp name
            add_msg( _( "%1$s is assigned to %2$s" ), p.disp_name(), temp_camp->camp_name() );
        } else {
            //~ %1$s is the NPC's translated name, %2$s is the translated faction camp name
            add_msg( _( "%1$s is assigned to guard %2$s" ), p.disp_name(), temp_camp->camp_name() );
        }
    } else {
        if( p.rules.has_flag( ally_rule::ignore_noise ) ) {
            //~ %1$s is the NPC's translated name, %2$s is the pronoun for the NPC's gender
            add_msg( _( "%1$s will wait for you where %2$s is." ), p.disp_name(),
                     p.male ? _( "he" ) : _( "she" ) );
        } else {
            add_msg( _( "%s is posted as a guard." ), p.disp_name() );
        }
    }
}
void basecamp::define_camp( npc &p )
{
    query_new_name();
    omt_pos = p.global_omt_location();
    sort_points = p.companion_mission_points;
    // purging the regions guarantees all entries will start with faction_base_
    for( std::pair<std::string, tripoint> expansion : talk_function::om_building_region( omt_pos, 1,
            true ) ) {
        add_expansion( expansion.first, expansion.second );
    }
    const std::string om_cur = overmap_buffer.ter( omt_pos ).id().c_str();
    if( om_cur.find( prefix ) == std::string::npos ) {
        expansion_data e;
        e.type = "camp";
        e.cur_level = 0;
        e.pos = omt_pos;
        expansions[ base_dir ] = e;
    } else {
        expansions[ base_dir ] = parse_expansion( om_cur, omt_pos );
    }
}