Skip to content

Commit

Permalink
Add item::get_food (#36119)
Browse files Browse the repository at this point in the history
* Add item::get_food

There were many places in the codebase which had to fetch either an item
or its contents, depending on which was food.  Factor that logic out
into a new item member function, to simplify code elsewhere.

* Factor out common get_food implementation
  • Loading branch information
jbytheway authored and ZhilkinSerg committed Dec 16, 2019
1 parent c30e36e commit b58d83c
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2522,7 +2522,7 @@ void activity_handlers::heat_item_finish( player_activity *act, player *p )
if( heat == nullptr ) {
return;
}
item &target = heat->is_food_container() ? heat->contents.front() : *heat;
item &target = *heat->get_food();
if( target.item_tags.count( "FROZEN" ) ) {
target.apply_freezerburn();
if( target.has_flag( "EATEN_COLD" ) ) {
Expand Down
9 changes: 4 additions & 5 deletions src/clzones.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,19 +805,18 @@ zone_type_id zone_manager::get_near_zone_type_for_item( const item &it,

if( cat.get_id() == "food" ) {
const bool preserves = it.is_food_container() && it.type->container->preserves;
const auto &it_food = it.is_food_container() ? it.contents.front() : it;

// skip food without comestible, like MREs
if( it_food.is_food() ) {
if( it_food.get_comestible()->comesttype == "DRINK" ) {
if( !preserves && it_food.goes_bad() && has_near( zone_type_id( "LOOT_PDRINK" ), where, range ) ) {
if( const item *it_food = it.get_food() ) {
if( it_food->get_comestible()->comesttype == "DRINK" ) {
if( !preserves && it_food->goes_bad() && has_near( zone_type_id( "LOOT_PDRINK" ), where, range ) ) {
return zone_type_id( "LOOT_PDRINK" );
} else if( has_near( zone_type_id( "LOOT_DRINK" ), where, range ) ) {
return zone_type_id( "LOOT_DRINK" );
}
}

if( !preserves && it_food.goes_bad() && has_near( zone_type_id( "LOOT_PFOOD" ), where, range ) ) {
if( !preserves && it_food->goes_bad() && has_near( zone_type_id( "LOOT_PFOOD" ), where, range ) ) {
return zone_type_id( "LOOT_PFOOD" );
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/crafting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1859,10 +1859,9 @@ ret_val<bool> player::can_disassemble( const item &obj, const inventory &inv ) c
return ret_val<bool>::make_failure( _( "You can't see to craft!" ) );
}
// refuse to disassemble rotten items
if( obj.goes_bad() || ( obj.is_food_container() && obj.contents.front().goes_bad() ) ) {
if( obj.rotten() || ( obj.is_food_container() && obj.contents.front().rotten() ) ) {
return ret_val<bool>::make_failure( _( "It's rotten, I'm not taking that apart." ) );
}
const item *food = obj.get_food();
if( ( obj.goes_bad() && obj.rotten() ) || ( food && food->goes_bad() && food->rotten() ) ) {
return ret_val<bool>::make_failure( _( "It's rotten, I'm not taking that apart." ) );
}

if( obj.count_by_charges() && !r.has_flag( "UNCRAFT_SINGLE_CHARGE" ) ) {
Expand Down
47 changes: 31 additions & 16 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1248,8 +1248,8 @@ void item::basic_info( std::vector<iteminfo> &info, const iteminfo_query *parts,
imap.second ) ) );
}

const item *food = is_food_container() ? &contents.front() : this;
if( food->goes_bad() ) {
const item *food = get_food();
if( food && food->goes_bad() ) {
info.push_back( iteminfo( "BASE", _( "age (turns): " ),
"", iteminfo::lower_is_better,
to_turns<int>( food->age() ) ) );
Expand All @@ -1266,7 +1266,7 @@ void item::basic_info( std::vector<iteminfo> &info, const iteminfo_query *parts,
"", iteminfo::lower_is_better,
to_turn<int>( food->last_temp_check ) ) );
}
if( food->has_temperature() ) {
if( food && food->has_temperature() ) {
info.push_back( iteminfo( "BASE", _( "Temp: " ), "", iteminfo::lower_is_better,
food->temperature ) );
info.push_back( iteminfo( "BASE", _( "Spec ener: " ), "",
Expand Down Expand Up @@ -3223,13 +3223,7 @@ std::string item::info( std::vector<iteminfo> &info, const iteminfo_query *parts
med_info( med_item, info, parts, batch, debug );
}

const item *food_item = nullptr;
if( is_food() ) {
food_item = this;
} else if( is_food_container() ) {
food_item = &contents.front();
}
if( food_item != nullptr ) {
if( const item *food_item = get_food() ) {
food_info( food_item, info, parts, batch, debug );
}

Expand Down Expand Up @@ -3364,13 +3358,12 @@ nc_color item::color_in_inventory() const
} else if( is_corpse() && can_revive() ) {
// Only reviving corpses are yellow
ret = c_yellow;
} else if( is_food() || is_food_container() ) {
} else if( const item *food = get_food() ) {
const bool preserves = type->container && type->container->preserves;
const item &to_color = is_food() ? *this : contents.front();

// Give color priority to allergy (allergy > inedible by freeze or other conditions)
// TODO: refactor u.will_eat to let this section handle coloring priority without duplicating code.
if( u.allergy_type( to_color ) != morale_type( "morale_null" ) ) {
if( u.allergy_type( *food ) != morale_type( "morale_null" ) ) {
return c_red;
}

Expand All @@ -3380,16 +3373,16 @@ nc_color item::color_in_inventory() const
// Red: morale penalty
// Yellow: will rot soon
// Cyan: will rot eventually
const ret_val<edible_rating> rating = u.will_eat( to_color );
const ret_val<edible_rating> rating = u.will_eat( *food );
// TODO: More colors
switch( rating.value() ) {
case EDIBLE:
case TOO_FULL:
if( preserves ) {
// Nothing, canned food won't rot
} else if( to_color.is_going_bad() ) {
} else if( food->is_going_bad() ) {
ret = c_yellow;
} else if( to_color.goes_bad() ) {
} else if( food->goes_bad() ) {
ret = c_cyan;
}
break;
Expand Down Expand Up @@ -5721,6 +5714,28 @@ float item::get_freeze_point() const
return get_comestible()->freeze_point;
}

template<typename Item>
static Item *get_food_impl( Item *it )
{
if( it->is_food() ) {
return it;
} else if( it->is_food_container() && !it->contents.empty() ) {
return &it->contents.front();
} else {
return nullptr;
}
}

item *item::get_food()
{
return get_food_impl( this );
}

const item *item::get_food() const
{
return get_food_impl( this );
}

void item::set_mtype( const mtype *const m )
{
// This is potentially dangerous, e.g. for corpse items, which *must* have a valid mtype pointer.
Expand Down
5 changes: 5 additions & 0 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,11 @@ class item : public visitable<item>
float get_latent_heat() const;
float get_freeze_point() const; // Farenheit

// If this is food, returns itself. If it contains food, return that
// contents. Otherwise, returns nullptr.
item *get_food();
const item *get_food() const;

/** What faults can potentially occur with this item? */
std::set<fault_id> faults_potential() const;

Expand Down
12 changes: 6 additions & 6 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5495,26 +5495,26 @@ int iuse::handle_ground_graffiti( player &p, item *it, const std::string &prefix
static bool heat_item( player &p )
{
auto loc = g->inv_map_splice( []( const item & itm ) {
return( ( itm.is_food() && !itm.item_tags.count( "HOT" ) ) ||
( itm.is_food_container() && !itm.contents.front().item_tags.count( "HOT" ) ) );
const item *food = itm.get_food();
return food && food->item_tags.count( "HOT" );
}, _( "Heat up what?" ), 1, _( "You don't have appropriate food to heat up." ) );

item *heat = loc.get_item();
if( heat == nullptr ) {
add_msg( m_info, _( "Never mind." ) );
return false;
}
item &target = heat->is_food_container() ? heat->contents.front() : *heat;
item *target = heat->get_food();
// simulates heat capacity of food, more weight = longer heating time
// this is x2 to simulate larger delta temperature of frozen food in relation to
// heating non-frozen food (x1); no real life physics here, only aproximations
int duration = to_turns<int>( time_duration::from_seconds( to_gram( target.weight() ) ) ) * 10;
if( target.item_tags.count( "FROZEN" ) && !target.has_flag( "EATEN_COLD" ) ) {
int duration = to_turns<int>( time_duration::from_seconds( to_gram( target->weight() ) ) ) * 10;
if( target->item_tags.count( "FROZEN" ) && !target->has_flag( "EATEN_COLD" ) ) {
duration *= 2;
}
p.add_msg_if_player( m_info, _( "You start heating up the food." ) );
p.assign_activity( activity_id( "ACT_HEATING" ), duration );
p.activity.targets.push_back( item_location( p, &target ) );
p.activity.targets.push_back( item_location( p, target ) );
return true;
}

Expand Down
9 changes: 3 additions & 6 deletions src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1482,12 +1482,9 @@ void npc::decide_needs()
invslice slice = inv.slice();
for( auto &i : slice ) {
item inventory_item = i->front();
if( inventory_item.is_food( ) ) {
needrank[ need_food ] += nutrition_for( inventory_item ) / 4.0;
needrank[ need_drink ] += inventory_item.get_comestible()->quench / 4.0;
} else if( inventory_item.is_food_container() ) {
needrank[ need_food ] += nutrition_for( inventory_item.contents.front() ) / 4.0;
needrank[ need_drink ] += inventory_item.contents.front().get_comestible()->quench / 4.0;
if( const item *food = inventory_item.get_food() ) {
needrank[ need_food ] += nutrition_for( *food ) / 4.0;
needrank[ need_drink ] += food->get_comestible()->quench / 4.0;
}
}
needs.clear();
Expand Down
14 changes: 7 additions & 7 deletions src/npcmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3707,13 +3707,13 @@ bool npc::consume_food()
invslice slice = inv.slice();
for( size_t i = 0; i < slice.size(); i++ ) {
const item &it = slice[i]->front();
const item &food_item = it.is_food_container() ?
it.contents.front() : it;
float cur_weight = rate_food( food_item, want_hunger, want_quench );
// Note: will_eat is expensive, avoid calling it if possible
if( cur_weight > best_weight && will_eat( food_item ).success() ) {
best_weight = cur_weight;
index = i;
if( const item *food_item = it.get_food() ) {
float cur_weight = rate_food( *food_item, want_hunger, want_quench );
// Note: will_eat is expensive, avoid calling it if possible
if( cur_weight > best_weight && will_eat( *food_item ).success() ) {
best_weight = cur_weight;
index = i;
}
}
}

Expand Down

0 comments on commit b58d83c

Please sign in to comment.