Skip to content

Commit

Permalink
Allow player to pick up frozen liquids (#32763)
Browse files Browse the repository at this point in the history
* allow player to pick frozen liquids
Players should be able to chip or crush ice or other frozen liquids
and pick them up and keep them in their inventory as long as they're
frozen
  • Loading branch information
EddiTheBambi authored and kevingranade committed Aug 16, 2019
1 parent 27b909c commit 946365f
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/advanced_inv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2162,7 +2162,7 @@ bool advanced_inventory::query_charges( aim_location destarea, const advanced_in
amount = input_amount;

// Includes moving from/to inventory and around on the map.
if( it.made_of_from_type( LIQUID ) ) {
if( it.made_of_from_type( LIQUID ) && !it.is_frozen_liquid() ) {
popup( _( "You can't pick up a liquid." ) );
redraw = true;
return false;
Expand Down
5 changes: 4 additions & 1 deletion src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,9 +1115,12 @@ void find_ammo_helper( T &src, const item &obj, bool empty, Output out, bool nes
return VisitResponse::SKIP;
}
if( !node->made_of( SOLID ) ) {
// some liquids are ammo but we can't reload with them unless within a container
// some liquids are ammo but we can't reload with them unless within a container or frozen
return VisitResponse::SKIP;
}
if( node->is_frozen_liquid() ) {
out = item_location( src, node );
}
if( node->is_ammo_container() && !node->contents.empty() &&
!node->contents_made_of( SOLID ) ) {
for( const ammotype &at : ammo ) {
Expand Down
6 changes: 6 additions & 0 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8538,6 +8538,12 @@ void game::reload( item_location &loc, bool prompt, bool empty )
item::reload_option( &u, it, it, u.ammo_location ) :
u.select_ammo( *it, prompt, empty );

if( opt.ammo.get_item() != nullptr && opt.ammo.get_item()->is_frozen_liquid() ) {
if( !u.crush_frozen_liquid( opt.ammo ) ) {
return;
}
}

if( opt ) {
u.assign_activity( activity_id( "ACT_RELOAD" ), opt.moves(), opt.qty() );
if( use_loc ) {
Expand Down
10 changes: 5 additions & 5 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,11 @@ bool item::is_unarmed_weapon() const
return has_flag( "UNARMED_WEAPON" ) || is_null();
}

bool item::is_frozen_liquid() const
{
return made_of( SOLID ) && made_of_from_type( LIQUID );
}

bool item::covers( const body_part bp ) const
{
return get_covered_body_parts().test( bp );
Expand Down Expand Up @@ -6631,11 +6636,6 @@ bool item::reload( player &u, item_location loc, int qty )
debugmsg( "Tried to reload liquid container with non-liquid." );
return false;
}
if( !ammo->made_of( LIQUID ) ) {
u.add_msg_if_player( m_bad, _( "The %s froze solid before you could finish." ),
ammo->tname() );
return false;
}
if( container ) {
container->on_contents_changed();
}
Expand Down
4 changes: 4 additions & 0 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,10 @@ class item : public visitable<item>
bool is_unarmed_weapon() const; //Returns true if the item should be considered unarmed

bool has_temperature() const;

/** Returns true if the item is A: is SOLID and if it B: is of type LIQUID */
bool is_frozen_liquid() const;

float get_specific_heat_liquid() const;
float get_specific_heat_solid() const;
float get_latent_heat() const;
Expand Down
13 changes: 8 additions & 5 deletions src/pickup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offer

// We already checked in do_pickup if this was a nullptr
// Make copies so the original remains untouched if we bail out
item newit = *loc.get_item();
item_location newloc = loc;
item newit = *newloc.get_item();
item leftovers = newit;

const auto wield_check = u.can_wield( newit );
Expand Down Expand Up @@ -213,8 +214,10 @@ bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offer
if( newit.is_ammo() && newit.charges == 0 ) {
picked_up = true;
option = NUM_ANSWERS; //Skip the options part
} else if( newit.made_of_from_type( LIQUID ) ) {
got_water = true;
} else if( newit.is_frozen_liquid() ) {
if( !( got_water = !( u.crush_frozen_liquid( newloc ) ) ) ) {
option = STASH;
}
} else if( !u.can_pickWeight( newit, false ) ) {
if( !autopickup ) {
const std::string &explain = string_format( _( "The %s is too heavy!" ),
Expand Down Expand Up @@ -388,11 +391,11 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from )
bool isEmpty = ( g->m.i_at( p ).empty() );

// Hide the pickup window if this is a toilet and there's nothing here
// but water.
// but non-frozen water.
if( ( !isEmpty ) && g->m.furn( p ) == f_toilet ) {
isEmpty = true;
for( const item &maybe_water : g->m.i_at( p ) ) {
if( maybe_water.typeId() != "water" ) {
if( maybe_water.typeId() != "water" || maybe_water.is_frozen_liquid() ) {
isEmpty = false;
break;
}
Expand Down
43 changes: 42 additions & 1 deletion src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8108,7 +8108,7 @@ void player::mend_item( item_location &&obj, bool interactive )

int player::item_reload_cost( const item &it, const item &ammo, int qty ) const
{
if( ammo.is_ammo() ) {
if( ammo.is_ammo() || ammo.is_frozen_liquid() ) {
qty = std::max( std::min( ammo.charges, qty ), 1 );
} else if( ammo.is_ammo_container() || ammo.is_container() ) {
qty = std::max( std::min( ammo.contents.front().charges, qty ), 1 );
Expand Down Expand Up @@ -11647,6 +11647,47 @@ std::vector<const item *> player::all_items_with_flag( const std::string &flag )
} );
}

item &player::item_with_best_of_quality( const quality_id &qid )
{
int maxq = max_quality( qid );
auto items_with_quality = items_with( [qid]( const item & it ) {
return it.has_quality( qid );
} );
for( item *it : items_with_quality ) {
if( it->get_quality( qid ) == maxq ) {
return *it;
}
}
return null_item_reference();
}

bool player::crush_frozen_liquid( item_location loc )
{

player &u = g->u;

if( u.has_quality( quality_id( "HAMMER" ) ) ) {
item hammering_item = u.item_with_best_of_quality( quality_id( "HAMMER" ) );
if( query_yn( _( "Do you want to crush up %s with your %s?\n%s" ), loc.get_item()->display_name(),
hammering_item.tname(),
colorize( _( "Be wary of fragile items nearby!" ), c_red ) ) ) {

//Risk smashing tile with hammering tool, risk is lower with higher dex, damage lower with lower strength
if( one_in( 1 + u.dex_cur / 4 ) ) {
add_msg_if_player( colorize( _( "You swing your %s wildly!" ), c_red ),
hammering_item.tname() );
int smashskill = u.str_cur + hammering_item.damage_melee( DT_BASH );
g->m.bash( loc.position(), smashskill );
}
add_msg_if_player( _( "You crush up and gather %s" ), loc.get_item()->display_name() );
return true;
}
} else {
popup( _( "You need a hammering tool to crush up frozen liquids!" ) );
}
return false;
}

bool player::has_item_with_flag( const std::string &flag, bool need_charges ) const
{
return has_item_with( [&flag, &need_charges]( const item & it ) {
Expand Down
9 changes: 9 additions & 0 deletions src/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,15 @@ class player : public Character
// Carried items may leak radiation or chemicals
int leak_level( const std::string &flag ) const;

/** Returns the item in the player's inventory with the highest of the specified quality*/
item &item_with_best_of_quality( const quality_id &qid );

/**
* Prompts user about crushing item at item_location loc, for harvesting of frozen liquids
* @param loc Location for item to crush
*/
bool crush_frozen_liquid( item_location loc );

// Has a weapon, inventory item or worn item with flag
bool has_item_with_flag( const std::string &flag, bool need_charges = false ) const;

Expand Down

0 comments on commit 946365f

Please sign in to comment.