Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stomach code refactor #35143

Merged
merged 9 commits into from
Nov 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions data/json/items/comestibles/meat_dishes.json
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,16 @@
"fun": -8,
"vitamins": [ [ "iron", 3 ] ]
},
{
"type": "COMESTIBLE",
"id": "debug_nutrition",
"copy-from": "can_spam",
"name": "holy SPAM of debugging",
"calories": 2100,
"description": "A mysterious lump of SPAM that contains just enough calories and vitamins to feed you for a day. For debug use only.",
"//": "This is used for the all_nutrient_starve_test.",
"vitamins": [ [ "vitA", 96 ], [ "vitB", 96 ], [ "vitC", 96 ], [ "calcium", 96 ], [ "iron", 96 ] ]
},
{
"type": "COMESTIBLE",
"id": "can_sardine",
Expand Down
3 changes: 1 addition & 2 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5219,8 +5219,7 @@ void Character::vomit()
g->events().send<event_type::throws_up>( getID() );

if( stomach.contains() != 0_ml ) {
// empty stomach contents
stomach.bowel_movement();
stomach.empty();
g->m.add_field( adjacent_tile(), fd_bile, 1 );
add_msg_player_or_npc( m_bad, _( "You throw up heavily!" ), _( "<npcname> throws up heavily!" ) );
}
Expand Down
23 changes: 18 additions & 5 deletions src/consumption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ ret_val<edible_rating> player::will_eat( const item &food, bool interactive ) co
add_consequence( _( "Your stomach won't be happy (not rotten enough)." ), ALLERGY_WEAK );
}

if( food.charges > 0 && stomach.stomach_remaining() < food.volume() / food.charges &&
if( food.charges > 0 && stomach.stomach_remaining( *this ) < food.volume() / food.charges &&
!food.has_infinite_charges() ) {
if( edible ) {
add_consequence( _( "You're full already and will be forcing yourself to eat." ), TOO_FULL );
Expand Down Expand Up @@ -679,10 +679,10 @@ bool player::eat( item &food, bool force )
_( "You've begun stockpiling calories and liquid for hibernation. You get the feeling that you should prepare for bed, just in case, but… you're hungry again, and you could eat a whole week's worth of food RIGHT NOW." ) );
}

const bool will_vomit = stomach.stomach_remaining() < food.volume() &&
rng( units::to_milliliter( stomach.capacity() ) / 2,
const bool will_vomit = stomach.stomach_remaining( *this ) < food.volume() &&
rng( units::to_milliliter( stomach.capacity( *this ) ) / 2,
units::to_milliliter( stomach.contains() ) ) > units::to_milliliter(
stomach.capacity() );
stomach.capacity( *this ) );
const bool saprophage = has_trait( trait_id( "SAPROPHAGE" ) );
if( spoiled && !saprophage ) {
add_msg_if_player( m_bad, _( "Ick, this %s doesn't taste so good…" ), food.tname() );
Expand Down Expand Up @@ -1143,8 +1143,21 @@ bool player::consume_effects( item &food )
// Note: We want this here to prevent "you can't finish this" messages
set_hunger( capacity );
}

// Set up food for ingestion
nutrients ingested;
const item &contained_food = food.is_container() ? food.get_contained() : food;
// maybe move tapeworm to digestion
for( const std::pair<vitamin_id, int> &v : vitamins_from( contained_food ) ) {
ingested.vitamins[v.first] += has_effect( efftype_id( "tapeworm" ) ) ? v.second / 2 : v.second;
}
// @TODO: Move quench values to mL and remove the magic number here
ingested.water = contained_food.type->comestible->quench * 5_ml;
ingested.solids = contained_food.base_volume() - std::max( ingested.water, 0_ml );
ingested.kcal = kcal_for( contained_food );

// GET IN MAH BELLY!
stomach.ingest( *this, food, 1 );
stomach.ingest( ingested );
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions src/debug_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,11 +1115,11 @@ void debug()
std::string stom =
_( "Stomach Contents: %d ml / %d ml kCal: %d, Water: %d ml" );
add_msg( m_info, stom.c_str(), units::to_milliliter( u.stomach.contains() ),
units::to_milliliter( u.stomach.capacity() ), u.stomach.get_calories(),
units::to_milliliter( u.stomach.capacity( u ) ), u.stomach.get_calories(),
units::to_milliliter( u.stomach.get_water() ), u.get_hunger() );
stom = _( "Guts Contents: %d ml / %d ml kCal: %d, Water: %d ml\nHunger: %d, Thirst: %d, kCal: %d / %d" );
add_msg( m_info, stom.c_str(), units::to_milliliter( u.guts.contains() ),
units::to_milliliter( u.guts.capacity() ), u.guts.get_calories(),
units::to_milliliter( u.guts.capacity( u ) ), u.guts.get_calories(),
units::to_milliliter( u.guts.get_water() ), u.get_hunger(), u.get_thirst(), u.get_stored_kcal(),
u.get_healthy_kcal() );
add_msg( m_info, _( "Body Mass Index: %.0f\nBasal Metabolic Rate: %i" ), u.get_bmi(), u.get_bmr() );
Expand Down
2 changes: 1 addition & 1 deletion src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,7 @@ static void marloss_common( player &p, item &it, const trait_id &current_color )

// previously used to set hunger to -10. with the new system, needs to do something
// else that actually makes sense, so it is a little bit more involved.
units::volume fulfill_vol = std::max( p.stomach.capacity() / 8 - p.stomach.contains(), 0_ml );
units::volume fulfill_vol = std::max( p.stomach.capacity( p ) / 8 - p.stomach.contains(), 0_ml );
if( fulfill_vol != 0_ml ) {
p.add_msg_if_player( m_good, _( "It is delicious, and very filling!" ) );
int fulfill_cal = units::to_milliliter( fulfill_vol * 6 );
Expand Down
50 changes: 26 additions & 24 deletions src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2491,37 +2491,39 @@ void player::update_stomach( const time_point &from, const time_point &to )
const bool mycus = has_trait( trait_M_DEPENDENT );
const float kcal_per_time = get_bmr() / ( 12.0f * 24.0f );
const int five_mins = ticks_between( from, to, 5_minutes );
const int half_hours = ticks_between( from, to, 30_minutes );
const units::volume stomach_capacity = stomach.capacity( *this );

if( five_mins > 0 ) {
stomach.absorb_water( *this, 250_ml * five_mins );
guts.absorb_water( *this, 250_ml * five_mins );
}
if( ticks_between( from, to, 30_minutes ) > 0 ) {
// the stomach does not currently have rates of absorption, but this is where it goes
stomach.calculate_absorbed( stomach.get_absorb_rates( true, rates ) );
guts.calculate_absorbed( guts.get_absorb_rates( false, rates ) );
stomach.store_absorbed( *this );
guts.store_absorbed( *this );
guts.bowel_movement( guts.get_pass_rates( false ) );
stomach.bowel_movement( stomach.get_pass_rates( true ), guts );
// Digest nutrients in stomach, they are destined for the guts (except water)
nutrients digested_to_guts = stomach.digest( *this, rates, five_mins, half_hours );
// Digest nutrients in guts, they will be distributed to needs levels
nutrients digested_to_body = guts.digest( *this, rates, five_mins, half_hours );
// Water from stomach skips guts and gets absorbed by body
set_thirst( std::max(
-100, get_thirst() - units::to_milliliter<int>( digested_to_guts.water ) / 5 ) );
guts.ingest( digested_to_guts );
// Apply nutrients, unless this is an NPC and NO_NPC_FOOD is enabled.
if( !is_npc() || !get_option<bool>( "NO_NPC_FOOD" ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if( !is_npc() || !get_option<bool>( "NO_NPC_FOOD" ) ) {
if( !( is_npc() && get_option<bool>( "NO_NPC_FOOD" ) ) ) {

IMHO this is more readable. "If it's not an NPC and we're using no NPC food" as opposed to "if it's not an NPC or we're not using no NPC food".

Copy link
Contributor Author

@Davi-DeGanne Davi-DeGanne Oct 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"If it's not an NPC and we're using no NPC food"

No, this isn't a correct articulation of your version. That wording would represent

if( !is_npc() && get_option<bool>( "NO_NPC_FOOD" ) ) {

which isn't what we want. Your code itself is logically equivalent to mine, but I don't agree that yours is more readable.

I do agree that mine isn't particularly readable either though, I'll add a comment that explains it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah the parenthesis don't come across in the word version I wrote earlier. My code is more like "Unless it's an NPC and we're using No NPC Food". Instead of a comment it could move to a should_process_food method and then if( should_process_food() ) {.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have to disagree, I think my version is more readable, and I don't want to add a function to a class we're trying to deprecate. I did add a comment though. I'll leave this conversation unresolved though so whoever goes to merge this can let me know if they think a change needs to be made.

mod_stored_kcal( digested_to_body.kcal );
vitamins_mod( digested_to_body.vitamins, false );
}
}
if( stomach.time_since_ate() > 10_minutes ) {
if( stomach.contains() >= stomach.capacity() && get_hunger() > -61 ) {
if( stomach.contains() >= stomach_capacity && get_hunger() > -61 ) {
// you're engorged! your stomach is full to bursting!
set_hunger( -61 );
} else if( stomach.contains() >= stomach.capacity() / 2 && get_hunger() > -21 ) {
} else if( stomach.contains() >= stomach_capacity / 2 && get_hunger() > -21 ) {
// sated
set_hunger( -21 );
} else if( stomach.contains() >= stomach.capacity() / 8 && get_hunger() > -1 ) {
} else if( stomach.contains() >= stomach_capacity / 8 && get_hunger() > -1 ) {
// that's really all the food you need to feel full
set_hunger( -1 );
} else if( stomach.contains() == 0_ml ) {
if( guts.get_calories() == 0 && guts.get_calories_absorbed() == 0 &&
get_stored_kcal() < get_healthy_kcal() && get_hunger() < 300 ) {
if( guts.get_calories() == 0 && get_stored_kcal() < get_healthy_kcal() && get_hunger() < 300 ) {
// there's no food except what you have stored in fat
set_hunger( 300 );
} else if( get_hunger() < 100 && ( ( guts.get_calories() == 0 &&
guts.get_calories_absorbed() == 0 &&
get_stored_kcal() >= get_healthy_kcal() ) || get_stored_kcal() < get_healthy_kcal() ) ) {
set_hunger( 100 );
} else if( get_hunger() < 0 ) {
Expand All @@ -2538,13 +2540,13 @@ void player::update_stomach( const time_point &from, const time_point &to )
// if you just ate but your stomach is still empty it will still
// delay your filling up (drugs?)
{
if( stomach.contains() >= stomach.capacity() && get_hunger() > -61 ) {
if( stomach.contains() >= stomach_capacity && get_hunger() > -61 ) {
// you're engorged! your stomach is full to bursting!
set_hunger( -61 );
} else if( stomach.contains() >= stomach.capacity() * 3 / 4 && get_hunger() > -21 ) {
} else if( stomach.contains() >= stomach_capacity * 3 / 4 && get_hunger() > -21 ) {
// sated
set_hunger( -21 );
} else if( stomach.contains() >= stomach.capacity() / 2 && get_hunger() > -1 ) {
} else if( stomach.contains() >= stomach_capacity / 2 && get_hunger() > -1 ) {
// that's really all the food you need to feel full
set_hunger( -1 );
} else if( stomach.contains() > 0_ml && get_kcal_percent() > 0.95 ) {
Expand Down Expand Up @@ -2642,7 +2644,7 @@ void player::check_needs_extremes()
} else {
if( calendar::once_every( 1_hours ) ) {
std::string message;
if( stomach.contains() <= stomach.capacity() / 4 ) {
if( stomach.contains() <= stomach.capacity( *this ) / 4 ) {
if( get_kcal_percent() < 0.1f ) {
message = _( "Food…" );
} else if( get_kcal_percent() < 0.25f ) {
Expand Down Expand Up @@ -2798,9 +2800,9 @@ void player::check_needs_extremes()

}

needs_rates player::calc_needs_rates()
needs_rates player::calc_needs_rates() const
{
effect &sleep = get_effect( effect_sleep );
const effect &sleep = get_effect( effect_sleep );
const bool has_recycler = has_bionic( bio_recycler );
const bool asleep = !sleep.is_null();

Expand Down Expand Up @@ -9426,7 +9428,7 @@ std::pair<std::string, nc_color> player::get_hunger_description() const
{
const bool calorie_deficit = get_bmi() < character_weight_category::normal;
const units::volume contains = stomach.contains();
const units::volume cap = stomach.capacity();
const units::volume cap = stomach.capacity( *this );
std::string hunger_string;
nc_color hunger_color = c_white;
// i ate just now!
Expand Down
2 changes: 1 addition & 1 deletion src/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class player : public Character
void update_stomach( const time_point &from, const time_point &to );
/** Increases hunger, thirst, fatigue and stimulants wearing off. `rate_multiplier` is for retroactive updates. */
void update_needs( int rate_multiplier );
needs_rates calc_needs_rates();
needs_rates calc_needs_rates() const;

/**
* Handles passive regeneration of pain and maybe hp.
Expand Down
Loading