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(); }
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 ); } }
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(); }