bool live_view::hide(bool refresh /*= true*/, bool force /*= false*/)
{
    if (!enabled || (!inuse && !force)) {
        return false;
    }

#if (defined TILES || defined SDLTILES || defined _WIN32 || defined WINDOWS)
    int full_height = w_live_view->height;
    if (use_narrow_sidebar() && last_height > 0) {
        // When using the narrow sidebar mode, the lower part of the screen
        // is used for the message queue. Best not to obscure too much of it.
        w_live_view->height = last_height;
    }
#endif

    werase(*this);

#if (defined TILES || defined SDLTILES || defined _WIN32 || defined WINDOWS)
    w_live_view->height = full_height;
#endif

    inuse = false;
    last_height = -1;
    if (refresh) {
        wrefresh(*this);
    }

    return true;
}
Beispiel #2
0
// Pick up items at (pos).
void Pickup::pick_up( const tripoint &pos, int min )
{
    int veh_root_part = 0;
    int cargo_part = -1;

    vehicle *veh = g->m.veh_at( pos, veh_root_part );
    bool from_vehicle = false;

    if( min != -1 ) {
        switch( interact_with_vehicle( veh, pos, veh_root_part ) ) {
            case DONE:
                return;
            case ITEMS_FROM_CARGO:
                cargo_part = veh->part_with_feature( veh_root_part, "CARGO", false );
                from_vehicle = cargo_part >= 0;
                break;
            case ITEMS_FROM_GROUND:
                // Nothing to change, default is to pick from ground anyway.
                if( g->m.has_flag( "SEALED", pos ) ) {
                    return;
                }

                break;
        }
    }

    if( !from_vehicle ) {
        bool isEmpty = ( g->m.i_at( pos ).empty() );

        // Hide the pickup window if this is a toilet and there's nothing here
        // but water.
        if( ( !isEmpty ) && g->m.furn( pos ) == f_toilet ) {
            isEmpty = true;
            for( auto maybe_water : g->m.i_at( pos ) ) {
                if( maybe_water.typeId() != "water" ) {
                    isEmpty = false;
                    break;
                }
            }
        }

        if( isEmpty && ( min != -1 || !OPTIONS["AUTO_PICKUP_ADJACENT"] ) ) {
            return;
        }
    }

    // which items are we grabbing?
    std::vector<item> here;
    if( from_vehicle ) {
        auto vehitems = veh->get_items( cargo_part );
        here.resize( vehitems.size() );
        std::copy( vehitems.rbegin(), vehitems.rend(), here.begin() );
    } else {
        auto mapitems = g->m.i_at( pos );
        here.resize( mapitems.size() );
        std::copy( mapitems.rbegin(), mapitems.rend(), here.begin() );
    }

    if( min == -1 ) {
        if( g->check_zone( "NO_AUTO_PICKUP", pos ) ) {
            here.clear();
        }

        // Recursively pick up adjacent items if that option is on.
        if( OPTIONS["AUTO_PICKUP_ADJACENT"] && g->u.pos() == pos ) {
            //Autopickup adjacent
            direction adjacentDir[8] = {NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST};
            for( auto &elem : adjacentDir ) {

                tripoint apos = tripoint( direction_XY( elem ), 0 );
                apos += pos;

                if( g->m.has_flag( "SEALED", apos ) ) {
                    continue;
                }
                if( g->check_zone( "NO_AUTO_PICKUP", apos ) ) {
                    continue;
                }
                pick_up( apos, min );
            }
        }
    }

    // Not many items, just grab them
    if( ( int )here.size() <= min && min != -1 ) {
        g->u.assign_activity( ACT_PICKUP, 0 );
        g->u.activity.placement = pos - g->u.pos();
        g->u.activity.values.push_back( from_vehicle );
        // Only one item means index is 0.
        g->u.activity.values.push_back( 0 );
        // auto-pickup means pick up all.
        g->u.activity.values.push_back( 0 );
        return;
    }

    if( min != -1 ) { // don't bother if we're just autopickup-ing
        g->temp_exit_fullscreen();
    }
    bool sideStyle = use_narrow_sidebar();

    // Otherwise, we have Autopickup, 2 or more items and should list them, etc.
    int maxmaxitems = sideStyle ? TERMY : getmaxy( g->w_messages ) - 3;

    int itemsH = std::min( 25, TERMY / 2 );
    int pickupBorderRows = 3;

    // The pickup list may consume the entire terminal, minus space needed for its
    // header/footer and the item info window.
    int minleftover = itemsH + pickupBorderRows;
    if( maxmaxitems > TERMY - minleftover ) {
        maxmaxitems = TERMY - minleftover;
    }

    const int minmaxitems = sideStyle ? 6 : 9;

    std::vector<pickup_count> getitem( here.size() );

    int maxitems = here.size();
    maxitems = ( maxitems < minmaxitems ? minmaxitems : ( maxitems > maxmaxitems ? maxmaxitems :
                 maxitems ) );

    int itemcount = 0;

    if( min == -1 ) { //Auto Pickup, select matching items
        if( !select_autopickup_items( here, getitem ) ) {
            // If we didn't find anything, bail out now.
            return;
        }
    } else {
        int pickupH = maxitems + pickupBorderRows;
        int pickupW = getmaxx( g->w_messages );
        int pickupY = VIEW_OFFSET_Y;
        int pickupX = getbegx( g->w_messages );

        int itemsW = pickupW;
        int itemsY = sideStyle ? pickupY + pickupH : TERMY - itemsH;
        int itemsX = pickupX;

        WINDOW *w_pickup    = newwin( pickupH, pickupW, pickupY, pickupX );
        WINDOW *w_item_info = newwin( itemsH,  itemsW,  itemsY,  itemsX );
        WINDOW_PTR w_pickupptr( w_pickup );
        WINDOW_PTR w_item_infoptr( w_item_info );

        std::string action;
        long raw_input_char = ' ';
        input_context ctxt( "PICKUP" );
        ctxt.register_action( "UP" );
        ctxt.register_action( "DOWN" );
        ctxt.register_action( "RIGHT" );
        ctxt.register_action( "LEFT" );
        ctxt.register_action( "NEXT_TAB", _( "Next page" ) );
        ctxt.register_action( "PREV_TAB", _( "Previous page" ) );
        ctxt.register_action( "SCROLL_UP" );
        ctxt.register_action( "SCROLL_DOWN" );
        ctxt.register_action( "CONFIRM" );
        ctxt.register_action( "SELECT_ALL" );
        ctxt.register_action( "QUIT", _( "Cancel" ) );
        ctxt.register_action( "ANY_INPUT" );
        ctxt.register_action( "HELP_KEYBINDINGS" );

        int start = 0, cur_it;
        player pl_copy = g->u;
        pl_copy.set_fake( true );
        bool update = true;
        mvwprintw( w_pickup, 0, 0, _( "PICK UP" ) );
        int selected = 0;
        int iScrollPos = 0;

        if( g->was_fullscreen ) {
            g->draw_ter();
        }
        // Now print the two lists; those on the ground and about to be added to inv
        // Continue until we hit return or space
        do {
            const std::string pickup_chars =
                ctxt.get_available_single_char_hotkeys( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:;" );
            int idx = -1;
            for( int i = 1; i < pickupH; i++ ) {
                mvwprintw( w_pickup, i, 0,
                           "                                                " );
            }
            if( action == "ANY_INPUT" &&
                raw_input_char >= '0' && raw_input_char <= '9' ) {
                int raw_input_char_value = ( char )raw_input_char - '0';
                itemcount *= 10;
                itemcount += raw_input_char_value;
                if( itemcount < 0 ) {
                    itemcount = 0;
                }
            } else if( action == "SCROLL_UP" ) {
                iScrollPos--;
            } else if( action == "SCROLL_DOWN" ) {
                iScrollPos++;
            } else if( action == "PREV_TAB" ) {
                if( start > 0 ) {
                    start -= maxitems;
                } else {
                    start = ( int )( ( here.size() - 1 ) / maxitems ) * maxitems;
                }
                selected = start;
                mvwprintw( w_pickup, maxitems + 2, 0, "         " );
            } else if( action == "NEXT_TAB" ) {
                if( start + maxitems < ( int )here.size() ) {
                    start += maxitems;
                } else {
                    start = 0;
                }
                iScrollPos = 0;
                selected = start;
                mvwprintw( w_pickup, maxitems + 2, pickupH, "            " );
            } else if( action == "UP" ) {
                selected--;
                iScrollPos = 0;
                if( selected < 0 ) {
                    selected = here.size() - 1;
                    start = ( int )( here.size() / maxitems ) * maxitems;
                    if( start >= ( int )here.size() ) {
                        start -= maxitems;
                    }
                } else if( selected < start ) {
                    start -= maxitems;
                }
            } else if( action == "DOWN" ) {
                selected++;
                iScrollPos = 0;
                if( selected >= ( int )here.size() ) {
                    selected = 0;
                    start = 0;
                } else if( selected >= start + maxitems ) {
                    start += maxitems;
                }
            } else if( selected >= 0 && (
                           ( action == "RIGHT" && !getitem[selected] ) ||
                           ( action == "LEFT" && getitem[selected] )
                       ) ) {
                idx = selected;
            } else if( action == "ANY_INPUT" && raw_input_char == '`' ) {
                std::string ext = string_input_popup(
                                      _( "Enter 2 letters (case sensitive):" ), 3, "", "", "", 2 );
                if( ext.size() == 2 ) {
                    int p1 = pickup_chars.find( ext.at( 0 ) );
                    int p2 = pickup_chars.find( ext.at( 1 ) );
                    if( p1 != -1 && p2 != -1 ) {
                        idx = pickup_chars.size() + ( p1 * pickup_chars.size() ) + p2;
                    }
                }
            } else if( action == "ANY_INPUT" ) {
                idx = ( raw_input_char <= 127 ) ? pickup_chars.find( raw_input_char ) : -1;
                iScrollPos = 0;
            }

            if( idx >= 0 && idx < ( int )here.size() ) {
                if( getitem[idx] ) {
                    if( here[idx].count_by_charges() ) {
                        if( getitem[idx].count == 0 ) {
                            pl_copy.inv.find_item( getitem[idx].position ).charges -= here[idx].charges;
                        } else {
                            pl_copy.inv.find_item( getitem[idx].position ).charges -= getitem[idx].count;
                        }
                    } else {
                        unsigned stack_size = pl_copy.inv.const_stack( getitem[idx].position ).size();
                        pl_copy.i_rem( getitem[idx].position );
                        //if the stack_was emptied, removing the item invalidated later positions- fix them
                        if( stack_size == 1 ) {
                            for( unsigned i = 0; i < here.size(); i++ ) {
                                if( getitem[i] && getitem[i].position > getitem[idx].position ) {
                                    getitem[i].position--;
                                }
                            }
                        }
                    }
                } //end if getitem[idx]

                if( itemcount != 0 || getitem[idx].count == 0 ) {
                    if( itemcount >= here[idx].charges || !here[idx].count_by_charges() ) {
                        // Ignore the count if we pickup the whole stack anyway
                        // or something that is not counted by charges (tools)
                        itemcount = 0;
                    }
                    getitem[idx].count = itemcount;
                    itemcount = 0;
                }

                // Note: this might not change the value of getitem[idx] at all!
                getitem[idx].pick = ( action == "RIGHT" ? true : ( action == "LEFT" ? false : !getitem[idx] ) );
                if( action != "RIGHT" && action != "LEFT" ) {
                    selected = idx;
                    start = ( int )( idx / maxitems ) * maxitems;
                }

                if( getitem[idx] ) {
                    item temp = here[idx];
                    if( getitem[idx].count != 0 &&
                        getitem[idx].count < here[idx].charges ) {
                        temp.charges = getitem[idx].count;
                    }
                    item *added = &( pl_copy.i_add( temp ) );
                    getitem[idx].position = pl_copy.inv.position_by_item( added );
                } else {
                    getitem[idx].count = 0;
                }
                update = true;
            }

            werase( w_item_info );
            if( selected >= 0 && selected <= ( int )here.size() - 1 ) {
                std::vector<iteminfo> vThisItem, vDummy;
                here[selected].info( true, vThisItem );

                draw_item_info( w_item_info, "", "", vThisItem, vDummy, iScrollPos, true, true );
            }
            draw_custom_border( w_item_info, false );
            mvwprintw( w_item_info, 0, 2, "< " );
            trim_and_print( w_item_info, 0, 4, itemsW - 8, c_white, "%s >",
                            here[selected].display_name().c_str() );
            wrefresh( w_item_info );

            if( action == "SELECT_ALL" ) {
                int count = 0;
                for( size_t i = 0; i < here.size(); i++ ) {
                    if( getitem[i] ) {
                        count++;
                    } else {
                        item *added = &( pl_copy.i_add( here[i] ) );
                        getitem[i].position = pl_copy.inv.position_by_item( added );
                    }
                    getitem[i].pick = true;
                }
                if( count == ( int )here.size() ) {
                    for( size_t i = 0; i < here.size(); i++ ) {
                        getitem[i].pick = false;
                    }
                    pl_copy = g->u;
                    pl_copy.set_fake( true );
                }
                update = true;
            }

            for( cur_it = start; cur_it < start + maxitems; cur_it++ ) {
                mvwprintw( w_pickup, 1 + ( cur_it % maxitems ), 0,
                           "                                        " );
                if( cur_it < ( int )here.size() ) {
                    nc_color icolor = here[cur_it].color_in_inventory();
                    if( cur_it == selected ) {
                        icolor = hilite( icolor );
                    }

                    if( cur_it < ( int )pickup_chars.size() ) {
                        mvwputch( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor,
                                  char( pickup_chars[cur_it] ) );
                    } else if( cur_it < ( int )pickup_chars.size() + ( int )pickup_chars.size() *
                               ( int )pickup_chars.size() ) {
                        int p = cur_it - pickup_chars.size();
                        int p1 = p / pickup_chars.size();
                        int p2 = p % pickup_chars.size();
                        mvwprintz( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor, "`%c%c",
                                   char( pickup_chars[p1] ), char( pickup_chars[p2] ) );
                    } else {
                        mvwputch( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor, ' ' );
                    }
                    if( getitem[cur_it] ) {
                        if( getitem[cur_it].count == 0 ) {
                            wprintz( w_pickup, c_ltblue, " + " );
                        } else {
                            wprintz( w_pickup, c_ltblue, " # " );
                        }
                    } else {
                        wprintw( w_pickup, " - " );
                    }
                    std::string item_name = here[cur_it].display_name();
                    if( OPTIONS["ITEM_SYMBOLS"] ) {
                        item_name = string_format( "%s %s", here[cur_it].symbol().c_str(),
                                                   item_name.c_str() );
                    }
                    trim_and_print( w_pickup, 1 + ( cur_it % maxitems ), 6, pickupW - 4, icolor,
                                    "%s", item_name.c_str() );
                }
            }

            mvwprintw( w_pickup, maxitems + 1, 0, _( "[%s] Unmark" ),
                       ctxt.get_desc( "LEFT", 1 ).c_str() );

            center_print( w_pickup, maxitems + 1, c_ltgray, _( "[%s] Help" ),
                          ctxt.get_desc( "HELP_KEYBINDINGS", 1 ).c_str() );

            right_print( w_pickup, maxitems + 1, 0, c_ltgray, _( "[%s] Mark" ),
                         ctxt.get_desc( "RIGHT", 1 ).c_str() );

            mvwprintw( w_pickup, maxitems + 2, 0, _( "[%s] Prev" ),
                       ctxt.get_desc( "PREV_TAB", 1 ).c_str() );

            center_print( w_pickup, maxitems + 2, c_ltgray, _( "[%s] All" ),
                          ctxt.get_desc( "SELECT_ALL", 1 ).c_str() );

            right_print( w_pickup, maxitems + 2, 0, c_ltgray, _( "[%s] Next" ),
                         ctxt.get_desc( "NEXT_TAB", 1 ).c_str() );

            if( update ) { // Update weight & volume information
                update = false;
                for( int i = 9; i < pickupW; ++i ) {
                    mvwaddch( w_pickup, 0, i, ' ' );
                }
                mvwprintz( w_pickup, 0,  9,
                           ( pl_copy.weight_carried() > g->u.weight_capacity() ? c_red : c_white ),
                           _( "Wgt %.1f" ), convert_weight( pl_copy.weight_carried() ) + 0.05 ); // +0.05 to round up
                wprintz( w_pickup, c_white, "/%.1f", convert_weight( g->u.weight_capacity() ) );
                mvwprintz( w_pickup, 0, 24,
                           ( pl_copy.volume_carried() > g->u.volume_capacity() ? c_red : c_white ),
                           _( "Vol %d" ), pl_copy.volume_carried() );
                wprintz( w_pickup, c_white, "/%d", g->u.volume_capacity() );
            }
            wrefresh( w_pickup );

            action = ctxt.handle_input();
            raw_input_char = ctxt.get_raw_input().get_first_input();

        } while( action != "QUIT" && action != "CONFIRM" );

        bool item_selected = false;
        // Check if we have selected an item.
        for( auto selection : getitem ) {
            if( selection ) {
                item_selected = true;
            }
        }
        if( action != "CONFIRM" || !item_selected ) {
            w_pickupptr.reset();
            w_item_infoptr.reset();
            add_msg( _( "Never mind." ) );
            g->reenter_fullscreen();
            g->refresh_all();
            return;
        }
    }

    // At this point we've selected our items, register an activity to pick them up.
    g->u.assign_activity( ACT_PICKUP, 0 );
    g->u.activity.placement = pos - g->u.pos();
    g->u.activity.values.push_back( from_vehicle );
    if( min == -1 ) {
        // Auto pickup will need to auto resume since there can be several of them on the stack.
        g->u.activity.auto_resume = true;
    }
    std::reverse( getitem.begin(), getitem.end() );
    for( size_t i = 0; i < here.size(); i++ ) {
        if( getitem[i] ) {
            g->u.activity.values.push_back( i );
            g->u.activity.values.push_back( getitem[i].count );
        }
    }

    g->reenter_fullscreen();
}
Beispiel #3
0
// Pick up items at (pos).
void Pickup::pick_up( const tripoint &pos, int min )
{
    int cargo_part = -1;

    const optional_vpart_position vp = g->m.veh_at( pos );
    vehicle *const veh = veh_pointer_or_null( vp );
    bool from_vehicle = false;

    if( min != -1 ) {
        switch( interact_with_vehicle( veh, pos, vp ? vp->part_index() : -1 ) ) {
            case DONE:
                return;
            case ITEMS_FROM_CARGO: {
                const cata::optional<vpart_reference> carg = vp.part_with_feature( "CARGO", false );
                cargo_part = carg ? carg->part_index() : -1;
            }
            from_vehicle = cargo_part >= 0;
            break;
            case ITEMS_FROM_GROUND:
                // Nothing to change, default is to pick from ground anyway.
                if( g->m.has_flag( "SEALED", pos ) ) {
                    return;
                }

                break;
        }
    }

    if( !from_vehicle ) {
        bool isEmpty = ( g->m.i_at( pos ).empty() );

        // Hide the pickup window if this is a toilet and there's nothing here
        // but water.
        if( ( !isEmpty ) && g->m.furn( pos ) == f_toilet ) {
            isEmpty = true;
            for( auto maybe_water : g->m.i_at( pos ) ) {
                if( maybe_water.typeId() != "water" ) {
                    isEmpty = false;
                    break;
                }
            }
        }

        if( isEmpty && ( min != -1 || !get_option<bool>( "AUTO_PICKUP_ADJACENT" ) ) ) {
            return;
        }
    }

    // which items are we grabbing?
    std::vector<item> here;
    if( from_vehicle ) {
        auto vehitems = veh->get_items( cargo_part );
        here.resize( vehitems.size() );
        std::copy( vehitems.begin(), vehitems.end(), here.begin() );
    } else {
        auto mapitems = g->m.i_at( pos );
        here.resize( mapitems.size() );
        std::copy( mapitems.begin(), mapitems.end(), here.begin() );
    }

    if( min == -1 ) {
        // Recursively pick up adjacent items if that option is on.
        if( get_option<bool>( "AUTO_PICKUP_ADJACENT" ) && g->u.pos() == pos ) {
            //Autopickup adjacent
            direction adjacentDir[8] = {NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST};
            for( auto &elem : adjacentDir ) {

                tripoint apos = tripoint( direction_XY( elem ), 0 );
                apos += pos;

                pick_up( apos, min );
            }
        }

        // Bail out if this square cannot be auto-picked-up
        if( g->check_zone( zone_type_id( "NO_AUTO_PICKUP" ), pos ) ) {
            return;
        } else if( g->m.has_flag( "SEALED", pos ) ) {
            return;
        }
    }

    // Not many items, just grab them
    if( ( int )here.size() <= min && min != -1 ) {
        g->u.assign_activity( activity_id( "ACT_PICKUP" ) );
        g->u.activity.placement = pos - g->u.pos();
        g->u.activity.values.push_back( from_vehicle );
        // Only one item means index is 0.
        g->u.activity.values.push_back( 0 );
        // auto-pickup means pick up all.
        g->u.activity.values.push_back( 0 );
        return;
    }

    std::vector<std::list<item_idx>> stacked_here;
    for( size_t i = 0; i < here.size(); i++ ) {
        item &it = here[i];
        bool found_stack = false;
        for( auto &stack : stacked_here ) {
            if( stack.begin()->_item.stacks_with( it ) ) {
                item_idx el = { it, i };
                stack.push_back( el );
                found_stack = true;
                break;
            }
        }
        if( !found_stack ) {
            std::list<item_idx> newstack;
            newstack.push_back( { it, i } );
            stacked_here.push_back( newstack );
        }
    }
    std::reverse( stacked_here.begin(), stacked_here.end() );

    if( min != -1 ) { // don't bother if we're just autopickuping
        g->temp_exit_fullscreen();
    }
    bool sideStyle = use_narrow_sidebar();

    // Otherwise, we have Autopickup, 2 or more items and should list them, etc.
    int maxmaxitems = sideStyle ? TERMY : getmaxy( g->w_messages ) - 3;

    int itemsH = std::min( 25, TERMY / 2 );
    int pickupBorderRows = 3;

    // The pickup list may consume the entire terminal, minus space needed for its
    // header/footer and the item info window.
    int minleftover = itemsH + pickupBorderRows;
    if( maxmaxitems > TERMY - minleftover ) {
        maxmaxitems = TERMY - minleftover;
    }

    const int minmaxitems = sideStyle ? 6 : 9;

    std::vector<pickup_count> getitem( stacked_here.size() );

    int maxitems = stacked_here.size();
    maxitems = ( maxitems < minmaxitems ? minmaxitems : ( maxitems > maxmaxitems ? maxmaxitems :
                 maxitems ) );

    int itemcount = 0;

    if( min == -1 ) { //Auto Pickup, select matching items
        if( !select_autopickup_items( stacked_here, getitem ) ) {
            // If we didn't find anything, bail out now.
            return;
        }
    } else {
        int pickupH = maxitems + pickupBorderRows;
        int pickupW = getmaxx( g->w_messages );
        int pickupY = VIEW_OFFSET_Y;
        int pickupX = getbegx( g->w_messages );

        int itemsW = pickupW;
        int itemsY = sideStyle ? pickupY + pickupH : TERMY - itemsH;
        int itemsX = pickupX;

        catacurses::window w_pickup = catacurses::newwin( pickupH, pickupW, pickupY, pickupX );
        catacurses::window w_item_info = catacurses::newwin( itemsH,  itemsW,  itemsY,  itemsX );

        std::string action;
        long raw_input_char = ' ';
        input_context ctxt( "PICKUP" );
        ctxt.register_action( "UP" );
        ctxt.register_action( "DOWN" );
        ctxt.register_action( "RIGHT" );
        ctxt.register_action( "LEFT" );
        ctxt.register_action( "NEXT_TAB", _( "Next page" ) );
        ctxt.register_action( "PREV_TAB", _( "Previous page" ) );
        ctxt.register_action( "SCROLL_UP" );
        ctxt.register_action( "SCROLL_DOWN" );
        ctxt.register_action( "CONFIRM" );
        ctxt.register_action( "SELECT_ALL" );
        ctxt.register_action( "QUIT", _( "Cancel" ) );
        ctxt.register_action( "ANY_INPUT" );
        ctxt.register_action( "HELP_KEYBINDINGS" );
        ctxt.register_action( "FILTER" );

        int start = 0;
        int cur_it = 0;
        bool update = true;
        mvwprintw( w_pickup, 0, 0, _( "PICK UP" ) );
        int selected = 0;
        int iScrollPos = 0;

        std::string filter;
        std::string new_filter;
        std::vector<int> matches;//Indexes of items that match the filter
        bool filter_changed = true;
        if( g->was_fullscreen ) {
            g->draw_ter();
        }
        // Now print the two lists; those on the ground and about to be added to inv
        // Continue until we hit return or space
        do {
            const std::string pickup_chars =
                ctxt.get_available_single_char_hotkeys( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:;" );
            int idx = -1;
            for( int i = 1; i < pickupH; i++ ) {
                mvwprintw( w_pickup, i, 0,
                           "                                                " );
            }
            if( action == "ANY_INPUT" &&
                raw_input_char >= '0' && raw_input_char <= '9' ) {
                int raw_input_char_value = ( char )raw_input_char - '0';
                itemcount *= 10;
                itemcount += raw_input_char_value;
                if( itemcount < 0 ) {
                    itemcount = 0;
                }
            } else if( action == "SCROLL_UP" ) {
                iScrollPos--;
            } else if( action == "SCROLL_DOWN" ) {
                iScrollPos++;
            } else if( action == "PREV_TAB" ) {
                if( start > 0 ) {
                    start -= maxitems;
                } else {
                    start = ( int )( ( matches.size() - 1 ) / maxitems ) * maxitems;
                }
                selected = start;
                mvwprintw( w_pickup, maxitems + 2, 0, "         " );
            } else if( action == "NEXT_TAB" ) {
                if( start + maxitems < ( int )matches.size() ) {
                    start += maxitems;
                } else {
                    start = 0;
                }
                iScrollPos = 0;
                selected = start;
                mvwprintw( w_pickup, maxitems + 2, pickupH, "            " );
            } else if( action == "UP" ) {
                selected--;
                iScrollPos = 0;
                if( selected < 0 ) {
                    selected = matches.size() - 1;
                    start = ( int )( matches.size() / maxitems ) * maxitems;
                    if( start >= ( int )matches.size() ) {
                        start -= maxitems;
                    }
                } else if( selected < start ) {
                    start -= maxitems;
                }
            } else if( action == "DOWN" ) {
                selected++;
                iScrollPos = 0;
                if( selected >= ( int )matches.size() ) {
                    selected = 0;
                    start = 0;
                } else if( selected >= start + maxitems ) {
                    start += maxitems;
                }
            } else if( selected >= 0 && selected < int( matches.size() ) &&
                       ( ( action == "RIGHT" && !getitem[matches[selected]].pick ) ||
                         ( action == "LEFT" && getitem[matches[selected]].pick ) ) ) {
                idx = selected;
            } else if( action == "FILTER" ) {
                new_filter = filter;
                string_input_popup popup;
                popup
                .title( _( "Set filter" ) )
                .width( 30 )
                .edit( new_filter );
                if( !popup.canceled() ) {
                    filter_changed = true;
                } else {
                    wrefresh( g->w_terrain );
                }
            } else if( action == "ANY_INPUT" && raw_input_char == '`' ) {
                std::string ext = string_input_popup()
                                  .title( _( "Enter 2 letters (case sensitive):" ) )
                                  .width( 3 )
                                  .max_length( 2 )
                                  .query_string();
                if( ext.size() == 2 ) {
                    int p1 = pickup_chars.find( ext.at( 0 ) );
                    int p2 = pickup_chars.find( ext.at( 1 ) );
                    if( p1 != -1 && p2 != -1 ) {
                        idx = pickup_chars.size() + ( p1 * pickup_chars.size() ) + p2;
                    }
                }
            } else if( action == "ANY_INPUT" ) {
                idx = ( raw_input_char <= 127 ) ? pickup_chars.find( raw_input_char ) : -1;
                iScrollPos = 0;
            }

            if( idx >= 0 && idx < ( int )matches.size() ) {
                size_t true_idx = matches[idx];
                if( itemcount != 0 || getitem[true_idx].count == 0 ) {
                    item &temp = stacked_here[true_idx].begin()->_item;
                    int amount_available = temp.count_by_charges() ? temp.charges : stacked_here[true_idx].size();
                    if( itemcount >= amount_available ) {
                        itemcount = 0;
                    }
                    getitem[true_idx].count = itemcount;
                    itemcount = 0;
                }

                // Note: this might not change the value of getitem[idx] at all!
                getitem[true_idx].pick = ( action == "RIGHT" ? true :
                                           ( action == "LEFT" ? false :
                                             !getitem[true_idx].pick ) );
                if( action != "RIGHT" && action != "LEFT" ) {
                    selected = idx;
                    start = ( int )( idx / maxitems ) * maxitems;
                }

                if( !getitem[true_idx].pick ) {
                    getitem[true_idx].count = 0;
                }
                update = true;
            }
            if( filter_changed ) {
                matches.clear();
                while( matches.empty() ) {
                    auto filter_func = item_filter_from_string( new_filter );
                    for( size_t index = 0; index < stacked_here.size(); index++ ) {
                        if( filter_func( stacked_here[index].begin()->_item ) ) {
                            matches.push_back( index );
                        }
                    }
                    if( matches.empty() ) {
                        popup( _( "Your filter returned no results" ) );
                        wrefresh( g->w_terrain );
                        // The filter must have results, or simply be emptied or canceled,
                        // as this screen can't be reached without there being
                        // items available
                        string_input_popup popup;
                        popup
                        .title( _( "Set filter" ) )
                        .width( 30 )
                        .edit( new_filter );
                        if( popup.canceled() ) {
                            new_filter = filter;
                            filter_changed = false;
                        }
                    }
                }
                if( filter_changed ) {
                    filter = new_filter;
                    filter_changed = false;
                    selected = 0;
                    start = 0;
                    iScrollPos = 0;
                }
                wrefresh( g->w_terrain );
            }
            item &selected_item = stacked_here[matches[selected]].begin()->_item;

            werase( w_item_info );
            if( selected >= 0 && selected <= ( int )stacked_here.size() - 1 ) {
                std::vector<iteminfo> vThisItem;
                std::vector<iteminfo> vDummy;
                selected_item.info( true, vThisItem );

                draw_item_info( w_item_info, "", "", vThisItem, vDummy, iScrollPos, true, true );
            }
            draw_custom_border( w_item_info, false );
            mvwprintw( w_item_info, 0, 2, "< " );
            trim_and_print( w_item_info, 0, 4, itemsW - 8, c_white, "%s >",
                            selected_item.display_name().c_str() );
            wrefresh( w_item_info );

            if( action == "SELECT_ALL" ) {
                int count = 0;
                for( auto i : matches ) {
                    if( getitem[i].pick ) {
                        count++;
                    }
                    getitem[i].pick = true;
                }
                if( count == ( int )stacked_here.size() ) {
                    for( size_t i = 0; i < stacked_here.size(); i++ ) {
                        getitem[i].pick = false;
                    }
                }
                update = true;
            }
            for( cur_it = start; cur_it < start + maxitems; cur_it++ ) {
                mvwprintw( w_pickup, 1 + ( cur_it % maxitems ), 0,
                           "                                        " );
                if( cur_it < ( int )matches.size() ) {
                    int true_it = matches[cur_it];
                    item &this_item = stacked_here[ true_it ].begin()->_item;
                    nc_color icolor = this_item.color_in_inventory();
                    if( cur_it == selected ) {
                        icolor = hilite( icolor );
                    }

                    if( cur_it < ( int )pickup_chars.size() ) {
                        mvwputch( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor,
                                  char( pickup_chars[cur_it] ) );
                    } else if( cur_it < ( int )pickup_chars.size() + ( int )pickup_chars.size() *
                               ( int )pickup_chars.size() ) {
                        int p = cur_it - pickup_chars.size();
                        int p1 = p / pickup_chars.size();
                        int p2 = p % pickup_chars.size();
                        mvwprintz( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor, "`%c%c",
                                   char( pickup_chars[p1] ), char( pickup_chars[p2] ) );
                    } else {
                        mvwputch( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor, ' ' );
                    }
                    if( getitem[true_it].pick ) {
                        if( getitem[true_it].count == 0 ) {
                            wprintz( w_pickup, c_light_blue, " + " );
                        } else {
                            wprintz( w_pickup, c_light_blue, " # " );
                        }
                    } else {
                        wprintw( w_pickup, " - " );
                    }
                    std::string item_name;
                    if( stacked_here[true_it].begin()->_item.ammo_type() == "money" ) {
                        //Count charges
                        //TODO: transition to the item_location system used for the inventory
                        unsigned long charges_total = 0;
                        for( const auto item : stacked_here[true_it] ) {
                            charges_total += item._item.charges;
                        }
                        //Picking up none or all the cards in a stack
                        if( !getitem[true_it].pick || getitem[true_it].count == 0 ) {
                            item_name = stacked_here[true_it].begin()->_item.display_money( stacked_here[true_it].size(),
                                        charges_total );
                        } else {
                            unsigned long charges = 0;
                            int c = getitem[true_it].count;
                            for( auto it = stacked_here[true_it].begin(); it != stacked_here[true_it].end() &&
                                 c > 0; ++it, --c ) {
                                charges += it->_item.charges;
                            }
                            item_name = string_format( _( "%s of %s" ),
                                                       stacked_here[true_it].begin()->_item.display_money( getitem[true_it].count, charges ),
                                                       format_money( charges_total ) );
                        }
                    } else {
                        item_name = this_item.display_name( stacked_here[true_it].size() );
                    }
                    if( stacked_here[true_it].size() > 1 ) {
                        item_name = string_format( "%d %s", stacked_here[true_it].size(), item_name.c_str() );
                    }
                    if( get_option<bool>( "ITEM_SYMBOLS" ) ) {
                        item_name = string_format( "%s %s", this_item.symbol().c_str(),
                                                   item_name.c_str() );
                    }
                    trim_and_print( w_pickup, 1 + ( cur_it % maxitems ), 6, pickupW - 4, icolor,
                                    item_name );
                }
            }

            mvwprintw( w_pickup, maxitems + 1, 0, _( "[%s] Unmark" ),
                       ctxt.get_desc( "LEFT", 1 ).c_str() );

            center_print( w_pickup, maxitems + 1, c_light_gray, string_format( _( "[%s] Help" ),
                          ctxt.get_desc( "HELP_KEYBINDINGS", 1 ).c_str() ) );

            right_print( w_pickup, maxitems + 1, 0, c_light_gray, string_format( _( "[%s] Mark" ),
                         ctxt.get_desc( "RIGHT", 1 ).c_str() ) );

            mvwprintw( w_pickup, maxitems + 2, 0, _( "[%s] Prev" ),
                       ctxt.get_desc( "PREV_TAB", 1 ).c_str() );

            center_print( w_pickup, maxitems + 2, c_light_gray, string_format( _( "[%s] All" ),
                          ctxt.get_desc( "SELECT_ALL", 1 ).c_str() ) );

            right_print( w_pickup, maxitems + 2, 0, c_light_gray, string_format( _( "[%s] Next" ),
                         ctxt.get_desc( "NEXT_TAB", 1 ).c_str() ) );

            if( update ) { // Update weight & volume information
                update = false;
                for( int i = 9; i < pickupW; ++i ) {
                    mvwaddch( w_pickup, 0, i, ' ' );
                }
                units::mass weight_picked_up = 0;
                units::volume volume_picked_up = 0;
                for( size_t i = 0; i < getitem.size(); i++ ) {
                    if( getitem[i].pick ) {
                        item temp = stacked_here[i].begin()->_item;
                        if( temp.count_by_charges() && getitem[i].count < temp.charges && getitem[i].count != 0 ) {
                            temp.charges = getitem[i].count;
                        }
                        int num_picked = std::min( stacked_here[i].size(),
                                                   getitem[i].count == 0 ? stacked_here[i].size() : getitem[i].count );
                        weight_picked_up += temp.weight() * num_picked;
                        volume_picked_up += temp.volume() * num_picked;
                    }
                }

                auto weight_predict = g->u.weight_carried() + weight_picked_up;
                auto volume_predict = g->u.volume_carried() + volume_picked_up;

                mvwprintz( w_pickup, 0, 9, weight_predict > g->u.weight_capacity() ? c_red : c_white,
                           _( "Wgt %.1f" ), round_up( convert_weight( weight_predict ), 1 ) );

                wprintz( w_pickup, c_white, "/%.1f", round_up( convert_weight( g->u.weight_capacity() ), 1 ) );

                std::string fmted_volume_predict = format_volume( volume_predict );
                mvwprintz( w_pickup, 0, 24, volume_predict > g->u.volume_capacity() ? c_red : c_white,
                           _( "Vol %s" ), fmted_volume_predict.c_str() );

                std::string fmted_volume_capacity = format_volume( g->u.volume_capacity() );
                wprintz( w_pickup, c_white, "/%s", fmted_volume_capacity.c_str() );
            };

            wrefresh( w_pickup );

            action = ctxt.handle_input();
            raw_input_char = ctxt.get_raw_input().get_first_input();

        } while( action != "QUIT" && action != "CONFIRM" );

        bool item_selected = false;
        // Check if we have selected an item.
        for( auto selection : getitem ) {
            if( selection.pick ) {
                item_selected = true;
            }
        }
        if( action != "CONFIRM" || !item_selected ) {
            w_pickup = catacurses::window();
            w_item_info = catacurses::window();
            add_msg( _( "Never mind." ) );
            g->reenter_fullscreen();
            g->refresh_all();
            return;
        }
    }

    // At this point we've selected our items, register an activity to pick them up.
    g->u.assign_activity( activity_id( "ACT_PICKUP" ) );
    g->u.activity.placement = pos - g->u.pos();
    g->u.activity.values.push_back( from_vehicle );
    if( min == -1 ) {
        // Auto pickup will need to auto resume since there can be several of them on the stack.
        g->u.activity.auto_resume = true;
    }
    std::vector<std::pair<int, int>> pick_values;
    for( size_t i = 0; i < stacked_here.size(); i++ ) {
        const auto &selection = getitem[i];
        if( !selection.pick ) {
            continue;
        }

        const auto &stack = stacked_here[i];
        // Note: items can be both charged and stacked
        // For robustness, let's assume they can be both in the same stack
        bool pick_all = selection.count == 0;
        size_t count = selection.count;
        for( const item_idx &it : stack ) {
            if( !pick_all && count == 0 ) {
                break;
            }

            if( it._item.count_by_charges() ) {
                size_t num_picked = std::min( ( size_t )it._item.charges, count );
                pick_values.push_back( { static_cast<int>( it.idx ), static_cast<int>( num_picked ) } );
                count -= num_picked;
            } else {
                size_t num_picked = 1;
                pick_values.push_back( { static_cast<int>( it.idx ), 0 } );
                count -= num_picked;
            }
        }
    }
    // The pickup activity picks up items last-to-first from its values list, so make sure the
    // higher indices are at the end.
    std::sort( pick_values.begin(), pick_values.end() );
    for( auto &it : pick_values ) {
        g->u.activity.values.push_back( it.first );
        g->u.activity.values.push_back( it.second );
    }

    g->reenter_fullscreen();
}
Beispiel #4
0
// Pick up items at (pos).
void Pickup::pick_up( const tripoint &pos, int min )
{
    int veh_root_part = 0;
    int cargo_part = -1;

    vehicle *veh = g->m.veh_at (pos, veh_root_part);
    bool from_vehicle = false;

    if( min != -1 ) {
        switch( interact_with_vehicle( veh, pos, veh_root_part ) ) {
        case DONE:
            return;
        case ITEMS_FROM_CARGO:
            cargo_part = veh->part_with_feature( veh_root_part, "CARGO", false );
            from_vehicle = cargo_part >= 0;
            break;
        case ITEMS_FROM_GROUND:
            // Nothing to change, default is to pick from ground anyway.
            break;
        }
    }

    if (g->m.has_flag("SEALED", pos)) {
        return;
    }

    //min == -1 is Autopickup
    if (!g->u.can_pickup(min != -1)) { // no message on autopickup (-1)
        return;
    }

    if( !from_vehicle ) {
        bool isEmpty = (g->m.i_at(pos).empty());

        // Hide the pickup window if this is a toilet and there's nothing here
        // but water.
        if ((!isEmpty) && g->m.furn(pos) == f_toilet) {
            isEmpty = true;
            for( auto maybe_water : g->m.i_at(pos) ) {
                if( maybe_water.typeId() != "water") {
                    isEmpty = false;
                    break;
                }
            }
        }

        if (isEmpty && (min != -1 || !OPTIONS["AUTO_PICKUP_ADJACENT"] )) {
            return;
        }
    }

    // which items are we grabbing?
    std::vector<item> here;
    if( from_vehicle ) {
        auto vehitems = veh->get_items(cargo_part);
        here.resize( vehitems.size() );
        std::copy( vehitems.begin(), vehitems.end(), here.begin() );
    } else {
        auto mapitems = g->m.i_at(pos);
        here.resize( mapitems.size() );
        std::copy( mapitems.begin(), mapitems.end(), here.begin() );
    }

    if (min == -1) {
        if( g->check_zone( "NO_AUTO_PICKUP", pos ) ) {
            here.clear();
        }

        // Recursively pick up adjacent items if that option is on.
        if( OPTIONS["AUTO_PICKUP_ADJACENT"] && g->u.pos() == pos ) {
            //Autopickup adjacent
            direction adjacentDir[8] = {NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST};
            for( auto &elem : adjacentDir ) {

                tripoint apos = tripoint( direction_XY( elem ), 0 );
                apos += pos;

                if( g->m.has_flag( "SEALED", apos ) ) {
                    continue;
                }
                if( g->check_zone( "NO_AUTO_PICKUP", apos ) ) {
                    continue;
                }
                pick_up( apos, min );
            }
        }
    }

    // Not many items, just grab them
    if ((int)here.size() <= min && min != -1) {
        g->u.assign_activity( ACT_PICKUP, 0 );
        g->u.activity.placement = pos - g->u.pos();
        g->u.activity.values.push_back( from_vehicle );
        // Only one item means index is 0.
        g->u.activity.values.push_back( 0 );
        // auto-pickup means pick up all.
        g->u.activity.values.push_back( 0 );
        return;
    }

    if(min != -1) { // don't bother if we're just autopickup-ing
        g->temp_exit_fullscreen();
    }
    bool sideStyle = use_narrow_sidebar();

    // Otherwise, we have Autopickup, 2 or more items and should list them, etc.
    int maxmaxitems = sideStyle ? TERMY : getmaxy(g->w_messages) - 3;

    int itemsH = std::min(25, TERMY / 2);
    int pickupBorderRows = 3;

    // The pickup list may consume the entire terminal, minus space needed for its
    // header/footer and the item info window.
    int minleftover = itemsH + pickupBorderRows;
    if(maxmaxitems > TERMY - minleftover) {
        maxmaxitems = TERMY - minleftover;
    }

    const int minmaxitems = sideStyle ? 6 : 9;

    std::vector<bool> getitem;
    getitem.resize(here.size(), false);

    int maxitems = here.size();
    maxitems = (maxitems < minmaxitems ? minmaxitems : (maxitems > maxmaxitems ? maxmaxitems :
                maxitems ));

    int itemcount = 0;
    std::map<int, unsigned int> pickup_count; // Count of how many we'll pick up from each stack

    if (min == -1) { //Auto Pickup, select matching items
        if( !select_autopickup_items( here, getitem) ) {
            // If we didn't find anything, bail out now.
            return;
        }
    } else {
        int pickupH = maxitems + pickupBorderRows;
        int pickupW = getmaxx(g->w_messages);
        int pickupY = VIEW_OFFSET_Y;
        int pickupX = getbegx(g->w_messages);

        int itemsW = pickupW;
        int itemsY = sideStyle ? pickupY + pickupH : TERMY - itemsH;
        int itemsX = pickupX;

        WINDOW *w_pickup    = newwin(pickupH, pickupW, pickupY, pickupX);
        WINDOW *w_item_info = newwin(itemsH,  itemsW,  itemsY,  itemsX);
        WINDOW_PTR w_pickupptr( w_pickup );
        WINDOW_PTR w_item_infoptr( w_item_info );

        int ch = ' ';
        int start = 0, cur_it;
        int new_weight = g->u.weight_carried(), new_volume = g->u.volume_carried();
        bool update = true;
        mvwprintw(w_pickup, 0, 0, _("PICK UP"));
        int selected = 0;
        int iScrollPos = 0;

        if(g->was_fullscreen) {
            g->draw_ter();
        }
        // Now print the two lists; those on the ground and about to be added to inv
        // Continue until we hit return or space
        do {
            static const std::string pickup_chars =
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:;";
            int idx = -1;
            for (int i = 1; i < pickupH; i++) {
                mvwprintw(w_pickup, i, 0,
                          "                                                ");
            }
            if (ch >= '0' && ch <= '9') {
                ch = (char)ch - '0';
                itemcount *= 10;
                itemcount += ch;
                if( itemcount < 0 ) {
                    itemcount = 0;
                }
            } else if ( ch == KEY_PPAGE) {
                iScrollPos--;
            } else if ( ch == KEY_NPAGE) {
                iScrollPos++;
            } else if ( ch == '<' ) {
                if ( start > 0 ) {
                    start -= maxitems;
                } else {
                    start = (int)( (here.size()-1) / maxitems ) * maxitems;
                }
                selected = start;
                mvwprintw(w_pickup, maxitems + 2, 0, "         ");
            } else if ( ch == '>' ) {
                if ( start + maxitems < (int)here.size() ) {
                    start += maxitems;
                } else {
                    start = 0;
                }
                iScrollPos = 0;
                selected = start;
                mvwprintw(w_pickup, maxitems + 2, pickupH, "            ");
            } else if ( ch == KEY_UP ) {
                selected--;
                iScrollPos = 0;
                if ( selected < 0 ) {
                    selected = here.size() - 1;
                    start = (int)( here.size() / maxitems ) * maxitems;
                    if (start >= (int)here.size()) {
                        start -= maxitems;
                    }
                } else if ( selected < start ) {
                    start -= maxitems;
                }
            } else if ( ch == KEY_DOWN ) {
                selected++;
                iScrollPos = 0;
                if ( selected >= (int)here.size() ) {
                    selected = 0;
                    start = 0;
                } else if ( selected >= start + maxitems ) {
                    start += maxitems;
                }
            } else if ( selected >= 0 && (
                            ( ch == KEY_RIGHT && !getitem[selected]) ||
                            ( ch == KEY_LEFT && getitem[selected] )
                        ) ) {
                idx = selected;
            } else if ( ch == '`' ) {
                std::string ext = string_input_popup(
                                      _("Enter 2 letters (case sensitive):"), 3, "", "", "", 2);
                if(ext.size() == 2) {
                    int p1 = pickup_chars.find(ext.at(0));
                    int p2 = pickup_chars.find(ext.at(1));
                    if ( p1 != -1 && p2 != -1 ) {
                        idx = pickup_chars.size() + ( p1 * pickup_chars.size() ) + p2;
                    }
                }
            } else {
                idx = ( ch <= 127 ) ? pickup_chars.find(ch) : -1;
                iScrollPos = 0;
            }

            if( idx >= 0 && idx < (int)here.size()) {
                if( getitem[idx] ) {
                    if( pickup_count[idx] != 0 && (int)pickup_count[idx] < here[idx].charges ) {
                        item temp = here[idx];
                        temp.charges = pickup_count[idx];
                        new_weight -= temp.weight();
                        new_volume -= temp.volume();
                    } else {
                        new_weight -= here[idx].weight();
                        new_volume -= here[idx].volume();
                    }
                }
                if (itemcount != 0 || pickup_count[idx] == 0) {
                    if (itemcount >= here[idx].charges || !here[idx].count_by_charges()) {
                        // Ignore the count if we pickup the whole stack anyway
                        // or something that is not counted by charges (tools)
                        itemcount = 0;
                    }
                    pickup_count[idx] = itemcount;
                    itemcount = 0;
                }

                // Note: this might not change the value of getitem[idx] at all!
                getitem[idx] = ( ch == KEY_RIGHT ? true : ( ch == KEY_LEFT ? false : !getitem[idx] ) );
                if ( ch != KEY_RIGHT && ch != KEY_LEFT) {
                    selected = idx;
                    start = (int)( idx / maxitems ) * maxitems;
                }

                if (getitem[idx]) {
                    if (pickup_count[idx] != 0 &&
                        (int)pickup_count[idx] < here[idx].charges) {
                        item temp = here[idx];
                        temp.charges = pickup_count[idx];
                        new_weight += temp.weight();
                        new_volume += temp.volume();
                    } else {
                        new_weight += here[idx].weight();
                        new_volume += here[idx].volume();
                    }
                } else {
                    pickup_count[idx] = 0;
                }
                update = true;
            }

            werase(w_item_info);
            if ( selected >= 0 && selected <= (int)here.size() - 1 ) {
                std::vector<iteminfo> vThisItem, vDummy;
                here[selected].info(true, vThisItem);

                draw_item_info(w_item_info, "", "", vThisItem, vDummy, iScrollPos, true, true);
            }
            draw_custom_border(w_item_info, false);
            mvwprintw(w_item_info, 0, 2, "< ");
            trim_and_print(w_item_info, 0, 4, itemsW - 8, c_white, "%s >", here[selected].display_name().c_str());
            wrefresh(w_item_info);

            if (ch == ',') {
                int count = 0;
                for (size_t i = 0; i < here.size(); i++) {
                    if (getitem[i]) {
                        count++;
                    } else {
                        new_weight += here[i].weight();
                        new_volume += here[i].volume();
                    }
                    getitem[i] = true;
                }
                if (count == (int)here.size()) {
                    for (size_t i = 0; i < here.size(); i++) {
                        getitem[i] = false;
                    }
                    new_weight = g->u.weight_carried();
                    new_volume = g->u.volume_carried();
                }
                update = true;
            }

            for (cur_it = start; cur_it < start + maxitems; cur_it++) {
                mvwprintw(w_pickup, 1 + (cur_it % maxitems), 0,
                          "                                        ");
                if (cur_it < (int)here.size()) {
                    nc_color icolor = here[cur_it].color_in_inventory();
                    if (cur_it == selected) {
                        icolor = hilite(icolor);
                    }

                    if (cur_it < (int)pickup_chars.size() ) {
                        mvwputch(w_pickup, 1 + (cur_it % maxitems), 0, icolor,
                                 char(pickup_chars[cur_it]));
                    } else {
                        int p = cur_it - pickup_chars.size();
                        int p1 = p / pickup_chars.size();
                        int p2 = p % pickup_chars.size();
                        mvwprintz(w_pickup, 1 + (cur_it % maxitems), 0, icolor, "`%c%c",
                                  char(pickup_chars[p1]), char(pickup_chars[p2]));
                    }
                    if (getitem[cur_it]) {
                        if (pickup_count[cur_it] == 0) {
                            wprintz(w_pickup, c_ltblue, " + ");
                        } else {
                            wprintz(w_pickup, c_ltblue, " # ");
                        }
                    } else {
                        wprintw(w_pickup, " - ");
                    }
                    std::string item_name = here[cur_it].display_name();
                    if (OPTIONS["ITEM_SYMBOLS"]) {
                        item_name = string_format("%c %s", here[cur_it].symbol(), item_name.c_str());
                    }
                    trim_and_print(w_pickup, 1 + (cur_it % maxitems), 6, pickupW - 4, icolor,
                                   "%s", item_name.c_str());
                }
            }

            int pw = pickupW;
            const char *unmark = _("[left] Unmark");
            const char *scroll = _("[up/dn] Scroll");
            const char *mark   = _("[right] Mark");
            mvwprintw(w_pickup, maxitems + 1, 0,                         unmark);
            mvwprintw(w_pickup, maxitems + 1, (pw - std::strlen(scroll)) / 2, scroll);
            mvwprintw(w_pickup, maxitems + 1,  pw - std::strlen(mark),        mark);
            const char *prev = _("[<] Prev");
            const char *all = _("[,] All");
            const char *next   = _("[>] Next");
            mvwprintw(w_pickup, maxitems + 2, 0, prev);
            mvwprintw(w_pickup, maxitems + 2, (pw - std::strlen(all)) / 2, all);
            mvwprintw(w_pickup, maxitems + 2, pw - std::strlen(next), next);

            if (update) { // Update weight & volume information
                update = false;
                for (int i = 9; i < pickupW; ++i) {
                    mvwaddch(w_pickup, 0, i, ' ');
                }
                mvwprintz(w_pickup, 0,  9,
                          (new_weight > g->u.weight_capacity() ? c_red : c_white),
                          _("Wgt %.1f"), g->u.convert_weight(new_weight) + 0.05); // +0.05 to round up
                wprintz(w_pickup, c_white, "/%.1f", g->u.convert_weight(g->u.weight_capacity()));
                mvwprintz(w_pickup, 0, 24,
                          (new_volume > g->u.volume_capacity() ? c_red : c_white),
                          _("Vol %d"), new_volume);
                wprintz(w_pickup, c_white, "/%d", g->u.volume_capacity());
            }
            wrefresh(w_pickup);

            ch = (int)getch();

        } while (ch != ' ' && ch != '\n' && ch != KEY_ENTER && ch != KEY_ESCAPE);

        bool item_selected = false;
        // Check if we have selected an item.
        for( auto selection : getitem ) {
            if( selection ) {
                item_selected = true;
            }
        }
        if( (ch != '\n' && ch != KEY_ENTER) || !item_selected ) {
            w_pickupptr.reset();
            w_item_infoptr.reset();
            add_msg(_("Never mind."));
            g->reenter_fullscreen();
            g->refresh_all();
            return;
        }
    }

    // At this point we've selected our items, register an activity to pick them up.
    g->u.assign_activity( ACT_PICKUP, 0 );
    g->u.activity.placement = pos - g->u.pos();
    g->u.activity.values.push_back( from_vehicle );
    if( min == -1 ) {
        // Auto pickup will need to auto resume since there can be several of them on the stack.
        g->u.activity.auto_resume = true;
    }
    for (size_t i = 0; i < here.size(); i++) {
        if( getitem[i] ) {
            g->u.activity.values.push_back( i );
            g->u.activity.values.push_back( pickup_count[i] );
        }
    }

    g->reenter_fullscreen();
}
Beispiel #5
0
std::vector<item> game::multidrop()
{
    WINDOW* w_inv = newwin(TERRAIN_WINDOW_HEIGHT, TERRAIN_WINDOW_WIDTH + (use_narrow_sidebar() ? 45 : 55), VIEW_OFFSET_Y, VIEW_OFFSET_X);
    const int maxitems = TERRAIN_WINDOW_HEIGHT - 5;

    u.inv.restack(&u);
    u.inv.sort();
    int drp_line_width=getmaxx(w_inv)-90;
    const std::string drp_line_padding = ( drp_line_width > 1 ? std::string(drp_line_width, ' ') : " ");
    std::map<int, int> dropping; // Count of how many we'll drop from each position
    int count = 0; // The current count
    std::vector<char> weapon_and_armor; // Always single, not counted
    bool warned_about_bionic = false; // Printed add_msg re: dropping bionics
    print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor);
    int base_weight = u.weight_carried();
    int base_volume = u.volume_carried();

    int ch = (int)'.';
    int start = 0, cur_it = 0, max_it;
    indexed_invslice stacks = u.inv.slice_filter();
    CategoriesVector CATEGORIES;
    std::vector<int> firsts = find_firsts(stacks, CATEGORIES);
    int selected = -1;
    int selected_pos = INT_MIN;

    int next_category_at = 0;
    int prev_category_at = 0;
    bool inCategoryMode = false;

    std::vector<int> category_order;
    category_order.reserve(firsts.size());

    // Items are not guaranteed to be in the same order as their categories, in fact they almost never are.
    // So we sort the categories by which items actually show up first in the inventory.
    for (int current_item = 0; current_item < u.inv.size(); ++current_item) {
        for (int i = 1; i < CATEGORIES.size(); ++i) {
            if (current_item == firsts[i - 1]) {
                category_order.push_back(i - 1);
            }
        }
    }

    do {
        // Find the inventory position of the first item in the previous and next category (in relation
        // to the currently selected category).
        for (int i = 0; i < category_order.size(); ++i) {
            if (selected > firsts[category_order[i]] && prev_category_at <= firsts[category_order[i]]) {
                prev_category_at = firsts[category_order[i]];
            }

            if (selected < firsts[category_order[i]] && next_category_at <= selected) {
                next_category_at = firsts[category_order[i]];
            }
        }

        inventory drop_subset = u.inv.subset(dropping);
        int new_weight = base_weight - drop_subset.weight();
        int new_volume = base_volume - drop_subset.volume();
        for (int i = 0; i < weapon_and_armor.size(); ++i) {
            new_weight -= u.i_at(weapon_and_armor[i]).weight();
        }
        print_inv_weight_vol(this, w_inv, new_weight, new_volume);
        int cur_line = 2;
        max_it = 0;
        int drp_line = 1;
        // Print weapon to be dropped, the first position is reserved for high visibility
        mvwprintw(w_inv, 0, 90, "%s", drp_line_padding.c_str());
        bool dropping_w = false;
        for (int k = 0; k < weapon_and_armor.size() && !dropping_w; k++) {
            if (weapon_and_armor[k] == u.weapon.invlet) {
                dropping_w = true;
            }
            if (dropping_w && u.is_armed()) {
                mvwprintz(w_inv, 0, 90, c_ltblue, "%c + %s", u.weapon.invlet, u.weapname().c_str());
            }
        }
        // Print worn items to be dropped
        if(dropping_w) {
            mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
            drp_line++;
        }
        bool dropping_a = false;
        if (u.worn.size() > 0){
            for (int k = 0; k < u.worn.size(); k++) {
                bool dropping_w = false;
                for (int j = 0; j < weapon_and_armor.size() && !dropping_w; j++) {
                    if (weapon_and_armor[j] == u.worn[k].invlet) {
                        dropping_w = true;
                        dropping_a = true;
                        mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
                        mvwprintz(w_inv, drp_line, 90, c_cyan, "%c + %s", u.worn[k].invlet, u.worn[k].tname().c_str());
                        drp_line++;
                    }
                }
            }
        }
        if(dropping_a) {
            mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
            drp_line++;
        }
        for (cur_it = start; cur_it < start + maxitems && cur_line < maxitems+3; cur_it++) {
            // Clear the current line;
            mvwprintw(w_inv, cur_line, 0, "                                             ");
            mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
            mvwprintw(w_inv, drp_line + 1, 90, "%s", drp_line_padding.c_str());
            // Print category header
            for (int i = 1; i < CATEGORIES.size(); i++) {
                if (cur_it == firsts[i-1]) {
                    mvwprintz(w_inv, cur_line, 0, c_magenta, CATEGORIES[i].name.c_str());
                    cur_line++;
                }
            }

            if ( selected < start && selected > -1 ) selected = start;

            if (cur_it < stacks.size()) {
                item& it = stacks[cur_it].first->front();
                if( cur_it == selected) {
                    selected_pos = stacks[cur_it].second;
                }
                nc_color selected_line_color = inCategoryMode ? c_white_red : h_white;
                mvwputch (w_inv, cur_line, 0, (cur_it == selected ? selected_line_color : c_white), it.invlet);
                char icon = '-';
                if (dropping[cur_it] >= (it.count_by_charges() ? it.charges : stacks[cur_it].first->size())) {
                    icon = '+';
                } else if (dropping[cur_it] > 0) {
                    icon = '#';
                }
                nc_color col = ( cur_it == selected ? selected_line_color : (dropping[cur_it] == 0 ? c_ltgray : c_white ) );
                mvwprintz(w_inv, cur_line, 1, col, " %c %s", icon,
                          it.tname().c_str());
                if (stacks[cur_it].first->size() > 1) {
                    wprintz(w_inv, col, " x %d", stacks[cur_it].first->size());
                }
                if (it.charges > 0) {
                    wprintz(w_inv, col, " (%d)", it.charges);
                } else if (it.contents.size() == 1 &&
                           it.contents[0].charges > 0) {
                    wprintw(w_inv, " (%d)", it.contents[0].charges);
                }
                if (icon=='+'||icon=='#') {
                    mvwprintz(w_inv, drp_line, 90, col, "%c %c %s", it.invlet, icon, it.tname().c_str());
                    if (icon=='+') {
                        if (stacks[cur_it].first->size() > 1) {
                            wprintz(w_inv, col, " x %d", stacks[cur_it].first->size());
                        }
                        if (it.charges > 0) {
                            wprintz(w_inv, col, " (%d)", it.charges);
                        }
                    }
                    if (icon=='#') {
                        wprintz(w_inv, col, " {%d}", dropping[cur_it]);
                    }
                    drp_line++;
                }
            }
            cur_line++;
            max_it=cur_it;
        }

        if (inCategoryMode) {
            mvwprintz(w_inv, maxitems + 4, 32, c_white_red, _("In category select mode! Press [SPACE] to enter item select mode."));
        } else {
            mvwprintz(w_inv, maxitems + 4, 32, h_white, _("In item select mode! Press [SPACE] to enter category select mode."));
        }

        if (start > 0) {
            mvwprintw(w_inv, maxitems + 4, 0, _("< Go Back"));
        }
        if (cur_it < u.inv.size()) {
            mvwprintw(w_inv, maxitems + 4, 12, _("> More items"));
        }
        wrefresh(w_inv);
/* back to (int)getch() as input() mangles arrow keys
  ch = input();
*/
        ch = getch();

        if (ch == ' ') {
            inCategoryMode = !inCategoryMode;
        }
        else if ( ch == '<' || ch == KEY_PPAGE ) {
            if( start > 0) {
                for (int i = 1; i < maxitems+4; i++)
                    mvwprintz(w_inv, i, 0, c_black, "                                             ");
                start -= maxitems;
                if (start < 0)
                    start = 0;
                mvwprintw(w_inv, maxitems + 4, 0, "         ");
                if ( selected > -1 ) selected = start; // oy, the cheese
            }
        } else if ( ch == '>' || ch == KEY_NPAGE ) {
            if ( cur_it < u.inv.size()) {
                start = cur_it;
                mvwprintw(w_inv, maxitems + 4, 12, "            ");
                for (int i = 1; i < maxitems+4; i++)
                    mvwprintz(w_inv, i, 0, c_black, "                                             ");
                if ( selected < start && selected > -1 ) selected = start;
            }
        } else if ( ch == KEY_DOWN ) {
            if ( selected < 0 ) {
                selected = start;
            } else {
                if (inCategoryMode) {
                    selected < firsts[category_order[category_order.size() - 1]] ? selected = next_category_at : 0;
                } else {
                    selected++;
                }

                next_category_at = prev_category_at = 0;
            }

            if ( selected > max_it ) {
                if( cur_it < u.inv.size() ) {
                    start = cur_it;
                    mvwprintw(w_inv, maxitems + 4, 12, "            ");
                    for (int i = 1; i < maxitems+4; i++)
                        mvwprintz(w_inv, i, 0, c_black, "                                             ");
                } else {
                    selected = u.inv.size() - 1; // wraparound?
                }
            }
        } else if ( ch == KEY_UP ) {
            inCategoryMode ? selected = prev_category_at : selected--;
            next_category_at = prev_category_at = 0;

            if ( selected < -1 ) {
                selected = -1; // wraparound?
            } else if ( selected < start ) {
                if ( start > 0 ) {
                    for (int i = 1; i < maxitems+4; i++)
                        mvwprintz(w_inv, i, 0, c_black, "                                             ");
                    start -= maxitems;
                    if (start < 0)
                        start = 0;
                    mvwprintw(w_inv, maxitems + 4, 0, "         ");
                }
            }
        } else if (ch >= '0'&& ch <= '9') {
            ch = (char)ch - '0';
            count *= 10;
            count += ch;
        } else { // todo: reformat and maybe rewrite
            item* it;
            int it_pos;
            if ( ch == '\t' || ch == KEY_RIGHT || ch == KEY_LEFT ) {
                it_pos = selected_pos;
                it = &u.inv.find_item(it_pos);
            } else {
                it = &u.inv.item_by_letter((char)ch);
                it_pos = u.inv.position_by_item(it);
            }
            if (it == 0 || it->is_null()) { // Not from inventory
                int found = false;
                for (int i = 0; i < weapon_and_armor.size() && !found; i++) {
                    if (weapon_and_armor[i] == ch) {
                        weapon_and_armor.erase(weapon_and_armor.begin() + i);
                        found = true;
                        print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor);
                    }
                }
                if (!found) {
                    if ( ch == u.weapon.invlet &&
                         std::find(unreal_itype_ids.begin(), unreal_itype_ids.end(), u.weapon.type->id) != unreal_itype_ids.end()){
                        if (!warned_about_bionic)
                            add_msg(_("You cannot drop your %s."), u.weapon.tname().c_str());
                        warned_about_bionic = true;
                    } else {
                        weapon_and_armor.push_back(ch);
                        print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor);
                    }
                }
            } else {
                int index = -1;
                for (int i = 0; i < stacks.size(); ++i) {
                    if (stacks[i].first->front().invlet == it->invlet) {
                        index = i;
                        break;
                    }
                }
                if (index == -1) {
                    debugmsg("Inventory got out of sync with inventory slice?");
                }
                if (count == 0) {
                    if (it->count_by_charges()) {
                        if (dropping[it_pos] == 0) {
                            dropping[it_pos] = -1;
                        } else {
                            dropping[it_pos] = 0;
                        }
                    } else {
                        if (dropping[it_pos] == 0) {
                            dropping[it_pos] = stacks[index].first->size();
                        } else {
                            dropping[it_pos] = 0;
                        }
                    }
                } else if (count >= stacks[index].first->size() && !it->count_by_charges()) {
                    dropping[it_pos] = stacks[index].first->size();
                } else {
                    dropping[it_pos] = count;
                }

                count = 0;
            }
        }
    } while (ch != '\n' && ch != KEY_ESCAPE);
    werase(w_inv);
    delwin(w_inv);
    erase();
    refresh_all();

    std::vector<item> ret;

    if (ch != '\n')
        return ret; // Canceled!

    // We iterate backwards because deletion will invalidate later indices.
    for (std::map<int,int>::reverse_iterator it = dropping.rbegin(); it != dropping.rend(); ++it) {
        if (it->second == -1)
            ret.push_back( u.inv.remove_item( it->first));
        else if (it->second && u.inv.find_item( it->first).count_by_charges()) {
            int charges = u.inv.find_item( it->first).charges;// >= it->second ? : it->second;
            ret.push_back( u.inv.reduce_charges( it->first, it->second > charges ? charges : it->second));
        } else if (it->second)
            for (int j = it->second; j > 0; j--)
                ret.push_back( u.inv.remove_item( it->first));
    }

    for (int i = 0; i < weapon_and_armor.size(); i++)
    {
        int wornpos = u.invlet_to_position(weapon_and_armor[i]);
        if (wornpos == INT_MIN || !u.takeoff(this, wornpos, true))
        {
            continue;
        }

        // Item could have been dropped after taking it off
        if (&u.inv.item_by_letter(weapon_and_armor[i]) != &u.inv.nullitem)
        {
            ret.push_back(u.i_rem(weapon_and_armor[i]));
        }
    }

    return ret;
}
Beispiel #6
0
int game::display_slice(indexed_invslice& slice, const std::string& title)
{
    WINDOW* w_inv = newwin( TERRAIN_WINDOW_HEIGHT,
                            TERRAIN_WINDOW_WIDTH + (use_narrow_sidebar() ? 45 : 55),
                            VIEW_OFFSET_Y, VIEW_OFFSET_X );
    const int maxitems = TERRAIN_WINDOW_HEIGHT - 5;

    int ch = (int)'.';
    int start = 0, cur_it = 0, max_it;
    std::vector<char> null_vector;
    print_inv_statics(this, w_inv, title, null_vector);
    // Gun, ammo, weapon, armor, food, tool, book, other

    CategoriesVector CATEGORIES;
    std::vector<int> firsts = find_firsts(slice, CATEGORIES);

    int selected =- 1;
    int selected_pos = INT_MIN;

    int next_category_at = 0;
    int prev_category_at = 0;
    bool inCategoryMode = false;

    std::vector<int> category_order;
    category_order.reserve(firsts.size());

    // Items are not guaranteed to be in the same order as their categories, in fact they almost never are.
    // So we sort the categories by which items actually show up first in the inventory.
    for (int current_item = 0; current_item < slice.size(); ++current_item) {
        for (int i = 1; i < CATEGORIES.size(); ++i) {
            if (current_item == firsts[i - 1]) {
                category_order.push_back(i - 1);
            }
        }
    }

 do {
  if (( ch == '<' || ch == KEY_PPAGE ) && start > 0) { // Clear lines and shift
   for (int i = 1; i < maxitems+4; i++)
    mvwprintz(w_inv, i, 0, c_black, "                                             ");
   start -= maxitems;
   if (start < 0)
    start = 0;
   mvwprintw(w_inv, maxitems + 4, 0, "         ");
   if ( selected > -1 ) selected = start; // oy, the cheese
  }
  if (( ch == '>' || ch == KEY_NPAGE ) && cur_it < slice.size()) { // Clear lines and shift
   start = cur_it;
   mvwprintw(w_inv, maxitems + 4, 12, "            ");
   for (int i = 1; i < maxitems+4; i++)
    mvwprintz(w_inv, i, 0, c_black, "                                             ");
   if ( selected < start && selected > -1 ) selected = start;
  }
  int cur_line = 2;
  max_it = 0;

  // Find the inventory position of the first item in the previous and next category (in relation
  // to the currently selected category).
  for (int i = 0; i < category_order.size(); ++i)
  {
	  if (selected > firsts[category_order[i]] && prev_category_at <= firsts[category_order[i]])
	  {
		  prev_category_at = firsts[category_order[i]];
	  }

	  if (selected < firsts[category_order[i]] && next_category_at <= selected)
	  {
		  next_category_at = firsts[category_order[i]];
	  }
  }

  for (cur_it = start; cur_it < start + maxitems && cur_line < maxitems+3; cur_it++) {
// Clear the current line;
   mvwprintw(w_inv, cur_line, 0, "                                             ");

   for (int i = 1; i < CATEGORIES.size(); i++) {
    if (cur_it == firsts[i-1]) {
     mvwprintz(w_inv, cur_line, 0, c_magenta, CATEGORIES[i].name.c_str());
     cur_line++;
    }
   }

   if (cur_it < slice.size())
   {
       item& it = slice[cur_it].first->front();
       if(cur_it == selected) {
           selected_pos=slice[cur_it].second;
       }
       nc_color selected_line_color = inCategoryMode ? c_white_red : h_white;
       mvwputch(w_inv, cur_line, 0, (cur_it == selected ? selected_line_color : c_white), it.invlet);
       mvwprintz(w_inv, cur_line, 1, (cur_it == selected ? selected_line_color : it.color_in_inventory()), " %s",
                 it.display_name().c_str());
       if (slice[cur_it].first->size() > 1) {
           wprintw(w_inv, " x %d", slice[cur_it].first->size());
       }
       cur_line++;
       max_it = cur_it;
   }
  }

  if (inCategoryMode)
  {
	  mvwprintz(w_inv, maxitems + 4, 32, c_white_red, _("In category select mode! Press [SPACE] to enter item select mode."));
  }
  else
  {
	  mvwprintz(w_inv, maxitems + 4, 32, h_white, _("In item select mode! Press [SPACE] to enter category select mode."));
  }

  if (start > 0)
   mvwprintw(w_inv, maxitems + 4, 0, _("< Go Back"));
  if (cur_it < slice.size())
   mvwprintw(w_inv, maxitems + 4, 12, _("> More items"));
  wrefresh(w_inv);

  input_context ctxt("INVENTORY");
  ctxt.register_action("ANY_INPUT");
  ctxt.handle_input();
  ch = ctxt.get_raw_input().get_first_input();

  if (ch == ' ')
  {
	  inCategoryMode = !inCategoryMode;
  }
  else if ( ch == KEY_DOWN ) {
    if ( selected < 0 ) {
      selected = start;
    } else {
		if (inCategoryMode)
		{
			selected < firsts[category_order[category_order.size() - 1]] ? selected = next_category_at : 0;
		}
		else
		{
			selected++;
		}
		
		next_category_at = prev_category_at = 0;
    }

    if ( selected > max_it ) {
      if( cur_it < u.inv.size() ) {
        ch='>';
      } else {
        selected = u.inv.size() - 1; // wraparound?
      }
    }
  } else if ( ch == KEY_UP ) {
	inCategoryMode ? selected = prev_category_at : selected--;
	next_category_at = prev_category_at = 0;

    if ( selected < -1 ) {
      selected = -1; // wraparound?
    } else if ( selected < start ) {
      if ( start > 0 ) {
        for (int i = 1; i < maxitems+4; i++)
         mvwprintz(w_inv, i, 0, c_black, "                                             ");
        start -= maxitems;
        if (start < 0)
         start = 0;
        mvwprintw(w_inv, maxitems + 4, 0, "         ");
      }
    }
  } else if ( ch == '\n' || ch == KEY_RIGHT ) {
    ch = '\n';
  }

 } while (ch == '<' || ch == '>' || ch == ' ' || ch == KEY_NPAGE || ch == KEY_PPAGE || ch == KEY_UP || ch == KEY_DOWN );
 werase(w_inv);
 delwin(w_inv);
 erase();
 refresh_all();
 if (ch == '\n') {  // user hit enter (or equivalent).
  return selected_pos;
 } else {  // user hit an invlet (or exited out, which will resolve to INT_MIN)
   return u.invlet_to_position((char)ch);
 }
}
Beispiel #7
0
std::vector<item> game::multidrop()
{
    WINDOW* w_inv = newwin(TERRAIN_WINDOW_HEIGHT, TERRAIN_WINDOW_WIDTH + (use_narrow_sidebar() ? 45 : 55), VIEW_OFFSET_Y, VIEW_OFFSET_X);
    const int maxitems = TERRAIN_WINDOW_HEIGHT - 5;

 u.inv.restack(&u);
 u.inv.sort();
 int drp_line_width=getmaxx(w_inv)-90;
 const std::string drp_line_padding = ( drp_line_width > 1 ? std::string(drp_line_width, ' ') : " ");
 std::map<char, int> dropping; // Count of how many we'll drop from each stack
 int count = 0; // The current count
 std::vector<char> weapon_and_armor; // Always single, not counted
 bool warned_about_bionic = false; // Printed add_msg re: dropping bionics
 print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor);
 int base_weight = u.weight_carried();
 int base_volume = u.volume_carried();

 int ch = (int)'.';
 int start = 0, cur_it = 0, max_it;
 invslice stacks = u.inv.slice(0, u.inv.size());
 std::vector<int> firsts = find_firsts(stacks);
 int selected=-1;
 int selected_char=(int)' ';
 do {
  inventory drop_subset = u.inv.subset(dropping);
  int new_weight = base_weight - drop_subset.weight();
  int new_volume = base_volume - drop_subset.volume();
  for (int i = 0; i < weapon_and_armor.size(); ++i) {
   new_weight -= u.i_at(weapon_and_armor[i]).weight();
  }
  print_inv_weight_vol(this, w_inv, new_weight, new_volume);
  int cur_line = 2;
  max_it = 0;
  int drp_line = 1;
  // Print weapon to be dropped, the first position is reserved for high visibility
  mvwprintw(w_inv, 0, 90, "%s", drp_line_padding.c_str());
  bool dropping_w = false;
  for (int k = 0; k < weapon_and_armor.size() && !dropping_w; k++) {
    if (weapon_and_armor[k] == u.weapon.invlet) {
      dropping_w = true;
    }
    if (dropping_w && u.is_armed()) {
      mvwprintz(w_inv, 0, 90, c_ltblue, "%c + %s", u.weapon.invlet, u.weapname().c_str());
    }
  }
  // Print worn items to be dropped
  if(dropping_w) {
    mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
    drp_line++;
  }
  bool dropping_a = false;
  if (u.worn.size() > 0){
    for (int k = 0; k < u.worn.size(); k++) {
      bool dropping_w = false;
      for (int j = 0; j < weapon_and_armor.size() && !dropping_w; j++) {
        if (weapon_and_armor[j] == u.worn[k].invlet) {
          dropping_w = true;
          dropping_a = true;
          mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
          mvwprintz(w_inv, drp_line, 90, c_cyan, "%c + %s", u.worn[k].invlet, u.worn[k].tname(this).c_str());
          drp_line++;
        }
      }
    }
  }
  if(dropping_a) {
    mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
    drp_line++;
  }
  for (cur_it = start; cur_it < start + maxitems && cur_line < maxitems+3; cur_it++) {
// Clear the current line;
   mvwprintw(w_inv, cur_line, 0, "                                             ");
   mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str());
   mvwprintw(w_inv, drp_line + 1, 90, "%s", drp_line_padding.c_str());
// Print category header
   for (int i = 1; i < iCategorieNum; i++) {
    if (cur_it == firsts[i-1]) {
     mvwprintz(w_inv, cur_line, 0, c_magenta, _(CATEGORIES[i].c_str()));
     cur_line++;
    }
   }

   if ( selected < start && selected > -1 ) selected = start;

   if (cur_it < stacks.size()) {
    item& it = stacks[cur_it]->front();
    if(cur_it==selected) selected_char=(int)it.invlet;
    mvwputch (w_inv, cur_line, 0, (cur_it == selected ? h_white : c_white), it.invlet);
    char icon = '-';
    if (dropping[it.invlet] >= (it.count_by_charges() ? it.charges : stacks[cur_it]->size()))
     icon = '+';
    else if (dropping[it.invlet] > 0)
     icon = '#';
    nc_color col = ( cur_it == selected ? h_white : (dropping[it.invlet] == 0 ? c_ltgray : c_white ) );
    mvwprintz(w_inv, cur_line, 1, col, " %c %s", icon,
              it.tname(this).c_str());
    if (stacks[cur_it]->size() > 1)
     wprintz(w_inv, col, " [%d]", stacks[cur_it]->size());
    if (it.charges > 0)
     wprintz(w_inv, col, " (%d)", it.charges);
    else if (it.contents.size() == 1 &&
             it.contents[0].charges > 0)
     wprintw(w_inv, " (%d)", it.contents[0].charges);
    if (icon=='+'||icon=='#') {
      mvwprintz(w_inv, drp_line, 90, col, "%c %c %s", it.invlet, icon, it.tname(this).c_str());
      if (icon=='+'){
        if (stacks[cur_it]->size() > 1)
          wprintz(w_inv, col, " [%d]", stacks[cur_it]->size());
        if (it.charges > 0)
          wprintz(w_inv, col, " (%d)", it.charges);
      }
      if (icon=='#') {
        wprintz(w_inv, col, " {%d}", dropping[it.invlet]);
      }
      drp_line++;
    }
   }
   cur_line++;
   max_it=cur_it;
  }
  if (start > 0)
   mvwprintw(w_inv, maxitems + 4, 0, _("< Go Back"));
  if (cur_it < u.inv.size())
   mvwprintw(w_inv, maxitems + 4, 12, _("> More items"));
  wrefresh(w_inv);
/* back to (int)getch() as input() mangles arrow keys
  ch = input();
*/
  ch = getch();
  if ( ch == '<' || ch == KEY_PPAGE ) {
   if( start > 0) {
    for (int i = 1; i < maxitems+4; i++)
     mvwprintz(w_inv, i, 0, c_black, "                                             ");
    start -= maxitems;
    if (start < 0)
     start = 0;
    mvwprintw(w_inv, maxitems + 4, 0, "         ");
    if ( selected > -1 ) selected = start; // oy, the cheese
    }
  } else if ( ch == '>' || ch == KEY_NPAGE ) {
   if ( cur_it < u.inv.size()) {
    start = cur_it;
    mvwprintw(w_inv, maxitems + 4, 12, "            ");
    for (int i = 1; i < maxitems+4; i++)
     mvwprintz(w_inv, i, 0, c_black, "                                             ");
    if ( selected < start && selected > -1 ) selected = start;
   }
  } else if ( ch == KEY_DOWN ) {
    if ( selected < 0 ) {
      selected = start;
    } else {
      selected++;
    }
    if ( selected > max_it ) {
      if( cur_it < u.inv.size() ) {
        start = cur_it;
        mvwprintw(w_inv, maxitems + 4, 12, "            ");
        for (int i = 1; i < maxitems+4; i++)
         mvwprintz(w_inv, i, 0, c_black, "                                             ");
      } else {
        selected = u.inv.size() - 1; // wraparound?
      }
    }
  } else if ( ch == KEY_UP ) {
    selected--;
    if ( selected < -1 ) {
      selected = -1; // wraparound?
    } else if ( selected < start ) {
      if ( start > 0 ) {
        for (int i = 1; i < maxitems+4; i++)
         mvwprintz(w_inv, i, 0, c_black, "                                             ");
        start -= maxitems;
        if (start < 0)
         start = 0;
        mvwprintw(w_inv, maxitems + 4, 0, "         ");
      }
    }
  } else if (ch >= '0'&& ch <= '9') {
   ch = (char)ch - '0';
   count *= 10;
   count += ch;
  } else { // todo: reformat and maybe rewrite
     if ( ch == '\t' || ch == KEY_RIGHT || ch == KEY_LEFT ) {
        ch = selected_char;
     }
     if (u.has_item(ch)) {
       item& it = u.inv.item_by_letter(ch);
       if (it.is_null()) { // Not from inventory
        int found = false;
        for (int i = 0; i < weapon_and_armor.size() && !found; i++) {
         if (weapon_and_armor[i] == ch) {
          weapon_and_armor.erase(weapon_and_armor.begin() + i);
          found = true;
          print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor);
         }
        }
        if (!found) {
         if ( ch == u.weapon.invlet &&
              std::find(unreal_itype_ids.begin(), unreal_itype_ids.end(), u.weapon.type->id) != unreal_itype_ids.end()){
          if (!warned_about_bionic)
           add_msg(_("You cannot drop your %s."), u.weapon.tname(this).c_str());
          warned_about_bionic = true;
         } else {
          weapon_and_armor.push_back(ch);
          print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor);
         }
        }
       } else {
        int index = -1;
        for (int i = 0; i < stacks.size(); ++i) {
         if (stacks[i]->front().invlet == it.invlet) {
          index = i;
          break;
         }
        }
        if (index == -1) {
         debugmsg("Inventory got out of sync with inventory slice?");
        }
        if (count == 0) {
        if (it.count_by_charges())
          {
           if (dropping[it.invlet] == 0)
            dropping[it.invlet] = -1;
           else
            dropping[it.invlet] = 0;
          }
        else
          {
           if (dropping[it.invlet] == 0)
            dropping[it.invlet] = stacks[index]->size();
           else
            dropping[it.invlet] = 0;
          }
        }

        else if (count >= stacks[index]->size() && !it.count_by_charges())
           dropping[it.invlet] = stacks[index]->size();
        else
          dropping[it.invlet] = count;

       count = 0;
       }
     }
  }
 } while (ch != '\n' && ch != KEY_ESCAPE && ch != ' ');
 werase(w_inv);
 delwin(w_inv);
 erase();
 refresh_all();

 std::vector<item> ret;

 if (ch != '\n')
  return ret; // Canceled!

 for (std::map<char,int>::iterator it = dropping.begin(); it != dropping.end(); ++it) {
  if (it->second == -1)
   ret.push_back( u.inv.remove_item_by_letter( it->first));
  else if (it->second && u.inv.item_by_letter( it->first).count_by_charges()) {
   int charges = u.inv.item_by_letter( it->first).charges;// >= it->second ? : it->second;
   ret.push_back( u.inv.remove_item_by_charges( it->first, it->second > charges ? charges : it->second));
  } else if (it->second)
   for (int j = it->second; j > 0; j--)
    ret.push_back( u.inv.remove_item_by_letter( it->first));
 }

 for (int i = 0; i < weapon_and_armor.size(); i++)
 {
     if (!u.takeoff(this, weapon_and_armor[i], true))
     {
         continue;
     }

     // Item could have been dropped after taking it off
     if (&u.inv.item_by_letter(weapon_and_armor[i]) != &u.inv.nullitem)
     {
         ret.push_back(u.i_rem(weapon_and_armor[i]));
     }
 }

 return ret;
}
Beispiel #8
0
char game::inv(inventory& inv, std::string title)
{
    WINDOW* w_inv = newwin(TERRAIN_WINDOW_HEIGHT, TERRAIN_WINDOW_WIDTH + (use_narrow_sidebar() ? 45 : 55), VIEW_OFFSET_Y, VIEW_OFFSET_X);
    const int maxitems = TERRAIN_WINDOW_HEIGHT - 5;

 int ch = (int)'.';
 int start = 0, cur_it = 0, max_it;
 inv.sort();
 std::vector<char> null_vector;
 print_inv_statics(this, w_inv, title, null_vector);
// Gun, ammo, weapon, armor, food, tool, book, other

 invslice slice = inv.slice(0, inv.size());
 std::vector<int> firsts = find_firsts(slice);

 int selected =- 1;
 int selected_char = (int)' ';
 do {
  if (( ch == '<' || ch == KEY_PPAGE ) && start > 0) { // Clear lines and shift
   for (int i = 1; i < maxitems+4; i++)
    mvwprintz(w_inv, i, 0, c_black, "                                             ");
   start -= maxitems;
   if (start < 0)
    start = 0;
   mvwprintw(w_inv, maxitems + 4, 0, "         ");
   if ( selected > -1 ) selected = start; // oy, the cheese
  }
  if (( ch == '>' || ch == KEY_NPAGE ) && cur_it < inv.size()) { // Clear lines and shift
   start = cur_it;
   mvwprintw(w_inv, maxitems + 4, 12, "            ");
   for (int i = 1; i < maxitems+4; i++)
    mvwprintz(w_inv, i, 0, c_black, "                                             ");
   if ( selected < start && selected > -1 ) selected = start;
  }
  int cur_line = 2;
  max_it = 0;
  for (cur_it = start; cur_it < start + maxitems && cur_line < maxitems+3; cur_it++) {
// Clear the current line;
   mvwprintw(w_inv, cur_line, 0, "                                             ");

   for (int i = 1; i < iCategorieNum; i++) {
    if (cur_it == firsts[i-1]) {
     mvwprintz(w_inv, cur_line, 0, c_magenta, _(CATEGORIES[i].c_str()));
     cur_line++;
    }
   }

   if (cur_it < slice.size())
   {
    item& it = slice[cur_it]->front();
    if(cur_it==selected) selected_char=(int)it.invlet;
    mvwputch (w_inv, cur_line, 0, (cur_it == selected ? h_white : c_white), it.invlet);
    mvwprintz(w_inv, cur_line, 1, (cur_it == selected ? h_white : it.color_in_inventory(&u) ), " %s",
              it.tname(this).c_str());
    if (slice[cur_it]->size() > 1)
     wprintw(w_inv, " [%d]", slice[cur_it]->size());
    if (it.charges > 0)
     wprintw(w_inv, " (%d)", it.charges);
    else if (it.contents.size() == 1 &&
             it.contents[0].charges > 0)
     wprintw(w_inv, " (%d)", it.contents[0].charges);
    cur_line++;
    max_it=cur_it;
   }
//   cur_line++;
  }
  if (start > 0)
   mvwprintw(w_inv, maxitems + 4, 0, _("< Go Back"));
  if (cur_it < inv.size())
   mvwprintw(w_inv, maxitems + 4, 12, _("> More items"));
  wrefresh(w_inv);

  ch = getch();

  if ( ch == KEY_DOWN ) {
    if ( selected < 0 ) {
      selected = start;
    } else {
      selected++;
    }
    if ( selected > max_it ) {
      if( cur_it < u.inv.size() ) {
        ch='>';
      } else {
        selected = u.inv.size() - 1; // wraparound?
      }
    }
  } else if ( ch == KEY_UP ) {
    selected--;
    if ( selected < -1 ) {
      selected = -1; // wraparound?
    } else if ( selected < start ) {
      if ( start > 0 ) {
        for (int i = 1; i < maxitems+4; i++)
         mvwprintz(w_inv, i, 0, c_black, "                                             ");
        start -= maxitems;
        if (start < 0)
         start = 0;
        mvwprintw(w_inv, maxitems + 4, 0, "         ");
      }
    }
  } else if ( ch == '\n' || ch == KEY_RIGHT ) {
    ch = selected_char;
  }

 } while (ch == '<' || ch == '>' || ch == KEY_NPAGE || ch == KEY_PPAGE || ch == KEY_UP || ch == KEY_DOWN );
 werase(w_inv);
 delwin(w_inv);
 erase();
 refresh_all();
 return (char)ch;
}
Beispiel #9
0
// TODO: Shunt redundant drawing code elsewhere
std::vector<point> game::target(int &x, int &y, int lowx, int lowy, int hix,
                                int hiy, std::vector <monster> t, int &target,
                                item *relevent)
{
 std::vector<point> ret;
 int tarx, tary, junk, tart;
 int range=(hix-u.posx);
// First, decide on a target among the monsters, if there are any in range
 if (!t.empty()) {
// Check for previous target
  if (target == -1) {
// If no previous target, target the closest there is
   double closest = -1;
   double dist;
   for (int i = 0; i < t.size(); i++) {
    dist = rl_dist(t[i].posx(), t[i].posy(), u.posx, u.posy);
    if (closest < 0 || dist < closest) {
     closest = dist;
     target = i;
    }
   }
  }
  x = t[target].posx();
  y = t[target].posy();
 } else
  target = -1; // No monsters in range, don't use target, reset to -1

 bool sideStyle = use_narrow_sidebar();
 int height = 13;
 int width  = getmaxx(w_messages);
 int top    = sideStyle ? getbegy(w_messages) : (getbegy(w_minimap) + getmaxy(w_minimap));
 int left   = getbegx(w_messages);
 WINDOW* w_target = newwin(height, width, top, left);
 draw_border(w_target);
 mvwprintz(w_target, 0, 2, c_white, "< ");
 if (!relevent) { // currently targetting vehicle to refill with fuel
   wprintz(w_target, c_red, _("Select a vehicle"));
 } else {
   if (relevent == &u.weapon && relevent->is_gun()) {
     wprintz(w_target, c_red, _("Firing %s (%d)"), // - %s (%d)",
            u.weapon.tname().c_str(),// u.weapon.curammo->name.c_str(),
            u.weapon.charges);
   } else {
     wprintz(w_target, c_red, _("Throwing %s"), relevent->tname().c_str());
   }
 }
 wprintz(w_target, c_white, " >");
/* Annoying clutter @ 2 3 4. */
 int text_y = getmaxy(w_target) - 4;
 if (is_mouse_enabled()) {
     --text_y;
 }
 mvwprintz(w_target, text_y++, 1, c_white,
           _("Move cursor to target with directional keys"));
 if (relevent) {
  mvwprintz(w_target, text_y++, 1, c_white,
            _("'<' '>' Cycle targets; 'f' or '.' to fire"));
  mvwprintz(w_target, text_y++, 1, c_white,
            _("'0' target self; '*' toggle snap-to-target"));
 }

 if (is_mouse_enabled()) {
     mvwprintz(w_target, text_y++, 1, c_white,
         _("Mouse: LMB: Target, Wheel: Cycle, RMB: Fire"));
 }

 wrefresh(w_target);
 bool snap_to_target = OPTIONS["SNAP_TO_TARGET"];
 do {
  if (m.sees(u.posx, u.posy, x, y, -1, tart))
    ret = line_to(u.posx, u.posy, x, y, tart);
  else
    ret = line_to(u.posx, u.posy, x, y, 0);

  if(trigdist && trig_dist(u.posx,u.posy, x,y) > range) {
    bool cont=true;
    int cx=x;
    int cy=y;
    for (int i = 0; i < ret.size() && cont; i++) {
      if(trig_dist(u.posx,u.posy, ret[i].x, ret[i].y) > range) {
        ret.resize(i);
        cont=false;
      } else {
        cx=0+ret[i].x; cy=0+ret[i].y;
      }
    }
    x=cx;y=cy;
  }
  point center;
  if (snap_to_target)
   center = point(x, y);
  else
   center = point(u.posx + u.view_offset_x, u.posy + u.view_offset_y);
  // Clear the target window.
  for (int i = 1; i < getmaxy(w_target) - 5; i++) {
   for (int j = 1; j < getmaxx(w_target) - 2; j++)
    mvwputch(w_target, i, j, c_white, ' ');
  }
  /* Start drawing w_terrain things -- possibly move out to centralized draw_terrain_window function as they all should be roughly similar*/
  m.build_map_cache(); // part of the SDLTILES drawing code
  m.draw(w_terrain, center); // embedded in SDL drawing code
  // Draw the Monsters
  for (int i = 0; i < num_zombies(); i++) {
   if (u_see(&(zombie(i)))) {
    zombie(i).draw(w_terrain, center.x, center.y, false);
   }
  }
  // Draw the NPCs
  for (int i = 0; i < active_npc.size(); i++) {
   if (u_see(active_npc[i]->posx, active_npc[i]->posy))
    active_npc[i]->draw(w_terrain, center.x, center.y, false);
  }
  if (x != u.posx || y != u.posy) {

   // Draw the player
   int atx = POSX + u.posx - center.x, aty = POSY + u.posy - center.y;
   if (atx >= 0 && atx < TERRAIN_WINDOW_WIDTH && aty >= 0 && aty < TERRAIN_WINDOW_HEIGHT)
    mvwputch(w_terrain, aty, atx, u.color(), '@');

   // Only draw a highlighted trajectory if we can see the endpoint.
   // Provides feedback to the player, and avoids leaking information about tiles they can't see.
   draw_line(x, y, center, ret);
/*
   if (u_see( x, y)) {
    for (int i = 0; i < ret.size(); i++) {
      int mondex = mon_at(ret[i].x, ret[i].y),
          npcdex = npc_at(ret[i].x, ret[i].y);
      // NPCs and monsters get drawn with inverted colors
      if (mondex != -1 && u_see(&(zombie(mondex))))
       zombie(mondex).draw(w_terrain, center.x, center.y, true);
      else if (npcdex != -1)
       active_npc[npcdex]->draw(w_terrain, center.x, center.y, true);
      else
       m.drawsq(w_terrain, u, ret[i].x, ret[i].y, true,true,center.x, center.y);
    }
   }
//*/
            // Print to target window
            if (!relevent) {
                // currently targetting vehicle to refill with fuel
                vehicle *veh = m.veh_at(x, y);
                if (veh) {
                    mvwprintw(w_target, 1, 1, _("There is a %s"),
                              veh->name.c_str());
                }
            } else if (relevent == &u.weapon && relevent->is_gun()) {
                // firing a gun
                mvwprintw(w_target, 1, 1, _("Range: %d"),
                          rl_dist(u.posx, u.posy, x, y));
                // get the current weapon mode or mods
                std::string mode = "";
                if (u.weapon.mode == "MODE_BURST") {
                    mode = _("Burst");
                } else {
                    item* gunmod = u.weapon.active_gunmod();
                    if (gunmod != NULL) {
                        mode = gunmod->type->name;
                    }
                }
                if (mode != "") {
                    mvwprintw(w_target, 1, 14, _("Firing mode: %s"),
                              mode.c_str());
                }
            } else {
                // throwing something
                mvwprintw(w_target, 1, 1, _("Range: %d"),
                          rl_dist(u.posx, u.posy, x, y));
            }

   const int zid = mon_at(x, y);
   if (zid == -1) {
    if (snap_to_target)
     mvwputch(w_terrain, POSY, POSX, c_red, '*');
    else
     mvwputch(w_terrain, POSY + y - center.y, POSX + x - center.x, c_red, '*');
   } else {
    if (u_see(&(zombie(zid)))) {
     zombie(zid).print_info(w_target,2);
    }
   }
  }
  wrefresh(w_target);
  wrefresh(w_terrain);
  wrefresh(w_status);
  refresh();

  input_context ctxt("TARGET");
  // "ANY_INPUT" should be added before any real help strings
  // Or strings will be writen on window border.
  ctxt.register_action("ANY_INPUT");
  ctxt.register_directions();
  ctxt.register_action("COORDINATE");
  ctxt.register_action("SELECT");
  ctxt.register_action("FIRE");
  ctxt.register_action("NEXT_TARGET");
  ctxt.register_action("PREV_TARGET");
  ctxt.register_action("WAIT");
  ctxt.register_action("CENTER");
  ctxt.register_action("TOGGLE_SNAP_TO_TARGET");
  ctxt.register_action("HELP_KEYBINDINGS");
  ctxt.register_action("QUIT");

  const std::string& action = ctxt.handle_input();


  tarx = 0; tary = 0;
  // Our coordinates will either be determined by coordinate input(mouse),
  // by a direction key, or by the previous value.
  if (action == "SELECT" && ctxt.get_coordinates(g->w_terrain, tarx, tary)) {
      if (!OPTIONS["USE_TILES"] && snap_to_target) {
          // Snap to target doesn't currently work with tiles.
          tarx += x - u.posx;
          tary += y - u.posy;
      }
      tarx -= x;
      tary -= y;


  } else {
    ctxt.get_direction(tarx, tary, action);
    if(tarx == -2) {
        tarx = 0;
        tary = 0;
    }
  }

  /* More drawing to terrain */
  if (tarx != 0 || tary != 0) {
   int mondex = mon_at(x, y), npcdex = npc_at(x, y);
   if (mondex != -1 && u_see(&(zombie(mondex))))
    zombie(mondex).draw(w_terrain, center.x, center.y, false);
   else if (npcdex != -1)
    active_npc[npcdex]->draw(w_terrain, center.x, center.y, false);
   else if (m.sees(u.posx, u.posy, x, y, -1, junk))
    m.drawsq(w_terrain, u, x, y, false, true, center.x, center.y);
   else
    mvwputch(w_terrain, POSY, POSX, c_black, 'X');
   x += tarx;
   y += tary;
   if (x < lowx)
    x = lowx;
   else if (x > hix)
    x = hix;
   if (y < lowy)
    y = lowy;
   else if (y > hiy)
    y = hiy;
  } else if ((action == "PREV_TARGET") && (target != -1)) {
   target--;
   if (target == -1) target = t.size() - 1;
   x = t[target].posx();
   y = t[target].posy();
  } else if ((action == "NEXT_TARGET") && (target != -1)) {
   target++;
   if (target == t.size()) target = 0;
   x = t[target].posx();
   y = t[target].posy();
  } else if (action == "WAIT" || action == "FIRE") {
   for (int i = 0; i < t.size(); i++) {
    if (t[i].posx() == x && t[i].posy() == y)
     target = i;
   }
   if (u.posx == x && u.posy == y)
       ret.clear();
   break;
  } else if (action == "CENTER") {
   x = u.posx;
   y = u.posy;
   ret.clear();
  } else if (action == "TOGGLE_SNAP_TO_TARGET")
   snap_to_target = !snap_to_target;
  else if (action == "QUIT") { // return empty vector (cancel)
   ret.clear();
   break;
  }
 } while (true);

 return ret;
}