Skip to content

Commit

Permalink
Stomach code refactor (CleverRaven#35143)
Browse files Browse the repository at this point in the history
* Remove unused methods from stomach.cpp

* Combine several methods so stomach.cpp is simpler
There were several issues with the previous implementation of the
stomach_contents class. For instance, using the class required intricate
knowledge of its implementation. Additionally, the most important and
commonly performed task, digesting food every half-hour, required
calling four specific methods in a specific order, when they could
easily be combined into one method. Overall, the class suffered from
over-complexity and I decided to fix this by making the following
changes:

Combined store_water, calculate_absorbed, store_absorbed, and
bowel_movement into one method, "digest".

Removed references to calories_absorbed and vitamins_absorbed, as these
are no longer used after the above change.

Combined pass_rates and absorb_rates: stomach-types never absorbed
anything, and guts-types passed so slowly as to be inconsequential, so
these concepts were combined into digest_rates.

Whether a stomach_contents is a stomach or guts is now decided when the
object is constructed; it was already that way in practice, I just made
it official.

* Make all_nutrition_starve_test far more strict
Now that vitamins aren't disappearing, this test can be tuned to make
sure that vitamins are being absorbed into the body correctly.

* Implement suggestions from KorGgenT
- Replace auto with type specification.
- Add const where applicable
- Replaces 'player' type parameters with 'needs_rates'

Co-Authored-By: Curtis Merrill <[email protected]>

* Remove unused #includes

* Refactor ingest function
The previous ingest function in stomach.cpp used the 'player' object,
which we are moving away from. Since the only call of that function was
in the 'player' scope, it was trivial to move that code there and call
the new, more generalized ingest function instead.

* Fix bug with stomach capacity calculation
Stomach capacity was always based on the player's mutations, no matter
who owned said stomach. Now the capacity function takes a Character
reference as a parameter, and uses that Character's mutations instead.
  • Loading branch information
Davi-DeGanne authored and AMurkin committed Nov 13, 2019
1 parent 6fdb4f7 commit 927e94d
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 423 deletions.
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 @@ -5567,8 +5567,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 @@ -595,7 +595,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 @@ -677,10 +677,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 @@ -1131,8 +1131,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 @@ -2388,37 +2388,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" ) ) {
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 @@ -2435,13 +2437,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 @@ -2539,7 +2541,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 @@ -2695,9 +2697,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 @@ -7358,7 +7360,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

0 comments on commit 927e94d

Please sign in to comment.