Skip to content

Commit

Permalink
Display nutrient ranges in item info
Browse files Browse the repository at this point in the history
Currently item info for items with variable nutrient content simply list
the default values with a disclaimer that they might be inaccurate.

In fact the default values are more or less the only values that *won't*
occur when you craft the recipe.

Instead, calculate and display the range of possible values for the
nutrient content.
  • Loading branch information
jbytheway committed Dec 22, 2019
1 parent 4afe91b commit 1bacbe2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 31 deletions.
9 changes: 1 addition & 8 deletions src/crafting_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <color_cyan>estimated</color>, varying with <color_cyan>chosen ingredients</color>." ) );
}

//color needs to be preserved in case part of the previous page was cut off
nc_color stored_color = col;
if( display_mode > 1 ) {
Expand Down
76 changes: 53 additions & 23 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1322,12 +1322,38 @@ void item::med_info( const item *med_item, std::vector<iteminfo> &info, const it
void item::food_info( const item *food_item, std::vector<iteminfo> &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 <color_cyan>vary with chosen ingredients</color>." ) );
if( recipe_dict.is_item_on_loop( food_item->typeId() ) ) {
info.emplace_back(
"FOOD", _( "Nutrition range cannot be calculated accurately due to "
"<color_red>recipe loops</color>." ) );
}
}

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", _( "<bold>Calories (kcal)</bold>: " ),
"", 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: " ),
Expand All @@ -1351,30 +1377,34 @@ void item::food_info( const item *food_item, std::vector<iteminfo> &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<vitamin_id, int> &v ) {
auto format_vitamin = [&]( const std::pair<vitamin_id, int> &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<int>( 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<vitamin_id, int> &v ) {
return format_vitamin( v, true );
} );

const std::string effect_vits = enumerate_as_string(
nutr.vitamins.begin(),
nutr.vitamins.end(),
[]( const std::pair<vitamin_id, int> &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<int>( v.second * g->u.vitamin_rate( v.first ) /
1_days * 100 ) ) :
std::string();
max_nutr.vitamins.begin(),
max_nutr.vitamins.end(),
[&]( const std::pair<vitamin_id, int> &v ) {
return format_vitamin( v, false );
} );

if( !required_vits.empty() && parts->test( iteminfo_parts::FOOD_VITAMINS ) ) {
Expand Down

0 comments on commit 1bacbe2

Please sign in to comment.