diff --git a/data/json/player_activities.json b/data/json/player_activities.json index 37a5d65db1003..947c20723245e 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -872,6 +872,15 @@ "based_on": "neither", "no_resume": true }, + { + "id": "ACT_CONSUME_FUEL_MENU", + "type": "activity_type", + "activity_level": "NO_EXERCISE", + "verb": "consuming fuel", + "suspendable": false, + "based_on": "neither", + "no_resume": true + }, { "id": "ACT_MIND_SPLICER", "type": "activity_type", diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index a0e9bec885d4d..ddee7b26850b0 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -1686,6 +1686,13 @@ "name": "Toggle safe fuel mod", "bindings": [ { "input_method": "keyboard_char", "key": "S" }, { "input_method": "keyboard_code", "key": "s", "mod": [ "shift" ] } ] }, + { + "type": "keybinding", + "id": "REFUEL", + "category": "BIONICS", + "name": "Open refuel menu", + "bindings": [ { "input_method": "keyboard_char", "key": "R" }, { "input_method": "keyboard_code", "key": "r", "mod": [ "shift" ] } ] + }, { "type": "keybinding", "id": "TOGGLE_AUTO_START", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index b22bf09ad6d3a..73bfcad937ebb 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -1466,7 +1466,13 @@ void consume_activity_actor::start( player_activity &act, Character &guy ) int moves; Character &player_character = get_player_character(); if( consume_location ) { - const ret_val ret = player_character.will_eat( *consume_location, true ); + ret_val ret = ret_val::make_success(); + if( refuel ) { + ret = player_character.can_consume_fuel( *consume_location ); + } else { + ret = player_character.will_eat( *consume_location, true ); + } + if( !ret.success() ) { canceled = true; consume_menu_selections = std::vector(); @@ -1476,7 +1482,12 @@ void consume_activity_actor::start( player_activity &act, Character &guy ) } moves = to_moves( guy.get_consume_time( *consume_location ) ); } else if( !consume_item.is_null() ) { - const ret_val ret = player_character.will_eat( consume_item, true ); + ret_val ret = ret_val::make_success(); + if( refuel ) { + ret = player_character.can_consume_fuel( consume_item ); + } else { + ret = player_character.will_eat( consume_item, true ); + } if( !ret.success() ) { canceled = true; consume_menu_selections = std::vector(); @@ -1513,9 +1524,9 @@ void consume_activity_actor::finish( player_activity &act, Character & ) avatar &player_character = get_avatar(); if( !canceled ) { if( consume_loc ) { - player_character.consume( consume_loc, /*force=*/true ); + player_character.consume( consume_loc, /*force=*/true, refuel ); } else if( !consume_item.is_null() ) { - player_character.consume( consume_item, /*force=*/true ); + player_character.consume( consume_item, /*force=*/true, refuel ); } else { debugmsg( "Item location/name to be consumed should not be null." ); } diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index 15de610521fc3..6cb0c6fc7502f 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -583,6 +583,7 @@ class consume_activity_actor : public activity_actor std::string consume_menu_filter; bool canceled = false; activity_id type; + bool refuel = false; /** * @pre @p other is a consume_activity_actor */ @@ -595,11 +596,11 @@ class consume_activity_actor : public activity_actor consume_activity_actor( const item_location &consume_location, std::vector consume_menu_selections, const std::vector &consume_menu_selected_items, - const std::string &consume_menu_filter, activity_id type ) : + const std::string &consume_menu_filter, activity_id type, bool refuel = false ) : consume_location( consume_location ), consume_menu_selections( consume_menu_selections ), consume_menu_selected_items( consume_menu_selected_items ), consume_menu_filter( consume_menu_filter ), - type( type ) {} + type( type ), refuel( refuel ) {} explicit consume_activity_actor( const item_location &consume_location ) : consume_location( consume_location ), consume_menu_selections( std::vector() ) {} diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index ea387b3622509..422f3fe4558fc 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -117,6 +117,7 @@ static const activity_id ACT_CLEAR_RUBBLE( "ACT_CLEAR_RUBBLE" ); static const activity_id ACT_CONSUME_DRINK_MENU( "ACT_CONSUME_DRINK_MENU" ); static const activity_id ACT_CONSUME_FOOD_MENU( "ACT_CONSUME_FOOD_MENU" ); static const activity_id ACT_CONSUME_MEDS_MENU( "ACT_CONSUME_MEDS_MENU" ); +static const activity_id ACT_CONSUME_FUEL_MENU( "ACT_CONSUME_FUEL_MENU" ); static const activity_id ACT_CRACKING( "ACT_CRACKING" ); static const activity_id ACT_DISMEMBER( "ACT_DISMEMBER" ); static const activity_id ACT_DISSECT( "ACT_DISSECT" ); @@ -272,6 +273,7 @@ activity_handlers::do_turn_functions = { { ACT_CONSUME_FOOD_MENU, consume_food_menu_do_turn }, { ACT_CONSUME_DRINK_MENU, consume_drink_menu_do_turn }, { ACT_CONSUME_MEDS_MENU, consume_meds_menu_do_turn }, + { ACT_CONSUME_FUEL_MENU, consume_fuel_menu_do_turn }, { ACT_MOVE_LOOT, move_loot_do_turn }, { ACT_ADV_INVENTORY, adv_inventory_do_turn }, { ACT_ARMOR_LAYERS, armor_layers_do_turn }, @@ -351,6 +353,7 @@ activity_handlers::finish_functions = { { ACT_CONSUME_FOOD_MENU, eat_menu_finish }, { ACT_CONSUME_DRINK_MENU, eat_menu_finish }, { ACT_CONSUME_MEDS_MENU, eat_menu_finish }, + { ACT_CONSUME_FUEL_MENU, eat_menu_finish }, { ACT_WASH, washing_finish }, { ACT_HACKSAW, hacksaw_finish }, { ACT_PRY_NAILS, pry_nails_finish }, @@ -2843,6 +2846,12 @@ void activity_handlers::consume_meds_menu_do_turn( player_activity *, player * ) avatar_action::eat( player_character, game_menus::inv::consume_meds( player_character ) ); } +void activity_handlers::consume_fuel_menu_do_turn( player_activity *, player * ) +{ + avatar &player_character = get_avatar(); + avatar_action::eat( player_character, game_menus::inv::consume_fuel( player_character ), true ); +} + void activity_handlers::move_loot_do_turn( player_activity *act, player *p ) { activity_on_turn_move_loot( *act, *p ); diff --git a/src/activity_handlers.h b/src/activity_handlers.h index bfb9ff44bd3af..2e897e4d0fe93 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -148,6 +148,7 @@ void eat_menu_do_turn( player_activity *act, player *p ); void consume_food_menu_do_turn( player_activity *act, player *p ); void consume_drink_menu_do_turn( player_activity *act, player *p ); void consume_meds_menu_do_turn( player_activity *act, player *p ); +void consume_fuel_menu_do_turn( player_activity *act, player *p ); void move_items_do_turn( player_activity *act, player *p ); void multiple_farm_do_turn( player_activity *act, player *p ); void multiple_fish_do_turn( player_activity *act, player *p ); diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index cb9b324efde4c..ccc0986c6ffb7 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -830,21 +830,21 @@ bool avatar_action::eat_here( avatar &you ) return false; } -void avatar_action::eat( avatar &you, const item_location &loc ) +void avatar_action::eat( avatar &you, const item_location &loc, bool refuel ) { std::string filter; if( !you.activity.str_values.empty() ) { filter = you.activity.str_values.back(); } avatar_action::eat( you, loc, you.activity.values, you.activity.targets, filter, - you.activity.id() ); + you.activity.id(), refuel ); } void avatar_action::eat( avatar &you, const item_location &loc, const std::vector &consume_menu_selections, const std::vector &consume_menu_selected_items, const std::string &consume_menu_filter, - activity_id type ) + activity_id type, bool refuel ) { if( !loc ) { you.cancel_activity(); @@ -852,7 +852,7 @@ void avatar_action::eat( avatar &you, const item_location &loc, return; } you.assign_activity( player_activity( consume_activity_actor( loc, consume_menu_selections, - consume_menu_selected_items, consume_menu_filter, type ) ) ); + consume_menu_selected_items, consume_menu_filter, type, refuel ) ) ); } void avatar_action::plthrow( avatar &you, item_location loc, diff --git a/src/avatar_action.h b/src/avatar_action.h index 149f55135d14c..cdc27d95f70d3 100644 --- a/src/avatar_action.h +++ b/src/avatar_action.h @@ -21,11 +21,11 @@ namespace avatar_action { /** Eat food or fuel 'E' (or 'a') */ -void eat( avatar &you, const item_location &loc ); +void eat( avatar &you, const item_location &loc, bool refuel = false ); void eat( avatar &you, const item_location &loc, const std::vector &consume_menu_selections, const std::vector &consume_menu_selected_items, - const std::string &consume_menu_filter, activity_id type ); + const std::string &consume_menu_filter, activity_id type, bool refuel = false ); // special rules for eating: grazing etc // returns false if no rules are needed bool eat_here( avatar &you ); diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index ce7835e5aa08c..5fd87546e2ba1 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -7,6 +7,7 @@ #include #include "avatar.h" +#include "avatar_action.h" #include "bionics.h" #include "bodypart.h" #include "calendar.h" @@ -17,6 +18,7 @@ #include "enums.h" #include "flat_set.h" #include "game.h" +#include "game_inventory.h" #include "input.h" #include "inventory.h" #include "material.h" @@ -268,9 +270,10 @@ static void draw_bionics_titlebar( const catacurses::window &window, avatar *p, std::string desc_append = string_format( _( "[%s] Reassign, [%s] Switch tabs, " "[%s] Toggle fuel saving mode, " - "[%s] Toggle auto start mode." ), + "[%s] Toggle auto start mode, " + "[%s] Open refueling menu." ), ctxt.get_desc( "REASSIGN" ), ctxt.get_desc( "NEXT_TAB" ), ctxt.get_desc( "TOGGLE_SAFE_FUEL" ), - ctxt.get_desc( "TOGGLE_AUTO_START" ) ); + ctxt.get_desc( "TOGGLE_AUTO_START" ), ctxt.get_desc( "REFUEL" ) ); desc_append += string_format( _( " [%s] Sort: %s" ), ctxt.get_desc( "SORT" ), sort_mode_str( uistate.bionic_sort_mode ) ); std::string desc; @@ -636,6 +639,7 @@ void avatar::power_bionics() ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "TOGGLE_SAFE_FUEL" ); + ctxt.register_action( "REFUEL" ); ctxt.register_action( "TOGGLE_AUTO_START" ); ctxt.register_action( "SORT" ); @@ -835,6 +839,9 @@ void avatar::power_bionics() popup( _( "You can't toggle fuel saving mode on a non-fueled CBM." ) ); } } + } else if( action == "REFUEL" ) { + avatar_action::eat( get_avatar(), game_menus::inv::consume_fuel( get_avatar() ), true ); + break; } else if( action == "TOGGLE_AUTO_START" ) { auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; if( !current_bionic_list->empty() ) { diff --git a/src/character.h b/src/character.h index f934faf72571a..cbdbf2528fd44 100644 --- a/src/character.h +++ b/src/character.h @@ -2365,6 +2365,8 @@ class Character : public Creature, public visitable int nutrition_for( const item &comest ) const; /** Can the food be [theoretically] eaten no matter the consequences? */ ret_val can_eat( const item &food ) const; + /** Can the fuel be [theoretically] eaten? */ + ret_val can_consume_fuel( const item &fuel ) const; /** * Same as @ref can_eat, but takes consequences into account. * Asks about them if @param interactive is true, refuses otherwise. diff --git a/src/consumption.cpp b/src/consumption.cpp index 430a46e02fb17..55102d8e10f29 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -635,22 +635,8 @@ morale_type Character::allergy_type( const item &food ) const ret_val Character::can_eat( const item &food ) const { - bool can_fuel_cbm = can_fuel_bionic_with( food ); - if( !food.is_comestible() && !can_fuel_cbm ) { + if( !food.is_comestible() ) { return ret_val::make_failure( _( "That doesn't look edible." ) ); - } else if( can_fuel_cbm ) { - std::string item_name = food.tname(); - material_id mat_type = food.get_base_material().id; - if( food.type->magazine ) { - const item ammo = item( food.ammo_current() ); - item_name = ammo.tname(); - mat_type = ammo.get_base_material().id; - } - if( get_fuel_capacity( mat_type ) <= 0 ) { - return ret_val::make_failure( _( "No space to store more %s" ), item_name ); - } else { - return ret_val::make_success(); - } } const auto &comest = food.get_comestible(); @@ -768,6 +754,26 @@ ret_val Character::can_eat( const item &food ) const return ret_val::make_success(); } +ret_val Character::can_consume_fuel( const item &fuel ) const +{ + if( !can_fuel_bionic_with( fuel ) ) { + return ret_val::make_failure( _( "That doesn't look useable as fuel." ) ); + } else { + std::string item_name = fuel.tname(); + material_id mat_type = fuel.get_base_material().id; + if( fuel.type->magazine ) { + const item ammo = item( fuel.ammo_current() ); + item_name = ammo.tname(); + mat_type = ammo.get_base_material().id; + } + if( get_fuel_capacity( mat_type ) <= 0 ) { + return ret_val::make_failure( _( "No space to store more %s" ), item_name ); + } + + } + return ret_val::make_success(); +} + ret_val Character::will_eat( const item &food, bool interactive ) const { const auto ret = can_eat( food ); @@ -778,7 +784,7 @@ ret_val Character::will_eat( const item &food, bool interactive ) return ret; } - // exit early for cbm fuel as we've already tested everything in can_eat + // exit early as we've already tested everything in can_eat if( !food.is_comestible() ) { return ret_val::make_success(); } @@ -1528,7 +1534,7 @@ bool Character::fuel_bionic_with( item &it ) ngettext( " load %1$i charge of %2$s in their %3$s.", " load %1$i charges of %2$s in their %3$s.", loadable ), loadable, mat->name(), bio->name ); - mod_moves( -250 ); + // Return false for magazines because only their ammo is consumed return !is_magazine; } @@ -1730,18 +1736,7 @@ static bool consume_med( item &target, player &you ) return true; } -static bool cbm_is_full( const player &guy, const item &fuel ) -{ - material_id fuel_mat; - if( fuel.is_magazine() ) { - fuel_mat = item( fuel.ammo_current() ).get_base_material().id; - } else { - fuel_mat = fuel.get_base_material().id; - } - return guy.get_fuel_capacity( fuel_mat ) > 0; -} - -trinary player::consume( item &target, bool force ) +trinary player::consume( item &target, bool force, bool refuel ) { if( target.is_null() ) { add_msg_if_player( m_info, _( "You do not have that item." ) ); @@ -1762,10 +1757,13 @@ trinary player::consume( item &target, bool force ) if( is_player() && !query_consume_ownership( target, *this ) ) { return trinary::NONE; } - if( consume_med( target, *this ) || - ( has_max_power() && get_power_level() < get_max_power_level() && - cbm_is_full( *this, target ) && fuel_bionic_with( target ) ) || - eat( target, *this, force ) ) { + + if( refuel ) { + fuel_bionic_with( target ); + return target.charges <= 0 ? trinary::ALL : trinary::SOME; + } + + if( consume_med( target, *this ) || eat( target, *this, force ) ) { get_event_bus().send( getID(), target.typeId() ); @@ -1776,7 +1774,7 @@ trinary player::consume( item &target, bool force ) return trinary::NONE; } -trinary player::consume( item_location loc, bool force ) +trinary player::consume( item_location loc, bool force, bool refuel ) { if( !loc ) { debugmsg( "Null loc to consume." ); @@ -1784,7 +1782,7 @@ trinary player::consume( item_location loc, bool force ) } contents_change_handler handler; item &target = *loc; - trinary result = consume( target, force ); + trinary result = consume( target, force, refuel ); if( result != trinary::NONE ) { handler.unseal_pocket_containing( loc ); } diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 87c47ebe5fba9..934ebd1536a35 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -62,6 +62,7 @@ static const activity_id ACT_EAT_MENU( "ACT_EAT_MENU" ); static const activity_id ACT_CONSUME_FOOD_MENU( "ACT_CONSUME_FOOD_MENU" ); static const activity_id ACT_CONSUME_DRINK_MENU( "ACT_CONSUME_DRINK_MENU" ); static const activity_id ACT_CONSUME_MEDS_MENU( "ACT_CONSUME_MEDS_MENU" ); +static const activity_id ACT_CONSUME_FUEL_MENU( "ACT_CONSUME_FUEL_MENU" ); static const quality_id qual_ANESTHESIA( "ANESTHESIA" ); @@ -131,7 +132,8 @@ static item_location inv_internal( Character &u, const inventory_selector_preset ACT_EAT_MENU, ACT_CONSUME_FOOD_MENU, ACT_CONSUME_DRINK_MENU, - ACT_CONSUME_MEDS_MENU }; + ACT_CONSUME_MEDS_MENU, + ACT_CONSUME_FUEL_MENU }; u.inv->restack( u ); @@ -655,26 +657,7 @@ class comestible_inventory_preset : public inventory_selector_preset } return std::string(); }, _( "SPOILS IN" ) ); - append_cell( [&p]( const item_location & loc ) { - std::string cbm_name; - if( p.can_fuel_bionic_with( *loc ) ) { - std::vector bids = p.get_bionic_fueled_with( *loc ); - if( !bids.empty() ) { - bionic_id bid = p.get_most_efficient_bionic( bids ); - cbm_name = bid->name.translated(); - } - } - if( !cbm_name.empty() ) { - return string_format( "%s", cbm_name ); - } - - return std::string(); - }, _( "CBM" ) ); - - append_cell( [&p]( const item_location & loc ) { - return good_bad_none( p.get_acquirable_energy( *loc ) ); - }, _( "ENERGY (kJ)" ) ); } bool is_shown( const item_location &loc ) const override { @@ -791,6 +774,181 @@ class comestible_inventory_preset : public inventory_selector_preset const player &p; }; +class fuel_inventory_preset : public inventory_selector_preset +{ + public: + explicit fuel_inventory_preset( const player &p ) : p( p ) { + + _indent_entries = false; + + append_cell( []( const item_location & loc ) { + const time_duration spoils = loc->is_comestible() ? loc->get_comestible()->spoils : + calendar::INDEFINITELY_LONG_DURATION; + if( spoils > 0_turns ) { + return to_string_clipped( spoils ); + } + //~ Used for permafood shelf life in the Eat menu + return std::string( _( "indefinite" ) ); + }, _( "SHELF LIFE" ) ); + + append_cell( []( const item_location & loc ) { + const item &it = *loc; + + int converted_volume_scale = 0; + const int charges = std::max( it.charges, 1 ); + const double converted_volume = round_up( convert_volume( it.volume().value() / charges, + &converted_volume_scale ), 2 ); + + //~ Eat menu Volume: + return string_format( _( "%.2f%s" ), converted_volume, volume_units_abbr() ); + }, _( "VOLUME" ) ); + + Character &player_character = get_player_character(); + append_cell( [&player_character]( const item_location & loc ) { + time_duration time = player_character.get_consume_time( *loc ); + return string_format( "%s", to_string( time, true ) ); + }, _( "CONSUME TIME" ) ); + + append_cell( [this, &player_character]( const item_location & loc ) { + std::string sealed; + if( loc.has_parent() ) { + item_pocket *pocket = loc.parent_item()->contained_where( *loc.get_item() ); + sealed = pocket->sealed() ? _( "sealed" ) : std::string(); + } + if( player_character.can_estimate_rot() ) { + if( loc->is_comestible() && loc->get_comestible()->spoils > 0_turns ) { + return sealed + ( sealed.empty() ? "" : " " ) + get_freshness( loc ); + } + return std::string( "---" ); + } + return sealed; + }, _( "FRESHNESS" ) ); + + append_cell( [this, &player_character]( const item_location & loc ) { + if( player_character.can_estimate_rot() ) { + if( loc->is_comestible() && loc->get_comestible()->spoils > 0_turns ) { + if( !loc->rotten() ) { + return get_time_left_rounded( loc ); + } + } + return std::string( "---" ); + } + return std::string(); + }, _( "SPOILS IN" ) ); + append_cell( [&p]( const item_location & loc ) { + std::string cbm_name; + + std::vector bids = p.get_bionic_fueled_with( *loc ); + if( !bids.empty() ) { + bionic_id bid = p.get_most_efficient_bionic( bids ); + cbm_name = bid->name.translated(); + } + + if( !cbm_name.empty() ) { + return string_format( "%s", cbm_name ); + } + + return std::string(); + }, _( "CBM" ) ); + + append_cell( [&p]( const item_location & loc ) { + return good_bad_none( p.get_acquirable_energy( *loc ) ); + }, _( "ENERGY (kJ)" ) ); + } + + bool is_shown( const item_location &loc ) const override { + return p.can_fuel_bionic_with( *loc ); + } + + std::string get_denial( const item_location &loc ) const override { + + if( loc->made_of_from_type( phase_id::LIQUID ) && loc.where() != item_location::type::container ) { + return _( "Can't use spilt liquids." ); + } + + if( p.get_fuel_capacity( loc->get_base_material().id ) <= 0 ) { + return ( _( "No space to store more" ) ); + } + + return inventory_selector_preset::get_denial( loc ); + } + + bool sort_compare( const inventory_entry &lhs, const inventory_entry &rhs ) const override { + time_duration time_a = get_time_left( lhs.any_item() ); + time_duration time_b = get_time_left( rhs.any_item() ); + int order_a = get_order( lhs.any_item(), time_a ); + int order_b = get_order( rhs.any_item(), time_b ); + + return order_a < order_b + || ( order_a == order_b && time_a < time_b ) + || ( order_a == order_b && time_a == time_b && + inventory_selector_preset::sort_compare( lhs, rhs ) ); + } + + protected: + int get_order( const item_location &loc, const time_duration &time ) const { + if( loc->rotten() ) { + return 2; + } else if( time == 0_turns ) { + return 2; + } else { + return 1; + } + } + + time_duration get_time_left( const item_location &loc ) const { + time_duration time_left = 0_turns; + const time_duration shelf_life = loc->is_comestible() ? loc->get_comestible()->spoils : + calendar::INDEFINITELY_LONG_DURATION; + if( shelf_life > 0_turns ) { + const item &it = *loc; + const double relative_rot = it.get_relative_rot(); + time_left = shelf_life - shelf_life * relative_rot; + + // Correct for an estimate that exceeds shelf life -- this happens especially with + // fresh items. + if( time_left > shelf_life ) { + time_left = shelf_life; + } + } + + return time_left; + } + + std::string get_time_left_rounded( const item_location &loc ) const { + const item &it = *loc; + if( it.is_going_bad() ) { + return _( "soon!" ); + } + + time_duration time_left = get_time_left( loc ); + return to_string_approx( time_left ); + } + + std::string get_freshness( const item_location &loc ) { + const item &it = *loc; + const double rot_progress = it.get_relative_rot(); + if( it.is_fresh() ) { + return _( "fresh" ); + } else if( rot_progress < 0.3 ) { + return _( "quite fresh" ); + } else if( rot_progress < 0.5 ) { + return _( "near midlife" ); + } else if( rot_progress < 0.7 ) { + return _( "past midlife" ); + } else if( rot_progress < 0.9 ) { + return _( "getting older" ); + } else if( !it.rotten() ) { + return _( "old" ); + } else { + return _( "rotten" ); + } + } + + private: + const player &p; +}; + static std::string get_consume_needs_hint( player &p ) { auto hint = std::string(); @@ -839,6 +997,21 @@ class comestible_filtered_inventory_preset : public comestible_inventory_preset bool( *predicate )( const item &it ); }; +class fuel_filtered_inventory_preset : public fuel_inventory_preset +{ + public: + fuel_filtered_inventory_preset( const player &p, bool( *predicate )( const item &it ) ) : + fuel_inventory_preset( p ), predicate( predicate ) {} + + bool is_shown( const item_location &loc ) const override { + return fuel_inventory_preset::is_shown( loc ) && + predicate( *loc ); + } + + private: + bool( *predicate )( const item &it ); +}; + item_location game_menus::inv::consume_food( player &p ) { Character &player_character = get_player_character(); @@ -889,6 +1062,21 @@ item_location game_menus::inv::consume_meds( player &p ) get_consume_needs_hint( p ) ); } +item_location game_menus::inv::consume_fuel( player &p ) +{ + Character &player_character = get_player_character(); + if( !player_character.has_activity( ACT_CONSUME_FUEL_MENU ) ) { + player_character.assign_activity( ACT_CONSUME_FUEL_MENU ); + } + std::string none_message = player_character.activity.str_values.size() == 2 ? + _( "You have no more fuel to consume." ) : _( "You have no fuel to consume." ); + return inv_internal( p, fuel_filtered_inventory_preset( p, []( const item & it ) { + return it.is_fuel(); + } ), + _( "Consume fuel" ), 1, + none_message ); +} + class activatable_inventory_preset : public pickup_inventory_preset { public: diff --git a/src/game_inventory.h b/src/game_inventory.h index 765150402e419..e8d37cc5305a9 100644 --- a/src/game_inventory.h +++ b/src/game_inventory.h @@ -94,6 +94,8 @@ item_location consume_food( player &p ); item_location consume_drink( player &p ); /** Consuming a medication item via a custom menu. */ item_location consume_meds( player &p ); +/** Consuming fuel item via a custom menu. */ +item_location consume_fuel( player &p ); /** Choosing a container for liquid. */ item_location container_for( Character &you, const item &liquid, int radius = 0, const item *avoid = nullptr ); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index bd65064e72558..f609b34df6f88 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1545,6 +1545,7 @@ void game::open_consume_item_menu() as_m.entries.emplace_back( 0, true, 'f', _( "Food" ) ); as_m.entries.emplace_back( 1, true, 'd', _( "Drink" ) ); as_m.entries.emplace_back( 2, true, 'm', _( "Medication" ) ); + as_m.entries.emplace_back( 3, true, 'u', _( "Fuel" ) ); as_m.query(); avatar &player_character = get_avatar(); @@ -1558,6 +1559,9 @@ void game::open_consume_item_menu() case 2: avatar_action::eat( player_character, game_menus::inv::consume_meds( player_character ) ); break; + case 3: + avatar_action::eat( player_character, game_menus::inv::consume_fuel( get_avatar() ), true ); + break; default: break; } diff --git a/src/player.h b/src/player.h index 1fae5446fed47..240cc74650761 100644 --- a/src/player.h +++ b/src/player.h @@ -213,12 +213,12 @@ class player : public Character /** Used for eating object at a location. Removes item if all of it was consumed. * @returns trinary enum NONE, SOME or ALL amount consumed. */ - trinary consume( item_location loc, bool force = false ); + trinary consume( item_location loc, bool force = false, bool refuel = false ); /** Used for eating a particular item that doesn't need to be in inventory. * @returns trinary enum NONE, SOME or ALL (doesn't remove). */ - trinary consume( item &target, bool force = false ); + trinary consume( item &target, bool force = false, bool refuel = false ); int get_lift_assist() const;