From 910fee470d5b7e42dee81cb6a4dbe9a8a5cc3f79 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 17 Aug 2019 13:16:26 -0400 Subject: [PATCH 01/19] # If this commit is applied, it will .... WIP for 'E'ating menu # Explain why this change is being made current one is clunky --- data/json/player_activities.json | 9 + src/activity_handlers.cpp | 8 + src/activity_handlers.h | 1 + src/advanced_inv.cpp | 2 + src/comestible_inv.cpp | 2494 ++++++++++++++++++++++++++++++ src/comestible_inv.h | 478 ++++++ src/handle_action.cpp | 7 +- src/uistate.h | 17 +- 8 files changed, 3013 insertions(+), 3 deletions(-) create mode 100644 src/comestible_inv.cpp create mode 100644 src/comestible_inv.h diff --git a/data/json/player_activities.json b/data/json/player_activities.json index 2a8f3425b5eb1..971eb5a3f2a45 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -342,6 +342,15 @@ "based_on": "neither", "no_resume": true }, + { + "id": "ACT_COMESTIBLE_INVENTORY", + "type": "activity_type", + "activity_level": "NO_EXERCISE", + "verb": "interacting with inventory", + "suspendable": false, + "based_on": "neither", + "no_resume": true + }, { "id": "ACT_ARMOR_LAYERS", "type": "activity_type", diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 98be2d46d0171..3329015587cce 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -16,6 +16,7 @@ #include "action.h" #include "advanced_inv.h" +#include "comestible_inv.h" #include "avatar.h" #include "avatar_action.h" #include "clzones.h" @@ -139,6 +140,7 @@ activity_handlers::do_turn_functions = { { activity_id( "ACT_MOVE_ITEMS" ), move_items_do_turn }, { activity_id( "ACT_MOVE_LOOT" ), move_loot_do_turn }, { activity_id( "ACT_ADV_INVENTORY" ), adv_inventory_do_turn }, + { activity_id( "ACT_COMESTIBLE_INVENTORY" ), comestible_inventory_do_turn }, { activity_id( "ACT_ARMOR_LAYERS" ), armor_layers_do_turn }, { activity_id( "ACT_ATM" ), atm_do_turn }, { activity_id( "ACT_CRACKING" ), cracking_do_turn }, @@ -2608,6 +2610,12 @@ void activity_handlers::adv_inventory_do_turn( player_activity *, player *p ) advanced_inv(); } +void activity_handlers::comestible_inventory_do_turn(player_activity*, player* p) +{ + p->cancel_activity(); + comestible_inv(); +} + void activity_handlers::drive_do_turn( player_activity *act, player *p ) { vehicle *player_veh = veh_pointer_or_null( g->m.veh_at( p->pos() ) ); diff --git a/src/activity_handlers.h b/src/activity_handlers.h index 315a7e31f4d94..20b16e36b4d88 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -81,6 +81,7 @@ void move_loot_do_turn( player_activity *act, player *p ); void travel_do_turn( player_activity *act, player *p ); void drive_do_turn( player_activity *act, player *p ); void adv_inventory_do_turn( player_activity *act, player *p ); +void comestible_inventory_do_turn( player_activity *act, player *p ); void armor_layers_do_turn( player_activity *act, player *p ); void atm_do_turn( player_activity *act, player *p ); void fish_do_turn( player_activity *act, player *p ); diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 8d6d3ab5f813c..7292ef45a9e2b 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -173,6 +173,8 @@ void advanced_inventory::load_settings() panes[i].filter = uistate.adv_inv_filter[i]; } uistate.adv_inv_exit_code = exit_none; + + add_msg(m_info, "~~~ %d %d", uistate.wishitem_selected, uistate.save_var); } std::string advanced_inventory::get_sortname( advanced_inv_sortby sortby ) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp new file mode 100644 index 0000000000000..67eae8a9bebb2 --- /dev/null +++ b/src/comestible_inv.cpp @@ -0,0 +1,2494 @@ +#include "comestible_inv.h" + +#include "auto_pickup.h" +#include "avatar.h" +#include "cata_utility.h" +#include "catacharset.h" +#include "debug.h" +#include "field.h" +#include "game.h" +#include "input.h" +#include "item_category.h" +#include "item_search.h" +#include "item_stack.h" +#include "map.h" +#include "mapdata.h" +#include "messages.h" +#include "options.h" +#include "output.h" +#include "player.h" +#include "player_activity.h" +#include "string_formatter.h" +#include "string_input_popup.h" +#include "translations.h" +#include "trap.h" +#include "ui.h" +#include "uistate.h" +#include "vehicle.h" +#include "vehicle_selector.h" +#include "vpart_position.h" +#include "calendar.h" +#include "color.h" +#include "game_constants.h" +#include "int_id.h" +#include "inventory.h" +#include "item.h" +#include "optional.h" +#include "ret_val.h" +#include "type_id.h" +#include "clzones.h" +#include "colony.h" +#include "enums.h" +#include "faction.h" +#include "item_location.h" +#include "map_selector.h" +#include "pimpl.h" + +#if defined(__ANDROID__) +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum aim_exit { + exit_none = 0, + exit_okay, + exit_re_entry +}; + +// *INDENT-OFF* +comestible_inventory::comestible_inventory() + : head_height(5) + , min_w_height(10) + , min_w_width(FULL_SCREEN_WIDTH) + , max_w_width(120) + , inCategoryMode(false) + , recalc(true) + , redraw(true) + , filter_edit(false) + // panes don't need initialization, they are recalculated immediately + , squares({ + { + // hx hy x y z + { AIM_INVENTORY, 25, 2, {0, 0, 0}, _("Inventory"), _("IN") }, + { AIM_SOUTHWEST, 30, 3, { -1, 1, 0}, _("South West"), _("SW") }, + { AIM_SOUTH, 33, 3, {0, 1, 0}, _("South"), _("S") }, + { AIM_SOUTHEAST, 36, 3, {1, 1, 0}, _("South East"), _("SE") }, + { AIM_WEST, 30, 2, { -1, 0, 0}, _("West"), _("W") }, + { AIM_CENTER, 33, 2, {0, 0, 0}, _("Directly below you"), _("DN") }, + { AIM_EAST, 36, 2, {1, 0, 0}, _("East"), _("E") }, + { AIM_NORTHWEST, 30, 1, { -1, -1, 0}, _("North West"), _("NW") }, + { AIM_NORTH, 33, 1, {0, -1, 0}, _("North"), _("N") }, + { AIM_NORTHEAST, 36, 1, {1, -1, 0}, _("North East"), _("NE") }, + { AIM_DRAGGED, 25, 1, {0, 0, 0}, _("Grabbed Vehicle"), _("GR") }, + { AIM_ALL, 22, 3, {0, 0, 0}, _("Surrounding area"), _("AL") }, + { AIM_CONTAINER, 22, 1, {0, 0, 0}, _("Container"), _("CN") }, + { AIM_WORN, 25, 3, {0, 0, 0}, _("Worn Items"), _("WR") } + } + }) +{ + // initialize screen coordinates for small overview 3x3 grid, depending on control scheme + if (tile_iso && use_tiles) { + // Rotate the coordinates. + squares[1].hscreen.x = 33; + squares[2].hscreen.x = 36; + squares[3].hscreen.y = 2; + squares[4].hscreen.y = 3; + squares[6].hscreen.y = 1; + squares[7].hscreen.y = 2; + squares[8].hscreen.x = 30; + squares[9].hscreen.x = 33; + } +} +// *INDENT-ON* + +comestible_inventory::~comestible_inventory() +{ + save_settings( false ); + auto &aim_code = uistate.adv_inv_exit_code; + if( aim_code != exit_re_entry ) { + aim_code = exit_okay; + } + // Only refresh if we exited manually, otherwise we're going to be right back + if( exit ) { + werase( head ); + werase( minimap ); + werase( mm_border ); + werase( window ); + g->refresh_all(); + } +} + +void comestible_inventory::save_settings( bool only_panes ) +{ + //if (!only_panes) { + // uistate.adv_inv_last_coords = g->u.pos(); + // uistate.adv_inv_src = src; + // uistate.adv_inv_dest = dest; + //} + uistate.adv_inv_in_vehicle[0] = pane.in_vehicle(); + uistate.adv_inv_area[0] = pane.get_area(); + uistate.adv_inv_index[0] = pane.index; + uistate.adv_inv_filter[0] = pane.filter; +} + +//TODO: fix settings +void comestible_inventory::load_settings() +{ + aim_exit aim_code = static_cast( uistate.adv_inv_exit_code ); + aim_location location; + if( get_option( "OPEN_DEFAULT_ADV_INV" ) ) { + location = static_cast( uistate.adv_inv_default_areas[0] ); + } else { + location = static_cast( uistate.adv_inv_area[0] ); + } + auto square = squares[location]; + // determine the square's vehicle/map item presence + bool has_veh_items = square.can_store_in_vehicle() ? + !square.veh->get_items( square.vstor ).empty() : false; + bool has_map_items = !g->m.i_at( square.pos ).empty(); + // determine based on map items and settings to show cargo + bool show_vehicle = aim_code == exit_re_entry ? + uistate.adv_inv_in_vehicle[0] : has_veh_items ? true : + has_map_items ? false : square.can_store_in_vehicle(); + pane.set_area( square, show_vehicle ); + //pane.sortby = static_cast(uistate.adv_inv_sort[0]); + pane.index = uistate.adv_inv_index[0]; + pane.filter = uistate.adv_inv_filter[0]; + uistate.adv_inv_exit_code = exit_none; + + pane.filter_show_food = true; +} + +std::string comestible_inventory::get_sortname( comestible_inv_sortby sortby ) +{ + switch( sortby ) { + case COMESTIBLE_SORTBY_NAME: + return _( "name" ); + case COMESTIBLE_SORTBY_WEIGHT: + return _( "weight" ); + case COMESTIBLE_SORTBY_VOLUME: + return _( "volume" ); + case COMESTIBLE_SORTBY_CALORIES: + return _( "calories" ); + case COMESTIBLE_SORTBY_QUENCH: + return _( "quench" ); + case COMESTIBLE_SORTBY_JOY: + return _( "joy" ); + case COMESTIBLE_SORTBY_SPOILAGE: + return _( "spoilage" ); + } + return "!BUG!"; +} + +bool comestible_inventory::get_square( const std::string &action, aim_location &ret ) +{ + if( action == "ITEMS_INVENTORY" ) { + ret = AIM_INVENTORY; + } else if( action == "ITEMS_WORN" ) { + ret = AIM_WORN; + } else if( action == "ITEMS_NW" ) { + ret = screen_relative_location( AIM_NORTHWEST ); + } else if( action == "ITEMS_N" ) { + ret = screen_relative_location( AIM_NORTH ); + } else if( action == "ITEMS_NE" ) { + ret = screen_relative_location( AIM_NORTHEAST ); + } else if( action == "ITEMS_W" ) { + ret = screen_relative_location( AIM_WEST ); + } else if( action == "ITEMS_CE" ) { + ret = AIM_CENTER; + } else if( action == "ITEMS_E" ) { + ret = screen_relative_location( AIM_EAST ); + } else if( action == "ITEMS_SW" ) { + ret = screen_relative_location( AIM_SOUTHWEST ); + } else if( action == "ITEMS_S" ) { + ret = screen_relative_location( AIM_SOUTH ); + } else if( action == "ITEMS_SE" ) { + ret = screen_relative_location( AIM_SOUTHEAST ); + } else if( action == "ITEMS_AROUND" ) { + ret = AIM_ALL; + } else if( action == "ITEMS_DRAGGED_CONTAINER" ) { + ret = AIM_DRAGGED; + } else if( action == "ITEMS_CONTAINER" ) { + ret = AIM_CONTAINER; + } else { + return false; + } + return true; +} + +void comestible_inventory::print_items( comestible_inventory_pane &pane ) +{ + const auto &items = pane.items; + const catacurses::window &window = pane.window; + const auto index = pane.index; + const int page = index / itemsPerPage; + bool compact = TERMX <= 100; + + int max_width = getmaxx( window ); + std::string spaces( max_width - 4, ' ' ); + + nc_color norm = c_white; + + //print inventory's current and total weight + volume + if( pane.get_area() == AIM_INVENTORY || pane.get_area() == AIM_WORN ) { + const double weight_carried = convert_weight( g->u.weight_carried() ); + const double weight_capacity = convert_weight( g->u.weight_capacity() ); + std::string volume_carried = format_volume( g->u.volume_carried() ); + std::string volume_capacity = format_volume( g->u.volume_capacity() ); + // align right, so calculate formatted head length + const std::string formatted_head = string_format( "%.1f/%.1f %s %s/%s %s", + weight_carried, weight_capacity, weight_units(), + volume_carried, + volume_capacity, + volume_units_abbr() ); + //const int hrightcol = columns - 1 - formatted_head.length(); + //nc_color color = weight_carried > weight_capacity ? c_red : c_light_green; + //mvwprintz(window, 4, hrightcol, color, "%.1f", weight_carried); + wprintz( window, c_light_gray, "/%.1f %s ", weight_capacity, weight_units() ); + nc_color color = g->u.volume_carried().value() > g->u.volume_capacity().value() ? c_red : + c_light_green; + wprintz( window, color, volume_carried ); + wprintz( window, c_light_gray, "/%s %s", volume_capacity, volume_units_abbr() ); + } else { //print square's current and total weight + volume + std::string formatted_head; + if( pane.get_area() == AIM_ALL ) { + formatted_head = string_format( "%3.1f %s %s %s", + convert_weight( squares[pane.get_area()].weight ), + weight_units(), + format_volume( squares[pane.get_area()].volume ), + volume_units_abbr() ); + } else { + units::volume maxvolume = 0_ml; + auto &s = squares[pane.get_area()]; + if( pane.get_area() == AIM_CONTAINER && s.get_container( pane.in_vehicle() ) != nullptr ) { + maxvolume = s.get_container( pane.in_vehicle() )->get_container_capacity(); + } else if( pane.in_vehicle() ) { + maxvolume = s.veh->max_volume( s.vstor ); + } else { + maxvolume = g->m.max_volume( s.pos ); + } + formatted_head = string_format( "%3.1f %s %s/%s %s", + convert_weight( s.weight ), + weight_units(), + format_volume( s.volume ), + format_volume( maxvolume ), + volume_units_abbr() ); + } + mvwprintz( window, 4, max_width - 1 - formatted_head.length(), norm, formatted_head ); + } + + const size_t last_x = max_width - 2; + const size_t name_startpos = compact ? 1 : 4; + + const int num_columns = 8 + 1; //to add columns change this + const int col_size[num_columns] = { 0, + 4, 5, 7, 8, + 9, 7, 4, 12 + }; //to change column size change this + const int total_col_width = std::accumulate( col_size, col_size + num_columns, 0 ); + int cur_col = 0; + int cur_col_x = last_x - total_col_width; + + const size_t src_startpos = cur_col_x += col_size[cur_col++]; + const size_t amt_startpos = cur_col_x += col_size[cur_col++]; + const size_t weight_startpos = cur_col_x += col_size[cur_col++]; + const size_t vol_startpos = cur_col_x += col_size[cur_col++]; + + const size_t cal_startpos = cur_col_x += col_size[cur_col++]; + const size_t quench_startpos = cur_col_x += col_size[cur_col++]; + const size_t joy_startpos = cur_col_x += col_size[cur_col++]; + const size_t expires_startpos = cur_col_x += col_size[cur_col++]; + + int max_name_length = src_startpos - name_startpos - 1; // Default name length + + //~ Items list header. Table fields length without spaces: amt - 4, weight - 5, vol - 4. + const int table_hdr_len1 = utf8_width( _( "amt weight vol" ) ); // Header length type 1 + //~ Items list header. Table fields length without spaces: src - 2, amt - 4, weight - 5, vol - 4. + const int table_hdr_len2 = utf8_width( _( "src amt weight vol" ) ); // Header length type 2 + + mvwprintz( window, 5, compact ? 1 : 4, c_light_gray, _( "Name (charges)" ) ); + //if (pane.get_area() == AIM_ALL && !compact) { + // mvwprintz(window, 5, last_x - table_hdr_len2 + 1, c_light_gray, _("src amt weight vol")); + // max_name_length = src_startpos - name_startpos - 1; // 1 for space + //} + //else { + // mvwprintz(window, 5, last_x - table_hdr_len1 + 1, c_light_gray, _("amt weight vol")); + //} + + mvwprintz( window, 5, src_startpos, c_light_gray, _( "src" ) ); + mvwprintz( window, 5, amt_startpos + 1, c_light_gray, _( "amt" ) ); + mvwprintz( window, 5, weight_startpos, c_light_gray, _( "weight" ) ); + mvwprintz( window, 5, vol_startpos + 2, c_light_gray, _( "vol" ) ); + mvwprintz( window, 5, cal_startpos, c_light_gray, _( "calories" ) ); + mvwprintz( window, 5, quench_startpos, c_light_gray, _( "quench" ) ); + mvwprintz( window, 5, joy_startpos, c_light_gray, _( "joy" ) ); + mvwprintz( window, 5, expires_startpos, c_light_gray, _( "expires in" ) ); + + player &p = g->u; + + for( int i = page * itemsPerPage, x = 0; i < static_cast( items.size() ) && + x < itemsPerPage; i++, x++ ) { + const auto &sitem = items[i]; + if( sitem.is_category_header() ) { + mvwprintz( window, 6 + x, ( max_width - utf8_width( sitem.name ) - 6 ) / 2, c_cyan, "[%s]", + sitem.name ); + continue; + } + if( !sitem.is_item_entry() ) { + // Empty entry at the bottom of a page. + continue; + } + + const auto &it = p.get_consumable_from( *sitem.items.front() ); + + const bool selected = index == i; + + nc_color thiscolor = it.color_in_inventory(); + nc_color thiscolordark = c_dark_gray; + nc_color print_color; + + if( selected ) { + thiscolor = inCategoryMode && pane.sortby == SORTBY_CATEGORY ? c_white_red : hilite( c_white ); + thiscolordark = hilite( thiscolordark ); + if( compact ) { + mvwprintz( window, 6 + x, 1, thiscolor, " %s", spaces ); + } else { + mvwprintz( window, 6 + x, 1, thiscolor, ">>%s", spaces ); + } + } + + std::string item_name; + std::string stolen_string; + bool stolen = false; + if( it.has_owner() ) { + const faction *item_fac = it.get_owner(); + if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { + stolen_string = string_format( "!" ); + stolen = true; + } + } + if( it.is_money() ) { + //Count charges + // TODO: transition to the item_location system used for the normal inventory + unsigned int charges_total = 0; + for( const auto item : sitem.items ) { + charges_total += item->charges; + } + if( stolen ) { + item_name = string_format( "%s %s", stolen_string, it.display_money( sitem.items.size(), + charges_total ) ); + } else { + item_name = it.display_money( sitem.items.size(), charges_total ); + } + } else { + if( stolen ) { + item_name = string_format( "%s %s", stolen_string, it.display_name() ); + } else { + //item_name = it.display_name(); + item_name = sitem.items.front()->display_name(); + } + } + if( get_option( "ITEM_SYMBOLS" ) ) { + item_name = string_format( "%s %s", it.symbol(), item_name ); + } + + //print item name + trim_and_print( window, 6 + x, compact ? 1 : 4, max_name_length, thiscolor, item_name ); + + //print src column + // TODO: specify this is coming from a vehicle! + if( pane.get_area() == AIM_ALL && !compact ) { + mvwprintz( window, 6 + x, src_startpos, thiscolor, squares[sitem.area].shortname ); + } + + //print "amount" column + int it_amt = sitem.stacks; + if( it_amt > 1 ) { + print_color = thiscolor; + if( it_amt > 9999 ) { + it_amt = 9999; + print_color = selected ? hilite( c_red ) : c_red; + } + mvwprintz( window, 6 + x, amt_startpos, print_color, "%4d", it_amt ); + } + + //print weight column + double it_weight = convert_weight( sitem.weight ); + size_t w_precision; + print_color = it_weight > 0 ? thiscolor : thiscolordark; + + if( it_weight >= 1000.0 ) { + if( it_weight >= 10000.0 ) { + print_color = selected ? hilite( c_red ) : c_red; + it_weight = 9999.0; + } + w_precision = 0; + } else if( it_weight >= 100.0 ) { + w_precision = 1; + } else { + w_precision = 2; + } + mvwprintz( window, 6 + x, weight_startpos, print_color, "%5.*f", w_precision, it_weight ); + + //print volume column + bool it_vol_truncated = false; + double it_vol_value = 0.0; + std::string it_vol = format_volume( sitem.volume, 5, &it_vol_truncated, &it_vol_value ); + if( it_vol_truncated && it_vol_value > 0.0 ) { + print_color = selected ? hilite( c_red ) : c_red; + } else { + print_color = sitem.volume.value() > 0 ? thiscolor : thiscolordark; + } + mvwprintz( window, 6 + x, vol_startpos, print_color, it_vol ); + + if( sitem.autopickup ) { + mvwprintz( window, 6 + x, 1, magenta_background( it.color_in_inventory() ), + compact ? it.tname().substr( 0, 1 ) : ">" ); + } + //get_consumable_item + char *string_format = ""; + islot_comestible it_c = get_edible_comestible( p, it ); // .type->comestible; + + //print "CALORIES" column + int it_cal = p.kcal_for( it ); + string_format = set_string_params( print_color, it_cal, selected ); + mvwprintz( window, 6 + x, cal_startpos, print_color, string_format, it_cal ); + + //print "QUENCH" column + int it_q = it_c.quench; + string_format = set_string_params( print_color, it_q, selected ); + mvwprintz( window, 6 + x, quench_startpos, print_color, string_format, it_q ); + + //print "JOY" column + int it_joy = p.fun_for( it ).first; + string_format = set_string_params( print_color, it_joy, selected, it.has_flag( "MUSHY" ) ); + mvwprintz( window, 6 + x, joy_startpos, print_color, string_format, it_joy ); + + //TODO: g->u.can_estimate_rot() + //print "SPOILS IN" column + std::string it_spoils_string; + if( it_c.spoils > 0_turns ) { + if( !it.rotten() ) { + it_spoils_string = get_time_left_rounded( p, it ); + } + } + print_color = selected ? hilite( c_white ) : c_cyan; + mvwprintz( window, 6 + x, expires_startpos, print_color, "%s", it_spoils_string ); + + /* + append_cell( [ this, &p ]( const item_location & loc ) { + std::string cbm_name; + + switch( p.get_cbm_rechargeable_with( get_consumable_item( loc ) ) ) { + case rechargeable_cbm::none: + break; + case rechargeable_cbm::battery: + cbm_name = _( "Battery" ); + break; + case rechargeable_cbm::reactor: + cbm_name = _( "Reactor" ); + break; + case rechargeable_cbm::furnace: + cbm_name = _( "Furnace" ); + break; + } + + if( !cbm_name.empty() ) { + return string_format( "%s", cbm_name ); + } + + return std::string(); + }, _( "CBM" ) ); + + append_cell( [ this, &p ]( const item_location & loc ) { + return good_bad_none( p.get_acquirable_energy( get_consumable_item( loc ) ) ); + }, _( "ENERGY" ) ); + + */ + } +} + +struct comestible_inv_sorter { + int counter; + comestible_inv_sortby sortby; + comestible_inv_sorter( comestible_inv_sortby sort ) { + sortby = sort; + counter = 0; + } + bool operator()( const comestible_inv_listitem &d1, const comestible_inv_listitem &d2 ) { + if( d1.is_category_header() ) { + return true; + } else if( d2.is_category_header() ) { + return false; + } + + /* + this code will put 'hot' items to the top of the list + problem is heating from inventory will remove it from aiming spot... decide if this is needed + item* it1 = d1.items.front(); + item* it2 = d2.items.front(); + + bool is_it1_hot = (it1->has_flag("HOT") || + (it1->contents.size() > 0 && it1->contents.front().has_flag("HOT"))); + bool is_it2_hot = (it2->has_flag("HOT") || + (it2->contents.size() > 0 && it2->contents.front().has_flag("HOT"))); + if (is_it1_hot != is_it2_hot) { + return is_it1_hot; + } + */ + + switch( sortby ) { + case COMESTIBLE_SORTBY_NAME: + const std::string *n1; + const std::string *n2; + if( d1.name_without_prefix == d2.name_without_prefix ) { + if( d1.name == d2.name ) { + //fall through + break; + } else { + //if names without prefix equal, compare full name + n1 = &d1.name; + n2 = &d2.name; + } + } else { + //else compare name without prefix + n1 = &d1.name_without_prefix; + n2 = &d2.name_without_prefix; + } + + return std::lexicographical_compare( n1->begin(), n1->end(), n2->begin(), n2->end(), + sort_case_insensitive_less() ); + break; + case COMESTIBLE_SORTBY_WEIGHT: + if( d1.weight != d2.weight ) { + return d1.weight > d2.weight; + } + break; + case COMESTIBLE_SORTBY_VOLUME: + if( d1.volume != d2.volume ) { + return d1.volume > d2.volume; + } + break; + case COMESTIBLE_SORTBY_CALORIES: + if( d1.calories != d2.calories ) { + return d1.calories > d2.calories; + } + break; + case COMESTIBLE_SORTBY_QUENCH: + if( d1.quench != d2.quench ) { + return d1.quench > d2.quench; + } + break; + case COMESTIBLE_SORTBY_JOY: + if( d1.joy != d2.joy ) { + return d1.joy > d2.joy; + } + break; + case COMESTIBLE_SORTBY_SPOILAGE: + + break; + } + // secondary sort by SPOILAGE + return d1.items.front()->spoilage_sort_order() < d2.items.front()->spoilage_sort_order(); + } +}; + +void comestible_inventory::menu_square( uilist &menu ) +{ + assert( menu.entries.size() >= 9 ); + int ofs = -25 - 4; + int sel = screen_relative_location( static_cast ( menu.selected + 1 ) ); + for( int i = 1; i < 10; i++ ) { + aim_location loc = screen_relative_location( static_cast ( i ) ); + char key = get_location_key( loc ); + bool in_vehicle = squares[loc].can_store_in_vehicle(); + const char *bracket = in_vehicle ? "<>" : "[]"; + // always show storage option for vehicle storage, if applicable + bool canputitems = menu.entries[i - 1].enabled && squares[loc].canputitems(); + nc_color bcolor = canputitems ? sel == loc ? h_white : c_light_gray : c_dark_gray; + nc_color kcolor = canputitems ? sel == loc ? h_white : c_light_gray : c_dark_gray; + const int x = squares[loc].hscreen.x + ofs; + const int y = squares[loc].hscreen.y + 5; + mvwprintz( menu.window, y, x, bcolor, "%c", bracket[0] ); + wprintz( menu.window, kcolor, "%c", key ); + wprintz( menu.window, bcolor, "%c", bracket[1] ); + } +} + +inline char comestible_inventory::get_location_key( aim_location area ) +{ + switch( area ) { + case AIM_INVENTORY: + return 'I'; + case AIM_WORN: + return 'W'; + case AIM_CENTER: + return '5'; + case AIM_ALL: + return 'A'; + case AIM_DRAGGED: + return 'D'; + case AIM_CONTAINER: + return 'C'; + case AIM_NORTH: + case AIM_SOUTH: + case AIM_EAST: + case AIM_WEST: + case AIM_NORTHEAST: + case AIM_NORTHWEST: + case AIM_SOUTHEAST: + case AIM_SOUTHWEST: + return get_direction_key( area ); + default: + debugmsg( "invalid [aim_location] in get_location_key()!" ); + return ' '; + } +} + +char comestible_inventory::get_direction_key( aim_location area ) +{ + + if( area == screen_relative_location( AIM_SOUTHWEST ) ) { + return '1'; + } + if( area == screen_relative_location( AIM_SOUTH ) ) { + return '2'; + } + if( area == screen_relative_location( AIM_SOUTHEAST ) ) { + return '3'; + } + if( area == screen_relative_location( AIM_WEST ) ) { + return '4'; + } + if( area == screen_relative_location( AIM_EAST ) ) { + return '6'; + } + if( area == screen_relative_location( AIM_NORTHWEST ) ) { + return '7'; + } + if( area == screen_relative_location( AIM_NORTH ) ) { + return '8'; + } + if( area == screen_relative_location( AIM_NORTHEAST ) ) { + return '9'; + } + debugmsg( "invalid [aim_location] in get_direction_key()!" ); + return '0'; +} + +int comestible_inventory::print_header( comestible_inventory_pane &pane, aim_location sel ) +{ + const catacurses::window &window = pane.window; + int area = pane.get_area(); + int wwidth = getmaxx( window ); + int ofs = wwidth - 25 - 2 - 14; + for( int i = 0; i < NUM_AIM_LOCATIONS; ++i ) { + const char key = get_location_key( static_cast( i ) ); + const char *bracket = squares[i].can_store_in_vehicle() ? "<>" : "[]"; + bool in_vehicle = pane.in_vehicle() && squares[i].id == area && sel == area && area != AIM_ALL; + bool all_brackets = area == AIM_ALL && ( i >= AIM_SOUTHWEST && i <= AIM_NORTHEAST ); + nc_color bcolor = c_red; + nc_color kcolor = c_red; + if( squares[i].canputitems( pane.get_cur_item_ptr() ) ) { + bcolor = in_vehicle ? c_light_blue : + area == i || all_brackets ? c_light_gray : c_dark_gray; + kcolor = area == i ? c_white : sel == i ? c_light_gray : c_dark_gray; + } + const int x = squares[i].hscreen.x + ofs; + const int y = squares[i].hscreen.y; + mvwprintz( window, y, x, bcolor, "%c", bracket[0] ); + wprintz( window, kcolor, "%c", in_vehicle && sel != AIM_DRAGGED ? 'V' : key ); + wprintz( window, bcolor, "%c", bracket[1] ); + } + return squares[AIM_INVENTORY].hscreen.y + ofs; +} + +int comestible_inv_area::get_item_count() const +{ + if( id == AIM_INVENTORY ) { + return g->u.inv.size(); + } else if( id == AIM_WORN ) { + return g->u.worn.size(); + } else if( id == AIM_ALL ) { + return 0; + } else if( id == AIM_DRAGGED ) { + return can_store_in_vehicle() ? veh->get_items( vstor ).size() : 0; + } else { + return g->m.i_at( pos ).size(); + } +} + +void comestible_inv_area::init() +{ + pos = g->u.pos() + off; + veh = nullptr; + vstor = -1; + volume = 0_ml; // must update in main function + weight = 0_gram; // must update in main function + switch( id ) { + case AIM_INVENTORY: + case AIM_WORN: + canputitemsloc = true; + break; + case AIM_DRAGGED: + if( g->u.get_grab_type() != OBJECT_VEHICLE ) { + canputitemsloc = false; + desc[0] = _( "Not dragging any vehicle!" ); + break; + } + // offset for dragged vehicles is not statically initialized, so get it + off = g->u.grab_point; + // Reset position because offset changed + pos = g->u.pos() + off; + if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", + false ) ) { + veh = &vp->vehicle(); + vstor = vp->part_index(); + } else { + veh = nullptr; + vstor = -1; + } + if( vstor >= 0 ) { + desc[0] = veh->name; + canputitemsloc = true; + max_size = MAX_ITEM_IN_VEHICLE_STORAGE; + } else { + veh = nullptr; + canputitemsloc = false; + desc[0] = _( "No dragged vehicle!" ); + } + break; + case AIM_CONTAINER: + // set container position based on location + set_container_position(); + // location always valid, actual check is done in canputitems() + // and depends on selected item in pane (if it is valid container) + canputitemsloc = true; + if( get_container() == nullptr ) { + desc[0] = _( "Invalid container!" ); + } + break; + case AIM_ALL: + desc[0] = _( "All 9 squares" ); + canputitemsloc = true; + break; + case AIM_SOUTHWEST: + case AIM_SOUTH: + case AIM_SOUTHEAST: + case AIM_WEST: + case AIM_CENTER: + case AIM_EAST: + case AIM_NORTHWEST: + case AIM_NORTH: + case AIM_NORTHEAST: + if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", + false ) ) { + veh = &vp->vehicle(); + vstor = vp->part_index(); + } else { + veh = nullptr; + vstor = -1; + } + canputitemsloc = can_store_in_vehicle() || g->m.can_put_items_ter_furn( pos ); + max_size = MAX_ITEM_IN_SQUARE; + if( can_store_in_vehicle() ) { + desc[1] = vpart_position( *veh, vstor ).get_label().value_or( "" ); + } + // get graffiti or terrain name + desc[0] = g->m.has_graffiti_at( pos ) ? + g->m.graffiti_at( pos ) : g->m.name( pos ); + default: + break; + } + + /* assemble a list of interesting traits of the target square */ + // fields? with a special case for fire + bool danger_field = false; + const field &tmpfld = g->m.field_at( pos ); + for( auto &fld : tmpfld ) { + const field_entry &cur = fld.second; + if( fld.first.obj().has_fire ) { + flags.append( _( " FIRE" ) ); + } else { + if( cur.is_dangerous() ) { + danger_field = true; + } + } + } + if( danger_field ) { + flags.append( _( " DANGER" ) ); + } + + // trap? + const trap &tr = g->m.tr_at( pos ); + if( tr.can_see( pos, g->u ) && !tr.is_benign() ) { + flags.append( _( " TRAP" ) ); + } + + // water? + static const std::array ter_water = { + {t_water_dp, t_water_pool, t_swater_dp, t_water_sh, t_swater_sh, t_sewage, t_water_moving_dp, t_water_moving_sh } + }; + auto ter_check = [this] + ( const ter_id & id ) { + return g->m.ter( this->pos ) == id; + }; + if( std::any_of( ter_water.begin(), ter_water.end(), ter_check ) ) { + flags.append( _( " WATER" ) ); + } + + // remove leading space + if( flags.length() && flags[0] == ' ' ) { + flags.erase( 0, 1 ); + } +} + +void comestible_inventory::init() +{ + for( auto &square : squares ) { + square.init(); + } + + load_settings(); + + w_height = TERMY < min_w_height + head_height ? min_w_height : TERMY - head_height; + w_width = TERMX < min_w_width ? min_w_width : TERMX > max_w_width ? max_w_width : + static_cast( TERMX ); + + headstart = 0; //(TERMY>w_height)?(TERMY-w_height)/2:0; + colstart = TERMX > w_width ? ( TERMX - w_width ) / 2 : 0; + + head = catacurses::newwin( head_height, w_width - minimap_width, headstart, colstart ); + mm_border = catacurses::newwin( minimap_height + 2, minimap_width + 2, headstart, + colstart + ( w_width - ( minimap_width + 2 ) ) ); + minimap = catacurses::newwin( minimap_height, minimap_width, headstart + 1, + colstart + ( w_width - ( minimap_width + 1 ) ) ); + window = catacurses::newwin( w_height, w_width, headstart + head_height, colstart ); + + itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff + + pane.window = window; +} + +comestible_inv_listitem::comestible_inv_listitem( item *an_item, int index, int count, + aim_location area, bool from_vehicle ) + : idx( index ) + , area( area ) + , id( an_item->typeId() ) + , name( an_item->tname( count ) ) + , name_without_prefix( an_item->tname( 1, false ) ) + , autopickup( get_auto_pickup().has_rule( an_item ) ) + , stacks( count ) + , volume( an_item->volume() * stacks ) + , weight( an_item->weight() * stacks ) + , cat( &an_item->get_category() ) + , from_vehicle( from_vehicle ) +{ + player &p = g->u; + item it = p.get_consumable_from( *an_item ); + islot_comestible it_c = get_edible_comestible( p, it ); + calories = p.kcal_for( it ); + quench = it_c.quench; + joy = p.fun_for( it ).first; + + items.push_back( an_item ); + assert( stacks >= 1 ); +} + +comestible_inv_listitem::comestible_inv_listitem( const std::list &list, int index, + aim_location area, bool from_vehicle ) : + idx( index ), + area( area ), + id( list.front()->typeId() ), + items( list ), + name( list.front()->tname( list.size() ) ), + name_without_prefix( list.front()->tname( 1, false ) ), + autopickup( get_auto_pickup().has_rule( list.front() ) ), + stacks( list.size() ), + volume( list.front()->volume() * stacks ), + weight( list.front()->weight() * stacks ), + cat( &list.front()->get_category() ), + from_vehicle( from_vehicle ) +{ + player &p = g->u; + item it = p.get_consumable_from( *list.front() ); + islot_comestible it_c = get_edible_comestible( p, it ); + calories = p.kcal_for( it ); + quench = it_c.quench; + joy = p.fun_for( it ).first; + assert( stacks >= 1 ); +} + +comestible_inv_listitem::comestible_inv_listitem() + : idx() + , area() + , id( "null" ) + , autopickup() + , stacks() + , cat( nullptr ) +{ +} + +comestible_inv_listitem::comestible_inv_listitem( const item_category *cat ) + : idx() + , area() + , id( "null" ) + , name( cat->name() ) + , autopickup() + , stacks() + , cat( cat ) +{ +} + +comestible_inv_listitem::comestible_inv_listitem( const std::string cat_name ) + : idx() + , area() + , id( "null" ) + , name( cat_name ) + , autopickup() + , stacks() + , cat( cat ) +{ +} + +bool comestible_inv_listitem::is_category_header() const +{ + return items.empty() && cat != nullptr; +} + +bool comestible_inv_listitem::is_item_entry() const +{ + return !items.empty(); +} + +const islot_comestible &comestible_inv_listitem::get_edible_comestible( player &p, + const item &it ) const +{ + if( it.is_comestible() && p.can_eat( it ).success() ) { + // Ok since can_eat() returns false if is_craft() is true + return *it.type->comestible; + } + static const islot_comestible dummy{}; + return dummy; +} + +bool comestible_inventory_pane::is_filtered( const comestible_inv_listitem &it ) const +{ + return is_filtered( *it.items.front() ); +} + +bool comestible_inventory_pane::is_filtered( const item &it ) const +{ + const std::string n = it.get_category().name(); + if( filter_show_food && n != "FOOD" ) { + return true; + } + if( !filter_show_food && n != "DRUGS" ) { + return true; + } + + player &p = g->u; + if( !p.can_consume( it ) ) { + return true; + } + + const std::string str = it.tname(); + if( filtercache.find( str ) == filtercache.end() ) { + const auto filter_fn = item_filter_from_string( filter ); + filtercache[str] = filter_fn; + + return !filter_fn( it ); + } + + return !filtercache[str]( it ); +} + +// roll our own, to handle moving stacks better +using itemstack = std::vector >; + +template +static itemstack i_stacked( T items ) +{ + //create a new container for our stacked items + itemstack stacks; + // // make a list of the items first, so we can add non stacked items back on + // std::list items(things.begin(), things.end()); + // used to recall indices we stored `itype_id' item at in itemstack + std::unordered_map> cache; + // iterate through and create stacks + for( auto &elem : items ) { + const auto id = elem.typeId(); + auto iter = cache.find( id ); + bool got_stacked = false; + // cache entry exists + if( iter != cache.end() ) { + // check to see if it stacks with each item in a stack, not just front() + for( auto &idx : iter->second ) { + for( auto &it : stacks[idx] ) { + if( ( got_stacked = it->display_stacked_with( elem ) ) ) { + stacks[idx].push_back( &elem ); + break; + } + } + if( got_stacked ) { + break; + } + } + } + if( !got_stacked ) { + cache[id].insert( stacks.size() ); + stacks.push_back( { &elem } ); + } + } + return stacks; +} + +void comestible_inventory_pane::add_items_from_area( comestible_inv_area &square, + bool vehicle_override ) +{ + assert( square.id != AIM_ALL ); + square.volume = 0_ml; + square.weight = 0_gram; + if( !square.canputitems() ) { + return; + } + map &m = g->m; + player &u = g->u; + // Existing items are *not* cleared on purpose, this might be called + // several times in case all surrounding squares are to be shown. + if( square.id == AIM_INVENTORY ) { + const invslice &stacks = u.inv.slice(); + for( size_t x = 0; x < stacks.size(); ++x ) { + std::list item_pointers; + for( item &i : *stacks[x] ) { + item_pointers.push_back( &i ); + } + comestible_inv_listitem it( item_pointers, x, square.id, false ); + if( is_filtered( *it.items.front() ) ) { + continue; + } + square.volume += it.volume; + square.weight += it.weight; + items.push_back( it ); + } + } else if( square.id == AIM_WORN ) { + auto iter = u.worn.begin(); + for( size_t i = 0; i < u.worn.size(); ++i, ++iter ) { + comestible_inv_listitem it( &*iter, i, 1, square.id, false ); + if( is_filtered( *it.items.front() ) ) { + continue; + } + square.volume += it.volume; + square.weight += it.weight; + items.push_back( it ); + } + } else if( square.id == AIM_CONTAINER ) { + item *cont = square.get_container( in_vehicle() ); + if( cont != nullptr ) { + if( !cont->is_container_empty() ) { + // filtering does not make sense for liquid in container + item *it = &square.get_container( in_vehicle() )->contents.front(); + comestible_inv_listitem ait( it, 0, 1, square.id, in_vehicle() ); + square.volume += ait.volume; + square.weight += ait.weight; + items.push_back( ait ); + } + square.desc[0] = cont->tname( 1, false ); + } + } else { + bool is_in_vehicle = square.can_store_in_vehicle() && ( in_vehicle() || vehicle_override ); + const itemstack &stacks = is_in_vehicle ? + i_stacked( square.veh->get_items( square.vstor ) ) : + i_stacked( m.i_at( square.pos ) ); + + for( size_t x = 0; x < stacks.size(); ++x ) { + comestible_inv_listitem it( stacks[x], x, square.id, is_in_vehicle ); + if( is_filtered( *it.items.front() ) ) { + continue; + } + square.volume += it.volume; + square.weight += it.weight; + items.push_back( it ); + } + } +} + +void comestible_inventory_pane::paginate( size_t itemsPerPage ) +{ + if( sortby != SORTBY_CATEGORY ) { + return; // not needed as there are no category entries here. + } + // first, we insert all the items, then we sort the result + for( size_t i = 0; i < items.size(); ++i ) { + if( i % itemsPerPage == 0 ) { + // first entry on the page, should be a category header + if( items[i].is_item_entry() ) { + items.insert( items.begin() + i, comestible_inv_listitem( items[i].cat ) ); + } + } + if( ( i + 1 ) % itemsPerPage == 0 && i + 1 < items.size() ) { + // last entry of the page, but not the last entry at all! + // Must *not* be a category header! + if( items[i].is_category_header() ) { + items.insert( items.begin() + i, comestible_inv_listitem() ); + } + } + } +} + +void comestible_inventory::recalc_pane() +{ + pane.recalc = false; + pane.items.clear(); + // Add items from the source location or in case of all 9 surrounding squares, + // add items from several locations. + if( pane.get_area() == AIM_ALL ) { + auto &alls = squares[AIM_ALL]; + auto &there = pane;// s[-p + 1]; + auto &other = squares[there.get_area()]; + alls.volume = 0_ml; + alls.weight = 0_gram; + for( auto &s : squares ) { + // All the surrounding squares, nothing else + if( s.id < AIM_SOUTHWEST || s.id > AIM_NORTHEAST ) { + continue; + } + + // To allow the user to transfer all items from all surrounding squares to + // a specific square, filter out items that are already on that square. + // e.g. left pane AIM_ALL, right pane AIM_NORTH. The user holds the + // enter key down in the left square and moves all items to the other side. + const bool same = other.is_same( s ); + + // Deal with squares with ground + vehicle storage + // Also handle the case when the other tile covers vehicle + // or the ground below the vehicle. + if( s.can_store_in_vehicle() && !( same && there.in_vehicle() ) ) { + bool do_vehicle = there.get_area() == s.id ? !there.in_vehicle() : true; + pane.add_items_from_area( s, do_vehicle ); + alls.volume += s.volume; + alls.weight += s.weight; + } + + // Add map items + if( !same || there.in_vehicle() ) { + pane.add_items_from_area( s ); + alls.volume += s.volume; + alls.weight += s.weight; + } + } + } else { + pane.add_items_from_area( squares[pane.get_area()] ); + } + + //TODO: just put it as a part of the header instead of one of the items + // Insert category headers + if( pane.filter_show_food ) { + pane.items.push_back( comestible_inv_listitem( "FOOD" ) ); + } else { + pane.items.push_back( comestible_inv_listitem( "CHEMICALS" ) ); + } + + // Insert category headers (only expected when sorting by category) + //if (pane.sortby == COMESTIBLE_SORTBY_CATEGORY) { + // + // std::set categories; + // for (auto& it : pane.items) { + // categories.insert(it.cat); + // } + // for (auto& cat : categories) { + // pane.items.push_back(comestible_inv_listitem(cat)); + // } + //} + + // Finally sort all items (category headers will now be moved to their proper position) + std::stable_sort( pane.items.begin(), pane.items.end(), comestible_inv_sorter( pane.sortby ) ); + pane.paginate( itemsPerPage ); +} + +void comestible_inventory_pane::fix_index() +{ + if( items.empty() ) { + index = 0; + return; + } + if( index < 0 ) { + index = 0; + } else if( static_cast( index ) >= items.size() ) { + index = static_cast( items.size() ) - 1; + } + skip_category_headers( +1 ); +} + +void comestible_inventory::redraw_pane() +{ + // don't update ui if processing demands + if( is_processing() ) { + return; + } + if( recalc || pane.recalc ) { + recalc_pane(); + } else if( !( redraw || pane.redraw ) ) { + return; + } + pane.redraw = false; + pane.fix_index(); + + const comestible_inv_area &square = squares[pane.get_area()]; + auto w = pane.window; + + werase( w ); + print_items( pane ); + + auto itm = pane.get_cur_item_ptr(); + int width = print_header( pane, itm != nullptr ? itm->area : pane.get_area() ); + bool same_as_dragged = ( square.id >= AIM_SOUTHWEST && square.id <= AIM_NORTHEAST ) && + // only cardinals + square.id != AIM_CENTER && pane.in_vehicle() && // not where you stand, and pane is in vehicle + square.off == squares[AIM_DRAGGED].off; // make sure the offsets are the same as the grab point + const comestible_inv_area &sq = same_as_dragged ? squares[AIM_DRAGGED] : square; + bool car = square.can_store_in_vehicle() && pane.in_vehicle() && sq.id != AIM_DRAGGED; + auto name = utf8_truncate( car ? sq.veh->name : sq.name, width ); + auto desc = utf8_truncate( sq.desc[car], width ); + width -= 2 + 1; // starts at offset 2, plus space between the header and the text + mvwprintz( w, 1, 2, c_green, name ); + mvwprintz( w, 2, 2, c_light_blue, desc ); + trim_and_print( w, 3, 2, width, c_cyan, square.flags ); + + const int max_page = ( pane.items.size() + itemsPerPage - 1 ) / itemsPerPage; + if( max_page > 1 ) { + const int page = pane.index / itemsPerPage; + mvwprintz( w, 4, 2, c_light_blue, _( "[<] page %d of %d [>]" ), page + 1, max_page ); + } + + wattron( w, c_cyan ); + // draw a darker border around the inactive pane + draw_border( w, BORDER_COLOR ); + mvwprintw( w, 0, 3, _( "< [s]ort: %s >" ), get_sortname( pane.sortby ) ); + int max = square.max_size; + if( max > 0 ) { + int itemcount = square.get_item_count(); + int fmtw = 7 + ( itemcount > 99 ? 3 : itemcount > 9 ? 2 : 1 ) + + ( max > 99 ? 3 : max > 9 ? 2 : 1 ); + mvwprintw( w, 0, w_width / 2 - fmtw, "< %d/%d >", itemcount, max ); + } + + const char *fprefix = _( "[F]ilter" ); + const char *fsuffix = _( "[R]eset" ); + if( !filter_edit ) { + if( !pane.filter.empty() ) { + mvwprintw( w, getmaxy( w ) - 1, 2, "< %s: %s >", fprefix, pane.filter ); + } else { + mvwprintw( w, getmaxy( w ) - 1, 2, "< %s >", fprefix ); + } + } + + wattroff( w, c_white ); + + if( !filter_edit && !pane.filter.empty() ) { + mvwprintz( w, getmaxy( w ) - 1, 6 + std::strlen( fprefix ), c_white, + pane.filter ); + mvwprintz( w, getmaxy( w ) - 1, + getmaxx( w ) - std::strlen( fsuffix ) - 2, c_white, "%s", fsuffix ); + } + wrefresh( w ); +} + +// be explicit with the values +enum aim_entry { + ENTRY_START = 0, + ENTRY_VEHICLE = 1, + ENTRY_MAP = 2, + ENTRY_RESET = 3 +}; + +bool comestible_inventory::show_sort_menu( comestible_inventory_pane &pane ) +{ + uilist sm; + sm.text = _( "Sort by... " ); + sm.addentry( COMESTIBLE_SORTBY_NAME, true, 'n', get_sortname( COMESTIBLE_SORTBY_NAME ) ); + sm.addentry( COMESTIBLE_SORTBY_WEIGHT, true, 'w', get_sortname( COMESTIBLE_SORTBY_WEIGHT ) ); + sm.addentry( COMESTIBLE_SORTBY_VOLUME, true, 'v', get_sortname( COMESTIBLE_SORTBY_VOLUME ) ); + sm.addentry( COMESTIBLE_SORTBY_CALORIES, true, 'c', get_sortname( COMESTIBLE_SORTBY_CALORIES ) ); + sm.addentry( COMESTIBLE_SORTBY_QUENCH, true, 'q', get_sortname( COMESTIBLE_SORTBY_QUENCH ) ); + sm.addentry( COMESTIBLE_SORTBY_JOY, true, 'j', get_sortname( COMESTIBLE_SORTBY_JOY ) ); + sm.addentry( COMESTIBLE_SORTBY_SPOILAGE, true, 's', get_sortname( COMESTIBLE_SORTBY_SPOILAGE ) ); + // Pre-select current sort. + sm.selected = pane.sortby; + // Calculate key and window variables, generate window, + // and loop until we get a valid answer. + sm.query(); + + if( sm.ret < 0 ) { + return false; + } + pane.sortby = static_cast( sm.ret ); + return true; +} + +static tripoint aim_vector( aim_location id ) +{ + switch( id ) { + case AIM_SOUTHWEST: + return tripoint( -1, 1, 0 ); + case AIM_SOUTH: + return tripoint( 0, 1, 0 ); + case AIM_SOUTHEAST: + return tripoint( 1, 1, 0 ); + case AIM_WEST: + return tripoint( -1, 0, 0 ); + case AIM_EAST: + return tripoint( 1, 0, 0 ); + case AIM_NORTHWEST: + return tripoint( -1, -1, 0 ); + case AIM_NORTH: + return tripoint( 0, -1, 0 ); + case AIM_NORTHEAST: + return tripoint( 1, -1, 0 ); + default: + return tripoint_zero; + } +} + +void comestible_inventory::display() +{ + init(); + + g->u.inv.restack( g->u ); + + input_context ctxt( "COMESTIBLE_INVENTORY" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "UP" ); + ctxt.register_action( "DOWN" ); + ctxt.register_action( "PAGE_DOWN" ); + ctxt.register_action( "PAGE_UP" ); + ctxt.register_action( "TOGGLE_VEH" ); + ctxt.register_action( "FILTER" ); + ctxt.register_action( "RESET_FILTER" ); + ctxt.register_action( "EXAMINE" ); + ctxt.register_action( "SORT" ); + ctxt.register_action( "TOGGLE_AUTO_PICKUP" ); + ctxt.register_action( "TOGGLE_FAVORITE" ); + ctxt.register_action( "MOVE_SINGLE_ITEM" ); + ctxt.register_action( "MOVE_VARIABLE_ITEM" ); + ctxt.register_action( "MOVE_ITEM_STACK" ); + ctxt.register_action( "CATEGORY_SELECTION" ); + ctxt.register_action( "ITEMS_NW" ); + ctxt.register_action( "ITEMS_N" ); + ctxt.register_action( "ITEMS_NE" ); + ctxt.register_action( "ITEMS_W" ); + ctxt.register_action( "ITEMS_CE" ); + ctxt.register_action( "ITEMS_E" ); + ctxt.register_action( "ITEMS_SW" ); + ctxt.register_action( "ITEMS_S" ); + ctxt.register_action( "ITEMS_SE" ); + ctxt.register_action( "ITEMS_INVENTORY" ); + ctxt.register_action( "ITEMS_WORN" ); + ctxt.register_action( "ITEMS_AROUND" ); + ctxt.register_action( "ITEMS_DRAGGED_CONTAINER" ); + ctxt.register_action( "ITEMS_CONTAINER" ); + + ctxt.register_action( "ITEMS_DEFAULT" ); + ctxt.register_action( "SAVE_DEFAULT" ); + + ctxt.register_action( "SWITCH_FOOD" ); + ctxt.register_action( "HEAT_UP" ); + + exit = false; + recalc = true; + redraw = true; + + while( !exit ) { + if( g->u.moves < 0 ) { + do_return_entry(); + return; + } + + redraw_pane(); + + if( redraw && !is_processing() ) { + werase( head ); + werase( minimap ); + werase( mm_border ); + draw_border( head ); + Messages::display_messages( head, 2, 1, w_width - 1, head_height - 2 ); + draw_minimap(); + const std::string msg = _( "< [?] show help >" ); + mvwprintz( head, 0, + w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, + c_white, msg ); + if( g->u.has_watch() ) { + const std::string time = to_string_time_of_day( calendar::turn ); + mvwprintz( head, 0, 2, c_white, time ); + } + wrefresh( head ); + refresh_minimap(); + } + redraw = false; + recalc = false; + + // current item in source pane, might be null + comestible_inv_listitem *sitem = pane.get_cur_item_ptr(); + aim_location changeSquare = NUM_AIM_LOCATIONS; + + const std::string action = ctxt.handle_input(); + if( action == "CATEGORY_SELECTION" ) { + inCategoryMode = !inCategoryMode; + pane.redraw = true; // We redraw to force the color change of the highlighted line and header text. + } else if( action == "HELP_KEYBINDINGS" ) { + redraw = true; + } else if( action == "ITEMS_DEFAULT" ) { + aim_location location = static_cast( uistate.adv_inv_default_areas[0] ); + if( pane.get_area() != location || location == AIM_ALL ) { + pane.recalc = true; + } + pane.set_area( squares[location] ); + redraw = true; + } else if( action == "SAVE_DEFAULT" ) { + uistate.adv_inv_default_areas[0] = pane.get_area(); + popup( _( "Default layout was saved." ) ); + redraw = true; + } else if( get_square( action, changeSquare ) ) { + if( pane.get_area() == changeSquare ) { + //DO NOTHING + } else if( squares[changeSquare].canputitems( pane.get_cur_item_ptr() ) ) { + bool in_vehicle_cargo = false; + if( changeSquare == AIM_CONTAINER ) { + squares[changeSquare].set_container( pane.get_cur_item_ptr() ); + } else if( pane.get_area() == AIM_CONTAINER ) { + squares[changeSquare].set_container( nullptr ); + // auto select vehicle if items exist at said square, or both are empty + } else if( squares[changeSquare].can_store_in_vehicle() ) { + if( changeSquare == AIM_DRAGGED ) { + in_vehicle_cargo = true; + } else { + // check item stacks in vehicle and map at said square + auto sq = squares[changeSquare]; + auto map_stack = g->m.i_at( sq.pos ); + auto veh_stack = sq.veh->get_items( sq.vstor ); + // auto switch to vehicle storage if vehicle items are there, or neither are there + if( !veh_stack.empty() || map_stack.empty() ) { + in_vehicle_cargo = true; + } + } + } + pane.set_area( squares[changeSquare], in_vehicle_cargo ); + pane.index = 0; + pane.recalc = true; + redraw = true; + } else { + popup( _( "You can't put items there!" ) ); + redraw = true; // to clear the popup + } + } else if( action == "TOGGLE_FAVORITE" ) { + if( sitem == nullptr || !sitem->is_item_entry() ) { + continue; + } + for( auto *it : sitem->items ) { + it->set_favorite( !it->is_favorite ); + } + recalc = true; // In case we've merged faved and unfaved items + redraw = true; + } else if( action == "MOVE_SINGLE_ITEM" || + action == "MOVE_VARIABLE_ITEM" || + action == "MOVE_ITEM_STACK" ) { + + } else if( action == "SORT" ) { + if( show_sort_menu( pane ) ) { + recalc = true; + + //TODO: find all uistate, no settings? + uistate.adv_inv_sort[0] = pane.sortby; + } + redraw = true; + } else if( action == "FILTER" ) { + string_input_popup spopup; + std::string filter = pane.filter; + filter_edit = true; + spopup.window( pane.window, 4, w_height - 1, w_width / 2 - 4 ) + .max_length( 256 ) + .text( filter ); + + draw_item_filter_rules( pane.window, 1, 11, item_filter_type::FILTER ); + +#if defined(__ANDROID__) + if( get_option( "ANDROID_AUTO_KEYBOARD" ) ) { + SDL_StartTextInput(); + } +#endif + + do { + mvwprintz( pane.window, getmaxy( pane.window ) - 1, 2, c_cyan, "< " ); + mvwprintz( pane.window, getmaxy( pane.window ) - 1, w_width / 2 - 4, c_cyan, " >" ); + std::string new_filter = spopup.query_string( false ); + if( spopup.context().get_raw_input().get_first_input() == KEY_ESCAPE ) { + // restore original filter + pane.set_filter( filter ); + } else { + pane.set_filter( new_filter ); + } + redraw_pane(); + } while( spopup.context().get_raw_input().get_first_input() != '\n' && + spopup.context().get_raw_input().get_first_input() != KEY_ESCAPE ); + filter_edit = false; + pane.redraw = true; + } else if( action == "RESET_FILTER" ) { + pane.set_filter( "" ); + } else if( action == "TOGGLE_AUTO_PICKUP" ) { + if( sitem == nullptr || !sitem->is_item_entry() ) { + continue; + } + if( sitem->autopickup ) { + get_auto_pickup().remove_rule( sitem->items.front() ); + sitem->autopickup = false; + } else { + get_auto_pickup().add_rule( sitem->items.front() ); + sitem->autopickup = true; + } + recalc = true; + } else if( action == "EXAMINE" ) { + if( sitem == nullptr || !sitem->is_item_entry() ) { + continue; + } + int ret = 0; + const int info_width = w_width / 2; + const int info_startx = colstart + info_width; + if( pane.get_area() == AIM_INVENTORY || pane.get_area() == AIM_WORN ) { + int idx = pane.get_area() == AIM_INVENTORY ? sitem->idx : + player::worn_position_to_index( sitem->idx ); + // Setup a "return to AIM" activity. If examining the item creates a new activity + // (e.g. reading, reloading, activating), the new activity will be put on top of + // "return to AIM". Once the new activity is finished, "return to AIM" comes back + // (automatically, see player activity handling) and it re-opens the AIM. + // If examining the item did not create a new activity, we have to remove + // "return to AIM". + do_return_entry(); + assert( g->u.has_activity( activity_id( "ACT_ADV_INVENTORY" ) ) ); + ret = g->inventory_item_menu( idx, info_startx, info_width, game::RIGHT_OF_INFO ); + //src == comestible_inventory::side::left ? game::LEFT_OF_INFO : game::RIGHT_OF_INFO); + if( !g->u.has_activity( activity_id( "ACT_ADV_INVENTORY" ) ) ) { + exit = true; + } else { + g->u.cancel_activity(); + } + // Might have changed a stack (activated an item, repaired an item, etc.) + if( pane.get_area() == AIM_INVENTORY ) { + g->u.inv.restack( g->u ); + } + recalc = true; + } else { + item &it = *sitem->items.front(); + std::vector vThisItem; + std::vector vDummy; + it.info( true, vThisItem ); + int iDummySelect = 0; + ret = draw_item_info( info_startx, + info_width, 0, 0, it.tname(), it.type_name(), vThisItem, vDummy, iDummySelect, + false, false, true ).get_first_input(); + } + if( ret == KEY_NPAGE || ret == KEY_DOWN ) { + pane.scroll_by( +1 ); + } else if( ret == KEY_PPAGE || ret == KEY_UP ) { + pane.scroll_by( -1 ); + } + redraw = true; // item info window overwrote the other pane and the header + } else if( action == "QUIT" ) { + exit = true; + } else if( action == "PAGE_DOWN" ) { + pane.scroll_by( +itemsPerPage ); + } else if( action == "PAGE_UP" ) { + pane.scroll_by( -itemsPerPage ); + } else if( action == "DOWN" ) { + pane.scroll_by( +1, inCategoryMode ); + } else if( action == "UP" ) { + pane.scroll_by( -1, inCategoryMode ); + } else if( action == "TOGGLE_VEH" ) { + if( squares[pane.get_area()].can_store_in_vehicle() ) { + // swap the panes if going vehicle will show the same tile + //if (spane.get_area() == dpane.get_area() && spane.in_vehicle() != dpane.in_vehicle()) { + // swap_panes(); + // // disallow for dragged vehicles + //} + //else + if( pane.get_area() != AIM_DRAGGED ) { + // Toggle between vehicle and ground + pane.set_area( squares[pane.get_area()], !pane.in_vehicle() ); + pane.index = 0; + pane.recalc = true; + // make sure to update the minimap as well! + redraw = true; + } + } else { + popup( _( "No vehicle there!" ) ); + redraw = true; + } + } else if( action == "SWITCH_FOOD" ) { + pane.filter_show_food = !pane.filter_show_food; + recalc = true; + } else if( action == "HEAT_UP" ) { + heat_up( sitem->items.front() ); + } + } +} + +void comestible_inventory_pane::skip_category_headers( int offset ) +{ + assert( offset != 0 ); // 0 would make no sense + assert( static_cast( index ) < items.size() ); // valid index is required + assert( offset == -1 || offset == +1 ); // only those two offsets are allowed + assert( !items.empty() ); // index would not be valid, and this would be an endless loop + while( !items[index].is_item_entry() ) { + mod_index( offset ); + } +} + +void comestible_inventory_pane::mod_index( int offset ) +{ + assert( offset != 0 ); // 0 would make no sense + assert( !items.empty() ); + index += offset; + if( index < 0 ) { + index = static_cast( items.size() ) - 1; + } else if( static_cast( index ) >= items.size() ) { + index = 0; + } +} + +void comestible_inventory_pane::scroll_by( int offset, bool scroll_by_category ) +{ + assert( offset != 0 ); // 0 would make no sense + if( items.empty() ) { + return; + } + if( scroll_by_category ) { + assert( offset == -1 || offset == +1 ); // only those two offsets are allowed + assert( get_cur_item_ptr() != nullptr ); // index must already be valid! + auto cur_cat = items[index].cat; + if( offset > 0 ) { + while( items[index].cat == cur_cat ) { + index++; + if( static_cast( index ) >= items.size() ) { + index = 0; // wrap to begin, stop there. + break; + } + } + } else { + while( items[index].cat == cur_cat ) { + index--; + if( index < 0 ) { + index = static_cast( items.size() ) - 1; // wrap to end, stop there. + break; + } + } + } + } else { + mod_index( offset ); + } + // Make sure we land on an item entry. + skip_category_headers( offset > 0 ? +1 : -1 ); + redraw = true; +} + +comestible_inv_listitem *comestible_inventory_pane::get_cur_item_ptr() +{ + if( static_cast( index ) >= items.size() ) { + return nullptr; + } + return &items[index]; +} + +void comestible_inventory_pane::set_filter( const std::string &new_filter ) +{ + if( filter == new_filter ) { + return; + } + filter = new_filter; + filtercache.clear(); + recalc = true; +} + +bool comestible_inventory::move_content( item &src_container, item &dest_container ) +{ + if( !src_container.is_container() ) { + popup( _( "Source must be container." ) ); + return false; + } + if( src_container.is_container_empty() ) { + popup( _( "Source container is empty." ) ); + return false; + } + + item &src_contents = src_container.contents.front(); + + if( !src_contents.made_of( LIQUID ) ) { + popup( _( "You can unload only liquids into target container." ) ); + return false; + } + + std::string err; + // TODO: Allow buckets here, but require them to be on the ground or wielded + const int amount = dest_container.get_remaining_capacity_for_liquid( src_contents, false, &err ); + if( !err.empty() ) { + popup( err ); + return false; + } + if( src_container.is_non_resealable_container() ) { + if( src_contents.charges > amount ) { + popup( _( "You can't partially unload liquids from unsealable container." ) ); + return false; + } + src_container.on_contents_changed(); + } + dest_container.fill_with( src_contents, amount ); + + uistate.adv_inv_container_content_type = dest_container.contents.front().typeId(); + if( src_contents.charges <= 0 ) { + src_container.contents.clear(); + } + + return true; +} + +units::volume comestible_inv_area::free_volume( bool in_vehicle ) const +{ + assert( id != AIM_ALL ); // should be a specific location instead + if( id == AIM_INVENTORY || id == AIM_WORN ) { + return g->u.volume_capacity() - g->u.volume_carried(); + } + return in_vehicle ? veh->free_volume( vstor ) : g->m.free_volume( pos ); +} +// +//bool comestible_inventory::query_charges(aim_location destarea, const comestible_inv_listitem& sitem, +// const std::string& action, int& amount) +//{ +// assert(destarea != AIM_ALL); // should be a specific location instead +// assert(!sitem.items.empty()); // valid item is obviously required +// const item& it = *sitem.items.front(); +// comestible_inv_area& p = squares[destarea]; +// const bool by_charges = it.count_by_charges(); +// const units::volume free_volume = p.free_volume(panes[dest].in_vehicle()); +// // default to move all, unless if being equipped +// const int input_amount = by_charges ? it.charges : action == "MOVE_SINGLE_ITEM" ? 1 : sitem.stacks; +// assert(input_amount > 0); // there has to be something to begin with +// amount = input_amount; +// +// // Includes moving from/to inventory and around on the map. +// if (it.made_of_from_type(LIQUID)) { +// popup(_("You can't pick up a liquid.")); +// redraw = true; +// return false; +// } +// +// // Check volume, this should work the same for inventory, map and vehicles, but not for worn +// const int room_for = it.charges_per_volume(free_volume); +// if (amount > room_for && squares[destarea].id != AIM_WORN) { +// if (room_for <= 0) { +// popup(_("Destination area is full. Remove some items first.")); +// redraw = true; +// return false; +// } +// amount = std::min(room_for, amount); +// } +// // Map and vehicles have a maximal item count, check that. Inventory does not have this. +// if (destarea != AIM_INVENTORY && +// destarea != AIM_WORN && +// destarea != AIM_CONTAINER) { +// const int cntmax = p.max_size - p.get_item_count(); +// // For items counted by charges, adding it adds 0 items if something there stacks with it. +// const bool adds0 = by_charges && std::any_of(pane.items.begin(), pane.items.end(), +// [&it](const comestible_inv_listitem& li) { +// return li.is_item_entry() && li.items.front()->stacks_with(it); +// }); +// if (cntmax <= 0 && !adds0) { +// popup(_("Destination area has too many items. Remove some first.")); +// redraw = true; +// return false; +// } +// // Items by charge count as a single item, regardless of the charges. As long as the +// // destination can hold another item, one can move all charges. +// if (!by_charges) { +// amount = std::min(cntmax, amount); +// } +// } +// // Inventory has a weight capacity, map and vehicle don't have that +// if (destarea == AIM_INVENTORY || destarea == AIM_WORN) { +// const units::mass unitweight = it.weight() / (by_charges ? it.charges : 1); +// const units::mass max_weight = g->u.has_trait(trait_id("DEBUG_STORAGE")) ? +// units::mass_max : g->u.weight_capacity() * 4 - g->u.weight_carried(); +// if (unitweight > 0_gram && unitweight * amount > max_weight) { +// const int weightmax = max_weight / unitweight; +// if (weightmax <= 0) { +// popup(_("This is too heavy!")); +// redraw = true; +// return false; +// } +// amount = std::min(weightmax, amount); +// } +// } +// // handle how many of armor type we can equip (max of 2 per type) +// if (destarea == AIM_WORN) { +// const auto& id = sitem.items.front()->typeId(); +// // how many slots are available for the item? +// const int slots_available = MAX_WORN_PER_TYPE - g->u.amount_worn(id); +// // base the amount to equip on amount of slots available +// amount = std::min(slots_available, input_amount); +// } +// // Now we have the final amount. Query if requested or limited room left. +// if (action == "MOVE_VARIABLE_ITEM" || amount < input_amount) { +// const int count = by_charges ? it.charges : sitem.stacks; +// const char* msg = nullptr; +// std::string popupmsg; +// if (amount >= input_amount) { +// msg = _("How many do you want to move? [Have %d] (0 to cancel)"); +// popupmsg = string_format(msg, count); +// } +// else { +// msg = _("Destination can only hold %d! Move how many? [Have %d] (0 to cancel)"); +// popupmsg = string_format(msg, amount, count); +// } +// // At this point amount contains the maximal amount that the destination can hold. +// const int possible_max = std::min(input_amount, amount); +// if (amount <= 0) { +// popup(_("The destination is already full!")); +// } +// else { +// amount = string_input_popup() +// .title(popupmsg) +// .width(20) +// .only_digits(true) +// .query_int(); +// } +// if (amount <= 0) { +// redraw = true; +// return false; +// } +// if (amount > possible_max) { +// amount = possible_max; +// } +// } +// return true; +//} + +bool comestible_inv_area::is_same( const comestible_inv_area &other ) const +{ + // All locations (sans the below) are compared by the coordinates, + // e.g. dragged vehicle (to the south) and AIM_SOUTH are the same. + if( id != AIM_INVENTORY && other.id != AIM_INVENTORY && + id != AIM_WORN && other.id != AIM_WORN && + id != AIM_CONTAINER && other.id != AIM_CONTAINER ) { + // have a vehicle?... ...do the cargo index and pos match?... ...at least pos? + return veh == other.veh ? pos == other.pos && vstor == other.vstor : pos == other.pos; + } + // ...is the id? + return id == other.id; +} + +bool comestible_inv_area::canputitems( const comestible_inv_listitem *advitem ) +{ + bool canputitems = false; + bool from_vehicle = false; + item *it = nullptr; + switch( id ) { + case AIM_CONTAINER: + if( advitem != nullptr && advitem->is_item_entry() ) { + it = advitem->items.front(); + from_vehicle = advitem->from_vehicle; + } + if( get_container( from_vehicle ) != nullptr ) { + it = get_container( from_vehicle ); + } + if( it != nullptr ) { + canputitems = it->is_watertight_container(); + } + break; + default: + canputitems = canputitemsloc; + break; + } + return canputitems; +} + +item *comestible_inv_area::get_container( bool in_vehicle ) +{ + item *container = nullptr; + + if( uistate.adv_inv_container_location != -1 ) { + // try to find valid container in the area + if( uistate.adv_inv_container_location == AIM_INVENTORY ) { + const invslice &stacks = g->u.inv.slice(); + + // check index first + if( stacks.size() > static_cast( uistate.adv_inv_container_index ) ) { + auto &it = stacks[uistate.adv_inv_container_index]->front(); + if( is_container_valid( &it ) ) { + container = ⁢ + } + } + + // try entire area + if( container == nullptr ) { + for( size_t x = 0; x < stacks.size(); ++x ) { + auto &it = stacks[x]->front(); + if( is_container_valid( &it ) ) { + container = ⁢ + uistate.adv_inv_container_index = x; + break; + } + } + } + } else if( uistate.adv_inv_container_location == AIM_WORN ) { + auto &worn = g->u.worn; + size_t idx = static_cast( uistate.adv_inv_container_index ); + if( worn.size() > idx ) { + auto iter = worn.begin(); + std::advance( iter, idx ); + if( is_container_valid( &*iter ) ) { + container = &*iter; + } + } + + // no need to reinvent the wheel + if( container == nullptr ) { + auto iter = worn.begin(); + for( size_t i = 0; i < worn.size(); ++i, ++iter ) { + if( is_container_valid( &*iter ) ) { + container = &*iter; + uistate.adv_inv_container_index = i; + break; + } + } + } + } else { + map &m = g->m; + bool is_in_vehicle = veh && + ( uistate.adv_inv_container_in_vehicle || ( can_store_in_vehicle() && in_vehicle ) ); + + const itemstack &stacks = is_in_vehicle ? + i_stacked( veh->get_items( vstor ) ) : + i_stacked( m.i_at( pos ) ); + + // check index first + if( stacks.size() > static_cast( uistate.adv_inv_container_index ) ) { + auto it = stacks[uistate.adv_inv_container_index].front(); + if( is_container_valid( it ) ) { + container = it; + } + } + + // try entire area + if( container == nullptr ) { + for( size_t x = 0; x < stacks.size(); ++x ) { + auto it = stacks[x].front(); + if( is_container_valid( it ) ) { + container = it; + uistate.adv_inv_container_index = x; + break; + } + } + } + } + + // no valid container in the area, resetting container + if( container == nullptr ) { + set_container( nullptr ); + desc[0] = _( "Invalid container" ); + } + } + + return container; +} + +void comestible_inv_area::set_container( const comestible_inv_listitem *advitem ) +{ + if( advitem != nullptr ) { + item *it( advitem->items.front() ); + uistate.adv_inv_container_location = advitem->area; + uistate.adv_inv_container_in_vehicle = advitem->from_vehicle; + uistate.adv_inv_container_index = advitem->idx; + uistate.adv_inv_container_type = it->typeId(); + uistate.adv_inv_container_content_type = !it->is_container_empty() ? + it->contents.front().typeId() : "null"; + set_container_position(); + } else { + uistate.adv_inv_container_location = -1; + uistate.adv_inv_container_index = 0; + uistate.adv_inv_container_in_vehicle = false; + uistate.adv_inv_container_type = "null"; + uistate.adv_inv_container_content_type = "null"; + } +} + +bool comestible_inv_area::is_container_valid( const item *it ) const +{ + if( it != nullptr ) { + if( it->typeId() == uistate.adv_inv_container_type ) { + if( it->is_container_empty() ) { + if( uistate.adv_inv_container_content_type == "null" ) { + return true; + } + } else { + if( it->contents.front().typeId() == uistate.adv_inv_container_content_type ) { + return true; + } + } + } + } + + return false; +} + +void comestible_inv_area::set_container_position() +{ + // update the offset of the container based on location + if( uistate.adv_inv_container_location == AIM_DRAGGED ) { + off = g->u.grab_point; + } else { + off = aim_vector( static_cast( uistate.adv_inv_container_location ) ); + } + // update the absolute position + pos = g->u.pos() + off; + // update vehicle information + if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", + false ) ) { + veh = &vp->vehicle(); + vstor = vp->part_index(); + } else { + veh = nullptr; + vstor = -1; + } +} + +void comestible_inv() +{ + comestible_inventory new_inv; + new_inv.display(); +} + +void comestible_inventory::refresh_minimap() +{ + // don't update ui if processing demands + if( is_processing() ) { + return; + } + // redraw border around minimap + draw_border( mm_border ); + // minor addition to border for AIM_ALL, sorta hacky + if( pane.get_area() == AIM_ALL ) { + mvwprintz( mm_border, 0, 1, c_light_gray, utf8_truncate( _( "All" ), minimap_width ) ); + } + // refresh border, then minimap + wrefresh( mm_border ); + wrefresh( minimap ); +} + +void comestible_inventory::draw_minimap() +{ + // if player is in one of the below, invert the player cell + static const std::array player_locations = { + {AIM_CENTER, AIM_INVENTORY, AIM_WORN} + }; + // get the center of the window + tripoint pc = { getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0 }; + // draw the 3x3 tiles centered around player + g->m.draw( minimap, g->u.pos() ); + auto sq = squares[pane.get_area()]; + auto pt = pc + sq.off; + // invert the color if pointing to the player's position + auto cl = sq.id == AIM_INVENTORY || sq.id == AIM_WORN ? + invert_color( c_light_cyan ) : c_light_cyan.blink(); + + // Invert player's tile color if exactly one pane points to player's tile + //bool invert_left = false; + //bool invert_right = false; + //const auto is_selected = [this](const aim_location& where, size_t side) { + // return where == this->panes[side].get_area(); + //}; + //for (auto& loc : player_locations) { + // invert_left |= is_selected(loc, 0); + // invert_right |= is_selected(loc, 1); + //} + + //if (!invert_left || !invert_right) { + // g->u.draw(minimap, g->u.pos(), invert_left || invert_right); + //} + + g->u.draw( minimap, g->u.pos(), false ); +} + +//char comestible_inventory::get_minimap_sym(side p) const +//{ +// static const std::array c_side = { {'L', 'R'} }; +// static const std::array d_side = { {'^', 'v'} }; +// static const std::array g_nome = { { +// '@', '#', '#', '#', '#', '@', '#', +// '#', '#', '#', 'D', '^', 'C', '@' +// } +// }; +// char ch = g_nome[pane.get_area()]; +// +// +// //TODO: don't get this code exactly, just simplify for now +// ch = pane.in_vehicle() ? 'V' : c_side[p]; +// +// switch (ch) { +// case '@': // '^' or 'v' +// ch = d_side[panes[-p + 1].get_area() == AIM_CENTER]; +// break; +// case '#': // 'L' or 'R' +// ch = panes[p].in_vehicle() ? 'V' : c_side[p]; +// break; +// case '^': // do not show anything +// ch ^= ch; +// break; +// } +// return ch; +//} + +aim_location comestible_inv_area::offset_to_location() const +{ + static aim_location loc_array[3][3] = { + {AIM_NORTHWEST, AIM_NORTH, AIM_NORTHEAST}, + {AIM_WEST, AIM_CENTER, AIM_EAST}, + {AIM_SOUTHWEST, AIM_SOUTH, AIM_SOUTHEAST} + }; + return loc_array[off.y + 1][off.x + 1]; +} + +void comestible_inventory::do_return_entry() +{ + // only save pane settings + //save_settings(true); + g->u.assign_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ); + g->u.activity.auto_resume = true; + uistate.adv_inv_exit_code = exit_re_entry; +} + +bool comestible_inventory::is_processing() const +{ + return uistate.adv_inv_re_enter_move_all != ENTRY_START; +} + +aim_location comestible_inventory::screen_relative_location( aim_location area ) +{ + + if( !( tile_iso && use_tiles ) ) { + return area; + } + switch( area ) { + + case AIM_SOUTHWEST: + return AIM_WEST; + + case AIM_SOUTH: + return AIM_SOUTHWEST; + + case AIM_SOUTHEAST: + return AIM_SOUTH; + + case AIM_WEST: + return AIM_NORTHWEST; + + case AIM_EAST: + return AIM_SOUTHEAST; + + case AIM_NORTHWEST: + return AIM_NORTH; + + case AIM_NORTH: + return AIM_NORTHEAST; + + case AIM_NORTHEAST: + return AIM_EAST; + + default: + return area; + } +} + +char *comestible_inventory::set_string_params( nc_color &print_color, int value, bool selected, + bool need_highlight ) +{ + char *string_format; + if( value > 0 ) { + print_color = need_highlight ? c_yellow_green : c_green; + string_format = "+%d"; + } else if( value < 0 ) { + print_color = need_highlight ? c_yellow_red : c_red; + string_format = "%d"; + } else { + print_color = need_highlight ? c_yellow : c_dark_gray; + string_format = ""; + } + + if( selected ) { + print_color = hilite( c_white ); + } + return string_format; +} + +const islot_comestible &comestible_inventory::get_edible_comestible( player &p, + const item &it ) const +{ + if( it.is_comestible() && p.can_eat( it ).success() ) { + // Ok since can_eat() returns false if is_craft() is true + return *it.type->comestible; + } + static const islot_comestible dummy{}; + return dummy; +} + +time_duration comestible_inventory::get_time_left( player &p, const item &it ) const +{ + time_duration time_left = 0_turns; + const time_duration shelf_life = get_edible_comestible( p, it ).spoils; + if( shelf_life > 0_turns ) { + 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 comestible_inventory::get_time_left_rounded( player &p, const item &it ) const +{ + if( it.is_going_bad() ) { + return _( "soon!" ); + } + + time_duration time_left = get_time_left( p, it ); + + //const auto make_result = [this](const time_duration& d, const char* verbose_str, + // const char* short_str) { + // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); + //}; + + time_duration divider = 0_turns; + time_duration vicinity = 0_turns; + + if( time_left > 1_days ) { + divider = 1_days; + vicinity = 2_hours; + } else if( time_left > 1_hours ) { + divider = 1_hours; + vicinity = 5_minutes; + } // Minutes and seconds can be estimated precisely. + + if( divider != 0_turns ) { + const time_duration remainder = time_left % divider; + + if( remainder >= divider - vicinity ) { + time_left += divider; + } else if( remainder > vicinity ) { + if( remainder < divider / 2 ) { + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("> %s", time_to_comestible_str(time_left)); + } else { + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("< %s", time_to_comestible_str(time_left)); + } + } + } + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("~ %s", time_to_comestible_str(time_left)); +} + +std::string comestible_inventory::time_to_comestible_str( const time_duration &d ) const +{ + if( d >= calendar::INDEFINITELY_LONG_DURATION ) { + return _( "forever" ); + } + + const float day = to_days( d ); + std::string format; + if( day < 1.00 ) { + format = _( "%.2f days" ); + } else if( day > 1.00 ) { + format = _( "%.0f days" ); + } else { + format = _( "1 day" ); + } + + return string_format( format, day ); +} + +void comestible_inventory::heat_up( item *it_to_heat ) +{ + player &p = g->u; + inventory map_inv = inventory(); + map_inv.form_from_map( p.pos(), 1 ); + + bool has_heat_item = false; + bool is_near_fire = false; + bool can_use_bio = false; + bool can_use_hotplate = false; + + //TODO: I think can use crafting.cpp - + // comp_selection player::select_item_component(){} + //or + // comp_selection player::select_tool_component(){} + //to search and select items + + //first find tools we can use + const std::function &heat_filter = + []( const item & it ) { + + bool can_heat = ( it.get_use( "HEAT_FOOD" ) != nullptr ); + return can_heat; + }; + + has_heat_item = p.has_item_with( heat_filter ); + if( !has_heat_item ) { + has_heat_item = map_inv.has_item_with( heat_filter ); + } + + if( has_heat_item ) { + if( g->m.has_nearby_fire( p.pos() ) ) { + is_near_fire = true; + } else if( p.has_active_bionic( bionic_id( "bio_tools" ) ) && p.power_level > 10 ) { + can_use_bio = true; + } + } + + const std::function &filter = + []( const item & it ) { + + if( !it.is_tool() ) { + return false; + } + bool is_hotplate = ( it.get_use( "HOTPLATE" ) != nullptr ); + if( !is_hotplate ) { + return false; + } + + return it.units_remaining( g->u ) >= it.type->charges_to_use(); + }; + + std::vector hotplates = p.items_with( filter ); + std::vector hotplates_map = map_inv.items_with( filter ); + //hotplates.insert(hotplates.end(), hotplates_map.begin(), hotplates_map.end()); + + can_use_hotplate = ( hotplates.size() > 0 ) || ( hotplates_map.size() > 0 ); + + //check we can actually heat up + if( !has_heat_item && !can_use_hotplate ) { + popup( _( "You don't have a suitable container or hotplate with enough charges." ) ); + redraw = true; + //p.add_msg_if_player(m_info, _("You don't have a suitable container or hotplate with enough charges.")); + return; + } + + if( has_heat_item && !can_use_hotplate ) { + if( !is_near_fire && !can_use_bio ) { + popup( _( "You need to be near fire to heat an item in a container." ) ); + redraw = true; + //p.add_msg_if_player(m_info, _("You need to be near fire to heat an item in a container.")); + return; + } + } + + //give user options to chose from + int choice = -1; + if( !( has_heat_item && is_near_fire ) ) { + uilist sm; + sm.text = _( "Choose a way to heat an item..." ); + int counter = 0; + if( can_use_bio ) { + sm.addentry( counter, true, counter, _( "use bio tools" ) ); + counter++; + } + + for each( item * var in hotplates ) { + sm.addentry( counter, true, counter, string_format( _( "%s in inventory" ), var->display_name() ) ); + counter++; + } + for each( item * var in hotplates_map ) { + sm.addentry( counter, true, counter, string_format( _( "%s nearby" ), var->display_name() ) ); + counter++; + } + //sm.selected = pane.sortby - SORTBY_NONE; + sm.query(); + + if( sm.ret < 0 ) { + //'Never mind' + redraw = true; + return; + } + choice = sm.ret; + } + + //use charges as needed; choice == -1 if we can use fire + if( choice != -1 ) { + if( can_use_bio && choice == 0 ) { + p.charge_power( -10 ); + } else { + if( can_use_bio ) { + choice--; + } + item *it_choice; + if( choice < hotplates.size() ) { + it_choice = hotplates[choice]; + } else { + choice -= hotplates.size(); + it_choice = hotplates_map[choice]; + } + int charges_to_use = it_choice->type->charges_to_use(); + std::list used = {}; + tripoint pos = tripoint(); + it_choice->use_charges( it_choice->typeId(), charges_to_use, used, pos ); + } + } + + //actually heat up the item + //lifted from iuse.cpp - static bool heat_item( player &p ) + item &target = it_to_heat->is_food_container() ? it_to_heat->contents.front() : *it_to_heat; + p.mod_moves( -to_turns( 3_seconds ) ); //initial preparations + // simulates heat capacity of food, more weight = longer heating time + // this is x2 to simulate larger delta temperature of frozen food in relation to + // heating non-frozen food (x1); no real life physics here, only aproximations + int move_mod = to_turns( time_duration::from_seconds( to_gram( target.weight() ) ) ); + if( target.item_tags.count( "FROZEN" ) ) { + target.apply_freezerburn(); + + if( target.has_flag( "EATEN_COLD" ) ) { + target.cold_up(); + add_msg( _( "You defrost the food, but don't heat it up, since you enjoy it cold." ) ); + } else { + add_msg( _( "You defrost and heat up the food." ) ); + target.heat_up(); + // x2 because we have to defrost and heat + move_mod *= 2; + } + } else { + add_msg( _( "You heat up the food." ) ); + target.heat_up(); + } + p.mod_moves( -move_mod ); // time needed to actually heat up +} + +//void cancel_aim_processing() +//{ +// uistate.adv_inv_re_enter_move_all = ENTRY_START; +//} diff --git a/src/comestible_inv.h b/src/comestible_inv.h new file mode 100644 index 0000000000000..99ee1862aae30 --- /dev/null +++ b/src/comestible_inv.h @@ -0,0 +1,478 @@ +#pragma once +#ifndef comestible_inv_H +#define comestible_inv_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cursesdef.h" +#include "point.h" +#include "units.h" + +#include "advanced_inv.h" +#include "itype.h" + +class uilist; +class vehicle; +class item; + +//enum aim_location { +// AIM_INVENTORY = 0, +// AIM_SOUTHWEST, +// AIM_SOUTH, +// AIM_SOUTHEAST, +// AIM_WEST, +// AIM_CENTER, +// AIM_EAST, +// AIM_NORTHWEST, +// AIM_NORTH, +// AIM_NORTHEAST, +// AIM_DRAGGED, +// AIM_ALL, +// AIM_CONTAINER, +// AIM_WORN, +// NUM_AIM_LOCATIONS, +// // only useful for AIM_ALL +// AIM_AROUND_BEGIN = AIM_SOUTHWEST, +// AIM_AROUND_END = AIM_NORTHEAST +//}; +// +enum comestible_inv_sortby { + COMESTIBLE_SORTBY_NAME, + COMESTIBLE_SORTBY_WEIGHT, + COMESTIBLE_SORTBY_VOLUME, + COMESTIBLE_SORTBY_CALORIES, + COMESTIBLE_SORTBY_QUENCH, + COMESTIBLE_SORTBY_JOY, + COMESTIBLE_SORTBY_SPOILAGE +}; + +//struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { +// bool operator()(char x, char y) const { +// return toupper(static_cast(x)) < toupper(static_cast(y)); +// } +//}; + +void comestible_inv(); + +/** + * Cancels ongoing move all action. + * TODO: Make this not needed. + */ +void cancel_aim_processing(); + +struct comestible_inv_listitem; + +/** + * Defines the source of item stacks. + */ +struct comestible_inv_area { + const aim_location id; + // Used for the small overview 3x3 grid + point hscreen = point_zero; + // relative (to the player) position of the map point + tripoint off; + /** Long name, displayed, translated */ + const std::string name = "fake"; + /** Shorter name (2 letters) */ + const std::string shortname = "FK"; // FK in my coffee + // absolute position of the map point. + tripoint pos; + /** Can we put items there? Only checks if location is valid, not if + selected container in pane is. For full check use canputitems() **/ + bool canputitemsloc; + // vehicle pointer and cargo part index + vehicle *veh; + int vstor; + // description, e.g. vehicle name, label, or terrain + std::array desc; + // flags, e.g. FIRE, TRAP, WATER + std::string flags; + // total volume and weight of items currently there + units::volume volume; + units::mass weight; + // maximal count / volume of items there. + int max_size; + + comestible_inv_area( aim_location id ) : id( id ) {} + comestible_inv_area( aim_location id, int hscreenx, int hscreeny, tripoint off, + const std::string &name, const std::string &shortname ) : id( id ), + hscreen( hscreenx, hscreeny ), off( off ), name( name ), shortname( shortname ), + canputitemsloc( false ), veh( nullptr ), vstor( -1 ), volume( 0_ml ), + weight( 0_gram ), max_size( 0 ) { + } + + void init(); + // if you want vehicle cargo, specify so via `in_vehicle' + units::volume free_volume( bool in_vehicle = false ) const; + int get_item_count() const; + // Other area is actually the same item source, e.g. dragged vehicle to the south and AIM_SOUTH + bool is_same( const comestible_inv_area &other ) const; + // does _not_ check vehicle storage, do that with `can_store_in_vehicle()' below + bool canputitems( const comestible_inv_listitem *advitem = nullptr ); + // if you want vehicle cargo, specify so via `in_vehicle' + item *get_container( bool in_vehicle = false ); + void set_container( const comestible_inv_listitem *advitem ); + bool is_container_valid( const item *it ) const; + void set_container_position(); + aim_location offset_to_location() const; + bool can_store_in_vehicle() const { + // disallow for non-valid vehicle locations + if( id > AIM_DRAGGED || id < AIM_SOUTHWEST ) { + return false; + } + return veh != nullptr && vstor >= 0; + } +}; + +// see item_factory.h +class item_category; + +/** + * Entry that is displayed in a adv. inv. pane. It can either contain a + * single item or a category header or nothing (empty entry). + * Most members are used only for sorting. + */ +struct comestible_inv_listitem { + using itype_id = std::string; + /** + * Index of the item in the itemstack. + */ + int idx; + /** + * The location of the item, never AIM_ALL. + */ + aim_location area; + // the id of the item + itype_id id; + // The list of items, and empty when a header + std::list items; + /** + * The displayed name of the item/the category header. + */ + std::string name; + /** + * Name of the item (singular) without damage (or similar) prefix, used for sorting. + */ + std::string name_without_prefix; + /** + * Whether auto pickup is enabled for this item (based on the name). + */ + bool autopickup; + /** + * The stack count represented by this item, should be >= 1, should be 1 + * for anything counted by charges. + */ + int stacks; + /** + * The volume of all the items in this stack, used for sorting. + */ + units::volume volume; + /** + * The weight of all the items in this stack, used for sorting. + */ + units::mass weight; + + /** + * TODO:docs + */ + int calories; + int quench; + int joy; + + /** + * The item category, or the category header. + */ + const item_category *cat; + /** + * Is the item stored in a vehicle? + */ + bool from_vehicle; + + + //TODO + const islot_comestible &get_edible_comestible( player &p, const item &it ) const; + + /** + * Whether this is a category header entry, which does *not* have a reference + * to an item, only @ref cat is valid. + */ + bool is_category_header() const; + + /** Returns true if this is an item entry */ + bool is_item_entry() const; + /** + * Create a category header entry. + * @param cat The category reference, must not be null. + */ + comestible_inv_listitem( const item_category *cat ); + + /** + * Create a category header entry. + * @param cat The category name + */ + comestible_inv_listitem::comestible_inv_listitem( const std::string cat_name ); + /** + * Creates an empty entry, both category and item pointer are null. + */ + comestible_inv_listitem(); + /** + * Create a normal item entry. + * @param an_item The item pointer. Must not be null. + * @param index The index + * @param count The stack size + * @param area The source area. Must not be AIM_ALL. + * @param from_vehicle Is the item from a vehicle cargo space? + */ + comestible_inv_listitem( item *an_item, int index, int count, + aim_location area, bool from_vehicle ); + /** + * Create a normal item entry. + * @param list The list of item pointers. + * @param index The index + * @param area The source area. Must not be AIM_ALL. + * @param from_vehicle Is the item from a vehicle cargo space? + */ + comestible_inv_listitem( const std::list &list, int index, + aim_location area, bool from_vehicle ); +}; + +/** + * Displayed pane, what is shown on the screen. + */ +class comestible_inventory_pane +{ + private: + aim_location area = NUM_AIM_LOCATIONS; + aim_location prev_area = area; + // pointer to the square this pane is pointing to + bool viewing_cargo = false; + bool prev_viewing_cargo = false; + public: + // set the pane's area via its square, and whether it is viewing a vehicle's cargo + void set_area( comestible_inv_area &square, bool in_vehicle_cargo = false ) { + prev_area = area; + prev_viewing_cargo = viewing_cargo; + area = square.id; + viewing_cargo = square.can_store_in_vehicle() && in_vehicle_cargo; + } + void restore_area() { + area = prev_area; + viewing_cargo = prev_viewing_cargo; + } + aim_location get_area() const { + return area; + } + bool prev_in_vehicle() const { + return prev_viewing_cargo; + } + bool in_vehicle() const { + return viewing_cargo; + } + bool on_ground() const { + return area > AIM_INVENTORY && area < AIM_DRAGGED; + } + /** + * Index of the selected item (index of @ref items), + */ + int index; + comestible_inv_sortby sortby; + catacurses::window window; + std::vector items; + /** + * The current filter string. + */ + std::string filter; + /** + * Food or Drug filter. True = show food. + */ + bool filter_show_food; + /** + * Whether to recalculate the content of this pane. + * Implies @ref redraw. + */ + bool recalc; + /** + * Whether to redraw this pane. + */ + bool redraw; + + void add_items_from_area( comestible_inv_area &square, bool vehicle_override = false ); + /** + * Makes sure the @ref index is valid (if possible). + */ + void fix_index(); + /** + * @param it The item to check, oly the name member is examined. + * @return Whether the item should be filtered (and not shown). + */ + bool is_filtered( const comestible_inv_listitem &it ) const; + /** + * Same as the other, but checks the real item. + */ + bool is_filtered( const item &it ) const; + /** + * Scroll @ref index, by given offset, set redraw to true, + * @param offset Must not be 0. + */ + void scroll_by( int offset, bool scroll_by_category = false ); + /** + * @return either null, if @ref index is invalid, or the selected + * item in @ref items. + */ + comestible_inv_listitem *get_cur_item_ptr(); + /** + * Set the filter string, disables filtering when the filter string is empty. + */ + void set_filter( const std::string &new_filter ); + /** + * Insert additional category headers on the top of each page. + */ + void paginate( size_t itemsPerPage ); + private: + /** Scroll to next non-header entry */ + void skip_category_headers( int offset ); + /** Only add offset to index, but wrap around! */ + void mod_index( int offset ); + + mutable std::map> filtercache; +}; + +class comestible_inventory +{ + public: + comestible_inventory(); + ~comestible_inventory(); + + void display(); + private: + const int head_height; + const int min_w_height; + const int min_w_width; + const int max_w_width; + + // minimap that displays things around character + catacurses::window minimap; + catacurses::window mm_border; + const int minimap_width = 3; + const int minimap_height = 3; + void draw_minimap(); + void refresh_minimap(); + char get_minimap_sym() const; + + bool inCategoryMode; + + int itemsPerPage; + int w_height; + int w_width; + + int headstart; + int colstart; + + bool recalc; + bool redraw; + /** + * True if (and only if) the filter of the active panel is currently + * being edited. + */ + bool filter_edit; + + comestible_inventory_pane pane; + //static const comestible_inventory_pane null_pane; + std::array squares; + + catacurses::window head; + catacurses::window window; + + bool exit; + + // store/load settings (such as index, filter, etc) + void save_settings( bool only_panes ); + void load_settings(); + // used to return back to AIM when other activities queued are finished + void do_return_entry(); + // returns true if currently processing a routine + // (such as `MOVE_ALL_ITEMS' with `AIM_ALL' source) + bool is_processing() const; + + static std::string get_sortname( comestible_inv_sortby sortby ); + //bool move_all_items(bool nested_call = false); + void print_items( comestible_inventory_pane &pane ); + void recalc_pane(); + void redraw_pane(); + // Returns the x coordinate where the header started. The header is + // displayed right of it, everything left of it is till free. + int print_header( comestible_inventory_pane &pane, aim_location sel ); + void init(); + /** + * Translate an action ident from the input context to an aim_location. + * @param action Action ident to translate + * @param ret If the action ident referred to a location, its id is stored + * here. Only valid when the function returns true. + * @return true if the action did refer to an location (which has been + * stored in ret), false otherwise. + */ + static bool get_square( const std::string &action, aim_location &ret ); + /** + * Show the sort-by menu and change the sorting of this pane accordingly. + * @return whether the sort order was actually changed. + */ + bool show_sort_menu( comestible_inventory_pane &pane ); + /** + * Checks whether one can put items into the supplied location. + * If the supplied location is AIM_ALL, query for the actual location + * (stores the result in def) and check that destination. + * @return false if one can not put items in the destination, true otherwise. + * The result true also indicates the def is not AIM_ALL (because the + * actual location has been queried). + */ + //bool query_destination(aim_location& def); + /** + * Move content of source container into destination container (destination pane = AIM_CONTAINER) + * @param src_container Source container + * @param dest_container Destination container + */ + bool move_content( item &src_container, item &dest_container ); + /** + * Setup how many items/charges (if counted by charges) should be moved. + * @param destarea Where to move to. This must not be AIM_ALL. + * @param sitem The source item, it must contain a valid reference to an item! + * @param action The action we are querying + * @param amount The input value is ignored, contains the amount that should + * be moved. Only valid if this returns true. + * @return false if nothing should/can be moved. True only if there can and + * should be moved. A return value of true indicates that amount now contains + * a valid item count to be moved. + */ + /*bool query_charges(aim_location destarea, const comestible_inv_listitem& sitem, + const std::string& action, int& amount);*/ + + void menu_square( uilist &menu ); + + static char get_location_key( aim_location area ); + static char get_direction_key( aim_location area ); + + /** + * Converts from screen relative location to game-space relative location + * for control rotation in isometric mode. + */ + static aim_location screen_relative_location( aim_location area ); + + char *comestible_inventory::set_string_params( nc_color &print_color, int value, bool selected, + bool need_highlight = false ); + //nc_color set_string_params(int value, bool need_highlight = false); + time_duration comestible_inventory::get_time_left( player &p, const item &it ) const; + const islot_comestible &get_edible_comestible( player &p, const item &it ) const; + std::string get_time_left_rounded( player &p, const item &it ) const; + std::string time_to_comestible_str( const time_duration &d ) const; + + void heat_up( item *it ); +}; + +#endif diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 5f42f29f8f74b..3a89b9358d2cb 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -8,6 +8,7 @@ #include "action.h" #include "advanced_inv.h" +#include "comestible_inv.h" #include "auto_pickup.h" #include "avatar.h" #include "avatar_action.h" @@ -1872,7 +1873,8 @@ bool game::handle_action() break; case ACTION_EAT: - eat(); + comestible_inv(); + //eat(); break; case ACTION_OPEN_CONSUME: @@ -1881,7 +1883,8 @@ bool game::handle_action() case ACTION_READ: // Shell-users are presumed to have the book just at an opening and read it that way - read(); + //read(); + eat(); break; case ACTION_WIELD: diff --git a/src/uistate.h b/src/uistate.h index 5df93f9de12c7..bae73fabd20a8 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -13,6 +13,17 @@ class item; +//struct comestible_inv_save_state { +//public: +// int sort_idx = 1; +// std::string filter = ""; +// int area_idx = 5; +// int selected_idx = 0; +// +// bool in_vehicle = false; +// int exit_code = 0; +//}; + /* centralized depot for trivial ui data such as sorting, string_input_popup history, etc. To use this, see the ****notes**** below @@ -53,6 +64,10 @@ class uistatedata std::map> adv_inv_veh_items, adv_inv_map_items; bool adv_inv_container_in_vehicle = false; + int save_var = 5; + + //comestible_inv_save_state comestible_save; + bool editmap_nsa_viewmode = false; // true: ignore LOS and lighting bool overmap_blinking = true; // toggles active blinking of overlays. bool overmap_show_overlays = false; // whether overlays are shown or not. @@ -277,6 +292,6 @@ class uistatedata } } }; -extern uistatedata uistate; +extern uistatedata uistate; #endif From ffa219686083ec82845971f880c5be3fc26c4705 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 17 Aug 2019 14:22:37 -0400 Subject: [PATCH 02/19] # If this commit is applied, it will .... fix tests/ errors --- src/comestible_inv.cpp | 87 +++++++++++++++++------------------------- src/comestible_inv.h | 9 +---- 2 files changed, 37 insertions(+), 59 deletions(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 67eae8a9bebb2..b025ef6cf719e 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -133,11 +133,11 @@ comestible_inventory::~comestible_inventory() void comestible_inventory::save_settings( bool only_panes ) { - //if (!only_panes) { + if (!only_panes) { // uistate.adv_inv_last_coords = g->u.pos(); // uistate.adv_inv_src = src; // uistate.adv_inv_dest = dest; - //} + } uistate.adv_inv_in_vehicle[0] = pane.in_vehicle(); uistate.adv_inv_area[0] = pane.get_area(); uistate.adv_inv_index[0] = pane.index; @@ -315,9 +315,9 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) int max_name_length = src_startpos - name_startpos - 1; // Default name length //~ Items list header. Table fields length without spaces: amt - 4, weight - 5, vol - 4. - const int table_hdr_len1 = utf8_width( _( "amt weight vol" ) ); // Header length type 1 + //const int table_hdr_len1 = utf8_width( _( "amt weight vol" ) ); // Header length type 1 //~ Items list header. Table fields length without spaces: src - 2, amt - 4, weight - 5, vol - 4. - const int table_hdr_len2 = utf8_width( _( "src amt weight vol" ) ); // Header length type 2 + //const int table_hdr_len2 = utf8_width( _( "src amt weight vol" ) ); // Header length type 2 mvwprintz( window, 5, compact ? 1 : 4, c_light_gray, _( "Name (charges)" ) ); //if (pane.get_area() == AIM_ALL && !compact) { @@ -360,8 +360,9 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) nc_color thiscolordark = c_dark_gray; nc_color print_color; + //TODO: remove inCategoryMode if( selected ) { - thiscolor = inCategoryMode && pane.sortby == SORTBY_CATEGORY ? c_white_red : hilite( c_white ); + thiscolor = inCategoryMode ? c_white_red : hilite( c_white ); thiscolordark = hilite( thiscolordark ); if( compact ) { mvwprintz( window, 6 + x, 1, thiscolor, " %s", spaces ); @@ -459,7 +460,7 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) compact ? it.tname().substr( 0, 1 ) : ">" ); } //get_consumable_item - char *string_format = ""; + char const *string_format = ""; islot_comestible it_c = get_edible_comestible( p, it ); // .type->comestible; //print "CALORIES" column @@ -953,17 +954,6 @@ comestible_inv_listitem::comestible_inv_listitem( const item_category *cat ) { } -comestible_inv_listitem::comestible_inv_listitem( const std::string cat_name ) - : idx() - , area() - , id( "null" ) - , name( cat_name ) - , autopickup() - , stacks() - , cat( cat ) -{ -} - bool comestible_inv_listitem::is_category_header() const { return items.empty() && cat != nullptr; @@ -1128,9 +1118,10 @@ void comestible_inventory_pane::add_items_from_area( comestible_inv_area &square void comestible_inventory_pane::paginate( size_t itemsPerPage ) { - if( sortby != SORTBY_CATEGORY ) { - return; // not needed as there are no category entries here. - } + //TODO: check this out, pagination not needed without categories? + //if( sortby != SORTBY_CATEGORY ) { + // return; // not needed as there are no category entries here. + //} // first, we insert all the items, then we sort the result for( size_t i = 0; i < items.size(); ++i ) { if( i % itemsPerPage == 0 ) { @@ -1195,24 +1186,15 @@ void comestible_inventory::recalc_pane() } //TODO: just put it as a part of the header instead of one of the items - // Insert category headers - if( pane.filter_show_food ) { - pane.items.push_back( comestible_inv_listitem( "FOOD" ) ); - } else { - pane.items.push_back( comestible_inv_listitem( "CHEMICALS" ) ); - } - + // Insert category headers (only expected when sorting by category) - //if (pane.sortby == COMESTIBLE_SORTBY_CATEGORY) { - // - // std::set categories; - // for (auto& it : pane.items) { - // categories.insert(it.cat); - // } - // for (auto& cat : categories) { - // pane.items.push_back(comestible_inv_listitem(cat)); - // } - //} + std::set categories; + for (auto& it : pane.items) { + categories.insert(it.cat); + } + for (auto& cat : categories) { + pane.items.push_back(comestible_inv_listitem(cat)); + } // Finally sort all items (category headers will now be moved to their proper position) std::stable_sort( pane.items.begin(), pane.items.end(), comestible_inv_sorter( pane.sortby ) ); @@ -2098,18 +2080,18 @@ void comestible_inventory::refresh_minimap() void comestible_inventory::draw_minimap() { // if player is in one of the below, invert the player cell - static const std::array player_locations = { - {AIM_CENTER, AIM_INVENTORY, AIM_WORN} - }; + //static const std::array player_locations = { + // {AIM_CENTER, AIM_INVENTORY, AIM_WORN} + //}; // get the center of the window - tripoint pc = { getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0 }; + //tripoint pc = { getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0 }; // draw the 3x3 tiles centered around player g->m.draw( minimap, g->u.pos() ); - auto sq = squares[pane.get_area()]; - auto pt = pc + sq.off; + //auto sq = squares[pane.get_area()]; + //auto pt = pc + sq.off; // invert the color if pointing to the player's position - auto cl = sq.id == AIM_INVENTORY || sq.id == AIM_WORN ? - invert_color( c_light_cyan ) : c_light_cyan.blink(); + //auto cl = sq.id == AIM_INVENTORY || sq.id == AIM_WORN ? + // invert_color( c_light_cyan ) : c_light_cyan.blink(); // Invert player's tile color if exactly one pane points to player's tile //bool invert_left = false; @@ -2219,10 +2201,10 @@ aim_location comestible_inventory::screen_relative_location( aim_location area ) } } -char *comestible_inventory::set_string_params( nc_color &print_color, int value, bool selected, +char const *comestible_inventory::set_string_params( nc_color &print_color, int value, bool selected, bool need_highlight ) { - char *string_format; + char const *string_format; if( value > 0 ) { print_color = need_highlight ? c_yellow_green : c_green; string_format = "+%d"; @@ -2420,12 +2402,13 @@ void comestible_inventory::heat_up( item *it_to_heat ) counter++; } - for each( item * var in hotplates ) { - sm.addentry( counter, true, counter, string_format( _( "%s in inventory" ), var->display_name() ) ); + for (size_t i = 0; i < hotplates.size(); i++) { + sm.addentry(counter, true, counter, string_format(_("%s in inventory"), hotplates.at(i)->display_name())); counter++; } - for each( item * var in hotplates_map ) { - sm.addentry( counter, true, counter, string_format( _( "%s nearby" ), var->display_name() ) ); + + for (size_t i = 0; i < hotplates_map.size(); i++) { + sm.addentry(counter, true, counter, string_format(_("%s nearby"), hotplates_map.at(i)->display_name())); counter++; } //sm.selected = pane.sortby - SORTBY_NONE; @@ -2448,7 +2431,7 @@ void comestible_inventory::heat_up( item *it_to_heat ) choice--; } item *it_choice; - if( choice < hotplates.size() ) { + if( static_cast(choice) < hotplates.size() ) { it_choice = hotplates[choice]; } else { choice -= hotplates.size(); diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 99ee1862aae30..22b639157be6a 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -213,11 +213,6 @@ struct comestible_inv_listitem { */ comestible_inv_listitem( const item_category *cat ); - /** - * Create a category header entry. - * @param cat The category name - */ - comestible_inv_listitem::comestible_inv_listitem( const std::string cat_name ); /** * Creates an empty entry, both category and item pointer are null. */ @@ -464,10 +459,10 @@ class comestible_inventory */ static aim_location screen_relative_location( aim_location area ); - char *comestible_inventory::set_string_params( nc_color &print_color, int value, bool selected, + char const *set_string_params( nc_color &print_color, int value, bool selected, bool need_highlight = false ); //nc_color set_string_params(int value, bool need_highlight = false); - time_duration comestible_inventory::get_time_left( player &p, const item &it ) const; + time_duration get_time_left( player &p, const item &it ) const; const islot_comestible &get_edible_comestible( player &p, const item &it ) const; std::string get_time_left_rounded( player &p, const item &it ) const; std::string time_to_comestible_str( const time_duration &d ) const; From 1fcc39e38cc141fe478e2e3979cae2a19479d44a Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 18 Aug 2019 16:30:53 -0400 Subject: [PATCH 03/19] clean up the code settings are saved within a session can actually eat now --- src/activity_handlers.cpp | 2 +- src/advanced_inv.cpp | 2 - src/comestible_inv.cpp | 849 ++++++++++++++------------------------ src/comestible_inv.h | 44 +- src/uistate.h | 30 +- 5 files changed, 367 insertions(+), 560 deletions(-) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index d73065f1db79d..ae86b319bc94c 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -2612,7 +2612,7 @@ void activity_handlers::adv_inventory_do_turn( player_activity *, player *p ) advanced_inv(); } -void activity_handlers::comestible_inventory_do_turn(player_activity*, player* p) +void activity_handlers::comestible_inventory_do_turn( player_activity *, player *p ) { p->cancel_activity(); comestible_inv(); diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index a84d03c3c6743..5c840c7805444 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -174,8 +174,6 @@ void advanced_inventory::load_settings() panes[i].filter = uistate.adv_inv_filter[i]; } uistate.adv_inv_exit_code = exit_none; - - add_msg(m_info, "~~~ %d %d", uistate.wishitem_selected, uistate.save_var); } std::string advanced_inventory::get_sortname( advanced_inv_sortby sortby ) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index b025ef6cf719e..2abccaff7365d 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -6,7 +6,6 @@ #include "catacharset.h" #include "debug.h" #include "field.h" -#include "game.h" #include "input.h" #include "item_category.h" #include "item_search.h" @@ -79,25 +78,28 @@ comestible_inventory::comestible_inventory() , redraw(true) , filter_edit(false) // panes don't need initialization, they are recalculated immediately - , squares({ - { - // hx hy x y z - { AIM_INVENTORY, 25, 2, {0, 0, 0}, _("Inventory"), _("IN") }, - { AIM_SOUTHWEST, 30, 3, { -1, 1, 0}, _("South West"), _("SW") }, - { AIM_SOUTH, 33, 3, {0, 1, 0}, _("South"), _("S") }, - { AIM_SOUTHEAST, 36, 3, {1, 1, 0}, _("South East"), _("SE") }, - { AIM_WEST, 30, 2, { -1, 0, 0}, _("West"), _("W") }, - { AIM_CENTER, 33, 2, {0, 0, 0}, _("Directly below you"), _("DN") }, - { AIM_EAST, 36, 2, {1, 0, 0}, _("East"), _("E") }, - { AIM_NORTHWEST, 30, 1, { -1, -1, 0}, _("North West"), _("NW") }, - { AIM_NORTH, 33, 1, {0, -1, 0}, _("North"), _("N") }, - { AIM_NORTHEAST, 36, 1, {1, -1, 0}, _("North East"), _("NE") }, - { AIM_DRAGGED, 25, 1, {0, 0, 0}, _("Grabbed Vehicle"), _("GR") }, - { AIM_ALL, 22, 3, {0, 0, 0}, _("Surrounding area"), _("AL") }, - { AIM_CONTAINER, 22, 1, {0, 0, 0}, _("Container"), _("CN") }, - { AIM_WORN, 25, 3, {0, 0, 0}, _("Worn Items"), _("WR") } - } - }) + ,squares({ + { + // hx hy + { AIM_INVENTORY, 25, 2, tripoint_zero, _("Inventory"), _("IN"), "I", AIM_INVENTORY, "ITEMS_INVENTORY" }, + + { AIM_SOUTHWEST, 30, 3, tripoint_south_west, _("South West"), _("SW"),"1",AIM_WEST ,"ITEMS_SW" }, + { AIM_SOUTH, 33, 3, tripoint_south, _("South"), _("S"),"2",AIM_SOUTHWEST ,"ITEMS_S"}, + { AIM_SOUTHEAST, 36, 3, tripoint_south_east, _("South East"), _("SE"),"3",AIM_SOUTH ,"ITEMS_SE"}, + { AIM_WEST, 30, 2, tripoint_west, _("West"), _("W"),"4",AIM_NORTHWEST ,"ITEMS_W" }, + { AIM_CENTER, 33, 2, tripoint_zero, _("Directly below you"), _("DN"),"5",AIM_CENTER ,"ITEMS_CE"}, + { AIM_EAST, 36, 2, tripoint_east, _("East"), _("E"),"6",AIM_SOUTHEAST ,"ITEMS_E" }, + { AIM_NORTHWEST, 30, 1, tripoint_north_west, _("North West"), _("NW"),"7",AIM_NORTH ,"ITEMS_NW"}, + { AIM_NORTH, 33, 1, tripoint_north, _("North"), _("N"),"8",AIM_NORTHEAST ,"ITEMS_N" }, + { AIM_NORTHEAST, 36, 1, tripoint_north_east, _("North East"), _("NE"),"9",AIM_EAST ,"ITEMS_NE" }, + + { AIM_DRAGGED, 25, 1, tripoint_zero, _("Grabbed Vehicle"), _("GR"),"D",AIM_DRAGGED ,"ITEMS_DRAGGED_CONTAINER" }, + { AIM_ALL, 22, 3, tripoint_zero, _("Surrounding area"), _("AL"),"A",AIM_ALL ,"ITEMS_AROUND" }, + { AIM_CONTAINER, 22, 1, tripoint_zero, _("Container"), _("CN"),"C",AIM_CONTAINER ,"ITEMS_CONTAINER"}, + { AIM_WORN, 25, 3, tripoint_zero, _("Worn Items"), _("WR"),"W",AIM_WORN ,"ITEMS_WORN"}, + //{ NUM_AIM_LOCATIONS, 22, 3, tripoint_zero, _("Surrounding area and Inventory"), _("A+I") } + } + }) { // initialize screen coordinates for small overview 3x3 grid, depending on control scheme if (tile_iso && use_tiles) { @@ -117,7 +119,7 @@ comestible_inventory::comestible_inventory() comestible_inventory::~comestible_inventory() { save_settings( false ); - auto &aim_code = uistate.adv_inv_exit_code; + auto &aim_code = uistate.comestible_save.exit_code; if( aim_code != exit_re_entry ) { aim_code = exit_okay; } @@ -133,27 +135,23 @@ comestible_inventory::~comestible_inventory() void comestible_inventory::save_settings( bool only_panes ) { - if (!only_panes) { - // uistate.adv_inv_last_coords = g->u.pos(); - // uistate.adv_inv_src = src; - // uistate.adv_inv_dest = dest; - } - uistate.adv_inv_in_vehicle[0] = pane.in_vehicle(); - uistate.adv_inv_area[0] = pane.get_area(); - uistate.adv_inv_index[0] = pane.index; - uistate.adv_inv_filter[0] = pane.filter; + if( !only_panes ) { + // uistate.adv_inv_last_coords = g->u.pos(); + // uistate.adv_inv_src = src; + // uistate.adv_inv_dest = dest; + } + uistate.comestible_save.in_vehicle = pane.in_vehicle(); + uistate.comestible_save.area_idx = pane.get_area(); + uistate.comestible_save.selected_idx = pane.index; + uistate.comestible_save.filter = pane.filter; } //TODO: fix settings void comestible_inventory::load_settings() { - aim_exit aim_code = static_cast( uistate.adv_inv_exit_code ); + aim_exit aim_code = static_cast( uistate.comestible_save.exit_code ); aim_location location; - if( get_option( "OPEN_DEFAULT_ADV_INV" ) ) { - location = static_cast( uistate.adv_inv_default_areas[0] ); - } else { - location = static_cast( uistate.adv_inv_area[0] ); - } + location = static_cast( uistate.comestible_save.area_idx ); auto square = squares[location]; // determine the square's vehicle/map item presence bool has_veh_items = square.can_store_in_vehicle() ? @@ -161,15 +159,15 @@ void comestible_inventory::load_settings() bool has_map_items = !g->m.i_at( square.pos ).empty(); // determine based on map items and settings to show cargo bool show_vehicle = aim_code == exit_re_entry ? - uistate.adv_inv_in_vehicle[0] : has_veh_items ? true : + uistate.comestible_save.in_vehicle : has_veh_items ? true : has_map_items ? false : square.can_store_in_vehicle(); pane.set_area( square, show_vehicle ); - //pane.sortby = static_cast(uistate.adv_inv_sort[0]); - pane.index = uistate.adv_inv_index[0]; - pane.filter = uistate.adv_inv_filter[0]; - uistate.adv_inv_exit_code = exit_none; + pane.sortby = static_cast( uistate.comestible_save.sort_idx ); + pane.index = uistate.comestible_save.selected_idx; + pane.filter = uistate.comestible_save.filter; + uistate.comestible_save.exit_code = exit_none; - pane.filter_show_food = true; + pane.filter_show_food = uistate.comestible_save.food_filter; } std::string comestible_inventory::get_sortname( comestible_inv_sortby sortby ) @@ -193,40 +191,14 @@ std::string comestible_inventory::get_sortname( comestible_inv_sortby sortby ) return "!BUG!"; } -bool comestible_inventory::get_square( const std::string &action, aim_location &ret ) +comestible_inv_area *comestible_inventory::get_square( const std::string &action ) { - if( action == "ITEMS_INVENTORY" ) { - ret = AIM_INVENTORY; - } else if( action == "ITEMS_WORN" ) { - ret = AIM_WORN; - } else if( action == "ITEMS_NW" ) { - ret = screen_relative_location( AIM_NORTHWEST ); - } else if( action == "ITEMS_N" ) { - ret = screen_relative_location( AIM_NORTH ); - } else if( action == "ITEMS_NE" ) { - ret = screen_relative_location( AIM_NORTHEAST ); - } else if( action == "ITEMS_W" ) { - ret = screen_relative_location( AIM_WEST ); - } else if( action == "ITEMS_CE" ) { - ret = AIM_CENTER; - } else if( action == "ITEMS_E" ) { - ret = screen_relative_location( AIM_EAST ); - } else if( action == "ITEMS_SW" ) { - ret = screen_relative_location( AIM_SOUTHWEST ); - } else if( action == "ITEMS_S" ) { - ret = screen_relative_location( AIM_SOUTH ); - } else if( action == "ITEMS_SE" ) { - ret = screen_relative_location( AIM_SOUTHEAST ); - } else if( action == "ITEMS_AROUND" ) { - ret = AIM_ALL; - } else if( action == "ITEMS_DRAGGED_CONTAINER" ) { - ret = AIM_DRAGGED; - } else if( action == "ITEMS_CONTAINER" ) { - ret = AIM_CONTAINER; - } else { - return false; + for( size_t i = 0; i < squares.size(); i++ ) { + if( action == squares[i].actionname ) { + return &squares[i]; + } } - return true; + return nullptr; } void comestible_inventory::print_items( comestible_inventory_pane &pane ) @@ -287,7 +259,7 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) format_volume( maxvolume ), volume_units_abbr() ); } - mvwprintz( window, 4, max_width - 1 - formatted_head.length(), norm, formatted_head ); + mvwprintz( window, point( max_width - 1 - formatted_head.length(), 4 ), norm, formatted_head ); } const size_t last_x = max_width - 2; @@ -319,7 +291,7 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) //~ Items list header. Table fields length without spaces: src - 2, amt - 4, weight - 5, vol - 4. //const int table_hdr_len2 = utf8_width( _( "src amt weight vol" ) ); // Header length type 2 - mvwprintz( window, 5, compact ? 1 : 4, c_light_gray, _( "Name (charges)" ) ); + mvwprintz( window, point( compact ? 1 : 4, 5 ), c_light_gray, _( "Name (charges)" ) ); //if (pane.get_area() == AIM_ALL && !compact) { // mvwprintz(window, 5, last_x - table_hdr_len2 + 1, c_light_gray, _("src amt weight vol")); // max_name_length = src_startpos - name_startpos - 1; // 1 for space @@ -328,14 +300,14 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) // mvwprintz(window, 5, last_x - table_hdr_len1 + 1, c_light_gray, _("amt weight vol")); //} - mvwprintz( window, 5, src_startpos, c_light_gray, _( "src" ) ); - mvwprintz( window, 5, amt_startpos + 1, c_light_gray, _( "amt" ) ); - mvwprintz( window, 5, weight_startpos, c_light_gray, _( "weight" ) ); - mvwprintz( window, 5, vol_startpos + 2, c_light_gray, _( "vol" ) ); - mvwprintz( window, 5, cal_startpos, c_light_gray, _( "calories" ) ); - mvwprintz( window, 5, quench_startpos, c_light_gray, _( "quench" ) ); - mvwprintz( window, 5, joy_startpos, c_light_gray, _( "joy" ) ); - mvwprintz( window, 5, expires_startpos, c_light_gray, _( "expires in" ) ); + mvwprintz( window, point( src_startpos, 5 ), c_light_gray, _( "src" ) ); + mvwprintz( window, point( amt_startpos + 1, 5 ), c_light_gray, _( "amt" ) ); + mvwprintz( window, point( weight_startpos, 5 ), c_light_gray, _( "weight" ) ); + mvwprintz( window, point( vol_startpos + 2, 5 ), c_light_gray, _( "vol" ) ); + mvwprintz( window, point( cal_startpos, 5 ), c_light_gray, _( "calories" ) ); + mvwprintz( window, point( quench_startpos, 5 ), c_light_gray, _( "quench" ) ); + mvwprintz( window, point( joy_startpos, 5 ), c_light_gray, _( "joy" ) ); + mvwprintz( window, point( expires_startpos, 5 ), c_light_gray, _( "expires in" ) ); player &p = g->u; @@ -343,7 +315,7 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) x < itemsPerPage; i++, x++ ) { const auto &sitem = items[i]; if( sitem.is_category_header() ) { - mvwprintz( window, 6 + x, ( max_width - utf8_width( sitem.name ) - 6 ) / 2, c_cyan, "[%s]", + mvwprintz( window, point( ( max_width - utf8_width( sitem.name ) - 6 ) / 2, 6 + x ), c_cyan, "[%s]", sitem.name ); continue; } @@ -365,9 +337,9 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) thiscolor = inCategoryMode ? c_white_red : hilite( c_white ); thiscolordark = hilite( thiscolordark ); if( compact ) { - mvwprintz( window, 6 + x, 1, thiscolor, " %s", spaces ); + mvwprintz( window, point( 1, 6 + x ), thiscolor, " %s", spaces ); } else { - mvwprintz( window, 6 + x, 1, thiscolor, ">>%s", spaces ); + mvwprintz( window, point( 1, 6 + x ), thiscolor, ">>%s", spaces ); } } @@ -407,12 +379,12 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) } //print item name - trim_and_print( window, 6 + x, compact ? 1 : 4, max_name_length, thiscolor, item_name ); + trim_and_print( window, point( compact ? 1 : 4, 6 + x ), max_name_length, thiscolor, item_name ); //print src column // TODO: specify this is coming from a vehicle! if( pane.get_area() == AIM_ALL && !compact ) { - mvwprintz( window, 6 + x, src_startpos, thiscolor, squares[sitem.area].shortname ); + mvwprintz( window, point( src_startpos, 6 + x ), thiscolor, squares[sitem.area].shortname ); } //print "amount" column @@ -423,7 +395,7 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) it_amt = 9999; print_color = selected ? hilite( c_red ) : c_red; } - mvwprintz( window, 6 + x, amt_startpos, print_color, "%4d", it_amt ); + mvwprintz( window, point( amt_startpos, 6 + x ), print_color, "%4d", it_amt ); } //print weight column @@ -442,7 +414,7 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) } else { w_precision = 2; } - mvwprintz( window, 6 + x, weight_startpos, print_color, "%5.*f", w_precision, it_weight ); + mvwprintz( window, point( weight_startpos, 6 + x ), print_color, "%5.*f", w_precision, it_weight ); //print volume column bool it_vol_truncated = false; @@ -453,10 +425,10 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) } else { print_color = sitem.volume.value() > 0 ? thiscolor : thiscolordark; } - mvwprintz( window, 6 + x, vol_startpos, print_color, it_vol ); + mvwprintz( window, point( vol_startpos, 6 + x ), print_color, it_vol ); if( sitem.autopickup ) { - mvwprintz( window, 6 + x, 1, magenta_background( it.color_in_inventory() ), + mvwprintz( window, point( 1, 6 + x ), magenta_background( it.color_in_inventory() ), compact ? it.tname().substr( 0, 1 ) : ">" ); } //get_consumable_item @@ -466,17 +438,17 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) //print "CALORIES" column int it_cal = p.kcal_for( it ); string_format = set_string_params( print_color, it_cal, selected ); - mvwprintz( window, 6 + x, cal_startpos, print_color, string_format, it_cal ); + mvwprintz( window, point( cal_startpos, 6 + x ), print_color, string_format, it_cal ); //print "QUENCH" column int it_q = it_c.quench; string_format = set_string_params( print_color, it_q, selected ); - mvwprintz( window, 6 + x, quench_startpos, print_color, string_format, it_q ); + mvwprintz( window, point( quench_startpos, 6 + x ), print_color, string_format, it_q ); //print "JOY" column int it_joy = p.fun_for( it ).first; string_format = set_string_params( print_color, it_joy, selected, it.has_flag( "MUSHY" ) ); - mvwprintz( window, 6 + x, joy_startpos, print_color, string_format, it_joy ); + mvwprintz( window, point( joy_startpos, 6 + x ), print_color, string_format, it_joy ); //TODO: g->u.can_estimate_rot() //print "SPOILS IN" column @@ -487,7 +459,7 @@ void comestible_inventory::print_items( comestible_inventory_pane &pane ) } } print_color = selected ? hilite( c_white ) : c_cyan; - mvwprintz( window, 6 + x, expires_startpos, print_color, "%s", it_spoils_string ); + mvwprintz( window, point( expires_startpos, 6 + x ), print_color, "%s", it_spoils_string ); /* append_cell( [ this, &p ]( const item_location & loc ) { @@ -607,97 +579,19 @@ struct comestible_inv_sorter { } }; -void comestible_inventory::menu_square( uilist &menu ) -{ - assert( menu.entries.size() >= 9 ); - int ofs = -25 - 4; - int sel = screen_relative_location( static_cast ( menu.selected + 1 ) ); - for( int i = 1; i < 10; i++ ) { - aim_location loc = screen_relative_location( static_cast ( i ) ); - char key = get_location_key( loc ); - bool in_vehicle = squares[loc].can_store_in_vehicle(); - const char *bracket = in_vehicle ? "<>" : "[]"; - // always show storage option for vehicle storage, if applicable - bool canputitems = menu.entries[i - 1].enabled && squares[loc].canputitems(); - nc_color bcolor = canputitems ? sel == loc ? h_white : c_light_gray : c_dark_gray; - nc_color kcolor = canputitems ? sel == loc ? h_white : c_light_gray : c_dark_gray; - const int x = squares[loc].hscreen.x + ofs; - const int y = squares[loc].hscreen.y + 5; - mvwprintz( menu.window, y, x, bcolor, "%c", bracket[0] ); - wprintz( menu.window, kcolor, "%c", key ); - wprintz( menu.window, bcolor, "%c", bracket[1] ); - } -} - -inline char comestible_inventory::get_location_key( aim_location area ) +inline std::string comestible_inventory::get_location_key( aim_location area ) { - switch( area ) { - case AIM_INVENTORY: - return 'I'; - case AIM_WORN: - return 'W'; - case AIM_CENTER: - return '5'; - case AIM_ALL: - return 'A'; - case AIM_DRAGGED: - return 'D'; - case AIM_CONTAINER: - return 'C'; - case AIM_NORTH: - case AIM_SOUTH: - case AIM_EAST: - case AIM_WEST: - case AIM_NORTHEAST: - case AIM_NORTHWEST: - case AIM_SOUTHEAST: - case AIM_SOUTHWEST: - return get_direction_key( area ); - default: - debugmsg( "invalid [aim_location] in get_location_key()!" ); - return ' '; - } -} - -char comestible_inventory::get_direction_key( aim_location area ) -{ - - if( area == screen_relative_location( AIM_SOUTHWEST ) ) { - return '1'; - } - if( area == screen_relative_location( AIM_SOUTH ) ) { - return '2'; - } - if( area == screen_relative_location( AIM_SOUTHEAST ) ) { - return '3'; - } - if( area == screen_relative_location( AIM_WEST ) ) { - return '4'; - } - if( area == screen_relative_location( AIM_EAST ) ) { - return '6'; - } - if( area == screen_relative_location( AIM_NORTHWEST ) ) { - return '7'; - } - if( area == screen_relative_location( AIM_NORTH ) ) { - return '8'; - } - if( area == screen_relative_location( AIM_NORTHEAST ) ) { - return '9'; - } - debugmsg( "invalid [aim_location] in get_direction_key()!" ); - return '0'; + return squares[squares[area].get_relative_location()].minimapname; } int comestible_inventory::print_header( comestible_inventory_pane &pane, aim_location sel ) { const catacurses::window &window = pane.window; - int area = pane.get_area(); + size_t area = pane.get_area(); int wwidth = getmaxx( window ); int ofs = wwidth - 25 - 2 - 14; - for( int i = 0; i < NUM_AIM_LOCATIONS; ++i ) { - const char key = get_location_key( static_cast( i ) ); + for( size_t i = 0; i < squares.size(); ++i ) { + std::string key = get_location_key( static_cast( i ) ); const char *bracket = squares[i].can_store_in_vehicle() ? "<>" : "[]"; bool in_vehicle = pane.in_vehicle() && squares[i].id == area && sel == area && area != AIM_ALL; bool all_brackets = area == AIM_ALL && ( i >= AIM_SOUTHWEST && i <= AIM_NORTHEAST ); @@ -710,8 +604,8 @@ int comestible_inventory::print_header( comestible_inventory_pane &pane, aim_loc } const int x = squares[i].hscreen.x + ofs; const int y = squares[i].hscreen.y; - mvwprintz( window, y, x, bcolor, "%c", bracket[0] ); - wprintz( window, kcolor, "%c", in_vehicle && sel != AIM_DRAGGED ? 'V' : key ); + mvwprintz( window, point( x, y ), bcolor, "%c", bracket[0] ); + wprintz( window, kcolor, "%s", in_vehicle && sel != AIM_DRAGGED ? "V" : key ); wprintz( window, bcolor, "%c", bracket[1] ); } return squares[AIM_INVENTORY].hscreen.y + ofs; @@ -872,12 +766,12 @@ void comestible_inventory::init() headstart = 0; //(TERMY>w_height)?(TERMY-w_height)/2:0; colstart = TERMX > w_width ? ( TERMX - w_width ) / 2 : 0; - head = catacurses::newwin( head_height, w_width - minimap_width, headstart, colstart ); - mm_border = catacurses::newwin( minimap_height + 2, minimap_width + 2, headstart, - colstart + ( w_width - ( minimap_width + 2 ) ) ); - minimap = catacurses::newwin( minimap_height, minimap_width, headstart + 1, - colstart + ( w_width - ( minimap_width + 1 ) ) ); - window = catacurses::newwin( w_height, w_width, headstart + head_height, colstart ); + head = catacurses::newwin( head_height, w_width - minimap_width, point( colstart, headstart ) ); + mm_border = catacurses::newwin( minimap_height + 2, minimap_width + 2, + point( colstart + ( w_width - ( minimap_width + 2 ) ), headstart ) ); + minimap = catacurses::newwin( minimap_height, minimap_width, + point( colstart + ( w_width - ( minimap_width + 1 ) ), headstart + 1 ) ); + window = catacurses::newwin( w_height, w_width, point( colstart, headstart + head_height ) ); itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff @@ -1142,14 +1036,16 @@ void comestible_inventory_pane::paginate( size_t itemsPerPage ) void comestible_inventory::recalc_pane() { + add_msg( m_info, "~~~~~~~~~ here" ); + pane.recalc = false; pane.items.clear(); // Add items from the source location or in case of all 9 surrounding squares, // add items from several locations. if( pane.get_area() == AIM_ALL ) { auto &alls = squares[AIM_ALL]; - auto &there = pane;// s[-p + 1]; - auto &other = squares[there.get_area()]; + //auto &there = pane;// s[-p + 1]; + //auto &other = squares[there.get_area()]; alls.volume = 0_ml; alls.weight = 0_gram; for( auto &s : squares ) { @@ -1158,42 +1054,33 @@ void comestible_inventory::recalc_pane() continue; } - // To allow the user to transfer all items from all surrounding squares to - // a specific square, filter out items that are already on that square. - // e.g. left pane AIM_ALL, right pane AIM_NORTH. The user holds the - // enter key down in the left square and moves all items to the other side. - const bool same = other.is_same( s ); - // Deal with squares with ground + vehicle storage // Also handle the case when the other tile covers vehicle // or the ground below the vehicle. - if( s.can_store_in_vehicle() && !( same && there.in_vehicle() ) ) { - bool do_vehicle = there.get_area() == s.id ? !there.in_vehicle() : true; - pane.add_items_from_area( s, do_vehicle ); + if( s.can_store_in_vehicle() ) { + pane.add_items_from_area( s, true ); alls.volume += s.volume; alls.weight += s.weight; } // Add map items - if( !same || there.in_vehicle() ) { - pane.add_items_from_area( s ); - alls.volume += s.volume; - alls.weight += s.weight; - } + pane.add_items_from_area( s ); + alls.volume += s.volume; + alls.weight += s.weight; } } else { pane.add_items_from_area( squares[pane.get_area()] ); } //TODO: just put it as a part of the header instead of one of the items - + // Insert category headers (only expected when sorting by category) - std::set categories; - for (auto& it : pane.items) { - categories.insert(it.cat); + std::set categories; + for( auto &it : pane.items ) { + categories.insert( it.cat ); } - for (auto& cat : categories) { - pane.items.push_back(comestible_inv_listitem(cat)); + for( auto &cat : categories ) { + pane.items.push_back( comestible_inv_listitem( cat ) ); } // Finally sort all items (category headers will now be moved to their proper position) @@ -1218,9 +1105,6 @@ void comestible_inventory_pane::fix_index() void comestible_inventory::redraw_pane() { // don't update ui if processing demands - if( is_processing() ) { - return; - } if( recalc || pane.recalc ) { recalc_pane(); } else if( !( redraw || pane.redraw ) ) { @@ -1246,45 +1130,45 @@ void comestible_inventory::redraw_pane() auto name = utf8_truncate( car ? sq.veh->name : sq.name, width ); auto desc = utf8_truncate( sq.desc[car], width ); width -= 2 + 1; // starts at offset 2, plus space between the header and the text - mvwprintz( w, 1, 2, c_green, name ); - mvwprintz( w, 2, 2, c_light_blue, desc ); - trim_and_print( w, 3, 2, width, c_cyan, square.flags ); + mvwprintz( w, point( 2, 1 ), c_green, name ); + mvwprintz( w, point( 2, 2 ), c_light_blue, desc ); + trim_and_print( w, point( 2, 3 ), width, c_cyan, square.flags ); const int max_page = ( pane.items.size() + itemsPerPage - 1 ) / itemsPerPage; if( max_page > 1 ) { const int page = pane.index / itemsPerPage; - mvwprintz( w, 4, 2, c_light_blue, _( "[<] page %d of %d [>]" ), page + 1, max_page ); + mvwprintz( w, point( 2, 4 ), c_light_blue, _( "[<] page %d of %d [>]" ), page + 1, max_page ); } wattron( w, c_cyan ); // draw a darker border around the inactive pane draw_border( w, BORDER_COLOR ); - mvwprintw( w, 0, 3, _( "< [s]ort: %s >" ), get_sortname( pane.sortby ) ); + mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), get_sortname( pane.sortby ) ); int max = square.max_size; if( max > 0 ) { int itemcount = square.get_item_count(); int fmtw = 7 + ( itemcount > 99 ? 3 : itemcount > 9 ? 2 : 1 ) + ( max > 99 ? 3 : max > 9 ? 2 : 1 ); - mvwprintw( w, 0, w_width / 2 - fmtw, "< %d/%d >", itemcount, max ); + mvwprintw( w, point( w_width / 2 - fmtw, 0 ), "< %d/%d >", itemcount, max ); } const char *fprefix = _( "[F]ilter" ); const char *fsuffix = _( "[R]eset" ); if( !filter_edit ) { if( !pane.filter.empty() ) { - mvwprintw( w, getmaxy( w ) - 1, 2, "< %s: %s >", fprefix, pane.filter ); + mvwprintw( w, point( 2, getmaxy( w ) - 1 ), "< %s: %s >", fprefix, pane.filter ); } else { - mvwprintw( w, getmaxy( w ) - 1, 2, "< %s >", fprefix ); + mvwprintw( w, point( 2, getmaxy( w ) - 1 ), "< %s >", fprefix ); } } wattroff( w, c_white ); if( !filter_edit && !pane.filter.empty() ) { - mvwprintz( w, getmaxy( w ) - 1, 6 + std::strlen( fprefix ), c_white, + mvwprintz( w, point( 6 + std::strlen( fprefix ), getmaxy( w ) - 1 ), c_white, pane.filter ); - mvwprintz( w, getmaxy( w ) - 1, - getmaxx( w ) - std::strlen( fsuffix ) - 2, c_white, "%s", fsuffix ); + mvwprintz( w, point( getmaxx( w ) - std::strlen( fsuffix ) - 2, getmaxy( w ) - 1 ), c_white, "%s", + fsuffix ); } wrefresh( w ); } @@ -1325,21 +1209,21 @@ static tripoint aim_vector( aim_location id ) { switch( id ) { case AIM_SOUTHWEST: - return tripoint( -1, 1, 0 ); + return tripoint_south_west; case AIM_SOUTH: - return tripoint( 0, 1, 0 ); + return tripoint_south; case AIM_SOUTHEAST: - return tripoint( 1, 1, 0 ); + return tripoint_south_east; case AIM_WEST: - return tripoint( -1, 0, 0 ); + return tripoint_west; case AIM_EAST: - return tripoint( 1, 0, 0 ); + return tripoint_east; case AIM_NORTHWEST: - return tripoint( -1, -1, 0 ); + return tripoint_north_west; case AIM_NORTH: - return tripoint( 0, -1, 0 ); + return tripoint_north; case AIM_NORTHEAST: - return tripoint( 1, -1, 0 ); + return tripoint_north_east; default: return tripoint_zero; } @@ -1387,6 +1271,7 @@ void comestible_inventory::display() ctxt.register_action( "ITEMS_DEFAULT" ); ctxt.register_action( "SAVE_DEFAULT" ); + ctxt.register_action( "CONSUME_FOOD" ); ctxt.register_action( "SWITCH_FOOD" ); ctxt.register_action( "HEAT_UP" ); @@ -1402,7 +1287,7 @@ void comestible_inventory::display() redraw_pane(); - if( redraw && !is_processing() ) { + if( redraw ) { werase( head ); werase( minimap ); werase( mm_border ); @@ -1410,12 +1295,11 @@ void comestible_inventory::display() Messages::display_messages( head, 2, 1, w_width - 1, head_height - 2 ); draw_minimap(); const std::string msg = _( "< [?] show help >" ); - mvwprintz( head, 0, - w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, + mvwprintz( head, point( w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, 0 ), c_white, msg ); if( g->u.has_watch() ) { const std::string time = to_string_time_of_day( calendar::turn ); - mvwprintz( head, 0, 2, c_white, time ); + mvwprintz( head, point( 2, 0 ), c_white, time ); } wrefresh( head ); refresh_minimap(); @@ -1425,7 +1309,8 @@ void comestible_inventory::display() // current item in source pane, might be null comestible_inv_listitem *sitem = pane.get_cur_item_ptr(); - aim_location changeSquare = NUM_AIM_LOCATIONS; + //aim_location changeSquare = NUM_AIM_LOCATIONS; + comestible_inv_area *new_square; const std::string action = ctxt.handle_input(); if( action == "CATEGORY_SELECTION" ) { @@ -1433,42 +1318,30 @@ void comestible_inventory::display() pane.redraw = true; // We redraw to force the color change of the highlighted line and header text. } else if( action == "HELP_KEYBINDINGS" ) { redraw = true; - } else if( action == "ITEMS_DEFAULT" ) { - aim_location location = static_cast( uistate.adv_inv_default_areas[0] ); - if( pane.get_area() != location || location == AIM_ALL ) { - pane.recalc = true; - } - pane.set_area( squares[location] ); - redraw = true; - } else if( action == "SAVE_DEFAULT" ) { - uistate.adv_inv_default_areas[0] = pane.get_area(); - popup( _( "Default layout was saved." ) ); - redraw = true; - } else if( get_square( action, changeSquare ) ) { - if( pane.get_area() == changeSquare ) { + } else if( ( new_square = get_square( action ) ) != nullptr ) { + if( pane.get_area() == new_square->get_relative_location() ) { //DO NOTHING - } else if( squares[changeSquare].canputitems( pane.get_cur_item_ptr() ) ) { + } else if( new_square->canputitems( pane.get_cur_item_ptr() ) ) { bool in_vehicle_cargo = false; - if( changeSquare == AIM_CONTAINER ) { - squares[changeSquare].set_container( pane.get_cur_item_ptr() ); + if( new_square->get_relative_location() == AIM_CONTAINER ) { + new_square->set_container( pane.get_cur_item_ptr() ); } else if( pane.get_area() == AIM_CONTAINER ) { - squares[changeSquare].set_container( nullptr ); + new_square->set_container( nullptr ); // auto select vehicle if items exist at said square, or both are empty - } else if( squares[changeSquare].can_store_in_vehicle() ) { - if( changeSquare == AIM_DRAGGED ) { + } else if( new_square->can_store_in_vehicle() ) { + if( new_square->get_relative_location() == AIM_DRAGGED ) { in_vehicle_cargo = true; } else { // check item stacks in vehicle and map at said square - auto sq = squares[changeSquare]; - auto map_stack = g->m.i_at( sq.pos ); - auto veh_stack = sq.veh->get_items( sq.vstor ); + auto map_stack = g->m.i_at( new_square->pos ); + auto veh_stack = new_square->veh->get_items( new_square->vstor ); // auto switch to vehicle storage if vehicle items are there, or neither are there if( !veh_stack.empty() || map_stack.empty() ) { in_vehicle_cargo = true; } } } - pane.set_area( squares[changeSquare], in_vehicle_cargo ); + pane.set_area( *new_square, in_vehicle_cargo ); pane.index = 0; pane.recalc = true; redraw = true; @@ -1492,9 +1365,7 @@ void comestible_inventory::display() } else if( action == "SORT" ) { if( show_sort_menu( pane ) ) { recalc = true; - - //TODO: find all uistate, no settings? - uistate.adv_inv_sort[0] = pane.sortby; + uistate.comestible_save.sort_idx = pane.sortby; } redraw = true; } else if( action == "FILTER" ) { @@ -1514,8 +1385,8 @@ void comestible_inventory::display() #endif do { - mvwprintz( pane.window, getmaxy( pane.window ) - 1, 2, c_cyan, "< " ); - mvwprintz( pane.window, getmaxy( pane.window ) - 1, w_width / 2 - 4, c_cyan, " >" ); + mvwprintz( pane.window, point( 2, getmaxy( pane.window ) - 1 ), c_cyan, "< " ); + mvwprintz( pane.window, point( w_width / 2 - 4, getmaxy( pane.window ) - 1 ), c_cyan, " >" ); std::string new_filter = spopup.query_string( false ); if( spopup.context().get_raw_input().get_first_input() == KEY_ESCAPE ) { // restore original filter @@ -1623,6 +1494,41 @@ void comestible_inventory::display() recalc = true; } else if( action == "HEAT_UP" ) { heat_up( sitem->items.front() ); + } else if( action == "CONSUME_FOOD" ) { + player &p = g->u; + item *it = sitem->items.front(); + int pos = p.get_item_position( it ); + if( pos != INT_MIN ) { + p.consume( pos ); + + } else if( p.consume_item( *it ) ) { + if( it->is_food_container() ) { + it->contents.erase( it->contents.begin() ); + add_msg( _( "You leave the empty %s." ), it->tname() ); + } else { + tripoint target = p.pos() + squares[sitem->area].off; + item_location loc; + if( sitem->from_vehicle ) { + const cata::optional vp = g->m.veh_at( target ).part_with_feature( "CARGO", true ); + if( !vp ) { + add_msg( _( "~~~~~~~~~ not vehicle?" ) ); + return; + } + vehicle *const veh = &vp->vehicle(); + const int part = vp->part_index(); + + loc = item_location( vehicle_cursor( *veh, part ), it ); + } else { + if( sitem->area == AIM_INVENTORY || sitem->area == AIM_WORN ) { + loc = item_location( p, it ); + } else { + loc = item_location( map_cursor( target ), it ); + } + } + + loc.remove_item(); + } + } } } } @@ -1737,7 +1643,7 @@ bool comestible_inventory::move_content( item &src_container, item &dest_contain } dest_container.fill_with( src_contents, amount ); - uistate.adv_inv_container_content_type = dest_container.contents.front().typeId(); + uistate.comestible_save.container_content_type = dest_container.contents.front().typeId(); if( src_contents.charges <= 0 ) { src_container.contents.clear(); } @@ -1753,131 +1659,6 @@ units::volume comestible_inv_area::free_volume( bool in_vehicle ) const } return in_vehicle ? veh->free_volume( vstor ) : g->m.free_volume( pos ); } -// -//bool comestible_inventory::query_charges(aim_location destarea, const comestible_inv_listitem& sitem, -// const std::string& action, int& amount) -//{ -// assert(destarea != AIM_ALL); // should be a specific location instead -// assert(!sitem.items.empty()); // valid item is obviously required -// const item& it = *sitem.items.front(); -// comestible_inv_area& p = squares[destarea]; -// const bool by_charges = it.count_by_charges(); -// const units::volume free_volume = p.free_volume(panes[dest].in_vehicle()); -// // default to move all, unless if being equipped -// const int input_amount = by_charges ? it.charges : action == "MOVE_SINGLE_ITEM" ? 1 : sitem.stacks; -// assert(input_amount > 0); // there has to be something to begin with -// amount = input_amount; -// -// // Includes moving from/to inventory and around on the map. -// if (it.made_of_from_type(LIQUID)) { -// popup(_("You can't pick up a liquid.")); -// redraw = true; -// return false; -// } -// -// // Check volume, this should work the same for inventory, map and vehicles, but not for worn -// const int room_for = it.charges_per_volume(free_volume); -// if (amount > room_for && squares[destarea].id != AIM_WORN) { -// if (room_for <= 0) { -// popup(_("Destination area is full. Remove some items first.")); -// redraw = true; -// return false; -// } -// amount = std::min(room_for, amount); -// } -// // Map and vehicles have a maximal item count, check that. Inventory does not have this. -// if (destarea != AIM_INVENTORY && -// destarea != AIM_WORN && -// destarea != AIM_CONTAINER) { -// const int cntmax = p.max_size - p.get_item_count(); -// // For items counted by charges, adding it adds 0 items if something there stacks with it. -// const bool adds0 = by_charges && std::any_of(pane.items.begin(), pane.items.end(), -// [&it](const comestible_inv_listitem& li) { -// return li.is_item_entry() && li.items.front()->stacks_with(it); -// }); -// if (cntmax <= 0 && !adds0) { -// popup(_("Destination area has too many items. Remove some first.")); -// redraw = true; -// return false; -// } -// // Items by charge count as a single item, regardless of the charges. As long as the -// // destination can hold another item, one can move all charges. -// if (!by_charges) { -// amount = std::min(cntmax, amount); -// } -// } -// // Inventory has a weight capacity, map and vehicle don't have that -// if (destarea == AIM_INVENTORY || destarea == AIM_WORN) { -// const units::mass unitweight = it.weight() / (by_charges ? it.charges : 1); -// const units::mass max_weight = g->u.has_trait(trait_id("DEBUG_STORAGE")) ? -// units::mass_max : g->u.weight_capacity() * 4 - g->u.weight_carried(); -// if (unitweight > 0_gram && unitweight * amount > max_weight) { -// const int weightmax = max_weight / unitweight; -// if (weightmax <= 0) { -// popup(_("This is too heavy!")); -// redraw = true; -// return false; -// } -// amount = std::min(weightmax, amount); -// } -// } -// // handle how many of armor type we can equip (max of 2 per type) -// if (destarea == AIM_WORN) { -// const auto& id = sitem.items.front()->typeId(); -// // how many slots are available for the item? -// const int slots_available = MAX_WORN_PER_TYPE - g->u.amount_worn(id); -// // base the amount to equip on amount of slots available -// amount = std::min(slots_available, input_amount); -// } -// // Now we have the final amount. Query if requested or limited room left. -// if (action == "MOVE_VARIABLE_ITEM" || amount < input_amount) { -// const int count = by_charges ? it.charges : sitem.stacks; -// const char* msg = nullptr; -// std::string popupmsg; -// if (amount >= input_amount) { -// msg = _("How many do you want to move? [Have %d] (0 to cancel)"); -// popupmsg = string_format(msg, count); -// } -// else { -// msg = _("Destination can only hold %d! Move how many? [Have %d] (0 to cancel)"); -// popupmsg = string_format(msg, amount, count); -// } -// // At this point amount contains the maximal amount that the destination can hold. -// const int possible_max = std::min(input_amount, amount); -// if (amount <= 0) { -// popup(_("The destination is already full!")); -// } -// else { -// amount = string_input_popup() -// .title(popupmsg) -// .width(20) -// .only_digits(true) -// .query_int(); -// } -// if (amount <= 0) { -// redraw = true; -// return false; -// } -// if (amount > possible_max) { -// amount = possible_max; -// } -// } -// return true; -//} - -bool comestible_inv_area::is_same( const comestible_inv_area &other ) const -{ - // All locations (sans the below) are compared by the coordinates, - // e.g. dragged vehicle (to the south) and AIM_SOUTH are the same. - if( id != AIM_INVENTORY && other.id != AIM_INVENTORY && - id != AIM_WORN && other.id != AIM_WORN && - id != AIM_CONTAINER && other.id != AIM_CONTAINER ) { - // have a vehicle?... ...do the cargo index and pos match?... ...at least pos? - return veh == other.veh ? pos == other.pos && vstor == other.vstor : pos == other.pos; - } - // ...is the id? - return id == other.id; -} bool comestible_inv_area::canputitems( const comestible_inv_listitem *advitem ) { @@ -1908,14 +1689,14 @@ item *comestible_inv_area::get_container( bool in_vehicle ) { item *container = nullptr; - if( uistate.adv_inv_container_location != -1 ) { + if( uistate.comestible_save.container_location != -1 ) { // try to find valid container in the area - if( uistate.adv_inv_container_location == AIM_INVENTORY ) { + if( uistate.comestible_save.container_location == AIM_INVENTORY ) { const invslice &stacks = g->u.inv.slice(); // check index first - if( stacks.size() > static_cast( uistate.adv_inv_container_index ) ) { - auto &it = stacks[uistate.adv_inv_container_index]->front(); + if( stacks.size() > static_cast( uistate.comestible_save.container_index ) ) { + auto &it = stacks[uistate.comestible_save.container_index]->front(); if( is_container_valid( &it ) ) { container = ⁢ } @@ -1927,14 +1708,14 @@ item *comestible_inv_area::get_container( bool in_vehicle ) auto &it = stacks[x]->front(); if( is_container_valid( &it ) ) { container = ⁢ - uistate.adv_inv_container_index = x; + uistate.comestible_save.container_index = x; break; } } } - } else if( uistate.adv_inv_container_location == AIM_WORN ) { + } else if( uistate.comestible_save.container_location == AIM_WORN ) { auto &worn = g->u.worn; - size_t idx = static_cast( uistate.adv_inv_container_index ); + size_t idx = static_cast( uistate.comestible_save.container_index ); if( worn.size() > idx ) { auto iter = worn.begin(); std::advance( iter, idx ); @@ -1949,7 +1730,7 @@ item *comestible_inv_area::get_container( bool in_vehicle ) for( size_t i = 0; i < worn.size(); ++i, ++iter ) { if( is_container_valid( &*iter ) ) { container = &*iter; - uistate.adv_inv_container_index = i; + uistate.comestible_save.container_index = i; break; } } @@ -1957,15 +1738,15 @@ item *comestible_inv_area::get_container( bool in_vehicle ) } else { map &m = g->m; bool is_in_vehicle = veh && - ( uistate.adv_inv_container_in_vehicle || ( can_store_in_vehicle() && in_vehicle ) ); + ( uistate.comestible_save.in_vehicle || ( can_store_in_vehicle() && in_vehicle ) ); const itemstack &stacks = is_in_vehicle ? i_stacked( veh->get_items( vstor ) ) : i_stacked( m.i_at( pos ) ); // check index first - if( stacks.size() > static_cast( uistate.adv_inv_container_index ) ) { - auto it = stacks[uistate.adv_inv_container_index].front(); + if( stacks.size() > static_cast( uistate.comestible_save.container_index ) ) { + auto it = stacks[uistate.comestible_save.container_index].front(); if( is_container_valid( it ) ) { container = it; } @@ -1977,7 +1758,7 @@ item *comestible_inv_area::get_container( bool in_vehicle ) auto it = stacks[x].front(); if( is_container_valid( it ) ) { container = it; - uistate.adv_inv_container_index = x; + uistate.comestible_save.container_index = x; break; } } @@ -1998,32 +1779,32 @@ void comestible_inv_area::set_container( const comestible_inv_listitem *advitem { if( advitem != nullptr ) { item *it( advitem->items.front() ); - uistate.adv_inv_container_location = advitem->area; - uistate.adv_inv_container_in_vehicle = advitem->from_vehicle; - uistate.adv_inv_container_index = advitem->idx; - uistate.adv_inv_container_type = it->typeId(); - uistate.adv_inv_container_content_type = !it->is_container_empty() ? + uistate.comestible_save.container_location = advitem->area; + uistate.comestible_save.in_vehicle = advitem->from_vehicle; + uistate.comestible_save.container_index = advitem->idx; + uistate.comestible_save.container_type = it->typeId(); + uistate.comestible_save.container_content_type = !it->is_container_empty() ? it->contents.front().typeId() : "null"; set_container_position(); } else { - uistate.adv_inv_container_location = -1; - uistate.adv_inv_container_index = 0; - uistate.adv_inv_container_in_vehicle = false; - uistate.adv_inv_container_type = "null"; - uistate.adv_inv_container_content_type = "null"; + uistate.comestible_save.container_location = -1; + uistate.comestible_save.container_index = 0; + uistate.comestible_save.in_vehicle = false; + uistate.comestible_save.container_type = "null"; + uistate.comestible_save.container_content_type = "null"; } } bool comestible_inv_area::is_container_valid( const item *it ) const { if( it != nullptr ) { - if( it->typeId() == uistate.adv_inv_container_type ) { + if( it->typeId() == uistate.comestible_save.container_type ) { if( it->is_container_empty() ) { - if( uistate.adv_inv_container_content_type == "null" ) { + if( uistate.comestible_save.container_content_type == "null" ) { return true; } } else { - if( it->contents.front().typeId() == uistate.adv_inv_container_content_type ) { + if( it->contents.front().typeId() == uistate.comestible_save.container_content_type ) { return true; } } @@ -2036,10 +1817,10 @@ bool comestible_inv_area::is_container_valid( const item *it ) const void comestible_inv_area::set_container_position() { // update the offset of the container based on location - if( uistate.adv_inv_container_location == AIM_DRAGGED ) { + if( uistate.comestible_save.container_location == AIM_DRAGGED ) { off = g->u.grab_point; } else { - off = aim_vector( static_cast( uistate.adv_inv_container_location ) ); + off = aim_vector( static_cast( uistate.comestible_save.container_location ) ); } // update the absolute position pos = g->u.pos() + off; @@ -2054,23 +1835,71 @@ void comestible_inv_area::set_container_position() } } +static const trait_id trait_GRAZER( "GRAZER" ); +static const trait_id trait_RUMINANT( "RUMINANT" ); void comestible_inv() { + player &p = g->u; + map &m = g->m; + + if( ( p.has_active_mutation( trait_RUMINANT ) || p.has_active_mutation( trait_GRAZER ) ) && + ( m.ter( p.pos() ) == t_underbrush || m.ter( p.pos() ) == t_shrub ) ) { + if( p.get_hunger() < 20 ) { + add_msg( _( "You're too full to eat the leaves from the %s." ), m.ter( p.pos() )->name() ); + return; + } else { + p.moves -= 400; + m.ter_set( p.pos(), t_grass ); + add_msg( _( "You eat the underbrush." ) ); + item food( "underbrush", calendar::turn, 1 ); + p.eat( food ); + return; + } + } + if( p.has_active_mutation( trait_GRAZER ) && ( m.ter( p.pos() ) == t_grass || + m.ter( p.pos() ) == t_grass_long || m.ter( p.pos() ) == t_grass_tall ) ) { + if( p.get_hunger() < 8 ) { + add_msg( _( "You're too full to graze." ) ); + return; + } else { + p.moves -= 400; + add_msg( _( "You eat the grass." ) ); + item food( item( "grass", calendar::turn, 1 ) ); + p.eat( food ); + m.ter_set( p.pos(), t_dirt ); + if( m.ter( p.pos() ) == t_grass_tall ) { + m.ter_set( p.pos(), t_grass_long ); + } else if( m.ter( p.pos() ) == t_grass_long ) { + m.ter_set( p.pos(), t_grass ); + } else { + m.ter_set( p.pos(), t_dirt ); + } + return; + } + } + if( p.has_active_mutation( trait_GRAZER ) ) { + if( m.ter( p.pos() ) == t_grass_golf ) { + add_msg( _( "This grass is too short to graze." ) ); + return; + } else if( m.ter( p.pos() ) == t_grass_dead ) { + add_msg( _( "This grass is dead and too mangled for you to graze." ) ); + return; + } else if( m.ter( p.pos() ) == t_grass_white ) { + add_msg( _( "This grass is tainted with paint and thus inedible." ) ); + return; + } + } comestible_inventory new_inv; new_inv.display(); } void comestible_inventory::refresh_minimap() { - // don't update ui if processing demands - if( is_processing() ) { - return; - } // redraw border around minimap draw_border( mm_border ); // minor addition to border for AIM_ALL, sorta hacky if( pane.get_area() == AIM_ALL ) { - mvwprintz( mm_border, 0, 1, c_light_gray, utf8_truncate( _( "All" ), minimap_width ) ); + mvwprintz( mm_border, point( 1, 0 ), c_light_gray, utf8_truncate( _( "All" ), minimap_width ) ); } // refresh border, then minimap wrefresh( mm_border ); @@ -2080,128 +1909,85 @@ void comestible_inventory::refresh_minimap() void comestible_inventory::draw_minimap() { // if player is in one of the below, invert the player cell - //static const std::array player_locations = { - // {AIM_CENTER, AIM_INVENTORY, AIM_WORN} - //}; + static const std::array player_locations = { + {AIM_CENTER, AIM_INVENTORY, AIM_WORN} + }; // get the center of the window - //tripoint pc = { getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0 }; + tripoint pc = { getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0 }; // draw the 3x3 tiles centered around player g->m.draw( minimap, g->u.pos() ); - //auto sq = squares[pane.get_area()]; - //auto pt = pc + sq.off; - // invert the color if pointing to the player's position - //auto cl = sq.id == AIM_INVENTORY || sq.id == AIM_WORN ? - // invert_color( c_light_cyan ) : c_light_cyan.blink(); + char sym = get_minimap_sym(); + if( sym != '\0' ) { + auto sq = squares[pane.get_area()]; + auto pt = pc + sq.off; + // invert the color if pointing to the player's position + auto cl = sq.id == AIM_INVENTORY || sq.id == AIM_WORN ? + invert_color( c_light_cyan ) : c_light_cyan.blink(); + mvwputch( minimap, pt.xy(), cl, sym ); + } // Invert player's tile color if exactly one pane points to player's tile - //bool invert_left = false; - //bool invert_right = false; - //const auto is_selected = [this](const aim_location& where, size_t side) { - // return where == this->panes[side].get_area(); + bool player_selected = false; + //const auto is_selected = [this](const aim_location& where) { + // return where == this->pane.get_area(); //}; - //for (auto& loc : player_locations) { - // invert_left |= is_selected(loc, 0); - // invert_right |= is_selected(loc, 1); - //} + for( auto &loc : player_locations ) { + if( loc == pane.get_area() ) { + player_selected = true; + break; + } + } - //if (!invert_left || !invert_right) { - // g->u.draw(minimap, g->u.pos(), invert_left || invert_right); - //} - g->u.draw( minimap, g->u.pos(), false ); -} + g->u.draw( minimap, g->u.pos(), player_selected ); -//char comestible_inventory::get_minimap_sym(side p) const -//{ -// static const std::array c_side = { {'L', 'R'} }; -// static const std::array d_side = { {'^', 'v'} }; -// static const std::array g_nome = { { -// '@', '#', '#', '#', '#', '@', '#', -// '#', '#', '#', 'D', '^', 'C', '@' -// } -// }; -// char ch = g_nome[pane.get_area()]; -// -// -// //TODO: don't get this code exactly, just simplify for now -// ch = pane.in_vehicle() ? 'V' : c_side[p]; -// -// switch (ch) { -// case '@': // '^' or 'v' -// ch = d_side[panes[-p + 1].get_area() == AIM_CENTER]; -// break; -// case '#': // 'L' or 'R' -// ch = panes[p].in_vehicle() ? 'V' : c_side[p]; -// break; -// case '^': // do not show anything -// ch ^= ch; -// break; -// } -// return ch; -//} + //if (player_selected) { + //} +} -aim_location comestible_inv_area::offset_to_location() const +char comestible_inventory::get_minimap_sym() const { - static aim_location loc_array[3][3] = { - {AIM_NORTHWEST, AIM_NORTH, AIM_NORTHEAST}, - {AIM_WEST, AIM_CENTER, AIM_EAST}, - {AIM_SOUTHWEST, AIM_SOUTH, AIM_SOUTHEAST} + static const std::array g_nome = { { + '@', '#', '#', '#', '#', '@', '#', + '#', '#', '#', 'D', '^', 'C', '@' + } }; - return loc_array[off.y + 1][off.x + 1]; + char ch = g_nome[pane.get_area()]; + switch( ch ) { + case '@': + ch = '^'; + break; + case '#': + ch = pane.in_vehicle() ? 'V' : '\0'; + break; + case '^': // do not show anything + ch = '\0'; + break; + } + return ch; } +//aim_location comestible_inv_area::offset_to_location() const +//{ +// static aim_location loc_array[3][3] = { +// {AIM_NORTHWEST, AIM_NORTH, AIM_NORTHEAST}, +// {AIM_WEST, AIM_CENTER, AIM_EAST}, +// {AIM_SOUTHWEST, AIM_SOUTH, AIM_SOUTHEAST} +// }; +// return loc_array[off.y + 1][off.x + 1]; +//} + void comestible_inventory::do_return_entry() { // only save pane settings //save_settings(true); g->u.assign_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ); g->u.activity.auto_resume = true; - uistate.adv_inv_exit_code = exit_re_entry; + uistate.comestible_save.exit_code = exit_re_entry; } -bool comestible_inventory::is_processing() const -{ - return uistate.adv_inv_re_enter_move_all != ENTRY_START; -} - -aim_location comestible_inventory::screen_relative_location( aim_location area ) -{ - - if( !( tile_iso && use_tiles ) ) { - return area; - } - switch( area ) { - - case AIM_SOUTHWEST: - return AIM_WEST; - - case AIM_SOUTH: - return AIM_SOUTHWEST; - - case AIM_SOUTHEAST: - return AIM_SOUTH; - - case AIM_WEST: - return AIM_NORTHWEST; - - case AIM_EAST: - return AIM_SOUTHEAST; - - case AIM_NORTHWEST: - return AIM_NORTH; - - case AIM_NORTH: - return AIM_NORTHEAST; - - case AIM_NORTHEAST: - return AIM_EAST; - - default: - return area; - } -} - -char const *comestible_inventory::set_string_params( nc_color &print_color, int value, bool selected, +char const *comestible_inventory::set_string_params( nc_color &print_color, int value, + bool selected, bool need_highlight ) { char const *string_format; @@ -2402,13 +2188,15 @@ void comestible_inventory::heat_up( item *it_to_heat ) counter++; } - for (size_t i = 0; i < hotplates.size(); i++) { - sm.addentry(counter, true, counter, string_format(_("%s in inventory"), hotplates.at(i)->display_name())); + for( size_t i = 0; i < hotplates.size(); i++ ) { + sm.addentry( counter, true, counter, string_format( _( "%s in inventory" ), + hotplates.at( i )->display_name() ) ); counter++; } - for (size_t i = 0; i < hotplates_map.size(); i++) { - sm.addentry(counter, true, counter, string_format(_("%s nearby"), hotplates_map.at(i)->display_name())); + for( size_t i = 0; i < hotplates_map.size(); i++ ) { + sm.addentry( counter, true, counter, string_format( _( "%s nearby" ), + hotplates_map.at( i )->display_name() ) ); counter++; } //sm.selected = pane.sortby - SORTBY_NONE; @@ -2431,7 +2219,7 @@ void comestible_inventory::heat_up( item *it_to_heat ) choice--; } item *it_choice; - if( static_cast(choice) < hotplates.size() ) { + if( static_cast( choice ) < hotplates.size() ) { it_choice = hotplates[choice]; } else { choice -= hotplates.size(); @@ -2470,8 +2258,3 @@ void comestible_inventory::heat_up( item *it_to_heat ) } p.mod_moves( -move_mod ); // time needed to actually heat up } - -//void cancel_aim_processing() -//{ -// uistate.adv_inv_re_enter_move_all = ENTRY_START; -//} diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 22b639157be6a..7eb4236d2eb0b 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -14,6 +14,7 @@ #include "cursesdef.h" #include "point.h" #include "units.h" +#include "game.h" #include "advanced_inv.h" #include "itype.h" @@ -80,8 +81,14 @@ struct comestible_inv_area { tripoint off; /** Long name, displayed, translated */ const std::string name = "fake"; - /** Shorter name (2 letters) */ + /** Appears as part of the list */ const std::string shortname = "FK"; // FK in my coffee + /** Appears as part of the legend at the top right */ + const std::string minimapname = "FKM"; // FK in my coffee + + const aim_location relative_location; + + const std::string actionname = "FKA"; // absolute position of the map point. tripoint pos; /** Can we put items there? Only checks if location is valid, not if @@ -100,10 +107,13 @@ struct comestible_inv_area { // maximal count / volume of items there. int max_size; - comestible_inv_area( aim_location id ) : id( id ) {} + comestible_inv_area( aim_location id ) : id( id ), relative_location( id ) {} comestible_inv_area( aim_location id, int hscreenx, int hscreeny, tripoint off, - const std::string &name, const std::string &shortname ) : id( id ), + const std::string &name, const std::string &shortname, + const std::string &minimapname, const aim_location relative_location, + const std::string &actionname ) : id( id ), hscreen( hscreenx, hscreeny ), off( off ), name( name ), shortname( shortname ), + minimapname( minimapname ), relative_location( relative_location ), actionname( actionname ), canputitemsloc( false ), veh( nullptr ), vstor( -1 ), volume( 0_ml ), weight( 0_gram ), max_size( 0 ) { } @@ -113,7 +123,7 @@ struct comestible_inv_area { units::volume free_volume( bool in_vehicle = false ) const; int get_item_count() const; // Other area is actually the same item source, e.g. dragged vehicle to the south and AIM_SOUTH - bool is_same( const comestible_inv_area &other ) const; + //bool is_same( const comestible_inv_area &other ) const; // does _not_ check vehicle storage, do that with `can_store_in_vehicle()' below bool canputitems( const comestible_inv_listitem *advitem = nullptr ); // if you want vehicle cargo, specify so via `in_vehicle' @@ -129,6 +139,18 @@ struct comestible_inv_area { } return veh != nullptr && vstor >= 0; } + + aim_location get_relative_location() { + if( !( tile_iso && use_tiles ) ) { + return id; + } else { + return relative_location; + } + } + + //std::string get_minimap_sym() { + + //} }; // see item_factory.h @@ -394,7 +416,7 @@ class comestible_inventory void do_return_entry(); // returns true if currently processing a routine // (such as `MOVE_ALL_ITEMS' with `AIM_ALL' source) - bool is_processing() const; + //bool is_processing() const; static std::string get_sortname( comestible_inv_sortby sortby ); //bool move_all_items(bool nested_call = false); @@ -413,7 +435,7 @@ class comestible_inventory * @return true if the action did refer to an location (which has been * stored in ret), false otherwise. */ - static bool get_square( const std::string &action, aim_location &ret ); + comestible_inv_area *get_square( const std::string &action ); /** * Show the sort-by menu and change the sorting of this pane accordingly. * @return whether the sort order was actually changed. @@ -448,19 +470,19 @@ class comestible_inventory /*bool query_charges(aim_location destarea, const comestible_inv_listitem& sitem, const std::string& action, int& amount);*/ - void menu_square( uilist &menu ); + //void menu_square( uilist &menu ); - static char get_location_key( aim_location area ); - static char get_direction_key( aim_location area ); + std::string get_location_key( aim_location area ); + char get_direction_key( aim_location area ); /** * Converts from screen relative location to game-space relative location * for control rotation in isometric mode. */ - static aim_location screen_relative_location( aim_location area ); + //static aim_location screen_relative_location( aim_location area ); char const *set_string_params( nc_color &print_color, int value, bool selected, - bool need_highlight = false ); + bool need_highlight = false ); //nc_color set_string_params(int value, bool need_highlight = false); time_duration get_time_left( player &p, const item &it ) const; const islot_comestible &get_edible_comestible( player &p, const item &it ) const; diff --git a/src/uistate.h b/src/uistate.h index bae73fabd20a8..b8404f0f3fa95 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -13,16 +13,22 @@ class item; -//struct comestible_inv_save_state { -//public: -// int sort_idx = 1; -// std::string filter = ""; -// int area_idx = 5; -// int selected_idx = 0; -// -// bool in_vehicle = false; -// int exit_code = 0; -//}; +struct comestible_inv_save_state { + public: + int sort_idx = 1; + std::string filter = ""; + int area_idx = 5; + int selected_idx = 0; + + bool in_vehicle = false; + int exit_code = 0; + bool food_filter = true; + + int container_location = -1; + int container_index = 0; + itype_id container_type = "null"; + itype_id container_content_type = "null"; +}; /* centralized depot for trivial ui data such as sorting, string_input_popup history, etc. @@ -64,9 +70,7 @@ class uistatedata std::map> adv_inv_veh_items, adv_inv_map_items; bool adv_inv_container_in_vehicle = false; - int save_var = 5; - - //comestible_inv_save_state comestible_save; + comestible_inv_save_state comestible_save; bool editmap_nsa_viewmode = false; // true: ignore LOS and lighting bool overmap_blinking = true; // toggles active blinking of overlays. From 7839d41ee4633181abb9eb2499f9e710a6ddcae5 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 24 Aug 2019 22:43:50 -0400 Subject: [PATCH 04/19] # If this commit is applied, it will .... bionics have special eating menu when activated can summon crafting menu from eating menu refactoring to make it more modular, future support --- src/bionics_ui.cpp | 14 +- src/comestible_inv.cpp | 1854 ++++------------------------------- src/comestible_inv.h | 392 +------- src/comestible_inv_area.cpp | 279 ++++++ src/comestible_inv_area.h | 221 +++++ src/comestible_inv_pane.cpp | 1281 ++++++++++++++++++++++++ src/comestible_inv_pane.h | 313 ++++++ src/crafting.cpp | 4 +- src/crafting.h | 3 +- src/crafting_gui.cpp | 4 +- src/crafting_gui.h | 2 +- src/handle_action.cpp | 7 +- src/player.h | 2 +- src/uistate.h | 13 +- 14 files changed, 2353 insertions(+), 2036 deletions(-) create mode 100644 src/comestible_inv_area.cpp create mode 100644 src/comestible_inv_area.h create mode 100644 src/comestible_inv_pane.cpp create mode 100644 src/comestible_inv_pane.h diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index fb133057c3f3c..45ab20819cb32 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -13,6 +13,7 @@ #include "translations.h" #include "options.h" #include "string_id.h" +#include "comestible_inv.h" // '!', '-' and '=' are uses as default bindings in the menu const invlet_wrapper @@ -623,11 +624,18 @@ void player::power_bionics() if( tmp->powered ) { deactivate_bionic( b ); } else { - activate_bionic( b ); - // Clear the menu if we are firing a bionic gun - if( tmp->info().gun_bionic || tmp->ammo_count > 0 ) { + if (bio_data.power_source) { + activate_bionic(b); + comestible_inv(b); break; } + else { + activate_bionic(b); + // Clear the menu if we are firing a bionic gun + if (tmp->info().gun_bionic || tmp->ammo_count > 0) { + break; + } + } } // update message log and the menu g->refresh_all(); diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 2abccaff7365d..83c31b0cc6171 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -1,5 +1,3 @@ -#include "comestible_inv.h" - #include "auto_pickup.h" #include "avatar.h" #include "cata_utility.h" @@ -42,10 +40,8 @@ #include "item_location.h" #include "map_selector.h" #include "pimpl.h" - -#if defined(__ANDROID__) -# include -#endif +#include "bionics.h" +#include "comestible_inv.h" #include #include @@ -61,13 +57,16 @@ #include #include +#if defined(__ANDROID__) +# include +#endif + enum aim_exit { exit_none = 0, exit_okay, exit_re_entry }; -// *INDENT-OFF* comestible_inventory::comestible_inventory() : head_height(5) , min_w_height(10) @@ -77,48 +76,45 @@ comestible_inventory::comestible_inventory() , recalc(true) , redraw(true) , filter_edit(false) - // panes don't need initialization, they are recalculated immediately ,squares({ { - // hx hy - { AIM_INVENTORY, 25, 2, tripoint_zero, _("Inventory"), _("IN"), "I", AIM_INVENTORY, "ITEMS_INVENTORY" }, - - { AIM_SOUTHWEST, 30, 3, tripoint_south_west, _("South West"), _("SW"),"1",AIM_WEST ,"ITEMS_SW" }, - { AIM_SOUTH, 33, 3, tripoint_south, _("South"), _("S"),"2",AIM_SOUTHWEST ,"ITEMS_S"}, - { AIM_SOUTHEAST, 36, 3, tripoint_south_east, _("South East"), _("SE"),"3",AIM_SOUTH ,"ITEMS_SE"}, - { AIM_WEST, 30, 2, tripoint_west, _("West"), _("W"),"4",AIM_NORTHWEST ,"ITEMS_W" }, - { AIM_CENTER, 33, 2, tripoint_zero, _("Directly below you"), _("DN"),"5",AIM_CENTER ,"ITEMS_CE"}, - { AIM_EAST, 36, 2, tripoint_east, _("East"), _("E"),"6",AIM_SOUTHEAST ,"ITEMS_E" }, - { AIM_NORTHWEST, 30, 1, tripoint_north_west, _("North West"), _("NW"),"7",AIM_NORTH ,"ITEMS_NW"}, - { AIM_NORTH, 33, 1, tripoint_north, _("North"), _("N"),"8",AIM_NORTHEAST ,"ITEMS_N" }, - { AIM_NORTHEAST, 36, 1, tripoint_north_east, _("North East"), _("NE"),"9",AIM_EAST ,"ITEMS_NE" }, - - { AIM_DRAGGED, 25, 1, tripoint_zero, _("Grabbed Vehicle"), _("GR"),"D",AIM_DRAGGED ,"ITEMS_DRAGGED_CONTAINER" }, - { AIM_ALL, 22, 3, tripoint_zero, _("Surrounding area"), _("AL"),"A",AIM_ALL ,"ITEMS_AROUND" }, - { AIM_CONTAINER, 22, 1, tripoint_zero, _("Container"), _("CN"),"C",AIM_CONTAINER ,"ITEMS_CONTAINER"}, - { AIM_WORN, 25, 3, tripoint_zero, _("Worn Items"), _("WR"),"W",AIM_WORN ,"ITEMS_WORN"}, - //{ NUM_AIM_LOCATIONS, 22, 3, tripoint_zero, _("Surrounding area and Inventory"), _("A+I") } + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_SOUTHWEST)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_SOUTH)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_SOUTHEAST)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_WEST)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_CENTER)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_EAST)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_NORTHWEST)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_NORTH)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_NORTHEAST)}, + + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_DRAGGED)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_INVENTORY)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_WORN)}, + + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_ALL)}, + {comestible_inv_area::get_info(comestible_inv_area_info::AIM_ALL_I_W)} } }) { + //TODO:XXX // initialize screen coordinates for small overview 3x3 grid, depending on control scheme - if (tile_iso && use_tiles) { - // Rotate the coordinates. - squares[1].hscreen.x = 33; - squares[2].hscreen.x = 36; - squares[3].hscreen.y = 2; - squares[4].hscreen.y = 3; - squares[6].hscreen.y = 1; - squares[7].hscreen.y = 2; - squares[8].hscreen.x = 30; - squares[9].hscreen.x = 33; - } + //if (tile_iso && use_tiles) { + // // Rotate the coordinates. + // squares[1].info.hscreen.x = 33; + // squares[2].info.hscreen.x = 36; + // squares[3].info.hscreen.y = 2; + // squares[4].info.hscreen.y = 3; + // squares[6].info.hscreen.y = 1; + // squares[7].info.hscreen.y = 2; + // squares[8].info.hscreen.x = 30; + // squares[9].info.hscreen.x = 33; + //} } -// *INDENT-ON* comestible_inventory::~comestible_inventory() { - save_settings( false ); + save_settings(); auto &aim_code = uistate.comestible_save.exit_code; if( aim_code != exit_re_entry ) { aim_code = exit_okay; @@ -133,632 +129,33 @@ comestible_inventory::~comestible_inventory() } } -void comestible_inventory::save_settings( bool only_panes ) -{ - if( !only_panes ) { - // uistate.adv_inv_last_coords = g->u.pos(); - // uistate.adv_inv_src = src; - // uistate.adv_inv_dest = dest; - } - uistate.comestible_save.in_vehicle = pane.in_vehicle(); - uistate.comestible_save.area_idx = pane.get_area(); - uistate.comestible_save.selected_idx = pane.index; - uistate.comestible_save.filter = pane.filter; -} - -//TODO: fix settings -void comestible_inventory::load_settings() -{ - aim_exit aim_code = static_cast( uistate.comestible_save.exit_code ); - aim_location location; - location = static_cast( uistate.comestible_save.area_idx ); - auto square = squares[location]; - // determine the square's vehicle/map item presence - bool has_veh_items = square.can_store_in_vehicle() ? - !square.veh->get_items( square.vstor ).empty() : false; - bool has_map_items = !g->m.i_at( square.pos ).empty(); - // determine based on map items and settings to show cargo - bool show_vehicle = aim_code == exit_re_entry ? - uistate.comestible_save.in_vehicle : has_veh_items ? true : - has_map_items ? false : square.can_store_in_vehicle(); - pane.set_area( square, show_vehicle ); - pane.sortby = static_cast( uistate.comestible_save.sort_idx ); - pane.index = uistate.comestible_save.selected_idx; - pane.filter = uistate.comestible_save.filter; - uistate.comestible_save.exit_code = exit_none; - - pane.filter_show_food = uistate.comestible_save.food_filter; -} - -std::string comestible_inventory::get_sortname( comestible_inv_sortby sortby ) -{ - switch( sortby ) { - case COMESTIBLE_SORTBY_NAME: - return _( "name" ); - case COMESTIBLE_SORTBY_WEIGHT: - return _( "weight" ); - case COMESTIBLE_SORTBY_VOLUME: - return _( "volume" ); - case COMESTIBLE_SORTBY_CALORIES: - return _( "calories" ); - case COMESTIBLE_SORTBY_QUENCH: - return _( "quench" ); - case COMESTIBLE_SORTBY_JOY: - return _( "joy" ); - case COMESTIBLE_SORTBY_SPOILAGE: - return _( "spoilage" ); +void comestible_inventory::save_settings() { + bool is_reset = uistate.comestible_save.exit_code != exit_re_entry; + pane.save_settings(is_reset); + if (is_reset) { + if (uistate.comestible_save.bio != -1) { + g->u.deactivate_bionic(uistate.comestible_save.bio); + } + uistate.comestible_save.bio = -1; } - return "!BUG!"; } comestible_inv_area *comestible_inventory::get_square( const std::string &action ) { for( size_t i = 0; i < squares.size(); i++ ) { - if( action == squares[i].actionname ) { + if( action == squares[i].info.actionname ) { return &squares[i]; } } return nullptr; } -void comestible_inventory::print_items( comestible_inventory_pane &pane ) -{ - const auto &items = pane.items; - const catacurses::window &window = pane.window; - const auto index = pane.index; - const int page = index / itemsPerPage; - bool compact = TERMX <= 100; - - int max_width = getmaxx( window ); - std::string spaces( max_width - 4, ' ' ); - - nc_color norm = c_white; - - //print inventory's current and total weight + volume - if( pane.get_area() == AIM_INVENTORY || pane.get_area() == AIM_WORN ) { - const double weight_carried = convert_weight( g->u.weight_carried() ); - const double weight_capacity = convert_weight( g->u.weight_capacity() ); - std::string volume_carried = format_volume( g->u.volume_carried() ); - std::string volume_capacity = format_volume( g->u.volume_capacity() ); - // align right, so calculate formatted head length - const std::string formatted_head = string_format( "%.1f/%.1f %s %s/%s %s", - weight_carried, weight_capacity, weight_units(), - volume_carried, - volume_capacity, - volume_units_abbr() ); - //const int hrightcol = columns - 1 - formatted_head.length(); - //nc_color color = weight_carried > weight_capacity ? c_red : c_light_green; - //mvwprintz(window, 4, hrightcol, color, "%.1f", weight_carried); - wprintz( window, c_light_gray, "/%.1f %s ", weight_capacity, weight_units() ); - nc_color color = g->u.volume_carried().value() > g->u.volume_capacity().value() ? c_red : - c_light_green; - wprintz( window, color, volume_carried ); - wprintz( window, c_light_gray, "/%s %s", volume_capacity, volume_units_abbr() ); - } else { //print square's current and total weight + volume - std::string formatted_head; - if( pane.get_area() == AIM_ALL ) { - formatted_head = string_format( "%3.1f %s %s %s", - convert_weight( squares[pane.get_area()].weight ), - weight_units(), - format_volume( squares[pane.get_area()].volume ), - volume_units_abbr() ); - } else { - units::volume maxvolume = 0_ml; - auto &s = squares[pane.get_area()]; - if( pane.get_area() == AIM_CONTAINER && s.get_container( pane.in_vehicle() ) != nullptr ) { - maxvolume = s.get_container( pane.in_vehicle() )->get_container_capacity(); - } else if( pane.in_vehicle() ) { - maxvolume = s.veh->max_volume( s.vstor ); - } else { - maxvolume = g->m.max_volume( s.pos ); - } - formatted_head = string_format( "%3.1f %s %s/%s %s", - convert_weight( s.weight ), - weight_units(), - format_volume( s.volume ), - format_volume( maxvolume ), - volume_units_abbr() ); - } - mvwprintz( window, point( max_width - 1 - formatted_head.length(), 4 ), norm, formatted_head ); - } - - const size_t last_x = max_width - 2; - const size_t name_startpos = compact ? 1 : 4; - - const int num_columns = 8 + 1; //to add columns change this - const int col_size[num_columns] = { 0, - 4, 5, 7, 8, - 9, 7, 4, 12 - }; //to change column size change this - const int total_col_width = std::accumulate( col_size, col_size + num_columns, 0 ); - int cur_col = 0; - int cur_col_x = last_x - total_col_width; - - const size_t src_startpos = cur_col_x += col_size[cur_col++]; - const size_t amt_startpos = cur_col_x += col_size[cur_col++]; - const size_t weight_startpos = cur_col_x += col_size[cur_col++]; - const size_t vol_startpos = cur_col_x += col_size[cur_col++]; - - const size_t cal_startpos = cur_col_x += col_size[cur_col++]; - const size_t quench_startpos = cur_col_x += col_size[cur_col++]; - const size_t joy_startpos = cur_col_x += col_size[cur_col++]; - const size_t expires_startpos = cur_col_x += col_size[cur_col++]; - - int max_name_length = src_startpos - name_startpos - 1; // Default name length - - //~ Items list header. Table fields length without spaces: amt - 4, weight - 5, vol - 4. - //const int table_hdr_len1 = utf8_width( _( "amt weight vol" ) ); // Header length type 1 - //~ Items list header. Table fields length without spaces: src - 2, amt - 4, weight - 5, vol - 4. - //const int table_hdr_len2 = utf8_width( _( "src amt weight vol" ) ); // Header length type 2 - - mvwprintz( window, point( compact ? 1 : 4, 5 ), c_light_gray, _( "Name (charges)" ) ); - //if (pane.get_area() == AIM_ALL && !compact) { - // mvwprintz(window, 5, last_x - table_hdr_len2 + 1, c_light_gray, _("src amt weight vol")); - // max_name_length = src_startpos - name_startpos - 1; // 1 for space - //} - //else { - // mvwprintz(window, 5, last_x - table_hdr_len1 + 1, c_light_gray, _("amt weight vol")); - //} - - mvwprintz( window, point( src_startpos, 5 ), c_light_gray, _( "src" ) ); - mvwprintz( window, point( amt_startpos + 1, 5 ), c_light_gray, _( "amt" ) ); - mvwprintz( window, point( weight_startpos, 5 ), c_light_gray, _( "weight" ) ); - mvwprintz( window, point( vol_startpos + 2, 5 ), c_light_gray, _( "vol" ) ); - mvwprintz( window, point( cal_startpos, 5 ), c_light_gray, _( "calories" ) ); - mvwprintz( window, point( quench_startpos, 5 ), c_light_gray, _( "quench" ) ); - mvwprintz( window, point( joy_startpos, 5 ), c_light_gray, _( "joy" ) ); - mvwprintz( window, point( expires_startpos, 5 ), c_light_gray, _( "expires in" ) ); - - player &p = g->u; - - for( int i = page * itemsPerPage, x = 0; i < static_cast( items.size() ) && - x < itemsPerPage; i++, x++ ) { - const auto &sitem = items[i]; - if( sitem.is_category_header() ) { - mvwprintz( window, point( ( max_width - utf8_width( sitem.name ) - 6 ) / 2, 6 + x ), c_cyan, "[%s]", - sitem.name ); - continue; - } - if( !sitem.is_item_entry() ) { - // Empty entry at the bottom of a page. - continue; - } - - const auto &it = p.get_consumable_from( *sitem.items.front() ); - - const bool selected = index == i; - - nc_color thiscolor = it.color_in_inventory(); - nc_color thiscolordark = c_dark_gray; - nc_color print_color; - - //TODO: remove inCategoryMode - if( selected ) { - thiscolor = inCategoryMode ? c_white_red : hilite( c_white ); - thiscolordark = hilite( thiscolordark ); - if( compact ) { - mvwprintz( window, point( 1, 6 + x ), thiscolor, " %s", spaces ); - } else { - mvwprintz( window, point( 1, 6 + x ), thiscolor, ">>%s", spaces ); - } - } - - std::string item_name; - std::string stolen_string; - bool stolen = false; - if( it.has_owner() ) { - const faction *item_fac = it.get_owner(); - if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { - stolen_string = string_format( "!" ); - stolen = true; - } - } - if( it.is_money() ) { - //Count charges - // TODO: transition to the item_location system used for the normal inventory - unsigned int charges_total = 0; - for( const auto item : sitem.items ) { - charges_total += item->charges; - } - if( stolen ) { - item_name = string_format( "%s %s", stolen_string, it.display_money( sitem.items.size(), - charges_total ) ); - } else { - item_name = it.display_money( sitem.items.size(), charges_total ); - } - } else { - if( stolen ) { - item_name = string_format( "%s %s", stolen_string, it.display_name() ); - } else { - //item_name = it.display_name(); - item_name = sitem.items.front()->display_name(); - } - } - if( get_option( "ITEM_SYMBOLS" ) ) { - item_name = string_format( "%s %s", it.symbol(), item_name ); - } - - //print item name - trim_and_print( window, point( compact ? 1 : 4, 6 + x ), max_name_length, thiscolor, item_name ); - - //print src column - // TODO: specify this is coming from a vehicle! - if( pane.get_area() == AIM_ALL && !compact ) { - mvwprintz( window, point( src_startpos, 6 + x ), thiscolor, squares[sitem.area].shortname ); - } - - //print "amount" column - int it_amt = sitem.stacks; - if( it_amt > 1 ) { - print_color = thiscolor; - if( it_amt > 9999 ) { - it_amt = 9999; - print_color = selected ? hilite( c_red ) : c_red; - } - mvwprintz( window, point( amt_startpos, 6 + x ), print_color, "%4d", it_amt ); - } - - //print weight column - double it_weight = convert_weight( sitem.weight ); - size_t w_precision; - print_color = it_weight > 0 ? thiscolor : thiscolordark; - - if( it_weight >= 1000.0 ) { - if( it_weight >= 10000.0 ) { - print_color = selected ? hilite( c_red ) : c_red; - it_weight = 9999.0; - } - w_precision = 0; - } else if( it_weight >= 100.0 ) { - w_precision = 1; - } else { - w_precision = 2; - } - mvwprintz( window, point( weight_startpos, 6 + x ), print_color, "%5.*f", w_precision, it_weight ); - - //print volume column - bool it_vol_truncated = false; - double it_vol_value = 0.0; - std::string it_vol = format_volume( sitem.volume, 5, &it_vol_truncated, &it_vol_value ); - if( it_vol_truncated && it_vol_value > 0.0 ) { - print_color = selected ? hilite( c_red ) : c_red; - } else { - print_color = sitem.volume.value() > 0 ? thiscolor : thiscolordark; - } - mvwprintz( window, point( vol_startpos, 6 + x ), print_color, it_vol ); - - if( sitem.autopickup ) { - mvwprintz( window, point( 1, 6 + x ), magenta_background( it.color_in_inventory() ), - compact ? it.tname().substr( 0, 1 ) : ">" ); - } - //get_consumable_item - char const *string_format = ""; - islot_comestible it_c = get_edible_comestible( p, it ); // .type->comestible; - - //print "CALORIES" column - int it_cal = p.kcal_for( it ); - string_format = set_string_params( print_color, it_cal, selected ); - mvwprintz( window, point( cal_startpos, 6 + x ), print_color, string_format, it_cal ); - - //print "QUENCH" column - int it_q = it_c.quench; - string_format = set_string_params( print_color, it_q, selected ); - mvwprintz( window, point( quench_startpos, 6 + x ), print_color, string_format, it_q ); - - //print "JOY" column - int it_joy = p.fun_for( it ).first; - string_format = set_string_params( print_color, it_joy, selected, it.has_flag( "MUSHY" ) ); - mvwprintz( window, point( joy_startpos, 6 + x ), print_color, string_format, it_joy ); - - //TODO: g->u.can_estimate_rot() - //print "SPOILS IN" column - std::string it_spoils_string; - if( it_c.spoils > 0_turns ) { - if( !it.rotten() ) { - it_spoils_string = get_time_left_rounded( p, it ); - } - } - print_color = selected ? hilite( c_white ) : c_cyan; - mvwprintz( window, point( expires_startpos, 6 + x ), print_color, "%s", it_spoils_string ); - - /* - append_cell( [ this, &p ]( const item_location & loc ) { - std::string cbm_name; - - switch( p.get_cbm_rechargeable_with( get_consumable_item( loc ) ) ) { - case rechargeable_cbm::none: - break; - case rechargeable_cbm::battery: - cbm_name = _( "Battery" ); - break; - case rechargeable_cbm::reactor: - cbm_name = _( "Reactor" ); - break; - case rechargeable_cbm::furnace: - cbm_name = _( "Furnace" ); - break; - } - - if( !cbm_name.empty() ) { - return string_format( "%s", cbm_name ); - } - - return std::string(); - }, _( "CBM" ) ); - - append_cell( [ this, &p ]( const item_location & loc ) { - return good_bad_none( p.get_acquirable_energy( get_consumable_item( loc ) ) ); - }, _( "ENERGY" ) ); - - */ - } -} - -struct comestible_inv_sorter { - int counter; - comestible_inv_sortby sortby; - comestible_inv_sorter( comestible_inv_sortby sort ) { - sortby = sort; - counter = 0; - } - bool operator()( const comestible_inv_listitem &d1, const comestible_inv_listitem &d2 ) { - if( d1.is_category_header() ) { - return true; - } else if( d2.is_category_header() ) { - return false; - } - - /* - this code will put 'hot' items to the top of the list - problem is heating from inventory will remove it from aiming spot... decide if this is needed - item* it1 = d1.items.front(); - item* it2 = d2.items.front(); - - bool is_it1_hot = (it1->has_flag("HOT") || - (it1->contents.size() > 0 && it1->contents.front().has_flag("HOT"))); - bool is_it2_hot = (it2->has_flag("HOT") || - (it2->contents.size() > 0 && it2->contents.front().has_flag("HOT"))); - if (is_it1_hot != is_it2_hot) { - return is_it1_hot; - } - */ - - switch( sortby ) { - case COMESTIBLE_SORTBY_NAME: - const std::string *n1; - const std::string *n2; - if( d1.name_without_prefix == d2.name_without_prefix ) { - if( d1.name == d2.name ) { - //fall through - break; - } else { - //if names without prefix equal, compare full name - n1 = &d1.name; - n2 = &d2.name; - } - } else { - //else compare name without prefix - n1 = &d1.name_without_prefix; - n2 = &d2.name_without_prefix; - } - - return std::lexicographical_compare( n1->begin(), n1->end(), n2->begin(), n2->end(), - sort_case_insensitive_less() ); - break; - case COMESTIBLE_SORTBY_WEIGHT: - if( d1.weight != d2.weight ) { - return d1.weight > d2.weight; - } - break; - case COMESTIBLE_SORTBY_VOLUME: - if( d1.volume != d2.volume ) { - return d1.volume > d2.volume; - } - break; - case COMESTIBLE_SORTBY_CALORIES: - if( d1.calories != d2.calories ) { - return d1.calories > d2.calories; - } - break; - case COMESTIBLE_SORTBY_QUENCH: - if( d1.quench != d2.quench ) { - return d1.quench > d2.quench; - } - break; - case COMESTIBLE_SORTBY_JOY: - if( d1.joy != d2.joy ) { - return d1.joy > d2.joy; - } - break; - case COMESTIBLE_SORTBY_SPOILAGE: - - break; - } - // secondary sort by SPOILAGE - return d1.items.front()->spoilage_sort_order() < d2.items.front()->spoilage_sort_order(); - } -}; - -inline std::string comestible_inventory::get_location_key( aim_location area ) -{ - return squares[squares[area].get_relative_location()].minimapname; -} - -int comestible_inventory::print_header( comestible_inventory_pane &pane, aim_location sel ) -{ - const catacurses::window &window = pane.window; - size_t area = pane.get_area(); - int wwidth = getmaxx( window ); - int ofs = wwidth - 25 - 2 - 14; - for( size_t i = 0; i < squares.size(); ++i ) { - std::string key = get_location_key( static_cast( i ) ); - const char *bracket = squares[i].can_store_in_vehicle() ? "<>" : "[]"; - bool in_vehicle = pane.in_vehicle() && squares[i].id == area && sel == area && area != AIM_ALL; - bool all_brackets = area == AIM_ALL && ( i >= AIM_SOUTHWEST && i <= AIM_NORTHEAST ); - nc_color bcolor = c_red; - nc_color kcolor = c_red; - if( squares[i].canputitems( pane.get_cur_item_ptr() ) ) { - bcolor = in_vehicle ? c_light_blue : - area == i || all_brackets ? c_light_gray : c_dark_gray; - kcolor = area == i ? c_white : sel == i ? c_light_gray : c_dark_gray; - } - const int x = squares[i].hscreen.x + ofs; - const int y = squares[i].hscreen.y; - mvwprintz( window, point( x, y ), bcolor, "%c", bracket[0] ); - wprintz( window, kcolor, "%s", in_vehicle && sel != AIM_DRAGGED ? "V" : key ); - wprintz( window, bcolor, "%c", bracket[1] ); - } - return squares[AIM_INVENTORY].hscreen.y + ofs; -} - -int comestible_inv_area::get_item_count() const -{ - if( id == AIM_INVENTORY ) { - return g->u.inv.size(); - } else if( id == AIM_WORN ) { - return g->u.worn.size(); - } else if( id == AIM_ALL ) { - return 0; - } else if( id == AIM_DRAGGED ) { - return can_store_in_vehicle() ? veh->get_items( vstor ).size() : 0; - } else { - return g->m.i_at( pos ).size(); - } -} - -void comestible_inv_area::init() -{ - pos = g->u.pos() + off; - veh = nullptr; - vstor = -1; - volume = 0_ml; // must update in main function - weight = 0_gram; // must update in main function - switch( id ) { - case AIM_INVENTORY: - case AIM_WORN: - canputitemsloc = true; - break; - case AIM_DRAGGED: - if( g->u.get_grab_type() != OBJECT_VEHICLE ) { - canputitemsloc = false; - desc[0] = _( "Not dragging any vehicle!" ); - break; - } - // offset for dragged vehicles is not statically initialized, so get it - off = g->u.grab_point; - // Reset position because offset changed - pos = g->u.pos() + off; - if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", - false ) ) { - veh = &vp->vehicle(); - vstor = vp->part_index(); - } else { - veh = nullptr; - vstor = -1; - } - if( vstor >= 0 ) { - desc[0] = veh->name; - canputitemsloc = true; - max_size = MAX_ITEM_IN_VEHICLE_STORAGE; - } else { - veh = nullptr; - canputitemsloc = false; - desc[0] = _( "No dragged vehicle!" ); - } - break; - case AIM_CONTAINER: - // set container position based on location - set_container_position(); - // location always valid, actual check is done in canputitems() - // and depends on selected item in pane (if it is valid container) - canputitemsloc = true; - if( get_container() == nullptr ) { - desc[0] = _( "Invalid container!" ); - } - break; - case AIM_ALL: - desc[0] = _( "All 9 squares" ); - canputitemsloc = true; - break; - case AIM_SOUTHWEST: - case AIM_SOUTH: - case AIM_SOUTHEAST: - case AIM_WEST: - case AIM_CENTER: - case AIM_EAST: - case AIM_NORTHWEST: - case AIM_NORTH: - case AIM_NORTHEAST: - if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", - false ) ) { - veh = &vp->vehicle(); - vstor = vp->part_index(); - } else { - veh = nullptr; - vstor = -1; - } - canputitemsloc = can_store_in_vehicle() || g->m.can_put_items_ter_furn( pos ); - max_size = MAX_ITEM_IN_SQUARE; - if( can_store_in_vehicle() ) { - desc[1] = vpart_position( *veh, vstor ).get_label().value_or( "" ); - } - // get graffiti or terrain name - desc[0] = g->m.has_graffiti_at( pos ) ? - g->m.graffiti_at( pos ) : g->m.name( pos ); - default: - break; - } - - /* assemble a list of interesting traits of the target square */ - // fields? with a special case for fire - bool danger_field = false; - const field &tmpfld = g->m.field_at( pos ); - for( auto &fld : tmpfld ) { - const field_entry &cur = fld.second; - if( fld.first.obj().has_fire ) { - flags.append( _( " FIRE" ) ); - } else { - if( cur.is_dangerous() ) { - danger_field = true; - } - } - } - if( danger_field ) { - flags.append( _( " DANGER" ) ); - } - - // trap? - const trap &tr = g->m.tr_at( pos ); - if( tr.can_see( pos, g->u ) && !tr.is_benign() ) { - flags.append( _( " TRAP" ) ); - } - - // water? - static const std::array ter_water = { - {t_water_dp, t_water_pool, t_swater_dp, t_water_sh, t_swater_sh, t_sewage, t_water_moving_dp, t_water_moving_sh } - }; - auto ter_check = [this] - ( const ter_id & id ) { - return g->m.ter( this->pos ) == id; - }; - if( std::any_of( ter_water.begin(), ter_water.end(), ter_check ) ) { - flags.append( _( " WATER" ) ); - } - - // remove leading space - if( flags.length() && flags[0] == ' ' ) { - flags.erase( 0, 1 ); - } -} - void comestible_inventory::init() { for( auto &square : squares ) { square.init(); } - load_settings(); - w_height = TERMY < min_w_height + head_height ? min_w_height : TERMY - head_height; w_width = TERMX < min_w_width ? min_w_width : TERMX > max_w_width ? max_w_width : static_cast( TERMX ); @@ -773,404 +170,62 @@ void comestible_inventory::init() point( colstart + ( w_width - ( minimap_width + 1 ) ), headstart + 1 ) ); window = catacurses::newwin( w_height, w_width, point( colstart, headstart + head_height ) ); - itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff - - pane.window = window; -} - -comestible_inv_listitem::comestible_inv_listitem( item *an_item, int index, int count, - aim_location area, bool from_vehicle ) - : idx( index ) - , area( area ) - , id( an_item->typeId() ) - , name( an_item->tname( count ) ) - , name_without_prefix( an_item->tname( 1, false ) ) - , autopickup( get_auto_pickup().has_rule( an_item ) ) - , stacks( count ) - , volume( an_item->volume() * stacks ) - , weight( an_item->weight() * stacks ) - , cat( &an_item->get_category() ) - , from_vehicle( from_vehicle ) -{ - player &p = g->u; - item it = p.get_consumable_from( *an_item ); - islot_comestible it_c = get_edible_comestible( p, it ); - calories = p.kcal_for( it ); - quench = it_c.quench; - joy = p.fun_for( it ).first; - - items.push_back( an_item ); - assert( stacks >= 1 ); -} - -comestible_inv_listitem::comestible_inv_listitem( const std::list &list, int index, - aim_location area, bool from_vehicle ) : - idx( index ), - area( area ), - id( list.front()->typeId() ), - items( list ), - name( list.front()->tname( list.size() ) ), - name_without_prefix( list.front()->tname( 1, false ) ), - autopickup( get_auto_pickup().has_rule( list.front() ) ), - stacks( list.size() ), - volume( list.front()->volume() * stacks ), - weight( list.front()->weight() * stacks ), - cat( &list.front()->get_category() ), - from_vehicle( from_vehicle ) -{ - player &p = g->u; - item it = p.get_consumable_from( *list.front() ); - islot_comestible it_c = get_edible_comestible( p, it ); - calories = p.kcal_for( it ); - quench = it_c.quench; - joy = p.fun_for( it ).first; - assert( stacks >= 1 ); -} - -comestible_inv_listitem::comestible_inv_listitem() - : idx() - , area() - , id( "null" ) - , autopickup() - , stacks() - , cat( nullptr ) -{ -} - -comestible_inv_listitem::comestible_inv_listitem( const item_category *cat ) - : idx() - , area() - , id( "null" ) - , name( cat->name() ) - , autopickup() - , stacks() - , cat( cat ) -{ -} - -bool comestible_inv_listitem::is_category_header() const -{ - return items.empty() && cat != nullptr; -} - -bool comestible_inv_listitem::is_item_entry() const -{ - return !items.empty(); -} - -const islot_comestible &comestible_inv_listitem::get_edible_comestible( player &p, - const item &it ) const -{ - if( it.is_comestible() && p.can_eat( it ).success() ) { - // Ok since can_eat() returns false if is_craft() is true - return *it.type->comestible; - } - static const islot_comestible dummy{}; - return dummy; -} - -bool comestible_inventory_pane::is_filtered( const comestible_inv_listitem &it ) const -{ - return is_filtered( *it.items.front() ); -} + -bool comestible_inventory_pane::is_filtered( const item &it ) const -{ - const std::string n = it.get_category().name(); - if( filter_show_food && n != "FOOD" ) { - return true; - } - if( !filter_show_food && n != "DRUGS" ) { - return true; - } - - player &p = g->u; - if( !p.can_consume( it ) ) { - return true; - } - - const std::string str = it.tname(); - if( filtercache.find( str ) == filtercache.end() ) { - const auto filter_fn = item_filter_from_string( filter ); - filtercache[str] = filter_fn; - - return !filter_fn( it ); - } - - return !filtercache[str]( it ); -} - -// roll our own, to handle moving stacks better -using itemstack = std::vector >; + uistate.comestible_save.exit_code = exit_none; -template -static itemstack i_stacked( T items ) -{ - //create a new container for our stacked items - itemstack stacks; - // // make a list of the items first, so we can add non stacked items back on - // std::list items(things.begin(), things.end()); - // used to recall indices we stored `itype_id' item at in itemstack - std::unordered_map> cache; - // iterate through and create stacks - for( auto &elem : items ) { - const auto id = elem.typeId(); - auto iter = cache.find( id ); - bool got_stacked = false; - // cache entry exists - if( iter != cache.end() ) { - // check to see if it stacks with each item in a stack, not just front() - for( auto &idx : iter->second ) { - for( auto &it : stacks[idx] ) { - if( ( got_stacked = it->display_stacked_with( elem ) ) ) { - stacks[idx].push_back( &elem ); - break; - } - } - if( got_stacked ) { - break; - } - } + std::vector columns; + if (uistate.comestible_save.bio == -1) { + columns = { COLUMN_CALORIES, COLUMN_QUENCH, COLUMN_JOY }; + if (g->u.can_estimate_rot()) { + columns.emplace_back(COLUMN_EXPIRES); } - if( !got_stacked ) { - cache[id].insert( stacks.size() ); - stacks.push_back( { &elem } ); + else { + columns.emplace_back(COLUMN_SHELF_LIFE); } } - return stacks; -} - -void comestible_inventory_pane::add_items_from_area( comestible_inv_area &square, - bool vehicle_override ) -{ - assert( square.id != AIM_ALL ); - square.volume = 0_ml; - square.weight = 0_gram; - if( !square.canputitems() ) { - return; + else { + columns = { COLUMN_ENERGY, COLUMN_SORTBY_CATEGORY }; } - map &m = g->m; - player &u = g->u; - // Existing items are *not* cleared on purpose, this might be called - // several times in case all surrounding squares are to be shown. - if( square.id == AIM_INVENTORY ) { - const invslice &stacks = u.inv.slice(); - for( size_t x = 0; x < stacks.size(); ++x ) { - std::list item_pointers; - for( item &i : *stacks[x] ) { - item_pointers.push_back( &i ); - } - comestible_inv_listitem it( item_pointers, x, square.id, false ); - if( is_filtered( *it.items.front() ) ) { - continue; + int itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff + pane.init(columns, itemsPerPage, window, &squares); + set_pane_legend(); + if (uistate.comestible_save.bio == -1) { + pane.special_filter = [](const item& it) { + const std::string n = it.get_category().name(); + if (uistate.comestible_save.show_food && n != "FOOD") { + return true; } - square.volume += it.volume; - square.weight += it.weight; - items.push_back( it ); - } - } else if( square.id == AIM_WORN ) { - auto iter = u.worn.begin(); - for( size_t i = 0; i < u.worn.size(); ++i, ++iter ) { - comestible_inv_listitem it( &*iter, i, 1, square.id, false ); - if( is_filtered( *it.items.front() ) ) { - continue; - } - square.volume += it.volume; - square.weight += it.weight; - items.push_back( it ); - } - } else if( square.id == AIM_CONTAINER ) { - item *cont = square.get_container( in_vehicle() ); - if( cont != nullptr ) { - if( !cont->is_container_empty() ) { - // filtering does not make sense for liquid in container - item *it = &square.get_container( in_vehicle() )->contents.front(); - comestible_inv_listitem ait( it, 0, 1, square.id, in_vehicle() ); - square.volume += ait.volume; - square.weight += ait.weight; - items.push_back( ait ); - } - square.desc[0] = cont->tname( 1, false ); - } - } else { - bool is_in_vehicle = square.can_store_in_vehicle() && ( in_vehicle() || vehicle_override ); - const itemstack &stacks = is_in_vehicle ? - i_stacked( square.veh->get_items( square.vstor ) ) : - i_stacked( m.i_at( square.pos ) ); - - for( size_t x = 0; x < stacks.size(); ++x ) { - comestible_inv_listitem it( stacks[x], x, square.id, is_in_vehicle ); - if( is_filtered( *it.items.front() ) ) { - continue; + if (!uistate.comestible_save.show_food && n != "DRUGS") { + return true; } - square.volume += it.volume; - square.weight += it.weight; - items.push_back( it ); - } - } -} -void comestible_inventory_pane::paginate( size_t itemsPerPage ) -{ - //TODO: check this out, pagination not needed without categories? - //if( sortby != SORTBY_CATEGORY ) { - // return; // not needed as there are no category entries here. - //} - // first, we insert all the items, then we sort the result - for( size_t i = 0; i < items.size(); ++i ) { - if( i % itemsPerPage == 0 ) { - // first entry on the page, should be a category header - if( items[i].is_item_entry() ) { - items.insert( items.begin() + i, comestible_inv_listitem( items[i].cat ) ); + if (!g->u.can_consume(it)) { + return true; } - } - if( ( i + 1 ) % itemsPerPage == 0 && i + 1 < items.size() ) { - // last entry of the page, but not the last entry at all! - // Must *not* be a category header! - if( items[i].is_category_header() ) { - items.insert( items.begin() + i, comestible_inv_listitem() ); - } - } - } -} - -void comestible_inventory::recalc_pane() -{ - add_msg( m_info, "~~~~~~~~~ here" ); - - pane.recalc = false; - pane.items.clear(); - // Add items from the source location or in case of all 9 surrounding squares, - // add items from several locations. - if( pane.get_area() == AIM_ALL ) { - auto &alls = squares[AIM_ALL]; - //auto &there = pane;// s[-p + 1]; - //auto &other = squares[there.get_area()]; - alls.volume = 0_ml; - alls.weight = 0_gram; - for( auto &s : squares ) { - // All the surrounding squares, nothing else - if( s.id < AIM_SOUTHWEST || s.id > AIM_NORTHEAST ) { - continue; - } - - // Deal with squares with ground + vehicle storage - // Also handle the case when the other tile covers vehicle - // or the ground below the vehicle. - if( s.can_store_in_vehicle() ) { - pane.add_items_from_area( s, true ); - alls.volume += s.volume; - alls.weight += s.weight; - } - - // Add map items - pane.add_items_from_area( s ); - alls.volume += s.volume; - alls.weight += s.weight; - } - } else { - pane.add_items_from_area( squares[pane.get_area()] ); - } - - //TODO: just put it as a part of the header instead of one of the items - - // Insert category headers (only expected when sorting by category) - std::set categories; - for( auto &it : pane.items ) { - categories.insert( it.cat ); + return false; + }; + pane.title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; + pane.default_sortby = COLUMN_EXPIRES; } - for( auto &cat : categories ) { - pane.items.push_back( comestible_inv_listitem( cat ) ); + else { + pane.special_filter = [](const item& it) { + return !g->u.can_consume(it); + }; + pane.title = g->u.bionic_at_index(uistate.comestible_save.bio).id.obj().name; + pane.default_sortby = COLUMN_ENERGY; } - - // Finally sort all items (category headers will now be moved to their proper position) - std::stable_sort( pane.items.begin(), pane.items.end(), comestible_inv_sorter( pane.sortby ) ); - pane.paginate( itemsPerPage ); } -void comestible_inventory_pane::fix_index() -{ - if( items.empty() ) { - index = 0; - return; +void comestible_inventory::set_pane_legend() { + std::vector data; + if (uistate.comestible_save.bio == -1) { + data.push_back({ 'z', c_light_gray, "Switch Food/Drugs" }); + data.push_back({ 'h', c_light_red, "Warm up food" }); + data.push_back({ '&', c_cyan, "Craft with" }); } - if( index < 0 ) { - index = 0; - } else if( static_cast( index ) >= items.size() ) { - index = static_cast( items.size() ) - 1; - } - skip_category_headers( +1 ); -} - -void comestible_inventory::redraw_pane() -{ - // don't update ui if processing demands - if( recalc || pane.recalc ) { - recalc_pane(); - } else if( !( redraw || pane.redraw ) ) { - return; - } - pane.redraw = false; - pane.fix_index(); - - const comestible_inv_area &square = squares[pane.get_area()]; - auto w = pane.window; - - werase( w ); - print_items( pane ); - - auto itm = pane.get_cur_item_ptr(); - int width = print_header( pane, itm != nullptr ? itm->area : pane.get_area() ); - bool same_as_dragged = ( square.id >= AIM_SOUTHWEST && square.id <= AIM_NORTHEAST ) && - // only cardinals - square.id != AIM_CENTER && pane.in_vehicle() && // not where you stand, and pane is in vehicle - square.off == squares[AIM_DRAGGED].off; // make sure the offsets are the same as the grab point - const comestible_inv_area &sq = same_as_dragged ? squares[AIM_DRAGGED] : square; - bool car = square.can_store_in_vehicle() && pane.in_vehicle() && sq.id != AIM_DRAGGED; - auto name = utf8_truncate( car ? sq.veh->name : sq.name, width ); - auto desc = utf8_truncate( sq.desc[car], width ); - width -= 2 + 1; // starts at offset 2, plus space between the header and the text - mvwprintz( w, point( 2, 1 ), c_green, name ); - mvwprintz( w, point( 2, 2 ), c_light_blue, desc ); - trim_and_print( w, point( 2, 3 ), width, c_cyan, square.flags ); - - const int max_page = ( pane.items.size() + itemsPerPage - 1 ) / itemsPerPage; - if( max_page > 1 ) { - const int page = pane.index / itemsPerPage; - mvwprintz( w, point( 2, 4 ), c_light_blue, _( "[<] page %d of %d [>]" ), page + 1, max_page ); - } - - wattron( w, c_cyan ); - // draw a darker border around the inactive pane - draw_border( w, BORDER_COLOR ); - mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), get_sortname( pane.sortby ) ); - int max = square.max_size; - if( max > 0 ) { - int itemcount = square.get_item_count(); - int fmtw = 7 + ( itemcount > 99 ? 3 : itemcount > 9 ? 2 : 1 ) + - ( max > 99 ? 3 : max > 9 ? 2 : 1 ); - mvwprintw( w, point( w_width / 2 - fmtw, 0 ), "< %d/%d >", itemcount, max ); - } - - const char *fprefix = _( "[F]ilter" ); - const char *fsuffix = _( "[R]eset" ); - if( !filter_edit ) { - if( !pane.filter.empty() ) { - mvwprintw( w, point( 2, getmaxy( w ) - 1 ), "< %s: %s >", fprefix, pane.filter ); - } else { - mvwprintw( w, point( 2, getmaxy( w ) - 1 ), "< %s >", fprefix ); - } - } - - wattroff( w, c_white ); - - if( !filter_edit && !pane.filter.empty() ) { - mvwprintz( w, point( 6 + std::strlen( fprefix ), getmaxy( w ) - 1 ), c_white, - pane.filter ); - mvwprintz( w, point( getmaxx( w ) - std::strlen( fsuffix ) - 2, getmaxy( w ) - 1 ), c_white, "%s", - fsuffix ); - } - wrefresh( w ); + pane.legend = data; + pane.needs_redraw = true; } // be explicit with the values @@ -1181,78 +236,49 @@ enum aim_entry { ENTRY_RESET = 3 }; -bool comestible_inventory::show_sort_menu( comestible_inventory_pane &pane ) +bool comestible_inventory::show_sort_menu( ) { uilist sm; sm.text = _( "Sort by... " ); - sm.addentry( COMESTIBLE_SORTBY_NAME, true, 'n', get_sortname( COMESTIBLE_SORTBY_NAME ) ); - sm.addentry( COMESTIBLE_SORTBY_WEIGHT, true, 'w', get_sortname( COMESTIBLE_SORTBY_WEIGHT ) ); - sm.addentry( COMESTIBLE_SORTBY_VOLUME, true, 'v', get_sortname( COMESTIBLE_SORTBY_VOLUME ) ); - sm.addentry( COMESTIBLE_SORTBY_CALORIES, true, 'c', get_sortname( COMESTIBLE_SORTBY_CALORIES ) ); - sm.addentry( COMESTIBLE_SORTBY_QUENCH, true, 'q', get_sortname( COMESTIBLE_SORTBY_QUENCH ) ); - sm.addentry( COMESTIBLE_SORTBY_JOY, true, 'j', get_sortname( COMESTIBLE_SORTBY_JOY ) ); - sm.addentry( COMESTIBLE_SORTBY_SPOILAGE, true, 's', get_sortname( COMESTIBLE_SORTBY_SPOILAGE ) ); - // Pre-select current sort. - sm.selected = pane.sortby; - // Calculate key and window variables, generate window, - // and loop until we get a valid answer. + pane.add_sort_enries(sm); sm.query(); if( sm.ret < 0 ) { return false; } - pane.sortby = static_cast( sm.ret ); + + pane.sortby = static_cast( sm.ret ); return true; } -static tripoint aim_vector( aim_location id ) +void comestible_inventory::display(int bio) { - switch( id ) { - case AIM_SOUTHWEST: - return tripoint_south_west; - case AIM_SOUTH: - return tripoint_south; - case AIM_SOUTHEAST: - return tripoint_south_east; - case AIM_WEST: - return tripoint_west; - case AIM_EAST: - return tripoint_east; - case AIM_NORTHWEST: - return tripoint_north_west; - case AIM_NORTH: - return tripoint_north; - case AIM_NORTHEAST: - return tripoint_north_east; - default: - return tripoint_zero; + if (uistate.comestible_save.exit_code != exit_re_entry) { + uistate.comestible_save.bio = bio; } -} - -void comestible_inventory::display() -{ init(); - g->u.inv.restack( g->u ); input_context ctxt( "COMESTIBLE_INVENTORY" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "QUIT" ); + ctxt.register_action( "UP" ); ctxt.register_action( "DOWN" ); ctxt.register_action( "PAGE_DOWN" ); ctxt.register_action( "PAGE_UP" ); + ctxt.register_action("CATEGORY_SELECTION"); + ctxt.register_action("SORT"); + ctxt.register_action("FILTER"); + ctxt.register_action("RESET_FILTER"); + ctxt.register_action( "TOGGLE_VEH" ); - ctxt.register_action( "FILTER" ); - ctxt.register_action( "RESET_FILTER" ); ctxt.register_action( "EXAMINE" ); - ctxt.register_action( "SORT" ); ctxt.register_action( "TOGGLE_AUTO_PICKUP" ); ctxt.register_action( "TOGGLE_FAVORITE" ); - ctxt.register_action( "MOVE_SINGLE_ITEM" ); - ctxt.register_action( "MOVE_VARIABLE_ITEM" ); - ctxt.register_action( "MOVE_ITEM_STACK" ); - ctxt.register_action( "CATEGORY_SELECTION" ); + ctxt.register_action("ITEMS_DEFAULT"); + ctxt.register_action("SAVE_DEFAULT"); + ctxt.register_action( "ITEMS_NW" ); ctxt.register_action( "ITEMS_N" ); ctxt.register_action( "ITEMS_NE" ); @@ -1265,27 +291,28 @@ void comestible_inventory::display() ctxt.register_action( "ITEMS_INVENTORY" ); ctxt.register_action( "ITEMS_WORN" ); ctxt.register_action( "ITEMS_AROUND" ); + ctxt.register_action( "ITEMS_AROUND_I_W" ); ctxt.register_action( "ITEMS_DRAGGED_CONTAINER" ); ctxt.register_action( "ITEMS_CONTAINER" ); - ctxt.register_action( "ITEMS_DEFAULT" ); - ctxt.register_action( "SAVE_DEFAULT" ); - - ctxt.register_action( "CONSUME_FOOD" ); - ctxt.register_action( "SWITCH_FOOD" ); - ctxt.register_action( "HEAT_UP" ); + if (uistate.comestible_save.bio == -1) { + ctxt.register_action("CONSUME_FOOD"); + ctxt.register_action("SWITCH_FOOD"); + ctxt.register_action("HEAT_UP"); + ctxt.register_action("CRAFT_WITH"); + } exit = false; - recalc = true; - redraw = true; - + redo(true, true); + + using ai = comestible_inv_area_info; while( !exit ) { if( g->u.moves < 0 ) { do_return_entry(); return; } - redraw_pane(); + pane.redraw(); if( redraw ) { werase( head ); @@ -1294,6 +321,7 @@ void comestible_inventory::display() draw_border( head ); Messages::display_messages( head, 2, 1, w_width - 1, head_height - 2 ); draw_minimap(); + const std::string msg = _( "< [?] show help >" ); mvwprintz( head, point( w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, 0 ), c_white, msg ); @@ -1304,50 +332,30 @@ void comestible_inventory::display() wrefresh( head ); refresh_minimap(); } - redraw = false; - recalc = false; + redo(false, false); // current item in source pane, might be null comestible_inv_listitem *sitem = pane.get_cur_item_ptr(); - //aim_location changeSquare = NUM_AIM_LOCATIONS; + //comestible_inv_area_info::aim_location changeSquare = NUM_AIM_LOCATIONS; comestible_inv_area *new_square; const std::string action = ctxt.handle_input(); + if( action == "CATEGORY_SELECTION" ) { - inCategoryMode = !inCategoryMode; - pane.redraw = true; // We redraw to force the color change of the highlighted line and header text. + pane.inCategoryMode = !pane.inCategoryMode; + pane.needs_redraw = true; // We redraw to force the color change of the highlighted line and header text. } else if( action == "HELP_KEYBINDINGS" ) { - redraw = true; + redo(recalc, true); } else if( ( new_square = get_square( action ) ) != nullptr ) { - if( pane.get_area() == new_square->get_relative_location() ) { + if( pane.get_area()->info.id == new_square->get_relative_location() ) { //DO NOTHING - } else if( new_square->canputitems( pane.get_cur_item_ptr() ) ) { - bool in_vehicle_cargo = false; - if( new_square->get_relative_location() == AIM_CONTAINER ) { - new_square->set_container( pane.get_cur_item_ptr() ); - } else if( pane.get_area() == AIM_CONTAINER ) { - new_square->set_container( nullptr ); - // auto select vehicle if items exist at said square, or both are empty - } else if( new_square->can_store_in_vehicle() ) { - if( new_square->get_relative_location() == AIM_DRAGGED ) { - in_vehicle_cargo = true; - } else { - // check item stacks in vehicle and map at said square - auto map_stack = g->m.i_at( new_square->pos ); - auto veh_stack = new_square->veh->get_items( new_square->vstor ); - // auto switch to vehicle storage if vehicle items are there, or neither are there - if( !veh_stack.empty() || map_stack.empty() ) { - in_vehicle_cargo = true; - } - } - } - pane.set_area( *new_square, in_vehicle_cargo ); + } else if( new_square->canputitems() ) { + pane.set_area( new_square, new_square->is_vehicle_default()); pane.index = 0; - pane.recalc = true; - redraw = true; + redo(true, true); } else { popup( _( "You can't put items there!" ) ); - redraw = true; // to clear the popup + redo(recalc, true); // to clear the popup } } else if( action == "TOGGLE_FAVORITE" ) { if( sitem == nullptr || !sitem->is_item_entry() ) { @@ -1356,49 +364,16 @@ void comestible_inventory::display() for( auto *it : sitem->items ) { it->set_favorite( !it->is_favorite ); } - recalc = true; // In case we've merged faved and unfaved items - redraw = true; - } else if( action == "MOVE_SINGLE_ITEM" || - action == "MOVE_VARIABLE_ITEM" || - action == "MOVE_ITEM_STACK" ) { - + // recalc = true; In case we've merged faved and unfaved items + redo(true, true); } else if( action == "SORT" ) { - if( show_sort_menu( pane ) ) { - recalc = true; - uistate.comestible_save.sort_idx = pane.sortby; + if( show_sort_menu( ) ) { + redo(true, redraw); } - redraw = true; + redo(recalc, true); } else if( action == "FILTER" ) { - string_input_popup spopup; - std::string filter = pane.filter; - filter_edit = true; - spopup.window( pane.window, 4, w_height - 1, w_width / 2 - 4 ) - .max_length( 256 ) - .text( filter ); - - draw_item_filter_rules( pane.window, 1, 11, item_filter_type::FILTER ); - -#if defined(__ANDROID__) - if( get_option( "ANDROID_AUTO_KEYBOARD" ) ) { - SDL_StartTextInput(); - } -#endif - - do { - mvwprintz( pane.window, point( 2, getmaxy( pane.window ) - 1 ), c_cyan, "< " ); - mvwprintz( pane.window, point( w_width / 2 - 4, getmaxy( pane.window ) - 1 ), c_cyan, " >" ); - std::string new_filter = spopup.query_string( false ); - if( spopup.context().get_raw_input().get_first_input() == KEY_ESCAPE ) { - // restore original filter - pane.set_filter( filter ); - } else { - pane.set_filter( new_filter ); - } - redraw_pane(); - } while( spopup.context().get_raw_input().get_first_input() != '\n' && - spopup.context().get_raw_input().get_first_input() != KEY_ESCAPE ); - filter_edit = false; - pane.redraw = true; + draw_item_filter_rules(pane.window, 1, 11, item_filter_type::FILTER); + pane.do_filter(w_height - 1, w_width / 2 - 4); } else if( action == "RESET_FILTER" ) { pane.set_filter( "" ); } else if( action == "TOGGLE_AUTO_PICKUP" ) { @@ -1412,7 +387,8 @@ void comestible_inventory::display() get_auto_pickup().add_rule( sitem->items.front() ); sitem->autopickup = true; } - recalc = true; + + redo(true, redraw); } else if( action == "EXAMINE" ) { if( sitem == nullptr || !sitem->is_item_entry() ) { continue; @@ -1420,8 +396,8 @@ void comestible_inventory::display() int ret = 0; const int info_width = w_width / 2; const int info_startx = colstart + info_width; - if( pane.get_area() == AIM_INVENTORY || pane.get_area() == AIM_WORN ) { - int idx = pane.get_area() == AIM_INVENTORY ? sitem->idx : + if( pane.get_area()->info.id == ai::AIM_INVENTORY || pane.get_area()->info.id == ai::AIM_WORN ) { + int idx = pane.get_area()->info.id == ai::AIM_INVENTORY ? sitem->idx : player::worn_position_to_index( sitem->idx ); // Setup a "return to AIM" activity. If examining the item creates a new activity // (e.g. reading, reloading, activating), the new activity will be put on top of @@ -1439,10 +415,10 @@ void comestible_inventory::display() g->u.cancel_activity(); } // Might have changed a stack (activated an item, repaired an item, etc.) - if( pane.get_area() == AIM_INVENTORY ) { + if( pane.get_area()->info.id == ai::AIM_INVENTORY ) { g->u.inv.restack( g->u ); } - recalc = true; + redo(true, redraw); } else { item &it = *sitem->items.front(); std::vector vThisItem; @@ -1458,42 +434,49 @@ void comestible_inventory::display() } else if( ret == KEY_PPAGE || ret == KEY_UP ) { pane.scroll_by( -1 ); } - redraw = true; // item info window overwrote the other pane and the header + redo(recalc, true); // item info window overwrote the other pane and the header } else if( action == "QUIT" ) { exit = true; } else if( action == "PAGE_DOWN" ) { - pane.scroll_by( +itemsPerPage ); + pane.scroll_by( +pane.itemsPerPage ); } else if( action == "PAGE_UP" ) { - pane.scroll_by( -itemsPerPage ); + pane.scroll_by( -pane.itemsPerPage); } else if( action == "DOWN" ) { - pane.scroll_by( +1, inCategoryMode ); + pane.scroll_by( +1); } else if( action == "UP" ) { - pane.scroll_by( -1, inCategoryMode ); + pane.scroll_by( -1); } else if( action == "TOGGLE_VEH" ) { - if( squares[pane.get_area()].can_store_in_vehicle() ) { - // swap the panes if going vehicle will show the same tile - //if (spane.get_area() == dpane.get_area() && spane.in_vehicle() != dpane.in_vehicle()) { - // swap_panes(); - // // disallow for dragged vehicles - //} - //else - if( pane.get_area() != AIM_DRAGGED ) { + if( pane.get_area()->has_vehicle() ) { + if( pane.get_area()->info.id != ai::AIM_DRAGGED ) { // Toggle between vehicle and ground - pane.set_area( squares[pane.get_area()], !pane.in_vehicle() ); + pane.set_area( pane.get_area(), !pane.is_in_vehicle() ); pane.index = 0; - pane.recalc = true; // make sure to update the minimap as well! - redraw = true; + redo(recalc, true); + pane.needs_recalc = true; } } else { popup( _( "No vehicle there!" ) ); - redraw = true; + redo(recalc, true); } } else if( action == "SWITCH_FOOD" ) { - pane.filter_show_food = !pane.filter_show_food; - recalc = true; + uistate.comestible_save.show_food = !uistate.comestible_save.show_food; + pane.title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; + redo(true, redraw); } else if( action == "HEAT_UP" ) { heat_up( sitem->items.front() ); + } else if( action == "CRAFT_WITH" ) { + item* it = sitem->items.front(); + if (it->is_food_container()) { + it = &it->contents.front(); + } + std::string food_name = it->nname(it->typeId()); + g->u.craft(tripoint_zero, string_format("c:%s", food_name)); + //TODO: next 2 lines seem hacky - refreshing twice? + //without 1st line we can see craft menu after it closes + //without 2nd line we can't see comestible menu after crafting closes + g->refresh_all(); + redo(recalc, true); } else if( action == "CONSUME_FOOD" ) { player &p = g->u; item *it = sitem->items.front(); @@ -1506,7 +489,7 @@ void comestible_inventory::display() it->contents.erase( it->contents.begin() ); add_msg( _( "You leave the empty %s." ), it->tname() ); } else { - tripoint target = p.pos() + squares[sitem->area].off; + tripoint target = p.pos() + sitem->area->offset; item_location loc; if( sitem->from_vehicle ) { const cata::optional vp = g->m.veh_at( target ).part_with_feature( "CARGO", true ); @@ -1519,7 +502,7 @@ void comestible_inventory::display() loc = item_location( vehicle_cursor( *veh, part ), it ); } else { - if( sitem->area == AIM_INVENTORY || sitem->area == AIM_WORN ) { + if( sitem->area->info.type == ai::AREA_TYPE_PLAYER) { loc = item_location( p, it ); } else { loc = item_location( map_cursor( target ), it ); @@ -1533,315 +516,14 @@ void comestible_inventory::display() } } -void comestible_inventory_pane::skip_category_headers( int offset ) -{ - assert( offset != 0 ); // 0 would make no sense - assert( static_cast( index ) < items.size() ); // valid index is required - assert( offset == -1 || offset == +1 ); // only those two offsets are allowed - assert( !items.empty() ); // index would not be valid, and this would be an endless loop - while( !items[index].is_item_entry() ) { - mod_index( offset ); - } -} - -void comestible_inventory_pane::mod_index( int offset ) -{ - assert( offset != 0 ); // 0 would make no sense - assert( !items.empty() ); - index += offset; - if( index < 0 ) { - index = static_cast( items.size() ) - 1; - } else if( static_cast( index ) >= items.size() ) { - index = 0; - } -} - -void comestible_inventory_pane::scroll_by( int offset, bool scroll_by_category ) -{ - assert( offset != 0 ); // 0 would make no sense - if( items.empty() ) { - return; - } - if( scroll_by_category ) { - assert( offset == -1 || offset == +1 ); // only those two offsets are allowed - assert( get_cur_item_ptr() != nullptr ); // index must already be valid! - auto cur_cat = items[index].cat; - if( offset > 0 ) { - while( items[index].cat == cur_cat ) { - index++; - if( static_cast( index ) >= items.size() ) { - index = 0; // wrap to begin, stop there. - break; - } - } - } else { - while( items[index].cat == cur_cat ) { - index--; - if( index < 0 ) { - index = static_cast( items.size() ) - 1; // wrap to end, stop there. - break; - } - } - } - } else { - mod_index( offset ); - } - // Make sure we land on an item entry. - skip_category_headers( offset > 0 ? +1 : -1 ); - redraw = true; -} - -comestible_inv_listitem *comestible_inventory_pane::get_cur_item_ptr() -{ - if( static_cast( index ) >= items.size() ) { - return nullptr; - } - return &items[index]; -} - -void comestible_inventory_pane::set_filter( const std::string &new_filter ) -{ - if( filter == new_filter ) { - return; - } - filter = new_filter; - filtercache.clear(); - recalc = true; -} - -bool comestible_inventory::move_content( item &src_container, item &dest_container ) -{ - if( !src_container.is_container() ) { - popup( _( "Source must be container." ) ); - return false; - } - if( src_container.is_container_empty() ) { - popup( _( "Source container is empty." ) ); - return false; - } - - item &src_contents = src_container.contents.front(); - - if( !src_contents.made_of( LIQUID ) ) { - popup( _( "You can unload only liquids into target container." ) ); - return false; - } - - std::string err; - // TODO: Allow buckets here, but require them to be on the ground or wielded - const int amount = dest_container.get_remaining_capacity_for_liquid( src_contents, false, &err ); - if( !err.empty() ) { - popup( err ); - return false; - } - if( src_container.is_non_resealable_container() ) { - if( src_contents.charges > amount ) { - popup( _( "You can't partially unload liquids from unsealable container." ) ); - return false; - } - src_container.on_contents_changed(); - } - dest_container.fill_with( src_contents, amount ); - - uistate.comestible_save.container_content_type = dest_container.contents.front().typeId(); - if( src_contents.charges <= 0 ) { - src_container.contents.clear(); - } - - return true; -} - -units::volume comestible_inv_area::free_volume( bool in_vehicle ) const -{ - assert( id != AIM_ALL ); // should be a specific location instead - if( id == AIM_INVENTORY || id == AIM_WORN ) { - return g->u.volume_capacity() - g->u.volume_carried(); - } - return in_vehicle ? veh->free_volume( vstor ) : g->m.free_volume( pos ); -} - -bool comestible_inv_area::canputitems( const comestible_inv_listitem *advitem ) -{ - bool canputitems = false; - bool from_vehicle = false; - item *it = nullptr; - switch( id ) { - case AIM_CONTAINER: - if( advitem != nullptr && advitem->is_item_entry() ) { - it = advitem->items.front(); - from_vehicle = advitem->from_vehicle; - } - if( get_container( from_vehicle ) != nullptr ) { - it = get_container( from_vehicle ); - } - if( it != nullptr ) { - canputitems = it->is_watertight_container(); - } - break; - default: - canputitems = canputitemsloc; - break; - } - return canputitems; -} - -item *comestible_inv_area::get_container( bool in_vehicle ) -{ - item *container = nullptr; - - if( uistate.comestible_save.container_location != -1 ) { - // try to find valid container in the area - if( uistate.comestible_save.container_location == AIM_INVENTORY ) { - const invslice &stacks = g->u.inv.slice(); - - // check index first - if( stacks.size() > static_cast( uistate.comestible_save.container_index ) ) { - auto &it = stacks[uistate.comestible_save.container_index]->front(); - if( is_container_valid( &it ) ) { - container = ⁢ - } - } - - // try entire area - if( container == nullptr ) { - for( size_t x = 0; x < stacks.size(); ++x ) { - auto &it = stacks[x]->front(); - if( is_container_valid( &it ) ) { - container = ⁢ - uistate.comestible_save.container_index = x; - break; - } - } - } - } else if( uistate.comestible_save.container_location == AIM_WORN ) { - auto &worn = g->u.worn; - size_t idx = static_cast( uistate.comestible_save.container_index ); - if( worn.size() > idx ) { - auto iter = worn.begin(); - std::advance( iter, idx ); - if( is_container_valid( &*iter ) ) { - container = &*iter; - } - } - - // no need to reinvent the wheel - if( container == nullptr ) { - auto iter = worn.begin(); - for( size_t i = 0; i < worn.size(); ++i, ++iter ) { - if( is_container_valid( &*iter ) ) { - container = &*iter; - uistate.comestible_save.container_index = i; - break; - } - } - } - } else { - map &m = g->m; - bool is_in_vehicle = veh && - ( uistate.comestible_save.in_vehicle || ( can_store_in_vehicle() && in_vehicle ) ); - - const itemstack &stacks = is_in_vehicle ? - i_stacked( veh->get_items( vstor ) ) : - i_stacked( m.i_at( pos ) ); - - // check index first - if( stacks.size() > static_cast( uistate.comestible_save.container_index ) ) { - auto it = stacks[uistate.comestible_save.container_index].front(); - if( is_container_valid( it ) ) { - container = it; - } - } - - // try entire area - if( container == nullptr ) { - for( size_t x = 0; x < stacks.size(); ++x ) { - auto it = stacks[x].front(); - if( is_container_valid( it ) ) { - container = it; - uistate.comestible_save.container_index = x; - break; - } - } - } - } - - // no valid container in the area, resetting container - if( container == nullptr ) { - set_container( nullptr ); - desc[0] = _( "Invalid container" ); - } - } - - return container; -} - -void comestible_inv_area::set_container( const comestible_inv_listitem *advitem ) -{ - if( advitem != nullptr ) { - item *it( advitem->items.front() ); - uistate.comestible_save.container_location = advitem->area; - uistate.comestible_save.in_vehicle = advitem->from_vehicle; - uistate.comestible_save.container_index = advitem->idx; - uistate.comestible_save.container_type = it->typeId(); - uistate.comestible_save.container_content_type = !it->is_container_empty() ? - it->contents.front().typeId() : "null"; - set_container_position(); - } else { - uistate.comestible_save.container_location = -1; - uistate.comestible_save.container_index = 0; - uistate.comestible_save.in_vehicle = false; - uistate.comestible_save.container_type = "null"; - uistate.comestible_save.container_content_type = "null"; - } -} - -bool comestible_inv_area::is_container_valid( const item *it ) const -{ - if( it != nullptr ) { - if( it->typeId() == uistate.comestible_save.container_type ) { - if( it->is_container_empty() ) { - if( uistate.comestible_save.container_content_type == "null" ) { - return true; - } - } else { - if( it->contents.front().typeId() == uistate.comestible_save.container_content_type ) { - return true; - } - } - } - } - - return false; -} - -void comestible_inv_area::set_container_position() -{ - // update the offset of the container based on location - if( uistate.comestible_save.container_location == AIM_DRAGGED ) { - off = g->u.grab_point; - } else { - off = aim_vector( static_cast( uistate.comestible_save.container_location ) ); - } - // update the absolute position - pos = g->u.pos() + off; - // update vehicle information - if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", - false ) ) { - veh = &vp->vehicle(); - vstor = vp->part_index(); - } else { - veh = nullptr; - vstor = -1; - } -} - static const trait_id trait_GRAZER( "GRAZER" ); static const trait_id trait_RUMINANT( "RUMINANT" ); -void comestible_inv() +void comestible_inv(int b) { player &p = g->u; map &m = g->m; + //lifted from handle_action.cpp - void game::eat(item_location(*menu)(player & p), int pos) if( ( p.has_active_mutation( trait_RUMINANT ) || p.has_active_mutation( trait_GRAZER ) ) && ( m.ter( p.pos() ) == t_underbrush || m.ter( p.pos() ) == t_shrub ) ) { if( p.get_hunger() < 20 ) { @@ -1890,7 +572,7 @@ void comestible_inv() } } comestible_inventory new_inv; - new_inv.display(); + new_inv.display(b); } void comestible_inventory::refresh_minimap() @@ -1898,8 +580,8 @@ void comestible_inventory::refresh_minimap() // redraw border around minimap draw_border( mm_border ); // minor addition to border for AIM_ALL, sorta hacky - if( pane.get_area() == AIM_ALL ) { - mvwprintz( mm_border, point( 1, 0 ), c_light_gray, utf8_truncate( _( "All" ), minimap_width ) ); + if( pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { + mvwprintz( mm_border, point( 1, 0 ), c_light_gray, utf8_truncate( _( "Mul" ), minimap_width ) ); } // refresh border, then minimap wrefresh( mm_border ); @@ -1908,198 +590,56 @@ void comestible_inventory::refresh_minimap() void comestible_inventory::draw_minimap() { - // if player is in one of the below, invert the player cell - static const std::array player_locations = { - {AIM_CENTER, AIM_INVENTORY, AIM_WORN} - }; // get the center of the window tripoint pc = { getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0 }; // draw the 3x3 tiles centered around player g->m.draw( minimap, g->u.pos() ); - char sym = get_minimap_sym(); + + if (pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI) return; + + char sym = minimap_get_sym(); if( sym != '\0' ) { - auto sq = squares[pane.get_area()]; - auto pt = pc + sq.off; + auto sq = pane.get_area(); + auto pt = pc + sq->offset; // invert the color if pointing to the player's position - auto cl = sq.id == AIM_INVENTORY || sq.id == AIM_WORN ? + auto cl = sq->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ? invert_color( c_light_cyan ) : c_light_cyan.blink(); mvwputch( minimap, pt.xy(), cl, sym ); } // Invert player's tile color if exactly one pane points to player's tile - bool player_selected = false; - //const auto is_selected = [this](const aim_location& where) { - // return where == this->pane.get_area(); - //}; - for( auto &loc : player_locations ) { - if( loc == pane.get_area() ) { - player_selected = true; - break; - } - } - - + bool player_selected = pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER; g->u.draw( minimap, g->u.pos(), player_selected ); - - //if (player_selected) { - //} } -char comestible_inventory::get_minimap_sym() const -{ - static const std::array g_nome = { { - '@', '#', '#', '#', '#', '@', '#', - '#', '#', '#', 'D', '^', 'C', '@' - } - }; - char ch = g_nome[pane.get_area()]; - switch( ch ) { - case '@': - ch = '^'; - break; - case '#': - ch = pane.in_vehicle() ? 'V' : '\0'; - break; - case '^': // do not show anything - ch = '\0'; - break; +char comestible_inventory::minimap_get_sym() const { + if (pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER) { + return '^'; + } + else if (pane.is_in_vehicle()) { + return 'V'; + } + else { + return ' '; } - return ch; } -//aim_location comestible_inv_area::offset_to_location() const -//{ -// static aim_location loc_array[3][3] = { -// {AIM_NORTHWEST, AIM_NORTH, AIM_NORTHEAST}, -// {AIM_WEST, AIM_CENTER, AIM_EAST}, -// {AIM_SOUTHWEST, AIM_SOUTH, AIM_SOUTHEAST} -// }; -// return loc_array[off.y + 1][off.x + 1]; -//} - void comestible_inventory::do_return_entry() { // only save pane settings - //save_settings(true); g->u.assign_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ); g->u.activity.auto_resume = true; uistate.comestible_save.exit_code = exit_re_entry; + save_settings(); } -char const *comestible_inventory::set_string_params( nc_color &print_color, int value, - bool selected, - bool need_highlight ) -{ - char const *string_format; - if( value > 0 ) { - print_color = need_highlight ? c_yellow_green : c_green; - string_format = "+%d"; - } else if( value < 0 ) { - print_color = need_highlight ? c_yellow_red : c_red; - string_format = "%d"; - } else { - print_color = need_highlight ? c_yellow : c_dark_gray; - string_format = ""; - } - - if( selected ) { - print_color = hilite( c_white ); - } - return string_format; -} - -const islot_comestible &comestible_inventory::get_edible_comestible( player &p, - const item &it ) const -{ - if( it.is_comestible() && p.can_eat( it ).success() ) { - // Ok since can_eat() returns false if is_craft() is true - return *it.type->comestible; - } - static const islot_comestible dummy{}; - return dummy; -} - -time_duration comestible_inventory::get_time_left( player &p, const item &it ) const -{ - time_duration time_left = 0_turns; - const time_duration shelf_life = get_edible_comestible( p, it ).spoils; - if( shelf_life > 0_turns ) { - 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 comestible_inventory::get_time_left_rounded( player &p, const item &it ) const +void comestible_inventory::redo(bool needs_recalc, bool needs_redraw) { - if( it.is_going_bad() ) { - return _( "soon!" ); - } - - time_duration time_left = get_time_left( p, it ); - - //const auto make_result = [this](const time_duration& d, const char* verbose_str, - // const char* short_str) { - // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); - //}; - - time_duration divider = 0_turns; - time_duration vicinity = 0_turns; - - if( time_left > 1_days ) { - divider = 1_days; - vicinity = 2_hours; - } else if( time_left > 1_hours ) { - divider = 1_hours; - vicinity = 5_minutes; - } // Minutes and seconds can be estimated precisely. - - if( divider != 0_turns ) { - const time_duration remainder = time_left % divider; - - if( remainder >= divider - vicinity ) { - time_left += divider; - } else if( remainder > vicinity ) { - if( remainder < divider / 2 ) { - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("> %s", time_to_comestible_str(time_left)); - } else { - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("< %s", time_to_comestible_str(time_left)); - } - } - } - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("~ %s", time_to_comestible_str(time_left)); -} - -std::string comestible_inventory::time_to_comestible_str( const time_duration &d ) const -{ - if( d >= calendar::INDEFINITELY_LONG_DURATION ) { - return _( "forever" ); - } - - const float day = to_days( d ); - std::string format; - if( day < 1.00 ) { - format = _( "%.2f days" ); - } else if( day > 1.00 ) { - format = _( "%.0f days" ); - } else { - format = _( "1 day" ); - } + recalc = needs_recalc; + pane.needs_recalc = needs_recalc; - return string_format( format, day ); + redraw = needs_redraw; + pane.needs_redraw = needs_redraw; } void comestible_inventory::heat_up( item *it_to_heat ) @@ -2163,16 +703,14 @@ void comestible_inventory::heat_up( item *it_to_heat ) //check we can actually heat up if( !has_heat_item && !can_use_hotplate ) { popup( _( "You don't have a suitable container or hotplate with enough charges." ) ); - redraw = true; - //p.add_msg_if_player(m_info, _("You don't have a suitable container or hotplate with enough charges.")); + redo(recalc, true); return; } if( has_heat_item && !can_use_hotplate ) { if( !is_near_fire && !can_use_bio ) { popup( _( "You need to be near fire to heat an item in a container." ) ); - redraw = true; - //p.add_msg_if_player(m_info, _("You need to be near fire to heat an item in a container.")); + redo(recalc, true); return; } } @@ -2204,7 +742,7 @@ void comestible_inventory::heat_up( item *it_to_heat ) if( sm.ret < 0 ) { //'Never mind' - redraw = true; + redo(recalc, true); return; } choice = sm.ret; diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 7eb4236d2eb0b..4004d62ba1b9f 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -1,6 +1,12 @@ #pragma once #ifndef comestible_inv_H #define comestible_inv_H +#include "cursesdef.h" +#include "point.h" +#include "units.h" +#include "game.h" +#include "itype.h" +#include "comestible_inv_pane.h" #include #include @@ -11,363 +17,22 @@ #include #include -#include "cursesdef.h" -#include "point.h" -#include "units.h" -#include "game.h" - -#include "advanced_inv.h" -#include "itype.h" - class uilist; class vehicle; class item; -//enum aim_location { -// AIM_INVENTORY = 0, -// AIM_SOUTHWEST, -// AIM_SOUTH, -// AIM_SOUTHEAST, -// AIM_WEST, -// AIM_CENTER, -// AIM_EAST, -// AIM_NORTHWEST, -// AIM_NORTH, -// AIM_NORTHEAST, -// AIM_DRAGGED, -// AIM_ALL, -// AIM_CONTAINER, -// AIM_WORN, -// NUM_AIM_LOCATIONS, -// // only useful for AIM_ALL -// AIM_AROUND_BEGIN = AIM_SOUTHWEST, -// AIM_AROUND_END = AIM_NORTHEAST -//}; -// -enum comestible_inv_sortby { - COMESTIBLE_SORTBY_NAME, - COMESTIBLE_SORTBY_WEIGHT, - COMESTIBLE_SORTBY_VOLUME, - COMESTIBLE_SORTBY_CALORIES, - COMESTIBLE_SORTBY_QUENCH, - COMESTIBLE_SORTBY_JOY, - COMESTIBLE_SORTBY_SPOILAGE -}; - -//struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { -// bool operator()(char x, char y) const { -// return toupper(static_cast(x)) < toupper(static_cast(y)); -// } -//}; - -void comestible_inv(); - -/** - * Cancels ongoing move all action. - * TODO: Make this not needed. - */ -void cancel_aim_processing(); - -struct comestible_inv_listitem; - -/** - * Defines the source of item stacks. - */ -struct comestible_inv_area { - const aim_location id; - // Used for the small overview 3x3 grid - point hscreen = point_zero; - // relative (to the player) position of the map point - tripoint off; - /** Long name, displayed, translated */ - const std::string name = "fake"; - /** Appears as part of the list */ - const std::string shortname = "FK"; // FK in my coffee - /** Appears as part of the legend at the top right */ - const std::string minimapname = "FKM"; // FK in my coffee - - const aim_location relative_location; - - const std::string actionname = "FKA"; - // absolute position of the map point. - tripoint pos; - /** Can we put items there? Only checks if location is valid, not if - selected container in pane is. For full check use canputitems() **/ - bool canputitemsloc; - // vehicle pointer and cargo part index - vehicle *veh; - int vstor; - // description, e.g. vehicle name, label, or terrain - std::array desc; - // flags, e.g. FIRE, TRAP, WATER - std::string flags; - // total volume and weight of items currently there - units::volume volume; - units::mass weight; - // maximal count / volume of items there. - int max_size; - - comestible_inv_area( aim_location id ) : id( id ), relative_location( id ) {} - comestible_inv_area( aim_location id, int hscreenx, int hscreeny, tripoint off, - const std::string &name, const std::string &shortname, - const std::string &minimapname, const aim_location relative_location, - const std::string &actionname ) : id( id ), - hscreen( hscreenx, hscreeny ), off( off ), name( name ), shortname( shortname ), - minimapname( minimapname ), relative_location( relative_location ), actionname( actionname ), - canputitemsloc( false ), veh( nullptr ), vstor( -1 ), volume( 0_ml ), - weight( 0_gram ), max_size( 0 ) { - } - - void init(); - // if you want vehicle cargo, specify so via `in_vehicle' - units::volume free_volume( bool in_vehicle = false ) const; - int get_item_count() const; - // Other area is actually the same item source, e.g. dragged vehicle to the south and AIM_SOUTH - //bool is_same( const comestible_inv_area &other ) const; - // does _not_ check vehicle storage, do that with `can_store_in_vehicle()' below - bool canputitems( const comestible_inv_listitem *advitem = nullptr ); - // if you want vehicle cargo, specify so via `in_vehicle' - item *get_container( bool in_vehicle = false ); - void set_container( const comestible_inv_listitem *advitem ); - bool is_container_valid( const item *it ) const; - void set_container_position(); - aim_location offset_to_location() const; - bool can_store_in_vehicle() const { - // disallow for non-valid vehicle locations - if( id > AIM_DRAGGED || id < AIM_SOUTHWEST ) { - return false; - } - return veh != nullptr && vstor >= 0; - } - - aim_location get_relative_location() { - if( !( tile_iso && use_tiles ) ) { - return id; - } else { - return relative_location; - } - } - - //std::string get_minimap_sym() { - - //} -}; +void comestible_inv(int bio = -1); // see item_factory.h class item_category; -/** - * Entry that is displayed in a adv. inv. pane. It can either contain a - * single item or a category header or nothing (empty entry). - * Most members are used only for sorting. - */ -struct comestible_inv_listitem { - using itype_id = std::string; - /** - * Index of the item in the itemstack. - */ - int idx; - /** - * The location of the item, never AIM_ALL. - */ - aim_location area; - // the id of the item - itype_id id; - // The list of items, and empty when a header - std::list items; - /** - * The displayed name of the item/the category header. - */ - std::string name; - /** - * Name of the item (singular) without damage (or similar) prefix, used for sorting. - */ - std::string name_without_prefix; - /** - * Whether auto pickup is enabled for this item (based on the name). - */ - bool autopickup; - /** - * The stack count represented by this item, should be >= 1, should be 1 - * for anything counted by charges. - */ - int stacks; - /** - * The volume of all the items in this stack, used for sorting. - */ - units::volume volume; - /** - * The weight of all the items in this stack, used for sorting. - */ - units::mass weight; - - /** - * TODO:docs - */ - int calories; - int quench; - int joy; - - /** - * The item category, or the category header. - */ - const item_category *cat; - /** - * Is the item stored in a vehicle? - */ - bool from_vehicle; - - - //TODO - const islot_comestible &get_edible_comestible( player &p, const item &it ) const; - - /** - * Whether this is a category header entry, which does *not* have a reference - * to an item, only @ref cat is valid. - */ - bool is_category_header() const; - - /** Returns true if this is an item entry */ - bool is_item_entry() const; - /** - * Create a category header entry. - * @param cat The category reference, must not be null. - */ - comestible_inv_listitem( const item_category *cat ); - - /** - * Creates an empty entry, both category and item pointer are null. - */ - comestible_inv_listitem(); - /** - * Create a normal item entry. - * @param an_item The item pointer. Must not be null. - * @param index The index - * @param count The stack size - * @param area The source area. Must not be AIM_ALL. - * @param from_vehicle Is the item from a vehicle cargo space? - */ - comestible_inv_listitem( item *an_item, int index, int count, - aim_location area, bool from_vehicle ); - /** - * Create a normal item entry. - * @param list The list of item pointers. - * @param index The index - * @param area The source area. Must not be AIM_ALL. - * @param from_vehicle Is the item from a vehicle cargo space? - */ - comestible_inv_listitem( const std::list &list, int index, - aim_location area, bool from_vehicle ); -}; - -/** - * Displayed pane, what is shown on the screen. - */ -class comestible_inventory_pane -{ - private: - aim_location area = NUM_AIM_LOCATIONS; - aim_location prev_area = area; - // pointer to the square this pane is pointing to - bool viewing_cargo = false; - bool prev_viewing_cargo = false; - public: - // set the pane's area via its square, and whether it is viewing a vehicle's cargo - void set_area( comestible_inv_area &square, bool in_vehicle_cargo = false ) { - prev_area = area; - prev_viewing_cargo = viewing_cargo; - area = square.id; - viewing_cargo = square.can_store_in_vehicle() && in_vehicle_cargo; - } - void restore_area() { - area = prev_area; - viewing_cargo = prev_viewing_cargo; - } - aim_location get_area() const { - return area; - } - bool prev_in_vehicle() const { - return prev_viewing_cargo; - } - bool in_vehicle() const { - return viewing_cargo; - } - bool on_ground() const { - return area > AIM_INVENTORY && area < AIM_DRAGGED; - } - /** - * Index of the selected item (index of @ref items), - */ - int index; - comestible_inv_sortby sortby; - catacurses::window window; - std::vector items; - /** - * The current filter string. - */ - std::string filter; - /** - * Food or Drug filter. True = show food. - */ - bool filter_show_food; - /** - * Whether to recalculate the content of this pane. - * Implies @ref redraw. - */ - bool recalc; - /** - * Whether to redraw this pane. - */ - bool redraw; - - void add_items_from_area( comestible_inv_area &square, bool vehicle_override = false ); - /** - * Makes sure the @ref index is valid (if possible). - */ - void fix_index(); - /** - * @param it The item to check, oly the name member is examined. - * @return Whether the item should be filtered (and not shown). - */ - bool is_filtered( const comestible_inv_listitem &it ) const; - /** - * Same as the other, but checks the real item. - */ - bool is_filtered( const item &it ) const; - /** - * Scroll @ref index, by given offset, set redraw to true, - * @param offset Must not be 0. - */ - void scroll_by( int offset, bool scroll_by_category = false ); - /** - * @return either null, if @ref index is invalid, or the selected - * item in @ref items. - */ - comestible_inv_listitem *get_cur_item_ptr(); - /** - * Set the filter string, disables filtering when the filter string is empty. - */ - void set_filter( const std::string &new_filter ); - /** - * Insert additional category headers on the top of each page. - */ - void paginate( size_t itemsPerPage ); - private: - /** Scroll to next non-header entry */ - void skip_category_headers( int offset ); - /** Only add offset to index, but wrap around! */ - void mod_index( int offset ); - - mutable std::map> filtercache; -}; - class comestible_inventory { public: comestible_inventory(); ~comestible_inventory(); - void display(); + void display(int bio); private: const int head_height; const int min_w_height; @@ -381,11 +46,10 @@ class comestible_inventory const int minimap_height = 3; void draw_minimap(); void refresh_minimap(); - char get_minimap_sym() const; + char minimap_get_sym() const; bool inCategoryMode; - int itemsPerPage; int w_height; int w_width; @@ -402,7 +66,7 @@ class comestible_inventory comestible_inventory_pane pane; //static const comestible_inventory_pane null_pane; - std::array squares; + std::array squares; catacurses::window head; catacurses::window window; @@ -410,23 +74,25 @@ class comestible_inventory bool exit; // store/load settings (such as index, filter, etc) - void save_settings( bool only_panes ); - void load_settings(); + void save_settings(); + //void load_settings(); // used to return back to AIM when other activities queued are finished void do_return_entry(); + void redo(bool needs_recalc, bool needs_redraw); // returns true if currently processing a routine // (such as `MOVE_ALL_ITEMS' with `AIM_ALL' source) //bool is_processing() const; - static std::string get_sortname( comestible_inv_sortby sortby ); + //static std::string get_sortname( comestible_inv_sortby sortby ); //bool move_all_items(bool nested_call = false); - void print_items( comestible_inventory_pane &pane ); - void recalc_pane(); - void redraw_pane(); + //void print_items( comestible_inventory_pane &pane ); + //void recalc_pane(); + //void redraw_pane(); // Returns the x coordinate where the header started. The header is // displayed right of it, everything left of it is till free. - int print_header( comestible_inventory_pane &pane, aim_location sel ); + //int print_header( comestible_inventory_pane &pane, aim_location sel ); void init(); + void set_pane_legend(); /** * Translate an action ident from the input context to an aim_location. * @param action Action ident to translate @@ -440,7 +106,7 @@ class comestible_inventory * Show the sort-by menu and change the sorting of this pane accordingly. * @return whether the sort order was actually changed. */ - bool show_sort_menu( comestible_inventory_pane &pane ); + bool show_sort_menu(); /** * Checks whether one can put items into the supplied location. * If the supplied location is AIM_ALL, query for the actual location @@ -455,7 +121,7 @@ class comestible_inventory * @param src_container Source container * @param dest_container Destination container */ - bool move_content( item &src_container, item &dest_container ); + //bool move_content( item &src_container, item &dest_container ); /** * Setup how many items/charges (if counted by charges) should be moved. * @param destarea Where to move to. This must not be AIM_ALL. @@ -472,8 +138,8 @@ class comestible_inventory //void menu_square( uilist &menu ); - std::string get_location_key( aim_location area ); - char get_direction_key( aim_location area ); + //std::string get_location_key( aim_location area ); + //char get_direction_key( aim_location area ); /** * Converts from screen relative location to game-space relative location @@ -481,13 +147,13 @@ class comestible_inventory */ //static aim_location screen_relative_location( aim_location area ); - char const *set_string_params( nc_color &print_color, int value, bool selected, - bool need_highlight = false ); + //char const *set_string_params( nc_color &print_color, int value, bool selected, + // bool need_highlight = false ); //nc_color set_string_params(int value, bool need_highlight = false); - time_duration get_time_left( player &p, const item &it ) const; - const islot_comestible &get_edible_comestible( player &p, const item &it ) const; - std::string get_time_left_rounded( player &p, const item &it ) const; - std::string time_to_comestible_str( const time_duration &d ) const; + //time_duration get_time_left( player &p, const item &it ) const; + //const islot_comestible &get_edible_comestible( player &p, const item &it ) const; + //std::string get_time_left_rounded( player &p, const item &it ) const; + //std::string time_to_comestible_str( const time_duration &d ) const; void heat_up( item *it ); }; diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp new file mode 100644 index 0000000000000..b74f6e1ed05c1 --- /dev/null +++ b/src/comestible_inv_area.cpp @@ -0,0 +1,279 @@ +#include "auto_pickup.h" +#include "avatar.h" +#include "cata_utility.h" +#include "catacharset.h" +#include "debug.h" +#include "field.h" +#include "input.h" +#include "item_category.h" +#include "item_search.h" +#include "item_stack.h" +#include "map.h" +#include "mapdata.h" +#include "messages.h" +#include "options.h" +#include "output.h" +#include "player.h" +#include "player_activity.h" +#include "string_formatter.h" +#include "string_input_popup.h" +#include "translations.h" +#include "trap.h" +#include "ui.h" +#include "uistate.h" +#include "vehicle.h" +#include "vehicle_selector.h" +#include "vpart_position.h" +#include "calendar.h" +#include "color.h" +#include "game_constants.h" +#include "int_id.h" +#include "inventory.h" +#include "item.h" +#include "optional.h" +#include "ret_val.h" +#include "type_id.h" +#include "clzones.h" +#include "colony.h" +#include "enums.h" +#include "faction.h" +#include "item_location.h" +#include "map_selector.h" +#include "pimpl.h" + +#include "comestible_inv_area.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__ANDROID__) +# include +#endif + +void comestible_inv_area::init() +{ + offset = info.default_offset; + tripoint pos = g->u.pos() + offset; + veh = nullptr; + veh_part = -1; + + using ai = comestible_inv_area_info; + switch (info.id) { + case ai::AIM_INVENTORY: + case ai::AIM_WORN: + is_valid = true; + break; + case ai::AIM_DRAGGED: + if (g->u.get_grab_type() != OBJECT_VEHICLE) { + is_valid = false; + desc[0] = _("Not dragging any vehicle!"); + break; + } + // Reset position because offset changed + pos = g->u.pos() + g->u.grab_point; + if (const cata::optional vp = g->m.veh_at(pos).part_with_feature("CARGO", + false)) { + veh = &vp->vehicle(); + veh_part = vp->part_index(); + } + else { + veh = nullptr; + veh_part = -1; + } + if (veh_part >= 0) { + desc[0] = veh->name; + is_valid = true; + //max_size = MAX_ITEM_IN_VEHICLE_STORAGE; + } + else { + veh = nullptr; + is_valid = false; + desc[0] = _("No dragged vehicle!"); + } + break; + case ai::AIM_ALL: + desc[0] = _("All 9 squares"); + is_valid = true; + break; + case ai::AIM_ALL_I_W: + desc[0] = _("Around,Inv,Worn"); + is_valid = true; + break; + case ai::AIM_SOUTHWEST: + case ai::AIM_SOUTH: + case ai::AIM_SOUTHEAST: + case ai::AIM_WEST: + case ai::AIM_CENTER: + case ai::AIM_EAST: + case ai::AIM_NORTHWEST: + case ai::AIM_NORTH: + case ai::AIM_NORTHEAST: + if (const cata::optional vp = g->m.veh_at(pos).part_with_feature("CARGO", + false)) { + veh = &vp->vehicle(); + veh_part = vp->part_index(); + } + else { + veh = nullptr; + veh_part = -1; + } + is_valid = has_vehicle() || g->m.can_put_items_ter_furn(pos); + //max_size = MAX_ITEM_IN_SQUARE; + if (has_vehicle()) { + desc[1] = vpart_position(*veh, veh_part).get_label().value_or(""); + } + // get graffiti or terrain name + desc[0] = g->m.has_graffiti_at(pos) ? + g->m.graffiti_at(pos) : g->m.name(pos); + default: + break; + } + + /* assemble a list of interesting traits of the target square */ + // fields? with a special case for fire + bool danger_field = false; + const field& tmpfld = g->m.field_at(pos); + for (auto& fld : tmpfld) { + const field_entry& cur = fld.second; + if (fld.first.obj().has_fire) { + flags.append(_(" FIRE")); + } + else { + if (cur.is_dangerous()) { + danger_field = true; + } + } + } + if (danger_field) { + flags.append(_(" DANGER")); + } + + // trap? + const trap& tr = g->m.tr_at(pos); + if (tr.can_see(pos, g->u) && !tr.is_benign()) { + flags.append(_(" TRAP")); + } + + // water? + static const std::array ter_water = { + {t_water_dp, t_water_pool, t_swater_dp, t_water_sh, t_swater_sh, t_sewage, t_water_moving_dp, t_water_moving_sh } + }; + auto ter_check = [pos] + (const ter_id& id) { + return g->m.ter(pos) == id; + }; + if (std::any_of(ter_water.begin(), ter_water.end(), ter_check)) { + flags.append(_(" WATER")); + } + + // remove leading space + if (flags.length() && flags[0] == ' ') { + flags.erase(0, 1); + } +} + +bool comestible_inv_area::canputitems() +{ + return is_valid; +} + +inline std::string comestible_inv_area::get_location_key() +{ + return comestible_inv_area::get_info(get_relative_location()).minimapname; +} + +template +static comestible_inv_area::area_items mi_stacked(T items) +{ + //create a new container for our stacked items + comestible_inv_area::area_items stacks; + // // make a list of the items first, so we can add non stacked items back on + // std::list items(things.begin(), things.end()); + // used to recall indices we stored `itype_id' item at in itemstack + std::unordered_map> cache; + // iterate through and create stacks + for (auto& elem : items) { + const auto id = elem.typeId(); + auto iter = cache.find(id); + bool got_stacked = false; + // cache entry exists + if (iter != cache.end()) { + // check to see if it stacks with each item in a stack, not just front() + for (auto& idx : iter->second) { + for (auto& it : stacks[idx]) { + if ((got_stacked = it->display_stacked_with(elem))) { + stacks[idx].push_back(&elem); + break; + } + } + if (got_stacked) { + break; + } + } + } + if (!got_stacked) { + cache[id].insert(stacks.size()); + stacks.push_back({ &elem }); + } + } + return stacks; +} + +comestible_inv_area::area_items comestible_inv_area::get_items(bool use_vehicle) { + if (use_vehicle) { + assert(has_vehicle()); + return mi_stacked(veh->get_items(veh_part)); + } + else { + map& m = g->m; + return mi_stacked(m.i_at(g->u.pos() + offset)); + } +} + +units::volume comestible_inv_area::get_max_volume(bool use_vehicle) { + if (use_vehicle) { + assert(has_vehicle()); + return veh->max_volume(veh_part); + } + else { + map& m = g->m; + return m.max_volume(g->u.pos() + offset); + } +} + +std::string comestible_inv_area::get_name(bool use_vehicle) const { + if (use_vehicle) { + assert(has_vehicle()); + return veh->name; + } + else { + return info.name; + } +} + +bool comestible_inv_area::is_vehicle_default() const { + if (has_vehicle()) { + if (get_relative_location() == comestible_inv_area_info::AIM_DRAGGED) { + return true; + } + else { + // check item stacks in vehicle and map at said square + auto map_stack = g->m.i_at(g->u.pos() + offset); + auto veh_stack = veh->get_items( veh_part ); + // auto switch to vehicle storage if vehicle items are there, or neither are there + return (!veh_stack.empty() || map_stack.empty()); + } + } + return false; +} diff --git a/src/comestible_inv_area.h b/src/comestible_inv_area.h new file mode 100644 index 0000000000000..de980c0005c44 --- /dev/null +++ b/src/comestible_inv_area.h @@ -0,0 +1,221 @@ +#pragma once +#ifndef COMESTIBLE_INV_AREA_H +#define COMESTIBLE_INV_AREA_H + +#include "cursesdef.h" +#include "point.h" +#include "units.h" +#include "game.h" +#include "itype.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Defines the source of item stacks. + */ +struct comestible_inv_area_info { + enum area_type { + AREA_TYPE_PLAYER, + AREA_TYPE_GROUND, + AREA_TYPE_MULTI + }; + + enum aim_location { + AIM_SOUTHWEST, + AIM_SOUTH, + AIM_SOUTHEAST, + AIM_WEST, + AIM_CENTER, + AIM_EAST, + AIM_NORTHWEST, + AIM_NORTH, + AIM_NORTHEAST, + + AIM_DRAGGED, + AIM_INVENTORY, + AIM_WORN, + + AIM_ALL, + AIM_ALL_I_W, + + NUM_AIM_LOCATIONS + }; + + + + const aim_location id; + // Used for the small overview 3x3 grid + point hscreen; + // relative (to the player) position of the map point + tripoint default_offset; + + area_type type; + + /** Long name, displayed, translated */ + const std::string name; + /** Appears as part of the list */ + const std::string shortname; + /** Appears as part of the legend at the top right */ + const std::string minimapname; + + const aim_location relative_location; + const std::string actionname; + + std::vector multi_locations = {}; + + bool has_area(aim_location loc) const { + return (std::find(multi_locations.begin(), multi_locations.end(), loc) != multi_locations.end()); + } + + comestible_inv_area_info(aim_location id, int hscreenx, int hscreeny, tripoint off, + const std::string& name, const std::string& shortname, + const std::string& minimapname, const aim_location relative_location, + const std::string& actionname) : id(id), + hscreen(hscreenx, hscreeny), default_offset(off), name(name), shortname(shortname), + minimapname(minimapname), relative_location(relative_location), actionname(actionname) { + static const std::array< aim_location, 9> ground_locations = { AIM_SOUTHWEST, + AIM_SOUTH, + AIM_SOUTHEAST, + AIM_WEST, + AIM_CENTER, + AIM_EAST, + AIM_NORTHWEST, + AIM_NORTH, + AIM_NORTHEAST }; + if (id == AIM_ALL) { + type = AREA_TYPE_MULTI; + multi_locations = std::vector(ground_locations.begin(), ground_locations.end()); + } else if (id == AIM_ALL_I_W) { + type = AREA_TYPE_MULTI; + multi_locations = std::vector(ground_locations.begin(), ground_locations.end()); + multi_locations.push_back(AIM_INVENTORY); + multi_locations.push_back(AIM_WORN); + } + else { + if (id == AIM_INVENTORY || id == AIM_WORN) { + type = AREA_TYPE_PLAYER; + } + else { + type = AREA_TYPE_GROUND; + } + multi_locations = { id }; + } + } +}; + + + +class comestible_inv_area { +public : + + // *INDENT-OFF* + static comestible_inv_area_info get_info(comestible_inv_area_info::aim_location loc) { + using i = comestible_inv_area_info; + static const std::array< comestible_inv_area_info, comestible_inv_area_info::NUM_AIM_LOCATIONS> area_info = { { + { i::AIM_SOUTHWEST, 30, 3, tripoint_south_west, _("South West"), _("SW"), "1", i::AIM_WEST, "ITEMS_SW" }, + { i::AIM_SOUTH, 33, 3, tripoint_south, _("South"), _("S"), "2", i::AIM_SOUTHWEST, "ITEMS_S"}, + { i::AIM_SOUTHEAST, 36, 3, tripoint_south_east, _("South East"), _("SE"), "3", i::AIM_SOUTH, "ITEMS_SE"}, + { i::AIM_WEST, 30, 2, tripoint_west, _("West"), _("W"), "4", i::AIM_NORTHWEST, "ITEMS_W" }, + { i::AIM_CENTER, 33, 2, tripoint_zero, _("Directly below you"), _("DN"), "5", i::AIM_CENTER, "ITEMS_CE"}, + { i::AIM_EAST, 36, 2, tripoint_east, _("East"), _("E"), "6", i::AIM_SOUTHEAST, "ITEMS_E" }, + { i::AIM_NORTHWEST, 30, 1, tripoint_north_west, _("North West"), _("NW"), "7", i::AIM_NORTH, "ITEMS_NW"}, + { i::AIM_NORTH, 33, 1, tripoint_north, _("North"), _("N"), "8", i::AIM_NORTHEAST, "ITEMS_N" }, + { i::AIM_NORTHEAST, 36, 1, tripoint_north_east, _("North East"), _("NE"), "9", i::AIM_EAST, "ITEMS_NE" }, + + { i::AIM_DRAGGED, 25, 1, tripoint_zero, _("Grabbed Vehicle"), _("GR"), "D", i::AIM_DRAGGED, "ITEMS_DRAGGED_CONTAINER" }, + { i::AIM_INVENTORY, 25, 2, tripoint_zero, _("Inventory"), _("I"), "I", i::AIM_INVENTORY, "ITEMS_INVENTORY" }, + { i::AIM_WORN, 22, 2, tripoint_zero, _("Worn Items"), _("W"), "W", i::AIM_WORN, "ITEMS_WORN"}, + + { i::AIM_ALL, 25, 3, tripoint_zero, _("Surrounding area"), "", "A", i::AIM_ALL, "ITEMS_AROUND" }, + { i::AIM_ALL_I_W, 18, 3, tripoint_zero, _("Everything"), "", "A+I+W", i::AIM_ALL_I_W, "ITEMS_AROUND_I_W" } + } + }; + return area_info[loc]; + } + // *INDENT-ON* + + const comestible_inv_area_info info; + +private: + + /** Can we put items there? Only checks if location is valid, not if + selected container in pane is. For full check use canputitems() **/ + bool is_valid; + // vehicle pointer and cargo part index + vehicle* veh; + int veh_part; + +public: + // roll our own, to handle moving stacks better + using area_items = std::vector >; + + area_items get_items(bool use_vehicle); + + units::volume get_max_volume(bool use_vehicle); + + std::string get_name(bool use_vehicle) const; + + bool is_vehicle_default() const; + + // absolute position of the map point. + //tripoint pos; + // description, e.g. vehicle name, label, or terrain + std::array desc; + // flags, e.g. FIRE, TRAP, WATER + std::string flags; + // total volume and weight of items currently there + //units::volume volume; + //units::mass weight; + // maximal count / volume of items there. + //int max_size; + + tripoint offset; + + + //comestible_inv_area(aim_location id) : id(id), relative_location(id) {} + //comestible_inv_area(aim_location id, int hscreenx, int hscreeny, tripoint off, + // const std::string& name, const std::string& shortname, + // const std::string& minimapname, const aim_location relative_location, + // const std::string& actionname) : id(id), + // hscreen(hscreenx, hscreeny), off(off), name(name), shortname(shortname), + // minimapname(minimapname), relative_location(relative_location), actionname(actionname), + // is_valid(false), veh(nullptr), veh_part(-1), volume(0_ml), + // weight(0_gram), max_size(0) { + //} + + comestible_inv_area(comestible_inv_area_info area_info) : info(area_info), + is_valid(false), veh(nullptr), veh_part(-1) { + } + + void init(); + // Other area is actually the same item source, e.g. dragged vehicle to the south and AIM_SOUTH + //bool is_same( const comestible_inv_area &other ) const; + // does _not_ check vehicle storage, do that with `can_store_in_vehicle()' below + bool canputitems(); + bool has_vehicle() const { + //add_msg("XXX veh: %d %d", info.id, info.type); + // disallow for non-valid vehicle locations + if (info.type != comestible_inv_area_info::AREA_TYPE_GROUND) { + return false; + } + return veh != nullptr && veh_part >= 0; + } + + std::string get_location_key(); + comestible_inv_area_info::aim_location get_relative_location() const { + if (!(tile_iso && use_tiles)) { + return info.id; + } + else { + return info.relative_location; + } + } +}; +#endif diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp new file mode 100644 index 0000000000000..f81defc717e65 --- /dev/null +++ b/src/comestible_inv_pane.cpp @@ -0,0 +1,1281 @@ +#include "auto_pickup.h" +#include "avatar.h" +#include "cata_utility.h" +#include "catacharset.h" +#include "debug.h" +#include "field.h" +#include "input.h" +#include "item_category.h" +#include "item_search.h" +#include "item_stack.h" +#include "map.h" +#include "mapdata.h" +#include "messages.h" +#include "options.h" +#include "output.h" +#include "player.h" +#include "player_activity.h" +#include "string_formatter.h" +#include "string_input_popup.h" +#include "translations.h" +#include "trap.h" +#include "ui.h" +#include "uistate.h" +#include "vehicle.h" +#include "vehicle_selector.h" +#include "vpart_position.h" +#include "calendar.h" +#include "color.h" +#include "game_constants.h" +#include "int_id.h" +#include "inventory.h" +#include "item.h" +#include "optional.h" +#include "ret_val.h" +#include "type_id.h" +#include "clzones.h" +#include "colony.h" +#include "enums.h" +#include "faction.h" +#include "item_location.h" +#include "map_selector.h" +#include "pimpl.h" +#include "bionics.h" +#include "comestible_inv_pane.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__ANDROID__) +# include +#endif + +struct col_data { + comestible_inv_columns id; + std::string col_name; + int width; + + char hotkey; + std::string sort_name; + + col_data(comestible_inv_columns id, std::string col_name, int width, char hotkey, std::string sort_name) : + id(id), + col_name(col_name), width(width), hotkey(hotkey), sort_name(sort_name){ + + } +}; + +// *INDENT-OFF* +static const col_data get_col_data(comestible_inv_columns col) { + static std::array col_data = { { + {COLUMN_NAME, _("Name (charges)"),0, 'n', _("name")}, + + {COLUMN_SRC, _("src"), 4, ';', _("")}, + {COLUMN_AMOUNT, _("amt"), 5, ';', _("")}, + + {COLUMN_WEIGHT, _("weight"), 7, 'w', _("weight")}, + {COLUMN_VOLUME, _("vol"), 8, 'v', _("volume")}, + + {COLUMN_CALORIES, _("calories"), 9, 'c', _("calories")}, + {COLUMN_QUENCH, _("quench"), 7, 'q', _("quench")}, + {COLUMN_JOY, _("joy"), 4, 'j', _("joy")}, + {COLUMN_EXPIRES, _("expires in"), 12,'s', _("spoilage")}, + {COLUMN_SHELF_LIFE, _("shelf life"), 12,'s', _("shelf life")}, + + {COLUMN_ENERGY, _("energy"), 12,'e', _("energy")}, + + {COLUMN_SORTBY_CATEGORY,_("fake"), 0,'c', _("category")} + } }; + return col_data[col]; +} +// *INDENT-ON* + +void comestible_inventory_pane::init(std::vector c, int items_per_page, catacurses::window w, std::array* s){ + columns = c; + itemsPerPage = items_per_page; + window = w; + squares = s; + is_compact = TERMX <= 100; + + inCategoryMode = false; + + comestible_inv_area_info::aim_location location = static_cast(uistate.comestible_save.area_idx); + set_area(&(*squares)[location], uistate.comestible_save.in_vehicle); + + index = uistate.comestible_save.selected_idx; + filter = uistate.comestible_save.filter; + + std::vector default_columns = { COLUMN_AMOUNT, COLUMN_WEIGHT, COLUMN_VOLUME }; + if (!is_compact) { + default_columns.emplace(default_columns.begin(), COLUMN_SRC); + } + columns.insert(columns.begin(), default_columns.begin(), default_columns.end()); + if (std::find(columns.begin(), columns.end(), uistate.comestible_save.sort_idx)!= columns.end()) { + sortby = static_cast(uistate.comestible_save.sort_idx); + } + else { + sortby = COLUMN_NAME; + } +} + +void comestible_inventory_pane::save_settings(bool reset) +{ + if (reset) { + uistate.comestible_save.in_vehicle = false; + uistate.comestible_save.area_idx = comestible_inv_area_info::AIM_ALL_I_W; + uistate.comestible_save.selected_idx = 0; + uistate.comestible_save.selected_itm = nullptr; + uistate.comestible_save.filter = ""; + } + else { + uistate.comestible_save.in_vehicle = viewing_cargo; + uistate.comestible_save.area_idx = cur_area->info.id; + uistate.comestible_save.selected_idx = index; + if (get_cur_item_ptr() != nullptr) { + uistate.comestible_save.selected_itm = get_cur_item_ptr()->items.front(); + } + else { + uistate.comestible_save.selected_itm = nullptr; + } + uistate.comestible_save.filter = filter; + } + uistate.comestible_save.sort_idx = sortby; +} + +void comestible_inventory_pane::add_sort_enries(uilist& sm) { + col_data c = get_col_data(COLUMN_NAME); + sm.addentry(c.id, true, c.hotkey, c.sort_name); + if (sortby == COLUMN_NAME) { + sm.selected = 0; + } + + for (size_t i = 0; i < columns.size(); i++) { + c = get_col_data(columns[i]); + if (c.id == COLUMN_SRC || c.id == COLUMN_AMOUNT) continue; + + sm.addentry(c.id, true, c.hotkey, c.sort_name); + if (sortby == c.id) { + sm.selected = i; + } + } +} + +void comestible_inventory_pane::do_filter(int h, int w) { + string_input_popup spopup; + std::string old_filter = filter; + filter_edit = true; + spopup.window(window, 4, h, w) + .max_length(256) + .text(filter); + +#if defined(__ANDROID__) + if (get_option("ANDROID_AUTO_KEYBOARD")) { + SDL_StartTextInput(); + } +#endif + + do { + mvwprintz(window, point(2, getmaxy(window) - 1), c_cyan, "< "); + mvwprintz(window, point(w, getmaxy(window) - 1), c_cyan, " >"); + std::string new_filter = spopup.query_string(false); + if (spopup.context().get_raw_input().get_first_input() == KEY_ESCAPE) { + set_filter(old_filter); + } + else { + set_filter(new_filter); + } + redraw(); + } while (spopup.context().get_raw_input().get_first_input() != '\n' && + spopup.context().get_raw_input().get_first_input() != KEY_ESCAPE); + filter_edit = false; + needs_redraw = true; +} +void comestible_inventory_pane::print_items() +{ + const int page = index / itemsPerPage; + + int max_width = getmaxx(window) - 1; + std::string spaces(max_width - 3, ' '); + nc_color norm = c_white; + + //print inventory's current and total weight + volume + if (cur_area->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER) { + const double weight_carried = convert_weight(g->u.weight_carried()); + const double weight_capacity = convert_weight(g->u.weight_capacity()); + std::string volume_carried = format_volume(g->u.volume_carried()); + std::string volume_capacity = format_volume(g->u.volume_capacity()); + // align right, so calculate formatted head length + const std::string formatted_head = string_format("%.1f/%.1f %s %s/%s %s", + weight_carried, weight_capacity, weight_units(), + volume_carried, + volume_capacity, + volume_units_abbr()); + const int hrightcol = max_width - formatted_head.length(); + nc_color color = weight_carried > weight_capacity ? c_red : c_light_green; + mvwprintz(window, point(hrightcol,4), color, "%.1f", weight_carried); + wprintz(window, c_light_gray, "/%.1f %s ", weight_capacity, weight_units()); + + color = g->u.volume_carried().value() > g->u.volume_capacity().value() ? c_red : + c_light_green; + wprintz(window, color, volume_carried); + wprintz(window, c_light_gray, "/%s %s", volume_capacity, volume_units_abbr()); + } + else { //print square's current and total weight + volume + std::string formatted_head; + std::string volume_str; + + if (cur_area->info.type == comestible_inv_area_info::AREA_TYPE_MULTI) { + volume_str = string_format("%s", format_volume(volume)); + } + else { + units::volume maxvolume = cur_area->get_max_volume(viewing_cargo); + volume_str = string_format("%s/%s", format_volume(volume), format_volume(maxvolume)); + } + formatted_head = string_format("%3.1f %s %s %s", + convert_weight(weight), + weight_units(), + volume_str, + volume_units_abbr()); + mvwprintz(window, point(max_width - formatted_head.length(), 4), norm, formatted_head); + } + + const size_t name_startpos = is_compact ? 1 : 4; + + mvwprintz(window, point(name_startpos, 5), c_light_gray, get_col_data(COLUMN_NAME).col_name); + int cur_x = max_width; + for (size_t i = columns.size(); i --> 0;) { + const col_data d = get_col_data(columns[i]); + if (d.width <= 0) continue; + cur_x -= d.width; + mvwprintz(window, point(cur_x, 5), c_light_gray, "%*s", d.width, d.col_name); + } + + for (int i = page * itemsPerPage, cur_print_y = 6; i < static_cast(items.size()) && + cur_print_y < itemsPerPage + 6; i++, cur_print_y++) { + comestible_inv_listitem& sitem = items[i]; + if (sitem.is_category_header()) { + mvwprintz(window, point((max_width - utf8_width(sitem.name) - 6) / 2, cur_print_y), c_cyan, "[%s]", + sitem.name); + continue; + } + if (!sitem.is_item_entry()) { + // Empty entry at the bottom of a page. + continue; + } + + const bool selected = index == i; + + + comestible_select_state selected_state; + if (selected) { + selected_state = inCategoryMode ? SELECTSTATE_CATEGORY : SELECTSTATE_SELECTED; + } + else { + selected_state = SELECTSTATE_NONE; + } + sitem.print_columns(columns, selected_state, is_compact, window, max_width, cur_print_y); + } +} + +void comestible_inventory_pane::skip_category_headers(int offset) +{ + assert(offset != 0); // 0 would make no sense + assert(static_cast(index) < items.size()); // valid index is required + assert(offset == -1 || offset == +1); // only those two offsets are allowed + assert(!items.empty()); // index would not be valid, and this would be an endless loop + while (!items[index].is_item_entry()) { + mod_index(offset); + } +} + +void comestible_inventory_pane::mod_index(int offset) +{ + assert(offset != 0); // 0 would make no sense + assert(!items.empty()); + index += offset; + if (index < 0) { + index = static_cast(items.size()) - 1; + } + else if (static_cast(index) >= items.size()) { + index = 0; + } +} + +void comestible_inventory_pane::scroll_by(int offset) +{ + assert(offset != 0); // 0 would make no sense + if (items.empty()) { + return; + } + if (inCategoryMode) { + assert(get_cur_item_ptr() != nullptr); // index must already be valid! + auto cur_cat = items[index].cat; + if (offset > 0) { + while (items[index].cat == cur_cat) { + index++; + if (static_cast(index) >= items.size()) { + index = 0; // wrap to begin, stop there. + break; + } + } + } + else { + while (items[index].cat == cur_cat) { + index--; + if (index < 0) { + index = static_cast(items.size()) - 1; // wrap to end, stop there. + break; + } + } + } + } + else { + mod_index(offset); + } + // Make sure we land on an item entry. + skip_category_headers(offset > 0 ? +1 : -1); + needs_redraw = true; +} + +comestible_inv_listitem* comestible_inventory_pane::get_cur_item_ptr() +{ + if (static_cast(index) >= items.size()) { + return nullptr; + } + return &items[index]; +} + +void comestible_inventory_pane::set_filter(const std::string& new_filter) +{ + if (filter == new_filter) { + return; + } + filter = new_filter; + filtercache.clear(); + needs_recalc = true; +} + +bool comestible_inventory_pane::is_filtered(const comestible_inv_listitem& it) const +{ + return is_filtered(*it.items.front()); +} + +bool comestible_inventory_pane::is_filtered(const item& it) const +{ + if (special_filter(it)) { + return true; + } + + if (filter.empty()) { + return false; + } + + const std::string str = it.tname(); + if (filtercache.find(str) == filtercache.end()) { + const auto filter_fn = item_filter_from_string(filter); + filtercache[str] = filter_fn; + + return !filter_fn(it); + } + + return !filtercache[str](it); +} + +void comestible_inventory_pane::paginate() +{ + if( sortby != COLUMN_SORTBY_CATEGORY ) { + return; // not needed as there are no category entries here. + } + // first, we insert all the items, then we sort the result + for (size_t i = 0; i < items.size(); ++i) { + if (i % itemsPerPage == 0) { + // first entry on the page, should be a category header + if (items[i].is_item_entry()) { + items.insert(items.begin() + i, comestible_inv_listitem(items[i].cat)); + } + } + if ((i + 1) % itemsPerPage == 0 && i + 1 < items.size()) { + // last entry of the page, but not the last entry at all! + // Must *not* be a category header! + if (items[i].is_category_header()) { + items.insert(items.begin() + i, comestible_inv_listitem()); + } + } + } +} + +void comestible_inventory_pane::fix_index() +{ + if (items.empty()) { + index = 0; + return; + } + if (index < 0) { + index = 0; + } + else if (static_cast(index) >= items.size()) { + index = static_cast(items.size()) - 1; + } + skip_category_headers(+1); +} + +struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { + bool operator()(char x, char y) const { + return toupper(static_cast(x)) < toupper(static_cast(y)); + } +}; + +struct comestible_inv_sorter { + comestible_inv_columns sortby; + comestible_inv_columns default_sortby; + comestible_inv_sorter(comestible_inv_columns sort, comestible_inv_columns default_sort) { + sortby = sort; + default_sortby = default_sort; + } + bool operator()(const comestible_inv_listitem& d1, const comestible_inv_listitem& d2) { + return compare(sortby, d1, d2); + } + + bool compare(comestible_inv_columns compare_by, const comestible_inv_listitem& d1, const comestible_inv_listitem& d2) { + switch (compare_by) { + case COLUMN_NAME: + const std::string* n1; + const std::string* n2; + if (d1.name_without_prefix == d2.name_without_prefix) { + if (d1.name == d2.name) { + //fall through + break; + } + else { + //if names without prefix equal, compare full name + n1 = &d1.name; + n2 = &d2.name; + } + } + else { + //else compare name without prefix + n1 = &d1.name_without_prefix; + n2 = &d2.name_without_prefix; + } + + return std::lexicographical_compare(n1->begin(), n1->end(), n2->begin(), n2->end(), + sort_case_insensitive_less()); + break; + case COLUMN_WEIGHT: + if (d1.weight != d2.weight) { + return d1.weight > d2.weight; + } + break; + case COLUMN_VOLUME: + if (d1.volume != d2.volume) { + return d1.volume > d2.volume; + } + break; + case COLUMN_CALORIES: + if (d1.calories != d2.calories) { + return d1.calories > d2.calories; + } + break; + case COLUMN_QUENCH: + if (d1.quench != d2.quench) { + return d1.quench > d2.quench; + } + break; + case COLUMN_JOY: + if (d1.joy != d2.joy) { + return d1.joy > d2.joy; + } + break; + case COLUMN_ENERGY: + if (d1.energy != d2.energy) { + return d1.energy > d2.energy; + } + break; + case COLUMN_EXPIRES: + case COLUMN_SHELF_LIFE: + if (d1.items.front()->spoilage_sort_order() != d2.items.front()->spoilage_sort_order()) { + return d1.items.front()->spoilage_sort_order() < d2.items.front()->spoilage_sort_order(); + } + break; + case COLUMN_SORTBY_CATEGORY: + assert(d1.cat != nullptr); + assert(d2.cat != nullptr); + if (d1.cat != d2.cat) { + return *d1.cat < *d2.cat; + } + else if (d1.is_category_header()) { + return true; + } + else if (d2.is_category_header()) { + return false; + } + break; + case COLUMN_SRC: + case COLUMN_AMOUNT: + case COLUMN_NUM_ENTRIES: + //shouldn't be here + assert(false); + break; + } + + if (compare_by == default_sortby) { + return false; + } + else { + return compare(default_sortby, d1, d2); + } + } +}; + +void comestible_inventory_pane::recalc() { + needs_recalc = false; + items.clear(); + // Add items from the source location or in case of all 9 surrounding squares, + // add items from several locations. + + units::volume tmp_vol; + units::mass tmp_weight; + if (cur_area->info.type == comestible_inv_area_info::AREA_TYPE_MULTI) { + volume = 0_ml; + weight = 0_gram; + std::vector loc = cur_area->info.multi_locations; + for (size_t i = 0; i < loc.size(); i++) { + comestible_inv_area* s = &((*squares)[loc[i]]); + // Deal with squares with ground + vehicle storage + // Also handle the case when the other tile covers vehicle + // or the ground below the vehicle. + if (s->has_vehicle()) { + add_items_from_area(s, true, tmp_vol, tmp_weight); + volume += tmp_vol; + weight += tmp_weight; + } + + // Add map items + add_items_from_area(s, false, tmp_vol, tmp_weight); + volume += tmp_vol; + weight += tmp_weight; + } + } + else { + add_items_from_area(cur_area, viewing_cargo, volume, weight); + } + + // Insert category headers (only expected when sorting by category) + if (sortby == COLUMN_SORTBY_CATEGORY) { + std::set categories; + for (auto& it : items) { + categories.insert(it.cat); + } + for (auto& cat : categories) { + items.push_back(comestible_inv_listitem(cat)); + } + } + + + // Finally sort all items (category headers will now be moved to their proper position) + std::stable_sort(items.begin(), items.end(), comestible_inv_sorter(sortby, default_sortby)); + paginate(); + + int i = 0; + for (auto& it : items) { + if (it.items.front() == uistate.comestible_save.selected_itm) { + uistate.comestible_save.selected_idx = i; + index = i; + break; + } + i++; + } +} + +//TODO: I want to move functionality to comestible_inv_area, but I dunno how to convert AIM_INVENTORY, AIM_WORN and other to the same type. +void comestible_inventory_pane::add_items_from_area(comestible_inv_area* area, bool from_cargo, units::volume& ret_volume, units::mass& ret_weight) +{ + assert(area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI); + if (!area->canputitems()) { + return; + } + player& u = g->u; + + ret_volume = 0_ml; + ret_weight = 0_gram; + + units::volume tmp_volume; + units::mass tmp_weight; + // Existing items are *not* cleared on purpose, this might be called + // several times in case all surrounding squares are to be shown. + if (area->info.id == comestible_inv_area_info::AIM_INVENTORY) { + const invslice& stacks = u.inv.slice(); + for (size_t x = 0; x < stacks.size(); ++x) { + std::list item_pointers; + for (item& i : *stacks[x]) { + item_pointers.push_back(&i); + } + comestible_inv_listitem it(item_pointers, x, area, false); + if (is_filtered(*it.items.front())) { + continue; + } + ret_volume += it.volume; + ret_weight += it.weight; + items.push_back(it); + } + } + else if (area->info.id == comestible_inv_area_info::AIM_WORN) { + auto iter = u.worn.begin(); + for (size_t i = 0; i < u.worn.size(); ++i, ++iter) { + comestible_inv_listitem it(&*iter, i, 1, area, false); + if (is_filtered(*it.items.front())) { + continue; + } + ret_volume += it.volume; + ret_weight += it.weight; + items.push_back(it); + } + } + else { + const comestible_inv_area::area_items stacks = area->get_items(from_cargo); + + for (size_t x = 0; x < stacks.size(); ++x) { + comestible_inv_listitem it(stacks[x], x, area, from_cargo); + if (is_filtered(*it.items.front())) { + continue; + } + ret_volume += it.volume; + ret_weight += it.weight; + items.push_back(it); + } + } +} + +void comestible_inventory_pane::redraw() +{ + // don't update ui if processing demands + if (needs_recalc) { + recalc(); + } + else if (!needs_redraw) { + return; + } + needs_redraw = false; + fix_index(); + + auto w = window; + + werase(w); + + print_items(); + + auto itm = get_cur_item_ptr(); + int width = print_header(itm != nullptr ? itm->area : get_area()); + bool same_as_dragged = (cur_area->info.id >= comestible_inv_area_info::AIM_SOUTHWEST && cur_area->info.id <= comestible_inv_area_info::AIM_NORTHEAST) && + // only cardinals + cur_area->info.id != comestible_inv_area_info::AIM_CENTER && is_in_vehicle() && // not where you stand, and pane is in vehicle + cur_area->info.default_offset == get_square(comestible_inv_area_info::AIM_DRAGGED)->info.default_offset; // make sure the offsets are the same as the grab point + const comestible_inv_area* sq = same_as_dragged ? get_square(comestible_inv_area_info::AIM_DRAGGED) : cur_area; + + + bool car = cur_area->has_vehicle() && is_in_vehicle() && sq->info.id != comestible_inv_area_info::AIM_DRAGGED; + auto name = utf8_truncate(sq->get_name(viewing_cargo), width); + auto desc = utf8_truncate(sq->desc[car], width); + width -= 2 + 1; // starts at offset 2, plus space between the header and the text + mvwprintz(w, point(2, 1), c_green, name); + mvwprintz(w, point(2, 2), c_light_blue, desc); + trim_and_print(w, point(2, 3), width, c_cyan, cur_area->flags); + + if (!is_compact) { + for (size_t i = 0; i < legend.size(); i++) + { + legend_data l = legend[i]; + mvwprintz(window, point(25, i + 1), c_light_gray, "[%c] ", l.shortcut); + wprintz(window, l.color, "%s", l.message); + } + } + + const int max_page = (items.size() + itemsPerPage - 1) / itemsPerPage; + if (max_page > 1) { + const int page = index / itemsPerPage; + mvwprintz(w, point(2, 4), c_light_blue, _("[<] page %d of %d [>]"), page + 1, max_page); + } + + wattron(w, c_cyan); + // draw a darker border around the inactive pane + draw_border(w, BORDER_COLOR); + mvwprintw(w, point(3, 0), _("< [s]ort: %s >"), get_col_data(sortby).sort_name); + + if (title.size() != 0) { + std::string title_string = string_format("<< %s >>", title); + mvwprintz(w, point((getmaxx(w) - title_string.size())/2, 0), c_light_cyan, title_string); + } + + const char* fprefix = _("[F]ilter"); + const char* fsuffix = _("[R]eset"); + + //TODO:XXX + //bool filter_edit = true; + if (!filter_edit) { + if (!filter.empty()) { + mvwprintw(w, point(2, getmaxy(w) - 1), "< %s: %s >", fprefix, filter); + } + else { + mvwprintw(w, point(2, getmaxy(w) - 1), "< %s >", fprefix); + } + } + + wattroff(w, c_white); + + if (!filter_edit && !filter.empty()) { + mvwprintz(w, point(6 + std::strlen(fprefix), getmaxy(w) - 1), c_white, + filter); + mvwprintz(w, point(getmaxx(w) - std::strlen(fsuffix) - 2, getmaxy(w) - 1), c_white, "%s", + fsuffix); + } + wrefresh(w); +} + + + +int comestible_inventory_pane::print_header(comestible_inv_area* sel_area) +{ + int wwidth = getmaxx(window); + int ofs = wwidth - 25 - 2 - 14; + for (size_t i = 0; i < squares->size(); ++i) { + std::string key = comestible_inv_area::get_info(static_cast(i)).minimapname; + + comestible_inv_area* iter_square = get_square(i); + + const char* bracket = iter_square->has_vehicle() ? "<>" : "[]"; + + bool is_single = cur_area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI; + bool is_selected_by_user = cur_area->info.has_area(get_square(i)->info.id); + bool is_selected_by_item; + if (is_single) { + is_selected_by_item = is_selected_by_user; + } + else { + is_selected_by_item = get_square(i)->info.id == sel_area->info.id; + } + + //bool is_selected = get_square(i)->info.has_area(sel_area->info.id); + + //bool q = (sel_area->info.id == get_square(i)->info.id); + + + + //bool iterIsMe = (get_square(i).info.id == area); + //bool selectIsMe = (sel == area); + + //bool in_vehicle = is_in_vehicle() && get_square(i).info.id == area && sel == area && area != comestible_inv_area_info::AIM_ALL; + //bool all_brackets = area == comestible_inv_area_info::AIM_ALL && (i >= comestible_inv_area_info::AIM_SOUTHWEST && i <= comestible_inv_area_info::AIM_NORTHEAST); + nc_color bcolor = c_red; + nc_color kcolor = c_red; + if (get_square(i)->canputitems()) { + if (is_single) { + if (is_selected_by_item) { + if (viewing_cargo) { + bcolor = c_light_blue; + } + else { + bcolor = c_light_gray; + } + kcolor = c_white; + } + else { + bcolor = kcolor = c_dark_gray; + } + } + else { + if (cur_area->info.id == get_square(i)->info.id) { + bcolor = c_light_gray; + kcolor = c_white; + } + else { + if (is_selected_by_user) { + bcolor = c_light_gray; + } + else { + bcolor = c_dark_gray; + } + + if (is_selected_by_item) { + kcolor = c_light_gray; + } + else { + kcolor = c_dark_gray; + } + } + } + + /* if (is_selected) { + if (is_single) { + if (viewing_cargo) { + bcolor = c_light_gray; + } + kcolor = c_white; + } + else { + bcolor = c_light_gray; + kcolor = c_light_gray; + } + } + else { + bcolor = kcolor = c_dark_gray; + }*/ + //bcolor = in_vehicle ? c_light_blue : + // area == i || all_brackets ? c_light_gray : c_dark_gray; + //kcolor = area == i ? c_white : sel == i ? c_light_gray : c_dark_gray; + } + + const int x = get_square(i)->info.hscreen.x + ofs; + const int y = get_square(i)->info.hscreen.y; + mvwprintz(window, point(x, y), bcolor, "%c", bracket[0]); + wprintz(window, kcolor, "%s", viewing_cargo && is_selected_by_item && is_single && cur_area->info.id != comestible_inv_area_info::AIM_DRAGGED ? "V" : key); + wprintz(window, bcolor, "%c", bracket[1]); + } + return get_square(comestible_inv_area_info::AIM_INVENTORY)->info.hscreen.y + ofs; +} + +void comestible_inv_listitem::print_columns(std::vector columns, comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, int cur_print_y) { + + is_selected = selected_state; + int w; + for (std::vector::reverse_iterator col_iter = columns.rbegin(); col_iter != columns.rend(); ++col_iter) { + w = get_col_data(*col_iter).width; + if (w <= 0) continue; + right_bound -= w; + if (print_string_column(*col_iter, window, right_bound, cur_print_y)) { + continue; + } + + if (print_int_column(*col_iter, window, right_bound, cur_print_y)) { + continue; + } + + if (print_default_columns(*col_iter, window, right_bound, cur_print_y)) { + continue; + } + + //TODO: error + } + print_name(is_compact, window, right_bound, cur_print_y); +} + +bool comestible_inv_listitem::print_string_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y) { + std::string print_string; + switch (col) + { + case COLUMN_SHELF_LIFE: + print_string = shelf_life; + break; + case COLUMN_EXPIRES: + print_string = exipres_in; + break; + default: + return false; + } + nc_color print_color; + set_print_color(print_color, c_cyan); + mvwprintz(window, point(cur_print_x, cur_print_y), print_color, "%*s", get_col_data(col).width, print_string); + return true; +} + +bool comestible_inv_listitem::print_int_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y) { + int print_val; + bool need_highlight = false; + switch (col) + { + case COLUMN_CALORIES: + print_val = calories; + break; + case COLUMN_QUENCH: + print_val = quench; + break; + case COLUMN_JOY: + print_val = joy; + need_highlight = is_mushy; + break; + case COLUMN_ENERGY: + print_val = energy; + break; + default: + return false; + break; + } + nc_color print_color; + char const* print_format = set_string_params(print_color, print_val, need_highlight); + std::string s = string_format(print_format, print_val); + mvwprintz(window, point(cur_print_x, cur_print_y), print_color, "%*s", get_col_data(col).width, s); + return true; +} + +char const* comestible_inv_listitem::set_string_params(nc_color& print_color, int value, + bool need_highlight) +{ + char const* string_format; + if (value > 0) { + print_color = need_highlight ? c_yellow_green : c_green; + string_format = "+%d"; + } + else if (value < 0) { + print_color = need_highlight ? c_yellow_red : c_red; + string_format = "%d"; + } + else { + print_color = need_highlight ? c_yellow : c_dark_gray; + string_format = ""; + } + + set_print_color(print_color, print_color); + return string_format; +} + +void comestible_inv_listitem::set_print_color(nc_color& retval, nc_color default_col) { + switch (is_selected) + { + case SELECTSTATE_NONE: + retval = default_col; + break; + case SELECTSTATE_SELECTED: + retval = hilite(c_white); + break; + case SELECTSTATE_CATEGORY: + retval = c_white_red; + break; + default: + break; + } +} + +bool comestible_inv_listitem::print_default_columns(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y) { + nc_color print_color; + std::string s; + + switch (col) + { + case COLUMN_VOLUME: { + bool it_vol_truncated = false; + double it_vol_value = 0.0; + s = format_volume(volume, 5, &it_vol_truncated, &it_vol_value); + if (it_vol_truncated && it_vol_value > 0.0) { + print_color = c_red; + } + else { + print_color = volume.value() > 0 ? menu_color : menu_color_dark; + } + break; } + + case COLUMN_WEIGHT: { + double it_weight = convert_weight(weight); + size_t w_precision; + print_color = it_weight > 0 ? menu_color : menu_color_dark; + + if (it_weight >= 1000.0) { + if (it_weight >= 10000.0) { + print_color = c_red; + it_weight = 9999.0; + } + w_precision = 0; + } + else if (it_weight >= 100.0) { + w_precision = 1; + } + else { + w_precision = 2; + } + s = string_format("%5.*f", w_precision, it_weight); + break; + } + case COLUMN_AMOUNT: { + if (stacks > 1) { + print_color = menu_color; + if (stacks > 9999) { + stacks = 9999; + print_color = c_red; + } + s = string_format("%4d", stacks); + } + else { + s = ""; + } + break; + } + case COLUMN_SRC: + print_color = menu_color; + s = area->info.shortname; + break; + + default: + return false; + break; + } + set_print_color(print_color, print_color); + mvwprintz(window, point(cur_print_x, cur_print_y), print_color, "%*s", get_col_data(col).width, s); + return true; +} + +void comestible_inv_listitem::print_name(bool is_compact, catacurses::window window, int right_bound, int cur_print_y) { + std::string item_name; + + item* it = items.front(); + if (it->is_money()) { + //Count charges + // TODO: transition to the item_location system used for the normal inventory + unsigned int charges_total = 0; + for (const auto item : items) { + charges_total += item->charges; + } + item_name = it->display_money(items.size(), charges_total); + } + else { + item_name = it->display_name(); + } + + //check stolen + if (it->has_owner()) { + const faction* item_fac = it->get_owner(); + if (item_fac != g->faction_manager_ptr->get(faction_id("your_followers"))) { + item_name = string_format("%s %s", "!", item_name); + } + } + if (get_option("ITEM_SYMBOLS")) { + item_name = string_format("%s %s", it->symbol(), item_name); + } + + int name_startpos = is_compact ? 1 : 4; + int max_name_length = right_bound - name_startpos - 1; + nc_color print_color; + set_print_color(print_color, menu_color); + + if (is_selected) { //fill whole line with color + mvwprintz(window, point(0, cur_print_y), print_color, "%*s", right_bound, ""); + } + trim_and_print(window, point(name_startpos, cur_print_y), max_name_length, print_color, item_name); + + if (autopickup) { + mvwprintz(window, point(name_startpos, cur_print_y), magenta_background(print_color), + is_compact ? item_name.substr(0, 1) : ">"); + } +} + + + + const islot_comestible& comestible_inv_listitem::get_edible_comestible(player& p, + const item& it) const + { + if (it.is_comestible() && p.can_eat(it).success()) { + // Ok since can_eat() returns false if is_craft() is true + return *it.type->comestible; + } + static const islot_comestible dummy{}; + return dummy; + } + + + std::string comestible_inv_listitem::get_time_left_rounded(player& p, const item& it) const + { + if (it.is_going_bad()) { + return _("soon!"); + } + + time_duration time_left = 0_turns; + const time_duration shelf_life = get_edible_comestible(p, it).spoils; + if (shelf_life > 0_turns) { + 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; + } + } + + //const auto make_result = [this](const time_duration& d, const char* verbose_str, + // const char* short_str) { + // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); + //}; + + time_duration divider = 0_turns; + time_duration vicinity = 0_turns; + + if (time_left > 1_days) { + divider = 1_days; + vicinity = 2_hours; + } + else if (time_left > 1_hours) { + divider = 1_hours; + vicinity = 5_minutes; + } // Minutes and seconds can be estimated precisely. + + if (divider != 0_turns) { + const time_duration remainder = time_left % divider; + + if (remainder >= divider - vicinity) { + time_left += divider; + } + else if (remainder > vicinity) { + if (remainder < divider / 2) { + //~ %s - time (e.g. 2 hours). + return string_format("%s", time_to_comestible_str(time_left)); + //return string_format("> %s", time_to_comestible_str(time_left)); + } + else { + //~ %s - time (e.g. 2 hours). + return string_format("%s", time_to_comestible_str(time_left)); + //return string_format("< %s", time_to_comestible_str(time_left)); + } + } + } + //~ %s - time (e.g. 2 hours). + return string_format("%s", time_to_comestible_str(time_left)); + //return string_format("~ %s", time_to_comestible_str(time_left)); + } + + std::string comestible_inv_listitem::time_to_comestible_str(const time_duration& d) const + { + if (d >= calendar::INDEFINITELY_LONG_DURATION) { + return _("forever"); + } + + const float day = to_days(d); + std::string format; + if (day < 1.00) { + format = _("%.2f days"); + } + else if (day > 1.00) { + format = _("%.0f days"); + } + else { + format = _("1 day"); + } + + return string_format(format, day); + } + +comestible_inv_listitem::comestible_inv_listitem(item* an_item, int index, int count, + comestible_inv_area* area, bool from_vehicle) + : idx(index) + , area(area) + , id(an_item->typeId()) + , name(an_item->tname(count)) + , name_without_prefix(an_item->tname(1, false)) + , autopickup(get_auto_pickup().has_rule(an_item)) + , stacks(count) + , volume(an_item->volume()* stacks) + , weight(an_item->weight()* stacks) + , cat(&an_item->get_category()) + , from_vehicle(from_vehicle) +{ + player& p = g->u; + item it = p.get_consumable_from(*an_item); + islot_comestible it_c = get_edible_comestible(p, it); + + + menu_color = it.color_in_inventory(); + + exipres_in = ""; + shelf_life = ""; + if (it_c.spoils > 0_turns) { + if (!it.rotten()) { + exipres_in = get_time_left_rounded(p, it); + } + shelf_life = to_string_clipped(it_c.spoils); + } + + calories = p.kcal_for(it); + quench = it_c.quench; + joy = p.fun_for(it).first; + is_mushy = it.has_flag("MUSHY"); + + energy = p.get_acquirable_energy(it); + + items.push_back(an_item); + + menu_color_dark = c_dark_gray; + assert(stacks >= 1); +} + +comestible_inv_listitem::comestible_inv_listitem(const std::list& list, int index, + comestible_inv_area* area, bool from_vehicle) : + idx(index), + area(area), + id(list.front()->typeId()), + items(list), + name(list.front()->tname(list.size())), + name_without_prefix(list.front()->tname(1, false)), + autopickup(get_auto_pickup().has_rule(list.front())), + stacks(list.size()), + volume(list.front()->volume()* stacks), + weight(list.front()->weight()* stacks), + cat(&list.front()->get_category()), + from_vehicle(from_vehicle) +{ + player& p = g->u; + item it = p.get_consumable_from(*list.front()); + islot_comestible it_c = get_edible_comestible(p, it); + + + + menu_color = it.color_in_inventory(); + + exipres_in = ""; + shelf_life = ""; + if (it_c.spoils > 0_turns) { + if (!it.rotten()) { + exipres_in = get_time_left_rounded(p, it); + } + shelf_life = to_string_clipped(it_c.spoils); + } + + calories = p.kcal_for(it); + quench = it_c.quench; + joy = p.fun_for(it).first; + is_mushy = it.has_flag("MUSHY"); + + energy = p.get_acquirable_energy(it); + + menu_color_dark = c_dark_gray; + assert(stacks >= 1); +} + +comestible_inv_listitem::comestible_inv_listitem() + : idx() + , area() + , id("null") + , autopickup() + , stacks() + , cat(nullptr) +{ + menu_color_dark = c_dark_gray; +} + +comestible_inv_listitem::comestible_inv_listitem(const item_category* cat) + : idx() + , area() + , id("null") + , name(cat->name()) + , autopickup() + , stacks() + , cat(cat) +{ + menu_color_dark = c_dark_gray; +} + +bool comestible_inv_listitem::is_category_header() const +{ + return items.empty() && cat != nullptr; +} + +bool comestible_inv_listitem::is_item_entry() const +{ + return !items.empty(); +} diff --git a/src/comestible_inv_pane.h b/src/comestible_inv_pane.h new file mode 100644 index 0000000000000..ea1ebff748ae6 --- /dev/null +++ b/src/comestible_inv_pane.h @@ -0,0 +1,313 @@ +#pragma once +#ifndef COMESTIBLE_INV_PANE_H +#define COMESTIBLE_INV_PANE_H +#include "cursesdef.h" +#include "point.h" +#include "units.h" +#include "game.h" +#include "ui.h" +#include "itype.h" +#include "comestible_inv_area.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +class item_category; + +//TODO: when changing this, also change comestible_inv_pane.cpp - get_col_data(). Make sure order is preserved. +enum comestible_inv_columns { + COLUMN_NAME, + + COLUMN_SRC, + COLUMN_AMOUNT, + COLUMN_WEIGHT, + COLUMN_VOLUME, + + COLUMN_CALORIES, + COLUMN_QUENCH, + COLUMN_JOY, + COLUMN_EXPIRES, + COLUMN_SHELF_LIFE, + + COLUMN_ENERGY, + + COLUMN_SORTBY_CATEGORY, //not actual clumn + COLUMN_NUM_ENTRIES +}; + +enum comestible_select_state { + SELECTSTATE_NONE, + SELECTSTATE_SELECTED, + SELECTSTATE_CATEGORY +}; + +struct legend_data { + char shortcut; + nc_color color; + std::string message; + legend_data(char shortcut, nc_color color, std::string message):shortcut(shortcut), color(color), message(message) { + + } +}; + +/** + * Entry that is displayed in a adv. inv. pane. It can either contain a + * single item or a category header or nothing (empty entry). + * Most members are used only for sorting. + */ +class comestible_inv_listitem { +public: + using itype_id = std::string; + /** + * Index of the item in the itemstack. + */ + int idx; + /** + * The location of the item, never AIM_ALL. + */ + //comestible_inv_area_info::aim_location area; + comestible_inv_area* area; + // the id of the item + itype_id id; + // The list of items, and empty when a header + std::list items; + /** + * The displayed name of the item/the category header. + */ + std::string name; + /** + * Name of the item (singular) without damage (or similar) prefix, used for sorting. + */ + std::string name_without_prefix; + /** + * Whether auto pickup is enabled for this item (based on the name). + */ + bool autopickup; + /** + * The stack count represented by this item, should be >= 1, should be 1 + * for anything counted by charges. + */ + int stacks; + /** + * The volume of all the items in this stack, used for sorting. + */ + units::volume volume; + /** + * The weight of all the items in this stack, used for sorting. + */ + units::mass weight; + + /** + * TODO:docs + */ + std::string shelf_life; + std::string exipres_in; + int calories; + int quench; + int joy; + bool is_mushy; + int energy; + + comestible_select_state is_selected; + nc_color menu_color; + nc_color menu_color_dark; + + void print_columns(std::vector columns, comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, int cur_print_y); +private: + bool print_string_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y); + bool print_int_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y); + void print_name(bool is_compact, catacurses::window window, int right_bound, int cur_print_y); + bool print_default_columns(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y); + void set_print_color(nc_color& retval, nc_color default_col); +public: + + + char const* set_string_params(nc_color& print_color, int value, bool need_highlight = false); + + /** + * The item category, or the category header. + */ + const item_category* cat; + /** + * Is the item stored in a vehicle? + */ + bool from_vehicle; + + + //TODO + const islot_comestible& get_edible_comestible(player& p, const item& it) const; + + std::string get_time_left_rounded(player& p, const item& it) const; + + std::string time_to_comestible_str(const time_duration& d) const; + /** + * Whether this is a category header entry, which does *not* have a reference + * to an item, only @ref cat is valid. + */ + bool is_category_header() const; + + /** Returns true if this is an item entry */ + bool is_item_entry() const; + /** + * Create a category header entry. + * @param cat The category reference, must not be null. + */ + comestible_inv_listitem(const item_category* cat); + + /** + * Creates an empty entry, both category and item pointer are null. + */ + comestible_inv_listitem(); + /** + * Create a normal item entry. + * @param an_item The item pointer. Must not be null. + * @param index The index + * @param count The stack size + * @param area The source area. Must not be AIM_ALL. + * @param from_vehicle Is the item from a vehicle cargo space? + */ + comestible_inv_listitem(item* an_item, int index, int count, + comestible_inv_area* area, bool from_vehicle); + /** + * Create a normal item entry. + * @param list The list of item pointers. + * @param index The index + * @param area The source area. Must not be AIM_ALL. + * @param from_vehicle Is the item from a vehicle cargo space? + */ + comestible_inv_listitem(const std::list& list, int index, + comestible_inv_area* area, bool from_vehicle); +}; + +/** + * Displayed pane, what is shown on the screen. + */ +class comestible_inventory_pane +{ +private: + comestible_inv_area* cur_area; + // pointer to the square this pane is pointing to + bool viewing_cargo = false; + bool is_compact; +public: + + // set the pane's area via its square, and whether it is viewing a vehicle's cargo + void set_area(comestible_inv_area* square, bool show_vehicle) { + cur_area = square; + viewing_cargo = square->has_vehicle() && show_vehicle; + } + comestible_inv_area* get_area() const { + return cur_area; + } + bool is_in_vehicle() const { + return viewing_cargo; + } + //bool on_ground() const { + // return area > AIM_INVENTORY && area < AIM_DRAGGED; + //} + /** + * Index of the selected item (index of @ref items), + */ + int index; + comestible_inv_columns sortby; + catacurses::window window; + std::vector items; + + std::function special_filter; + + std::vector legend; + std::string title; + + bool inCategoryMode; + + units::volume volume; + units::mass weight; + bool filter_edit; + + /** + * The current filter string. + */ + std::string filter; + /** + * Food or Drug filter. True = show food. + */ + //bool filter_show_food; + /** + * Whether to recalculate the content of this pane. + * Implies @ref redraw. + */ + bool needs_recalc; + /** + * Whether to redraw this pane. + */ + bool needs_redraw; + + void add_items_from_area(comestible_inv_area* area, bool from_cargo, units::volume& ret_volume, units::mass& ret_weight); + /** + * Makes sure the @ref index is valid (if possible). + */ + void fix_index(); + void recalc(); + void redraw(); + std::array* squares; + comestible_inv_area* get_square(comestible_inv_area_info::aim_location loc) { + return &((*squares)[loc]); + } + comestible_inv_area* get_square(size_t loc) { + return &((*squares)[loc]); + } + int print_header(comestible_inv_area* sel_area); + /** + * @param it The item to check, oly the name member is examined. + * @return Whether the item should be filtered (and not shown). + */ + bool is_filtered(const comestible_inv_listitem& it) const; + /** + * Same as the other, but checks the real item. + */ + bool is_filtered(const item& it) const; + /** + * Scroll @ref index, by given offset, set redraw to true, + * @param offset Must not be 0. + */ + void scroll_by(int offset); + /** + * @return either null, if @ref index is invalid, or the selected + * item in @ref items. + */ + comestible_inv_listitem* get_cur_item_ptr(); + /** + * Set the filter string, disables filtering when the filter string is empty. + */ + void set_filter(const std::string& new_filter); + /** + * Insert additional category headers on the top of each page. + */ + void paginate(); + + //TODO:docs'n'stuffs + int itemsPerPage; + std::vector columns; + comestible_inv_columns default_sortby; + + void add_sort_enries(uilist& sm); + void init(std::vector c, int items_per_page, catacurses::window w, std::array* s); + void save_settings(bool reset); + void do_filter(int h, int w); + void print_items(); +private: + /** Scroll to next non-header entry */ + void skip_category_headers(int offset); + /** Only add offset to index, but wrap around! */ + void mod_index(int offset); + + mutable std::map> filtercache; +}; +#endif diff --git a/src/crafting.cpp b/src/crafting.cpp index 5343c992fe966..c904673721edf 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -283,10 +283,10 @@ bool player::has_morale_to_craft() const return get_morale_level() >= -50; } -void player::craft( const tripoint &loc ) +void player::craft( const tripoint &loc, std::string filter) { int batch_size = 0; - const recipe *rec = select_crafting_recipe( batch_size ); + const recipe *rec = select_crafting_recipe( batch_size, filter); if( rec ) { if( crafting_allowed( *this, *rec ) ) { make_craft( rec->ident(), batch_size, loc ); diff --git a/src/crafting.h b/src/crafting.h index 4649ce9cd643e..334f7a52aaba5 100644 --- a/src/crafting.h +++ b/src/crafting.h @@ -3,6 +3,7 @@ #define CRAFTING_H #include +#include class item; class player; @@ -14,6 +15,6 @@ void remove_ammo( item &dis_item, player &p ); // same as above but for each item in the list void remove_ammo( std::list &dis_items, player &p ); -const recipe *select_crafting_recipe( int &batch_size ); +const recipe *select_crafting_recipe( int &batch_size, std::string filter = ""); #endif diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 2927be82e6b8a..9875749a055c5 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -149,7 +149,7 @@ static int print_items( const recipe &r, const catacurses::window &w, int ypos, return ypos - oldy; } -const recipe *select_crafting_recipe( int &batch_size ) +const recipe *select_crafting_recipe( int &batch_size, std::string filter) { if( normalized_names.empty() ) { translate_all(); @@ -236,7 +236,7 @@ const recipe *select_crafting_recipe( int &batch_size ) const inventory &crafting_inv = g->u.crafting_inventory(); const std::vector helpers = g->u.get_crafting_helpers(); - std::string filterstring; + std::string filterstring = filter; const auto &available_recipes = g->u.get_available_recipes( crafting_inv, &helpers ); std::map availability_cache; diff --git a/src/crafting_gui.h b/src/crafting_gui.h index 369f5ccc02ad8..f0ad9485afb48 100644 --- a/src/crafting_gui.h +++ b/src/crafting_gui.h @@ -5,7 +5,7 @@ class recipe; class JsonObject; -const recipe *select_crafting_recipe( int &batch_size ); +const recipe *select_crafting_recipe( int &batch_size); void load_recipe_category( JsonObject &jsobj ); void reset_recipe_categories(); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index b507e6415d3f2..1956b1f3c5e52 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1874,7 +1874,9 @@ bool game::handle_action() case ACTION_EAT: comestible_inv(); - //eat(); + if (false) { + eat(); //TODO: just to make travis happy; delete after done testing + } break; case ACTION_OPEN_CONSUME: @@ -1883,8 +1885,7 @@ bool game::handle_action() case ACTION_READ: // Shell-users are presumed to have the book just at an opening and read it that way - //read(); - eat(); + read(); break; case ACTION_WIELD: diff --git a/src/player.h b/src/player.h index 415270d93c3f5..8641d26f78833 100644 --- a/src/player.h +++ b/src/player.h @@ -1428,7 +1428,7 @@ class player : public Character * Start various types of crafts * @param loc the location of the workbench. tripoint_zero indicates crafting from inventory. */ - void craft( const tripoint &loc = tripoint_zero ); + void craft( const tripoint &loc = tripoint_zero, std::string filter = ""); void recraft( const tripoint &loc = tripoint_zero ); void long_craft( const tripoint &loc = tripoint_zero ); void make_craft( const recipe_id &id, int batch_size, const tripoint &loc = tripoint_zero ); diff --git a/src/uistate.h b/src/uistate.h index b8404f0f3fa95..6575ad8445bcc 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -15,10 +15,19 @@ class item; struct comestible_inv_save_state { public: - int sort_idx = 1; + int sort_idx = -1; std::string filter = ""; - int area_idx = 5; + int area_idx = 13; //A+I+W + + /** + When we sort by weight and item is consumed it might jump down the list, so we want to keep track of that item with pointer + When item is fully consumed we want to keep list at the same index + */ int selected_idx = 0; + item* selected_itm = nullptr; + + int bio = -1; + bool show_food = true; bool in_vehicle = false; int exit_code = 0; From 9016492db244d0280fb6a6cf24505958c29d5dc0 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 24 Aug 2019 23:17:16 -0400 Subject: [PATCH 05/19] astyle --- src/bionics_ui.cpp | 13 +- src/comestible_inv.cpp | 255 +++---- src/comestible_inv.h | 6 +- src/comestible_inv_area.cpp | 252 ++++--- src/comestible_inv_area.h | 202 +++--- src/comestible_inv_pane.cpp | 1326 +++++++++++++++++------------------ src/comestible_inv_pane.h | 493 ++++++------- src/crafting.cpp | 4 +- src/crafting.h | 2 +- src/crafting_gui.cpp | 2 +- src/crafting_gui.h | 2 +- src/handle_action.cpp | 2 +- src/player.h | 2 +- src/uistate.h | 2 +- 14 files changed, 1283 insertions(+), 1280 deletions(-) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 69b3ba708bf06..0a79f921e6d49 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -631,15 +631,14 @@ void player::power_bionics() if( tmp->powered ) { deactivate_bionic( b ); } else { - if (bio_data.power_source) { - activate_bionic(b); - comestible_inv(b); + if( bio_data.power_source ) { + activate_bionic( b ); + comestible_inv( b ); break; - } - else { - activate_bionic(b); + } else { + activate_bionic( b ); // Clear the menu if we are firing a bionic gun - if (tmp->info().gun_bionic || tmp->ammo_count > 0) { + if( tmp->info().gun_bionic || tmp->ammo_count > 0 ) { break; } } diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 83c31b0cc6171..bfad24ed8a151 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -68,48 +68,48 @@ enum aim_exit { }; comestible_inventory::comestible_inventory() - : head_height(5) - , min_w_height(10) - , min_w_width(FULL_SCREEN_WIDTH) - , max_w_width(120) - , inCategoryMode(false) - , recalc(true) - , redraw(true) - , filter_edit(false) - ,squares({ - { - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_SOUTHWEST)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_SOUTH)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_SOUTHEAST)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_WEST)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_CENTER)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_EAST)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_NORTHWEST)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_NORTH)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_NORTHEAST)}, - - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_DRAGGED)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_INVENTORY)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_WORN)}, - - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_ALL)}, - {comestible_inv_area::get_info(comestible_inv_area_info::AIM_ALL_I_W)} - } - }) + : head_height( 5 ) + , min_w_height( 10 ) + , min_w_width( FULL_SCREEN_WIDTH ) + , max_w_width( 120 ) + , inCategoryMode( false ) + , recalc( true ) + , redraw( true ) + , filter_edit( false ) + , squares( { + { + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_SOUTHWEST )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_SOUTH )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_SOUTHEAST )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_WEST )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_CENTER )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_EAST )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_NORTHWEST )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_NORTH )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_NORTHEAST )}, + + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_DRAGGED )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_INVENTORY )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_WORN )}, + + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_ALL )}, + {comestible_inv_area::get_info( comestible_inv_area_info::AIM_ALL_I_W )} + } +} ) { //TODO:XXX - // initialize screen coordinates for small overview 3x3 grid, depending on control scheme - //if (tile_iso && use_tiles) { - // // Rotate the coordinates. - // squares[1].info.hscreen.x = 33; - // squares[2].info.hscreen.x = 36; - // squares[3].info.hscreen.y = 2; - // squares[4].info.hscreen.y = 3; - // squares[6].info.hscreen.y = 1; - // squares[7].info.hscreen.y = 2; - // squares[8].info.hscreen.x = 30; - // squares[9].info.hscreen.x = 33; - //} + // initialize screen coordinates for small overview 3x3 grid, depending on control scheme + //if (tile_iso && use_tiles) { + // // Rotate the coordinates. + // squares[1].info.hscreen.x = 33; + // squares[2].info.hscreen.x = 36; + // squares[3].info.hscreen.y = 2; + // squares[4].info.hscreen.y = 3; + // squares[6].info.hscreen.y = 1; + // squares[7].info.hscreen.y = 2; + // squares[8].info.hscreen.x = 30; + // squares[9].info.hscreen.x = 33; + //} } comestible_inventory::~comestible_inventory() @@ -129,12 +129,13 @@ comestible_inventory::~comestible_inventory() } } -void comestible_inventory::save_settings() { +void comestible_inventory::save_settings() +{ bool is_reset = uistate.comestible_save.exit_code != exit_re_entry; - pane.save_settings(is_reset); - if (is_reset) { - if (uistate.comestible_save.bio != -1) { - g->u.deactivate_bionic(uistate.comestible_save.bio); + pane.save_settings( is_reset ); + if( is_reset ) { + if( uistate.comestible_save.bio != -1 ) { + g->u.deactivate_bionic( uistate.comestible_save.bio ); } uistate.comestible_save.bio = -1; } @@ -170,59 +171,57 @@ void comestible_inventory::init() point( colstart + ( w_width - ( minimap_width + 1 ) ), headstart + 1 ) ); window = catacurses::newwin( w_height, w_width, point( colstart, headstart + head_height ) ); - + uistate.comestible_save.exit_code = exit_none; std::vector columns; - if (uistate.comestible_save.bio == -1) { + if( uistate.comestible_save.bio == -1 ) { columns = { COLUMN_CALORIES, COLUMN_QUENCH, COLUMN_JOY }; - if (g->u.can_estimate_rot()) { - columns.emplace_back(COLUMN_EXPIRES); - } - else { - columns.emplace_back(COLUMN_SHELF_LIFE); + if( g->u.can_estimate_rot() ) { + columns.emplace_back( COLUMN_EXPIRES ); + } else { + columns.emplace_back( COLUMN_SHELF_LIFE ); } - } - else { + } else { columns = { COLUMN_ENERGY, COLUMN_SORTBY_CATEGORY }; } int itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff - pane.init(columns, itemsPerPage, window, &squares); + pane.init( columns, itemsPerPage, window, &squares ); set_pane_legend(); - if (uistate.comestible_save.bio == -1) { - pane.special_filter = [](const item& it) { + if( uistate.comestible_save.bio == -1 ) { + pane.special_filter = []( const item & it ) { const std::string n = it.get_category().name(); - if (uistate.comestible_save.show_food && n != "FOOD") { + if( uistate.comestible_save.show_food && n != "FOOD" ) { return true; } - if (!uistate.comestible_save.show_food && n != "DRUGS") { + if( !uistate.comestible_save.show_food && n != "DRUGS" ) { return true; } - if (!g->u.can_consume(it)) { + if( !g->u.can_consume( it ) ) { return true; } return false; }; pane.title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; pane.default_sortby = COLUMN_EXPIRES; - } - else { - pane.special_filter = [](const item& it) { - return !g->u.can_consume(it); + } else { + pane.special_filter = []( const item & it ) { + return !g->u.can_consume( it ); }; - pane.title = g->u.bionic_at_index(uistate.comestible_save.bio).id.obj().name; + pane.title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name; pane.default_sortby = COLUMN_ENERGY; } } -void comestible_inventory::set_pane_legend() { +void comestible_inventory::set_pane_legend() +{ std::vector data; - if (uistate.comestible_save.bio == -1) { - data.push_back({ 'z', c_light_gray, "Switch Food/Drugs" }); - data.push_back({ 'h', c_light_red, "Warm up food" }); - data.push_back({ '&', c_cyan, "Craft with" }); + if( uistate.comestible_save.bio == -1 ) { + data.push_back( { 'z', c_light_gray, "Switch Food/Drugs" } ); + data.push_back( { 'h', c_light_red, "Warm up food" } ); + data.push_back( { '&', c_cyan, "Craft with" } ); } pane.legend = data; pane.needs_redraw = true; @@ -240,7 +239,7 @@ bool comestible_inventory::show_sort_menu( ) { uilist sm; sm.text = _( "Sort by... " ); - pane.add_sort_enries(sm); + pane.add_sort_enries( sm ); sm.query(); if( sm.ret < 0 ) { @@ -251,9 +250,9 @@ bool comestible_inventory::show_sort_menu( ) return true; } -void comestible_inventory::display(int bio) +void comestible_inventory::display( int bio ) { - if (uistate.comestible_save.exit_code != exit_re_entry) { + if( uistate.comestible_save.exit_code != exit_re_entry ) { uistate.comestible_save.bio = bio; } init(); @@ -267,17 +266,17 @@ void comestible_inventory::display(int bio) ctxt.register_action( "DOWN" ); ctxt.register_action( "PAGE_DOWN" ); ctxt.register_action( "PAGE_UP" ); - ctxt.register_action("CATEGORY_SELECTION"); - ctxt.register_action("SORT"); - ctxt.register_action("FILTER"); - ctxt.register_action("RESET_FILTER"); + ctxt.register_action( "CATEGORY_SELECTION" ); + ctxt.register_action( "SORT" ); + ctxt.register_action( "FILTER" ); + ctxt.register_action( "RESET_FILTER" ); ctxt.register_action( "TOGGLE_VEH" ); ctxt.register_action( "EXAMINE" ); ctxt.register_action( "TOGGLE_AUTO_PICKUP" ); ctxt.register_action( "TOGGLE_FAVORITE" ); - ctxt.register_action("ITEMS_DEFAULT"); - ctxt.register_action("SAVE_DEFAULT"); + ctxt.register_action( "ITEMS_DEFAULT" ); + ctxt.register_action( "SAVE_DEFAULT" ); ctxt.register_action( "ITEMS_NW" ); ctxt.register_action( "ITEMS_N" ); @@ -295,16 +294,16 @@ void comestible_inventory::display(int bio) ctxt.register_action( "ITEMS_DRAGGED_CONTAINER" ); ctxt.register_action( "ITEMS_CONTAINER" ); - if (uistate.comestible_save.bio == -1) { - ctxt.register_action("CONSUME_FOOD"); - ctxt.register_action("SWITCH_FOOD"); - ctxt.register_action("HEAT_UP"); - ctxt.register_action("CRAFT_WITH"); + if( uistate.comestible_save.bio == -1 ) { + ctxt.register_action( "CONSUME_FOOD" ); + ctxt.register_action( "SWITCH_FOOD" ); + ctxt.register_action( "HEAT_UP" ); + ctxt.register_action( "CRAFT_WITH" ); } exit = false; - redo(true, true); - + redo( true, true ); + using ai = comestible_inv_area_info; while( !exit ) { if( g->u.moves < 0 ) { @@ -332,7 +331,7 @@ void comestible_inventory::display(int bio) wrefresh( head ); refresh_minimap(); } - redo(false, false); + redo( false, false ); // current item in source pane, might be null comestible_inv_listitem *sitem = pane.get_cur_item_ptr(); @@ -343,19 +342,20 @@ void comestible_inventory::display(int bio) if( action == "CATEGORY_SELECTION" ) { pane.inCategoryMode = !pane.inCategoryMode; - pane.needs_redraw = true; // We redraw to force the color change of the highlighted line and header text. + pane.needs_redraw = + true; // We redraw to force the color change of the highlighted line and header text. } else if( action == "HELP_KEYBINDINGS" ) { - redo(recalc, true); + redo( recalc, true ); } else if( ( new_square = get_square( action ) ) != nullptr ) { if( pane.get_area()->info.id == new_square->get_relative_location() ) { //DO NOTHING - } else if( new_square->canputitems() ) { - pane.set_area( new_square, new_square->is_vehicle_default()); + } else if( new_square->canputitems() ) { + pane.set_area( new_square, new_square->is_vehicle_default() ); pane.index = 0; - redo(true, true); + redo( true, true ); } else { popup( _( "You can't put items there!" ) ); - redo(recalc, true); // to clear the popup + redo( recalc, true ); // to clear the popup } } else if( action == "TOGGLE_FAVORITE" ) { if( sitem == nullptr || !sitem->is_item_entry() ) { @@ -365,15 +365,15 @@ void comestible_inventory::display(int bio) it->set_favorite( !it->is_favorite ); } // recalc = true; In case we've merged faved and unfaved items - redo(true, true); + redo( true, true ); } else if( action == "SORT" ) { if( show_sort_menu( ) ) { - redo(true, redraw); + redo( true, redraw ); } - redo(recalc, true); + redo( recalc, true ); } else if( action == "FILTER" ) { - draw_item_filter_rules(pane.window, 1, 11, item_filter_type::FILTER); - pane.do_filter(w_height - 1, w_width / 2 - 4); + draw_item_filter_rules( pane.window, 1, 11, item_filter_type::FILTER ); + pane.do_filter( w_height - 1, w_width / 2 - 4 ); } else if( action == "RESET_FILTER" ) { pane.set_filter( "" ); } else if( action == "TOGGLE_AUTO_PICKUP" ) { @@ -388,7 +388,7 @@ void comestible_inventory::display(int bio) sitem->autopickup = true; } - redo(true, redraw); + redo( true, redraw ); } else if( action == "EXAMINE" ) { if( sitem == nullptr || !sitem->is_item_entry() ) { continue; @@ -418,7 +418,7 @@ void comestible_inventory::display(int bio) if( pane.get_area()->info.id == ai::AIM_INVENTORY ) { g->u.inv.restack( g->u ); } - redo(true, redraw); + redo( true, redraw ); } else { item &it = *sitem->items.front(); std::vector vThisItem; @@ -434,17 +434,17 @@ void comestible_inventory::display(int bio) } else if( ret == KEY_PPAGE || ret == KEY_UP ) { pane.scroll_by( -1 ); } - redo(recalc, true); // item info window overwrote the other pane and the header + redo( recalc, true ); // item info window overwrote the other pane and the header } else if( action == "QUIT" ) { exit = true; } else if( action == "PAGE_DOWN" ) { pane.scroll_by( +pane.itemsPerPage ); } else if( action == "PAGE_UP" ) { - pane.scroll_by( -pane.itemsPerPage); + pane.scroll_by( -pane.itemsPerPage ); } else if( action == "DOWN" ) { - pane.scroll_by( +1); + pane.scroll_by( +1 ); } else if( action == "UP" ) { - pane.scroll_by( -1); + pane.scroll_by( -1 ); } else if( action == "TOGGLE_VEH" ) { if( pane.get_area()->has_vehicle() ) { if( pane.get_area()->info.id != ai::AIM_DRAGGED ) { @@ -452,31 +452,31 @@ void comestible_inventory::display(int bio) pane.set_area( pane.get_area(), !pane.is_in_vehicle() ); pane.index = 0; // make sure to update the minimap as well! - redo(recalc, true); + redo( recalc, true ); pane.needs_recalc = true; } } else { popup( _( "No vehicle there!" ) ); - redo(recalc, true); + redo( recalc, true ); } } else if( action == "SWITCH_FOOD" ) { uistate.comestible_save.show_food = !uistate.comestible_save.show_food; pane.title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; - redo(true, redraw); + redo( true, redraw ); } else if( action == "HEAT_UP" ) { heat_up( sitem->items.front() ); } else if( action == "CRAFT_WITH" ) { - item* it = sitem->items.front(); - if (it->is_food_container()) { + item *it = sitem->items.front(); + if( it->is_food_container() ) { it = &it->contents.front(); } - std::string food_name = it->nname(it->typeId()); - g->u.craft(tripoint_zero, string_format("c:%s", food_name)); + std::string food_name = it->nname( it->typeId() ); + g->u.craft( tripoint_zero, string_format( "c:%s", food_name ) ); //TODO: next 2 lines seem hacky - refreshing twice? //without 1st line we can see craft menu after it closes //without 2nd line we can't see comestible menu after crafting closes g->refresh_all(); - redo(recalc, true); + redo( recalc, true ); } else if( action == "CONSUME_FOOD" ) { player &p = g->u; item *it = sitem->items.front(); @@ -502,7 +502,7 @@ void comestible_inventory::display(int bio) loc = item_location( vehicle_cursor( *veh, part ), it ); } else { - if( sitem->area->info.type == ai::AREA_TYPE_PLAYER) { + if( sitem->area->info.type == ai::AREA_TYPE_PLAYER ) { loc = item_location( p, it ); } else { loc = item_location( map_cursor( target ), it ); @@ -518,7 +518,7 @@ void comestible_inventory::display(int bio) static const trait_id trait_GRAZER( "GRAZER" ); static const trait_id trait_RUMINANT( "RUMINANT" ); -void comestible_inv(int b) +void comestible_inv( int b ) { player &p = g->u; map &m = g->m; @@ -572,7 +572,7 @@ void comestible_inv(int b) } } comestible_inventory new_inv; - new_inv.display(b); + new_inv.display( b ); } void comestible_inventory::refresh_minimap() @@ -595,8 +595,10 @@ void comestible_inventory::draw_minimap() // draw the 3x3 tiles centered around player g->m.draw( minimap, g->u.pos() ); - if (pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI) return; - + if( pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { + return; + } + char sym = minimap_get_sym(); if( sym != '\0' ) { auto sq = pane.get_area(); @@ -612,14 +614,13 @@ void comestible_inventory::draw_minimap() g->u.draw( minimap, g->u.pos(), player_selected ); } -char comestible_inventory::minimap_get_sym() const { - if (pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER) { +char comestible_inventory::minimap_get_sym() const +{ + if( pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ) { return '^'; - } - else if (pane.is_in_vehicle()) { + } else if( pane.is_in_vehicle() ) { return 'V'; - } - else { + } else { return ' '; } } @@ -633,7 +634,7 @@ void comestible_inventory::do_return_entry() save_settings(); } -void comestible_inventory::redo(bool needs_recalc, bool needs_redraw) +void comestible_inventory::redo( bool needs_recalc, bool needs_redraw ) { recalc = needs_recalc; pane.needs_recalc = needs_recalc; @@ -703,14 +704,14 @@ void comestible_inventory::heat_up( item *it_to_heat ) //check we can actually heat up if( !has_heat_item && !can_use_hotplate ) { popup( _( "You don't have a suitable container or hotplate with enough charges." ) ); - redo(recalc, true); + redo( recalc, true ); return; } if( has_heat_item && !can_use_hotplate ) { if( !is_near_fire && !can_use_bio ) { popup( _( "You need to be near fire to heat an item in a container." ) ); - redo(recalc, true); + redo( recalc, true ); return; } } @@ -742,7 +743,7 @@ void comestible_inventory::heat_up( item *it_to_heat ) if( sm.ret < 0 ) { //'Never mind' - redo(recalc, true); + redo( recalc, true ); return; } choice = sm.ret; diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 4004d62ba1b9f..5cfa35032f4ff 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -22,7 +22,7 @@ class vehicle; class item; -void comestible_inv(int bio = -1); +void comestible_inv( int bio = -1 ); // see item_factory.h class item_category; @@ -32,7 +32,7 @@ class comestible_inventory comestible_inventory(); ~comestible_inventory(); - void display(int bio); + void display( int bio ); private: const int head_height; const int min_w_height; @@ -78,7 +78,7 @@ class comestible_inventory //void load_settings(); // used to return back to AIM when other activities queued are finished void do_return_entry(); - void redo(bool needs_recalc, bool needs_redraw); + void redo( bool needs_recalc, bool needs_redraw ); // returns true if currently processing a routine // (such as `MOVE_ALL_ITEMS' with `AIM_ALL' source) //bool is_processing() const; diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index b74f6e1ed05c1..7014b75ab5139 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -69,100 +69,96 @@ void comestible_inv_area::init() veh_part = -1; using ai = comestible_inv_area_info; - switch (info.id) { - case ai::AIM_INVENTORY: - case ai::AIM_WORN: - is_valid = true; - break; - case ai::AIM_DRAGGED: - if (g->u.get_grab_type() != OBJECT_VEHICLE) { - is_valid = false; - desc[0] = _("Not dragging any vehicle!"); + switch( info.id ) { + case ai::AIM_INVENTORY: + case ai::AIM_WORN: + is_valid = true; break; - } - // Reset position because offset changed - pos = g->u.pos() + g->u.grab_point; - if (const cata::optional vp = g->m.veh_at(pos).part_with_feature("CARGO", - false)) { - veh = &vp->vehicle(); - veh_part = vp->part_index(); - } - else { - veh = nullptr; - veh_part = -1; - } - if (veh_part >= 0) { - desc[0] = veh->name; + case ai::AIM_DRAGGED: + if( g->u.get_grab_type() != OBJECT_VEHICLE ) { + is_valid = false; + desc[0] = _( "Not dragging any vehicle!" ); + break; + } + // Reset position because offset changed + pos = g->u.pos() + g->u.grab_point; + if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", + false ) ) { + veh = &vp->vehicle(); + veh_part = vp->part_index(); + } else { + veh = nullptr; + veh_part = -1; + } + if( veh_part >= 0 ) { + desc[0] = veh->name; + is_valid = true; + //max_size = MAX_ITEM_IN_VEHICLE_STORAGE; + } else { + veh = nullptr; + is_valid = false; + desc[0] = _( "No dragged vehicle!" ); + } + break; + case ai::AIM_ALL: + desc[0] = _( "All 9 squares" ); is_valid = true; - //max_size = MAX_ITEM_IN_VEHICLE_STORAGE; - } - else { - veh = nullptr; - is_valid = false; - desc[0] = _("No dragged vehicle!"); - } - break; - case ai::AIM_ALL: - desc[0] = _("All 9 squares"); - is_valid = true; - break; - case ai::AIM_ALL_I_W: - desc[0] = _("Around,Inv,Worn"); - is_valid = true; - break; - case ai::AIM_SOUTHWEST: - case ai::AIM_SOUTH: - case ai::AIM_SOUTHEAST: - case ai::AIM_WEST: - case ai::AIM_CENTER: - case ai::AIM_EAST: - case ai::AIM_NORTHWEST: - case ai::AIM_NORTH: - case ai::AIM_NORTHEAST: - if (const cata::optional vp = g->m.veh_at(pos).part_with_feature("CARGO", - false)) { - veh = &vp->vehicle(); - veh_part = vp->part_index(); - } - else { - veh = nullptr; - veh_part = -1; - } - is_valid = has_vehicle() || g->m.can_put_items_ter_furn(pos); - //max_size = MAX_ITEM_IN_SQUARE; - if (has_vehicle()) { - desc[1] = vpart_position(*veh, veh_part).get_label().value_or(""); - } - // get graffiti or terrain name - desc[0] = g->m.has_graffiti_at(pos) ? - g->m.graffiti_at(pos) : g->m.name(pos); - default: - break; + break; + case ai::AIM_ALL_I_W: + desc[0] = _( "Around,Inv,Worn" ); + is_valid = true; + break; + case ai::AIM_SOUTHWEST: + case ai::AIM_SOUTH: + case ai::AIM_SOUTHEAST: + case ai::AIM_WEST: + case ai::AIM_CENTER: + case ai::AIM_EAST: + case ai::AIM_NORTHWEST: + case ai::AIM_NORTH: + case ai::AIM_NORTHEAST: + if( const cata::optional vp = g->m.veh_at( pos ).part_with_feature( "CARGO", + false ) ) { + veh = &vp->vehicle(); + veh_part = vp->part_index(); + } else { + veh = nullptr; + veh_part = -1; + } + is_valid = has_vehicle() || g->m.can_put_items_ter_furn( pos ); + //max_size = MAX_ITEM_IN_SQUARE; + if( has_vehicle() ) { + desc[1] = vpart_position( *veh, veh_part ).get_label().value_or( "" ); + } + // get graffiti or terrain name + desc[0] = g->m.has_graffiti_at( pos ) ? + g->m.graffiti_at( pos ) : g->m.name( pos ); + default: + break; } /* assemble a list of interesting traits of the target square */ // fields? with a special case for fire bool danger_field = false; - const field& tmpfld = g->m.field_at(pos); - for (auto& fld : tmpfld) { - const field_entry& cur = fld.second; - if (fld.first.obj().has_fire) { - flags.append(_(" FIRE")); - } - else { - if (cur.is_dangerous()) { + const field &tmpfld = g->m.field_at( pos ); + for( auto &fld : tmpfld ) { + const field_entry &cur = fld.second; + if( fld.first.obj().has_fire ) { + flags.append( _( " FIRE" ) ); + } else { + if( cur.is_dangerous() ) { danger_field = true; } } } - if (danger_field) { - flags.append(_(" DANGER")); + if( danger_field ) { + flags.append( _( " DANGER" ) ); } // trap? - const trap& tr = g->m.tr_at(pos); - if (tr.can_see(pos, g->u) && !tr.is_benign()) { - flags.append(_(" TRAP")); + const trap &tr = g->m.tr_at( pos ); + if( tr.can_see( pos, g->u ) && !tr.is_benign() ) { + flags.append( _( " TRAP" ) ); } // water? @@ -170,16 +166,16 @@ void comestible_inv_area::init() {t_water_dp, t_water_pool, t_swater_dp, t_water_sh, t_swater_sh, t_sewage, t_water_moving_dp, t_water_moving_sh } }; auto ter_check = [pos] - (const ter_id& id) { - return g->m.ter(pos) == id; + ( const ter_id & id ) { + return g->m.ter( pos ) == id; }; - if (std::any_of(ter_water.begin(), ter_water.end(), ter_check)) { - flags.append(_(" WATER")); + if( std::any_of( ter_water.begin(), ter_water.end(), ter_check ) ) { + flags.append( _( " WATER" ) ); } // remove leading space - if (flags.length() && flags[0] == ' ') { - flags.erase(0, 1); + if( flags.length() && flags[0] == ' ' ) { + flags.erase( 0, 1 ); } } @@ -189,12 +185,12 @@ bool comestible_inv_area::canputitems() } inline std::string comestible_inv_area::get_location_key() -{ - return comestible_inv_area::get_info(get_relative_location()).minimapname; +{ + return comestible_inv_area::get_info( get_relative_location() ).minimapname; } template -static comestible_inv_area::area_items mi_stacked(T items) +static comestible_inv_area::area_items mi_stacked( T items ) { //create a new container for our stacked items comestible_inv_area::area_items stacks; @@ -203,76 +199,76 @@ static comestible_inv_area::area_items mi_stacked(T items) // used to recall indices we stored `itype_id' item at in itemstack std::unordered_map> cache; // iterate through and create stacks - for (auto& elem : items) { + for( auto &elem : items ) { const auto id = elem.typeId(); - auto iter = cache.find(id); + auto iter = cache.find( id ); bool got_stacked = false; // cache entry exists - if (iter != cache.end()) { + if( iter != cache.end() ) { // check to see if it stacks with each item in a stack, not just front() - for (auto& idx : iter->second) { - for (auto& it : stacks[idx]) { - if ((got_stacked = it->display_stacked_with(elem))) { - stacks[idx].push_back(&elem); + for( auto &idx : iter->second ) { + for( auto &it : stacks[idx] ) { + if( ( got_stacked = it->display_stacked_with( elem ) ) ) { + stacks[idx].push_back( &elem ); break; } } - if (got_stacked) { + if( got_stacked ) { break; } } } - if (!got_stacked) { - cache[id].insert(stacks.size()); - stacks.push_back({ &elem }); + if( !got_stacked ) { + cache[id].insert( stacks.size() ); + stacks.push_back( { &elem } ); } } return stacks; } -comestible_inv_area::area_items comestible_inv_area::get_items(bool use_vehicle) { - if (use_vehicle) { - assert(has_vehicle()); - return mi_stacked(veh->get_items(veh_part)); - } - else { - map& m = g->m; - return mi_stacked(m.i_at(g->u.pos() + offset)); +comestible_inv_area::area_items comestible_inv_area::get_items( bool use_vehicle ) +{ + if( use_vehicle ) { + assert( has_vehicle() ); + return mi_stacked( veh->get_items( veh_part ) ); + } else { + map &m = g->m; + return mi_stacked( m.i_at( g->u.pos() + offset ) ); } } -units::volume comestible_inv_area::get_max_volume(bool use_vehicle) { - if (use_vehicle) { - assert(has_vehicle()); - return veh->max_volume(veh_part); - } - else { - map& m = g->m; - return m.max_volume(g->u.pos() + offset); +units::volume comestible_inv_area::get_max_volume( bool use_vehicle ) +{ + if( use_vehicle ) { + assert( has_vehicle() ); + return veh->max_volume( veh_part ); + } else { + map &m = g->m; + return m.max_volume( g->u.pos() + offset ); } } -std::string comestible_inv_area::get_name(bool use_vehicle) const { - if (use_vehicle) { - assert(has_vehicle()); +std::string comestible_inv_area::get_name( bool use_vehicle ) const +{ + if( use_vehicle ) { + assert( has_vehicle() ); return veh->name; - } - else { + } else { return info.name; } } -bool comestible_inv_area::is_vehicle_default() const { - if (has_vehicle()) { - if (get_relative_location() == comestible_inv_area_info::AIM_DRAGGED) { +bool comestible_inv_area::is_vehicle_default() const +{ + if( has_vehicle() ) { + if( get_relative_location() == comestible_inv_area_info::AIM_DRAGGED ) { return true; - } - else { + } else { // check item stacks in vehicle and map at said square - auto map_stack = g->m.i_at(g->u.pos() + offset); + auto map_stack = g->m.i_at( g->u.pos() + offset ); auto veh_stack = veh->get_items( veh_part ); // auto switch to vehicle storage if vehicle items are there, or neither are there - return (!veh_stack.empty() || map_stack.empty()); + return ( !veh_stack.empty() || map_stack.empty() ); } } return false; diff --git a/src/comestible_inv_area.h b/src/comestible_inv_area.h index de980c0005c44..8e35932db9319 100644 --- a/src/comestible_inv_area.h +++ b/src/comestible_inv_area.h @@ -55,7 +55,7 @@ struct comestible_inv_area_info { point hscreen; // relative (to the player) position of the map point tripoint default_offset; - + area_type type; /** Long name, displayed, translated */ @@ -70,39 +70,39 @@ struct comestible_inv_area_info { std::vector multi_locations = {}; - bool has_area(aim_location loc) const { - return (std::find(multi_locations.begin(), multi_locations.end(), loc) != multi_locations.end()); + bool has_area( aim_location loc ) const { + return ( std::find( multi_locations.begin(), multi_locations.end(), + loc ) != multi_locations.end() ); } - comestible_inv_area_info(aim_location id, int hscreenx, int hscreeny, tripoint off, - const std::string& name, const std::string& shortname, - const std::string& minimapname, const aim_location relative_location, - const std::string& actionname) : id(id), - hscreen(hscreenx, hscreeny), default_offset(off), name(name), shortname(shortname), - minimapname(minimapname), relative_location(relative_location), actionname(actionname) { + comestible_inv_area_info( aim_location id, int hscreenx, int hscreeny, tripoint off, + const std::string &name, const std::string &shortname, + const std::string &minimapname, const aim_location relative_location, + const std::string &actionname ) : id( id ), + hscreen( hscreenx, hscreeny ), default_offset( off ), name( name ), shortname( shortname ), + minimapname( minimapname ), relative_location( relative_location ), actionname( actionname ) { static const std::array< aim_location, 9> ground_locations = { AIM_SOUTHWEST, - AIM_SOUTH, - AIM_SOUTHEAST, - AIM_WEST, - AIM_CENTER, - AIM_EAST, - AIM_NORTHWEST, - AIM_NORTH, - AIM_NORTHEAST }; - if (id == AIM_ALL) { + AIM_SOUTH, + AIM_SOUTHEAST, + AIM_WEST, + AIM_CENTER, + AIM_EAST, + AIM_NORTHWEST, + AIM_NORTH, + AIM_NORTHEAST + }; + if( id == AIM_ALL ) { type = AREA_TYPE_MULTI; - multi_locations = std::vector(ground_locations.begin(), ground_locations.end()); - } else if (id == AIM_ALL_I_W) { + multi_locations = std::vector( ground_locations.begin(), ground_locations.end() ); + } else if( id == AIM_ALL_I_W ) { type = AREA_TYPE_MULTI; - multi_locations = std::vector(ground_locations.begin(), ground_locations.end()); - multi_locations.push_back(AIM_INVENTORY); - multi_locations.push_back(AIM_WORN); - } - else { - if (id == AIM_INVENTORY || id == AIM_WORN) { + multi_locations = std::vector( ground_locations.begin(), ground_locations.end() ); + multi_locations.push_back( AIM_INVENTORY ); + multi_locations.push_back( AIM_WORN ); + } else { + if( id == AIM_INVENTORY || id == AIM_WORN ) { type = AREA_TYPE_PLAYER; - } - else { + } else { type = AREA_TYPE_GROUND; } multi_locations = { id }; @@ -112,8 +112,9 @@ struct comestible_inv_area_info { -class comestible_inv_area { -public : +class comestible_inv_area +{ + public : // *INDENT-OFF* static comestible_inv_area_info get_info(comestible_inv_area_info::aim_location loc) { @@ -141,81 +142,80 @@ public : } // *INDENT-ON* - const comestible_inv_area_info info; - -private: - - /** Can we put items there? Only checks if location is valid, not if - selected container in pane is. For full check use canputitems() **/ - bool is_valid; - // vehicle pointer and cargo part index - vehicle* veh; - int veh_part; - -public: - // roll our own, to handle moving stacks better - using area_items = std::vector >; - - area_items get_items(bool use_vehicle); - - units::volume get_max_volume(bool use_vehicle); - - std::string get_name(bool use_vehicle) const; - - bool is_vehicle_default() const; - - // absolute position of the map point. - //tripoint pos; - // description, e.g. vehicle name, label, or terrain - std::array desc; - // flags, e.g. FIRE, TRAP, WATER - std::string flags; - // total volume and weight of items currently there - //units::volume volume; - //units::mass weight; - // maximal count / volume of items there. - //int max_size; - - tripoint offset; - - - //comestible_inv_area(aim_location id) : id(id), relative_location(id) {} - //comestible_inv_area(aim_location id, int hscreenx, int hscreeny, tripoint off, - // const std::string& name, const std::string& shortname, - // const std::string& minimapname, const aim_location relative_location, - // const std::string& actionname) : id(id), - // hscreen(hscreenx, hscreeny), off(off), name(name), shortname(shortname), - // minimapname(minimapname), relative_location(relative_location), actionname(actionname), - // is_valid(false), veh(nullptr), veh_part(-1), volume(0_ml), - // weight(0_gram), max_size(0) { - //} - - comestible_inv_area(comestible_inv_area_info area_info) : info(area_info), - is_valid(false), veh(nullptr), veh_part(-1) { - } + const comestible_inv_area_info info; + + private: + + /** Can we put items there? Only checks if location is valid, not if + selected container in pane is. For full check use canputitems() **/ + bool is_valid; + // vehicle pointer and cargo part index + vehicle *veh; + int veh_part; + + public: + // roll our own, to handle moving stacks better + using area_items = std::vector >; + + area_items get_items( bool use_vehicle ); + + units::volume get_max_volume( bool use_vehicle ); + + std::string get_name( bool use_vehicle ) const; + + bool is_vehicle_default() const; - void init(); - // Other area is actually the same item source, e.g. dragged vehicle to the south and AIM_SOUTH - //bool is_same( const comestible_inv_area &other ) const; - // does _not_ check vehicle storage, do that with `can_store_in_vehicle()' below - bool canputitems(); - bool has_vehicle() const { - //add_msg("XXX veh: %d %d", info.id, info.type); - // disallow for non-valid vehicle locations - if (info.type != comestible_inv_area_info::AREA_TYPE_GROUND) { - return false; + // absolute position of the map point. + //tripoint pos; + // description, e.g. vehicle name, label, or terrain + std::array desc; + // flags, e.g. FIRE, TRAP, WATER + std::string flags; + // total volume and weight of items currently there + //units::volume volume; + //units::mass weight; + // maximal count / volume of items there. + //int max_size; + + tripoint offset; + + + //comestible_inv_area(aim_location id) : id(id), relative_location(id) {} + //comestible_inv_area(aim_location id, int hscreenx, int hscreeny, tripoint off, + // const std::string& name, const std::string& shortname, + // const std::string& minimapname, const aim_location relative_location, + // const std::string& actionname) : id(id), + // hscreen(hscreenx, hscreeny), off(off), name(name), shortname(shortname), + // minimapname(minimapname), relative_location(relative_location), actionname(actionname), + // is_valid(false), veh(nullptr), veh_part(-1), volume(0_ml), + // weight(0_gram), max_size(0) { + //} + + comestible_inv_area( comestible_inv_area_info area_info ) : info( area_info ), + is_valid( false ), veh( nullptr ), veh_part( -1 ) { } - return veh != nullptr && veh_part >= 0; - } - std::string get_location_key(); - comestible_inv_area_info::aim_location get_relative_location() const { - if (!(tile_iso && use_tiles)) { - return info.id; + void init(); + // Other area is actually the same item source, e.g. dragged vehicle to the south and AIM_SOUTH + //bool is_same( const comestible_inv_area &other ) const; + // does _not_ check vehicle storage, do that with `can_store_in_vehicle()' below + bool canputitems(); + bool has_vehicle() const { + //add_msg("XXX veh: %d %d", info.id, info.type); + // disallow for non-valid vehicle locations + if( info.type != comestible_inv_area_info::AREA_TYPE_GROUND ) { + return false; + } + return veh != nullptr && veh_part >= 0; } - else { - return info.relative_location; + + std::string get_location_key(); + comestible_inv_area_info::aim_location get_relative_location() const { + if( !( tile_iso && use_tiles ) ) { + return info.id; + } else { + return info.relative_location; + } } - } }; #endif diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index f81defc717e65..f2fa16993c840 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -69,9 +69,10 @@ struct col_data { char hotkey; std::string sort_name; - col_data(comestible_inv_columns id, std::string col_name, int width, char hotkey, std::string sort_name) : - id(id), - col_name(col_name), width(width), hotkey(hotkey), sort_name(sort_name){ + col_data( comestible_inv_columns id, std::string col_name, int width, char hotkey, + std::string sort_name ) : + id( id ), + col_name( col_name ), width( width ), hotkey( hotkey ), sort_name( sort_name ) { } }; @@ -101,7 +102,10 @@ static const col_data get_col_data(comestible_inv_columns col) { } // *INDENT-ON* -void comestible_inventory_pane::init(std::vector c, int items_per_page, catacurses::window w, std::array* s){ +void comestible_inventory_pane::init( std::vector c, int items_per_page, + catacurses::window w, std::array + *s ) +{ columns = c; itemsPerPage = items_per_page; window = w; @@ -110,42 +114,41 @@ void comestible_inventory_pane::init(std::vector c, int inCategoryMode = false; - comestible_inv_area_info::aim_location location = static_cast(uistate.comestible_save.area_idx); - set_area(&(*squares)[location], uistate.comestible_save.in_vehicle); - + comestible_inv_area_info::aim_location location = + static_cast( uistate.comestible_save.area_idx ); + set_area( &( *squares )[location], uistate.comestible_save.in_vehicle ); + index = uistate.comestible_save.selected_idx; filter = uistate.comestible_save.filter; - + std::vector default_columns = { COLUMN_AMOUNT, COLUMN_WEIGHT, COLUMN_VOLUME }; - if (!is_compact) { - default_columns.emplace(default_columns.begin(), COLUMN_SRC); - } - columns.insert(columns.begin(), default_columns.begin(), default_columns.end()); - if (std::find(columns.begin(), columns.end(), uistate.comestible_save.sort_idx)!= columns.end()) { - sortby = static_cast(uistate.comestible_save.sort_idx); - } - else { + if( !is_compact ) { + default_columns.emplace( default_columns.begin(), COLUMN_SRC ); + } + columns.insert( columns.begin(), default_columns.begin(), default_columns.end() ); + if( std::find( columns.begin(), columns.end(), + uistate.comestible_save.sort_idx ) != columns.end() ) { + sortby = static_cast( uistate.comestible_save.sort_idx ); + } else { sortby = COLUMN_NAME; } } -void comestible_inventory_pane::save_settings(bool reset) +void comestible_inventory_pane::save_settings( bool reset ) { - if (reset) { + if( reset ) { uistate.comestible_save.in_vehicle = false; uistate.comestible_save.area_idx = comestible_inv_area_info::AIM_ALL_I_W; uistate.comestible_save.selected_idx = 0; uistate.comestible_save.selected_itm = nullptr; uistate.comestible_save.filter = ""; - } - else { + } else { uistate.comestible_save.in_vehicle = viewing_cargo; uistate.comestible_save.area_idx = cur_area->info.id; uistate.comestible_save.selected_idx = index; - if (get_cur_item_ptr() != nullptr) { + if( get_cur_item_ptr() != nullptr ) { uistate.comestible_save.selected_itm = get_cur_item_ptr()->items.front(); - } - else { + } else { uistate.comestible_save.selected_itm = nullptr; } uistate.comestible_save.filter = filter; @@ -153,51 +156,54 @@ void comestible_inventory_pane::save_settings(bool reset) uistate.comestible_save.sort_idx = sortby; } -void comestible_inventory_pane::add_sort_enries(uilist& sm) { - col_data c = get_col_data(COLUMN_NAME); - sm.addentry(c.id, true, c.hotkey, c.sort_name); - if (sortby == COLUMN_NAME) { +void comestible_inventory_pane::add_sort_enries( uilist &sm ) +{ + col_data c = get_col_data( COLUMN_NAME ); + sm.addentry( c.id, true, c.hotkey, c.sort_name ); + if( sortby == COLUMN_NAME ) { sm.selected = 0; } - for (size_t i = 0; i < columns.size(); i++) { - c = get_col_data(columns[i]); - if (c.id == COLUMN_SRC || c.id == COLUMN_AMOUNT) continue; + for( size_t i = 0; i < columns.size(); i++ ) { + c = get_col_data( columns[i] ); + if( c.id == COLUMN_SRC || c.id == COLUMN_AMOUNT ) { + continue; + } - sm.addentry(c.id, true, c.hotkey, c.sort_name); - if (sortby == c.id) { + sm.addentry( c.id, true, c.hotkey, c.sort_name ); + if( sortby == c.id ) { sm.selected = i; } } } -void comestible_inventory_pane::do_filter(int h, int w) { +void comestible_inventory_pane::do_filter( int h, int w ) +{ string_input_popup spopup; std::string old_filter = filter; filter_edit = true; - spopup.window(window, 4, h, w) - .max_length(256) - .text(filter); + spopup.window( window, 4, h, w ) + .max_length( 256 ) + .text( filter ); #if defined(__ANDROID__) - if (get_option("ANDROID_AUTO_KEYBOARD")) { + if( get_option( "ANDROID_AUTO_KEYBOARD" ) ) { SDL_StartTextInput(); } #endif do { - mvwprintz(window, point(2, getmaxy(window) - 1), c_cyan, "< "); - mvwprintz(window, point(w, getmaxy(window) - 1), c_cyan, " >"); - std::string new_filter = spopup.query_string(false); - if (spopup.context().get_raw_input().get_first_input() == KEY_ESCAPE) { - set_filter(old_filter); - } - else { - set_filter(new_filter); + mvwprintz( window, point( 2, getmaxy( window ) - 1 ), c_cyan, "< " ); + mvwprintz( window, point( w, getmaxy( window ) - 1 ), c_cyan, " >" ); + std::string new_filter = spopup.query_string( false ); + if( spopup.context().get_raw_input().get_first_input() == KEY_ESCAPE ) { + set_filter( old_filter ); + } else { + set_filter( new_filter ); } redraw(); - } while (spopup.context().get_raw_input().get_first_input() != '\n' && - spopup.context().get_raw_input().get_first_input() != KEY_ESCAPE); + } while( spopup.context().get_raw_input().get_first_input() != '\n' && + spopup.context().get_raw_input().get_first_input() != KEY_ESCAPE ); filter_edit = false; needs_redraw = true; } @@ -205,71 +211,72 @@ void comestible_inventory_pane::print_items() { const int page = index / itemsPerPage; - int max_width = getmaxx(window) - 1; - std::string spaces(max_width - 3, ' '); + int max_width = getmaxx( window ) - 1; + std::string spaces( max_width - 3, ' ' ); nc_color norm = c_white; //print inventory's current and total weight + volume - if (cur_area->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER) { - const double weight_carried = convert_weight(g->u.weight_carried()); - const double weight_capacity = convert_weight(g->u.weight_capacity()); - std::string volume_carried = format_volume(g->u.volume_carried()); - std::string volume_capacity = format_volume(g->u.volume_capacity()); + if( cur_area->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ) { + const double weight_carried = convert_weight( g->u.weight_carried() ); + const double weight_capacity = convert_weight( g->u.weight_capacity() ); + std::string volume_carried = format_volume( g->u.volume_carried() ); + std::string volume_capacity = format_volume( g->u.volume_capacity() ); // align right, so calculate formatted head length - const std::string formatted_head = string_format("%.1f/%.1f %s %s/%s %s", - weight_carried, weight_capacity, weight_units(), - volume_carried, - volume_capacity, - volume_units_abbr()); + const std::string formatted_head = string_format( "%.1f/%.1f %s %s/%s %s", + weight_carried, weight_capacity, weight_units(), + volume_carried, + volume_capacity, + volume_units_abbr() ); const int hrightcol = max_width - formatted_head.length(); nc_color color = weight_carried > weight_capacity ? c_red : c_light_green; - mvwprintz(window, point(hrightcol,4), color, "%.1f", weight_carried); - wprintz(window, c_light_gray, "/%.1f %s ", weight_capacity, weight_units()); + mvwprintz( window, point( hrightcol, 4 ), color, "%.1f", weight_carried ); + wprintz( window, c_light_gray, "/%.1f %s ", weight_capacity, weight_units() ); color = g->u.volume_carried().value() > g->u.volume_capacity().value() ? c_red : - c_light_green; - wprintz(window, color, volume_carried); - wprintz(window, c_light_gray, "/%s %s", volume_capacity, volume_units_abbr()); - } - else { //print square's current and total weight + volume + c_light_green; + wprintz( window, color, volume_carried ); + wprintz( window, c_light_gray, "/%s %s", volume_capacity, volume_units_abbr() ); + } else { //print square's current and total weight + volume std::string formatted_head; std::string volume_str; - if (cur_area->info.type == comestible_inv_area_info::AREA_TYPE_MULTI) { - volume_str = string_format("%s", format_volume(volume)); - } - else { - units::volume maxvolume = cur_area->get_max_volume(viewing_cargo); - volume_str = string_format("%s/%s", format_volume(volume), format_volume(maxvolume)); + if( cur_area->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { + volume_str = string_format( "%s", format_volume( volume ) ); + } else { + units::volume maxvolume = cur_area->get_max_volume( viewing_cargo ); + volume_str = string_format( "%s/%s", format_volume( volume ), format_volume( maxvolume ) ); } - formatted_head = string_format("%3.1f %s %s %s", - convert_weight(weight), - weight_units(), - volume_str, - volume_units_abbr()); - mvwprintz(window, point(max_width - formatted_head.length(), 4), norm, formatted_head); + formatted_head = string_format( "%3.1f %s %s %s", + convert_weight( weight ), + weight_units(), + volume_str, + volume_units_abbr() ); + mvwprintz( window, point( max_width - formatted_head.length(), 4 ), norm, formatted_head ); } - const size_t name_startpos = is_compact ? 1 : 4; + const size_t name_startpos = is_compact ? 1 : 4; - mvwprintz(window, point(name_startpos, 5), c_light_gray, get_col_data(COLUMN_NAME).col_name); + mvwprintz( window, point( name_startpos, 5 ), c_light_gray, get_col_data( COLUMN_NAME ).col_name ); int cur_x = max_width; - for (size_t i = columns.size(); i --> 0;) { - const col_data d = get_col_data(columns[i]); - if (d.width <= 0) continue; + for( size_t i = columns.size(); i -- > 0; ) { + const col_data d = get_col_data( columns[i] ); + if( d.width <= 0 ) { + continue; + } cur_x -= d.width; - mvwprintz(window, point(cur_x, 5), c_light_gray, "%*s", d.width, d.col_name); + mvwprintz( window, point( cur_x, 5 ), c_light_gray, "%*s", d.width, d.col_name ); } - for (int i = page * itemsPerPage, cur_print_y = 6; i < static_cast(items.size()) && - cur_print_y < itemsPerPage + 6; i++, cur_print_y++) { - comestible_inv_listitem& sitem = items[i]; - if (sitem.is_category_header()) { - mvwprintz(window, point((max_width - utf8_width(sitem.name) - 6) / 2, cur_print_y), c_cyan, "[%s]", - sitem.name); + for( int i = page * itemsPerPage, cur_print_y = 6; i < static_cast( items.size() ) && + cur_print_y < itemsPerPage + 6; i++, cur_print_y++ ) { + comestible_inv_listitem &sitem = items[i]; + if( sitem.is_category_header() ) { + mvwprintz( window, point( ( max_width - utf8_width( sitem.name ) - 6 ) / 2, cur_print_y ), c_cyan, + "[%s]", + sitem.name ); continue; } - if (!sitem.is_item_entry()) { + if( !sitem.is_item_entry() ) { // Empty entry at the bottom of a page. continue; } @@ -278,87 +285,83 @@ void comestible_inventory_pane::print_items() comestible_select_state selected_state; - if (selected) { + if( selected ) { selected_state = inCategoryMode ? SELECTSTATE_CATEGORY : SELECTSTATE_SELECTED; - } - else { + } else { selected_state = SELECTSTATE_NONE; } - sitem.print_columns(columns, selected_state, is_compact, window, max_width, cur_print_y); + sitem.print_columns( columns, selected_state, is_compact, window, max_width, cur_print_y ); } } -void comestible_inventory_pane::skip_category_headers(int offset) +void comestible_inventory_pane::skip_category_headers( int offset ) { - assert(offset != 0); // 0 would make no sense - assert(static_cast(index) < items.size()); // valid index is required - assert(offset == -1 || offset == +1); // only those two offsets are allowed - assert(!items.empty()); // index would not be valid, and this would be an endless loop - while (!items[index].is_item_entry()) { - mod_index(offset); + assert( offset != 0 ); // 0 would make no sense + assert( static_cast( index ) < items.size() ); // valid index is required + assert( offset == -1 || offset == +1 ); // only those two offsets are allowed + assert( !items.empty() ); // index would not be valid, and this would be an endless loop + while( !items[index].is_item_entry() ) { + mod_index( offset ); } } -void comestible_inventory_pane::mod_index(int offset) +void comestible_inventory_pane::mod_index( int offset ) { - assert(offset != 0); // 0 would make no sense - assert(!items.empty()); + assert( offset != 0 ); // 0 would make no sense + assert( !items.empty() ); index += offset; - if (index < 0) { - index = static_cast(items.size()) - 1; - } - else if (static_cast(index) >= items.size()) { + if( index < 0 ) { + index = static_cast( items.size() ) - 1; + } else if( static_cast( index ) >= items.size() ) { index = 0; } } -void comestible_inventory_pane::scroll_by(int offset) +void comestible_inventory_pane::scroll_by( int offset ) { - assert(offset != 0); // 0 would make no sense - if (items.empty()) { + assert( offset != 0 ); // 0 would make no sense + if( items.empty() ) { return; } - if (inCategoryMode) { - assert(get_cur_item_ptr() != nullptr); // index must already be valid! + if( inCategoryMode ) { + assert( get_cur_item_ptr() != nullptr ); // index must already be valid! auto cur_cat = items[index].cat; - if (offset > 0) { - while (items[index].cat == cur_cat) { + if( offset > 0 ) { + while( items[index].cat == cur_cat ) { index++; - if (static_cast(index) >= items.size()) { + if( static_cast( index ) >= items.size() ) { index = 0; // wrap to begin, stop there. break; } } - } - else { - while (items[index].cat == cur_cat) { + } else { + while( items[index].cat == cur_cat ) { index--; - if (index < 0) { - index = static_cast(items.size()) - 1; // wrap to end, stop there. + if( index < 0 ) { + index = static_cast( items.size() ) - 1; // wrap to end, stop there. break; } } } - } - else { - mod_index(offset); + } else { + mod_index( offset ); } // Make sure we land on an item entry. - skip_category_headers(offset > 0 ? +1 : -1); + skip_category_headers( offset > 0 ? +1 : -1 ); needs_redraw = true; } -comestible_inv_listitem* comestible_inventory_pane::get_cur_item_ptr() +comestible_inv_listitem *comestible_inventory_pane::get_cur_item_ptr() { - if (static_cast(index) >= items.size()) { + if( static_cast( index ) >= items.size() ) { return nullptr; } return &items[index]; } -void comestible_inventory_pane::set_filter(const std::string& new_filter) +void comestible_inventory_pane::set_filter( const std::string &new_filter ) { - if (filter == new_filter) { + if( filter == new_filter ) { return; } filter = new_filter; @@ -366,30 +369,30 @@ void comestible_inventory_pane::set_filter(const std::string& new_filter) needs_recalc = true; } -bool comestible_inventory_pane::is_filtered(const comestible_inv_listitem& it) const +bool comestible_inventory_pane::is_filtered( const comestible_inv_listitem &it ) const { - return is_filtered(*it.items.front()); + return is_filtered( *it.items.front() ); } -bool comestible_inventory_pane::is_filtered(const item& it) const +bool comestible_inventory_pane::is_filtered( const item &it ) const { - if (special_filter(it)) { + if( special_filter( it ) ) { return true; } - if (filter.empty()) { + if( filter.empty() ) { return false; } const std::string str = it.tname(); - if (filtercache.find(str) == filtercache.end()) { - const auto filter_fn = item_filter_from_string(filter); + if( filtercache.find( str ) == filtercache.end() ) { + const auto filter_fn = item_filter_from_string( filter ); filtercache[str] = filter_fn; - return !filter_fn(it); + return !filter_fn( it ); } - return !filtercache[str](it); + return !filtercache[str]( it ); } void comestible_inventory_pane::paginate() @@ -398,18 +401,18 @@ void comestible_inventory_pane::paginate() return; // not needed as there are no category entries here. } // first, we insert all the items, then we sort the result - for (size_t i = 0; i < items.size(); ++i) { - if (i % itemsPerPage == 0) { + for( size_t i = 0; i < items.size(); ++i ) { + if( i % itemsPerPage == 0 ) { // first entry on the page, should be a category header - if (items[i].is_item_entry()) { - items.insert(items.begin() + i, comestible_inv_listitem(items[i].cat)); + if( items[i].is_item_entry() ) { + items.insert( items.begin() + i, comestible_inv_listitem( items[i].cat ) ); } } - if ((i + 1) % itemsPerPage == 0 && i + 1 < items.size()) { + if( ( i + 1 ) % itemsPerPage == 0 && i + 1 < items.size() ) { // last entry of the page, but not the last entry at all! // Must *not* be a category header! - if (items[i].is_category_header()) { - items.insert(items.begin() + i, comestible_inv_listitem()); + if( items[i].is_category_header() ) { + items.insert( items.begin() + i, comestible_inv_listitem() ); } } } @@ -417,128 +420,124 @@ void comestible_inventory_pane::paginate() void comestible_inventory_pane::fix_index() { - if (items.empty()) { + if( items.empty() ) { index = 0; return; } - if (index < 0) { + if( index < 0 ) { index = 0; + } else if( static_cast( index ) >= items.size() ) { + index = static_cast( items.size() ) - 1; } - else if (static_cast(index) >= items.size()) { - index = static_cast(items.size()) - 1; - } - skip_category_headers(+1); + skip_category_headers( +1 ); } struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { - bool operator()(char x, char y) const { - return toupper(static_cast(x)) < toupper(static_cast(y)); + bool operator()( char x, char y ) const { + return toupper( static_cast( x ) ) < toupper( static_cast( y ) ); } }; struct comestible_inv_sorter { comestible_inv_columns sortby; comestible_inv_columns default_sortby; - comestible_inv_sorter(comestible_inv_columns sort, comestible_inv_columns default_sort) { + comestible_inv_sorter( comestible_inv_columns sort, comestible_inv_columns default_sort ) { sortby = sort; default_sortby = default_sort; } - bool operator()(const comestible_inv_listitem& d1, const comestible_inv_listitem& d2) { - return compare(sortby, d1, d2); - } + bool operator()( const comestible_inv_listitem &d1, const comestible_inv_listitem &d2 ) { + return compare( sortby, d1, d2 ); + } + + bool compare( comestible_inv_columns compare_by, const comestible_inv_listitem &d1, + const comestible_inv_listitem &d2 ) { + switch( compare_by ) { + case COLUMN_NAME: + const std::string *n1; + const std::string *n2; + if( d1.name_without_prefix == d2.name_without_prefix ) { + if( d1.name == d2.name ) { + //fall through + break; + } else { + //if names without prefix equal, compare full name + n1 = &d1.name; + n2 = &d2.name; + } + } else { + //else compare name without prefix + n1 = &d1.name_without_prefix; + n2 = &d2.name_without_prefix; + } - bool compare(comestible_inv_columns compare_by, const comestible_inv_listitem& d1, const comestible_inv_listitem& d2) { - switch (compare_by) { - case COLUMN_NAME: - const std::string* n1; - const std::string* n2; - if (d1.name_without_prefix == d2.name_without_prefix) { - if (d1.name == d2.name) { - //fall through - break; + return std::lexicographical_compare( n1->begin(), n1->end(), n2->begin(), n2->end(), + sort_case_insensitive_less() ); + break; + case COLUMN_WEIGHT: + if( d1.weight != d2.weight ) { + return d1.weight > d2.weight; } - else { - //if names without prefix equal, compare full name - n1 = &d1.name; - n2 = &d2.name; + break; + case COLUMN_VOLUME: + if( d1.volume != d2.volume ) { + return d1.volume > d2.volume; } - } - else { - //else compare name without prefix - n1 = &d1.name_without_prefix; - n2 = &d2.name_without_prefix; - } - - return std::lexicographical_compare(n1->begin(), n1->end(), n2->begin(), n2->end(), - sort_case_insensitive_less()); - break; - case COLUMN_WEIGHT: - if (d1.weight != d2.weight) { - return d1.weight > d2.weight; - } - break; - case COLUMN_VOLUME: - if (d1.volume != d2.volume) { - return d1.volume > d2.volume; - } - break; - case COLUMN_CALORIES: - if (d1.calories != d2.calories) { - return d1.calories > d2.calories; - } - break; - case COLUMN_QUENCH: - if (d1.quench != d2.quench) { - return d1.quench > d2.quench; - } - break; - case COLUMN_JOY: - if (d1.joy != d2.joy) { - return d1.joy > d2.joy; - } - break; - case COLUMN_ENERGY: - if (d1.energy != d2.energy) { - return d1.energy > d2.energy; - } - break; - case COLUMN_EXPIRES: - case COLUMN_SHELF_LIFE: - if (d1.items.front()->spoilage_sort_order() != d2.items.front()->spoilage_sort_order()) { - return d1.items.front()->spoilage_sort_order() < d2.items.front()->spoilage_sort_order(); - } - break; - case COLUMN_SORTBY_CATEGORY: - assert(d1.cat != nullptr); - assert(d2.cat != nullptr); - if (d1.cat != d2.cat) { - return *d1.cat < *d2.cat; - } - else if (d1.is_category_header()) { - return true; - } - else if (d2.is_category_header()) { - return false; - } - break; - case COLUMN_SRC: - case COLUMN_AMOUNT: - case COLUMN_NUM_ENTRIES: - //shouldn't be here - assert(false); - break; + break; + case COLUMN_CALORIES: + if( d1.calories != d2.calories ) { + return d1.calories > d2.calories; + } + break; + case COLUMN_QUENCH: + if( d1.quench != d2.quench ) { + return d1.quench > d2.quench; + } + break; + case COLUMN_JOY: + if( d1.joy != d2.joy ) { + return d1.joy > d2.joy; + } + break; + case COLUMN_ENERGY: + if( d1.energy != d2.energy ) { + return d1.energy > d2.energy; + } + break; + case COLUMN_EXPIRES: + case COLUMN_SHELF_LIFE: + if( d1.items.front()->spoilage_sort_order() != d2.items.front()->spoilage_sort_order() ) { + return d1.items.front()->spoilage_sort_order() < d2.items.front()->spoilage_sort_order(); + } + break; + case COLUMN_SORTBY_CATEGORY: + assert( d1.cat != nullptr ); + assert( d2.cat != nullptr ); + if( d1.cat != d2.cat ) { + return *d1.cat < *d2.cat; + } else if( d1.is_category_header() ) { + return true; + } else if( d2.is_category_header() ) { + return false; + } + break; + case COLUMN_SRC: + case COLUMN_AMOUNT: + case COLUMN_NUM_ENTRIES: + //shouldn't be here + assert( false ); + break; } - if (compare_by == default_sortby) { - return false; - } - else { - return compare(default_sortby, d1, d2); + if( compare_by == default_sortby ) { + return false; + } else { + return compare( default_sortby, d1, d2 ); } } }; -void comestible_inventory_pane::recalc() { +void comestible_inventory_pane::recalc() +{ needs_recalc = false; items.clear(); // Add items from the source location or in case of all 9 surrounding squares, @@ -546,50 +545,49 @@ void comestible_inventory_pane::recalc() { units::volume tmp_vol; units::mass tmp_weight; - if (cur_area->info.type == comestible_inv_area_info::AREA_TYPE_MULTI) { + if( cur_area->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { volume = 0_ml; weight = 0_gram; std::vector loc = cur_area->info.multi_locations; - for (size_t i = 0; i < loc.size(); i++) { - comestible_inv_area* s = &((*squares)[loc[i]]); + for( size_t i = 0; i < loc.size(); i++ ) { + comestible_inv_area *s = &( ( *squares )[loc[i]] ); // Deal with squares with ground + vehicle storage // Also handle the case when the other tile covers vehicle // or the ground below the vehicle. - if (s->has_vehicle()) { - add_items_from_area(s, true, tmp_vol, tmp_weight); + if( s->has_vehicle() ) { + add_items_from_area( s, true, tmp_vol, tmp_weight ); volume += tmp_vol; weight += tmp_weight; } // Add map items - add_items_from_area(s, false, tmp_vol, tmp_weight); + add_items_from_area( s, false, tmp_vol, tmp_weight ); volume += tmp_vol; weight += tmp_weight; } - } - else { - add_items_from_area(cur_area, viewing_cargo, volume, weight); + } else { + add_items_from_area( cur_area, viewing_cargo, volume, weight ); } // Insert category headers (only expected when sorting by category) - if (sortby == COLUMN_SORTBY_CATEGORY) { - std::set categories; - for (auto& it : items) { - categories.insert(it.cat); + if( sortby == COLUMN_SORTBY_CATEGORY ) { + std::set categories; + for( auto &it : items ) { + categories.insert( it.cat ); } - for (auto& cat : categories) { - items.push_back(comestible_inv_listitem(cat)); + for( auto &cat : categories ) { + items.push_back( comestible_inv_listitem( cat ) ); } } - + // Finally sort all items (category headers will now be moved to their proper position) - std::stable_sort(items.begin(), items.end(), comestible_inv_sorter(sortby, default_sortby)); + std::stable_sort( items.begin(), items.end(), comestible_inv_sorter( sortby, default_sortby ) ); paginate(); int i = 0; - for (auto& it : items) { - if (it.items.front() == uistate.comestible_save.selected_itm) { + for( auto &it : items ) { + if( it.items.front() == uistate.comestible_save.selected_itm ) { uistate.comestible_save.selected_idx = i; index = i; break; @@ -599,13 +597,14 @@ void comestible_inventory_pane::recalc() { } //TODO: I want to move functionality to comestible_inv_area, but I dunno how to convert AIM_INVENTORY, AIM_WORN and other to the same type. -void comestible_inventory_pane::add_items_from_area(comestible_inv_area* area, bool from_cargo, units::volume& ret_volume, units::mass& ret_weight) +void comestible_inventory_pane::add_items_from_area( comestible_inv_area *area, bool from_cargo, + units::volume &ret_volume, units::mass &ret_weight ) { - assert(area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI); - if (!area->canputitems()) { + assert( area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI ); + if( !area->canputitems() ) { return; } - player& u = g->u; + player &u = g->u; ret_volume = 0_ml; ret_weight = 0_gram; @@ -614,45 +613,43 @@ void comestible_inventory_pane::add_items_from_area(comestible_inv_area* area, b units::mass tmp_weight; // Existing items are *not* cleared on purpose, this might be called // several times in case all surrounding squares are to be shown. - if (area->info.id == comestible_inv_area_info::AIM_INVENTORY) { - const invslice& stacks = u.inv.slice(); - for (size_t x = 0; x < stacks.size(); ++x) { - std::list item_pointers; - for (item& i : *stacks[x]) { - item_pointers.push_back(&i); + if( area->info.id == comestible_inv_area_info::AIM_INVENTORY ) { + const invslice &stacks = u.inv.slice(); + for( size_t x = 0; x < stacks.size(); ++x ) { + std::list item_pointers; + for( item &i : *stacks[x] ) { + item_pointers.push_back( &i ); } - comestible_inv_listitem it(item_pointers, x, area, false); - if (is_filtered(*it.items.front())) { + comestible_inv_listitem it( item_pointers, x, area, false ); + if( is_filtered( *it.items.front() ) ) { continue; } ret_volume += it.volume; ret_weight += it.weight; - items.push_back(it); + items.push_back( it ); } - } - else if (area->info.id == comestible_inv_area_info::AIM_WORN) { + } else if( area->info.id == comestible_inv_area_info::AIM_WORN ) { auto iter = u.worn.begin(); - for (size_t i = 0; i < u.worn.size(); ++i, ++iter) { - comestible_inv_listitem it(&*iter, i, 1, area, false); - if (is_filtered(*it.items.front())) { + for( size_t i = 0; i < u.worn.size(); ++i, ++iter ) { + comestible_inv_listitem it( &*iter, i, 1, area, false ); + if( is_filtered( *it.items.front() ) ) { continue; } ret_volume += it.volume; ret_weight += it.weight; - items.push_back(it); + items.push_back( it ); } - } - else { - const comestible_inv_area::area_items stacks = area->get_items(from_cargo); + } else { + const comestible_inv_area::area_items stacks = area->get_items( from_cargo ); - for (size_t x = 0; x < stacks.size(); ++x) { - comestible_inv_listitem it(stacks[x], x, area, from_cargo); - if (is_filtered(*it.items.front())) { + for( size_t x = 0; x < stacks.size(); ++x ) { + comestible_inv_listitem it( stacks[x], x, area, from_cargo ); + if( is_filtered( *it.items.front() ) ) { continue; } ret_volume += it.volume; ret_weight += it.weight; - items.push_back(it); + items.push_back( it ); } } } @@ -660,10 +657,9 @@ void comestible_inventory_pane::add_items_from_area(comestible_inv_area* area, b void comestible_inventory_pane::redraw() { // don't update ui if processing demands - if (needs_recalc) { + if( needs_recalc ) { recalc(); - } - else if (!needs_redraw) { + } else if( !needs_redraw ) { return; } needs_redraw = false; @@ -671,98 +667,101 @@ void comestible_inventory_pane::redraw() auto w = window; - werase(w); + werase( w ); print_items(); auto itm = get_cur_item_ptr(); - int width = print_header(itm != nullptr ? itm->area : get_area()); - bool same_as_dragged = (cur_area->info.id >= comestible_inv_area_info::AIM_SOUTHWEST && cur_area->info.id <= comestible_inv_area_info::AIM_NORTHEAST) && - // only cardinals - cur_area->info.id != comestible_inv_area_info::AIM_CENTER && is_in_vehicle() && // not where you stand, and pane is in vehicle - cur_area->info.default_offset == get_square(comestible_inv_area_info::AIM_DRAGGED)->info.default_offset; // make sure the offsets are the same as the grab point - const comestible_inv_area* sq = same_as_dragged ? get_square(comestible_inv_area_info::AIM_DRAGGED) : cur_area; - - - bool car = cur_area->has_vehicle() && is_in_vehicle() && sq->info.id != comestible_inv_area_info::AIM_DRAGGED; - auto name = utf8_truncate(sq->get_name(viewing_cargo), width); - auto desc = utf8_truncate(sq->desc[car], width); + int width = print_header( itm != nullptr ? itm->area : get_area() ); + bool same_as_dragged = ( cur_area->info.id >= comestible_inv_area_info::AIM_SOUTHWEST && + cur_area->info.id <= comestible_inv_area_info::AIM_NORTHEAST ) && + // only cardinals + cur_area->info.id != comestible_inv_area_info::AIM_CENTER && is_in_vehicle() && + // not where you stand, and pane is in vehicle + cur_area->info.default_offset == get_square( + comestible_inv_area_info::AIM_DRAGGED )->info.default_offset; // make sure the offsets are the same as the grab point + const comestible_inv_area *sq = same_as_dragged ? get_square( + comestible_inv_area_info::AIM_DRAGGED ) : cur_area; + + + bool car = cur_area->has_vehicle() && is_in_vehicle() && + sq->info.id != comestible_inv_area_info::AIM_DRAGGED; + auto name = utf8_truncate( sq->get_name( viewing_cargo ), width ); + auto desc = utf8_truncate( sq->desc[car], width ); width -= 2 + 1; // starts at offset 2, plus space between the header and the text - mvwprintz(w, point(2, 1), c_green, name); - mvwprintz(w, point(2, 2), c_light_blue, desc); - trim_and_print(w, point(2, 3), width, c_cyan, cur_area->flags); + mvwprintz( w, point( 2, 1 ), c_green, name ); + mvwprintz( w, point( 2, 2 ), c_light_blue, desc ); + trim_and_print( w, point( 2, 3 ), width, c_cyan, cur_area->flags ); - if (!is_compact) { - for (size_t i = 0; i < legend.size(); i++) - { + if( !is_compact ) { + for( size_t i = 0; i < legend.size(); i++ ) { legend_data l = legend[i]; - mvwprintz(window, point(25, i + 1), c_light_gray, "[%c] ", l.shortcut); - wprintz(window, l.color, "%s", l.message); + mvwprintz( window, point( 25, i + 1 ), c_light_gray, "[%c] ", l.shortcut ); + wprintz( window, l.color, "%s", l.message ); } } - const int max_page = (items.size() + itemsPerPage - 1) / itemsPerPage; - if (max_page > 1) { + const int max_page = ( items.size() + itemsPerPage - 1 ) / itemsPerPage; + if( max_page > 1 ) { const int page = index / itemsPerPage; - mvwprintz(w, point(2, 4), c_light_blue, _("[<] page %d of %d [>]"), page + 1, max_page); + mvwprintz( w, point( 2, 4 ), c_light_blue, _( "[<] page %d of %d [>]" ), page + 1, max_page ); } - wattron(w, c_cyan); + wattron( w, c_cyan ); // draw a darker border around the inactive pane - draw_border(w, BORDER_COLOR); - mvwprintw(w, point(3, 0), _("< [s]ort: %s >"), get_col_data(sortby).sort_name); + draw_border( w, BORDER_COLOR ); + mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), get_col_data( sortby ).sort_name ); - if (title.size() != 0) { - std::string title_string = string_format("<< %s >>", title); - mvwprintz(w, point((getmaxx(w) - title_string.size())/2, 0), c_light_cyan, title_string); + if( title.size() != 0 ) { + std::string title_string = string_format( "<< %s >>", title ); + mvwprintz( w, point( ( getmaxx( w ) - title_string.size() ) / 2, 0 ), c_light_cyan, title_string ); } - const char* fprefix = _("[F]ilter"); - const char* fsuffix = _("[R]eset"); + const char *fprefix = _( "[F]ilter" ); + const char *fsuffix = _( "[R]eset" ); //TODO:XXX //bool filter_edit = true; - if (!filter_edit) { - if (!filter.empty()) { - mvwprintw(w, point(2, getmaxy(w) - 1), "< %s: %s >", fprefix, filter); - } - else { - mvwprintw(w, point(2, getmaxy(w) - 1), "< %s >", fprefix); + if( !filter_edit ) { + if( !filter.empty() ) { + mvwprintw( w, point( 2, getmaxy( w ) - 1 ), "< %s: %s >", fprefix, filter ); + } else { + mvwprintw( w, point( 2, getmaxy( w ) - 1 ), "< %s >", fprefix ); } } - wattroff(w, c_white); + wattroff( w, c_white ); - if (!filter_edit && !filter.empty()) { - mvwprintz(w, point(6 + std::strlen(fprefix), getmaxy(w) - 1), c_white, - filter); - mvwprintz(w, point(getmaxx(w) - std::strlen(fsuffix) - 2, getmaxy(w) - 1), c_white, "%s", - fsuffix); + if( !filter_edit && !filter.empty() ) { + mvwprintz( w, point( 6 + std::strlen( fprefix ), getmaxy( w ) - 1 ), c_white, + filter ); + mvwprintz( w, point( getmaxx( w ) - std::strlen( fsuffix ) - 2, getmaxy( w ) - 1 ), c_white, "%s", + fsuffix ); } - wrefresh(w); + wrefresh( w ); } -int comestible_inventory_pane::print_header(comestible_inv_area* sel_area) +int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) { - int wwidth = getmaxx(window); + int wwidth = getmaxx( window ); int ofs = wwidth - 25 - 2 - 14; - for (size_t i = 0; i < squares->size(); ++i) { - std::string key = comestible_inv_area::get_info(static_cast(i)).minimapname; + for( size_t i = 0; i < squares->size(); ++i ) { + std::string key = comestible_inv_area::get_info( + static_cast( i ) ).minimapname; - comestible_inv_area* iter_square = get_square(i); + comestible_inv_area *iter_square = get_square( i ); - const char* bracket = iter_square->has_vehicle() ? "<>" : "[]"; + const char *bracket = iter_square->has_vehicle() ? "<>" : "[]"; bool is_single = cur_area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI; - bool is_selected_by_user = cur_area->info.has_area(get_square(i)->info.id); + bool is_selected_by_user = cur_area->info.has_area( get_square( i )->info.id ); bool is_selected_by_item; - if (is_single) { + if( is_single ) { is_selected_by_item = is_selected_by_user; - } - else { - is_selected_by_item = get_square(i)->info.id == sel_area->info.id; + } else { + is_selected_by_item = get_square( i )->info.id == sel_area->info.id; } //bool is_selected = get_square(i)->info.has_area(sel_area->info.id); @@ -778,450 +777,449 @@ int comestible_inventory_pane::print_header(comestible_inv_area* sel_area) //bool all_brackets = area == comestible_inv_area_info::AIM_ALL && (i >= comestible_inv_area_info::AIM_SOUTHWEST && i <= comestible_inv_area_info::AIM_NORTHEAST); nc_color bcolor = c_red; nc_color kcolor = c_red; - if (get_square(i)->canputitems()) { - if (is_single) { - if (is_selected_by_item) { - if (viewing_cargo) { + if( get_square( i )->canputitems() ) { + if( is_single ) { + if( is_selected_by_item ) { + if( viewing_cargo ) { bcolor = c_light_blue; - } - else { + } else { bcolor = c_light_gray; } kcolor = c_white; - } - else { + } else { bcolor = kcolor = c_dark_gray; } - } - else { - if (cur_area->info.id == get_square(i)->info.id) { + } else { + if( cur_area->info.id == get_square( i )->info.id ) { bcolor = c_light_gray; kcolor = c_white; - } - else { - if (is_selected_by_user) { + } else { + if( is_selected_by_user ) { bcolor = c_light_gray; - } - else { + } else { bcolor = c_dark_gray; } - if (is_selected_by_item) { + if( is_selected_by_item ) { kcolor = c_light_gray; - } - else { + } else { kcolor = c_dark_gray; } } } - /* if (is_selected) { - if (is_single) { - if (viewing_cargo) { - bcolor = c_light_gray; - } - kcolor = c_white; - } - else { - bcolor = c_light_gray; - kcolor = c_light_gray; - } - } - else { - bcolor = kcolor = c_dark_gray; - }*/ + /* if (is_selected) { + if (is_single) { + if (viewing_cargo) { + bcolor = c_light_gray; + } + kcolor = c_white; + } + else { + bcolor = c_light_gray; + kcolor = c_light_gray; + } + } + else { + bcolor = kcolor = c_dark_gray; + }*/ //bcolor = in_vehicle ? c_light_blue : // area == i || all_brackets ? c_light_gray : c_dark_gray; //kcolor = area == i ? c_white : sel == i ? c_light_gray : c_dark_gray; } - - const int x = get_square(i)->info.hscreen.x + ofs; - const int y = get_square(i)->info.hscreen.y; - mvwprintz(window, point(x, y), bcolor, "%c", bracket[0]); - wprintz(window, kcolor, "%s", viewing_cargo && is_selected_by_item && is_single && cur_area->info.id != comestible_inv_area_info::AIM_DRAGGED ? "V" : key); - wprintz(window, bcolor, "%c", bracket[1]); + + const int x = get_square( i )->info.hscreen.x + ofs; + const int y = get_square( i )->info.hscreen.y; + mvwprintz( window, point( x, y ), bcolor, "%c", bracket[0] ); + wprintz( window, kcolor, "%s", viewing_cargo && is_selected_by_item && is_single && + cur_area->info.id != comestible_inv_area_info::AIM_DRAGGED ? "V" : key ); + wprintz( window, bcolor, "%c", bracket[1] ); } - return get_square(comestible_inv_area_info::AIM_INVENTORY)->info.hscreen.y + ofs; + return get_square( comestible_inv_area_info::AIM_INVENTORY )->info.hscreen.y + ofs; } -void comestible_inv_listitem::print_columns(std::vector columns, comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, int cur_print_y) { - +void comestible_inv_listitem::print_columns( std::vector columns, + comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, + int cur_print_y ) +{ + is_selected = selected_state; int w; - for (std::vector::reverse_iterator col_iter = columns.rbegin(); col_iter != columns.rend(); ++col_iter) { - w = get_col_data(*col_iter).width; - if (w <= 0) continue; + for( std::vector::reverse_iterator col_iter = columns.rbegin(); + col_iter != columns.rend(); ++col_iter ) { + w = get_col_data( *col_iter ).width; + if( w <= 0 ) { + continue; + } right_bound -= w; - if (print_string_column(*col_iter, window, right_bound, cur_print_y)) { + if( print_string_column( *col_iter, window, right_bound, cur_print_y ) ) { continue; } - if (print_int_column(*col_iter, window, right_bound, cur_print_y)) { + if( print_int_column( *col_iter, window, right_bound, cur_print_y ) ) { continue; } - if (print_default_columns(*col_iter, window, right_bound, cur_print_y)) { + if( print_default_columns( *col_iter, window, right_bound, cur_print_y ) ) { continue; } //TODO: error } - print_name(is_compact, window, right_bound, cur_print_y); + print_name( is_compact, window, right_bound, cur_print_y ); } -bool comestible_inv_listitem::print_string_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y) { +bool comestible_inv_listitem::print_string_column( comestible_inv_columns col, + catacurses::window window, int cur_print_x, int cur_print_y ) +{ std::string print_string; - switch (col) - { - case COLUMN_SHELF_LIFE: - print_string = shelf_life; - break; - case COLUMN_EXPIRES: - print_string = exipres_in; - break; - default: - return false; + switch( col ) { + case COLUMN_SHELF_LIFE: + print_string = shelf_life; + break; + case COLUMN_EXPIRES: + print_string = exipres_in; + break; + default: + return false; } nc_color print_color; - set_print_color(print_color, c_cyan); - mvwprintz(window, point(cur_print_x, cur_print_y), print_color, "%*s", get_col_data(col).width, print_string); + set_print_color( print_color, c_cyan ); + mvwprintz( window, point( cur_print_x, cur_print_y ), print_color, "%*s", get_col_data( col ).width, + print_string ); return true; } -bool comestible_inv_listitem::print_int_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y) { +bool comestible_inv_listitem::print_int_column( comestible_inv_columns col, + catacurses::window window, int cur_print_x, int cur_print_y ) +{ int print_val; bool need_highlight = false; - switch (col) - { - case COLUMN_CALORIES: - print_val = calories; - break; - case COLUMN_QUENCH: - print_val = quench; - break; - case COLUMN_JOY: - print_val = joy; - need_highlight = is_mushy; - break; - case COLUMN_ENERGY: - print_val = energy; - break; - default: - return false; - break; + switch( col ) { + case COLUMN_CALORIES: + print_val = calories; + break; + case COLUMN_QUENCH: + print_val = quench; + break; + case COLUMN_JOY: + print_val = joy; + need_highlight = is_mushy; + break; + case COLUMN_ENERGY: + print_val = energy; + break; + default: + return false; + break; } nc_color print_color; - char const* print_format = set_string_params(print_color, print_val, need_highlight); - std::string s = string_format(print_format, print_val); - mvwprintz(window, point(cur_print_x, cur_print_y), print_color, "%*s", get_col_data(col).width, s); + char const *print_format = set_string_params( print_color, print_val, need_highlight ); + std::string s = string_format( print_format, print_val ); + mvwprintz( window, point( cur_print_x, cur_print_y ), print_color, "%*s", get_col_data( col ).width, + s ); return true; } -char const* comestible_inv_listitem::set_string_params(nc_color& print_color, int value, - bool need_highlight) +char const *comestible_inv_listitem::set_string_params( nc_color &print_color, int value, + bool need_highlight ) { - char const* string_format; - if (value > 0) { + char const *string_format; + if( value > 0 ) { print_color = need_highlight ? c_yellow_green : c_green; string_format = "+%d"; - } - else if (value < 0) { + } else if( value < 0 ) { print_color = need_highlight ? c_yellow_red : c_red; string_format = "%d"; - } - else { + } else { print_color = need_highlight ? c_yellow : c_dark_gray; string_format = ""; } - set_print_color(print_color, print_color); + set_print_color( print_color, print_color ); return string_format; } -void comestible_inv_listitem::set_print_color(nc_color& retval, nc_color default_col) { - switch (is_selected) - { - case SELECTSTATE_NONE: - retval = default_col; - break; - case SELECTSTATE_SELECTED: - retval = hilite(c_white); - break; - case SELECTSTATE_CATEGORY: - retval = c_white_red; - break; - default: - break; +void comestible_inv_listitem::set_print_color( nc_color &retval, nc_color default_col ) +{ + switch( is_selected ) { + case SELECTSTATE_NONE: + retval = default_col; + break; + case SELECTSTATE_SELECTED: + retval = hilite( c_white ); + break; + case SELECTSTATE_CATEGORY: + retval = c_white_red; + break; + default: + break; } } -bool comestible_inv_listitem::print_default_columns(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y) { +bool comestible_inv_listitem::print_default_columns( comestible_inv_columns col, + catacurses::window window, int cur_print_x, int cur_print_y ) +{ nc_color print_color; std::string s; - switch (col) - { - case COLUMN_VOLUME: { - bool it_vol_truncated = false; - double it_vol_value = 0.0; - s = format_volume(volume, 5, &it_vol_truncated, &it_vol_value); - if (it_vol_truncated && it_vol_value > 0.0) { - print_color = c_red; - } - else { - print_color = volume.value() > 0 ? menu_color : menu_color_dark; + switch( col ) { + case COLUMN_VOLUME: { + bool it_vol_truncated = false; + double it_vol_value = 0.0; + s = format_volume( volume, 5, &it_vol_truncated, &it_vol_value ); + if( it_vol_truncated && it_vol_value > 0.0 ) { + print_color = c_red; + } else { + print_color = volume.value() > 0 ? menu_color : menu_color_dark; + } + break; } - break; } - case COLUMN_WEIGHT: { - double it_weight = convert_weight(weight); - size_t w_precision; - print_color = it_weight > 0 ? menu_color : menu_color_dark; + case COLUMN_WEIGHT: { + double it_weight = convert_weight( weight ); + size_t w_precision; + print_color = it_weight > 0 ? menu_color : menu_color_dark; - if (it_weight >= 1000.0) { - if (it_weight >= 10000.0) { - print_color = c_red; - it_weight = 9999.0; + if( it_weight >= 1000.0 ) { + if( it_weight >= 10000.0 ) { + print_color = c_red; + it_weight = 9999.0; + } + w_precision = 0; + } else if( it_weight >= 100.0 ) { + w_precision = 1; + } else { + w_precision = 2; } - w_precision = 0; - } - else if (it_weight >= 100.0) { - w_precision = 1; - } - else { - w_precision = 2; + s = string_format( "%5.*f", w_precision, it_weight ); + break; } - s = string_format("%5.*f", w_precision, it_weight); - break; - } - case COLUMN_AMOUNT: { - if (stacks > 1) { - print_color = menu_color; - if (stacks > 9999) { - stacks = 9999; - print_color = c_red; + case COLUMN_AMOUNT: { + if( stacks > 1 ) { + print_color = menu_color; + if( stacks > 9999 ) { + stacks = 9999; + print_color = c_red; + } + s = string_format( "%4d", stacks ); + } else { + s = ""; } - s = string_format("%4d", stacks); - } - else { - s = ""; + break; } - break; - } - case COLUMN_SRC: - print_color = menu_color; - s = area->info.shortname; - break; + case COLUMN_SRC: + print_color = menu_color; + s = area->info.shortname; + break; - default: - return false; - break; + default: + return false; + break; } - set_print_color(print_color, print_color); - mvwprintz(window, point(cur_print_x, cur_print_y), print_color, "%*s", get_col_data(col).width, s); + set_print_color( print_color, print_color ); + mvwprintz( window, point( cur_print_x, cur_print_y ), print_color, "%*s", get_col_data( col ).width, + s ); return true; } -void comestible_inv_listitem::print_name(bool is_compact, catacurses::window window, int right_bound, int cur_print_y) { +void comestible_inv_listitem::print_name( bool is_compact, catacurses::window window, + int right_bound, int cur_print_y ) +{ std::string item_name; - item* it = items.front(); - if (it->is_money()) { + item *it = items.front(); + if( it->is_money() ) { //Count charges // TODO: transition to the item_location system used for the normal inventory unsigned int charges_total = 0; - for (const auto item : items) { + for( const auto item : items ) { charges_total += item->charges; } - item_name = it->display_money(items.size(), charges_total); - } - else { + item_name = it->display_money( items.size(), charges_total ); + } else { item_name = it->display_name(); } //check stolen - if (it->has_owner()) { - const faction* item_fac = it->get_owner(); - if (item_fac != g->faction_manager_ptr->get(faction_id("your_followers"))) { - item_name = string_format("%s %s", "!", item_name); + if( it->has_owner() ) { + const faction *item_fac = it->get_owner(); + if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { + item_name = string_format( "%s %s", "!", item_name ); } } - if (get_option("ITEM_SYMBOLS")) { - item_name = string_format("%s %s", it->symbol(), item_name); + if( get_option( "ITEM_SYMBOLS" ) ) { + item_name = string_format( "%s %s", it->symbol(), item_name ); } int name_startpos = is_compact ? 1 : 4; int max_name_length = right_bound - name_startpos - 1; nc_color print_color; - set_print_color(print_color, menu_color); + set_print_color( print_color, menu_color ); - if (is_selected) { //fill whole line with color - mvwprintz(window, point(0, cur_print_y), print_color, "%*s", right_bound, ""); + if( is_selected ) { //fill whole line with color + mvwprintz( window, point( 0, cur_print_y ), print_color, "%*s", right_bound, "" ); } - trim_and_print(window, point(name_startpos, cur_print_y), max_name_length, print_color, item_name); + trim_and_print( window, point( name_startpos, cur_print_y ), max_name_length, print_color, + item_name ); - if (autopickup) { - mvwprintz(window, point(name_startpos, cur_print_y), magenta_background(print_color), - is_compact ? item_name.substr(0, 1) : ">"); + if( autopickup ) { + mvwprintz( window, point( name_startpos, cur_print_y ), magenta_background( print_color ), + is_compact ? item_name.substr( 0, 1 ) : ">" ); } } - - - const islot_comestible& comestible_inv_listitem::get_edible_comestible(player& p, - const item& it) const - { - if (it.is_comestible() && p.can_eat(it).success()) { - // Ok since can_eat() returns false if is_craft() is true - return *it.type->comestible; - } - static const islot_comestible dummy{}; - return dummy; - } - std::string comestible_inv_listitem::get_time_left_rounded(player& p, const item& it) const - { - if (it.is_going_bad()) { - return _("soon!"); - } +const islot_comestible &comestible_inv_listitem::get_edible_comestible( player &p, + const item &it ) const +{ + if( it.is_comestible() && p.can_eat( it ).success() ) { + // Ok since can_eat() returns false if is_craft() is true + return *it.type->comestible; + } + static const islot_comestible dummy{}; + return dummy; +} - time_duration time_left = 0_turns; - const time_duration shelf_life = get_edible_comestible(p, it).spoils; - if (shelf_life > 0_turns) { - 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; - } - } - - //const auto make_result = [this](const time_duration& d, const char* verbose_str, - // const char* short_str) { - // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); - //}; +std::string comestible_inv_listitem::get_time_left_rounded( player &p, const item &it ) const +{ + if( it.is_going_bad() ) { + return _( "soon!" ); + } - time_duration divider = 0_turns; - time_duration vicinity = 0_turns; + time_duration time_left = 0_turns; + const time_duration shelf_life = get_edible_comestible( p, it ).spoils; + if( shelf_life > 0_turns ) { + const double relative_rot = it.get_relative_rot(); + time_left = shelf_life - shelf_life * relative_rot; - if (time_left > 1_days) { - divider = 1_days; - vicinity = 2_hours; + // Correct for an estimate that exceeds shelf life -- this happens especially with + // fresh items. + if( time_left > shelf_life ) { + time_left = shelf_life; } - else if (time_left > 1_hours) { - divider = 1_hours; - vicinity = 5_minutes; - } // Minutes and seconds can be estimated precisely. - - if (divider != 0_turns) { - const time_duration remainder = time_left % divider; + } - if (remainder >= divider - vicinity) { - time_left += divider; - } - else if (remainder > vicinity) { - if (remainder < divider / 2) { - //~ %s - time (e.g. 2 hours). - return string_format("%s", time_to_comestible_str(time_left)); - //return string_format("> %s", time_to_comestible_str(time_left)); - } - else { - //~ %s - time (e.g. 2 hours). - return string_format("%s", time_to_comestible_str(time_left)); - //return string_format("< %s", time_to_comestible_str(time_left)); - } + //const auto make_result = [this](const time_duration& d, const char* verbose_str, + // const char* short_str) { + // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); + //}; + + time_duration divider = 0_turns; + time_duration vicinity = 0_turns; + + if( time_left > 1_days ) { + divider = 1_days; + vicinity = 2_hours; + } else if( time_left > 1_hours ) { + divider = 1_hours; + vicinity = 5_minutes; + } // Minutes and seconds can be estimated precisely. + + if( divider != 0_turns ) { + const time_duration remainder = time_left % divider; + + if( remainder >= divider - vicinity ) { + time_left += divider; + } else if( remainder > vicinity ) { + if( remainder < divider / 2 ) { + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("> %s", time_to_comestible_str(time_left)); + } else { + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("< %s", time_to_comestible_str(time_left)); } } - //~ %s - time (e.g. 2 hours). - return string_format("%s", time_to_comestible_str(time_left)); - //return string_format("~ %s", time_to_comestible_str(time_left)); } + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("~ %s", time_to_comestible_str(time_left)); +} - std::string comestible_inv_listitem::time_to_comestible_str(const time_duration& d) const - { - if (d >= calendar::INDEFINITELY_LONG_DURATION) { - return _("forever"); - } - - const float day = to_days(d); - std::string format; - if (day < 1.00) { - format = _("%.2f days"); - } - else if (day > 1.00) { - format = _("%.0f days"); - } - else { - format = _("1 day"); - } +std::string comestible_inv_listitem::time_to_comestible_str( const time_duration &d ) const +{ + if( d >= calendar::INDEFINITELY_LONG_DURATION ) { + return _( "forever" ); + } - return string_format(format, day); + const float day = to_days( d ); + std::string format; + if( day < 1.00 ) { + format = _( "%.2f days" ); + } else if( day > 1.00 ) { + format = _( "%.0f days" ); + } else { + format = _( "1 day" ); } -comestible_inv_listitem::comestible_inv_listitem(item* an_item, int index, int count, - comestible_inv_area* area, bool from_vehicle) - : idx(index) - , area(area) - , id(an_item->typeId()) - , name(an_item->tname(count)) - , name_without_prefix(an_item->tname(1, false)) - , autopickup(get_auto_pickup().has_rule(an_item)) - , stacks(count) - , volume(an_item->volume()* stacks) - , weight(an_item->weight()* stacks) - , cat(&an_item->get_category()) - , from_vehicle(from_vehicle) + return string_format( format, day ); +} + +comestible_inv_listitem::comestible_inv_listitem( item *an_item, int index, int count, + comestible_inv_area *area, bool from_vehicle ) + : idx( index ) + , area( area ) + , id( an_item->typeId() ) + , name( an_item->tname( count ) ) + , name_without_prefix( an_item->tname( 1, false ) ) + , autopickup( get_auto_pickup().has_rule( an_item ) ) + , stacks( count ) + , volume( an_item->volume() * stacks ) + , weight( an_item->weight() * stacks ) + , cat( &an_item->get_category() ) + , from_vehicle( from_vehicle ) { - player& p = g->u; - item it = p.get_consumable_from(*an_item); - islot_comestible it_c = get_edible_comestible(p, it); + player &p = g->u; + item it = p.get_consumable_from( *an_item ); + islot_comestible it_c = get_edible_comestible( p, it ); menu_color = it.color_in_inventory(); exipres_in = ""; shelf_life = ""; - if (it_c.spoils > 0_turns) { - if (!it.rotten()) { - exipres_in = get_time_left_rounded(p, it); + if( it_c.spoils > 0_turns ) { + if( !it.rotten() ) { + exipres_in = get_time_left_rounded( p, it ); } - shelf_life = to_string_clipped(it_c.spoils); + shelf_life = to_string_clipped( it_c.spoils ); } - calories = p.kcal_for(it); + calories = p.kcal_for( it ); quench = it_c.quench; - joy = p.fun_for(it).first; - is_mushy = it.has_flag("MUSHY"); + joy = p.fun_for( it ).first; + is_mushy = it.has_flag( "MUSHY" ); - energy = p.get_acquirable_energy(it); + energy = p.get_acquirable_energy( it ); - items.push_back(an_item); + items.push_back( an_item ); menu_color_dark = c_dark_gray; - assert(stacks >= 1); + assert( stacks >= 1 ); } -comestible_inv_listitem::comestible_inv_listitem(const std::list& list, int index, - comestible_inv_area* area, bool from_vehicle) : - idx(index), - area(area), - id(list.front()->typeId()), - items(list), - name(list.front()->tname(list.size())), - name_without_prefix(list.front()->tname(1, false)), - autopickup(get_auto_pickup().has_rule(list.front())), - stacks(list.size()), - volume(list.front()->volume()* stacks), - weight(list.front()->weight()* stacks), - cat(&list.front()->get_category()), - from_vehicle(from_vehicle) -{ - player& p = g->u; - item it = p.get_consumable_from(*list.front()); - islot_comestible it_c = get_edible_comestible(p, it); +comestible_inv_listitem::comestible_inv_listitem( const std::list &list, int index, + comestible_inv_area *area, bool from_vehicle ) : + idx( index ), + area( area ), + id( list.front()->typeId() ), + items( list ), + name( list.front()->tname( list.size() ) ), + name_without_prefix( list.front()->tname( 1, false ) ), + autopickup( get_auto_pickup().has_rule( list.front() ) ), + stacks( list.size() ), + volume( list.front()->volume() * stacks ), + weight( list.front()->weight() * stacks ), + cat( &list.front()->get_category() ), + from_vehicle( from_vehicle ) +{ + player &p = g->u; + item it = p.get_consumable_from( *list.front() ); + islot_comestible it_c = get_edible_comestible( p, it ); @@ -1229,43 +1227,43 @@ comestible_inv_listitem::comestible_inv_listitem(const std::list& list, i exipres_in = ""; shelf_life = ""; - if (it_c.spoils > 0_turns) { - if (!it.rotten()) { - exipres_in = get_time_left_rounded(p, it); + if( it_c.spoils > 0_turns ) { + if( !it.rotten() ) { + exipres_in = get_time_left_rounded( p, it ); } - shelf_life = to_string_clipped(it_c.spoils); + shelf_life = to_string_clipped( it_c.spoils ); } - calories = p.kcal_for(it); + calories = p.kcal_for( it ); quench = it_c.quench; - joy = p.fun_for(it).first; - is_mushy = it.has_flag("MUSHY"); + joy = p.fun_for( it ).first; + is_mushy = it.has_flag( "MUSHY" ); - energy = p.get_acquirable_energy(it); + energy = p.get_acquirable_energy( it ); menu_color_dark = c_dark_gray; - assert(stacks >= 1); + assert( stacks >= 1 ); } comestible_inv_listitem::comestible_inv_listitem() : idx() , area() - , id("null") + , id( "null" ) , autopickup() , stacks() - , cat(nullptr) + , cat( nullptr ) { menu_color_dark = c_dark_gray; } -comestible_inv_listitem::comestible_inv_listitem(const item_category* cat) +comestible_inv_listitem::comestible_inv_listitem( const item_category *cat ) : idx() , area() - , id("null") - , name(cat->name()) + , id( "null" ) + , name( cat->name() ) , autopickup() , stacks() - , cat(cat) + , cat( cat ) { menu_color_dark = c_dark_gray; } diff --git a/src/comestible_inv_pane.h b/src/comestible_inv_pane.h index ea1ebff748ae6..03b023b21cd11 100644 --- a/src/comestible_inv_pane.h +++ b/src/comestible_inv_pane.h @@ -29,7 +29,7 @@ enum comestible_inv_columns { COLUMN_AMOUNT, COLUMN_WEIGHT, COLUMN_VOLUME, - + COLUMN_CALORIES, COLUMN_QUENCH, COLUMN_JOY, @@ -52,7 +52,8 @@ struct legend_data { char shortcut; nc_color color; std::string message; - legend_data(char shortcut, nc_color color, std::string message):shortcut(shortcut), color(color), message(message) { + legend_data( char shortcut, nc_color color, std::string message ): shortcut( shortcut ), + color( color ), message( message ) { } }; @@ -62,128 +63,134 @@ struct legend_data { * single item or a category header or nothing (empty entry). * Most members are used only for sorting. */ -class comestible_inv_listitem { -public: - using itype_id = std::string; - /** - * Index of the item in the itemstack. - */ - int idx; - /** - * The location of the item, never AIM_ALL. - */ - //comestible_inv_area_info::aim_location area; - comestible_inv_area* area; - // the id of the item - itype_id id; - // The list of items, and empty when a header - std::list items; - /** - * The displayed name of the item/the category header. - */ - std::string name; - /** - * Name of the item (singular) without damage (or similar) prefix, used for sorting. - */ - std::string name_without_prefix; - /** - * Whether auto pickup is enabled for this item (based on the name). - */ - bool autopickup; - /** - * The stack count represented by this item, should be >= 1, should be 1 - * for anything counted by charges. - */ - int stacks; - /** - * The volume of all the items in this stack, used for sorting. - */ - units::volume volume; - /** - * The weight of all the items in this stack, used for sorting. - */ - units::mass weight; - - /** - * TODO:docs - */ - std::string shelf_life; - std::string exipres_in; - int calories; - int quench; - int joy; - bool is_mushy; - int energy; - - comestible_select_state is_selected; - nc_color menu_color; - nc_color menu_color_dark; - - void print_columns(std::vector columns, comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, int cur_print_y); -private: - bool print_string_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y); - bool print_int_column(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y); - void print_name(bool is_compact, catacurses::window window, int right_bound, int cur_print_y); - bool print_default_columns(comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y); - void set_print_color(nc_color& retval, nc_color default_col); -public: - - - char const* set_string_params(nc_color& print_color, int value, bool need_highlight = false); - - /** - * The item category, or the category header. - */ - const item_category* cat; - /** - * Is the item stored in a vehicle? - */ - bool from_vehicle; - - - //TODO - const islot_comestible& get_edible_comestible(player& p, const item& it) const; - - std::string get_time_left_rounded(player& p, const item& it) const; - - std::string time_to_comestible_str(const time_duration& d) const; - /** - * Whether this is a category header entry, which does *not* have a reference - * to an item, only @ref cat is valid. - */ - bool is_category_header() const; - - /** Returns true if this is an item entry */ - bool is_item_entry() const; - /** - * Create a category header entry. - * @param cat The category reference, must not be null. - */ - comestible_inv_listitem(const item_category* cat); - - /** - * Creates an empty entry, both category and item pointer are null. - */ - comestible_inv_listitem(); - /** - * Create a normal item entry. - * @param an_item The item pointer. Must not be null. - * @param index The index - * @param count The stack size - * @param area The source area. Must not be AIM_ALL. - * @param from_vehicle Is the item from a vehicle cargo space? - */ - comestible_inv_listitem(item* an_item, int index, int count, - comestible_inv_area* area, bool from_vehicle); - /** - * Create a normal item entry. - * @param list The list of item pointers. - * @param index The index - * @param area The source area. Must not be AIM_ALL. - * @param from_vehicle Is the item from a vehicle cargo space? - */ - comestible_inv_listitem(const std::list& list, int index, - comestible_inv_area* area, bool from_vehicle); +class comestible_inv_listitem +{ + public: + using itype_id = std::string; + /** + * Index of the item in the itemstack. + */ + int idx; + /** + * The location of the item, never AIM_ALL. + */ + //comestible_inv_area_info::aim_location area; + comestible_inv_area *area; + // the id of the item + itype_id id; + // The list of items, and empty when a header + std::list items; + /** + * The displayed name of the item/the category header. + */ + std::string name; + /** + * Name of the item (singular) without damage (or similar) prefix, used for sorting. + */ + std::string name_without_prefix; + /** + * Whether auto pickup is enabled for this item (based on the name). + */ + bool autopickup; + /** + * The stack count represented by this item, should be >= 1, should be 1 + * for anything counted by charges. + */ + int stacks; + /** + * The volume of all the items in this stack, used for sorting. + */ + units::volume volume; + /** + * The weight of all the items in this stack, used for sorting. + */ + units::mass weight; + + /** + * TODO:docs + */ + std::string shelf_life; + std::string exipres_in; + int calories; + int quench; + int joy; + bool is_mushy; + int energy; + + comestible_select_state is_selected; + nc_color menu_color; + nc_color menu_color_dark; + + void print_columns( std::vector columns, + comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, + int cur_print_y ); + private: + bool print_string_column( comestible_inv_columns col, catacurses::window window, int cur_print_x, + int cur_print_y ); + bool print_int_column( comestible_inv_columns col, catacurses::window window, int cur_print_x, + int cur_print_y ); + void print_name( bool is_compact, catacurses::window window, int right_bound, int cur_print_y ); + bool print_default_columns( comestible_inv_columns col, catacurses::window window, int cur_print_x, + int cur_print_y ); + void set_print_color( nc_color &retval, nc_color default_col ); + public: + + + char const *set_string_params( nc_color &print_color, int value, bool need_highlight = false ); + + /** + * The item category, or the category header. + */ + const item_category *cat; + /** + * Is the item stored in a vehicle? + */ + bool from_vehicle; + + + //TODO + const islot_comestible &get_edible_comestible( player &p, const item &it ) const; + + std::string get_time_left_rounded( player &p, const item &it ) const; + + std::string time_to_comestible_str( const time_duration &d ) const; + /** + * Whether this is a category header entry, which does *not* have a reference + * to an item, only @ref cat is valid. + */ + bool is_category_header() const; + + /** Returns true if this is an item entry */ + bool is_item_entry() const; + /** + * Create a category header entry. + * @param cat The category reference, must not be null. + */ + comestible_inv_listitem( const item_category *cat ); + + /** + * Creates an empty entry, both category and item pointer are null. + */ + comestible_inv_listitem(); + /** + * Create a normal item entry. + * @param an_item The item pointer. Must not be null. + * @param index The index + * @param count The stack size + * @param area The source area. Must not be AIM_ALL. + * @param from_vehicle Is the item from a vehicle cargo space? + */ + comestible_inv_listitem( item *an_item, int index, int count, + comestible_inv_area *area, bool from_vehicle ); + /** + * Create a normal item entry. + * @param list The list of item pointers. + * @param index The index + * @param area The source area. Must not be AIM_ALL. + * @param from_vehicle Is the item from a vehicle cargo space? + */ + comestible_inv_listitem( const std::list &list, int index, + comestible_inv_area *area, bool from_vehicle ); }; /** @@ -191,123 +198,125 @@ class comestible_inv_listitem { */ class comestible_inventory_pane { -private: - comestible_inv_area* cur_area; - // pointer to the square this pane is pointing to - bool viewing_cargo = false; - bool is_compact; -public: - - // set the pane's area via its square, and whether it is viewing a vehicle's cargo - void set_area(comestible_inv_area* square, bool show_vehicle) { - cur_area = square; - viewing_cargo = square->has_vehicle() && show_vehicle; - } - comestible_inv_area* get_area() const { - return cur_area; - } - bool is_in_vehicle() const { - return viewing_cargo; - } - //bool on_ground() const { - // return area > AIM_INVENTORY && area < AIM_DRAGGED; - //} - /** - * Index of the selected item (index of @ref items), - */ - int index; - comestible_inv_columns sortby; - catacurses::window window; - std::vector items; - - std::function special_filter; - - std::vector legend; - std::string title; - - bool inCategoryMode; - - units::volume volume; - units::mass weight; - bool filter_edit; - - /** - * The current filter string. - */ - std::string filter; - /** - * Food or Drug filter. True = show food. - */ - //bool filter_show_food; - /** - * Whether to recalculate the content of this pane. - * Implies @ref redraw. - */ - bool needs_recalc; - /** - * Whether to redraw this pane. - */ - bool needs_redraw; - - void add_items_from_area(comestible_inv_area* area, bool from_cargo, units::volume& ret_volume, units::mass& ret_weight); - /** - * Makes sure the @ref index is valid (if possible). - */ - void fix_index(); - void recalc(); - void redraw(); - std::array* squares; - comestible_inv_area* get_square(comestible_inv_area_info::aim_location loc) { - return &((*squares)[loc]); - } - comestible_inv_area* get_square(size_t loc) { - return &((*squares)[loc]); - } - int print_header(comestible_inv_area* sel_area); - /** - * @param it The item to check, oly the name member is examined. - * @return Whether the item should be filtered (and not shown). - */ - bool is_filtered(const comestible_inv_listitem& it) const; - /** - * Same as the other, but checks the real item. - */ - bool is_filtered(const item& it) const; - /** - * Scroll @ref index, by given offset, set redraw to true, - * @param offset Must not be 0. - */ - void scroll_by(int offset); - /** - * @return either null, if @ref index is invalid, or the selected - * item in @ref items. - */ - comestible_inv_listitem* get_cur_item_ptr(); - /** - * Set the filter string, disables filtering when the filter string is empty. - */ - void set_filter(const std::string& new_filter); - /** - * Insert additional category headers on the top of each page. - */ - void paginate(); - - //TODO:docs'n'stuffs - int itemsPerPage; - std::vector columns; - comestible_inv_columns default_sortby; - - void add_sort_enries(uilist& sm); - void init(std::vector c, int items_per_page, catacurses::window w, std::array* s); - void save_settings(bool reset); - void do_filter(int h, int w); - void print_items(); -private: - /** Scroll to next non-header entry */ - void skip_category_headers(int offset); - /** Only add offset to index, but wrap around! */ - void mod_index(int offset); - - mutable std::map> filtercache; + private: + comestible_inv_area *cur_area; + // pointer to the square this pane is pointing to + bool viewing_cargo = false; + bool is_compact; + public: + + // set the pane's area via its square, and whether it is viewing a vehicle's cargo + void set_area( comestible_inv_area *square, bool show_vehicle ) { + cur_area = square; + viewing_cargo = square->has_vehicle() && show_vehicle; + } + comestible_inv_area *get_area() const { + return cur_area; + } + bool is_in_vehicle() const { + return viewing_cargo; + } + //bool on_ground() const { + // return area > AIM_INVENTORY && area < AIM_DRAGGED; + //} + /** + * Index of the selected item (index of @ref items), + */ + int index; + comestible_inv_columns sortby; + catacurses::window window; + std::vector items; + + std::function special_filter; + + std::vector legend; + std::string title; + + bool inCategoryMode; + + units::volume volume; + units::mass weight; + bool filter_edit; + + /** + * The current filter string. + */ + std::string filter; + /** + * Food or Drug filter. True = show food. + */ + //bool filter_show_food; + /** + * Whether to recalculate the content of this pane. + * Implies @ref redraw. + */ + bool needs_recalc; + /** + * Whether to redraw this pane. + */ + bool needs_redraw; + + void add_items_from_area( comestible_inv_area *area, bool from_cargo, units::volume &ret_volume, + units::mass &ret_weight ); + /** + * Makes sure the @ref index is valid (if possible). + */ + void fix_index(); + void recalc(); + void redraw(); + std::array *squares; + comestible_inv_area *get_square( comestible_inv_area_info::aim_location loc ) { + return &( ( *squares )[loc] ); + } + comestible_inv_area *get_square( size_t loc ) { + return &( ( *squares )[loc] ); + } + int print_header( comestible_inv_area *sel_area ); + /** + * @param it The item to check, oly the name member is examined. + * @return Whether the item should be filtered (and not shown). + */ + bool is_filtered( const comestible_inv_listitem &it ) const; + /** + * Same as the other, but checks the real item. + */ + bool is_filtered( const item &it ) const; + /** + * Scroll @ref index, by given offset, set redraw to true, + * @param offset Must not be 0. + */ + void scroll_by( int offset ); + /** + * @return either null, if @ref index is invalid, or the selected + * item in @ref items. + */ + comestible_inv_listitem *get_cur_item_ptr(); + /** + * Set the filter string, disables filtering when the filter string is empty. + */ + void set_filter( const std::string &new_filter ); + /** + * Insert additional category headers on the top of each page. + */ + void paginate(); + + //TODO:docs'n'stuffs + int itemsPerPage; + std::vector columns; + comestible_inv_columns default_sortby; + + void add_sort_enries( uilist &sm ); + void init( std::vector c, int items_per_page, catacurses::window w, + std::array *s ); + void save_settings( bool reset ); + void do_filter( int h, int w ); + void print_items(); + private: + /** Scroll to next non-header entry */ + void skip_category_headers( int offset ); + /** Only add offset to index, but wrap around! */ + void mod_index( int offset ); + + mutable std::map> filtercache; }; #endif diff --git a/src/crafting.cpp b/src/crafting.cpp index a459eb351cb9a..b6de781461ca6 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -283,10 +283,10 @@ bool player::has_morale_to_craft() const return get_morale_level() >= -50; } -void player::craft( const tripoint &loc, std::string filter) +void player::craft( const tripoint &loc, std::string filter ) { int batch_size = 0; - const recipe *rec = select_crafting_recipe( batch_size, filter); + const recipe *rec = select_crafting_recipe( batch_size, filter ); if( rec ) { if( crafting_allowed( *this, *rec ) ) { make_craft( rec->ident(), batch_size, loc ); diff --git a/src/crafting.h b/src/crafting.h index 334f7a52aaba5..0fd17b85f662d 100644 --- a/src/crafting.h +++ b/src/crafting.h @@ -15,6 +15,6 @@ void remove_ammo( item &dis_item, player &p ); // same as above but for each item in the list void remove_ammo( std::list &dis_items, player &p ); -const recipe *select_crafting_recipe( int &batch_size, std::string filter = ""); +const recipe *select_crafting_recipe( int &batch_size, std::string filter = "" ); #endif diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 2b8aee33412cb..db9108fd31328 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -149,7 +149,7 @@ static int print_items( const recipe &r, const catacurses::window &w, int ypos, return ypos - oldy; } -const recipe *select_crafting_recipe( int &batch_size, std::string filter) +const recipe *select_crafting_recipe( int &batch_size, std::string filter ) { if( normalized_names.empty() ) { translate_all(); diff --git a/src/crafting_gui.h b/src/crafting_gui.h index f0ad9485afb48..369f5ccc02ad8 100644 --- a/src/crafting_gui.h +++ b/src/crafting_gui.h @@ -5,7 +5,7 @@ class recipe; class JsonObject; -const recipe *select_crafting_recipe( int &batch_size); +const recipe *select_crafting_recipe( int &batch_size ); void load_recipe_category( JsonObject &jsobj ); void reset_recipe_categories(); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index a9098d98bee01..8854c92ee2147 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1875,7 +1875,7 @@ bool game::handle_action() case ACTION_EAT: comestible_inv(); - if (false) { + if( false ) { eat(); //TODO: just to make travis happy; delete after done testing } break; diff --git a/src/player.h b/src/player.h index 34c39d3a4e006..aa9c55a27a8e4 100644 --- a/src/player.h +++ b/src/player.h @@ -1433,7 +1433,7 @@ class player : public Character * Start various types of crafts * @param loc the location of the workbench. tripoint_zero indicates crafting from inventory. */ - void craft( const tripoint &loc = tripoint_zero, std::string filter = ""); + void craft( const tripoint &loc = tripoint_zero, std::string filter = "" ); void recraft( const tripoint &loc = tripoint_zero ); void long_craft( const tripoint &loc = tripoint_zero ); void make_craft( const recipe_id &id, int batch_size, const tripoint &loc = tripoint_zero ); diff --git a/src/uistate.h b/src/uistate.h index 6575ad8445bcc..59df79feb1ed5 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -24,7 +24,7 @@ struct comestible_inv_save_state { When item is fully consumed we want to keep list at the same index */ int selected_idx = 0; - item* selected_itm = nullptr; + item *selected_itm = nullptr; int bio = -1; bool show_food = true; From e6628adf21fa25ec935143bc61745c6380c45479 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 24 Aug 2019 23:57:38 -0400 Subject: [PATCH 06/19] travis error --- src/comestible_inv_area.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/comestible_inv_area.h b/src/comestible_inv_area.h index 8e35932db9319..6c6b31edf1a8d 100644 --- a/src/comestible_inv_area.h +++ b/src/comestible_inv_area.h @@ -81,16 +81,18 @@ struct comestible_inv_area_info { const std::string &actionname ) : id( id ), hscreen( hscreenx, hscreeny ), default_offset( off ), name( name ), shortname( shortname ), minimapname( minimapname ), relative_location( relative_location ), actionname( actionname ) { - static const std::array< aim_location, 9> ground_locations = { AIM_SOUTHWEST, - AIM_SOUTH, - AIM_SOUTHEAST, - AIM_WEST, - AIM_CENTER, - AIM_EAST, - AIM_NORTHWEST, - AIM_NORTH, - AIM_NORTHEAST - }; + static const std::array< aim_location, 9> ground_locations = { { + AIM_SOUTHWEST, + AIM_SOUTH, + AIM_SOUTHEAST, + AIM_WEST, + AIM_CENTER, + AIM_EAST, + AIM_NORTHWEST, + AIM_NORTH, + AIM_NORTHEAST + } + }; if( id == AIM_ALL ) { type = AREA_TYPE_MULTI; multi_locations = std::vector( ground_locations.begin(), ground_locations.end() ); From fbf078adf47f46ae3d8decce3c5c57dbef28528f Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 25 Aug 2019 00:41:51 -0400 Subject: [PATCH 07/19] travis error2 --- src/comestible_inv.cpp | 2 -- src/comestible_inv.h | 7 ------- 2 files changed, 9 deletions(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index bfad24ed8a151..11eb3c7fc143e 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -72,10 +72,8 @@ comestible_inventory::comestible_inventory() , min_w_height( 10 ) , min_w_width( FULL_SCREEN_WIDTH ) , max_w_width( 120 ) - , inCategoryMode( false ) , recalc( true ) , redraw( true ) - , filter_edit( false ) , squares( { { {comestible_inv_area::get_info( comestible_inv_area_info::AIM_SOUTHWEST )}, diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 5cfa35032f4ff..7cac1cc44fc0b 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -48,8 +48,6 @@ class comestible_inventory void refresh_minimap(); char minimap_get_sym() const; - bool inCategoryMode; - int w_height; int w_width; @@ -58,11 +56,6 @@ class comestible_inventory bool recalc; bool redraw; - /** - * True if (and only if) the filter of the active panel is currently - * being edited. - */ - bool filter_edit; comestible_inventory_pane pane; //static const comestible_inventory_pane null_pane; From e63bdad17b00360318f9852a5a6c3b88a84c16f1 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 25 Aug 2019 02:36:12 -0400 Subject: [PATCH 08/19] travis error 3 fixing CBM menu showing wrong items fixing heat_up not having shortcuts --- src/comestible_inv.cpp | 8 ++++---- src/comestible_inv_pane.cpp | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 11eb3c7fc143e..d139de4186c98 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -206,7 +206,7 @@ void comestible_inventory::init() pane.default_sortby = COLUMN_EXPIRES; } else { pane.special_filter = []( const item & it ) { - return !g->u.can_consume( it ); + return !g->u.can_consume( it ) || g->u.get_acquirable_energy(it) <= 0; }; pane.title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name; pane.default_sortby = COLUMN_ENERGY; @@ -721,18 +721,18 @@ void comestible_inventory::heat_up( item *it_to_heat ) sm.text = _( "Choose a way to heat an item..." ); int counter = 0; if( can_use_bio ) { - sm.addentry( counter, true, counter, _( "use bio tools" ) ); + sm.addentry( counter, true, 'a' + counter, _( "use bio tools" ) ); counter++; } for( size_t i = 0; i < hotplates.size(); i++ ) { - sm.addentry( counter, true, counter, string_format( _( "%s in inventory" ), + sm.addentry( counter, true, 'a' + counter, string_format( _( "%s in inventory" ), hotplates.at( i )->display_name() ) ); counter++; } for( size_t i = 0; i < hotplates_map.size(); i++ ) { - sm.addentry( counter, true, counter, string_format( _( "%s nearby" ), + sm.addentry( counter, true, 'a' + counter, string_format( _( "%s nearby" ), hotplates_map.at( i )->display_name() ) ); counter++; } diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index f2fa16993c840..f965f52b3d5b6 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -609,8 +609,6 @@ void comestible_inventory_pane::add_items_from_area( comestible_inv_area *area, ret_volume = 0_ml; ret_weight = 0_gram; - units::volume tmp_volume; - units::mass tmp_weight; // Existing items are *not* cleared on purpose, this might be called // several times in case all surrounding squares are to be shown. if( area->info.id == comestible_inv_area_info::AIM_INVENTORY ) { From c749bafe2fa489eb41d8233cd5b0e6d43e4fc2f6 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 25 Aug 2019 09:12:12 -0400 Subject: [PATCH 09/19] astyle --- src/comestible_inv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index d139de4186c98..3b1f82e55bac6 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -206,7 +206,7 @@ void comestible_inventory::init() pane.default_sortby = COLUMN_EXPIRES; } else { pane.special_filter = []( const item & it ) { - return !g->u.can_consume( it ) || g->u.get_acquirable_energy(it) <= 0; + return !g->u.can_consume( it ) || g->u.get_acquirable_energy( it ) <= 0; }; pane.title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name; pane.default_sortby = COLUMN_ENERGY; From 4bb63dade966ca2e07f73a32e1098c220f2f187f Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 25 Aug 2019 09:44:44 -0400 Subject: [PATCH 10/19] update for translation in bionics --- src/comestible_inv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 3b1f82e55bac6..cd8f0b3dd8e87 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -208,7 +208,7 @@ void comestible_inventory::init() pane.special_filter = []( const item & it ) { return !g->u.can_consume( it ) || g->u.get_acquirable_energy( it ) <= 0; }; - pane.title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name; + pane.title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name.translated(); pane.default_sortby = COLUMN_ENERGY; } } From 3a1d5aa7d91ad0ff978c7f2106c3bb47157efc05 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 25 Aug 2019 11:56:41 -0400 Subject: [PATCH 11/19] adding shortcuts reorganizing things a little --- data/raw/keybindings.json | 221 ++++++++++++++++++++++++++++++++++++ src/comestible_inv.cpp | 7 +- src/comestible_inv.h | 61 +--------- src/comestible_inv_area.cpp | 18 +-- src/comestible_inv_area.h | 97 +++++++--------- src/comestible_inv_pane.cpp | 54 ++------- src/comestible_inv_pane.h | 148 ++++++++++++------------ 7 files changed, 363 insertions(+), 243 deletions(-) diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index 317c92cbd6453..9f95c36bfd84e 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -2603,6 +2603,227 @@ "id": "SAVE_DEFAULT", "category": "ADVANCED_INVENTORY", "name": "Save default layout" + }, + { + "type": "keybinding", + "id": "UP", + "category": "COMESTIBLE_INVENTORY", + "name": "Pan up", + "bindings": [ + { "input_method": "keyboard", "key": "k" }, + { "input_method": "keyboard", "key": "UP" }, + { "input_method": "gamepad", "key": "JOY_UP" } + ] + }, + { + "type": "keybinding", + "id": "DOWN", + "category": "COMESTIBLE_INVENTORY", + "name": "Pan down", + "bindings": [ + { "input_method": "keyboard", "key": "j" }, + { "input_method": "keyboard", "key": "DOWN" }, + { "input_method": "gamepad", "key": "JOY_DOWN" } + ] + }, + { + "type": "keybinding", + "id": "PAGE_DOWN", + "category": "COMESTIBLE_INVENTORY", + "name": "Page down", + "bindings": [ { "input_method": "keyboard", "key": "NPAGE" }, { "input_method": "keyboard", "key": ">" } ] + }, + { + "type": "keybinding", + "id": "PAGE_UP", + "category": "COMESTIBLE_INVENTORY", + "name": "Page up", + "bindings": [ { "input_method": "keyboard", "key": "PPAGE" }, { "input_method": "keyboard", "key": "<" } ] + }, + { + "type": "keybinding", + "id": "TOGGLE_VEH", + "category": "COMESTIBLE_INVENTORY", + "name": "Toggle vehicle", + "bindings": [ { "input_method": "keyboard", "key": "v" }, { "input_method": "keyboard", "key": "V" } ] + }, + { + "type": "keybinding", + "id": "TOGGLE_AUTO_PICKUP", + "category": "COMESTIBLE_INVENTORY", + "name": "Toggle auto-pickup for item", + "bindings": [ { "input_method": "keyboard", "key": "p" } ] + }, + { + "type": "keybinding", + "id": "EXAMINE", + "category": "COMESTIBLE_INVENTORY", + "name": "Examine", + "bindings": [ { "input_method": "keyboard", "key": "e" }, { "input_method": "keyboard", "key": "E" } ] + }, + { + "type": "keybinding", + "id": "SORT", + "category": "COMESTIBLE_INVENTORY", + "name": "Change sorting mode", + "bindings": [ { "input_method": "keyboard", "key": "s" }, { "input_method": "keyboard", "key": "S" } ] + }, + { + "type": "keybinding", + "id": "CATEGORY_SELECTION", + "category": "COMESTIBLE_INVENTORY", + "name": "Toggle category selection mode", + "bindings": [ { "input_method": "keyboard", "key": "t" } ] + }, + { + "type": "keybinding", + "id": "TOGGLE_FAVORITE", + "category": "COMESTIBLE_INVENTORY", + "name": "Toggle item as favorite", + "bindings": [ { "input_method": "keyboard", "key": "*" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_NW", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ North-West", + "bindings": [ { "input_method": "keyboard", "key": "7" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_N", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ North", + "bindings": [ { "input_method": "keyboard", "key": "8" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_NE", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ North-East", + "bindings": [ { "input_method": "keyboard", "key": "9" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_W", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ West", + "bindings": [ { "input_method": "keyboard", "key": "4" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_CE", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ center", + "bindings": [ { "input_method": "keyboard", "key": "5" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_E", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ East", + "bindings": [ { "input_method": "keyboard", "key": "6" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_SW", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ South-West", + "bindings": [ { "input_method": "keyboard", "key": "1" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_S", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ South", + "bindings": [ { "input_method": "keyboard", "key": "2" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_SE", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ South-East", + "bindings": [ { "input_method": "keyboard", "key": "3" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_INVENTORY", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items in inventory", + "bindings": [ + { "input_method": "keyboard", "key": "i" }, + { "input_method": "keyboard", "key": "I" }, + { "input_method": "keyboard", "key": "0" } + ] + }, + { + "type": "keybinding", + "id": "ITEMS_WORN", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items currently worn", + "bindings": [ { "input_method": "keyboard", "key": "w" }, { "input_method": "keyboard", "key": "W" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_AROUND", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ all 9 fields", + "bindings": [ { "input_method": "keyboard", "key": "a" }, { "input_method": "keyboard", "key": "A" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_AROUND_I_W", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items @ around, inv and worn", + "bindings": [ { "input_method": "keyboard", "key": "x" }, { "input_method": "keyboard", "key": "X" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_DRAGGED_CONTAINER", + "category": "COMESTIBLE_INVENTORY", + "name": "Select items in dragged container", + "bindings": [ { "input_method": "keyboard", "key": "d" }, { "input_method": "keyboard", "key": "D" } ] + }, + { + "type": "keybinding", + "id": "ITEMS_DEFAULT", + "category": "COMESTIBLE_INVENTORY", + "name": "Restore default layout" + }, + { + "type": "keybinding", + "id": "SAVE_DEFAULT", + "category": "COMESTIBLE_INVENTORY", + "name": "Save default layout" + }, + + { + "type": "keybinding", + "id": "CONSUME_FOOD", + "category": "COMESTIBLE_INVENTORY", + "name": "Consume selected", + "bindings": [ { "input_method": "keyboard", "key": "RETURN" } ] + }, + { + "type": "keybinding", + "id": "SWITCH_FOOD", + "category": "COMESTIBLE_INVENTORY", + "name": "Switch between Food/Drugs", + "bindings": [ { "input_method": "keyboard", "key": "z" }, { "input_method": "keyboard", "key": "Z" } ] + }, + { + "type": "keybinding", + "id": "HEAT_UP", + "category": "COMESTIBLE_INVENTORY", + "name": "Heat up selected", + "bindings": [ { "input_method": "keyboard", "key": "h" }, { "input_method": "keyboard", "key": "H" } ] + }, + { + "type": "keybinding", + "id": "CRAFT_WITH", + "category": "COMESTIBLE_INVENTORY", + "name": "Start crafting with selected", + "bindings": [ { "input_method": "keyboard", "key": "&" } ] }, { "type": "keybinding", diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index cd8f0b3dd8e87..4d7b9699196d2 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -290,7 +290,6 @@ void comestible_inventory::display( int bio ) ctxt.register_action( "ITEMS_AROUND" ); ctxt.register_action( "ITEMS_AROUND_I_W" ); ctxt.register_action( "ITEMS_DRAGGED_CONTAINER" ); - ctxt.register_action( "ITEMS_CONTAINER" ); if( uistate.comestible_save.bio == -1 ) { ctxt.register_action( "CONSUME_FOOD" ); @@ -333,7 +332,6 @@ void comestible_inventory::display( int bio ) // current item in source pane, might be null comestible_inv_listitem *sitem = pane.get_cur_item_ptr(); - //comestible_inv_area_info::aim_location changeSquare = NUM_AIM_LOCATIONS; comestible_inv_area *new_square; const std::string action = ctxt.handle_input(); @@ -347,7 +345,7 @@ void comestible_inventory::display( int bio ) } else if( ( new_square = get_square( action ) ) != nullptr ) { if( pane.get_area()->info.id == new_square->get_relative_location() ) { //DO NOTHING - } else if( new_square->canputitems() ) { + } else if( new_square->is_valid() ) { pane.set_area( new_square, new_square->is_vehicle_default() ); pane.index = 0; redo( true, true ); @@ -371,7 +369,7 @@ void comestible_inventory::display( int bio ) redo( recalc, true ); } else if( action == "FILTER" ) { draw_item_filter_rules( pane.window, 1, 11, item_filter_type::FILTER ); - pane.do_filter( w_height - 1, w_width / 2 - 4 ); + pane.start_user_filtering( w_height - 1, w_width / 2 - 4 ); } else if( action == "RESET_FILTER" ) { pane.set_filter( "" ); } else if( action == "TOGGLE_AUTO_PICKUP" ) { @@ -736,7 +734,6 @@ void comestible_inventory::heat_up( item *it_to_heat ) hotplates_map.at( i )->display_name() ) ); counter++; } - //sm.selected = pane.sortby - SORTBY_NONE; sm.query(); if( sm.ret < 0 ) { diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 7cac1cc44fc0b..a51f10ff0d468 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -71,19 +71,8 @@ class comestible_inventory //void load_settings(); // used to return back to AIM when other activities queued are finished void do_return_entry(); + //sets recalculate and redraw for this and pane void redo( bool needs_recalc, bool needs_redraw ); - // returns true if currently processing a routine - // (such as `MOVE_ALL_ITEMS' with `AIM_ALL' source) - //bool is_processing() const; - - //static std::string get_sortname( comestible_inv_sortby sortby ); - //bool move_all_items(bool nested_call = false); - //void print_items( comestible_inventory_pane &pane ); - //void recalc_pane(); - //void redraw_pane(); - // Returns the x coordinate where the header started. The header is - // displayed right of it, everything left of it is till free. - //int print_header( comestible_inventory_pane &pane, aim_location sel ); void init(); void set_pane_legend(); /** @@ -100,54 +89,8 @@ class comestible_inventory * @return whether the sort order was actually changed. */ bool show_sort_menu(); - /** - * Checks whether one can put items into the supplied location. - * If the supplied location is AIM_ALL, query for the actual location - * (stores the result in def) and check that destination. - * @return false if one can not put items in the destination, true otherwise. - * The result true also indicates the def is not AIM_ALL (because the - * actual location has been queried). - */ - //bool query_destination(aim_location& def); - /** - * Move content of source container into destination container (destination pane = AIM_CONTAINER) - * @param src_container Source container - * @param dest_container Destination container - */ - //bool move_content( item &src_container, item &dest_container ); - /** - * Setup how many items/charges (if counted by charges) should be moved. - * @param destarea Where to move to. This must not be AIM_ALL. - * @param sitem The source item, it must contain a valid reference to an item! - * @param action The action we are querying - * @param amount The input value is ignored, contains the amount that should - * be moved. Only valid if this returns true. - * @return false if nothing should/can be moved. True only if there can and - * should be moved. A return value of true indicates that amount now contains - * a valid item count to be moved. - */ - /*bool query_charges(aim_location destarea, const comestible_inv_listitem& sitem, - const std::string& action, int& amount);*/ - - //void menu_square( uilist &menu ); - - //std::string get_location_key( aim_location area ); - //char get_direction_key( aim_location area ); - - /** - * Converts from screen relative location to game-space relative location - * for control rotation in isometric mode. - */ - //static aim_location screen_relative_location( aim_location area ); - - //char const *set_string_params( nc_color &print_color, int value, bool selected, - // bool need_highlight = false ); - //nc_color set_string_params(int value, bool need_highlight = false); - //time_duration get_time_left( player &p, const item &it ) const; - //const islot_comestible &get_edible_comestible( player &p, const item &it ) const; - //std::string get_time_left_rounded( player &p, const item &it ) const; - //std::string time_to_comestible_str( const time_duration &d ) const; + //try to find a way to warm up/defrost an item, and do it void heat_up( item *it ); }; diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index 7014b75ab5139..d8aff0ad23352 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -72,11 +72,11 @@ void comestible_inv_area::init() switch( info.id ) { case ai::AIM_INVENTORY: case ai::AIM_WORN: - is_valid = true; + is_valid_location = true; break; case ai::AIM_DRAGGED: if( g->u.get_grab_type() != OBJECT_VEHICLE ) { - is_valid = false; + is_valid_location = false; desc[0] = _( "Not dragging any vehicle!" ); break; } @@ -92,21 +92,21 @@ void comestible_inv_area::init() } if( veh_part >= 0 ) { desc[0] = veh->name; - is_valid = true; + is_valid_location = true; //max_size = MAX_ITEM_IN_VEHICLE_STORAGE; } else { veh = nullptr; - is_valid = false; + is_valid_location = false; desc[0] = _( "No dragged vehicle!" ); } break; case ai::AIM_ALL: desc[0] = _( "All 9 squares" ); - is_valid = true; + is_valid_location = true; break; case ai::AIM_ALL_I_W: desc[0] = _( "Around,Inv,Worn" ); - is_valid = true; + is_valid_location = true; break; case ai::AIM_SOUTHWEST: case ai::AIM_SOUTH: @@ -125,7 +125,7 @@ void comestible_inv_area::init() veh = nullptr; veh_part = -1; } - is_valid = has_vehicle() || g->m.can_put_items_ter_furn( pos ); + is_valid_location = has_vehicle() || g->m.can_put_items_ter_furn( pos ); //max_size = MAX_ITEM_IN_SQUARE; if( has_vehicle() ) { desc[1] = vpart_position( *veh, veh_part ).get_label().value_or( "" ); @@ -179,9 +179,9 @@ void comestible_inv_area::init() } } -bool comestible_inv_area::canputitems() +bool comestible_inv_area::is_valid() { - return is_valid; + return is_valid_location; } inline std::string comestible_inv_area::get_location_key() diff --git a/src/comestible_inv_area.h b/src/comestible_inv_area.h index 6c6b31edf1a8d..4e8d952a2af80 100644 --- a/src/comestible_inv_area.h +++ b/src/comestible_inv_area.h @@ -118,70 +118,55 @@ class comestible_inv_area { public : - // *INDENT-OFF* - static comestible_inv_area_info get_info(comestible_inv_area_info::aim_location loc) { - using i = comestible_inv_area_info; - static const std::array< comestible_inv_area_info, comestible_inv_area_info::NUM_AIM_LOCATIONS> area_info = { { - { i::AIM_SOUTHWEST, 30, 3, tripoint_south_west, _("South West"), _("SW"), "1", i::AIM_WEST, "ITEMS_SW" }, - { i::AIM_SOUTH, 33, 3, tripoint_south, _("South"), _("S"), "2", i::AIM_SOUTHWEST, "ITEMS_S"}, - { i::AIM_SOUTHEAST, 36, 3, tripoint_south_east, _("South East"), _("SE"), "3", i::AIM_SOUTH, "ITEMS_SE"}, - { i::AIM_WEST, 30, 2, tripoint_west, _("West"), _("W"), "4", i::AIM_NORTHWEST, "ITEMS_W" }, - { i::AIM_CENTER, 33, 2, tripoint_zero, _("Directly below you"), _("DN"), "5", i::AIM_CENTER, "ITEMS_CE"}, - { i::AIM_EAST, 36, 2, tripoint_east, _("East"), _("E"), "6", i::AIM_SOUTHEAST, "ITEMS_E" }, - { i::AIM_NORTHWEST, 30, 1, tripoint_north_west, _("North West"), _("NW"), "7", i::AIM_NORTH, "ITEMS_NW"}, - { i::AIM_NORTH, 33, 1, tripoint_north, _("North"), _("N"), "8", i::AIM_NORTHEAST, "ITEMS_N" }, - { i::AIM_NORTHEAST, 36, 1, tripoint_north_east, _("North East"), _("NE"), "9", i::AIM_EAST, "ITEMS_NE" }, - - { i::AIM_DRAGGED, 25, 1, tripoint_zero, _("Grabbed Vehicle"), _("GR"), "D", i::AIM_DRAGGED, "ITEMS_DRAGGED_CONTAINER" }, - { i::AIM_INVENTORY, 25, 2, tripoint_zero, _("Inventory"), _("I"), "I", i::AIM_INVENTORY, "ITEMS_INVENTORY" }, - { i::AIM_WORN, 22, 2, tripoint_zero, _("Worn Items"), _("W"), "W", i::AIM_WORN, "ITEMS_WORN"}, - - { i::AIM_ALL, 25, 3, tripoint_zero, _("Surrounding area"), "", "A", i::AIM_ALL, "ITEMS_AROUND" }, - { i::AIM_ALL_I_W, 18, 3, tripoint_zero, _("Everything"), "", "A+I+W", i::AIM_ALL_I_W, "ITEMS_AROUND_I_W" } - } - }; - return area_info[loc]; - } - // *INDENT-ON* + // *INDENT-OFF* + static comestible_inv_area_info get_info(comestible_inv_area_info::aim_location loc) { + using i = comestible_inv_area_info; + static const std::array< comestible_inv_area_info, comestible_inv_area_info::NUM_AIM_LOCATIONS> area_info = { { + { i::AIM_SOUTHWEST, 30, 3, tripoint_south_west, _("South West"), _("SW"), "1", i::AIM_WEST, "ITEMS_SW" }, + { i::AIM_SOUTH, 33, 3, tripoint_south, _("South"), _("S"), "2", i::AIM_SOUTHWEST, "ITEMS_S"}, + { i::AIM_SOUTHEAST, 36, 3, tripoint_south_east, _("South East"), _("SE"), "3", i::AIM_SOUTH, "ITEMS_SE"}, + { i::AIM_WEST, 30, 2, tripoint_west, _("West"), _("W"), "4", i::AIM_NORTHWEST, "ITEMS_W" }, + { i::AIM_CENTER, 33, 2, tripoint_zero, _("Directly below you"), _("DN"), "5", i::AIM_CENTER, "ITEMS_CE"}, + { i::AIM_EAST, 36, 2, tripoint_east, _("East"), _("E"), "6", i::AIM_SOUTHEAST, "ITEMS_E" }, + { i::AIM_NORTHWEST, 30, 1, tripoint_north_west, _("North West"), _("NW"), "7", i::AIM_NORTH, "ITEMS_NW"}, + { i::AIM_NORTH, 33, 1, tripoint_north, _("North"), _("N"), "8", i::AIM_NORTHEAST, "ITEMS_N" }, + { i::AIM_NORTHEAST, 36, 1, tripoint_north_east, _("North East"), _("NE"), "9", i::AIM_EAST, "ITEMS_NE" }, + + { i::AIM_DRAGGED, 25, 1, tripoint_zero, _("Grabbed Vehicle"), _("GR"), "D", i::AIM_DRAGGED, "ITEMS_DRAGGED_CONTAINER" }, + { i::AIM_INVENTORY, 25, 2, tripoint_zero, _("Inventory"), _("I"), "I", i::AIM_INVENTORY, "ITEMS_INVENTORY" }, + { i::AIM_WORN, 22, 2, tripoint_zero, _("Worn Items"), _("W"), "W", i::AIM_WORN, "ITEMS_WORN"}, + + { i::AIM_ALL, 25, 3, tripoint_zero, _("Surrounding area"), "", "A", i::AIM_ALL, "ITEMS_AROUND" }, + { i::AIM_ALL_I_W, 18, 3, tripoint_zero, _("Everything"), "", "A+I+W", i::AIM_ALL_I_W, "ITEMS_AROUND_I_W" } + } + }; + return area_info[loc]; + } + // *INDENT-ON* const comestible_inv_area_info info; private: - /** Can we put items there? Only checks if location is valid, not if - selected container in pane is. For full check use canputitems() **/ - bool is_valid; + /** false if blocked by somehting (like a wall) **/ + bool is_valid_location; // vehicle pointer and cargo part index vehicle *veh; int veh_part; public: - // roll our own, to handle moving stacks better - using area_items = std::vector >; - - area_items get_items( bool use_vehicle ); - - units::volume get_max_volume( bool use_vehicle ); - - std::string get_name( bool use_vehicle ) const; - - bool is_vehicle_default() const; - - // absolute position of the map point. - //tripoint pos; // description, e.g. vehicle name, label, or terrain std::array desc; // flags, e.g. FIRE, TRAP, WATER std::string flags; - // total volume and weight of items currently there - //units::volume volume; - //units::mass weight; - // maximal count / volume of items there. - //int max_size; + // use this instead of info.offset, because 'D'ragged containers change original tripoint offset; + // roll our own, to handle moving stacks better + using area_items = std::vector >; + //TODO: might want to get rind of info... keep for now //comestible_inv_area(aim_location id) : id(id), relative_location(id) {} //comestible_inv_area(aim_location id, int hscreenx, int hscreeny, tripoint off, // const std::string& name, const std::string& shortname, @@ -194,16 +179,23 @@ class comestible_inv_area //} comestible_inv_area( comestible_inv_area_info area_info ) : info( area_info ), - is_valid( false ), veh( nullptr ), veh_part( -1 ) { + is_valid_location( false ), veh( nullptr ), veh_part( -1 ) { } void init(); - // Other area is actually the same item source, e.g. dragged vehicle to the south and AIM_SOUTH - //bool is_same( const comestible_inv_area &other ) const; - // does _not_ check vehicle storage, do that with `can_store_in_vehicle()' below - bool canputitems(); + //just a getter + bool is_valid(); + + std::string get_name( bool use_vehicle ) const; + area_items get_items( bool use_vehicle ); + units::volume get_max_volume( bool use_vehicle ); + + // whether to show vehicle when we open location for the first time + bool is_vehicle_default() const; + + std::string get_location_key(); + bool has_vehicle() const { - //add_msg("XXX veh: %d %d", info.id, info.type); // disallow for non-valid vehicle locations if( info.type != comestible_inv_area_info::AREA_TYPE_GROUND ) { return false; @@ -211,7 +203,6 @@ class comestible_inv_area return veh != nullptr && veh_part >= 0; } - std::string get_location_key(); comestible_inv_area_info::aim_location get_relative_location() const { if( !( tile_iso && use_tiles ) ) { return info.id; diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index f965f52b3d5b6..8142480319350 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -177,7 +177,7 @@ void comestible_inventory_pane::add_sort_enries( uilist &sm ) } } -void comestible_inventory_pane::do_filter( int h, int w ) +void comestible_inventory_pane::start_user_filtering( int h, int w ) { string_input_popup spopup; std::string old_filter = filter; @@ -601,7 +601,7 @@ void comestible_inventory_pane::add_items_from_area( comestible_inv_area *area, units::volume &ret_volume, units::mass &ret_weight ) { assert( area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI ); - if( !area->canputitems() ) { + if( !area->is_valid() ) { return; } player &u = g->u; @@ -670,19 +670,18 @@ void comestible_inventory_pane::redraw() print_items(); auto itm = get_cur_item_ptr(); - int width = print_header( itm != nullptr ? itm->area : get_area() ); - bool same_as_dragged = ( cur_area->info.id >= comestible_inv_area_info::AIM_SOUTHWEST && - cur_area->info.id <= comestible_inv_area_info::AIM_NORTHEAST ) && + int width = print_header( itm != nullptr ? itm->area : cur_area ); + bool same_as_dragged = ( cur_area->info.type == comestible_inv_area_info::AREA_TYPE_GROUND ) && // only cardinals - cur_area->info.id != comestible_inv_area_info::AIM_CENTER && is_in_vehicle() && + cur_area->info.id != comestible_inv_area_info::AIM_CENTER && viewing_cargo && // not where you stand, and pane is in vehicle cur_area->info.default_offset == get_square( - comestible_inv_area_info::AIM_DRAGGED )->info.default_offset; // make sure the offsets are the same as the grab point + comestible_inv_area_info::AIM_DRAGGED )->offset; // make sure the offsets are the same as the grab point const comestible_inv_area *sq = same_as_dragged ? get_square( comestible_inv_area_info::AIM_DRAGGED ) : cur_area; - bool car = cur_area->has_vehicle() && is_in_vehicle() && + bool car = cur_area->has_vehicle() && viewing_cargo && sq->info.id != comestible_inv_area_info::AIM_DRAGGED; auto name = utf8_truncate( sq->get_name( viewing_cargo ), width ); auto desc = utf8_truncate( sq->desc[car], width ); @@ -718,8 +717,6 @@ void comestible_inventory_pane::redraw() const char *fprefix = _( "[F]ilter" ); const char *fsuffix = _( "[R]eset" ); - //TODO:XXX - //bool filter_edit = true; if( !filter_edit ) { if( !filter.empty() ) { mvwprintw( w, point( 2, getmaxy( w ) - 1 ), "< %s: %s >", fprefix, filter ); @@ -761,21 +758,9 @@ int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) } else { is_selected_by_item = get_square( i )->info.id == sel_area->info.id; } - - //bool is_selected = get_square(i)->info.has_area(sel_area->info.id); - - //bool q = (sel_area->info.id == get_square(i)->info.id); - - - - //bool iterIsMe = (get_square(i).info.id == area); - //bool selectIsMe = (sel == area); - - //bool in_vehicle = is_in_vehicle() && get_square(i).info.id == area && sel == area && area != comestible_inv_area_info::AIM_ALL; - //bool all_brackets = area == comestible_inv_area_info::AIM_ALL && (i >= comestible_inv_area_info::AIM_SOUTHWEST && i <= comestible_inv_area_info::AIM_NORTHEAST); nc_color bcolor = c_red; nc_color kcolor = c_red; - if( get_square( i )->canputitems() ) { + if( get_square( i )->is_valid() ) { if( is_single ) { if( is_selected_by_item ) { if( viewing_cargo ) { @@ -805,25 +790,6 @@ int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) } } } - - /* if (is_selected) { - if (is_single) { - if (viewing_cargo) { - bcolor = c_light_gray; - } - kcolor = c_white; - } - else { - bcolor = c_light_gray; - kcolor = c_light_gray; - } - } - else { - bcolor = kcolor = c_dark_gray; - }*/ - //bcolor = in_vehicle ? c_light_blue : - // area == i || all_brackets ? c_light_gray : c_dark_gray; - //kcolor = area == i ? c_white : sel == i ? c_light_gray : c_dark_gray; } const int x = get_square( i )->info.hscreen.x + ofs; @@ -862,7 +828,8 @@ void comestible_inv_listitem::print_columns( std::vector continue; } - //TODO: error + //we encountered a column that had no printing code + assert( false ); } print_name( is_compact, window, right_bound, cur_print_y ); } @@ -1029,7 +996,6 @@ void comestible_inv_listitem::print_name( bool is_compact, catacurses::window wi item *it = items.front(); if( it->is_money() ) { //Count charges - // TODO: transition to the item_location system used for the normal inventory unsigned int charges_total = 0; for( const auto item : items ) { charges_total += item->charges; diff --git a/src/comestible_inv_pane.h b/src/comestible_inv_pane.h index 03b023b21cd11..a5b82de4fdb2e 100644 --- a/src/comestible_inv_pane.h +++ b/src/comestible_inv_pane.h @@ -199,88 +199,90 @@ class comestible_inv_listitem class comestible_inventory_pane { private: - comestible_inv_area *cur_area; // pointer to the square this pane is pointing to + comestible_inv_area *cur_area; bool viewing_cargo = false; bool is_compact; + + units::volume volume; + units::mass weight; + //supplied by parent to say which columns need to be displayed + std::vector columns; + + std::vector items; + + //true when user is editing item filter + bool filter_edit; + /** + * The current filter string. + */ + std::string filter; + /** + * @param it The item to check, oly the name member is examined. + * @return Whether the item should be filtered (and not shown). + */ + bool is_filtered( const comestible_inv_listitem &it ) const; + /** + * Same as the other, but checks the real item. + */ + bool is_filtered( const item &it ) const; + + int print_header( comestible_inv_area *sel_area ); + /** + * Insert additional category headers on the top of each page. + */ + void paginate(); + + void add_items_from_area( comestible_inv_area *area, bool from_cargo, units::volume &ret_volume, + units::mass &ret_weight ); + + void print_items(); + + /** Scroll to next non-header entry */ + void skip_category_headers( int offset ); + /** Only add offset to index, but wrap around! */ + void mod_index( int offset ); + + mutable std::map> filtercache; + public: - // set the pane's area via its square, and whether it is viewing a vehicle's cargo - void set_area( comestible_inv_area *square, bool show_vehicle ) { - cur_area = square; - viewing_cargo = square->has_vehicle() && show_vehicle; - } - comestible_inv_area *get_area() const { - return cur_area; - } - bool is_in_vehicle() const { - return viewing_cargo; - } - //bool on_ground() const { - // return area > AIM_INVENTORY && area < AIM_DRAGGED; - //} /** * Index of the selected item (index of @ref items), */ int index; - comestible_inv_columns sortby; catacurses::window window; - std::vector items; - + //this filter is supplied by parent, applied before user input filtering std::function special_filter; - + //list of shortcut reminders (created manually by parent) std::vector legend; std::string title; + int itemsPerPage; + bool inCategoryMode; - units::volume volume; - units::mass weight; - bool filter_edit; + comestible_inv_columns sortby; + // secondary sort, in case original returns == items + comestible_inv_columns default_sortby; - /** - * The current filter string. - */ - std::string filter; - /** - * Food or Drug filter. True = show food. - */ - //bool filter_show_food; /** * Whether to recalculate the content of this pane. * Implies @ref redraw. */ bool needs_recalc; - /** - * Whether to redraw this pane. - */ bool needs_redraw; - void add_items_from_area( comestible_inv_area *area, bool from_cargo, units::volume &ret_volume, - units::mass &ret_weight ); + void init( std::vector c, int items_per_page, catacurses::window w, + std::array *s ); + void save_settings( bool reset ); + /** * Makes sure the @ref index is valid (if possible). */ void fix_index(); void recalc(); void redraw(); - std::array *squares; - comestible_inv_area *get_square( comestible_inv_area_info::aim_location loc ) { - return &( ( *squares )[loc] ); - } - comestible_inv_area *get_square( size_t loc ) { - return &( ( *squares )[loc] ); - } - int print_header( comestible_inv_area *sel_area ); - /** - * @param it The item to check, oly the name member is examined. - * @return Whether the item should be filtered (and not shown). - */ - bool is_filtered( const comestible_inv_listitem &it ) const; - /** - * Same as the other, but checks the real item. - */ - bool is_filtered( const item &it ) const; /** * Scroll @ref index, by given offset, set redraw to true, * @param offset Must not be 0. @@ -292,31 +294,31 @@ class comestible_inventory_pane */ comestible_inv_listitem *get_cur_item_ptr(); /** - * Set the filter string, disables filtering when the filter string is empty. + * Set the filter string */ void set_filter( const std::string &new_filter ); - /** - * Insert additional category headers on the top of each page. - */ - void paginate(); - - //TODO:docs'n'stuffs - int itemsPerPage; - std::vector columns; - comestible_inv_columns default_sortby; + void start_user_filtering( int h, int w ); + //adds things this can sort on. List is provided by parent void add_sort_enries( uilist &sm ); - void init( std::vector c, int items_per_page, catacurses::window w, - std::array *s ); - void save_settings( bool reset ); - void do_filter( int h, int w ); - void print_items(); - private: - /** Scroll to next non-header entry */ - void skip_category_headers( int offset ); - /** Only add offset to index, but wrap around! */ - void mod_index( int offset ); - mutable std::map> filtercache; + std::array *squares; + comestible_inv_area *get_square( comestible_inv_area_info::aim_location loc ) { + return &( ( *squares )[loc] ); + } + comestible_inv_area *get_square( size_t loc ) { + return &( ( *squares )[loc] ); + } + // set the pane's area via its square, and whether it is viewing a vehicle's cargo + void set_area( comestible_inv_area *square, bool show_vehicle ) { + cur_area = square; + viewing_cargo = square->has_vehicle() && show_vehicle; + } + comestible_inv_area *get_area() const { + return cur_area; + } + bool is_in_vehicle() const { + return viewing_cargo; + } }; #endif From c2587ff66759eeb06966f513011a14d564766555 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 25 Aug 2019 12:39:01 -0400 Subject: [PATCH 12/19] travis error 4 --- src/comestible_inv.cpp | 30 ++++++++++++++++++------------ src/comestible_inv_pane.cpp | 8 ++++---- src/handle_action.cpp | 5 ++--- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 4d7b9699196d2..2963ca92ab63c 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -141,11 +141,17 @@ void comestible_inventory::save_settings() comestible_inv_area *comestible_inventory::get_square( const std::string &action ) { - for( size_t i = 0; i < squares.size(); i++ ) { - if( action == squares[i].info.actionname ) { - return &squares[i]; + for( auto &i : squares ) { + if( action == i.info.actionname ) { + return &i; } } + + //for( size_t i = 0; i < squares.size(); i++ ) { + // if( action == squares[i].info.actionname ) { + // return &squares[i]; + // } + //} return nullptr; } @@ -466,8 +472,8 @@ void comestible_inventory::display( int bio ) if( it->is_food_container() ) { it = &it->contents.front(); } - std::string food_name = it->nname( it->typeId() ); - g->u.craft( tripoint_zero, string_format( "c:%s", food_name ) ); + std::string food_name = item::nname( it->typeId() ); + g->u.craft( tripoint_zero, string_format( "c:%s,", food_name ) ); //TODO: next 2 lines seem hacky - refreshing twice? //without 1st line we can see craft menu after it closes //without 2nd line we can't see comestible menu after crafting closes @@ -577,7 +583,8 @@ void comestible_inventory::refresh_minimap() draw_border( mm_border ); // minor addition to border for AIM_ALL, sorta hacky if( pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { - mvwprintz( mm_border, point( 1, 0 ), c_light_gray, utf8_truncate( _( "Mul" ), minimap_width ) ); + //point(1,0) - point_east so travis is happy + mvwprintz( mm_border, point_east, c_light_gray, utf8_truncate( _( "Mul" ), minimap_width ) ); } // refresh border, then minimap wrefresh( mm_border ); @@ -695,7 +702,7 @@ void comestible_inventory::heat_up( item *it_to_heat ) std::vector hotplates_map = map_inv.items_with( filter ); //hotplates.insert(hotplates.end(), hotplates_map.begin(), hotplates_map.end()); - can_use_hotplate = ( hotplates.size() > 0 ) || ( hotplates_map.size() > 0 ); + can_use_hotplate = ( !hotplates.empty() ) || ( !hotplates_map.empty() ); //check we can actually heat up if( !has_heat_item && !can_use_hotplate ) { @@ -723,15 +730,14 @@ void comestible_inventory::heat_up( item *it_to_heat ) counter++; } - for( size_t i = 0; i < hotplates.size(); i++ ) { + for( auto &i : hotplates ) { sm.addentry( counter, true, 'a' + counter, string_format( _( "%s in inventory" ), - hotplates.at( i )->display_name() ) ); + i->display_name() ) ); counter++; } - - for( size_t i = 0; i < hotplates_map.size(); i++ ) { + for( auto &i : hotplates_map ) { sm.addentry( counter, true, 'a' + counter, string_format( _( "%s nearby" ), - hotplates_map.at( i )->display_name() ) ); + i->display_name() ) ); counter++; } sm.query(); diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index 8142480319350..ddf49c31b71f8 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -78,7 +78,7 @@ struct col_data { }; // *INDENT-OFF* -static const col_data get_col_data(comestible_inv_columns col) { +static col_data get_col_data(comestible_inv_columns col) { static std::array col_data = { { {COLUMN_NAME, _("Name (charges)"),0, 'n', _("name")}, @@ -549,8 +549,8 @@ void comestible_inventory_pane::recalc() volume = 0_ml; weight = 0_gram; std::vector loc = cur_area->info.multi_locations; - for( size_t i = 0; i < loc.size(); i++ ) { - comestible_inv_area *s = &( ( *squares )[loc[i]] ); + for( auto &i : loc ) { + comestible_inv_area *s = &( ( *squares )[i] ); // Deal with squares with ground + vehicle storage // Also handle the case when the other tile covers vehicle // or the ground below the vehicle. @@ -709,7 +709,7 @@ void comestible_inventory_pane::redraw() draw_border( w, BORDER_COLOR ); mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), get_col_data( sortby ).sort_name ); - if( title.size() != 0 ) { + if( !title.empty() ) { std::string title_string = string_format( "<< %s >>", title ); mvwprintz( w, point( ( getmaxx( w ) - title_string.size() ) / 2, 0 ), c_light_cyan, title_string ); } diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 2ff5aaa83f357..e2c2c842b6ee7 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1639,6 +1639,8 @@ bool game::handle_action() switch( act ) { case ACTION_NULL: case NUM_ACTIONS: + //TODO:delete eat(); + eat(); break; // dummy entries case ACTION_ACTIONMENU: case ACTION_MAIN_MENU: @@ -1875,9 +1877,6 @@ bool game::handle_action() case ACTION_EAT: comestible_inv(); - if( false ) { - eat(); //TODO: just to make travis happy; delete after done testing - } break; case ACTION_OPEN_CONSUME: From 270986523bb8537fb554b9895bd864eb6af47601 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 25 Aug 2019 13:01:44 -0400 Subject: [PATCH 13/19] travis error 5 --- data/raw/keybindings.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index 9f95c36bfd84e..963d02e084dd8 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -2603,7 +2603,7 @@ "id": "SAVE_DEFAULT", "category": "ADVANCED_INVENTORY", "name": "Save default layout" - }, + }, { "type": "keybinding", "id": "UP", @@ -2770,7 +2770,7 @@ "name": "Select items @ all 9 fields", "bindings": [ { "input_method": "keyboard", "key": "a" }, { "input_method": "keyboard", "key": "A" } ] }, - { + { "type": "keybinding", "id": "ITEMS_AROUND_I_W", "category": "COMESTIBLE_INVENTORY", @@ -2796,21 +2796,20 @@ "category": "COMESTIBLE_INVENTORY", "name": "Save default layout" }, - { "type": "keybinding", "id": "CONSUME_FOOD", "category": "COMESTIBLE_INVENTORY", "name": "Consume selected", "bindings": [ { "input_method": "keyboard", "key": "RETURN" } ] - }, + }, { "type": "keybinding", "id": "SWITCH_FOOD", "category": "COMESTIBLE_INVENTORY", "name": "Switch between Food/Drugs", "bindings": [ { "input_method": "keyboard", "key": "z" }, { "input_method": "keyboard", "key": "Z" } ] - }, + }, { "type": "keybinding", "id": "HEAT_UP", From f8451322d38dd06e8fa0ba4ad9b75f7b689438af Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 10 Sep 2019 10:08:40 -0400 Subject: [PATCH 14/19] fixing bug with crafting fixing bug with heating up food in car adding hunger,quench,pain / power to the header adding condition indicators to food --- data/raw/keybindings.json | 7 + src/activity_handlers.cpp | 2 +- src/character.cpp | 20 +++ src/character.h | 1 + src/comestible_inv.cpp | 285 ++++++++++++++++-------------------- src/comestible_inv.h | 21 +-- src/comestible_inv_area.cpp | 4 +- src/comestible_inv_area.h | 225 ++++++++++++++-------------- src/comestible_inv_pane.cpp | 221 +++++++++++++++------------- src/comestible_inv_pane.h | 56 ++++--- src/panels.cpp | 18 +-- 11 files changed, 421 insertions(+), 439 deletions(-) diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index 260c8fdbefada..44189850af4d0 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -2867,6 +2867,13 @@ "name": "Start crafting with selected", "bindings": [ { "input_method": "keyboard", "key": "&" } ] }, + { + "type": "keybinding", + "id": "SHOW_HELP", + "category": "COMESTIBLE_INVENTORY", + "name": "Start crafting with selected", + "bindings": [ { "input_method": "keyboard", "key": "F1" } ] + }, { "type": "keybinding", "id": "SCROLL_UP", diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 5d085c975cb96..5e46ef6150377 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -3383,7 +3383,7 @@ void activity_handlers::craft_do_turn( player_activity *act, player *p ) if( craft->item_counter >= 10'000'000 ) { item craft_copy = *craft; act->targets.front().remove_item(); - p->cancel_activity(); + act->set_to_null(); p->complete_craft( craft_copy, loc ); if( is_long ) { if( p->making_would_work( p->lastrecipe, craft_copy.charges ) ) { diff --git a/src/character.cpp b/src/character.cpp index fe01c9d910728..017e869f8260a 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -2511,6 +2511,26 @@ std::pair Character::get_fatigue_description() const return std::make_pair( fatigue_string, fatigue_color ); } +std::pair Character::get_power_description() const +{ + nc_color c_pwr = c_red; + std::string s_pwr; + if( max_power_level == 0 ) { + s_pwr = "--"; + c_pwr = c_light_gray; + } else { + if( power_level >= max_power_level / 2 ) { + c_pwr = c_light_blue; + } else if( power_level >= max_power_level / 3 ) { + c_pwr = c_yellow; + } else if( power_level >= max_power_level / 4 ) { + c_pwr = c_red; + } + s_pwr = to_string( power_level ); + } + return std::make_pair( s_pwr, c_pwr ); +} + void Character::mod_thirst( int nthirst ) { set_thirst( thirst + nthirst ); diff --git a/src/character.h b/src/character.h index 38a67930f6bed..33939dbd71b84 100644 --- a/src/character.h +++ b/src/character.h @@ -264,6 +264,7 @@ class Character : public Creature, public visitable virtual std::pair get_thirst_description() const; virtual std::pair get_hunger_description() const; virtual std::pair get_fatigue_description() const; + virtual std::pair get_power_description() const; virtual int get_fatigue() const; virtual int get_sleep_deprivation() const; diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 2963ca92ab63c..ab01b227ad71c 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -42,6 +42,7 @@ #include "pimpl.h" #include "bionics.h" #include "comestible_inv.h" +#include "recipe_dictionary.h" #include #include @@ -139,19 +140,13 @@ void comestible_inventory::save_settings() } } -comestible_inv_area *comestible_inventory::get_square( const std::string &action ) +comestible_inv_area *comestible_inventory::get_area( const std::string &action ) { for( auto &i : squares ) { if( action == i.info.actionname ) { return &i; } } - - //for( size_t i = 0; i < squares.size(); i++ ) { - // if( action == squares[i].info.actionname ) { - // return &squares[i]; - // } - //} return nullptr; } @@ -175,8 +170,6 @@ void comestible_inventory::init() point( colstart + ( w_width - ( minimap_width + 1 ) ), headstart + 1 ) ); window = catacurses::newwin( w_height, w_width, point( colstart, headstart + head_height ) ); - - uistate.comestible_save.exit_code = exit_none; std::vector columns; @@ -192,7 +185,6 @@ void comestible_inventory::init() } int itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff pane.init( columns, itemsPerPage, window, &squares ); - set_pane_legend(); if( uistate.comestible_save.bio == -1 ) { pane.special_filter = []( const item & it ) { const std::string n = it.get_category().name(); @@ -219,15 +211,22 @@ void comestible_inventory::init() } } -void comestible_inventory::set_pane_legend() +void comestible_inventory::set_additional_info() { std::vector data; + std::pair desc; if( uistate.comestible_save.bio == -1 ) { - data.push_back( { 'z', c_light_gray, "Switch Food/Drugs" } ); - data.push_back( { 'h', c_light_red, "Warm up food" } ); - data.push_back( { '&', c_cyan, "Craft with" } ); + desc = g->u.get_hunger_description(); + data.push_back( { string_format( "%s %s", _( "Food :" ), colorize( desc.first, desc.second ) ), point_zero, c_dark_gray } ); + desc = g->u.get_thirst_description(); + data.push_back( { string_format( "%s %s", _( "Drink:" ), colorize( desc.first, desc.second ) ), point_south, c_dark_gray } ); + desc = g->u.get_pain_description(); + data.push_back( { string_format( "%s %s", _( "Pain :" ), colorize( desc.first, desc.second ) ), point( 0, 2 ), c_dark_gray } ); + } else { + desc = g->u.get_power_description(); + data.push_back( { string_format( "%s %s", _( "Power :" ), colorize( desc.first, desc.second ) ), point_zero, c_dark_gray } ); } - pane.legend = data; + pane.additional_info = data; pane.needs_redraw = true; } @@ -243,7 +242,7 @@ bool comestible_inventory::show_sort_menu( ) { uilist sm; sm.text = _( "Sort by... " ); - pane.add_sort_enries( sm ); + pane.add_sort_entries( sm ); sm.query(); if( sm.ret < 0 ) { @@ -297,15 +296,16 @@ void comestible_inventory::display( int bio ) ctxt.register_action( "ITEMS_AROUND_I_W" ); ctxt.register_action( "ITEMS_DRAGGED_CONTAINER" ); + ctxt.register_action( "CONSUME_FOOD" ); if( uistate.comestible_save.bio == -1 ) { - ctxt.register_action( "CONSUME_FOOD" ); ctxt.register_action( "SWITCH_FOOD" ); ctxt.register_action( "HEAT_UP" ); ctxt.register_action( "CRAFT_WITH" ); + ctxt.register_action( "SHOW_HELP" ); } exit = false; - redo( true, true ); + refresh( true, true ); using ai = comestible_inv_area_info; while( !exit ) { @@ -314,6 +314,9 @@ void comestible_inventory::display( int bio ) return; } + if( recalc ) { + set_additional_info(); + } pane.redraw(); if( redraw ) { @@ -324,9 +327,12 @@ void comestible_inventory::display( int bio ) Messages::display_messages( head, 2, 1, w_width - 1, head_height - 2 ); draw_minimap(); - const std::string msg = _( "< [?] show help >" ); - mvwprintz( head, point( w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, 0 ), - c_white, msg ); + if( uistate.comestible_save.bio == -1 ) { + const std::string msg = string_format( _( "< [%s] Statuses info >" ), + ctxt.get_desc( "SHOW_HELP" ) ); + mvwprintz( head, point( w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, 0 ), + c_white, msg ); + } if( g->u.has_watch() ) { const std::string time = to_string_time_of_day( calendar::turn ); mvwprintz( head, point( 2, 0 ), c_white, time ); @@ -334,7 +340,7 @@ void comestible_inventory::display( int bio ) wrefresh( head ); refresh_minimap(); } - redo( false, false ); + refresh( false, false ); // current item in source pane, might be null comestible_inv_listitem *sitem = pane.get_cur_item_ptr(); @@ -347,17 +353,17 @@ void comestible_inventory::display( int bio ) pane.needs_redraw = true; // We redraw to force the color change of the highlighted line and header text. } else if( action == "HELP_KEYBINDINGS" ) { - redo( recalc, true ); - } else if( ( new_square = get_square( action ) ) != nullptr ) { + refresh( recalc, true ); + } else if( ( new_square = get_area( action ) ) != nullptr ) { if( pane.get_area()->info.id == new_square->get_relative_location() ) { //DO NOTHING } else if( new_square->is_valid() ) { pane.set_area( new_square, new_square->is_vehicle_default() ); pane.index = 0; - redo( true, true ); + refresh( true, true ); } else { popup( _( "You can't put items there!" ) ); - redo( recalc, true ); // to clear the popup + refresh( recalc, true ); // to clear the popup } } else if( action == "TOGGLE_FAVORITE" ) { if( sitem == nullptr || !sitem->is_item_entry() ) { @@ -367,12 +373,12 @@ void comestible_inventory::display( int bio ) it->set_favorite( !it->is_favorite ); } // recalc = true; In case we've merged faved and unfaved items - redo( true, true ); + refresh( true, true ); } else if( action == "SORT" ) { if( show_sort_menu( ) ) { - redo( true, redraw ); + refresh( true, redraw ); } - redo( recalc, true ); + refresh( recalc, true ); } else if( action == "FILTER" ) { draw_item_filter_rules( pane.window, 1, 11, item_filter_type::FILTER ); pane.start_user_filtering( w_height - 1, w_width / 2 - 4 ); @@ -390,7 +396,7 @@ void comestible_inventory::display( int bio ) sitem->autopickup = true; } - redo( true, redraw ); + refresh( true, redraw ); } else if( action == "EXAMINE" ) { if( sitem == nullptr || !sitem->is_item_entry() ) { continue; @@ -408,10 +414,10 @@ void comestible_inventory::display( int bio ) // If examining the item did not create a new activity, we have to remove // "return to AIM". do_return_entry(); - assert( g->u.has_activity( activity_id( "ACT_ADV_INVENTORY" ) ) ); + assert( g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ); ret = g->inventory_item_menu( idx, info_startx, info_width, game::RIGHT_OF_INFO ); //src == comestible_inventory::side::left ? game::LEFT_OF_INFO : game::RIGHT_OF_INFO); - if( !g->u.has_activity( activity_id( "ACT_ADV_INVENTORY" ) ) ) { + if( !g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ) { exit = true; } else { g->u.cancel_activity(); @@ -420,7 +426,7 @@ void comestible_inventory::display( int bio ) if( pane.get_area()->info.id == ai::AIM_INVENTORY ) { g->u.inv.restack( g->u ); } - redo( true, redraw ); + refresh( true, redraw ); } else { item &it = *sitem->items.front(); std::vector vThisItem; @@ -436,7 +442,7 @@ void comestible_inventory::display( int bio ) } else if( ret == KEY_PPAGE || ret == KEY_UP ) { pane.scroll_by( -1 ); } - redo( recalc, true ); // item info window overwrote the other pane and the header + refresh( recalc, true ); // item info window overwrote the other pane and the header } else if( action == "QUIT" ) { exit = true; } else if( action == "PAGE_DOWN" ) { @@ -454,38 +460,69 @@ void comestible_inventory::display( int bio ) pane.set_area( pane.get_area(), !pane.is_in_vehicle() ); pane.index = 0; // make sure to update the minimap as well! - redo( recalc, true ); + refresh( recalc, true ); pane.needs_recalc = true; } } else { popup( _( "No vehicle there!" ) ); - redo( recalc, true ); + refresh( recalc, true ); } } else if( action == "SWITCH_FOOD" ) { uistate.comestible_save.show_food = !uistate.comestible_save.show_food; pane.title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; - redo( true, redraw ); + refresh( true, redraw ); } else if( action == "HEAT_UP" ) { heat_up( sitem->items.front() ); - } else if( action == "CRAFT_WITH" ) { + } else if( action == "CRAFT_WITH" ) { + do_return_entry(); + + assert( g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ); + item *it = sitem->items.front(); if( it->is_food_container() ) { it = &it->contents.front(); } std::string food_name = item::nname( it->typeId() ); g->u.craft( tripoint_zero, string_format( "c:%s,", food_name ) ); - //TODO: next 2 lines seem hacky - refreshing twice? - //without 1st line we can see craft menu after it closes - //without 2nd line we can't see comestible menu after crafting closes - g->refresh_all(); - redo( recalc, true ); + + if( !g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ) { + exit = true; + } else { + //TODO: next 2 lines seem hacky - refreshing twice? + //without 1st line we can see craft menu after it closes + //without 2nd line we can't see comestible menu after crafting closes + + g->u.cancel_activity(); + g->refresh_all(); + refresh( recalc, true ); + } + } else if( action == "SHOW_HELP" ) { + std::string desc; + std::string status; + status = ctxt.get_desc( "HEAT_UP" ); + desc += colorize( string_format( "%c", status[0] ), c_red ); + desc += colorize( string_format( + _( ": this food is frozen and cannot be consumed. Press %s to attempt reheating it.\n" ), status ), + c_light_gray ); + + status = ctxt.get_desc( "CRAFT_WITH" ); + desc += colorize( string_format( "%c", status[0] ), c_cyan ); + desc += colorize( string_format( + _( ": this item cannot be eaten in its current form. Press %s to attempt cooking with it.\n" ), + status ), c_light_gray ); + + desc += colorize( "!", c_light_red ); + desc += colorize( string_format( _( ": eating this will be considered stealing." ), status ), + c_light_gray ); + + popup( desc ); + refresh( recalc, true ); } else if( action == "CONSUME_FOOD" ) { player &p = g->u; item *it = sitem->items.front(); int pos = p.get_item_position( it ); if( pos != INT_MIN ) { p.consume( pos ); - } else if( p.consume_item( *it ) ) { if( it->is_food_container() ) { it->contents.erase( it->contents.begin() ); @@ -510,7 +547,6 @@ void comestible_inventory::display( int bio ) loc = item_location( map_cursor( target ), it ); } } - loc.remove_item(); } } @@ -518,10 +554,11 @@ void comestible_inventory::display( int bio ) } } -static const trait_id trait_GRAZER( "GRAZER" ); -static const trait_id trait_RUMINANT( "RUMINANT" ); void comestible_inv( int b ) { + static const trait_id trait_GRAZER( "GRAZER" ); + static const trait_id trait_RUMINANT( "RUMINANT" ); + player &p = g->u; map &m = g->m; @@ -637,7 +674,7 @@ void comestible_inventory::do_return_entry() save_settings(); } -void comestible_inventory::redo( bool needs_recalc, bool needs_redraw ) +void comestible_inventory::refresh( bool needs_recalc, bool needs_redraw ) { recalc = needs_recalc; pane.needs_recalc = needs_recalc; @@ -648,128 +685,62 @@ void comestible_inventory::redo( bool needs_recalc, bool needs_redraw ) void comestible_inventory::heat_up( item *it_to_heat ) { + //in case we want to warm up a certail quantity later on + int batch_size = 1; + player &p = g->u; - inventory map_inv = inventory(); - map_inv.form_from_map( p.pos(), 1 ); - - bool has_heat_item = false; - bool is_near_fire = false; - bool can_use_bio = false; - bool can_use_hotplate = false; - - //TODO: I think can use crafting.cpp - - // comp_selection player::select_item_component(){} - //or - // comp_selection player::select_tool_component(){} - //to search and select items - - //first find tools we can use - const std::function &heat_filter = - []( const item & it ) { - - bool can_heat = ( it.get_use( "HEAT_FOOD" ) != nullptr ); - return can_heat; - }; - - has_heat_item = p.has_item_with( heat_filter ); - if( !has_heat_item ) { - has_heat_item = map_inv.has_item_with( heat_filter ); - } - if( has_heat_item ) { - if( g->m.has_nearby_fire( p.pos() ) ) { - is_near_fire = true; - } else if( p.has_active_bionic( bionic_id( "bio_tools" ) ) && p.power_level > 10 ) { - can_use_bio = true; + // basically we want a recipe that satisfies all the requirements for warming food up + // water seems exactly what we need, so find it and use it. + //might be good idea to create a dummy recipe + item water = item( "water_clean", 0 ); + recipe_subset lr = p.get_learned_recipes(); + std::vector < const recipe * > water_recipes = lr.search_result( water.typeId() ); + requirement_data req = water_recipes[0]->requirements(); + + const std::vector> req_tools = req.get_tools(); + const std::vector> req_qual = req.get_qualities(); + + // see if we have required tools (e.g. BOIL 1) + bool has_qual = true; + for( const auto &i : req_qual ) { + for( auto &rq : i ) { + if( !p.crafting_inventory().has_quality( rq.type, rq.level, batch_size ) ) { + has_qual = false; + break; + } } } - - const std::function &filter = - []( const item & it ) { - - if( !it.is_tool() ) { - return false; - } - bool is_hotplate = ( it.get_use( "HOTPLATE" ) != nullptr ); - if( !is_hotplate ) { - return false; - } - - return it.units_remaining( g->u ) >= it.type->charges_to_use(); - }; - - std::vector hotplates = p.items_with( filter ); - std::vector hotplates_map = map_inv.items_with( filter ); - //hotplates.insert(hotplates.end(), hotplates_map.begin(), hotplates_map.end()); - - can_use_hotplate = ( !hotplates.empty() ) || ( !hotplates_map.empty() ); - - //check we can actually heat up - if( !has_heat_item && !can_use_hotplate ) { - popup( _( "You don't have a suitable container or hotplate with enough charges." ) ); - redo( recalc, true ); + if( !has_qual ) { + popup( "You don't have necessary tools to heat up your food." ); return; } - if( has_heat_item && !can_use_hotplate ) { - if( !is_near_fire && !can_use_bio ) { - popup( _( "You need to be near fire to heat an item in a container." ) ); - redo( recalc, true ); - return; + // see if we have enough charges or fire + inventory crafting_inv; + crafting_inv.form_from_map( p.pos(), PICKUP_RANGE, &p ); + std::vector> tool_selections; + for( const auto &it : req_tools ) { + comp_selection ts = p.select_tool_component( + it, batch_size, crafting_inv, DEFAULT_HOTKEYS, true, true, []( int charges ) { + return charges / 20 + charges % 20; + } ); + if( ts.use_from == cancel ) { + refresh( recalc, true ); + return; //Never mind. } - } - //give user options to chose from - int choice = -1; - if( !( has_heat_item && is_near_fire ) ) { - uilist sm; - sm.text = _( "Choose a way to heat an item..." ); - int counter = 0; - if( can_use_bio ) { - sm.addentry( counter, true, 'a' + counter, _( "use bio tools" ) ); - counter++; - } - - for( auto &i : hotplates ) { - sm.addentry( counter, true, 'a' + counter, string_format( _( "%s in inventory" ), - i->display_name() ) ); - counter++; - } - for( auto &i : hotplates_map ) { - sm.addentry( counter, true, 'a' + counter, string_format( _( "%s nearby" ), - i->display_name() ) ); - counter++; - } - sm.query(); - - if( sm.ret < 0 ) { - //'Never mind' - redo( recalc, true ); + //no item found + if( ts.comp.type == itype_id( "null" ) ) { + popup( "You don't have a neraby fire or tool with enough charges to heat up your food." ); return; } - choice = sm.ret; + + tool_selections.push_back( ts ); } - //use charges as needed; choice == -1 if we can use fire - if( choice != -1 ) { - if( can_use_bio && choice == 0 ) { - p.charge_power( -10 ); - } else { - if( can_use_bio ) { - choice--; - } - item *it_choice; - if( static_cast( choice ) < hotplates.size() ) { - it_choice = hotplates[choice]; - } else { - choice -= hotplates.size(); - it_choice = hotplates_map[choice]; - } - int charges_to_use = it_choice->type->charges_to_use(); - std::list used = {}; - tripoint pos = tripoint(); - it_choice->use_charges( it_choice->typeId(), charges_to_use, used, pos ); - } + for( auto &tool : tool_selections ) { + p.consume_tools( tool, batch_size ); } //actually heat up the item diff --git a/src/comestible_inv.h b/src/comestible_inv.h index a51f10ff0d468..d8616c4e3d0e1 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -66,24 +66,19 @@ class comestible_inventory bool exit; - // store/load settings (such as index, filter, etc) + void init(); + //sets recalculate and redraw for this and pane + void refresh( bool needs_recalc, bool needs_redraw ); void save_settings(); - //void load_settings(); // used to return back to AIM when other activities queued are finished void do_return_entry(); - //sets recalculate and redraw for this and pane - void redo( bool needs_recalc, bool needs_redraw ); - void init(); - void set_pane_legend(); + // any additional info, relevant for menu, but not part of main data + void set_additional_info(); /** - * Translate an action ident from the input context to an aim_location. - * @param action Action ident to translate - * @param ret If the action ident referred to a location, its id is stored - * here. Only valid when the function returns true. - * @return true if the action did refer to an location (which has been - * stored in ret), false otherwise. + * Translate an action ident from the input context to an comestible_inv_area. + * @param action one of ctxt.register_action */ - comestible_inv_area *get_square( const std::string &action ); + comestible_inv_area *get_area( const std::string &action ); /** * Show the sort-by menu and change the sorting of this pane accordingly. * @return whether the sort order was actually changed. diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index d8aff0ad23352..0633c77087ca2 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -93,7 +93,6 @@ void comestible_inv_area::init() if( veh_part >= 0 ) { desc[0] = veh->name; is_valid_location = true; - //max_size = MAX_ITEM_IN_VEHICLE_STORAGE; } else { veh = nullptr; is_valid_location = false; @@ -126,7 +125,6 @@ void comestible_inv_area::init() veh_part = -1; } is_valid_location = has_vehicle() || g->m.can_put_items_ter_furn( pos ); - //max_size = MAX_ITEM_IN_SQUARE; if( has_vehicle() ) { desc[1] = vpart_position( *veh, veh_part ).get_label().value_or( "" ); } @@ -254,7 +252,7 @@ std::string comestible_inv_area::get_name( bool use_vehicle ) const assert( has_vehicle() ); return veh->name; } else { - return info.name; + return info.get_name(); } } diff --git a/src/comestible_inv_area.h b/src/comestible_inv_area.h index 4e8d952a2af80..be9862caf6ddd 100644 --- a/src/comestible_inv_area.h +++ b/src/comestible_inv_area.h @@ -21,95 +21,104 @@ * Defines the source of item stacks. */ struct comestible_inv_area_info { - enum area_type { - AREA_TYPE_PLAYER, - AREA_TYPE_GROUND, - AREA_TYPE_MULTI - }; - - enum aim_location { - AIM_SOUTHWEST, - AIM_SOUTH, - AIM_SOUTHEAST, - AIM_WEST, - AIM_CENTER, - AIM_EAST, - AIM_NORTHWEST, - AIM_NORTH, - AIM_NORTHEAST, - - AIM_DRAGGED, - AIM_INVENTORY, - AIM_WORN, - - AIM_ALL, - AIM_ALL_I_W, - - NUM_AIM_LOCATIONS - }; - - - - const aim_location id; - // Used for the small overview 3x3 grid - point hscreen; - // relative (to the player) position of the map point - tripoint default_offset; - - area_type type; - - /** Long name, displayed, translated */ - const std::string name; - /** Appears as part of the list */ - const std::string shortname; - /** Appears as part of the legend at the top right */ - const std::string minimapname; - - const aim_location relative_location; - const std::string actionname; - - std::vector multi_locations = {}; - - bool has_area( aim_location loc ) const { - return ( std::find( multi_locations.begin(), multi_locations.end(), - loc ) != multi_locations.end() ); - } - - comestible_inv_area_info( aim_location id, int hscreenx, int hscreeny, tripoint off, - const std::string &name, const std::string &shortname, - const std::string &minimapname, const aim_location relative_location, - const std::string &actionname ) : id( id ), - hscreen( hscreenx, hscreeny ), default_offset( off ), name( name ), shortname( shortname ), - minimapname( minimapname ), relative_location( relative_location ), actionname( actionname ) { - static const std::array< aim_location, 9> ground_locations = { { - AIM_SOUTHWEST, - AIM_SOUTH, - AIM_SOUTHEAST, - AIM_WEST, - AIM_CENTER, - AIM_EAST, - AIM_NORTHWEST, - AIM_NORTH, - AIM_NORTHEAST - } + enum area_type { + AREA_TYPE_PLAYER, + AREA_TYPE_GROUND, + AREA_TYPE_MULTI + }; + + enum aim_location { + AIM_SOUTHWEST, + AIM_SOUTH, + AIM_SOUTHEAST, + AIM_WEST, + AIM_CENTER, + AIM_EAST, + AIM_NORTHWEST, + AIM_NORTH, + AIM_NORTHEAST, + + AIM_DRAGGED, + AIM_INVENTORY, + AIM_WORN, + + AIM_ALL, + AIM_ALL_I_W, + + NUM_AIM_LOCATIONS }; - if( id == AIM_ALL ) { - type = AREA_TYPE_MULTI; - multi_locations = std::vector( ground_locations.begin(), ground_locations.end() ); - } else if( id == AIM_ALL_I_W ) { - type = AREA_TYPE_MULTI; - multi_locations = std::vector( ground_locations.begin(), ground_locations.end() ); - multi_locations.push_back( AIM_INVENTORY ); - multi_locations.push_back( AIM_WORN ); - } else { - if( id == AIM_INVENTORY || id == AIM_WORN ) { - type = AREA_TYPE_PLAYER; + + public: + + const aim_location id; + // Used for the small overview 3x3 grid + point hscreen; + // relative (to the player) position of the map point + tripoint default_offset; + private: + /** Long name, displayed */ + const std::string name; + /** Appears as part of the list */ + const std::string shortname; + public: + + area_type type; + + const std::string get_name() const { + return _( name ); + } + const std::string get_shortname() const { + return _( shortname ); + } + + /** Appears as part of the legend at the top right */ + const std::string minimapname; + + const aim_location relative_location; + const std::string actionname; + + std::vector multi_locations = {}; + + bool has_area( aim_location loc ) const { + return ( std::find( multi_locations.begin(), multi_locations.end(), + loc ) != multi_locations.end() ); + } + + comestible_inv_area_info( aim_location id, int hscreenx, int hscreeny, tripoint off, + const std::string &name, const std::string &shortname, + const std::string &minimapname, const aim_location relative_location, + const std::string &actionname ) : id( id ), + hscreen( hscreenx, hscreeny ), default_offset( off ), name( name ), shortname( shortname ), + minimapname( minimapname ), relative_location( relative_location ), actionname( actionname ) { + static const std::array< aim_location, 9> ground_locations = { { + AIM_SOUTHWEST, + AIM_SOUTH, + AIM_SOUTHEAST, + AIM_WEST, + AIM_CENTER, + AIM_EAST, + AIM_NORTHWEST, + AIM_NORTH, + AIM_NORTHEAST + } + }; + if( id == AIM_ALL ) { + type = AREA_TYPE_MULTI; + multi_locations = std::vector( ground_locations.begin(), ground_locations.end() ); + } else if( id == AIM_ALL_I_W ) { + type = AREA_TYPE_MULTI; + multi_locations = std::vector( ground_locations.begin(), ground_locations.end() ); + multi_locations.push_back( AIM_INVENTORY ); + multi_locations.push_back( AIM_WORN ); } else { - type = AREA_TYPE_GROUND; + if( id == AIM_INVENTORY || id == AIM_WORN ) { + type = AREA_TYPE_PLAYER; + } else { + type = AREA_TYPE_GROUND; + } + multi_locations = { id }; } - multi_locations = { id }; } - } }; @@ -122,22 +131,22 @@ class comestible_inv_area static comestible_inv_area_info get_info(comestible_inv_area_info::aim_location loc) { using i = comestible_inv_area_info; static const std::array< comestible_inv_area_info, comestible_inv_area_info::NUM_AIM_LOCATIONS> area_info = { { - { i::AIM_SOUTHWEST, 30, 3, tripoint_south_west, _("South West"), _("SW"), "1", i::AIM_WEST, "ITEMS_SW" }, - { i::AIM_SOUTH, 33, 3, tripoint_south, _("South"), _("S"), "2", i::AIM_SOUTHWEST, "ITEMS_S"}, - { i::AIM_SOUTHEAST, 36, 3, tripoint_south_east, _("South East"), _("SE"), "3", i::AIM_SOUTH, "ITEMS_SE"}, - { i::AIM_WEST, 30, 2, tripoint_west, _("West"), _("W"), "4", i::AIM_NORTHWEST, "ITEMS_W" }, - { i::AIM_CENTER, 33, 2, tripoint_zero, _("Directly below you"), _("DN"), "5", i::AIM_CENTER, "ITEMS_CE"}, - { i::AIM_EAST, 36, 2, tripoint_east, _("East"), _("E"), "6", i::AIM_SOUTHEAST, "ITEMS_E" }, - { i::AIM_NORTHWEST, 30, 1, tripoint_north_west, _("North West"), _("NW"), "7", i::AIM_NORTH, "ITEMS_NW"}, - { i::AIM_NORTH, 33, 1, tripoint_north, _("North"), _("N"), "8", i::AIM_NORTHEAST, "ITEMS_N" }, - { i::AIM_NORTHEAST, 36, 1, tripoint_north_east, _("North East"), _("NE"), "9", i::AIM_EAST, "ITEMS_NE" }, - - { i::AIM_DRAGGED, 25, 1, tripoint_zero, _("Grabbed Vehicle"), _("GR"), "D", i::AIM_DRAGGED, "ITEMS_DRAGGED_CONTAINER" }, - { i::AIM_INVENTORY, 25, 2, tripoint_zero, _("Inventory"), _("I"), "I", i::AIM_INVENTORY, "ITEMS_INVENTORY" }, - { i::AIM_WORN, 22, 2, tripoint_zero, _("Worn Items"), _("W"), "W", i::AIM_WORN, "ITEMS_WORN"}, - - { i::AIM_ALL, 25, 3, tripoint_zero, _("Surrounding area"), "", "A", i::AIM_ALL, "ITEMS_AROUND" }, - { i::AIM_ALL_I_W, 18, 3, tripoint_zero, _("Everything"), "", "A+I+W", i::AIM_ALL_I_W, "ITEMS_AROUND_I_W" } + { i::AIM_SOUTHWEST, 30, 3, tripoint_south_west, translate_marker("South West"), translate_marker("SW"), "1", i::AIM_WEST, "ITEMS_SW" }, + { i::AIM_SOUTH, 33, 3, tripoint_south, translate_marker("South"), translate_marker("S"), "2", i::AIM_SOUTHWEST, "ITEMS_S"}, + { i::AIM_SOUTHEAST, 36, 3, tripoint_south_east, translate_marker("South East"), translate_marker("SE"), "3", i::AIM_SOUTH, "ITEMS_SE"}, + { i::AIM_WEST, 30, 2, tripoint_west, translate_marker("West"), translate_marker("W"), "4", i::AIM_NORTHWEST, "ITEMS_W" }, + { i::AIM_CENTER, 33, 2, tripoint_zero, translate_marker("Directly below you"), translate_marker("DN"), "5", i::AIM_CENTER, "ITEMS_CE"}, + { i::AIM_EAST, 36, 2, tripoint_east, translate_marker("East"), translate_marker("E"), "6", i::AIM_SOUTHEAST, "ITEMS_E" }, + { i::AIM_NORTHWEST, 30, 1, tripoint_north_west, translate_marker("North West"), translate_marker("NW"), "7", i::AIM_NORTH, "ITEMS_NW"}, + { i::AIM_NORTH, 33, 1, tripoint_north, translate_marker("North"), translate_marker("N"), "8", i::AIM_NORTHEAST, "ITEMS_N" }, + { i::AIM_NORTHEAST, 36, 1, tripoint_north_east, translate_marker("North East"), translate_marker("NE"), "9", i::AIM_EAST, "ITEMS_NE" }, + + { i::AIM_DRAGGED, 25, 1, tripoint_zero, translate_marker("Grabbed Vehicle"), translate_marker("GR"), "D", i::AIM_DRAGGED, "ITEMS_DRAGGED_CONTAINER" }, + { i::AIM_INVENTORY, 25, 2, tripoint_zero, translate_marker("Inventory"), translate_marker("I"), "I", i::AIM_INVENTORY, "ITEMS_INVENTORY" }, + { i::AIM_WORN, 22, 2, tripoint_zero, translate_marker("Worn Items"), translate_marker("W"), "W", i::AIM_WORN, "ITEMS_WORN"}, + + { i::AIM_ALL, 25, 3, tripoint_zero, translate_marker("Surrounding area"), "", "A", i::AIM_ALL, "ITEMS_AROUND" }, + { i::AIM_ALL_I_W, 18, 3, tripoint_zero, translate_marker("Everything"), "", "A+I+W", i::AIM_ALL_I_W, "ITEMS_AROUND_I_W" } } }; return area_info[loc]; @@ -166,24 +175,12 @@ class comestible_inv_area // roll our own, to handle moving stacks better using area_items = std::vector >; - //TODO: might want to get rind of info... keep for now - //comestible_inv_area(aim_location id) : id(id), relative_location(id) {} - //comestible_inv_area(aim_location id, int hscreenx, int hscreeny, tripoint off, - // const std::string& name, const std::string& shortname, - // const std::string& minimapname, const aim_location relative_location, - // const std::string& actionname) : id(id), - // hscreen(hscreenx, hscreeny), off(off), name(name), shortname(shortname), - // minimapname(minimapname), relative_location(relative_location), actionname(actionname), - // is_valid(false), veh(nullptr), veh_part(-1), volume(0_ml), - // weight(0_gram), max_size(0) { - //} - comestible_inv_area( comestible_inv_area_info area_info ) : info( area_info ), is_valid_location( false ), veh( nullptr ), veh_part( -1 ) { } void init(); - //just a getter + /** false if blocked by somehting (like a wall) **/ bool is_valid(); std::string get_name( bool use_vehicle ) const; diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index ddf49c31b71f8..0c8331d13c083 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -42,6 +42,7 @@ #include "pimpl.h" #include "bionics.h" #include "comestible_inv_pane.h" +#include "material.h" #include #include @@ -56,47 +57,58 @@ #include #include #include - #if defined(__ANDROID__) # include #endif struct col_data { - comestible_inv_columns id; - std::string col_name; - int width; - char hotkey; - std::string sort_name; + public: + comestible_inv_columns id; + private: + std::string col_name; + public: + int width; + char hotkey; + private: + std::string sort_name; + + public: + std::string get_col_name() const { + return _( col_name ); + } + std::string get_sort_name() const { + return _( sort_name ); + } - col_data( comestible_inv_columns id, std::string col_name, int width, char hotkey, - std::string sort_name ) : - id( id ), - col_name( col_name ), width( width ), hotkey( hotkey ), sort_name( sort_name ) { + col_data( comestible_inv_columns id, std::string col_name, int width, char hotkey, + std::string sort_name ) : + id( id ), + col_name( col_name ), width( width ), hotkey( hotkey ), sort_name( sort_name ) { - } + } }; // *INDENT-OFF* static col_data get_col_data(comestible_inv_columns col) { static std::array col_data = { { - {COLUMN_NAME, _("Name (charges)"),0, 'n', _("name")}, + {COLUMN_NAME, translate_marker("Name (charges)"),0, 'n', translate_marker("name")}, - {COLUMN_SRC, _("src"), 4, ';', _("")}, - {COLUMN_AMOUNT, _("amt"), 5, ';', _("")}, + {COLUMN_SRC, translate_marker("src"), 4, ';', ""}, + {COLUMN_AMOUNT, translate_marker("amt"), 5, ';', ""}, - {COLUMN_WEIGHT, _("weight"), 7, 'w', _("weight")}, - {COLUMN_VOLUME, _("vol"), 8, 'v', _("volume")}, + {COLUMN_WEIGHT, translate_marker("weight"), 7, 'w', translate_marker("weight")}, + {COLUMN_VOLUME, translate_marker("volume"), 7, 'v', translate_marker("volume")}, - {COLUMN_CALORIES, _("calories"), 9, 'c', _("calories")}, - {COLUMN_QUENCH, _("quench"), 7, 'q', _("quench")}, - {COLUMN_JOY, _("joy"), 4, 'j', _("joy")}, - {COLUMN_EXPIRES, _("expires in"), 12,'s', _("spoilage")}, - {COLUMN_SHELF_LIFE, _("shelf life"), 12,'s', _("shelf life")}, + {COLUMN_CALORIES, translate_marker("calories"), 9, 'c', translate_marker("calories")}, + {COLUMN_QUENCH, translate_marker("quench"), 7, 'q', translate_marker("quench")}, + {COLUMN_JOY, translate_marker("joy"), 4, 'j', translate_marker("joy")}, + {COLUMN_EXPIRES, translate_marker("expires in"), 11,'s', translate_marker("spoilage")}, + {COLUMN_SHELF_LIFE, translate_marker("shelf life"), 11,'s', translate_marker("shelf life")}, - {COLUMN_ENERGY, _("energy"), 12,'e', _("energy")}, + {COLUMN_ENERGY, translate_marker("energy"), 11,'e', translate_marker("energy")}, - {COLUMN_SORTBY_CATEGORY,_("fake"), 0,'c', _("category")} + {COLUMN_SORTBY_CATEGORY,translate_marker("fake"), 0,'c', translate_marker("category")} } }; return col_data[col]; } @@ -104,19 +116,19 @@ static col_data get_col_data(comestible_inv_columns col) { void comestible_inventory_pane::init( std::vector c, int items_per_page, catacurses::window w, std::array - *s ) + *a ) { columns = c; itemsPerPage = items_per_page; window = w; - squares = s; + all_areas = a; is_compact = TERMX <= 100; inCategoryMode = false; comestible_inv_area_info::aim_location location = static_cast( uistate.comestible_save.area_idx ); - set_area( &( *squares )[location], uistate.comestible_save.in_vehicle ); + set_area( &( *all_areas )[location], uistate.comestible_save.in_vehicle ); index = uistate.comestible_save.selected_idx; filter = uistate.comestible_save.filter; @@ -156,21 +168,21 @@ void comestible_inventory_pane::save_settings( bool reset ) uistate.comestible_save.sort_idx = sortby; } -void comestible_inventory_pane::add_sort_enries( uilist &sm ) +void comestible_inventory_pane::add_sort_entries( uilist &sm ) { col_data c = get_col_data( COLUMN_NAME ); - sm.addentry( c.id, true, c.hotkey, c.sort_name ); + sm.addentry( c.id, true, c.hotkey, c.get_sort_name() ); if( sortby == COLUMN_NAME ) { sm.selected = 0; } for( size_t i = 0; i < columns.size(); i++ ) { c = get_col_data( columns[i] ); - if( c.id == COLUMN_SRC || c.id == COLUMN_AMOUNT ) { + if( c.get_sort_name() == "" ) { continue; } - sm.addentry( c.id, true, c.hotkey, c.sort_name ); + sm.addentry( c.id, true, c.hotkey, c.get_sort_name() ); if( sortby == c.id ) { sm.selected = i; } @@ -254,9 +266,10 @@ void comestible_inventory_pane::print_items() mvwprintz( window, point( max_width - formatted_head.length(), 4 ), norm, formatted_head ); } - const size_t name_startpos = is_compact ? 1 : 4; + const size_t name_startpos = 3;//is_compact ? 1 : 4; - mvwprintz( window, point( name_startpos, 5 ), c_light_gray, get_col_data( COLUMN_NAME ).col_name ); + mvwprintz( window, point( name_startpos, 5 ), c_light_gray, + get_col_data( COLUMN_NAME ).get_col_name() ); int cur_x = max_width; for( size_t i = columns.size(); i -- > 0; ) { const col_data d = get_col_data( columns[i] ); @@ -264,7 +277,7 @@ void comestible_inventory_pane::print_items() continue; } cur_x -= d.width; - mvwprintz( window, point( cur_x, 5 ), c_light_gray, "%*s", d.width, d.col_name ); + mvwprintz( window, point( cur_x, 5 ), c_light_gray, "%*s", d.width, d.get_col_name() ); } for( int i = page * itemsPerPage, cur_print_y = 6; i < static_cast( items.size() ) && @@ -290,7 +303,7 @@ void comestible_inventory_pane::print_items() } else { selected_state = SELECTSTATE_NONE; } - sitem.print_columns( columns, selected_state, is_compact, window, max_width, cur_print_y ); + sitem.print_columns( columns, selected_state, window, max_width, cur_print_y ); } } @@ -550,7 +563,7 @@ void comestible_inventory_pane::recalc() weight = 0_gram; std::vector loc = cur_area->info.multi_locations; for( auto &i : loc ) { - comestible_inv_area *s = &( ( *squares )[i] ); + comestible_inv_area *s = &( ( *all_areas )[i] ); // Deal with squares with ground + vehicle storage // Also handle the case when the other tile covers vehicle // or the ground below the vehicle. @@ -680,7 +693,6 @@ void comestible_inventory_pane::redraw() const comestible_inv_area *sq = same_as_dragged ? get_square( comestible_inv_area_info::AIM_DRAGGED ) : cur_area; - bool car = cur_area->has_vehicle() && viewing_cargo && sq->info.id != comestible_inv_area_info::AIM_DRAGGED; auto name = utf8_truncate( sq->get_name( viewing_cargo ), width ); @@ -690,12 +702,8 @@ void comestible_inventory_pane::redraw() mvwprintz( w, point( 2, 2 ), c_light_blue, desc ); trim_and_print( w, point( 2, 3 ), width, c_cyan, cur_area->flags ); - if( !is_compact ) { - for( size_t i = 0; i < legend.size(); i++ ) { - legend_data l = legend[i]; - mvwprintz( window, point( 25, i + 1 ), c_light_gray, "[%c] ", l.shortcut ); - wprintz( window, l.color, "%s", l.message ); - } + for( auto &i : additional_info ) { + print_colored_text( window, i.position, i.color, i.color, i.message ); } const int max_page = ( items.size() + itemsPerPage - 1 ) / itemsPerPage; @@ -707,7 +715,7 @@ void comestible_inventory_pane::redraw() wattron( w, c_cyan ); // draw a darker border around the inactive pane draw_border( w, BORDER_COLOR ); - mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), get_col_data( sortby ).sort_name ); + mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), get_col_data( sortby ).get_sort_name() ); if( !title.empty() ) { std::string title_string = string_format( "<< %s >>", title ); @@ -736,13 +744,11 @@ void comestible_inventory_pane::redraw() wrefresh( w ); } - - int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) { int wwidth = getmaxx( window ); int ofs = wwidth - 25 - 2 - 14; - for( size_t i = 0; i < squares->size(); ++i ) { + for( size_t i = 0; i < all_areas->size(); ++i ) { std::string key = comestible_inv_area::get_info( static_cast( i ) ).minimapname; @@ -803,7 +809,7 @@ int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) } void comestible_inv_listitem::print_columns( std::vector columns, - comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, + comestible_select_state selected_state, catacurses::window window, int right_bound, int cur_print_y ) { @@ -831,7 +837,7 @@ void comestible_inv_listitem::print_columns( std::vector //we encountered a column that had no printing code assert( false ); } - print_name( is_compact, window, right_bound, cur_print_y ); + print_name( window, right_bound, cur_print_y ); } bool comestible_inv_listitem::print_string_column( comestible_inv_columns col, @@ -975,7 +981,7 @@ bool comestible_inv_listitem::print_default_columns( comestible_inv_columns col, } case COLUMN_SRC: print_color = menu_color; - s = area->info.shortname; + s = area->info.get_shortname(); break; default: @@ -988,7 +994,7 @@ bool comestible_inv_listitem::print_default_columns( comestible_inv_columns col, return true; } -void comestible_inv_listitem::print_name( bool is_compact, catacurses::window window, +void comestible_inv_listitem::print_name( catacurses::window window, int right_bound, int cur_print_y ) { std::string item_name; @@ -1005,36 +1011,26 @@ void comestible_inv_listitem::print_name( bool is_compact, catacurses::window wi item_name = it->display_name(); } - //check stolen - if( it->has_owner() ) { - const faction *item_fac = it->get_owner(); - if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { - item_name = string_format( "%s %s", "!", item_name ); - } - } if( get_option( "ITEM_SYMBOLS" ) ) { item_name = string_format( "%s %s", it->symbol(), item_name ); } - int name_startpos = is_compact ? 1 : 4; - int max_name_length = right_bound - name_startpos - 1; + int name_startpos = cond_size; nc_color print_color; + for( size_t i = 0; i < cond.size(); i++ ) { + auto c = cond[i]; + set_print_color( print_color, c.second ); + mvwprintz( window, point( i + 1, cur_print_y ), print_color, "%c", c.first ); + } set_print_color( print_color, menu_color ); - if( is_selected ) { //fill whole line with color - mvwprintz( window, point( 0, cur_print_y ), print_color, "%*s", right_bound, "" ); + mvwprintz( window, point( cond.size() + 1, cur_print_y ), print_color, "%*s", right_bound, "" ); } - trim_and_print( window, point( name_startpos, cur_print_y ), max_name_length, print_color, + int max_name_length = right_bound - name_startpos - 1; + trim_and_print( window, point( name_startpos, cur_print_y ), max_name_length, print_color, "%s", item_name ); - - if( autopickup ) { - mvwprintz( window, point( name_startpos, cur_print_y ), magenta_background( print_color ), - is_compact ? item_name.substr( 0, 1 ) : ">" ); - } } - - const islot_comestible &comestible_inv_listitem::get_edible_comestible( player &p, const item &it ) const { @@ -1066,6 +1062,7 @@ std::string comestible_inv_listitem::get_time_left_rounded( player &p, const ite } } + //commneted code will give approximate times instead of exact ones, in case we want that //const auto make_result = [this](const time_duration& d, const char* verbose_str, // const char* short_str) { // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); @@ -1137,33 +1134,9 @@ comestible_inv_listitem::comestible_inv_listitem( item *an_item, int index, int , cat( &an_item->get_category() ) , from_vehicle( from_vehicle ) { - player &p = g->u; - item it = p.get_consumable_from( *an_item ); - islot_comestible it_c = get_edible_comestible( p, it ); - - - menu_color = it.color_in_inventory(); - - exipres_in = ""; - shelf_life = ""; - if( it_c.spoils > 0_turns ) { - if( !it.rotten() ) { - exipres_in = get_time_left_rounded( p, it ); - } - shelf_life = to_string_clipped( it_c.spoils ); - } - - calories = p.kcal_for( it ); - quench = it_c.quench; - joy = p.fun_for( it ).first; - is_mushy = it.has_flag( "MUSHY" ); - - energy = p.get_acquirable_energy( it ); - items.push_back( an_item ); - - menu_color_dark = c_dark_gray; - assert( stacks >= 1 ); + init( g->u.get_consumable_from( *an_item ) ); + energy = g->u.get_acquirable_energy( *an_item ); } comestible_inv_listitem::comestible_inv_listitem( const std::list &list, int index, @@ -1181,34 +1154,74 @@ comestible_inv_listitem::comestible_inv_listitem( const std::list &list, cat( &list.front()->get_category() ), from_vehicle( from_vehicle ) { - player &p = g->u; - item it = p.get_consumable_from( *list.front() ); - islot_comestible it_c = get_edible_comestible( p, it ); - + init( g->u.get_consumable_from( *list.front() ) ); + energy = g->u.get_acquirable_energy( *list.front() ); +} +void comestible_inv_listitem::init( const item &it ) +{ + player &p = g->u; + islot_comestible edible = get_edible_comestible( p, it ); menu_color = it.color_in_inventory(); + // statuses + const auto &comest = it.get_comestible(); + cond.reserve( cond_size ); + const bool eat_verb = it.has_flag( "USE_EAT_VERB" ); + const bool is_food = eat_verb || comest->comesttype == "FOOD"; + const bool is_drink = !eat_verb && comest->comesttype == "DRINK"; + + bool craft_only = false; + bool warm_only = false; + + if( it.is_craft() ) { + craft_only = true; + } else if( is_food || is_drink ) { + for( const auto &elem : it.type->materials ) { + if( !elem->edible() ) { + craft_only = true; + break; + } + } + } + if( !craft_only && it.item_tags.count( "FROZEN" ) && !it.has_flag( "EDIBLE_FROZEN" ) && + !it.has_flag( "MELTS" ) ) { + warm_only = true; + } + input_context ctxt( "COMESTIBLE_INVENTORY" ); + if( craft_only ) { + cond.emplace_back( ctxt.get_desc( "CRAFT_WITH" )[0], c_cyan ); + } else if( warm_only ) { + cond.emplace_back( ctxt.get_desc( "HEAT_UP" )[0], c_red ); + } + //check stolen + if( it.has_owner() ) { + const faction *item_fac = it.get_owner(); + if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { + cond.emplace_back( '!', c_light_red ); + } + } + exipres_in = ""; shelf_life = ""; - if( it_c.spoils > 0_turns ) { + if( edible.spoils > 0_turns ) { if( !it.rotten() ) { exipres_in = get_time_left_rounded( p, it ); } - shelf_life = to_string_clipped( it_c.spoils ); + shelf_life = to_string_clipped( edible.spoils ); } calories = p.kcal_for( it ); - quench = it_c.quench; + quench = edible.quench; joy = p.fun_for( it ).first; is_mushy = it.has_flag( "MUSHY" ); - energy = p.get_acquirable_energy( it ); - menu_color_dark = c_dark_gray; assert( stacks >= 1 ); } + comestible_inv_listitem::comestible_inv_listitem() : idx() , area() diff --git a/src/comestible_inv_pane.h b/src/comestible_inv_pane.h index a5b82de4fdb2e..f482752175d50 100644 --- a/src/comestible_inv_pane.h +++ b/src/comestible_inv_pane.h @@ -8,6 +8,7 @@ #include "ui.h" #include "itype.h" #include "comestible_inv_area.h" +#include "color.h" #include #include @@ -17,7 +18,7 @@ #include #include #include - +#include class item_category; @@ -49,20 +50,15 @@ enum comestible_select_state { }; struct legend_data { - char shortcut; - nc_color color; + point position; std::string message; - legend_data( char shortcut, nc_color color, std::string message ): shortcut( shortcut ), - color( color ), message( message ) { - + nc_color color; + legend_data( std::string message, point position, nc_color color ): message( message ), + color( color ) { + this->position = point( 25, 1 ) + position; } }; -/** - * Entry that is displayed in a adv. inv. pane. It can either contain a - * single item or a category header or nothing (empty entry). - * Most members are used only for sorting. - */ class comestible_inv_listitem { public: @@ -72,11 +68,10 @@ class comestible_inv_listitem */ int idx; /** - * The location of the item, never AIM_ALL. + * The location of the item, should nevere be AREA_TYPE_MULTI */ - //comestible_inv_area_info::aim_location area; comestible_inv_area *area; - // the id of the item + itype_id id; // The list of items, and empty when a header std::list items; @@ -97,39 +92,37 @@ class comestible_inv_listitem * for anything counted by charges. */ int stacks; - /** - * The volume of all the items in this stack, used for sorting. - */ + + // from all the items in a stack units::volume volume; - /** - * The weight of all the items in this stack, used for sorting. - */ units::mass weight; - /** - * TODO:docs - */ std::string shelf_life; std::string exipres_in; int calories; int quench; int joy; bool is_mushy; + // when eating with CBMs int energy; + // item conditions, shown before name. Just for display. + int cond_size = 3; + std::vector> cond; + comestible_select_state is_selected; nc_color menu_color; nc_color menu_color_dark; void print_columns( std::vector columns, - comestible_select_state selected_state, bool is_compact, catacurses::window window, int right_bound, + comestible_select_state selected_state, catacurses::window window, int right_bound, int cur_print_y ); private: bool print_string_column( comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y ); bool print_int_column( comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y ); - void print_name( bool is_compact, catacurses::window window, int right_bound, int cur_print_y ); + void print_name( catacurses::window window, int right_bound, int cur_print_y ); bool print_default_columns( comestible_inv_columns col, catacurses::window window, int cur_print_x, int cur_print_y ); void set_print_color( nc_color &retval, nc_color default_col ); @@ -148,7 +141,6 @@ class comestible_inv_listitem bool from_vehicle; - //TODO const islot_comestible &get_edible_comestible( player &p, const item &it ) const; std::string get_time_left_rounded( player &p, const item &it ) const; @@ -191,6 +183,7 @@ class comestible_inv_listitem */ comestible_inv_listitem( const std::list &list, int index, comestible_inv_area *area, bool from_vehicle ); + void init( const item &an_item ); }; /** @@ -255,8 +248,8 @@ class comestible_inventory_pane //this filter is supplied by parent, applied before user input filtering std::function special_filter; //list of shortcut reminders (created manually by parent) - std::vector legend; std::string title; + std::vector additional_info; int itemsPerPage; @@ -283,6 +276,7 @@ class comestible_inventory_pane void fix_index(); void recalc(); void redraw(); + /** * Scroll @ref index, by given offset, set redraw to true, * @param offset Must not be 0. @@ -300,14 +294,14 @@ class comestible_inventory_pane void start_user_filtering( int h, int w ); //adds things this can sort on. List is provided by parent - void add_sort_enries( uilist &sm ); + void add_sort_entries( uilist &sm ); - std::array *squares; + std::array *all_areas; comestible_inv_area *get_square( comestible_inv_area_info::aim_location loc ) { - return &( ( *squares )[loc] ); + return &( ( *all_areas )[loc] ); } comestible_inv_area *get_square( size_t loc ) { - return &( ( *squares )[loc] ); + return &( ( *all_areas )[loc] ); } // set the pane's area via its square, and whether it is viewing a vehicle's cargo void set_area( comestible_inv_area *square, bool show_vehicle ) { diff --git a/src/panels.cpp b/src/panels.cpp index ec8197c1a9def..da1e205d79048 100644 --- a/src/panels.cpp +++ b/src/panels.cpp @@ -777,22 +777,8 @@ static std::string morale_emotion( const int morale_cur, const face_type face, static std::pair power_stat( const avatar &u ) { - nc_color c_pwr = c_red; - std::string s_pwr; - if( u.max_power_level == 0 ) { - s_pwr = "--"; - c_pwr = c_light_gray; - } else { - if( u.power_level >= u.max_power_level / 2 ) { - c_pwr = c_light_blue; - } else if( u.power_level >= u.max_power_level / 3 ) { - c_pwr = c_yellow; - } else if( u.power_level >= u.max_power_level / 4 ) { - c_pwr = c_red; - } - s_pwr = to_string( u.power_level ); - } - return std::make_pair( c_pwr, s_pwr ); + auto desc = u.get_power_description(); + return std::make_pair( desc.second, desc.first ); } static std::pair mana_stat( const player &u ) From fae9f0b345c1a8c5f8f0a7517404dc68b05372d9 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 11 Sep 2019 17:53:14 -0400 Subject: [PATCH 15/19] big refactor: split everything into base,food,bio added more food conditions, and food error messages will show now too. cleaned up includes --- data/raw/keybindings.json | 2 +- src/comestible_inv.cpp | 776 ++++++++++++++++---------------- src/comestible_inv.h | 43 +- src/comestible_inv_area.cpp | 60 +-- src/comestible_inv_area.h | 5 +- src/comestible_inv_listitem.cpp | 773 +++++++++++++++++++++++++++++++ src/comestible_inv_listitem.h | 239 ++++++++++ src/comestible_inv_pane.cpp | 756 ++++--------------------------- src/comestible_inv_pane.h | 203 ++------- 9 files changed, 1586 insertions(+), 1271 deletions(-) create mode 100644 src/comestible_inv_listitem.cpp create mode 100644 src/comestible_inv_listitem.h diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index 44189850af4d0..2503b57c77f0c 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -2871,7 +2871,7 @@ "type": "keybinding", "id": "SHOW_HELP", "category": "COMESTIBLE_INVENTORY", - "name": "Start crafting with selected", + "name": "Food conditions help", "bindings": [ { "input_method": "keyboard", "key": "F1" } ] }, { diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index ab01b227ad71c..03a2634c20a1b 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -2,43 +2,25 @@ #include "avatar.h" #include "cata_utility.h" #include "catacharset.h" -#include "debug.h" -#include "field.h" #include "input.h" -#include "item_category.h" -#include "item_search.h" -#include "item_stack.h" #include "map.h" #include "mapdata.h" #include "messages.h" -#include "options.h" #include "output.h" #include "player.h" #include "player_activity.h" #include "string_formatter.h" #include "string_input_popup.h" -#include "translations.h" -#include "trap.h" -#include "ui.h" #include "uistate.h" #include "vehicle.h" #include "vehicle_selector.h" #include "vpart_position.h" -#include "calendar.h" #include "color.h" #include "game_constants.h" #include "int_id.h" #include "inventory.h" #include "item.h" -#include "optional.h" -#include "ret_val.h" -#include "type_id.h" -#include "clzones.h" -#include "colony.h" #include "enums.h" -#include "faction.h" -#include "item_location.h" -#include "map_selector.h" #include "pimpl.h" #include "bionics.h" #include "comestible_inv.h" @@ -47,14 +29,10 @@ #include #include #include -#include -#include #include #include #include #include -#include -#include #include #include @@ -126,12 +104,13 @@ comestible_inventory::~comestible_inventory() werase( window ); g->refresh_all(); } + delete pane; } void comestible_inventory::save_settings() { bool is_reset = uistate.comestible_save.exit_code != exit_re_entry; - pane.save_settings( is_reset ); + pane->save_settings( is_reset ); if( is_reset ) { if( uistate.comestible_save.bio != -1 ) { g->u.deactivate_bionic( uistate.comestible_save.bio ); @@ -160,7 +139,7 @@ void comestible_inventory::init() w_width = TERMX < min_w_width ? min_w_width : TERMX > max_w_width ? max_w_width : static_cast( TERMX ); - headstart = 0; //(TERMY>w_height)?(TERMY-w_height)/2:0; + headstart = 0; colstart = TERMX > w_width ? ( TERMX - w_width ) / 2 : 0; head = catacurses::newwin( head_height, w_width - minimap_width, point( colstart, headstart ) ); @@ -172,62 +151,15 @@ void comestible_inventory::init() uistate.comestible_save.exit_code = exit_none; - std::vector columns; - if( uistate.comestible_save.bio == -1 ) { - columns = { COLUMN_CALORIES, COLUMN_QUENCH, COLUMN_JOY }; - if( g->u.can_estimate_rot() ) { - columns.emplace_back( COLUMN_EXPIRES ); - } else { - columns.emplace_back( COLUMN_SHELF_LIFE ); - } - } else { - columns = { COLUMN_ENERGY, COLUMN_SORTBY_CATEGORY }; - } + //pane is set by child int itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff - pane.init( columns, itemsPerPage, window, &squares ); - if( uistate.comestible_save.bio == -1 ) { - pane.special_filter = []( const item & it ) { - const std::string n = it.get_category().name(); - if( uistate.comestible_save.show_food && n != "FOOD" ) { - return true; - } - if( !uistate.comestible_save.show_food && n != "DRUGS" ) { - return true; - } - - if( !g->u.can_consume( it ) ) { - return true; - } - return false; - }; - pane.title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; - pane.default_sortby = COLUMN_EXPIRES; - } else { - pane.special_filter = []( const item & it ) { - return !g->u.can_consume( it ) || g->u.get_acquirable_energy( it ) <= 0; - }; - pane.title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name.translated(); - pane.default_sortby = COLUMN_ENERGY; - } + pane->init( itemsPerPage, window, &squares ); } -void comestible_inventory::set_additional_info() +void comestible_inventory::set_additional_info( std::vector data ) { - std::vector data; - std::pair desc; - if( uistate.comestible_save.bio == -1 ) { - desc = g->u.get_hunger_description(); - data.push_back( { string_format( "%s %s", _( "Food :" ), colorize( desc.first, desc.second ) ), point_zero, c_dark_gray } ); - desc = g->u.get_thirst_description(); - data.push_back( { string_format( "%s %s", _( "Drink:" ), colorize( desc.first, desc.second ) ), point_south, c_dark_gray } ); - desc = g->u.get_pain_description(); - data.push_back( { string_format( "%s %s", _( "Pain :" ), colorize( desc.first, desc.second ) ), point( 0, 2 ), c_dark_gray } ); - } else { - desc = g->u.get_power_description(); - data.push_back( { string_format( "%s %s", _( "Power :" ), colorize( desc.first, desc.second ) ), point_zero, c_dark_gray } ); - } - pane.additional_info = data; - pane.needs_redraw = true; + pane->additional_info = data; + pane->needs_redraw = true; } // be explicit with the values @@ -242,25 +174,18 @@ bool comestible_inventory::show_sort_menu( ) { uilist sm; sm.text = _( "Sort by... " ); - pane.add_sort_entries( sm ); + pane->add_sort_entries( sm ); sm.query(); if( sm.ret < 0 ) { return false; } - pane.sortby = static_cast( sm.ret ); + pane->sortby = static_cast( sm.ret ); return true; } - -void comestible_inventory::display( int bio ) +input_context comestible_inventory::register_actions() { - if( uistate.comestible_save.exit_code != exit_re_entry ) { - uistate.comestible_save.bio = bio; - } - init(); - g->u.inv.restack( g->u ); - input_context ctxt( "COMESTIBLE_INVENTORY" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "QUIT" ); @@ -296,18 +221,186 @@ void comestible_inventory::display( int bio ) ctxt.register_action( "ITEMS_AROUND_I_W" ); ctxt.register_action( "ITEMS_DRAGGED_CONTAINER" ); + //todo ctxt.register_action( "CONSUME_FOOD" ); - if( uistate.comestible_save.bio == -1 ) { - ctxt.register_action( "SWITCH_FOOD" ); - ctxt.register_action( "HEAT_UP" ); - ctxt.register_action( "CRAFT_WITH" ); - ctxt.register_action( "SHOW_HELP" ); + return ctxt; +} + +const std::string comestible_inventory::process_actions( input_context ctxt ) +{ + using ai = comestible_inv_area_info; + // current item in source pane, might be null + comestible_inv_listitem *sitem = pane->get_cur_item_ptr(); + comestible_inv_area *new_square; + + const std::string action = ctxt.handle_input(); + + if( action == "CATEGORY_SELECTION" ) { + pane->inCategoryMode = !pane->inCategoryMode; + pane->needs_redraw = + true; // We redraw to force the color change of the highlighted line and header text. + } else if( action == "HELP_KEYBINDINGS" ) { + refresh( recalc, true ); + } else if( ( new_square = get_area( action ) ) != nullptr ) { + if( pane->get_area()->info.id == new_square->get_relative_location() ) { + //DO NOTHING + } else if( new_square->is_valid() ) { + pane->set_area( new_square, new_square->is_vehicle_default() ); + pane->index = 0; + refresh( true, true ); + } else { + popup( _( "You can't put items there!" ) ); + refresh( recalc, true ); // to clear the popup + } + } else if( action == "TOGGLE_FAVORITE" ) { + if( sitem == nullptr || !sitem->is_item_entry() ) { + return action; + } + for( auto *it : sitem->items ) { + it->set_favorite( !it->is_favorite ); + } + // recalc = true; In case we've merged faved and unfaved items + refresh( true, true ); + } else if( action == "SORT" ) { + if( show_sort_menu() ) { + refresh( true, redraw ); + } + refresh( recalc, true ); + } else if( action == "FILTER" ) { + draw_item_filter_rules( pane->window, 1, 11, item_filter_type::FILTER ); + pane->start_user_filtering( w_height - 1, w_width / 2 - 4 ); + } else if( action == "RESET_FILTER" ) { + pane->set_filter( "" ); + } else if( action == "TOGGLE_AUTO_PICKUP" ) { + if( sitem == nullptr || !sitem->is_item_entry() ) { + return action; + } + if( sitem->autopickup ) { + get_auto_pickup().remove_rule( sitem->items.front() ); + sitem->autopickup = false; + } else { + get_auto_pickup().add_rule( sitem->items.front() ); + sitem->autopickup = true; + } + + refresh( true, redraw ); + } else if( action == "EXAMINE" ) { + if( sitem == nullptr || !sitem->is_item_entry() ) { + return action; + } + int ret = 0; + const int info_width = w_width / 2; + const int info_startx = colstart + info_width; + if( pane->get_area()->info.id == ai::AIM_INVENTORY || pane->get_area()->info.id == ai::AIM_WORN ) { + int idx = pane->get_area()->info.id == ai::AIM_INVENTORY ? sitem->idx : + player::worn_position_to_index( sitem->idx ); + // Setup a "return to AIM" activity. If examining the item creates a new activity + // (e.g. reading, reloading, activating), the new activity will be put on top of + // "return to AIM". Once the new activity is finished, "return to AIM" comes back + // (automatically, see player activity handling) and it re-opens the AIM. + // If examining the item did not create a new activity, we have to remove + // "return to AIM". + do_return_entry(); + assert( g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ); + ret = g->inventory_item_menu( idx, info_startx, info_width, game::RIGHT_OF_INFO ); + //src == comestible_inventory::side::left ? game::LEFT_OF_INFO : game::RIGHT_OF_INFO); + if( !g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ) { + exit = true; + } else { + g->u.cancel_activity(); + } + // Might have changed a stack (activated an item, repaired an item, etc.) + if( pane->get_area()->info.id == ai::AIM_INVENTORY ) { + g->u.inv.restack( g->u ); + } + refresh( true, redraw ); + } else { + item &it = *sitem->items.front(); + std::vector vThisItem; + std::vector vDummy; + it.info( true, vThisItem ); + int iDummySelect = 0; + ret = draw_item_info( info_startx, + info_width, 0, 0, it.tname(), it.type_name(), vThisItem, vDummy, iDummySelect, + false, false, true ).get_first_input(); + } + if( ret == KEY_NPAGE || ret == KEY_DOWN ) { + pane->scroll_by( +1 ); + } else if( ret == KEY_PPAGE || ret == KEY_UP ) { + pane->scroll_by( -1 ); + } + refresh( recalc, true ); // item info window overwrote the other pane and the header + } else if( action == "QUIT" ) { + exit = true; + } else if( action == "PAGE_DOWN" ) { + pane->scroll_by( +pane->itemsPerPage ); + } else if( action == "PAGE_UP" ) { + pane->scroll_by( -pane->itemsPerPage ); + } else if( action == "DOWN" ) { + pane->scroll_by( +1 ); + } else if( action == "UP" ) { + pane->scroll_by( -1 ); + } else if( action == "TOGGLE_VEH" ) { + if( pane->get_area()->has_vehicle() ) { + if( pane->get_area()->info.id != ai::AIM_DRAGGED ) { + // Toggle between vehicle and ground + pane->set_area( pane->get_area(), !pane->is_in_vehicle() ); + pane->index = 0; + // make sure to update the minimap as well! + refresh( recalc, true ); + pane->needs_recalc = true; + } + } else { + popup( _( "No vehicle there!" ) ); + refresh( recalc, true ); + } + } else if( action == "CONSUME_FOOD" ) { + player &p = g->u; + item *it = sitem->items.front(); + int pos = p.get_item_position( it ); + if( pos != INT_MIN ) { + p.consume( pos ); + } else if( p.consume_item( *it ) ) { + if( it->is_food_container() ) { + it->contents.erase( it->contents.begin() ); + add_msg( _( "You leave the empty %s." ), it->tname() ); + } else { + tripoint target = p.pos() + sitem->area->offset; + item_location loc; + if( sitem->from_vehicle ) { + const cata::optional vp = g->m.veh_at( target ).part_with_feature( "CARGO", true ); + if( !vp ) { + add_msg( _( "~~~~~~~~~ not vehicle?" ) ); + return action; + } + vehicle *const veh = &vp->vehicle(); + const int part = vp->part_index(); + + loc = item_location( vehicle_cursor( *veh, part ), it ); + } else { + if( sitem->area->info.type == ai::AREA_TYPE_PLAYER ) { + loc = item_location( p, it ); + } else { + loc = item_location( map_cursor( target ), it ); + } + } + loc.remove_item(); + } + } } + return action; +} + +void comestible_inventory::display() +{ + init(); + g->u.inv.restack( g->u ); + + input_context ctxt = register_actions(); exit = false; refresh( true, true ); - using ai = comestible_inv_area_info; while( !exit ) { if( g->u.moves < 0 ) { do_return_entry(); @@ -317,16 +410,12 @@ void comestible_inventory::display( int bio ) if( recalc ) { set_additional_info(); } - pane.redraw(); + pane->redraw(); if( redraw ) { werase( head ); - werase( minimap ); - werase( mm_border ); draw_border( head ); Messages::display_messages( head, 2, 1, w_width - 1, head_height - 2 ); - draw_minimap(); - if( uistate.comestible_save.bio == -1 ) { const std::string msg = string_format( _( "< [%s] Statuses info >" ), ctxt.get_desc( "SHOW_HELP" ) ); @@ -338,310 +427,40 @@ void comestible_inventory::display( int bio ) mvwprintz( head, point( 2, 0 ), c_white, time ); } wrefresh( head ); - refresh_minimap(); - } - refresh( false, false ); - - // current item in source pane, might be null - comestible_inv_listitem *sitem = pane.get_cur_item_ptr(); - comestible_inv_area *new_square; - const std::string action = ctxt.handle_input(); - - if( action == "CATEGORY_SELECTION" ) { - pane.inCategoryMode = !pane.inCategoryMode; - pane.needs_redraw = - true; // We redraw to force the color change of the highlighted line and header text. - } else if( action == "HELP_KEYBINDINGS" ) { - refresh( recalc, true ); - } else if( ( new_square = get_area( action ) ) != nullptr ) { - if( pane.get_area()->info.id == new_square->get_relative_location() ) { - //DO NOTHING - } else if( new_square->is_valid() ) { - pane.set_area( new_square, new_square->is_vehicle_default() ); - pane.index = 0; - refresh( true, true ); - } else { - popup( _( "You can't put items there!" ) ); - refresh( recalc, true ); // to clear the popup - } - } else if( action == "TOGGLE_FAVORITE" ) { - if( sitem == nullptr || !sitem->is_item_entry() ) { - continue; - } - for( auto *it : sitem->items ) { - it->set_favorite( !it->is_favorite ); - } - // recalc = true; In case we've merged faved and unfaved items - refresh( true, true ); - } else if( action == "SORT" ) { - if( show_sort_menu( ) ) { - refresh( true, redraw ); - } - refresh( recalc, true ); - } else if( action == "FILTER" ) { - draw_item_filter_rules( pane.window, 1, 11, item_filter_type::FILTER ); - pane.start_user_filtering( w_height - 1, w_width / 2 - 4 ); - } else if( action == "RESET_FILTER" ) { - pane.set_filter( "" ); - } else if( action == "TOGGLE_AUTO_PICKUP" ) { - if( sitem == nullptr || !sitem->is_item_entry() ) { - continue; - } - if( sitem->autopickup ) { - get_auto_pickup().remove_rule( sitem->items.front() ); - sitem->autopickup = false; - } else { - get_auto_pickup().add_rule( sitem->items.front() ); - sitem->autopickup = true; - } - - refresh( true, redraw ); - } else if( action == "EXAMINE" ) { - if( sitem == nullptr || !sitem->is_item_entry() ) { - continue; - } - int ret = 0; - const int info_width = w_width / 2; - const int info_startx = colstart + info_width; - if( pane.get_area()->info.id == ai::AIM_INVENTORY || pane.get_area()->info.id == ai::AIM_WORN ) { - int idx = pane.get_area()->info.id == ai::AIM_INVENTORY ? sitem->idx : - player::worn_position_to_index( sitem->idx ); - // Setup a "return to AIM" activity. If examining the item creates a new activity - // (e.g. reading, reloading, activating), the new activity will be put on top of - // "return to AIM". Once the new activity is finished, "return to AIM" comes back - // (automatically, see player activity handling) and it re-opens the AIM. - // If examining the item did not create a new activity, we have to remove - // "return to AIM". - do_return_entry(); - assert( g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ); - ret = g->inventory_item_menu( idx, info_startx, info_width, game::RIGHT_OF_INFO ); - //src == comestible_inventory::side::left ? game::LEFT_OF_INFO : game::RIGHT_OF_INFO); - if( !g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ) { - exit = true; - } else { - g->u.cancel_activity(); - } - // Might have changed a stack (activated an item, repaired an item, etc.) - if( pane.get_area()->info.id == ai::AIM_INVENTORY ) { - g->u.inv.restack( g->u ); - } - refresh( true, redraw ); - } else { - item &it = *sitem->items.front(); - std::vector vThisItem; - std::vector vDummy; - it.info( true, vThisItem ); - int iDummySelect = 0; - ret = draw_item_info( info_startx, - info_width, 0, 0, it.tname(), it.type_name(), vThisItem, vDummy, iDummySelect, - false, false, true ).get_first_input(); - } - if( ret == KEY_NPAGE || ret == KEY_DOWN ) { - pane.scroll_by( +1 ); - } else if( ret == KEY_PPAGE || ret == KEY_UP ) { - pane.scroll_by( -1 ); - } - refresh( recalc, true ); // item info window overwrote the other pane and the header - } else if( action == "QUIT" ) { - exit = true; - } else if( action == "PAGE_DOWN" ) { - pane.scroll_by( +pane.itemsPerPage ); - } else if( action == "PAGE_UP" ) { - pane.scroll_by( -pane.itemsPerPage ); - } else if( action == "DOWN" ) { - pane.scroll_by( +1 ); - } else if( action == "UP" ) { - pane.scroll_by( -1 ); - } else if( action == "TOGGLE_VEH" ) { - if( pane.get_area()->has_vehicle() ) { - if( pane.get_area()->info.id != ai::AIM_DRAGGED ) { - // Toggle between vehicle and ground - pane.set_area( pane.get_area(), !pane.is_in_vehicle() ); - pane.index = 0; - // make sure to update the minimap as well! - refresh( recalc, true ); - pane.needs_recalc = true; - } - } else { - popup( _( "No vehicle there!" ) ); - refresh( recalc, true ); - } - } else if( action == "SWITCH_FOOD" ) { - uistate.comestible_save.show_food = !uistate.comestible_save.show_food; - pane.title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; - refresh( true, redraw ); - } else if( action == "HEAT_UP" ) { - heat_up( sitem->items.front() ); - } else if( action == "CRAFT_WITH" ) { - do_return_entry(); - - assert( g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ); - - item *it = sitem->items.front(); - if( it->is_food_container() ) { - it = &it->contents.front(); - } - std::string food_name = item::nname( it->typeId() ); - g->u.craft( tripoint_zero, string_format( "c:%s,", food_name ) ); - - if( !g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ) { - exit = true; - } else { - //TODO: next 2 lines seem hacky - refreshing twice? - //without 1st line we can see craft menu after it closes - //without 2nd line we can't see comestible menu after crafting closes - - g->u.cancel_activity(); - g->refresh_all(); - refresh( recalc, true ); - } - } else if( action == "SHOW_HELP" ) { - std::string desc; - std::string status; - status = ctxt.get_desc( "HEAT_UP" ); - desc += colorize( string_format( "%c", status[0] ), c_red ); - desc += colorize( string_format( - _( ": this food is frozen and cannot be consumed. Press %s to attempt reheating it.\n" ), status ), - c_light_gray ); - - status = ctxt.get_desc( "CRAFT_WITH" ); - desc += colorize( string_format( "%c", status[0] ), c_cyan ); - desc += colorize( string_format( - _( ": this item cannot be eaten in its current form. Press %s to attempt cooking with it.\n" ), - status ), c_light_gray ); - - desc += colorize( "!", c_light_red ); - desc += colorize( string_format( _( ": eating this will be considered stealing." ), status ), - c_light_gray ); - - popup( desc ); - refresh( recalc, true ); - } else if( action == "CONSUME_FOOD" ) { - player &p = g->u; - item *it = sitem->items.front(); - int pos = p.get_item_position( it ); - if( pos != INT_MIN ) { - p.consume( pos ); - } else if( p.consume_item( *it ) ) { - if( it->is_food_container() ) { - it->contents.erase( it->contents.begin() ); - add_msg( _( "You leave the empty %s." ), it->tname() ); - } else { - tripoint target = p.pos() + sitem->area->offset; - item_location loc; - if( sitem->from_vehicle ) { - const cata::optional vp = g->m.veh_at( target ).part_with_feature( "CARGO", true ); - if( !vp ) { - add_msg( _( "~~~~~~~~~ not vehicle?" ) ); - return; - } - vehicle *const veh = &vp->vehicle(); - const int part = vp->part_index(); - - loc = item_location( vehicle_cursor( *veh, part ), it ); - } else { - if( sitem->area->info.type == ai::AREA_TYPE_PLAYER ) { - loc = item_location( p, it ); - } else { - loc = item_location( map_cursor( target ), it ); - } - } - loc.remove_item(); - } - } + redraw_minimap(); } - } -} - -void comestible_inv( int b ) -{ - static const trait_id trait_GRAZER( "GRAZER" ); - static const trait_id trait_RUMINANT( "RUMINANT" ); - - player &p = g->u; - map &m = g->m; + refresh( false, false ); - //lifted from handle_action.cpp - void game::eat(item_location(*menu)(player & p), int pos) - if( ( p.has_active_mutation( trait_RUMINANT ) || p.has_active_mutation( trait_GRAZER ) ) && - ( m.ter( p.pos() ) == t_underbrush || m.ter( p.pos() ) == t_shrub ) ) { - if( p.get_hunger() < 20 ) { - add_msg( _( "You're too full to eat the leaves from the %s." ), m.ter( p.pos() )->name() ); - return; - } else { - p.moves -= 400; - m.ter_set( p.pos(), t_grass ); - add_msg( _( "You eat the underbrush." ) ); - item food( "underbrush", calendar::turn, 1 ); - p.eat( food ); - return; - } - } - if( p.has_active_mutation( trait_GRAZER ) && ( m.ter( p.pos() ) == t_grass || - m.ter( p.pos() ) == t_grass_long || m.ter( p.pos() ) == t_grass_tall ) ) { - if( p.get_hunger() < 8 ) { - add_msg( _( "You're too full to graze." ) ); - return; - } else { - p.moves -= 400; - add_msg( _( "You eat the grass." ) ); - item food( item( "grass", calendar::turn, 1 ) ); - p.eat( food ); - m.ter_set( p.pos(), t_dirt ); - if( m.ter( p.pos() ) == t_grass_tall ) { - m.ter_set( p.pos(), t_grass_long ); - } else if( m.ter( p.pos() ) == t_grass_long ) { - m.ter_set( p.pos(), t_grass ); - } else { - m.ter_set( p.pos(), t_dirt ); - } - return; - } - } - if( p.has_active_mutation( trait_GRAZER ) ) { - if( m.ter( p.pos() ) == t_grass_golf ) { - add_msg( _( "This grass is too short to graze." ) ); - return; - } else if( m.ter( p.pos() ) == t_grass_dead ) { - add_msg( _( "This grass is dead and too mangled for you to graze." ) ); - return; - } else if( m.ter( p.pos() ) == t_grass_white ) { - add_msg( _( "This grass is tainted with paint and thus inedible." ) ); - return; - } + process_actions( ctxt ); } - comestible_inventory new_inv; - new_inv.display( b ); } -void comestible_inventory::refresh_minimap() +void comestible_inventory::redraw_minimap() { + werase( mm_border ); // redraw border around minimap draw_border( mm_border ); // minor addition to border for AIM_ALL, sorta hacky - if( pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { + if( pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { //point(1,0) - point_east so travis is happy mvwprintz( mm_border, point_east, c_light_gray, utf8_truncate( _( "Mul" ), minimap_width ) ); } - // refresh border, then minimap wrefresh( mm_border ); - wrefresh( minimap ); -} -void comestible_inventory::draw_minimap() -{ + werase( minimap ); // get the center of the window tripoint pc = { getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0 }; // draw the 3x3 tiles centered around player g->m.draw( minimap, g->u.pos() ); - if( pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { + if( pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { return; } char sym = minimap_get_sym(); if( sym != '\0' ) { - auto sq = pane.get_area(); + auto sq = pane->get_area(); auto pt = pc + sq->offset; // invert the color if pointing to the player's position auto cl = sq->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ? @@ -650,15 +469,16 @@ void comestible_inventory::draw_minimap() } // Invert player's tile color if exactly one pane points to player's tile - bool player_selected = pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER; + bool player_selected = pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER; g->u.draw( minimap, g->u.pos(), player_selected ); + wrefresh( minimap ); } char comestible_inventory::minimap_get_sym() const { - if( pane.get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ) { + if( pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ) { return '^'; - } else if( pane.is_in_vehicle() ) { + } else if( pane->is_in_vehicle() ) { return 'V'; } else { return ' '; @@ -677,13 +497,122 @@ void comestible_inventory::do_return_entry() void comestible_inventory::refresh( bool needs_recalc, bool needs_redraw ) { recalc = needs_recalc; - pane.needs_recalc = needs_recalc; + pane->needs_recalc = needs_recalc; redraw = needs_redraw; - pane.needs_redraw = needs_redraw; + pane->needs_redraw = needs_redraw; +} + +void comestible_inventory_food::init() +{ + pane = new comestible_inventory_pane_food(); + comestible_inventory::init(); +} + +input_context comestible_inventory_food::register_actions() +{ + input_context ctxt = comestible_inventory::register_actions(); + ctxt.register_action( "SWITCH_FOOD" ); + ctxt.register_action( "HEAT_UP" ); + ctxt.register_action( "CRAFT_WITH" ); + ctxt.register_action( "SHOW_HELP" ); + return ctxt; } -void comestible_inventory::heat_up( item *it_to_heat ) +void comestible_inventory_food::set_additional_info( std::vector data ) +{ + std::pair desc; + desc = g->u.get_hunger_description(); + data.emplace_back( string_format( "%s %s", _( "Food :" ), colorize( desc.first, desc.second ) ), + point_zero, c_dark_gray ); + desc = g->u.get_thirst_description(); + data.emplace_back( string_format( "%s %s", _( "Drink:" ), colorize( desc.first, desc.second ) ), + point_south, c_dark_gray ); + desc = g->u.get_pain_description(); + data.emplace_back( string_format( "%s %s", _( "Pain :" ), colorize( desc.first, desc.second ) ), + point( 0, 2 ), c_dark_gray ); + comestible_inventory::set_additional_info( data ); +} + +const std::string comestible_inventory_food::process_actions( input_context ctxt ) +{ + const std::string action = comestible_inventory::process_actions( ctxt ); + + //using ai = comestible_inv_area_info; + // current item in source pane, might be null + comestible_inv_listitem *sitem = pane->get_cur_item_ptr(); + if( action == "SWITCH_FOOD" ) { + uistate.comestible_save.show_food = !uistate.comestible_save.show_food; + pane->title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; + refresh( true, redraw ); + } else if( action == "HEAT_UP" ) { + heat_up( sitem->items.front() ); + } else if( action == "CRAFT_WITH" ) { + do_return_entry(); + + assert( g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ); + + item *it = sitem->items.front(); + if( it->is_food_container() ) { + it = &it->contents.front(); + } + std::string food_name = item::nname( it->typeId() ); + g->u.craft( tripoint_zero, string_format( "c:%s,", food_name ) ); + + if( !g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ) { + exit = true; + } else { + //TODO: next 2 lines seem hacky - refreshing twice? + //without 1st line we can see craft menu after it closes + //without 2nd line we can't see comestible menu after crafting closes + + g->u.cancel_activity(); + g->refresh_all(); + refresh( recalc, true ); + } + } else if( action == "SHOW_HELP" ) { + std::string desc; + std::string status; + status = ctxt.get_desc( "HEAT_UP" ); + desc += colorize( string_format( "%c", status[0] ), c_cyan ); + desc += colorize( string_format( + _( ": this food is frozen and cannot be consumed. Press %s to attempt reheating it.\n" ), status ), + c_light_gray ); + + status = ctxt.get_desc( "CRAFT_WITH" ); + desc += colorize( string_format( "%c", status[0] ), c_cyan ); + desc += colorize( string_format( + _( ": this item cannot be eaten in its current form. Press %s to attempt cooking with it.\n" ), + status ), c_light_gray ); + desc += "\n"; + + desc += colorize( string_format( "%c", 'm' ), c_yellow ); + desc += colorize( _( ": this food is mushy and has reduced joy.\n" ), c_light_gray ); + + desc += colorize( string_format( "%c", 's' ), c_yellow ); + desc += colorize( _( ": this is stimulant (e.g. coffe, pop).\n" ), c_light_gray ); + + desc += colorize( string_format( "%c", 'd' ), c_yellow ); + desc += colorize( _( ": this is depressant (e.g. alcohol).\n" ), c_light_gray ); + desc += "\n"; + + desc += colorize( string_format( "%c", 'a' ), c_yellow ); + desc += colorize( _( ": this item is mildly addictive.\n" ), c_light_gray ); + + desc += colorize( string_format( "%c", 'a' ), c_red ); + desc += colorize( _( ": this item is strongly addictive.\n" ), c_light_gray ); + + desc += colorize( "!", c_light_red ); + desc += colorize( string_format( _( ": eating this will be considered stealing." ), status ), + c_light_gray ); + + popup( desc ); + refresh( recalc, true ); + } + return action; +} + +void comestible_inventory_food::heat_up( item *it_to_heat ) { //in case we want to warm up a certail quantity later on int batch_size = 1; @@ -769,3 +698,86 @@ void comestible_inventory::heat_up( item *it_to_heat ) } p.mod_moves( -move_mod ); // time needed to actually heat up } + +void comestible_inventory_bio::set_additional_info( std::vector data ) +{ + std::pair desc; + desc = g->u.get_power_description(); + data.push_back( { string_format( "%s %s", _( "Power :" ), colorize( desc.first, desc.second ) ), point_zero, c_dark_gray } ); + comestible_inventory::set_additional_info( data ); +} + +void comestible_inventory_bio::init() +{ + pane = new comestible_inventory_pane_bio(); + comestible_inventory::init(); +} + +void comestible_inv( int b ) +{ + static const trait_id trait_GRAZER( "GRAZER" ); + static const trait_id trait_RUMINANT( "RUMINANT" ); + + player &p = g->u; + map &m = g->m; + + //lifted from handle_action.cpp - void game::eat(item_location(*menu)(player & p), int pos) + if( ( p.has_active_mutation( trait_RUMINANT ) || p.has_active_mutation( trait_GRAZER ) ) && + ( m.ter( p.pos() ) == t_underbrush || m.ter( p.pos() ) == t_shrub ) ) { + if( p.get_hunger() < 20 ) { + add_msg( _( "You're too full to eat the leaves from the %s." ), m.ter( p.pos() )->name() ); + return; + } else { + p.moves -= 400; + m.ter_set( p.pos(), t_grass ); + add_msg( _( "You eat the underbrush." ) ); + item food( "underbrush", calendar::turn, 1 ); + p.eat( food ); + return; + } + } + if( p.has_active_mutation( trait_GRAZER ) && ( m.ter( p.pos() ) == t_grass || + m.ter( p.pos() ) == t_grass_long || m.ter( p.pos() ) == t_grass_tall ) ) { + if( p.get_hunger() < 8 ) { + add_msg( _( "You're too full to graze." ) ); + return; + } else { + p.moves -= 400; + add_msg( _( "You eat the grass." ) ); + item food( item( "grass", calendar::turn, 1 ) ); + p.eat( food ); + m.ter_set( p.pos(), t_dirt ); + if( m.ter( p.pos() ) == t_grass_tall ) { + m.ter_set( p.pos(), t_grass_long ); + } else if( m.ter( p.pos() ) == t_grass_long ) { + m.ter_set( p.pos(), t_grass ); + } else { + m.ter_set( p.pos(), t_dirt ); + } + return; + } + } + if( p.has_active_mutation( trait_GRAZER ) ) { + if( m.ter( p.pos() ) == t_grass_golf ) { + add_msg( _( "This grass is too short to graze." ) ); + return; + } else if( m.ter( p.pos() ) == t_grass_dead ) { + add_msg( _( "This grass is dead and too mangled for you to graze." ) ); + return; + } else if( m.ter( p.pos() ) == t_grass_white ) { + add_msg( _( "This grass is tainted with paint and thus inedible." ) ); + return; + } + } + + if( uistate.comestible_save.exit_code != exit_re_entry ) { + uistate.comestible_save.bio = b; + } + if( uistate.comestible_save.bio == -1 ) { + comestible_inventory_food new_inv; + new_inv.display(); + } else { + comestible_inventory_bio new_inv; + new_inv.display(); + } +} diff --git a/src/comestible_inv.h b/src/comestible_inv.h index d8616c4e3d0e1..1ea8366562f42 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -2,18 +2,9 @@ #ifndef comestible_inv_H #define comestible_inv_H #include "cursesdef.h" -#include "point.h" -#include "units.h" -#include "game.h" -#include "itype.h" #include "comestible_inv_pane.h" -#include -#include #include -#include -#include -#include #include #include @@ -32,8 +23,11 @@ class comestible_inventory comestible_inventory(); ~comestible_inventory(); - void display( int bio ); - private: + virtual void display(); + protected: + virtual input_context register_actions(); + virtual const std::string process_actions( input_context ctxt ); + const int head_height; const int min_w_height; const int min_w_width; @@ -44,8 +38,7 @@ class comestible_inventory catacurses::window mm_border; const int minimap_width = 3; const int minimap_height = 3; - void draw_minimap(); - void refresh_minimap(); + void redraw_minimap(); char minimap_get_sym() const; int w_height; @@ -57,7 +50,7 @@ class comestible_inventory bool recalc; bool redraw; - comestible_inventory_pane pane; + comestible_inventory_pane *pane; //static const comestible_inventory_pane null_pane; std::array squares; @@ -66,14 +59,14 @@ class comestible_inventory bool exit; - void init(); + virtual void init(); //sets recalculate and redraw for this and pane void refresh( bool needs_recalc, bool needs_redraw ); void save_settings(); // used to return back to AIM when other activities queued are finished void do_return_entry(); // any additional info, relevant for menu, but not part of main data - void set_additional_info(); + virtual void set_additional_info( std::vector data = {} ); /** * Translate an action ident from the input context to an comestible_inv_area. * @param action one of ctxt.register_action @@ -84,9 +77,27 @@ class comestible_inventory * @return whether the sort order was actually changed. */ bool show_sort_menu(); +}; +class comestible_inventory_food : public comestible_inventory +{ + public: + protected: + void init() override; + input_context register_actions() override; + const std::string process_actions( input_context ctxt ) override; + void set_additional_info( std::vector data ) override; + private: //try to find a way to warm up/defrost an item, and do it void heat_up( item *it ); }; +class comestible_inventory_bio : public comestible_inventory +{ + public: + protected: + void init() override; + void set_additional_info( std::vector data ) override; +}; + #endif diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index 0633c77087ca2..7a00e508a2844 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -2,17 +2,12 @@ #include "avatar.h" #include "cata_utility.h" #include "catacharset.h" -#include "debug.h" -#include "field.h" -#include "input.h" #include "item_category.h" #include "item_search.h" #include "item_stack.h" #include "map.h" #include "mapdata.h" #include "messages.h" -#include "options.h" -#include "output.h" #include "player.h" #include "player_activity.h" #include "string_formatter.h" @@ -20,40 +15,25 @@ #include "translations.h" #include "trap.h" #include "ui.h" -#include "uistate.h" #include "vehicle.h" #include "vehicle_selector.h" #include "vpart_position.h" -#include "calendar.h" -#include "color.h" -#include "game_constants.h" -#include "int_id.h" #include "inventory.h" #include "item.h" -#include "optional.h" -#include "ret_val.h" -#include "type_id.h" -#include "clzones.h" -#include "colony.h" #include "enums.h" -#include "faction.h" #include "item_location.h" #include "map_selector.h" #include "pimpl.h" - +#include "field.h" #include "comestible_inv_area.h" #include #include #include -#include -#include #include #include #include #include -#include -#include #include #include @@ -224,15 +204,41 @@ static comestible_inv_area::area_items mi_stacked( T items ) return stacks; } -comestible_inv_area::area_items comestible_inv_area::get_items( bool use_vehicle ) +comestible_inv_area::area_items comestible_inv_area::get_items( bool from_cargo ) { - if( use_vehicle ) { - assert( has_vehicle() ); - return mi_stacked( veh->get_items( veh_part ) ); + player &u = g->u; + comestible_inv_area::area_items retval; + + if( info.id == comestible_inv_area_info::AIM_INVENTORY ) { + const invslice &stacks = u.inv.slice(); + + retval.reserve( stacks.size() ); + for( size_t x = 0; x < stacks.size(); ++x ) { + std::list item_pointers; + for( item &i : *stacks[x] ) { + item_pointers.push_back( &i ); + } + + retval.push_back( item_pointers ); + } + } else if( info.id == comestible_inv_area_info::AIM_WORN ) { + auto iter = u.worn.begin(); + + retval.reserve( u.worn.size() ); + for( size_t i = 0; i < u.worn.size(); ++i, ++iter ) { + std::list item_pointers = { {& *iter} }; + retval.push_back( item_pointers ); + } } else { - map &m = g->m; - return mi_stacked( m.i_at( g->u.pos() + offset ) ); + if( from_cargo ) { + assert( has_vehicle() ); + retval = mi_stacked( veh->get_items( veh_part ) ); + } else { + retval = mi_stacked( g->m.i_at( g->u.pos() + offset ) ); + } } + + return retval; } units::volume comestible_inv_area::get_max_volume( bool use_vehicle ) diff --git a/src/comestible_inv_area.h b/src/comestible_inv_area.h index be9862caf6ddd..25ee2246f3277 100644 --- a/src/comestible_inv_area.h +++ b/src/comestible_inv_area.h @@ -8,10 +8,7 @@ #include "game.h" #include "itype.h" -#include -#include #include -#include #include #include #include @@ -184,7 +181,7 @@ class comestible_inv_area bool is_valid(); std::string get_name( bool use_vehicle ) const; - area_items get_items( bool use_vehicle ); + area_items get_items( bool from_cargo ); units::volume get_max_volume( bool use_vehicle ); // whether to show vehicle when we open location for the first time diff --git a/src/comestible_inv_listitem.cpp b/src/comestible_inv_listitem.cpp new file mode 100644 index 0000000000000..69c243ee23e62 --- /dev/null +++ b/src/comestible_inv_listitem.cpp @@ -0,0 +1,773 @@ +#include "auto_pickup.h" +#include "avatar.h" +#include "cata_utility.h" +#include "catacharset.h" +#include "input.h" +#include "item_category.h" +#include "item_search.h" +#include "item_stack.h" +#include "options.h" +#include "output.h" +#include "player.h" +#include "player_activity.h" +#include "string_formatter.h" +#include "color.h" +#include "int_id.h" +#include "item.h" +#include "ret_val.h" +#include "type_id.h" +#include "enums.h" +#include "faction.h" +#include "material.h" +#include "comestible_inv_listitem.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__ANDROID__) +# include +#endif + +void comestible_inv_listitem::print_columns( std::vector columns, + comestible_select_state selected_state, catacurses::window window, int right_bound, + int cur_print_y ) +{ + is_selected = selected_state; + int w; + std::string print_str; + nc_color print_col; + for( std::vector::reverse_iterator col_iter = columns.rbegin(); + col_iter != columns.rend(); ++col_iter ) { + w = get_col_data( *col_iter ).width; + if( w <= 0 ) { // internal column, not meant for display + continue; + } + // if (true) - we found the column, and set data for it; if (false) - try to find in another type + if( print_string_column( *col_iter, print_str, print_col ) ) { + } else if( print_int_column( *col_iter, print_str, print_col ) ) { + } else if( print_default_columns( *col_iter, print_str, print_col ) ) { + } else { + //we encountered a column that had no printing code + assert( false ); + } + + right_bound -= w; + mvwprintz( window, point( right_bound, cur_print_y ), print_col, "%*s", w, print_str ); + } + print_name( window, right_bound, cur_print_y ); +} + +bool comestible_inv_listitem::print_string_column( comestible_inv_columns col, + std::string &print_str, nc_color &print_col ) +{ + //Function is overriden in children. Code is to supress warnings/errors. + if( col == 0 ) { + print_str = ""; + print_col = c_white; + } + return false; +} + +bool comestible_inv_listitem::print_int_column( comestible_inv_columns col, std::string &print_str, + nc_color &print_col ) +{ + //Function is overriden in children. Code is to supress warnings/errors. + if( col == 0 ) { + print_str = ""; + print_col = c_white; + } + return false; +} + +bool comestible_inv_listitem::print_default_columns( comestible_inv_columns col, + std::string &print_str, nc_color &print_col ) +{ + switch( col ) { + case COLUMN_VOLUME: { + bool it_vol_truncated = false; + double it_vol_value = 0.0; + print_str = format_volume( volume, 5, &it_vol_truncated, &it_vol_value ); + if( it_vol_truncated && it_vol_value > 0.0 ) { + print_col = c_red; + } else { + print_col = volume.value() > 0 ? menu_color : menu_color_dark; + } + break; + } + + case COLUMN_WEIGHT: { + double it_weight = convert_weight( weight ); + size_t w_precision; + print_col = it_weight > 0 ? menu_color : menu_color_dark; + + if( it_weight >= 1000.0 ) { + if( it_weight >= 10000.0 ) { + print_col = c_red; + it_weight = 9999.0; + } + w_precision = 0; + } else if( it_weight >= 100.0 ) { + w_precision = 1; + } else { + w_precision = 2; + } + print_str = string_format( "%5.*f", w_precision, it_weight ); + break; + } + case COLUMN_AMOUNT: { + if( stacks > 1 ) { + print_col = menu_color; + if( stacks > 9999 ) { + stacks = 9999; + print_col = c_red; + } + print_str = string_format( "%4d", stacks ); + } else { + print_str = ""; + } + break; + } + case COLUMN_SRC: + print_col = menu_color; + print_str = area->info.get_shortname(); + break; + + default: + return false; + break; + } + set_print_color( print_col, print_col ); + return true; +} + +void comestible_inv_listitem::print_name( catacurses::window window, + int right_bound, int cur_print_y ) +{ + std::string item_name; + + item *it = items.front(); + if( it->is_money() ) { + //Count charges + unsigned int charges_total = 0; + for( const auto item : items ) { + charges_total += item->charges; + } + item_name = it->display_money( items.size(), charges_total ); + } else { + item_name = it->display_name(); + } + //check stolen + if( it->has_owner() ) { + const faction *item_fac = it->get_owner(); + if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { + item_name = string_format( "%s%s", colorize( "!", c_light_red ), item_name ); + } + } + if( get_option( "ITEM_SYMBOLS" ) ) { + item_name = string_format( "%s %s", it->symbol(), item_name ); + } + + int name_startpos = 1; + nc_color print_color; + //for (size_t i = 0; i < cond.size(); i++) { + // auto c = cond[i]; + // set_print_color(print_color, c.second); + // mvwprintz(window, point(i + 1, cur_print_y), print_color, "%c", c.first); + //} + set_print_color( print_color, menu_color ); + if( is_selected ) { //fill whole line with color + mvwprintz( window, point( 1, cur_print_y ), print_color, "%*s", right_bound, "" ); + } + int max_name_length = right_bound - name_startpos - 1; + trim_and_print( window, point( name_startpos, cur_print_y ), max_name_length, print_color, "%s", + item_name ); +} + + +char const *comestible_inv_listitem::set_string_params( nc_color &print_color, int value, + bool need_highlight ) +{ + char const *string_format; + if( value > 0 ) { + print_color = need_highlight ? c_yellow_green : c_green; + string_format = "+%d"; + } else if( value < 0 ) { + print_color = need_highlight ? c_yellow_red : c_red; + string_format = "%d"; + } else { + print_color = need_highlight ? c_yellow : c_dark_gray; + string_format = ""; + } + + set_print_color( print_color, print_color ); + return string_format; +} + +void comestible_inv_listitem::set_print_color( nc_color &retval, nc_color default_col ) +{ + switch( is_selected ) { + case SELECTSTATE_NONE: + retval = default_col; + break; + case SELECTSTATE_SELECTED: + retval = hilite( c_white ); + break; + case SELECTSTATE_CATEGORY: + retval = c_white_red; + break; + default: + break; + } +} + +const islot_comestible &comestible_inv_listitem::get_edible_comestible( player &p, + const item &it ) const +{ + if( it.is_comestible() && p.can_eat( it ).success() ) { + // Ok since can_eat() returns false if is_craft() is true + return *it.type->comestible; + } + static const islot_comestible dummy{}; + return dummy; +} + + +std::string comestible_inv_listitem::get_time_left_rounded( player &p, const item &it ) const +{ + if( it.is_going_bad() ) { + return _( "soon!" ); + } + + time_duration time_left = 0_turns; + const time_duration shelf_life = get_edible_comestible( p, it ).spoils; + if( shelf_life > 0_turns ) { + 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; + } + } + + //commneted code will give approximate times instead of exact ones, in case we want that + //const auto make_result = [this](const time_duration& d, const char* verbose_str, + // const char* short_str) { + // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); + //}; + + time_duration divider = 0_turns; + time_duration vicinity = 0_turns; + + if( time_left > 1_days ) { + divider = 1_days; + vicinity = 2_hours; + } else if( time_left > 1_hours ) { + divider = 1_hours; + vicinity = 5_minutes; + } // Minutes and seconds can be estimated precisely. + + if( divider != 0_turns ) { + const time_duration remainder = time_left % divider; + + if( remainder >= divider - vicinity ) { + time_left += divider; + } else if( remainder > vicinity ) { + if( remainder < divider / 2 ) { + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("> %s", time_to_comestible_str(time_left)); + } else { + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("< %s", time_to_comestible_str(time_left)); + } + } + } + //~ %s - time (e.g. 2 hours). + return string_format( "%s", time_to_comestible_str( time_left ) ); + //return string_format("~ %s", time_to_comestible_str(time_left)); +} + +std::string comestible_inv_listitem::time_to_comestible_str( const time_duration &d ) const +{ + if( d >= calendar::INDEFINITELY_LONG_DURATION ) { + return _( "forever" ); + } + + const float day = to_days( d ); + std::string format; + if( day < 1.00 ) { + format = _( "%.2f days" ); + } else if( day > 1.00 ) { + format = _( "%.0f days" ); + } else { + format = _( "1 day" ); + } + + return string_format( format, day ); +} + +struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { + bool operator()( char x, char y ) const { + return toupper( static_cast( x ) ) < toupper( static_cast( y ) ); + } +}; + +std::function +comestible_inv_listitem::get_sort_function( comestible_inv_columns sortby, + comestible_inv_columns default_sortby ) +{ + using itm = comestible_inv_listitem; + return [ = ]( const itm * d1, const itm * d2 ) { + auto f1 = compare_function( sortby ); + auto f2 = compare_function( default_sortby ); + + bool retval; + if( !f1( d1, d2, retval ) ) { + f2( d1, d2, retval ); + } + return retval; + }; +} + +std::function +comestible_inv_listitem::compare_function( comestible_inv_columns sortby ) +{ + using itm = comestible_inv_listitem; + switch( sortby ) { + case COLUMN_NAME: + return []( const itm * d1, const itm * d2, bool & retval ) { + const std::string *n1; + const std::string *n2; + if( d1->name_without_prefix == d2->name_without_prefix ) { + if( d1->name == d2->name ) { + return false; + } else { + //if names without prefix equal, compare full name + n1 = &d1->name; + n2 = &d2->name; + } + } else { + //else compare name without prefix + n1 = &d1->name_without_prefix; + n2 = &d2->name_without_prefix; + } + + retval = std::lexicographical_compare( n1->begin(), n1->end(), n2->begin(), n2->end(), + sort_case_insensitive_less() ); + return true; + }; + case COLUMN_WEIGHT: + return []( const itm * d1, const itm * d2, bool & retval ) { + retval = d1->weight > d2->weight; + return d1->weight != d2->weight; + }; + case COLUMN_VOLUME: + return []( const itm * d1, const itm * d2, bool & retval ) { + retval = d1->volume > d2->volume; + return d1->volume != d2->volume; + }; + case COLUMN_SORTBY_CATEGORY: + return []( const itm * d1, const itm * d2, bool & retval ) { + assert( d1->cat != nullptr ); + assert( d2->cat != nullptr ); + if( d1->cat != d2->cat ) { + retval = *d1->cat < *d2->cat; + return true; + } else if( d1->is_category_header() ) { + retval = true; + return true; + } else if( d2->is_category_header() ) { + retval = false; + return true; + } + retval = false; + return false; + }; + default: + return nullptr; + } +} + +comestible_inv_listitem::comestible_inv_listitem( const std::list &list, int index, + comestible_inv_area *area, bool from_vehicle ) : + idx( index ), + area( area ), + id( list.front()->typeId() ), + items( list ), + name( list.front()->tname( list.size() ) ), + name_without_prefix( list.front()->tname( 1, false ) ), + autopickup( get_auto_pickup().has_rule( list.front() ) ), + stacks( list.size() ), + volume( list.front()->volume() * stacks ), + weight( list.front()->weight() * stacks ), + cat( &list.front()->get_category() ), + from_vehicle( from_vehicle ) +{ + init( g->u.get_consumable_from( *list.front() ) ); +} + +void comestible_inv_listitem::init( const item &it ) +{ + menu_color = it.color_in_inventory(); + menu_color_dark = c_dark_gray; + assert( stacks >= 1 ); +} + +comestible_inv_listitem::comestible_inv_listitem( const item_category *cat ) + : idx() + , area() + , id( "null" ) + , autopickup() + , stacks() + , cat( cat ) +{ + if( cat != nullptr ) { + name = cat->name(); + } + menu_color_dark = c_dark_gray; +} + +bool comestible_inv_listitem::is_category_header() const +{ + return items.empty() && cat != nullptr; +} + +bool comestible_inv_listitem::is_item_entry() const +{ + return !items.empty(); +} + + +/******* FOOD *******/ + + +comestible_inv_listitem_food::comestible_inv_listitem_food( const item_category *cat ): + comestible_inv_listitem( cat ) +{ +} + +comestible_inv_listitem_food::comestible_inv_listitem_food( const std::list &list, + int index, + comestible_inv_area *area, bool from_vehicle ): comestible_inv_listitem( list, index, area, + from_vehicle ) +{ + init( g->u.get_consumable_from( *list.front() ) ); +} + +void comestible_inv_listitem_food::init( const item &it ) +{ + player &p = g->u; + islot_comestible edible = get_edible_comestible( p, it ); + + menu_color = it.color_in_inventory(); + + // statuses + const auto &comest = it.get_comestible(); + cond.reserve( cond_size ); + const bool eat_verb = it.has_flag( "USE_EAT_VERB" ); + const bool is_food = eat_verb || comest->comesttype == "FOOD"; + const bool is_drink = !eat_verb && comest->comesttype == "DRINK"; + + bool craft_only = false; + bool warm_only = false; + + if( it.is_craft() ) { + craft_only = true; + } else if( is_food || is_drink ) { + for( const auto &elem : it.type->materials ) { + if( !elem->edible() ) { + craft_only = true; + break; + } + } + } + if( !craft_only && it.item_tags.count( "FROZEN" ) && !it.has_flag( "EDIBLE_FROZEN" ) && + !it.has_flag( "MELTS" ) ) { + warm_only = true; + } + input_context ctxt( "COMESTIBLE_INVENTORY" ); + if( craft_only ) { + cond.emplace_back( ctxt.get_desc( "CRAFT_WITH" )[0], c_cyan ); + } else if( warm_only ) { + cond.emplace_back( ctxt.get_desc( "HEAT_UP" )[0], c_cyan ); + } else { + cond.emplace_back( ' ', c_cyan ); + } + + if( it.has_flag( "MUSHY" ) ) { + cond.emplace_back( 'm', c_yellow ); + } else if( edible.stim > 0 ) { + cond.emplace_back( 's', c_yellow ); + } else if( edible.stim < 0 ) { + cond.emplace_back( 'd', c_yellow ); + } else { + cond.emplace_back( ' ', c_cyan ); + } + + //These numbers are arbitrary. + if( edible.addict > 7 ) { + if( edible.addict < 20 ) { + cond.emplace_back( 'a', c_yellow ); + } else { + cond.emplace_back( 'a', c_red ); + } + } else { + cond.emplace_back( ' ', c_cyan ); + } + + eat_error = p.can_eat( it ); + + exipres_in = ""; + shelf_life = ""; + if( edible.spoils > 0_turns ) { + if( !it.rotten() ) { + exipres_in = get_time_left_rounded( p, it ); + } + shelf_life = to_string_clipped( edible.spoils ); + } + + calories = p.kcal_for( it ); + quench = edible.quench; + joy = p.fun_for( it ).first; +} +void comestible_inv_listitem_food::print_columns( std::vector columns, + comestible_select_state selected_state, catacurses::window window, int right_bound, + int cur_print_y ) +{ + // if it's ineddible, but cookable or reheatable we want to show full data + if( !eat_error.success() && eat_error.value() != edible_rating::INEDIBLE ) { + int max_x = right_bound; + is_selected = selected_state; + int w; + std::string print_str; + nc_color print_col; + + //basically same code as base, except we skip few columns and replace them with error message + //we still want to print base columns and find position to print error from, so keep the loop + for( std::vector::reverse_iterator col_iter = columns.rbegin(); + col_iter != columns.rend(); ++col_iter ) { + w = get_col_data( *col_iter ).width; + if( w <= 0 ) { // internal column, not meant for display + continue; + } + right_bound -= w; + + //can't put this as return value from one of the columns, because we want to print in a non-standard way + if( *col_iter == COLUMN_CALORIES ) { + print_col = is_selected ? hilite( c_white ) : c_red; + print_str = string_format( " %s", eat_error.str() ); + int width = max_x - right_bound; + trim_and_print( window, point( right_bound, cur_print_y ), width, print_col, "%*s", width, + print_str ); + continue; + } + + // if (true) - we found the column, and set data for it; if (false) - try to find in another type + if( print_string_column( *col_iter, print_str, print_col ) ) { + continue; + } else if( print_int_column( *col_iter, print_str, print_col ) ) { + continue; + } else if( print_default_columns( *col_iter, print_str, print_col ) ) { + } else { + //we encountered a column that had no printing code + assert( false ); + } + + mvwprintz( window, point( right_bound, cur_print_y ), print_col, "%*s", w, print_str ); + } + print_name( window, right_bound, cur_print_y ); + } else { + comestible_inv_listitem::print_columns( columns, selected_state, window, right_bound, cur_print_y ); + } +} + +bool comestible_inv_listitem_food::print_string_column( comestible_inv_columns col, + std::string &print_str, nc_color &print_col ) +{ + switch( col ) { + case COLUMN_SHELF_LIFE: + print_str = shelf_life; + break; + case COLUMN_EXPIRES: + print_str = exipres_in; + break; + default: + return false; + } + + set_print_color( print_col, c_cyan ); + return true; +} + +bool comestible_inv_listitem_food::print_int_column( comestible_inv_columns col, + std::string &print_str, nc_color &print_col ) +{ + int print_val; + switch( col ) { + case COLUMN_CALORIES: + print_val = calories; + break; + case COLUMN_QUENCH: + print_val = quench; + break; + case COLUMN_JOY: + print_val = joy; + break; + default: + return false; + break; + } + char const *print_format = set_string_params( print_col, print_val, false ); + print_str = string_format( print_format, print_val ); + return true; +} + +void comestible_inv_listitem_food::print_name( catacurses::window window, + int right_bound, int cur_print_y ) +{ + std::string item_name; + + item *it = items.front(); + if( it->is_money() ) { + //Count charges + unsigned int charges_total = 0; + for( const auto item : items ) { + charges_total += item->charges; + } + item_name = it->display_money( items.size(), charges_total ); + } else { + item_name = it->display_name(); + } + + if( get_option( "ITEM_SYMBOLS" ) ) { + item_name = string_format( "%s %s", it->symbol(), item_name ); + } + + int name_startpos = cond_size + 1; + nc_color print_color; + for( size_t i = 0; i < cond.size(); i++ ) { + auto c = cond[i]; + set_print_color( print_color, c.second ); + mvwprintz( window, point( i + 1, cur_print_y ), print_color, "%c", c.first ); + } + set_print_color( print_color, menu_color ); + if( is_selected ) { //fill whole line with color + mvwprintz( window, point( cond.size() + 1, cur_print_y ), print_color, "%*s", right_bound, "" ); + } + int max_name_length = right_bound - name_startpos - 1; + trim_and_print( window, point( name_startpos, cur_print_y ), max_name_length, print_color, "%s", + item_name ); +} + +std::function +comestible_inv_listitem_food::compare_function( comestible_inv_columns sortby ) +{ + auto f = comestible_inv_listitem::compare_function( sortby ); + if( f != nullptr ) { + return f; + } + + using itm = comestible_inv_listitem; + using itmf = comestible_inv_listitem_food; + switch( sortby ) { + case COLUMN_CALORIES: + return []( const itm * d1, const itm * d2, bool & retval ) { + const itmf *d1f = static_cast( d1 ); + const itmf *d2f = static_cast( d2 ); + retval = d1f->calories > d2f->calories; + return d1f->calories != d2f->calories; + }; + case COLUMN_QUENCH: + return []( const itm * d1, const itm * d2, bool & retval ) { + const itmf *d1f = static_cast( d1 ); + const itmf *d2f = static_cast( d2 ); + retval = d1f->quench > d2f->quench; + return d1f->quench != d2f->quench; + }; + case COLUMN_JOY: + return []( const itm * d1, const itm * d2, bool & retval ) { + const itmf *d1f = static_cast( d1 ); + const itmf *d2f = static_cast( d2 ); + retval = d1f->joy > d2f->joy; + return d1f->joy != d2f->joy; + }; + case COLUMN_EXPIRES: + case COLUMN_SHELF_LIFE: + return []( const itm * d1, const itm * d2, bool & retval ) { + const itmf *d1f = static_cast( d1 ); + const itmf *d2f = static_cast( d2 ); + int s1 = d1f->items.front()->spoilage_sort_order(); + int s2 = d2f->items.front()->spoilage_sort_order(); + retval = s1 < s2; + return s1 != s2; + }; + default: + return nullptr; + } +} + +/******* BIO *******/ + +comestible_inv_listitem_bio::comestible_inv_listitem_bio( const item_category *cat ) : + comestible_inv_listitem( cat ) +{ +} + +comestible_inv_listitem_bio::comestible_inv_listitem_bio( const std::list &list, int index, + comestible_inv_area *area, bool from_vehicle ) : comestible_inv_listitem( list, index, area, + from_vehicle ) +{ + energy = g->u.get_acquirable_energy( *list.front() ); +} + +bool comestible_inv_listitem_bio::print_int_column( comestible_inv_columns col, + std::string &print_str, nc_color &print_col ) +{ + int print_val; + bool need_highlight = false; + switch( col ) { + case COLUMN_ENERGY: + print_val = energy; + break; + default: + return false; + break; + } + char const *print_format = set_string_params( print_col, print_val, need_highlight ); + print_str = string_format( print_format, print_val ); + return true; +} + +std::function +comestible_inv_listitem_bio::compare_function( comestible_inv_columns sortby ) +{ + auto f = comestible_inv_listitem::compare_function( sortby ); + if( f != nullptr ) { + return f; + } + + using itm = comestible_inv_listitem; + using itmb = comestible_inv_listitem_bio; + switch( sortby ) { + case COLUMN_ENERGY: + return []( const itm * d1, const itm * d2, bool & retval ) { + const itmb *d1f = static_cast( d1 ); + const itmb *d2f = static_cast( d2 ); + retval = d1f->energy > d2f->energy; + return d1f->energy != d2f->energy; + }; + default: + return nullptr; + } +} + + diff --git a/src/comestible_inv_listitem.h b/src/comestible_inv_listitem.h new file mode 100644 index 0000000000000..96e42422216be --- /dev/null +++ b/src/comestible_inv_listitem.h @@ -0,0 +1,239 @@ +#pragma once +#ifndef COMESTIBLE_INV_LISTITEM_H +#define COMESTIBLE_INV_LISTITEM_H +#include "cursesdef.h" +#include "units.h" +#include "comestible_inv_area.h" +#include "color.h" +#include "player.h" + +#include +#include +#include +#include +#include +#include + +class item_category; + +//TODO: when changing this, also change comestible_inv_pane.cpp - get_col_data(). Make sure order is preserved. +enum comestible_inv_columns { + COLUMN_NAME, + + COLUMN_SRC, + COLUMN_AMOUNT, + COLUMN_WEIGHT, + COLUMN_VOLUME, + + COLUMN_CALORIES, + COLUMN_QUENCH, + COLUMN_JOY, + COLUMN_EXPIRES, + COLUMN_SHELF_LIFE, + + COLUMN_ENERGY, + + COLUMN_SORTBY_CATEGORY, //not actual clumn + COLUMN_NUM_ENTRIES +}; + +enum comestible_select_state { + SELECTSTATE_NONE, + SELECTSTATE_SELECTED, + SELECTSTATE_CATEGORY +}; +struct col_data { + + public: + comestible_inv_columns id; + private: + std::string col_name; + public: + int width; + char hotkey; + private: + std::string sort_name; + + public: + std::string get_col_name() const { + return _( col_name ); + } + std::string get_sort_name() const { + return _( sort_name ); + } + + col_data( comestible_inv_columns id, std::string col_name, int width, char hotkey, + std::string sort_name ) : + id( id ), + col_name( col_name ), width( width ), hotkey( hotkey ), sort_name( sort_name ) { + + } +}; + + +class comestible_inv_listitem +{ + public: + // *INDENT-OFF* + static col_data get_col_data(comestible_inv_columns col) { + static std::array col_data = { { + {COLUMN_NAME, translate_marker("Name (charges)"),0, 'n', translate_marker("name")}, + + {COLUMN_SRC, translate_marker("src"), 4, ';', ""}, + {COLUMN_AMOUNT, translate_marker("amt"), 5, ';', ""}, + + {COLUMN_WEIGHT, translate_marker("weight"), 7, 'w', translate_marker("weight")}, + {COLUMN_VOLUME, translate_marker("volume"), 7, 'v', translate_marker("volume")}, + + {COLUMN_CALORIES, translate_marker("calories"), 9, 'c', translate_marker("calories")}, + {COLUMN_QUENCH, translate_marker("quench"), 7, 'q', translate_marker("quench")}, + {COLUMN_JOY, translate_marker("joy"), 4, 'j', translate_marker("joy")}, + {COLUMN_EXPIRES, translate_marker("expires in"), 11,'s', translate_marker("spoilage")}, + {COLUMN_SHELF_LIFE, translate_marker("shelf life"), 11,'s', translate_marker("shelf life")}, + + {COLUMN_ENERGY, translate_marker("energy"), 11,'e', translate_marker("energy")}, + + {COLUMN_SORTBY_CATEGORY,translate_marker("fake"), 0,'c', translate_marker("category")} + } }; + return col_data[col]; + } + // *INDENT-ON* + public: + /** + * Index of the item in the itemstack. + */ + int idx; + + /** + * The location of the item, should nevere be AREA_TYPE_MULTI + */ + comestible_inv_area *area; + + using itype_id = std::string; + itype_id id; + // The list of items, and empty when a header + std::list items; + + std::string name; + // Name of the item (singular) without damage (or similar) prefix, used for sorting. + std::string name_without_prefix; + /** + * Whether auto pickup is enabled for this item (based on the name). + */ + bool autopickup; + /** + * The stack count represented by this item, should be >= 1, should be 1 + * for anything counted by charges. + */ + int stacks; + + // from all the items in a stack + units::volume volume; + units::mass weight; + + comestible_select_state is_selected; + nc_color menu_color; + nc_color menu_color_dark; + + virtual void print_columns( std::vector columns, + comestible_select_state selected_state, catacurses::window window, int right_bound, + int cur_print_y ); + protected: + virtual bool print_string_column( comestible_inv_columns col, std::string &print_str, + nc_color &print_col ); + virtual bool print_int_column( comestible_inv_columns col, std::string &print_str, + nc_color &print_col ); + virtual bool print_default_columns( comestible_inv_columns col, std::string &print_str, + nc_color &print_col ); + virtual void print_name( catacurses::window window, int right_bound, int cur_print_y ); + virtual std::function + compare_function( comestible_inv_columns sortby ); + + void set_print_color( nc_color &retval, nc_color default_col ); + + public: + std::function + get_sort_function( comestible_inv_columns sortby, comestible_inv_columns default_sortby ); + + char const *set_string_params( nc_color &print_color, int value, bool need_highlight = false ); + /** + * The item category, or the category header. + */ + const item_category *cat; + + bool from_vehicle; + + const islot_comestible &get_edible_comestible( player &p, const item &it ) const; + + std::string get_time_left_rounded( player &p, const item &it ) const; + std::string time_to_comestible_str( const time_duration &d ) const; + /** + * Whether this is a category header entry, which does *not* have a reference + * to an item, only @ref cat is valid. + */ + bool is_category_header() const; + bool is_item_entry() const; + + comestible_inv_listitem( const item_category *cat = nullptr ); + /** + * Create a normal item entry. + * @param list The list of item pointers. + * @param index The index + * @param area The source area. Must not be AIM_ALL. + * @param from_vehicle Is the item from a vehicle cargo space? + */ + comestible_inv_listitem( const std::list &list, int index, + comestible_inv_area *area, bool from_vehicle ); + + virtual ~comestible_inv_listitem() {} + + private: + void init( const item &it ); +}; + +class comestible_inv_listitem_food : public comestible_inv_listitem +{ + public: + comestible_inv_listitem_food( const item_category *cat = nullptr ); + comestible_inv_listitem_food( const std::list &list, int index, + comestible_inv_area *area, bool from_vehicle ); + void print_columns( std::vector columns, + comestible_select_state selected_state, catacurses::window window, int right_bound, + int cur_print_y ) override; + private: + std::string shelf_life; + std::string exipres_in; + int calories; + int quench; + int joy; + // item conditions, shown before name. Just for display. + int cond_size = 4; + std::vector> cond; + ret_val eat_error = ret_val::make_success(); + protected: + void init( const item &it ); + bool print_string_column( comestible_inv_columns col, std::string &print_str, + nc_color &print_col ) override; + bool print_int_column( comestible_inv_columns col, std::string &print_str, + nc_color &print_col ) override; + void print_name( catacurses::window window, int right_bound, int cur_print_y ) override; + std::function + compare_function( comestible_inv_columns sortby ) override; +}; + +class comestible_inv_listitem_bio: public comestible_inv_listitem +{ + public: + comestible_inv_listitem_bio( const item_category *cat = nullptr ); + comestible_inv_listitem_bio( const std::list &list, int index, + comestible_inv_area *area, bool from_vehicle ); + private: + int energy; + protected: + bool print_int_column( comestible_inv_columns col, std::string &print_str, + nc_color &print_col ) override; + std::function + compare_function( comestible_inv_columns sortby ) override; +}; + +#endif diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index 0c8331d13c083..6923e550e9ca3 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -2,44 +2,25 @@ #include "avatar.h" #include "cata_utility.h" #include "catacharset.h" -#include "debug.h" -#include "field.h" #include "input.h" #include "item_category.h" #include "item_search.h" #include "item_stack.h" -#include "map.h" -#include "mapdata.h" -#include "messages.h" -#include "options.h" #include "output.h" #include "player.h" -#include "player_activity.h" #include "string_formatter.h" #include "string_input_popup.h" -#include "translations.h" -#include "trap.h" -#include "ui.h" #include "uistate.h" -#include "vehicle.h" -#include "vehicle_selector.h" -#include "vpart_position.h" #include "calendar.h" #include "color.h" #include "game_constants.h" #include "int_id.h" #include "inventory.h" #include "item.h" -#include "optional.h" #include "ret_val.h" #include "type_id.h" #include "clzones.h" -#include "colony.h" #include "enums.h" -#include "faction.h" -#include "item_location.h" -#include "map_selector.h" -#include "pimpl.h" #include "bionics.h" #include "comestible_inv_pane.h" #include "material.h" @@ -47,78 +28,21 @@ #include #include #include -#include -#include #include #include #include #include -#include -#include #include #include #if defined(__ANDROID__) # include #endif -struct col_data { - - public: - comestible_inv_columns id; - private: - std::string col_name; - public: - int width; - char hotkey; - private: - std::string sort_name; - - public: - std::string get_col_name() const { - return _( col_name ); - } - std::string get_sort_name() const { - return _( sort_name ); - } - - col_data( comestible_inv_columns id, std::string col_name, int width, char hotkey, - std::string sort_name ) : - id( id ), - col_name( col_name ), width( width ), hotkey( hotkey ), sort_name( sort_name ) { - - } -}; - -// *INDENT-OFF* -static col_data get_col_data(comestible_inv_columns col) { - static std::array col_data = { { - {COLUMN_NAME, translate_marker("Name (charges)"),0, 'n', translate_marker("name")}, - - {COLUMN_SRC, translate_marker("src"), 4, ';', ""}, - {COLUMN_AMOUNT, translate_marker("amt"), 5, ';', ""}, - - {COLUMN_WEIGHT, translate_marker("weight"), 7, 'w', translate_marker("weight")}, - {COLUMN_VOLUME, translate_marker("volume"), 7, 'v', translate_marker("volume")}, - - {COLUMN_CALORIES, translate_marker("calories"), 9, 'c', translate_marker("calories")}, - {COLUMN_QUENCH, translate_marker("quench"), 7, 'q', translate_marker("quench")}, - {COLUMN_JOY, translate_marker("joy"), 4, 'j', translate_marker("joy")}, - {COLUMN_EXPIRES, translate_marker("expires in"), 11,'s', translate_marker("spoilage")}, - {COLUMN_SHELF_LIFE, translate_marker("shelf life"), 11,'s', translate_marker("shelf life")}, - - {COLUMN_ENERGY, translate_marker("energy"), 11,'e', translate_marker("energy")}, - - {COLUMN_SORTBY_CATEGORY,translate_marker("fake"), 0,'c', translate_marker("category")} - } }; - return col_data[col]; -} -// *INDENT-ON* -void comestible_inventory_pane::init( std::vector c, int items_per_page, +void comestible_inventory_pane::init( int items_per_page, catacurses::window w, std::array *a ) { - columns = c; itemsPerPage = items_per_page; window = w; all_areas = a; @@ -142,10 +66,23 @@ void comestible_inventory_pane::init( std::vector c, int uistate.comestible_save.sort_idx ) != columns.end() ) { sortby = static_cast( uistate.comestible_save.sort_idx ); } else { - sortby = COLUMN_NAME; + sortby = default_sortby; } } +comestible_inventory_pane::~comestible_inventory_pane() +{ + clear_items(); +} + +void comestible_inventory_pane::clear_items() +{ + for( auto &i : items ) { + delete i; + } + items.clear(); +} + void comestible_inventory_pane::save_settings( bool reset ) { if( reset ) { @@ -170,14 +107,14 @@ void comestible_inventory_pane::save_settings( bool reset ) void comestible_inventory_pane::add_sort_entries( uilist &sm ) { - col_data c = get_col_data( COLUMN_NAME ); + col_data c = comestible_inv_listitem::get_col_data( COLUMN_NAME ); sm.addentry( c.id, true, c.hotkey, c.get_sort_name() ); if( sortby == COLUMN_NAME ) { sm.selected = 0; } for( size_t i = 0; i < columns.size(); i++ ) { - c = get_col_data( columns[i] ); + c = comestible_inv_listitem::get_col_data( columns[i] ); if( c.get_sort_name() == "" ) { continue; } @@ -269,10 +206,10 @@ void comestible_inventory_pane::print_items() const size_t name_startpos = 3;//is_compact ? 1 : 4; mvwprintz( window, point( name_startpos, 5 ), c_light_gray, - get_col_data( COLUMN_NAME ).get_col_name() ); + comestible_inv_listitem::get_col_data( COLUMN_NAME ).get_col_name() ); int cur_x = max_width; for( size_t i = columns.size(); i -- > 0; ) { - const col_data d = get_col_data( columns[i] ); + const col_data d = comestible_inv_listitem::get_col_data( columns[i] ); if( d.width <= 0 ) { continue; } @@ -282,7 +219,7 @@ void comestible_inventory_pane::print_items() for( int i = page * itemsPerPage, cur_print_y = 6; i < static_cast( items.size() ) && cur_print_y < itemsPerPage + 6; i++, cur_print_y++ ) { - comestible_inv_listitem &sitem = items[i]; + comestible_inv_listitem &sitem = *items[i]; if( sitem.is_category_header() ) { mvwprintz( window, point( ( max_width - utf8_width( sitem.name ) - 6 ) / 2, cur_print_y ), c_cyan, "[%s]", @@ -313,7 +250,7 @@ void comestible_inventory_pane::skip_category_headers( int offset ) assert( static_cast( index ) < items.size() ); // valid index is required assert( offset == -1 || offset == +1 ); // only those two offsets are allowed assert( !items.empty() ); // index would not be valid, and this would be an endless loop - while( !items[index].is_item_entry() ) { + while( !items[index]->is_item_entry() ) { mod_index( offset ); } } @@ -338,9 +275,9 @@ void comestible_inventory_pane::scroll_by( int offset ) } if( inCategoryMode ) { assert( get_cur_item_ptr() != nullptr ); // index must already be valid! - auto cur_cat = items[index].cat; + auto cur_cat = items[index]->cat; if( offset > 0 ) { - while( items[index].cat == cur_cat ) { + while( items[index]->cat == cur_cat ) { index++; if( static_cast( index ) >= items.size() ) { index = 0; // wrap to begin, stop there. @@ -348,7 +285,7 @@ void comestible_inventory_pane::scroll_by( int offset ) } } } else { - while( items[index].cat == cur_cat ) { + while( items[index]->cat == cur_cat ) { index--; if( index < 0 ) { index = static_cast( items.size() ) - 1; // wrap to end, stop there. @@ -369,7 +306,7 @@ comestible_inv_listitem *comestible_inventory_pane::get_cur_item_ptr() if( static_cast( index ) >= items.size() ) { return nullptr; } - return &items[index]; + return items[index]; } void comestible_inventory_pane::set_filter( const std::string &new_filter ) @@ -417,15 +354,15 @@ void comestible_inventory_pane::paginate() for( size_t i = 0; i < items.size(); ++i ) { if( i % itemsPerPage == 0 ) { // first entry on the page, should be a category header - if( items[i].is_item_entry() ) { - items.insert( items.begin() + i, comestible_inv_listitem( items[i].cat ) ); + if( items[i]->is_item_entry() ) { + items.insert( items.begin() + i, create_listitem( items[i]->cat ) ); } } if( ( i + 1 ) % itemsPerPage == 0 && i + 1 < items.size() ) { // last entry of the page, but not the last entry at all! // Must *not* be a category header! - if( items[i].is_category_header() ) { - items.insert( items.begin() + i, comestible_inv_listitem() ); + if( items[i]->is_category_header() ) { + items.insert( items.begin() + i, create_listitem() ); } } } @@ -445,114 +382,10 @@ void comestible_inventory_pane::fix_index() skip_category_headers( +1 ); } -struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { - bool operator()( char x, char y ) const { - return toupper( static_cast( x ) ) < toupper( static_cast( y ) ); - } -}; - -struct comestible_inv_sorter { - comestible_inv_columns sortby; - comestible_inv_columns default_sortby; - comestible_inv_sorter( comestible_inv_columns sort, comestible_inv_columns default_sort ) { - sortby = sort; - default_sortby = default_sort; - } - bool operator()( const comestible_inv_listitem &d1, const comestible_inv_listitem &d2 ) { - return compare( sortby, d1, d2 ); - } - - bool compare( comestible_inv_columns compare_by, const comestible_inv_listitem &d1, - const comestible_inv_listitem &d2 ) { - switch( compare_by ) { - case COLUMN_NAME: - const std::string *n1; - const std::string *n2; - if( d1.name_without_prefix == d2.name_without_prefix ) { - if( d1.name == d2.name ) { - //fall through - break; - } else { - //if names without prefix equal, compare full name - n1 = &d1.name; - n2 = &d2.name; - } - } else { - //else compare name without prefix - n1 = &d1.name_without_prefix; - n2 = &d2.name_without_prefix; - } - - return std::lexicographical_compare( n1->begin(), n1->end(), n2->begin(), n2->end(), - sort_case_insensitive_less() ); - break; - case COLUMN_WEIGHT: - if( d1.weight != d2.weight ) { - return d1.weight > d2.weight; - } - break; - case COLUMN_VOLUME: - if( d1.volume != d2.volume ) { - return d1.volume > d2.volume; - } - break; - case COLUMN_CALORIES: - if( d1.calories != d2.calories ) { - return d1.calories > d2.calories; - } - break; - case COLUMN_QUENCH: - if( d1.quench != d2.quench ) { - return d1.quench > d2.quench; - } - break; - case COLUMN_JOY: - if( d1.joy != d2.joy ) { - return d1.joy > d2.joy; - } - break; - case COLUMN_ENERGY: - if( d1.energy != d2.energy ) { - return d1.energy > d2.energy; - } - break; - case COLUMN_EXPIRES: - case COLUMN_SHELF_LIFE: - if( d1.items.front()->spoilage_sort_order() != d2.items.front()->spoilage_sort_order() ) { - return d1.items.front()->spoilage_sort_order() < d2.items.front()->spoilage_sort_order(); - } - break; - case COLUMN_SORTBY_CATEGORY: - assert( d1.cat != nullptr ); - assert( d2.cat != nullptr ); - if( d1.cat != d2.cat ) { - return *d1.cat < *d2.cat; - } else if( d1.is_category_header() ) { - return true; - } else if( d2.is_category_header() ) { - return false; - } - break; - case COLUMN_SRC: - case COLUMN_AMOUNT: - case COLUMN_NUM_ENTRIES: - //shouldn't be here - assert( false ); - break; - } - - if( compare_by == default_sortby ) { - return false; - } else { - return compare( default_sortby, d1, d2 ); - } - } -}; - void comestible_inventory_pane::recalc() { needs_recalc = false; - items.clear(); + clear_items(); // Add items from the source location or in case of all 9 surrounding squares, // add items from several locations. @@ -586,21 +419,22 @@ void comestible_inventory_pane::recalc() if( sortby == COLUMN_SORTBY_CATEGORY ) { std::set categories; for( auto &it : items ) { - categories.insert( it.cat ); + categories.insert( it->cat ); } for( auto &cat : categories ) { - items.push_back( comestible_inv_listitem( cat ) ); + items.push_back( create_listitem( cat ) ); } } - - // Finally sort all items (category headers will now be moved to their proper position) - std::stable_sort( items.begin(), items.end(), comestible_inv_sorter( sortby, default_sortby ) ); + if( !items.empty() ) { + std::stable_sort( items.begin(), items.end(), items.front()->get_sort_function( sortby, + default_sortby ) ); + } paginate(); int i = 0; for( auto &it : items ) { - if( it.items.front() == uistate.comestible_save.selected_itm ) { + if( it->items.front() == uistate.comestible_save.selected_itm ) { uistate.comestible_save.selected_idx = i; index = i; break; @@ -609,7 +443,6 @@ void comestible_inventory_pane::recalc() } } -//TODO: I want to move functionality to comestible_inv_area, but I dunno how to convert AIM_INVENTORY, AIM_WORN and other to the same type. void comestible_inventory_pane::add_items_from_area( comestible_inv_area *area, bool from_cargo, units::volume &ret_volume, units::mass &ret_weight ) { @@ -617,51 +450,23 @@ void comestible_inventory_pane::add_items_from_area( comestible_inv_area *area, if( !area->is_valid() ) { return; } - player &u = g->u; ret_volume = 0_ml; ret_weight = 0_gram; + comestible_inv_listitem *it; // Existing items are *not* cleared on purpose, this might be called // several times in case all surrounding squares are to be shown. - if( area->info.id == comestible_inv_area_info::AIM_INVENTORY ) { - const invslice &stacks = u.inv.slice(); - for( size_t x = 0; x < stacks.size(); ++x ) { - std::list item_pointers; - for( item &i : *stacks[x] ) { - item_pointers.push_back( &i ); - } - comestible_inv_listitem it( item_pointers, x, area, false ); - if( is_filtered( *it.items.front() ) ) { - continue; - } - ret_volume += it.volume; - ret_weight += it.weight; - items.push_back( it ); - } - } else if( area->info.id == comestible_inv_area_info::AIM_WORN ) { - auto iter = u.worn.begin(); - for( size_t i = 0; i < u.worn.size(); ++i, ++iter ) { - comestible_inv_listitem it( &*iter, i, 1, area, false ); - if( is_filtered( *it.items.front() ) ) { - continue; - } - ret_volume += it.volume; - ret_weight += it.weight; - items.push_back( it ); - } - } else { - const comestible_inv_area::area_items stacks = area->get_items( from_cargo ); + const comestible_inv_area::area_items stacks = area->get_items( from_cargo ); - for( size_t x = 0; x < stacks.size(); ++x ) { - comestible_inv_listitem it( stacks[x], x, area, from_cargo ); - if( is_filtered( *it.items.front() ) ) { - continue; - } - ret_volume += it.volume; - ret_weight += it.weight; - items.push_back( it ); + for( size_t x = 0; x < stacks.size(); ++x ) { + it = create_listitem( stacks[x], x, area, from_cargo ); + if( is_filtered( *it->items.front() ) ) { + continue; } + ret_volume += it->volume; + ret_weight += it->weight; + items.push_back( it ); } } @@ -715,7 +520,8 @@ void comestible_inventory_pane::redraw() wattron( w, c_cyan ); // draw a darker border around the inactive pane draw_border( w, BORDER_COLOR ); - mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), get_col_data( sortby ).get_sort_name() ); + mvwprintw( w, point( 3, 0 ), _( "< [s]ort: %s >" ), + comestible_inv_listitem::get_col_data( sortby ).get_sort_name() ); if( !title.empty() ) { std::string title_string = string_format( "<< %s >>", title ); @@ -808,449 +614,61 @@ int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) return get_square( comestible_inv_area_info::AIM_INVENTORY )->info.hscreen.y + ofs; } -void comestible_inv_listitem::print_columns( std::vector columns, - comestible_select_state selected_state, catacurses::window window, int right_bound, - int cur_print_y ) -{ - - is_selected = selected_state; - int w; - for( std::vector::reverse_iterator col_iter = columns.rbegin(); - col_iter != columns.rend(); ++col_iter ) { - w = get_col_data( *col_iter ).width; - if( w <= 0 ) { - continue; - } - right_bound -= w; - if( print_string_column( *col_iter, window, right_bound, cur_print_y ) ) { - continue; - } - - if( print_int_column( *col_iter, window, right_bound, cur_print_y ) ) { - continue; - } - - if( print_default_columns( *col_iter, window, right_bound, cur_print_y ) ) { - continue; - } - - //we encountered a column that had no printing code - assert( false ); - } - print_name( window, right_bound, cur_print_y ); -} - -bool comestible_inv_listitem::print_string_column( comestible_inv_columns col, - catacurses::window window, int cur_print_x, int cur_print_y ) -{ - std::string print_string; - switch( col ) { - case COLUMN_SHELF_LIFE: - print_string = shelf_life; - break; - case COLUMN_EXPIRES: - print_string = exipres_in; - break; - default: - return false; - } - nc_color print_color; - set_print_color( print_color, c_cyan ); - mvwprintz( window, point( cur_print_x, cur_print_y ), print_color, "%*s", get_col_data( col ).width, - print_string ); - return true; -} - -bool comestible_inv_listitem::print_int_column( comestible_inv_columns col, - catacurses::window window, int cur_print_x, int cur_print_y ) +void comestible_inventory_pane_food::init( int items_per_page, catacurses::window w, + std::array *s ) { - int print_val; - bool need_highlight = false; - switch( col ) { - case COLUMN_CALORIES: - print_val = calories; - break; - case COLUMN_QUENCH: - print_val = quench; - break; - case COLUMN_JOY: - print_val = joy; - need_highlight = is_mushy; - break; - case COLUMN_ENERGY: - print_val = energy; - break; - default: - return false; - break; - } - nc_color print_color; - char const *print_format = set_string_params( print_color, print_val, need_highlight ); - std::string s = string_format( print_format, print_val ); - mvwprintz( window, point( cur_print_x, cur_print_y ), print_color, "%*s", get_col_data( col ).width, - s ); - return true; -} - -char const *comestible_inv_listitem::set_string_params( nc_color &print_color, int value, - bool need_highlight ) -{ - char const *string_format; - if( value > 0 ) { - print_color = need_highlight ? c_yellow_green : c_green; - string_format = "+%d"; - } else if( value < 0 ) { - print_color = need_highlight ? c_yellow_red : c_red; - string_format = "%d"; + columns = { COLUMN_CALORIES, COLUMN_QUENCH, COLUMN_JOY }; + if( g->u.can_estimate_rot() ) { + columns.emplace_back( COLUMN_EXPIRES ); } else { - print_color = need_highlight ? c_yellow : c_dark_gray; - string_format = ""; + columns.emplace_back( COLUMN_SHELF_LIFE ); } - - set_print_color( print_color, print_color ); - return string_format; -} - -void comestible_inv_listitem::set_print_color( nc_color &retval, nc_color default_col ) -{ - switch( is_selected ) { - case SELECTSTATE_NONE: - retval = default_col; - break; - case SELECTSTATE_SELECTED: - retval = hilite( c_white ); - break; - case SELECTSTATE_CATEGORY: - retval = c_white_red; - break; - default: - break; - } -} - -bool comestible_inv_listitem::print_default_columns( comestible_inv_columns col, - catacurses::window window, int cur_print_x, int cur_print_y ) -{ - nc_color print_color; - std::string s; - - switch( col ) { - case COLUMN_VOLUME: { - bool it_vol_truncated = false; - double it_vol_value = 0.0; - s = format_volume( volume, 5, &it_vol_truncated, &it_vol_value ); - if( it_vol_truncated && it_vol_value > 0.0 ) { - print_color = c_red; - } else { - print_color = volume.value() > 0 ? menu_color : menu_color_dark; - } - break; + special_filter = []( const item & it ) { + const std::string n = it.get_category().name(); + if( uistate.comestible_save.show_food && n != "FOOD" ) { + return true; } - - case COLUMN_WEIGHT: { - double it_weight = convert_weight( weight ); - size_t w_precision; - print_color = it_weight > 0 ? menu_color : menu_color_dark; - - if( it_weight >= 1000.0 ) { - if( it_weight >= 10000.0 ) { - print_color = c_red; - it_weight = 9999.0; - } - w_precision = 0; - } else if( it_weight >= 100.0 ) { - w_precision = 1; - } else { - w_precision = 2; - } - s = string_format( "%5.*f", w_precision, it_weight ); - break; - } - case COLUMN_AMOUNT: { - if( stacks > 1 ) { - print_color = menu_color; - if( stacks > 9999 ) { - stacks = 9999; - print_color = c_red; - } - s = string_format( "%4d", stacks ); - } else { - s = ""; - } - break; + if( !uistate.comestible_save.show_food && n != "DRUGS" ) { + return true; } - case COLUMN_SRC: - print_color = menu_color; - s = area->info.get_shortname(); - break; - default: - return false; - break; - } - set_print_color( print_color, print_color ); - mvwprintz( window, point( cur_print_x, cur_print_y ), print_color, "%*s", get_col_data( col ).width, - s ); - return true; -} - -void comestible_inv_listitem::print_name( catacurses::window window, - int right_bound, int cur_print_y ) -{ - std::string item_name; - - item *it = items.front(); - if( it->is_money() ) { - //Count charges - unsigned int charges_total = 0; - for( const auto item : items ) { - charges_total += item->charges; + if( !g->u.can_consume( it ) ) { + return true; } - item_name = it->display_money( items.size(), charges_total ); - } else { - item_name = it->display_name(); - } - - if( get_option( "ITEM_SYMBOLS" ) ) { - item_name = string_format( "%s %s", it->symbol(), item_name ); - } - - int name_startpos = cond_size; - nc_color print_color; - for( size_t i = 0; i < cond.size(); i++ ) { - auto c = cond[i]; - set_print_color( print_color, c.second ); - mvwprintz( window, point( i + 1, cur_print_y ), print_color, "%c", c.first ); - } - set_print_color( print_color, menu_color ); - if( is_selected ) { //fill whole line with color - mvwprintz( window, point( cond.size() + 1, cur_print_y ), print_color, "%*s", right_bound, "" ); - } - int max_name_length = right_bound - name_startpos - 1; - trim_and_print( window, point( name_startpos, cur_print_y ), max_name_length, print_color, "%s", - item_name ); -} - -const islot_comestible &comestible_inv_listitem::get_edible_comestible( player &p, - const item &it ) const -{ - if( it.is_comestible() && p.can_eat( it ).success() ) { - // Ok since can_eat() returns false if is_craft() is true - return *it.type->comestible; - } - static const islot_comestible dummy{}; - return dummy; -} - - -std::string comestible_inv_listitem::get_time_left_rounded( player &p, const item &it ) const -{ - if( it.is_going_bad() ) { - return _( "soon!" ); - } - - time_duration time_left = 0_turns; - const time_duration shelf_life = get_edible_comestible( p, it ).spoils; - if( shelf_life > 0_turns ) { - 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; - } - } - - //commneted code will give approximate times instead of exact ones, in case we want that - //const auto make_result = [this](const time_duration& d, const char* verbose_str, - // const char* short_str) { - // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); - //}; - - time_duration divider = 0_turns; - time_duration vicinity = 0_turns; - - if( time_left > 1_days ) { - divider = 1_days; - vicinity = 2_hours; - } else if( time_left > 1_hours ) { - divider = 1_hours; - vicinity = 5_minutes; - } // Minutes and seconds can be estimated precisely. - - if( divider != 0_turns ) { - const time_duration remainder = time_left % divider; - - if( remainder >= divider - vicinity ) { - time_left += divider; - } else if( remainder > vicinity ) { - if( remainder < divider / 2 ) { - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("> %s", time_to_comestible_str(time_left)); - } else { - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("< %s", time_to_comestible_str(time_left)); - } - } - } - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("~ %s", time_to_comestible_str(time_left)); -} - -std::string comestible_inv_listitem::time_to_comestible_str( const time_duration &d ) const -{ - if( d >= calendar::INDEFINITELY_LONG_DURATION ) { - return _( "forever" ); - } - - const float day = to_days( d ); - std::string format; - if( day < 1.00 ) { - format = _( "%.2f days" ); - } else if( day > 1.00 ) { - format = _( "%.0f days" ); - } else { - format = _( "1 day" ); - } - - return string_format( format, day ); -} - -comestible_inv_listitem::comestible_inv_listitem( item *an_item, int index, int count, - comestible_inv_area *area, bool from_vehicle ) - : idx( index ) - , area( area ) - , id( an_item->typeId() ) - , name( an_item->tname( count ) ) - , name_without_prefix( an_item->tname( 1, false ) ) - , autopickup( get_auto_pickup().has_rule( an_item ) ) - , stacks( count ) - , volume( an_item->volume() * stacks ) - , weight( an_item->weight() * stacks ) - , cat( &an_item->get_category() ) - , from_vehicle( from_vehicle ) -{ - items.push_back( an_item ); - init( g->u.get_consumable_from( *an_item ) ); - energy = g->u.get_acquirable_energy( *an_item ); + return false; + }; + title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; + default_sortby = COLUMN_EXPIRES; + comestible_inventory_pane::init( items_per_page, w, s ); } - -comestible_inv_listitem::comestible_inv_listitem( const std::list &list, int index, - comestible_inv_area *area, bool from_vehicle ) : - idx( index ), - area( area ), - id( list.front()->typeId() ), - items( list ), - name( list.front()->tname( list.size() ) ), - name_without_prefix( list.front()->tname( 1, false ) ), - autopickup( get_auto_pickup().has_rule( list.front() ) ), - stacks( list.size() ), - volume( list.front()->volume() * stacks ), - weight( list.front()->weight() * stacks ), - cat( &list.front()->get_category() ), - from_vehicle( from_vehicle ) +comestible_inv_listitem *comestible_inventory_pane_food::create_listitem( std::list list, + int index, comestible_inv_area *area, bool from_vehicle ) { - init( g->u.get_consumable_from( *list.front() ) ); - energy = g->u.get_acquirable_energy( *list.front() ); + return new comestible_inv_listitem_food( list, index, area, from_vehicle ); } - -void comestible_inv_listitem::init( const item &it ) +comestible_inv_listitem *comestible_inventory_pane_food::create_listitem( + const item_category *cat ) { - player &p = g->u; - islot_comestible edible = get_edible_comestible( p, it ); - - menu_color = it.color_in_inventory(); - - // statuses - const auto &comest = it.get_comestible(); - cond.reserve( cond_size ); - const bool eat_verb = it.has_flag( "USE_EAT_VERB" ); - const bool is_food = eat_verb || comest->comesttype == "FOOD"; - const bool is_drink = !eat_verb && comest->comesttype == "DRINK"; - - bool craft_only = false; - bool warm_only = false; - - if( it.is_craft() ) { - craft_only = true; - } else if( is_food || is_drink ) { - for( const auto &elem : it.type->materials ) { - if( !elem->edible() ) { - craft_only = true; - break; - } - } - } - if( !craft_only && it.item_tags.count( "FROZEN" ) && !it.has_flag( "EDIBLE_FROZEN" ) && - !it.has_flag( "MELTS" ) ) { - warm_only = true; - } - input_context ctxt( "COMESTIBLE_INVENTORY" ); - if( craft_only ) { - cond.emplace_back( ctxt.get_desc( "CRAFT_WITH" )[0], c_cyan ); - } else if( warm_only ) { - cond.emplace_back( ctxt.get_desc( "HEAT_UP" )[0], c_red ); - } - //check stolen - if( it.has_owner() ) { - const faction *item_fac = it.get_owner(); - if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { - cond.emplace_back( '!', c_light_red ); - } - } - - exipres_in = ""; - shelf_life = ""; - if( edible.spoils > 0_turns ) { - if( !it.rotten() ) { - exipres_in = get_time_left_rounded( p, it ); - } - shelf_life = to_string_clipped( edible.spoils ); - } - - calories = p.kcal_for( it ); - quench = edible.quench; - joy = p.fun_for( it ).first; - is_mushy = it.has_flag( "MUSHY" ); - - menu_color_dark = c_dark_gray; - assert( stacks >= 1 ); -} - - -comestible_inv_listitem::comestible_inv_listitem() - : idx() - , area() - , id( "null" ) - , autopickup() - , stacks() - , cat( nullptr ) -{ - menu_color_dark = c_dark_gray; + return new comestible_inv_listitem_food( cat ); } -comestible_inv_listitem::comestible_inv_listitem( const item_category *cat ) - : idx() - , area() - , id( "null" ) - , name( cat->name() ) - , autopickup() - , stacks() - , cat( cat ) +void comestible_inventory_pane_bio::init( int items_per_page, catacurses::window w, + std::array *s ) { - menu_color_dark = c_dark_gray; + columns = { COLUMN_ENERGY, COLUMN_SORTBY_CATEGORY }; + special_filter = []( const item & it ) { + return !g->u.can_consume( it ) || g->u.get_acquirable_energy( it ) <= 0; + }; + title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name.translated(); + default_sortby = COLUMN_ENERGY; + comestible_inventory_pane::init( items_per_page, w, s ); } - -bool comestible_inv_listitem::is_category_header() const +comestible_inv_listitem *comestible_inventory_pane_bio::create_listitem( std::list list, + int index, comestible_inv_area *area, bool from_vehicle ) { - return items.empty() && cat != nullptr; + return new comestible_inv_listitem_bio( list, index, area, from_vehicle ); } - -bool comestible_inv_listitem::is_item_entry() const +comestible_inv_listitem *comestible_inventory_pane_bio::create_listitem( const item_category *cat ) { - return !items.empty(); + return new comestible_inv_listitem_bio( cat ); } diff --git a/src/comestible_inv_pane.h b/src/comestible_inv_pane.h index f482752175d50..23eaca88ff267 100644 --- a/src/comestible_inv_pane.h +++ b/src/comestible_inv_pane.h @@ -4,51 +4,17 @@ #include "cursesdef.h" #include "point.h" #include "units.h" -#include "game.h" -#include "ui.h" -#include "itype.h" #include "comestible_inv_area.h" +#include "comestible_inv_listitem.h" #include "color.h" -#include -#include #include #include #include -#include #include #include #include -class item_category; - -//TODO: when changing this, also change comestible_inv_pane.cpp - get_col_data(). Make sure order is preserved. -enum comestible_inv_columns { - COLUMN_NAME, - - COLUMN_SRC, - COLUMN_AMOUNT, - COLUMN_WEIGHT, - COLUMN_VOLUME, - - COLUMN_CALORIES, - COLUMN_QUENCH, - COLUMN_JOY, - COLUMN_EXPIRES, - COLUMN_SHELF_LIFE, - - COLUMN_ENERGY, - - COLUMN_SORTBY_CATEGORY, //not actual clumn - COLUMN_NUM_ENTRIES -}; - -enum comestible_select_state { - SELECTSTATE_NONE, - SELECTSTATE_SELECTED, - SELECTSTATE_CATEGORY -}; - struct legend_data { point position; std::string message; @@ -59,139 +25,9 @@ struct legend_data { } }; -class comestible_inv_listitem -{ - public: - using itype_id = std::string; - /** - * Index of the item in the itemstack. - */ - int idx; - /** - * The location of the item, should nevere be AREA_TYPE_MULTI - */ - comestible_inv_area *area; - - itype_id id; - // The list of items, and empty when a header - std::list items; - /** - * The displayed name of the item/the category header. - */ - std::string name; - /** - * Name of the item (singular) without damage (or similar) prefix, used for sorting. - */ - std::string name_without_prefix; - /** - * Whether auto pickup is enabled for this item (based on the name). - */ - bool autopickup; - /** - * The stack count represented by this item, should be >= 1, should be 1 - * for anything counted by charges. - */ - int stacks; - - // from all the items in a stack - units::volume volume; - units::mass weight; - - std::string shelf_life; - std::string exipres_in; - int calories; - int quench; - int joy; - bool is_mushy; - // when eating with CBMs - int energy; - - // item conditions, shown before name. Just for display. - int cond_size = 3; - std::vector> cond; - - comestible_select_state is_selected; - nc_color menu_color; - nc_color menu_color_dark; - - void print_columns( std::vector columns, - comestible_select_state selected_state, catacurses::window window, int right_bound, - int cur_print_y ); - private: - bool print_string_column( comestible_inv_columns col, catacurses::window window, int cur_print_x, - int cur_print_y ); - bool print_int_column( comestible_inv_columns col, catacurses::window window, int cur_print_x, - int cur_print_y ); - void print_name( catacurses::window window, int right_bound, int cur_print_y ); - bool print_default_columns( comestible_inv_columns col, catacurses::window window, int cur_print_x, - int cur_print_y ); - void set_print_color( nc_color &retval, nc_color default_col ); - public: - - - char const *set_string_params( nc_color &print_color, int value, bool need_highlight = false ); - - /** - * The item category, or the category header. - */ - const item_category *cat; - /** - * Is the item stored in a vehicle? - */ - bool from_vehicle; - - - const islot_comestible &get_edible_comestible( player &p, const item &it ) const; - - std::string get_time_left_rounded( player &p, const item &it ) const; - - std::string time_to_comestible_str( const time_duration &d ) const; - /** - * Whether this is a category header entry, which does *not* have a reference - * to an item, only @ref cat is valid. - */ - bool is_category_header() const; - - /** Returns true if this is an item entry */ - bool is_item_entry() const; - /** - * Create a category header entry. - * @param cat The category reference, must not be null. - */ - comestible_inv_listitem( const item_category *cat ); - - /** - * Creates an empty entry, both category and item pointer are null. - */ - comestible_inv_listitem(); - /** - * Create a normal item entry. - * @param an_item The item pointer. Must not be null. - * @param index The index - * @param count The stack size - * @param area The source area. Must not be AIM_ALL. - * @param from_vehicle Is the item from a vehicle cargo space? - */ - comestible_inv_listitem( item *an_item, int index, int count, - comestible_inv_area *area, bool from_vehicle ); - /** - * Create a normal item entry. - * @param list The list of item pointers. - * @param index The index - * @param area The source area. Must not be AIM_ALL. - * @param from_vehicle Is the item from a vehicle cargo space? - */ - comestible_inv_listitem( const std::list &list, int index, - comestible_inv_area *area, bool from_vehicle ); - void init( const item &an_item ); -}; - -/** - * Displayed pane, what is shown on the screen. - */ class comestible_inventory_pane { - private: + protected: // pointer to the square this pane is pointing to comestible_inv_area *cur_area; bool viewing_cargo = false; @@ -202,7 +38,7 @@ class comestible_inventory_pane //supplied by parent to say which columns need to be displayed std::vector columns; - std::vector items; + std::vector items; //true when user is editing item filter bool filter_edit; @@ -215,9 +51,6 @@ class comestible_inventory_pane * @return Whether the item should be filtered (and not shown). */ bool is_filtered( const comestible_inv_listitem &it ) const; - /** - * Same as the other, but checks the real item. - */ bool is_filtered( const item &it ) const; int print_header( comestible_inv_area *sel_area ); @@ -228,6 +61,9 @@ class comestible_inventory_pane void add_items_from_area( comestible_inv_area *area, bool from_cargo, units::volume &ret_volume, units::mass &ret_weight ); + virtual comestible_inv_listitem *create_listitem( std::list list, int index, + comestible_inv_area *area, bool from_vehicle ) = 0; + virtual comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ) = 0; void print_items(); @@ -236,10 +72,14 @@ class comestible_inventory_pane /** Only add offset to index, but wrap around! */ void mod_index( int offset ); + void clear_items(); + mutable std::map> filtercache; public: + virtual ~comestible_inventory_pane(); + /** * Index of the selected item (index of @ref items), */ @@ -266,8 +106,8 @@ class comestible_inventory_pane bool needs_recalc; bool needs_redraw; - void init( std::vector c, int items_per_page, catacurses::window w, - std::array *s ); + virtual void init( int items_per_page, catacurses::window w, + std::array *s ); void save_settings( bool reset ); /** @@ -315,4 +155,23 @@ class comestible_inventory_pane return viewing_cargo; } }; + +class comestible_inventory_pane_food : public comestible_inventory_pane +{ + using comestible_inventory_pane::comestible_inventory_pane; + void init( int items_per_page, catacurses::window w, + std::array *s ); + comestible_inv_listitem *create_listitem( std::list list, int index, + comestible_inv_area *area, bool from_vehicle ); + comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ); +}; +class comestible_inventory_pane_bio: public comestible_inventory_pane +{ + using comestible_inventory_pane::comestible_inventory_pane; + void init( int items_per_page, catacurses::window w, + std::array *s ); + comestible_inv_listitem *create_listitem( std::list list, int index, + comestible_inv_area *area, bool from_vehicle ); + comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ); +}; #endif From ca556e5ae5e1b2bfd5e34ba8de4130b4d76156d2 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 11 Sep 2019 18:18:06 -0400 Subject: [PATCH 16/19] travis 1 --- src/comestible_inv_area.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index 7a00e508a2844..f9e363ee15b95 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -226,7 +226,7 @@ comestible_inv_area::area_items comestible_inv_area::get_items( bool from_cargo retval.reserve( u.worn.size() ); for( size_t i = 0; i < u.worn.size(); ++i, ++iter ) { - std::list item_pointers = { {& *iter} }; + std::list item_pointers = { & *iter }; retval.push_back( item_pointers ); } } else { From ec1e0375d55fa000f521985b4d82b245b98b074c Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 11 Sep 2019 21:29:54 -0400 Subject: [PATCH 17/19] merged with some advanced_inv changes travis 2 --- src/comestible_inv.cpp | 9 +++------ src/comestible_inv.h | 4 ++-- src/comestible_inv_area.cpp | 4 ---- src/comestible_inv_area.h | 4 ++-- src/comestible_inv_listitem.cpp | 6 ++---- src/comestible_inv_listitem.h | 2 +- src/comestible_inv_pane.cpp | 8 +++----- 7 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index 03a2634c20a1b..d31a83ca3a234 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -36,10 +36,6 @@ #include #include -#if defined(__ANDROID__) -# include -#endif - enum aim_exit { exit_none = 0, exit_okay, @@ -103,6 +99,7 @@ comestible_inventory::~comestible_inventory() werase( mm_border ); werase( window ); g->refresh_all(); + g->u.check_item_encumbrance_flag(); } delete pane; } @@ -226,7 +223,7 @@ input_context comestible_inventory::register_actions() return ctxt; } -const std::string comestible_inventory::process_actions( input_context ctxt ) +std::string comestible_inventory::process_actions( input_context ctxt ) { using ai = comestible_inv_area_info; // current item in source pane, might be null @@ -534,7 +531,7 @@ void comestible_inventory_food::set_additional_info( std::vector da comestible_inventory::set_additional_info( data ); } -const std::string comestible_inventory_food::process_actions( input_context ctxt ) +std::string comestible_inventory_food::process_actions( input_context ctxt ) { const std::string action = comestible_inventory::process_actions( ctxt ); diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 1ea8366562f42..7f2eed0f37aad 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -26,7 +26,7 @@ class comestible_inventory virtual void display(); protected: virtual input_context register_actions(); - virtual const std::string process_actions( input_context ctxt ); + virtual std::string process_actions( input_context ctxt ); const int head_height; const int min_w_height; @@ -85,7 +85,7 @@ class comestible_inventory_food : public comestible_inventory protected: void init() override; input_context register_actions() override; - const std::string process_actions( input_context ctxt ) override; + std::string process_actions( input_context ctxt ) override; void set_additional_info( std::vector data ) override; private: //try to find a way to warm up/defrost an item, and do it diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index f9e363ee15b95..39fa8a29dafd2 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -37,10 +37,6 @@ #include #include -#if defined(__ANDROID__) -# include -#endif - void comestible_inv_area::init() { offset = info.default_offset; diff --git a/src/comestible_inv_area.h b/src/comestible_inv_area.h index 25ee2246f3277..f086d60e34332 100644 --- a/src/comestible_inv_area.h +++ b/src/comestible_inv_area.h @@ -61,10 +61,10 @@ struct comestible_inv_area_info { area_type type; - const std::string get_name() const { + std::string get_name() const { return _( name ); } - const std::string get_shortname() const { + std::string get_shortname() const { return _( shortname ); } diff --git a/src/comestible_inv_listitem.cpp b/src/comestible_inv_listitem.cpp index 69c243ee23e62..8cf997fb9a6bf 100644 --- a/src/comestible_inv_listitem.cpp +++ b/src/comestible_inv_listitem.cpp @@ -30,9 +30,6 @@ #include #include #include -#if defined(__ANDROID__) -# include -#endif void comestible_inv_listitem::print_columns( std::vector columns, comestible_select_state selected_state, catacurses::window window, int right_bound, @@ -330,7 +327,7 @@ comestible_inv_listitem::get_sort_function( comestible_inv_columns sortby, auto f1 = compare_function( sortby ); auto f2 = compare_function( default_sortby ); - bool retval; + bool retval = false; if( !f1( d1, d2, retval ) ) { f2( d1, d2, retval ); } @@ -349,6 +346,7 @@ comestible_inv_listitem::compare_function( comestible_inv_columns sortby ) const std::string *n2; if( d1->name_without_prefix == d2->name_without_prefix ) { if( d1->name == d2->name ) { + retval = false; return false; } else { //if names without prefix equal, compare full name diff --git a/src/comestible_inv_listitem.h b/src/comestible_inv_listitem.h index 96e42422216be..c3f0a9257c7f8 100644 --- a/src/comestible_inv_listitem.h +++ b/src/comestible_inv_listitem.h @@ -185,7 +185,7 @@ class comestible_inv_listitem comestible_inv_listitem( const std::list &list, int index, comestible_inv_area *area, bool from_vehicle ); - virtual ~comestible_inv_listitem() {} + virtual ~comestible_inv_listitem() = default; private: void init( const item &it ); diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index 6923e550e9ca3..cf3e5babc0ff1 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -24,6 +24,7 @@ #include "bionics.h" #include "comestible_inv_pane.h" #include "material.h" +#include "ime.h" #include #include @@ -135,11 +136,8 @@ void comestible_inventory_pane::start_user_filtering( int h, int w ) .max_length( 256 ) .text( filter ); -#if defined(__ANDROID__) - if( get_option( "ANDROID_AUTO_KEYBOARD" ) ) { - SDL_StartTextInput(); - } -#endif + + ime_sentry sentry; do { mvwprintz( window, point( 2, getmaxy( window ) - 1 ), c_cyan, "< " ); From f36506053431372ddb5a04da891cddf88bfb15dc Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 11 Sep 2019 23:22:01 -0400 Subject: [PATCH 18/19] travis 3 --- src/comestible_inv.cpp | 4 ++-- src/comestible_inv_area.cpp | 4 ++-- src/comestible_inv_pane.cpp | 2 +- src/comestible_inv_pane.h | 14 +++++++------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index d31a83ca3a234..ccf2f93bdba1d 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -624,8 +624,8 @@ void comestible_inventory_food::heat_up( item *it_to_heat ) std::vector < const recipe * > water_recipes = lr.search_result( water.typeId() ); requirement_data req = water_recipes[0]->requirements(); - const std::vector> req_tools = req.get_tools(); - const std::vector> req_qual = req.get_qualities(); + const std::vector> &req_tools = req.get_tools(); + const std::vector> &req_qual = req.get_qualities(); // see if we have required tools (e.g. BOIL 1) bool has_qual = true; diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index 39fa8a29dafd2..e09c6fa787a38 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -209,9 +209,9 @@ comestible_inv_area::area_items comestible_inv_area::get_items( bool from_cargo const invslice &stacks = u.inv.slice(); retval.reserve( stacks.size() ); - for( size_t x = 0; x < stacks.size(); ++x ) { + for( auto stack : stacks ) { std::list item_pointers; - for( item &i : *stacks[x] ) { + for( item &i : *stack ) { item_pointers.push_back( &i ); } diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index cf3e5babc0ff1..89fb5673dc457 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -116,7 +116,7 @@ void comestible_inventory_pane::add_sort_entries( uilist &sm ) for( size_t i = 0; i < columns.size(); i++ ) { c = comestible_inv_listitem::get_col_data( columns[i] ); - if( c.get_sort_name() == "" ) { + if( c.get_sort_name().empty() ) { continue; } diff --git a/src/comestible_inv_pane.h b/src/comestible_inv_pane.h index 23eaca88ff267..76af20a013751 100644 --- a/src/comestible_inv_pane.h +++ b/src/comestible_inv_pane.h @@ -107,7 +107,7 @@ class comestible_inventory_pane bool needs_redraw; virtual void init( int items_per_page, catacurses::window w, - std::array *s ); + std::array *a ); void save_settings( bool reset ); /** @@ -160,18 +160,18 @@ class comestible_inventory_pane_food : public comestible_inventory_pane { using comestible_inventory_pane::comestible_inventory_pane; void init( int items_per_page, catacurses::window w, - std::array *s ); + std::array *s ) override; comestible_inv_listitem *create_listitem( std::list list, int index, - comestible_inv_area *area, bool from_vehicle ); - comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ); + comestible_inv_area *area, bool from_vehicle ) override; + comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ) override; }; class comestible_inventory_pane_bio: public comestible_inventory_pane { using comestible_inventory_pane::comestible_inventory_pane; void init( int items_per_page, catacurses::window w, - std::array *s ); + std::array *s ) override; comestible_inv_listitem *create_listitem( std::list list, int index, - comestible_inv_area *area, bool from_vehicle ); - comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ); + comestible_inv_area *area, bool from_vehicle ) override; + comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ) override; }; #endif From c37364fef8533d9af12b39261f718eff2c24eab1 Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 24 Sep 2019 21:41:31 -0400 Subject: [PATCH 19/19] fixes from BevapDin --- src/comestible_inv.cpp | 78 +++++++++++------------ src/comestible_inv.h | 7 +- src/comestible_inv_area.cpp | 8 +-- src/comestible_inv_listitem.cpp | 109 ++++++++++++++------------------ src/comestible_inv_listitem.h | 17 +++-- src/comestible_inv_pane.cpp | 74 ++++++++++------------ src/comestible_inv_pane.h | 44 ++++++------- src/crafting.cpp | 2 +- src/crafting.h | 2 +- src/crafting_gui.cpp | 2 +- src/player.h | 2 +- src/uistate.h | 2 +- 12 files changed, 161 insertions(+), 186 deletions(-) diff --git a/src/comestible_inv.cpp b/src/comestible_inv.cpp index ccf2f93bdba1d..0c910bd50e5b0 100644 --- a/src/comestible_inv.cpp +++ b/src/comestible_inv.cpp @@ -101,7 +101,6 @@ comestible_inventory::~comestible_inventory() g->refresh_all(); g->u.check_item_encumbrance_flag(); } - delete pane; } void comestible_inventory::save_settings() @@ -131,7 +130,6 @@ void comestible_inventory::init() for( auto &square : squares ) { square.init(); } - w_height = TERMY < min_w_height + head_height ? min_w_height : TERMY - head_height; w_width = TERMX < min_w_width ? min_w_width : TERMX > max_w_width ? max_w_width : static_cast( TERMX ); @@ -150,7 +148,7 @@ void comestible_inventory::init() //pane is set by child int itemsPerPage = w_height - 2 - 5; // 2 for the borders, 5 for the header stuff - pane->init( itemsPerPage, window, &squares ); + pane->init( itemsPerPage, window ); } void comestible_inventory::set_additional_info( std::vector data ) @@ -218,12 +216,11 @@ input_context comestible_inventory::register_actions() ctxt.register_action( "ITEMS_AROUND_I_W" ); ctxt.register_action( "ITEMS_DRAGGED_CONTAINER" ); - //todo ctxt.register_action( "CONSUME_FOOD" ); return ctxt; } -std::string comestible_inventory::process_actions( input_context ctxt ) +std::string comestible_inventory::process_actions( input_context &ctxt ) { using ai = comestible_inv_area_info; // current item in source pane, might be null @@ -239,10 +236,10 @@ std::string comestible_inventory::process_actions( input_context ctxt ) } else if( action == "HELP_KEYBINDINGS" ) { refresh( recalc, true ); } else if( ( new_square = get_area( action ) ) != nullptr ) { - if( pane->get_area()->info.id == new_square->get_relative_location() ) { + if( pane->get_area().info.id == new_square->get_relative_location() ) { //DO NOTHING } else if( new_square->is_valid() ) { - pane->set_area( new_square, new_square->is_vehicle_default() ); + pane->set_area( *new_square, new_square->is_vehicle_default() ); pane->index = 0; refresh( true, true ); } else { @@ -288,8 +285,8 @@ std::string comestible_inventory::process_actions( input_context ctxt ) int ret = 0; const int info_width = w_width / 2; const int info_startx = colstart + info_width; - if( pane->get_area()->info.id == ai::AIM_INVENTORY || pane->get_area()->info.id == ai::AIM_WORN ) { - int idx = pane->get_area()->info.id == ai::AIM_INVENTORY ? sitem->idx : + if( pane->get_area().info.id == ai::AIM_INVENTORY || pane->get_area().info.id == ai::AIM_WORN ) { + int idx = pane->get_area().info.id == ai::AIM_INVENTORY ? sitem->idx : player::worn_position_to_index( sitem->idx ); // Setup a "return to AIM" activity. If examining the item creates a new activity // (e.g. reading, reloading, activating), the new activity will be put on top of @@ -300,14 +297,13 @@ std::string comestible_inventory::process_actions( input_context ctxt ) do_return_entry(); assert( g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ); ret = g->inventory_item_menu( idx, info_startx, info_width, game::RIGHT_OF_INFO ); - //src == comestible_inventory::side::left ? game::LEFT_OF_INFO : game::RIGHT_OF_INFO); if( !g->u.has_activity( activity_id( "ACT_COMESTIBLE_INVENTORY" ) ) ) { exit = true; } else { g->u.cancel_activity(); } // Might have changed a stack (activated an item, repaired an item, etc.) - if( pane->get_area()->info.id == ai::AIM_INVENTORY ) { + if( pane->get_area().info.id == ai::AIM_INVENTORY ) { g->u.inv.restack( g->u ); } refresh( true, redraw ); @@ -338,8 +334,8 @@ std::string comestible_inventory::process_actions( input_context ctxt ) } else if( action == "UP" ) { pane->scroll_by( -1 ); } else if( action == "TOGGLE_VEH" ) { - if( pane->get_area()->has_vehicle() ) { - if( pane->get_area()->info.id != ai::AIM_DRAGGED ) { + if( pane->get_area().has_vehicle() ) { + if( pane->get_area().info.id != ai::AIM_DRAGGED ) { // Toggle between vehicle and ground pane->set_area( pane->get_area(), !pane->is_in_vehicle() ); pane->index = 0; @@ -362,20 +358,20 @@ std::string comestible_inventory::process_actions( input_context ctxt ) it->contents.erase( it->contents.begin() ); add_msg( _( "You leave the empty %s." ), it->tname() ); } else { - tripoint target = p.pos() + sitem->area->offset; + tripoint target = p.pos() + sitem->get_area().offset; item_location loc; if( sitem->from_vehicle ) { const cata::optional vp = g->m.veh_at( target ).part_with_feature( "CARGO", true ); if( !vp ) { - add_msg( _( "~~~~~~~~~ not vehicle?" ) ); + assert( false ); //item is from vehicle, but there's no vehicle at that location return action; } - vehicle *const veh = &vp->vehicle(); + vehicle &veh = vp->vehicle(); const int part = vp->part_index(); - loc = item_location( vehicle_cursor( *veh, part ), it ); + loc = item_location( vehicle_cursor( veh, part ), it ); } else { - if( sitem->area->info.type == ai::AREA_TYPE_PLAYER ) { + if( sitem->get_area().info.type == ai::AREA_TYPE_PLAYER ) { loc = item_location( p, it ); } else { loc = item_location( map_cursor( target ), it ); @@ -436,10 +432,10 @@ void comestible_inventory::display() void comestible_inventory::redraw_minimap() { werase( mm_border ); - // redraw border around minimap + draw_border( mm_border ); // minor addition to border for AIM_ALL, sorta hacky - if( pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { + if( pane->get_area().info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { //point(1,0) - point_east so travis is happy mvwprintz( mm_border, point_east, c_light_gray, utf8_truncate( _( "Mul" ), minimap_width ) ); } @@ -451,29 +447,29 @@ void comestible_inventory::redraw_minimap() // draw the 3x3 tiles centered around player g->m.draw( minimap, g->u.pos() ); - if( pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { + if( pane->get_area().info.type == comestible_inv_area_info::AREA_TYPE_MULTI ) { return; } char sym = minimap_get_sym(); if( sym != '\0' ) { - auto sq = pane->get_area(); - auto pt = pc + sq->offset; + auto a = pane->get_area(); + auto pt = pc + a.offset; // invert the color if pointing to the player's position - auto cl = sq->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ? + auto cl = a.info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ? invert_color( c_light_cyan ) : c_light_cyan.blink(); mvwputch( minimap, pt.xy(), cl, sym ); } // Invert player's tile color if exactly one pane points to player's tile - bool player_selected = pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER; + bool player_selected = pane->get_area().info.type == comestible_inv_area_info::AREA_TYPE_PLAYER; g->u.draw( minimap, g->u.pos(), player_selected ); wrefresh( minimap ); } char comestible_inventory::minimap_get_sym() const { - if( pane->get_area()->info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ) { + if( pane->get_area().info.type == comestible_inv_area_info::AREA_TYPE_PLAYER ) { return '^'; } else if( pane->is_in_vehicle() ) { return 'V'; @@ -500,9 +496,11 @@ void comestible_inventory::refresh( bool needs_recalc, bool needs_redraw ) pane->needs_redraw = needs_redraw; } +/******* FOOD *******/ + void comestible_inventory_food::init() { - pane = new comestible_inventory_pane_food(); + pane = std::make_unique< comestible_inventory_pane_food>( squares ); comestible_inventory::init(); } @@ -531,16 +529,15 @@ void comestible_inventory_food::set_additional_info( std::vector da comestible_inventory::set_additional_info( data ); } -std::string comestible_inventory_food::process_actions( input_context ctxt ) +std::string comestible_inventory_food::process_actions( input_context &ctxt ) { const std::string action = comestible_inventory::process_actions( ctxt ); - //using ai = comestible_inv_area_info; // current item in source pane, might be null comestible_inv_listitem *sitem = pane->get_cur_item_ptr(); if( action == "SWITCH_FOOD" ) { uistate.comestible_save.show_food = !uistate.comestible_save.show_food; - pane->title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; + pane->title = uistate.comestible_save.show_food ? _( "FOOD" ) : _( "DRUGS" ); refresh( true, redraw ); } else if( action == "HEAT_UP" ) { heat_up( sitem->items.front() ); @@ -583,20 +580,20 @@ std::string comestible_inventory_food::process_actions( input_context ctxt ) status ), c_light_gray ); desc += "\n"; - desc += colorize( string_format( "%c", 'm' ), c_yellow ); + desc += colorize( "m", c_yellow ); desc += colorize( _( ": this food is mushy and has reduced joy.\n" ), c_light_gray ); - desc += colorize( string_format( "%c", 's' ), c_yellow ); + desc += colorize( "s", c_yellow ); desc += colorize( _( ": this is stimulant (e.g. coffe, pop).\n" ), c_light_gray ); - desc += colorize( string_format( "%c", 'd' ), c_yellow ); + desc += colorize( "d", c_yellow ); desc += colorize( _( ": this is depressant (e.g. alcohol).\n" ), c_light_gray ); desc += "\n"; - desc += colorize( string_format( "%c", 'a' ), c_yellow ); + desc += colorize( "a", c_yellow ); desc += colorize( _( ": this item is mildly addictive.\n" ), c_light_gray ); - desc += colorize( string_format( "%c", 'a' ), c_red ); + desc += colorize( "a", c_red ); desc += colorize( _( ": this item is strongly addictive.\n" ), c_light_gray ); desc += colorize( "!", c_light_red ); @@ -638,7 +635,7 @@ void comestible_inventory_food::heat_up( item *it_to_heat ) } } if( !has_qual ) { - popup( "You don't have necessary tools to heat up your food." ); + popup( _( "You don't have necessary tools to heat up your food." ) ); return; } @@ -658,7 +655,7 @@ void comestible_inventory_food::heat_up( item *it_to_heat ) //no item found if( ts.comp.type == itype_id( "null" ) ) { - popup( "You don't have a neraby fire or tool with enough charges to heat up your food." ); + popup( _( "You don't have a neraby fire or tool with enough charges to heat up your food." ) ); return; } @@ -696,17 +693,18 @@ void comestible_inventory_food::heat_up( item *it_to_heat ) p.mod_moves( -move_mod ); // time needed to actually heat up } +/******* BIO *******/ + void comestible_inventory_bio::set_additional_info( std::vector data ) { - std::pair desc; - desc = g->u.get_power_description(); + std::pair desc = g->u.get_power_description(); data.push_back( { string_format( "%s %s", _( "Power :" ), colorize( desc.first, desc.second ) ), point_zero, c_dark_gray } ); comestible_inventory::set_additional_info( data ); } void comestible_inventory_bio::init() { - pane = new comestible_inventory_pane_bio(); + pane = std::make_unique< comestible_inventory_pane_bio>( squares ); comestible_inventory::init(); } diff --git a/src/comestible_inv.h b/src/comestible_inv.h index 7f2eed0f37aad..762e30b721183 100644 --- a/src/comestible_inv.h +++ b/src/comestible_inv.h @@ -26,7 +26,7 @@ class comestible_inventory virtual void display(); protected: virtual input_context register_actions(); - virtual std::string process_actions( input_context ctxt ); + virtual std::string process_actions( input_context &ctxt ); const int head_height; const int min_w_height; @@ -50,7 +50,8 @@ class comestible_inventory bool recalc; bool redraw; - comestible_inventory_pane *pane; + //comestible_inventory_pane *pane; + std::unique_ptr< comestible_inventory_pane> pane; //static const comestible_inventory_pane null_pane; std::array squares; @@ -85,7 +86,7 @@ class comestible_inventory_food : public comestible_inventory protected: void init() override; input_context register_actions() override; - std::string process_actions( input_context ctxt ) override; + std::string process_actions( input_context &ctxt ) override; void set_additional_info( std::vector data ) override; private: //try to find a way to warm up/defrost an item, and do it diff --git a/src/comestible_inv_area.cpp b/src/comestible_inv_area.cpp index e09c6fa787a38..e8c0f2f86785d 100644 --- a/src/comestible_inv_area.cpp +++ b/src/comestible_inv_area.cpp @@ -147,10 +147,7 @@ void comestible_inv_area::init() flags.append( _( " WATER" ) ); } - // remove leading space - if( flags.length() && flags[0] == ' ' ) { - flags.erase( 0, 1 ); - } + trim( flags ); } bool comestible_inv_area::is_valid() @@ -243,8 +240,7 @@ units::volume comestible_inv_area::get_max_volume( bool use_vehicle ) assert( has_vehicle() ); return veh->max_volume( veh_part ); } else { - map &m = g->m; - return m.max_volume( g->u.pos() + offset ); + return g->m.max_volume( g->u.pos() + offset ); } } diff --git a/src/comestible_inv_listitem.cpp b/src/comestible_inv_listitem.cpp index 8cf997fb9a6bf..a0556eb5dbb37 100644 --- a/src/comestible_inv_listitem.cpp +++ b/src/comestible_inv_listitem.cpp @@ -36,12 +36,12 @@ void comestible_inv_listitem::print_columns( std::vector int cur_print_y ) { is_selected = selected_state; - int w; - std::string print_str; - nc_color print_col; for( std::vector::reverse_iterator col_iter = columns.rbegin(); col_iter != columns.rend(); ++col_iter ) { - w = get_col_data( *col_iter ).width; + std::string print_str; + nc_color print_col; + const int w = get_col_data( *col_iter ).width; + if( w <= 0 ) { // internal column, not meant for display continue; } @@ -132,7 +132,7 @@ bool comestible_inv_listitem::print_default_columns( comestible_inv_columns col, } case COLUMN_SRC: print_col = menu_color; - print_str = area->info.get_shortname(); + print_str = area.info.get_shortname(); break; default: @@ -163,7 +163,7 @@ void comestible_inv_listitem::print_name( catacurses::window window, if( it->has_owner() ) { const faction *item_fac = it->get_owner(); if( item_fac != g->faction_manager_ptr->get( faction_id( "your_followers" ) ) ) { - item_name = string_format( "%s%s", colorize( "!", c_light_red ), item_name ); + item_name = colorize( "!", c_light_red ) + item_name; } } if( get_option( "ITEM_SYMBOLS" ) ) { @@ -172,11 +172,6 @@ void comestible_inv_listitem::print_name( catacurses::window window, int name_startpos = 1; nc_color print_color; - //for (size_t i = 0; i < cond.size(); i++) { - // auto c = cond[i]; - // set_print_color(print_color, c.second); - // mvwprintz(window, point(i + 1, cur_print_y), print_color, "%c", c.first); - //} set_print_color( print_color, menu_color ); if( is_selected ) { //fill whole line with color mvwprintz( window, point( 1, cur_print_y ), print_color, "%*s", right_bound, "" ); @@ -234,6 +229,24 @@ const islot_comestible &comestible_inv_listitem::get_edible_comestible( player & return dummy; } +static std::string time_to_comestible_str( const time_duration &d ) +{ + if( d >= calendar::INDEFINITELY_LONG_DURATION ) { + return _( "forever" ); + } + + const float day = to_days( d ); + std::string format; + if( day < 1.00 ) { + format = _( "%.2f days" ); + } else if( day > 1.00 ) { + format = _( "%.0f days" ); + } else { + format = _( "1 day" ); + } + + return string_format( format, day ); +} std::string comestible_inv_listitem::get_time_left_rounded( player &p, const item &it ) const { @@ -254,12 +267,6 @@ std::string comestible_inv_listitem::get_time_left_rounded( player &p, const ite } } - //commneted code will give approximate times instead of exact ones, in case we want that - //const auto make_result = [this](const time_duration& d, const char* verbose_str, - // const char* short_str) { - // return string_format(false ? verbose_str : short_str, time_to_comestible_str(d)); - //}; - time_duration divider = 0_turns; time_duration vicinity = 0_turns; @@ -277,39 +284,10 @@ std::string comestible_inv_listitem::get_time_left_rounded( player &p, const ite if( remainder >= divider - vicinity ) { time_left += divider; } else if( remainder > vicinity ) { - if( remainder < divider / 2 ) { - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("> %s", time_to_comestible_str(time_left)); - } else { - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("< %s", time_to_comestible_str(time_left)); - } + return time_to_comestible_str( time_left ); } } - //~ %s - time (e.g. 2 hours). - return string_format( "%s", time_to_comestible_str( time_left ) ); - //return string_format("~ %s", time_to_comestible_str(time_left)); -} - -std::string comestible_inv_listitem::time_to_comestible_str( const time_duration &d ) const -{ - if( d >= calendar::INDEFINITELY_LONG_DURATION ) { - return _( "forever" ); - } - - const float day = to_days( d ); - std::string format; - if( day < 1.00 ) { - format = _( "%.2f days" ); - } else if( day > 1.00 ) { - format = _( "%.0f days" ); - } else { - format = _( "1 day" ); - } - - return string_format( format, day ); + return time_to_comestible_str( time_left ); } struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { @@ -396,7 +374,7 @@ comestible_inv_listitem::compare_function( comestible_inv_columns sortby ) } comestible_inv_listitem::comestible_inv_listitem( const std::list &list, int index, - comestible_inv_area *area, bool from_vehicle ) : + comestible_inv_area &area, bool from_vehicle ) : idx( index ), area( area ), id( list.front()->typeId() ), @@ -420,9 +398,12 @@ void comestible_inv_listitem::init( const item &it ) assert( stacks >= 1 ); } +// area is not used when listitem is a category, so AIM_SOUTHWEST is fine +static comestible_inv_area DUMMY_AREA = comestible_inv_area( comestible_inv_area::get_info( + comestible_inv_area_info::AIM_SOUTHWEST ) ); comestible_inv_listitem::comestible_inv_listitem( const item_category *cat ) : idx() - , area() + , area( DUMMY_AREA ) , id( "null" ) , autopickup() , stacks() @@ -455,7 +436,7 @@ comestible_inv_listitem_food::comestible_inv_listitem_food( const item_category comestible_inv_listitem_food::comestible_inv_listitem_food( const std::list &list, int index, - comestible_inv_area *area, bool from_vehicle ): comestible_inv_listitem( list, index, area, + comestible_inv_area &area, bool from_vehicle ): comestible_inv_listitem( list, index, area, from_vehicle ) { init( g->u.get_consumable_from( *list.front() ) ); @@ -466,14 +447,15 @@ void comestible_inv_listitem_food::init( const item &it ) player &p = g->u; islot_comestible edible = get_edible_comestible( p, it ); + + menu_color = it.color_in_inventory(); // statuses - const auto &comest = it.get_comestible(); cond.reserve( cond_size ); const bool eat_verb = it.has_flag( "USE_EAT_VERB" ); - const bool is_food = eat_verb || comest->comesttype == "FOOD"; - const bool is_drink = !eat_verb && comest->comesttype == "DRINK"; + const bool is_food = eat_verb || edible.comesttype == "FOOD"; + const bool is_drink = !eat_verb && edible.comesttype == "DRINK"; bool craft_only = false; bool warm_only = false; @@ -543,17 +525,17 @@ void comestible_inv_listitem_food::print_columns( std::vector::reverse_iterator col_iter = columns.rbegin(); col_iter != columns.rend(); ++col_iter ) { - w = get_col_data( *col_iter ).width; + std::string print_str; + nc_color print_col; + + const int w = get_col_data( *col_iter ).width; if( w <= 0 ) { // internal column, not meant for display continue; } @@ -571,9 +553,9 @@ void comestible_inv_listitem_food::print_columns( std::vector &list, int index, - comestible_inv_area *area, bool from_vehicle ) : comestible_inv_listitem( list, index, area, + comestible_inv_area &area, bool from_vehicle ) : comestible_inv_listitem( list, index, area, from_vehicle ) { energy = g->u.get_acquirable_energy( *list.front() ); diff --git a/src/comestible_inv_listitem.h b/src/comestible_inv_listitem.h index c3f0a9257c7f8..c0b174007f099 100644 --- a/src/comestible_inv_listitem.h +++ b/src/comestible_inv_listitem.h @@ -70,7 +70,6 @@ struct col_data { } }; - class comestible_inv_listitem { public: @@ -103,11 +102,12 @@ class comestible_inv_listitem * Index of the item in the itemstack. */ int idx; - + private: /** * The location of the item, should nevere be AREA_TYPE_MULTI */ - comestible_inv_area *area; + comestible_inv_area &area; + public: using itype_id = std::string; itype_id id; @@ -166,7 +166,6 @@ class comestible_inv_listitem const islot_comestible &get_edible_comestible( player &p, const item &it ) const; std::string get_time_left_rounded( player &p, const item &it ) const; - std::string time_to_comestible_str( const time_duration &d ) const; /** * Whether this is a category header entry, which does *not* have a reference * to an item, only @ref cat is valid. @@ -174,6 +173,10 @@ class comestible_inv_listitem bool is_category_header() const; bool is_item_entry() const; + comestible_inv_area &get_area() { + return area; + } + comestible_inv_listitem( const item_category *cat = nullptr ); /** * Create a normal item entry. @@ -183,7 +186,7 @@ class comestible_inv_listitem * @param from_vehicle Is the item from a vehicle cargo space? */ comestible_inv_listitem( const std::list &list, int index, - comestible_inv_area *area, bool from_vehicle ); + comestible_inv_area &area, bool from_vehicle ); virtual ~comestible_inv_listitem() = default; @@ -196,7 +199,7 @@ class comestible_inv_listitem_food : public comestible_inv_listitem public: comestible_inv_listitem_food( const item_category *cat = nullptr ); comestible_inv_listitem_food( const std::list &list, int index, - comestible_inv_area *area, bool from_vehicle ); + comestible_inv_area &area, bool from_vehicle ); void print_columns( std::vector columns, comestible_select_state selected_state, catacurses::window window, int right_bound, int cur_print_y ) override; @@ -226,7 +229,7 @@ class comestible_inv_listitem_bio: public comestible_inv_listitem public: comestible_inv_listitem_bio( const item_category *cat = nullptr ); comestible_inv_listitem_bio( const std::list &list, int index, - comestible_inv_area *area, bool from_vehicle ); + comestible_inv_area &area, bool from_vehicle ); private: int energy; protected: diff --git a/src/comestible_inv_pane.cpp b/src/comestible_inv_pane.cpp index 89fb5673dc457..04614f8a985ec 100644 --- a/src/comestible_inv_pane.cpp +++ b/src/comestible_inv_pane.cpp @@ -40,20 +40,17 @@ #endif -void comestible_inventory_pane::init( int items_per_page, - catacurses::window w, std::array - *a ) +void comestible_inventory_pane::init( int items_per_page, catacurses::window w ) { itemsPerPage = items_per_page; window = w; - all_areas = a; is_compact = TERMX <= 100; inCategoryMode = false; comestible_inv_area_info::aim_location location = static_cast( uistate.comestible_save.area_idx ); - set_area( &( *all_areas )[location], uistate.comestible_save.in_vehicle ); + set_area( all_areas[location], uistate.comestible_save.in_vehicle ); index = uistate.comestible_save.selected_idx; filter = uistate.comestible_save.filter; @@ -394,11 +391,11 @@ void comestible_inventory_pane::recalc() weight = 0_gram; std::vector loc = cur_area->info.multi_locations; for( auto &i : loc ) { - comestible_inv_area *s = &( ( *all_areas )[i] ); + comestible_inv_area &s = get_square( i ); // Deal with squares with ground + vehicle storage // Also handle the case when the other tile covers vehicle // or the ground below the vehicle. - if( s->has_vehicle() ) { + if( s.has_vehicle() ) { add_items_from_area( s, true, tmp_vol, tmp_weight ); volume += tmp_vol; weight += tmp_weight; @@ -410,7 +407,7 @@ void comestible_inventory_pane::recalc() weight += tmp_weight; } } else { - add_items_from_area( cur_area, viewing_cargo, volume, weight ); + add_items_from_area( *cur_area, viewing_cargo, volume, weight ); } // Insert category headers (only expected when sorting by category) @@ -441,11 +438,11 @@ void comestible_inventory_pane::recalc() } } -void comestible_inventory_pane::add_items_from_area( comestible_inv_area *area, bool from_cargo, +void comestible_inventory_pane::add_items_from_area( comestible_inv_area &area, bool from_cargo, units::volume &ret_volume, units::mass &ret_weight ) { - assert( area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI ); - if( !area->is_valid() ) { + assert( area.info.type != comestible_inv_area_info::AREA_TYPE_MULTI ); + if( !area.is_valid() ) { return; } @@ -455,7 +452,7 @@ void comestible_inventory_pane::add_items_from_area( comestible_inv_area *area, // Existing items are *not* cleared on purpose, this might be called // several times in case all surrounding squares are to be shown. - const comestible_inv_area::area_items stacks = area->get_items( from_cargo ); + const comestible_inv_area::area_items stacks = area.get_items( from_cargo ); for( size_t x = 0; x < stacks.size(); ++x ) { it = create_listitem( stacks[x], x, area, from_cargo ); @@ -486,14 +483,14 @@ void comestible_inventory_pane::redraw() print_items(); auto itm = get_cur_item_ptr(); - int width = print_header( itm != nullptr ? itm->area : cur_area ); + int width = print_header( itm != nullptr ? itm->get_area() : get_area() ); bool same_as_dragged = ( cur_area->info.type == comestible_inv_area_info::AREA_TYPE_GROUND ) && // only cardinals cur_area->info.id != comestible_inv_area_info::AIM_CENTER && viewing_cargo && // not where you stand, and pane is in vehicle cur_area->info.default_offset == get_square( - comestible_inv_area_info::AIM_DRAGGED )->offset; // make sure the offsets are the same as the grab point - const comestible_inv_area *sq = same_as_dragged ? get_square( + comestible_inv_area_info::AIM_DRAGGED ).offset; // make sure the offsets are the same as the grab point + const comestible_inv_area *sq = same_as_dragged ? &get_square( comestible_inv_area_info::AIM_DRAGGED ) : cur_area; bool car = cur_area->has_vehicle() && viewing_cargo && @@ -548,29 +545,28 @@ void comestible_inventory_pane::redraw() wrefresh( w ); } -int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) +int comestible_inventory_pane::print_header( comestible_inv_area &sel_area ) { - int wwidth = getmaxx( window ); - int ofs = wwidth - 25 - 2 - 14; - for( size_t i = 0; i < all_areas->size(); ++i ) { + int ofs = getmaxx( window ) - 25 - 2 - 14; + for( size_t i = 0; i < all_areas.size(); ++i ) { std::string key = comestible_inv_area::get_info( static_cast( i ) ).minimapname; - comestible_inv_area *iter_square = get_square( i ); + comestible_inv_area &iter_square = get_square( i ); - const char *bracket = iter_square->has_vehicle() ? "<>" : "[]"; + const char *bracket = iter_square.has_vehicle() ? "<>" : "[]"; bool is_single = cur_area->info.type != comestible_inv_area_info::AREA_TYPE_MULTI; - bool is_selected_by_user = cur_area->info.has_area( get_square( i )->info.id ); + bool is_selected_by_user = cur_area->info.has_area( iter_square.info.id ); bool is_selected_by_item; if( is_single ) { is_selected_by_item = is_selected_by_user; } else { - is_selected_by_item = get_square( i )->info.id == sel_area->info.id; + is_selected_by_item = iter_square.info.id == sel_area.info.id; } nc_color bcolor = c_red; nc_color kcolor = c_red; - if( get_square( i )->is_valid() ) { + if( iter_square.is_valid() ) { if( is_single ) { if( is_selected_by_item ) { if( viewing_cargo ) { @@ -583,7 +579,7 @@ int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) bcolor = kcolor = c_dark_gray; } } else { - if( cur_area->info.id == get_square( i )->info.id ) { + if( cur_area->info.id == iter_square.info.id ) { bcolor = c_light_gray; kcolor = c_white; } else { @@ -602,18 +598,17 @@ int comestible_inventory_pane::print_header( comestible_inv_area *sel_area ) } } - const int x = get_square( i )->info.hscreen.x + ofs; - const int y = get_square( i )->info.hscreen.y; + const int x = iter_square.info.hscreen.x + ofs; + const int y = iter_square.info.hscreen.y; mvwprintz( window, point( x, y ), bcolor, "%c", bracket[0] ); wprintz( window, kcolor, "%s", viewing_cargo && is_selected_by_item && is_single && cur_area->info.id != comestible_inv_area_info::AIM_DRAGGED ? "V" : key ); wprintz( window, bcolor, "%c", bracket[1] ); } - return get_square( comestible_inv_area_info::AIM_INVENTORY )->info.hscreen.y + ofs; + return get_square( comestible_inv_area_info::AIM_INVENTORY ).info.hscreen.y + ofs; } -void comestible_inventory_pane_food::init( int items_per_page, catacurses::window w, - std::array *s ) +void comestible_inventory_pane_food::init( int items_per_page, catacurses::window w ) { columns = { COLUMN_CALORIES, COLUMN_QUENCH, COLUMN_JOY }; if( g->u.can_estimate_rot() ) { @@ -622,11 +617,11 @@ void comestible_inventory_pane_food::init( int items_per_page, catacurses::windo columns.emplace_back( COLUMN_SHELF_LIFE ); } special_filter = []( const item & it ) { - const std::string n = it.get_category().name(); - if( uistate.comestible_save.show_food && n != "FOOD" ) { + const std::string n = it.get_category().id(); + if( uistate.comestible_save.show_food && n != "food" ) { return true; } - if( !uistate.comestible_save.show_food && n != "DRUGS" ) { + if( !uistate.comestible_save.show_food && n != "drugs" ) { return true; } @@ -635,12 +630,12 @@ void comestible_inventory_pane_food::init( int items_per_page, catacurses::windo } return false; }; - title = uistate.comestible_save.show_food ? "FOOD" : "DRUGS"; + title = uistate.comestible_save.show_food ? _( "FOOD" ) : _( "DRUGS" ); default_sortby = COLUMN_EXPIRES; - comestible_inventory_pane::init( items_per_page, w, s ); + comestible_inventory_pane::init( items_per_page, w ); } comestible_inv_listitem *comestible_inventory_pane_food::create_listitem( std::list list, - int index, comestible_inv_area *area, bool from_vehicle ) + int index, comestible_inv_area &area, bool from_vehicle ) { return new comestible_inv_listitem_food( list, index, area, from_vehicle ); } @@ -650,8 +645,7 @@ comestible_inv_listitem *comestible_inventory_pane_food::create_listitem( return new comestible_inv_listitem_food( cat ); } -void comestible_inventory_pane_bio::init( int items_per_page, catacurses::window w, - std::array *s ) +void comestible_inventory_pane_bio::init( int items_per_page, catacurses::window w ) { columns = { COLUMN_ENERGY, COLUMN_SORTBY_CATEGORY }; special_filter = []( const item & it ) { @@ -659,10 +653,10 @@ void comestible_inventory_pane_bio::init( int items_per_page, catacurses::window }; title = g->u.bionic_at_index( uistate.comestible_save.bio ).id.obj().name.translated(); default_sortby = COLUMN_ENERGY; - comestible_inventory_pane::init( items_per_page, w, s ); + comestible_inventory_pane::init( items_per_page, w ); } comestible_inv_listitem *comestible_inventory_pane_bio::create_listitem( std::list list, - int index, comestible_inv_area *area, bool from_vehicle ) + int index, comestible_inv_area &area, bool from_vehicle ) { return new comestible_inv_listitem_bio( list, index, area, from_vehicle ); } diff --git a/src/comestible_inv_pane.h b/src/comestible_inv_pane.h index 76af20a013751..b61d4ad012e65 100644 --- a/src/comestible_inv_pane.h +++ b/src/comestible_inv_pane.h @@ -28,7 +28,7 @@ struct legend_data { class comestible_inventory_pane { protected: - // pointer to the square this pane is pointing to + // where items come from. Should never be null comestible_inv_area *cur_area; bool viewing_cargo = false; bool is_compact; @@ -53,16 +53,16 @@ class comestible_inventory_pane bool is_filtered( const comestible_inv_listitem &it ) const; bool is_filtered( const item &it ) const; - int print_header( comestible_inv_area *sel_area ); + int print_header( comestible_inv_area &sel_area ); /** * Insert additional category headers on the top of each page. */ void paginate(); - void add_items_from_area( comestible_inv_area *area, bool from_cargo, units::volume &ret_volume, + void add_items_from_area( comestible_inv_area &area, bool from_cargo, units::volume &ret_volume, units::mass &ret_weight ); virtual comestible_inv_listitem *create_listitem( std::list list, int index, - comestible_inv_area *area, bool from_vehicle ) = 0; + comestible_inv_area &area, bool from_vehicle ) = 0; virtual comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ) = 0; void print_items(); @@ -78,6 +78,9 @@ class comestible_inventory_pane public: + comestible_inventory_pane( + std::array &areas ) : all_areas( + areas ) {}; virtual ~comestible_inventory_pane(); /** @@ -106,8 +109,7 @@ class comestible_inventory_pane bool needs_recalc; bool needs_redraw; - virtual void init( int items_per_page, catacurses::window w, - std::array *a ); + virtual void init( int items_per_page, catacurses::window w ); void save_settings( bool reset ); /** @@ -136,20 +138,20 @@ class comestible_inventory_pane //adds things this can sort on. List is provided by parent void add_sort_entries( uilist &sm ); - std::array *all_areas; - comestible_inv_area *get_square( comestible_inv_area_info::aim_location loc ) { - return &( ( *all_areas )[loc] ); + std::array &all_areas; + comestible_inv_area &get_square( comestible_inv_area_info::aim_location loc ) { + return all_areas[loc]; } - comestible_inv_area *get_square( size_t loc ) { - return &( ( *all_areas )[loc] ); + comestible_inv_area &get_square( size_t loc ) { + return all_areas[loc]; } // set the pane's area via its square, and whether it is viewing a vehicle's cargo - void set_area( comestible_inv_area *square, bool show_vehicle ) { - cur_area = square; - viewing_cargo = square->has_vehicle() && show_vehicle; + void set_area( comestible_inv_area &square, bool show_vehicle ) { + cur_area = □ + viewing_cargo = cur_area->has_vehicle() && show_vehicle; } - comestible_inv_area *get_area() const { - return cur_area; + comestible_inv_area &get_area() const { + return *cur_area; } bool is_in_vehicle() const { return viewing_cargo; @@ -159,19 +161,17 @@ class comestible_inventory_pane class comestible_inventory_pane_food : public comestible_inventory_pane { using comestible_inventory_pane::comestible_inventory_pane; - void init( int items_per_page, catacurses::window w, - std::array *s ) override; + void init( int items_per_page, catacurses::window w ) override; comestible_inv_listitem *create_listitem( std::list list, int index, - comestible_inv_area *area, bool from_vehicle ) override; + comestible_inv_area &area, bool from_vehicle ) override; comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ) override; }; class comestible_inventory_pane_bio: public comestible_inventory_pane { using comestible_inventory_pane::comestible_inventory_pane; - void init( int items_per_page, catacurses::window w, - std::array *s ) override; + void init( int items_per_page, catacurses::window w ) override; comestible_inv_listitem *create_listitem( std::list list, int index, - comestible_inv_area *area, bool from_vehicle ) override; + comestible_inv_area &area, bool from_vehicle ) override; comestible_inv_listitem *create_listitem( const item_category *cat = nullptr ) override; }; #endif diff --git a/src/crafting.cpp b/src/crafting.cpp index 080e36be6aeff..0492f0ca4156a 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -282,7 +282,7 @@ bool player::has_morale_to_craft() const return get_morale_level() >= -50; } -void player::craft( const tripoint &loc, std::string filter ) +void player::craft( const tripoint &loc, const std::string &filter ) { int batch_size = 0; const recipe *rec = select_crafting_recipe( batch_size, filter ); diff --git a/src/crafting.h b/src/crafting.h index 0fd17b85f662d..beaddf116da4e 100644 --- a/src/crafting.h +++ b/src/crafting.h @@ -15,6 +15,6 @@ void remove_ammo( item &dis_item, player &p ); // same as above but for each item in the list void remove_ammo( std::list &dis_items, player &p ); -const recipe *select_crafting_recipe( int &batch_size, std::string filter = "" ); +const recipe *select_crafting_recipe( int &batch_size, const std::string &filter = "" ); #endif diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 4e1d4f7ee779c..0926d038e581f 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -150,7 +150,7 @@ static int print_items( const recipe &r, const catacurses::window &w, int ypos, return ypos - oldy; } -const recipe *select_crafting_recipe( int &batch_size, std::string filter ) +const recipe *select_crafting_recipe( int &batch_size, const std::string &filter ) { // always re-translate the category names in case the language has changed translate_all(); diff --git a/src/player.h b/src/player.h index dcfc515709421..e91384cfbd94b 100644 --- a/src/player.h +++ b/src/player.h @@ -1424,7 +1424,7 @@ class player : public Character * Start various types of crafts * @param loc the location of the workbench. tripoint_zero indicates crafting from inventory. */ - void craft( const tripoint &loc = tripoint_zero, std::string filter = "" ); + void craft( const tripoint &loc = tripoint_zero, const std::string &filter = "" ); void recraft( const tripoint &loc = tripoint_zero ); void long_craft( const tripoint &loc = tripoint_zero ); void make_craft( const recipe_id &id, int batch_size, const tripoint &loc = tripoint_zero ); diff --git a/src/uistate.h b/src/uistate.h index 59df79feb1ed5..601d0b8c68199 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -16,7 +16,7 @@ class item; struct comestible_inv_save_state { public: int sort_idx = -1; - std::string filter = ""; + std::string filter; int area_idx = 13; //A+I+W /**