diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index ca4bf9e5d0850..41c7f84b3ee10 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -607,17 +607,10 @@ const recipe *select_crafting_recipe( int &batch_size ) if( last_recipe != current[line] ) { last_recipe = current[line]; tmp = current[line]->create_result(); + tmp.set_var( "recipe_exemplar", last_recipe->ident().str() ); } tmp.info( true, thisItem, count ); - // If it's food that can have variable nutrition, add disclaimer. - // Hidden if the user is attempting to page through components. - if( ( tmp.is_food_container() || tmp.is_food() ) && !tmp.has_flag( "NUTRIENT_OVERRIDE" ) && - display_mode == 0 ) { - ypos += fold_and_print( w_data, point( xpos + 2, ypos ), pane - 2, c_light_gray, - _( "Shown nutrition is estimated, varying with chosen ingredients." ) ); - } - //color needs to be preserved in case part of the previous page was cut off nc_color stored_color = col; if( display_mode > 1 ) { diff --git a/src/item.cpp b/src/item.cpp index 7a1e28e066a03..0569205198a34 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1322,12 +1322,38 @@ void item::med_info( const item *med_item, std::vector &info, const it void item::food_info( const item *food_item, std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const { - const nutrients nutr = g->u.compute_effective_nutrients( *food_item ); + nutrients min_nutr; + nutrients max_nutr; + + std::string recipe_exemplar = get_var( "recipe_exemplar", "" ); + if( recipe_exemplar.empty() ) { + min_nutr = max_nutr = g->u.compute_effective_nutrients( *food_item ); + } else { + std::tie( min_nutr, max_nutr ) = + g->u.compute_nutrient_range( *food_item, recipe_id( recipe_exemplar ) ); + } + + bool show_nutr = parts->test( iteminfo_parts::FOOD_NUTRITION ) || + parts->test( iteminfo_parts::FOOD_VITAMINS ); + if( min_nutr != max_nutr && show_nutr ) { + info.emplace_back( + "FOOD", _( "Nutrition will vary with chosen ingredients." ) ); + if( recipe_dict.is_item_on_loop( food_item->typeId() ) ) { + info.emplace_back( + "FOOD", _( "Nutrition range cannot be calculated accurately due to " + "recipe loops." ) ); + } + } + const std::string space = " "; - if( nutr.kcal != 0 || food_item->get_comestible()->quench != 0 ) { + if( max_nutr.kcal != 0 || food_item->get_comestible()->quench != 0 ) { if( parts->test( iteminfo_parts::FOOD_NUTRITION ) ) { info.push_back( iteminfo( "FOOD", _( "Calories (kcal): " ), - "", iteminfo::no_newline, nutr.kcal ) ); + "", iteminfo::no_newline, min_nutr.kcal ) ); + if( max_nutr.kcal != min_nutr.kcal ) { + info.push_back( iteminfo( "FOOD", _( "-" ), + "", iteminfo::no_newline, max_nutr.kcal ) ); + } } if( parts->test( iteminfo_parts::FOOD_QUENCH ) ) { info.push_back( iteminfo( "FOOD", space + _( "Quench: " ), @@ -1351,30 +1377,34 @@ void item::food_info( const item *food_item, std::vector &info, info.push_back( iteminfo( "FOOD", _( "Smells like: " ) + food_item->corpse->nname() ) ); } - const std::string required_vits = enumerate_as_string( - nutr.vitamins.begin(), - nutr.vitamins.end(), - []( const std::pair &v ) { + auto format_vitamin = [&]( const std::pair &v, bool display_vitamins ) { + const bool is_vitamin = v.first->type() == vitamin_type::VITAMIN; // only display vitamins that we actually require - return ( g->u.vitamin_rate( v.first ) > 0_turns && v.second != 0 && - v.first->type() == vitamin_type::VITAMIN && !v.first->has_flag( "NO_DISPLAY" ) ) ? - string_format( "%s (%i%%)", v.first.obj().name(), - static_cast( v.second * g->u.vitamin_rate( v.first ) / - 1_days * 100 ) ) : - std::string(); + if( g->u.vitamin_rate( v.first ) == 0_turns || v.second == 0 || + display_vitamins != is_vitamin || v.first->has_flag( "NO_DISPLAY" ) ) { + return std::string(); + } + const double multiplier = g->u.vitamin_rate( v.first ) / 1_days * 100; + const int min_value = min_nutr.get_vitamin( v.first ); + const int max_value = v.second; + const int min_rda = lround( min_value * multiplier ); + const int max_rda = lround( max_value * multiplier ); + const std::string format = min_rda == max_rda ? "%s (%i%%)" : "%s (%i-%i%%)"; + return string_format( format, v.first->name(), min_value, max_value ); + }; + + const std::string required_vits = enumerate_as_string( + max_nutr.vitamins.begin(), + max_nutr.vitamins.end(), + [&]( const std::pair &v ) { + return format_vitamin( v, true ); } ); const std::string effect_vits = enumerate_as_string( - nutr.vitamins.begin(), - nutr.vitamins.end(), - []( const std::pair &v ) { - // only display vitamins that we actually require - return ( g->u.vitamin_rate( v.first ) > 0_turns && v.second != 0 && - v.first->type() != vitamin_type::VITAMIN && !v.first->has_flag( "NO_DISPLAY" ) ) ? - string_format( "%s (%i%%)", v.first.obj().name(), - static_cast( v.second * g->u.vitamin_rate( v.first ) / - 1_days * 100 ) ) : - std::string(); + max_nutr.vitamins.begin(), + max_nutr.vitamins.end(), + [&]( const std::pair &v ) { + return format_vitamin( v, false ); } ); if( !required_vits.empty() && parts->test( iteminfo_parts::FOOD_VITAMINS ) ) {