From b196175e38097d456719e7189c299bbb5e3f261b Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Thu, 19 Dec 2019 21:29:17 -0500 Subject: [PATCH] Use COOKED and RAW flags in nutrient predictions To predict nutrient content we need to also predict changes to the item flags that occur when cooking. Implement that, and add a test to verify that it works correctly for cooked wild veggies. --- src/consumption.cpp | 30 ++++++++++++++++++++---------- src/player.h | 8 +++++--- tests/comestible_tests.cpp | 21 ++++++++++++++++++++- tests/iteminfo_test.cpp | 2 +- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/consumption.cpp b/src/consumption.cpp index aa3299006caa2..08ea0258df406 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -98,7 +98,8 @@ int player::stomach_capacity() const } // TODO: Move pizza scraping here. -static int compute_default_effective_kcal( const item &comest, const player &p ) +static int compute_default_effective_kcal( const item &comest, const player &p, + const cata::flat_set &extra_flags = {} ) { static const trait_id trait_CARNIVORE( "CARNIVORE" ); static const trait_id trait_GIZZARD( "GIZZARD" ); @@ -113,7 +114,8 @@ static int compute_default_effective_kcal( const item &comest, const player &p ) float kcal = comest.get_comestible()->default_nutrition.kcal; // Many raw foods give less calories, as your body has expends more energy digesting them. - if( comest.has_flag( "RAW" ) && !comest.has_flag( "COOKED" ) ) { + bool cooked = comest.has_flag( "COOKED" ) || extra_flags.count( "COOKED" ); + if( comest.has_flag( "RAW" ) && !cooked ) { kcal *= 0.75f; } @@ -179,9 +181,9 @@ static std::map compute_default_effective_vitamins( // Calculate the effective nutrients for a given item, taking // into account player traits but not item components. static nutrients compute_default_effective_nutrients( const item &comest, - const player &p ) + const player &p, const cata::flat_set &extra_flags = {} ) { - return { compute_default_effective_kcal( comest, p ), + return { compute_default_effective_kcal( comest, p, extra_flags ), compute_default_effective_vitamins( comest, p ) }; } @@ -215,8 +217,9 @@ nutrients player::compute_effective_nutrients( const item &comest ) const // Calculate range of nutrients obtainable for a given item when crafted via // the given recipe -std::pair player::compute_nutrient_range( const item &comest, - const recipe_id &recipe_i ) const +std::pair player::compute_nutrient_range( + const item &comest, const recipe_id &recipe_i, + const cata::flat_set &extra_flags ) const { if( !comest.is_comestible() ) { return {}; @@ -233,6 +236,12 @@ std::pair player::compute_nutrient_range( const item &come const recipe &rec = *recipe_i; + cata::flat_set our_extra_flags = extra_flags; + + if( rec.hot_result() ) { + our_extra_flags.insert( "COOKED" ); + } + const requirement_data requirements = rec.requirements(); const requirement_data::alter_item_comp_vector &component_requirements = requirements.get_components(); @@ -243,7 +252,7 @@ std::pair player::compute_nutrient_range( const item &come bool first = true; for( const item_comp &component_option : component_options ) { std::pair component_option_range = - compute_nutrient_range( component_option.type ); + compute_nutrient_range( component_option.type, our_extra_flags ); component_option_range.first *= component_option.count; component_option_range.second *= component_option.count; @@ -272,7 +281,8 @@ std::pair player::compute_nutrient_range( const item &come // Calculate the range of nturients possible for a given item across all // possible recipes -std::pair player::compute_nutrient_range( const itype_id &comest_id ) const +std::pair player::compute_nutrient_range( + const itype_id &comest_id, const cata::flat_set &extra_flags ) const { const itype *comest = item::find_type( comest_id ); if( !comest->comestible ) { @@ -281,7 +291,7 @@ std::pair player::compute_nutrient_range( const itype_id & item comest_it( comest, calendar::turn, 1 ); // The default nutrients are always a possibility - nutrients min_nutr = compute_default_effective_nutrients( comest_it, *this ); + nutrients min_nutr = compute_default_effective_nutrients( comest_it, *this, extra_flags ); if( comest->item_tags.count( "NUTRIENT_OVERRIDE" ) || recipe_dict.is_item_on_loop( comest->get_id() ) ) { @@ -305,7 +315,7 @@ std::pair player::compute_nutrient_range( const itype_id & debugmsg( "When creating recipe result expected %s, got %s\n", comest_it.typeId(), result_it.typeId() ); } - std::tie( this_min, this_max ) = compute_nutrient_range( result_it, rec ); + std::tie( this_min, this_max ) = compute_nutrient_range( result_it, rec, extra_flags ); min_nutr.min_in_place( this_min ); max_nutr.max_in_place( this_max ); } diff --git a/src/player.h b/src/player.h index 695ca6106ac58..c4097b54f2ec2 100644 --- a/src/player.h +++ b/src/player.h @@ -673,10 +673,12 @@ class player : public Character nutrients compute_effective_nutrients( const item & ) const; /** Get range of possible nutrient content, for a particular recipe, * depending on choice of ingredients */ - std::pair compute_nutrient_range( const item &, - const recipe_id & ) const; + std::pair compute_nutrient_range( + const item &, const recipe_id &, + const cata::flat_set &extra_flags = {} ) const; /** Same, but across arbitrary recipes */ - std::pair compute_nutrient_range( const itype_id & ) const; + std::pair compute_nutrient_range( + const itype_id &, const cata::flat_set &extra_flags = {} ) const; /** Get vitamin usage rate (minutes per unit) accounting for bionics, mutations and effects */ time_duration vitamin_rate( const vitamin_id &vit ) const; diff --git a/tests/comestible_tests.cpp b/tests/comestible_tests.cpp index 1c99a77137e97..9b525f6e5912d 100644 --- a/tests/comestible_tests.cpp +++ b/tests/comestible_tests.cpp @@ -5,7 +5,9 @@ #include #include +#include "avatar.h" #include "catch/catch.hpp" +#include "game.h" #include "itype.h" #include "recipe_dictionary.h" #include "recipe.h" @@ -108,7 +110,7 @@ static item food_or_food_container( const item &it ) return it.is_food_container() ? it.contents.front() : it; } -TEST_CASE( "recipe_permutations" ) +TEST_CASE( "recipe_permutations", "[recipe]" ) { // Are these tests failing? Here's how to fix that: // If the average is over the upper bound, you need to increase the calories for the item @@ -155,3 +157,20 @@ TEST_CASE( "recipe_permutations" ) } } } + +TEST_CASE( "cooked_veggies_get_correct_calorie_prediction", "[recipe]" ) +{ + // This test verifies that predicted calorie ranges properly take into + // account the "RAW"/"COOKED" flags. + const item veggy_wild_cooked( "veggy_wild_cooked" ); + const recipe_id veggy_wild_cooked_recipe( "veggy_wild_cooked" ); + + const avatar &u = g->u; + + nutrients default_nutrition = u.compute_effective_nutrients( veggy_wild_cooked ); + std::pair predicted_nutrition = + u.compute_nutrient_range( veggy_wild_cooked, veggy_wild_cooked_recipe ); + + CHECK( default_nutrition.kcal == predicted_nutrition.first.kcal ); + CHECK( default_nutrition.kcal == predicted_nutrition.second.kcal ); +} diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index a11040fa3062b..46a1e4ea495e1 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -94,7 +94,7 @@ TEST_CASE( "nutrient_ranges_for_recipe_exemplars", "[item][iteminfo]" ) i, q, "--\n" "Nutrition will vary with chosen ingredients.\n" - "Calories (kcal): 313-" + "Calories (kcal): 317-" "469 Quench: 0\n" "Vitamins (RDA): Calcium (7-28%), Iron (0-83%), " "Vitamin A (3-11%), Vitamin B12 (2-6%), and Vitamin C (1-85%)\n" );