void game::item_action_menu()
{
    const auto &gen = item_action_generator::generator();
    const action_map &item_actions = gen.get_item_action_map();
    item_action_map iactions = gen.map_actions_to_items( u );
    if( iactions.empty() ) {
        popup( _("You don't have any items with registered uses") );
    }

    uimenu kmenu;
    kmenu.text = _( "Execute which action?" );
    input_context ctxt("ITEM_ACTIONS");
    actmenu_cb callback( item_actions );
    kmenu.callback = &callback;
    int num = 0;
    for( auto &p : iactions ) {
        it_tool *tool = dynamic_cast<it_tool*>( p.second->type );
        int would_use_charges = tool == nullptr ? 0 : tool->charges_per_use;
        
        std::stringstream ss;
        ss << _( gen.get_action_name( p.first ).c_str() ) << " [" << p.second->display_name();
        if( would_use_charges > 0 ) {
            ss << " (" << would_use_charges << '/' << p.second->charges << ')';
        }
        ss << "]";
        
        char bind = key_bound_to( ctxt, p.first );
        kmenu.addentry( num, true, bind, ss.str() );
        num++;
    }

    std::set< item_action_id > itemless;
    for( auto &p : item_actions ) {
        if( iactions.find( p.first ) == iactions.end() ) {
            char bind = key_bound_to( ctxt, p.first );
            kmenu.addentry( num, false, bind, _( gen.get_action_name( p.first ).c_str() ) );
            num++;
        }
    }

    kmenu.addentry( num, true, key_bound_to( ctxt, "QUIT" ), _("Cancel") );

    kmenu.query();
    if( kmenu.ret < 0 || kmenu.ret >= (int)iactions.size() ) {
        return;
    }

    draw_ter();
    
    auto iter = iactions.begin();
    std::advance( iter, kmenu.ret );

    if( u.invoke_item( iter->second, iter->first ) ) {
        // Need to remove item
        u.i_rem( iter->second );
    }

    u.inv.restack( &u );
    u.inv.unsort();
}
Example #2
0
void game::item_action_menu()
{
    item_action_map iactions = map_actions_to_items( u );
    if( iactions.empty() ) {
        popup( _("You don't have any items with registered uses") );
    }

    uimenu kmenu;
    kmenu.text = _( "Execute which action?" );
    input_context ctxt("ITEM_ACTIONS");
    actmenu_cb callback;
    kmenu.callback = &callback;
    int num = 0;
    for( auto &p : iactions ) {
        it_tool *tool = dynamic_cast<it_tool*>( p.second->type );
        int would_use_charges = tool == nullptr ? 0 : tool->charges_per_use;
        
        std::stringstream ss;
        ss << _( item_actions[p.first].name.c_str() ) << " [" << p.second->type_name( 1 );
        if( would_use_charges > 0 ) {
            ss << " (" << would_use_charges << '/' << p.second->charges << ')';
        }
        ss << "]";
        
        char bind = key_bound_to( ctxt, p.first );
        kmenu.addentry( num, true, bind, ss.str() );
        num++;
    }

    std::set< item_action_id > itemless;
    for( auto &p : item_actions ) {
        if( iactions.find( p.first ) == iactions.end() ) {
            char bind = key_bound_to( ctxt, p.first );
            kmenu.addentry( num, false, bind, _( item_actions[p.first].name.c_str() ) );
            num++;
        }
    }
    
    kmenu.addentry( num, true, key_bound_to( ctxt, "QUIT" ), _("Cancel") );

    kmenu.query();
    if( kmenu.ret < 0 || kmenu.ret >= (int)iactions.size() ) {
        return;
    }
    
    auto iter = iactions.begin();
    for( int i = 0; i < kmenu.ret; i++) {
        iter++;
    }
    int invpos = u.inv.position_by_item( iter->second );
    draw_ter();
    if( invpos != INT_MIN ) {
        u.use( invpos );
    }
}
Example #3
0
void game::item_action_menu()
{
    const auto &gen = item_action_generator::generator();
    const action_map &item_actions = gen.get_item_action_map();

    // A bit of a hack for now. If more pseudos get implemented, this should be un-hacked
    std::vector<item *> pseudos;
    item toolset( "toolset", calendar::turn );
    if( u.has_active_bionic( bionic_id( "bio_tools" ) ) ) {
        pseudos.push_back( &toolset );
    }

    item_action_map iactions = gen.map_actions_to_items( u, pseudos );
    if( iactions.empty() ) {
        popup( _( "You don't have any items with registered uses" ) );
    }

    uimenu kmenu;
    kmenu.text = _( "Execute which action?" );
    kmenu.return_invalid = true;
    kmenu.input_category = "ITEM_ACTIONS";
    input_context ctxt( "ITEM_ACTIONS" );
    for( const auto &id : item_actions ) {
        ctxt.register_action( id.first, id.second.name );
        kmenu.additional_actions.emplace_back( id.first, id.second.name );
    }
    actmenu_cb callback( item_actions );
    kmenu.callback = &callback;
    int num = 0;

    const auto assigned_action = [&iactions]( const item_action_id & action ) {
        return iactions.find( action ) != iactions.end();
    };

    std::vector<std::tuple<item_action_id, std::string, std::string>> menu_items;
    // Sorts menu items by action.
    typedef decltype( menu_items )::iterator Iter;
    const auto sort_menu = []( Iter from, Iter to ) {
        std::sort( from, to, []( const std::tuple<item_action_id, std::string, std::string> &lhs,
        const std::tuple<item_action_id, std::string, std::string> &rhs ) {
            return std::get<1>( lhs ).compare( std::get<1>( rhs ) ) < 0;
        } );
    };
    // Add mapped actions to the menu vector.
    std::transform( iactions.begin(), iactions.end(), std::back_inserter( menu_items ),
    []( const std::pair<item_action_id, item *> &elem ) {
        std::stringstream ss;
        ss << elem.second->display_name();
        if( elem.second->ammo_required() ) {
            ss << " (" << elem.second->ammo_required() << '/'
               << elem.second->ammo_remaining() << ')';
        }

        const auto method = elem.second->get_use( elem.first );
        return std::make_tuple( method->get_type(), method->get_name(), ss.str() );
    } );
    // Sort mapped actions.
    sort_menu( menu_items.begin(), menu_items.end() );
    // Add unmapped but binded actions to the menu vector.
    for( const auto &elem : item_actions ) {
        if( key_bound_to( ctxt, elem.first ) != '\0' && !assigned_action( elem.first ) ) {
            menu_items.emplace_back( elem.first, gen.get_action_name( elem.first ), "-" );
        }
    }
    // Sort unmapped actions.
    auto iter = menu_items.begin();
    std::advance( iter, iactions.size() );
    sort_menu( iter, menu_items.end() );
    // Determine max lengths, to print the menu nicely.
    std::pair<int, int> max_len;
    for( const auto &elem : menu_items ) {
        max_len.first = std::max( max_len.first, utf8_width( std::get<1>( elem ), true ) );
        max_len.second = std::max( max_len.second, utf8_width( std::get<2>( elem ), true ) );
    }
    // Fill the menu.
    for( const auto &elem : menu_items ) {
        std::stringstream ss;
        ss << std::get<1>( elem )
           << std::string( max_len.first - utf8_width( std::get<1>( elem ), true ), ' ' )
           << std::string( 4, ' ' );

        ss << std::get<2>( elem )
           << std::string( max_len.second - utf8_width( std::get<2>( elem ), true ), ' ' );

        const char bind = key_bound_to( ctxt, std::get<0>( elem ) );
        const bool enabled = assigned_action( std::get<0>( elem ) );

        kmenu.addentry( num, enabled, bind, ss.str() );
        num++;
    }

    kmenu.query();
    if( kmenu.ret < 0 || kmenu.ret >= ( int )iactions.size() ) {
        return;
    }

    draw_ter();

    const item_action_id action = std::get<0>( menu_items[kmenu.ret] );
    item *it = iactions[action];

    u.invoke_item( it, action );

    u.inv.restack( &u );
    u.inv.unsort();
}