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

Initial code for improvements of the water faucet. #36315

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 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
9 changes: 9 additions & 0 deletions src/vehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ int cmps_to_vmiph( int cmps );
int vmiph_to_cmps( int vmiph );
static constexpr float accel_g = 9.81f;

using item_count_tuple = std::tuple<item *, uint32_t>;

/**
* Structure, describing vehicle part (ie, wheel, seat)
*/
Expand Down Expand Up @@ -1582,6 +1584,13 @@ class vehicle
void use_bike_rack( int part );
void use_harness( int part, const tripoint &pos );

std::vector<item_count_tuple> get_comestible_liquids();
item_count_tuple select_comestible_liquid( const std::vector<item_count_tuple> &comestible_liquids,
const std::string &message );
void use_fill_container( const item *comestible_liquid, bool has_hotplate,
bool has_freezer );
void use_faucet( const item *comestible_liquid, bool has_hotplate, bool has_freezer );

void interact_with( const tripoint &pos, int interact_part );

std::string disp_name() const;
Expand Down
144 changes: 138 additions & 6 deletions src/vehicle_use.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,129 @@ void vehicle::use_harness( int part, const tripoint &pos )
}
}

std::vector<item_count_tuple> vehicle::get_comestible_liquids()
{
std::vector<item_count_tuple> liquids;
std::map<item *, uint32_t> liquids_map;

liquids.clear();
liquids_map.clear();

for( auto &part : parts ) {
const int remaining = part.ammo_remaining();

if( !part.is_tank() || part.base.contents_made_of( SOLID ) || remaining <= 0 ) {
continue;
}

item *food_ptr = part.base.get_food();

if( food_ptr == nullptr || !food_ptr->is_comestible() ) {
continue;
}

const islot_comestible &comestible = *food_ptr->get_comestible();

if( "DRINK" != comestible.comesttype ) {
continue;
}

const itype_id liquid_id = part.ammo_current();

if( liquid_id == "null" || liquid_id == "water" ) {
continue;
}

liquids_map[food_ptr] += static_cast<uint32_t>( remaining );
}

for( auto &liquid : liquids_map ) {
liquids.emplace_back( liquid.first, liquid.second );
}

std::sort( liquids.begin(), liquids.end(),
[]( const item_count_tuple & a, const item_count_tuple & b ) {
return std::get<1>( a ) > std::get<1>( b );
} );

return liquids;
}

item_count_tuple vehicle::select_comestible_liquid( const std::vector<item_count_tuple> &liquids,
const std::string &message )
{
uilist selectmenu;
int choice = std::numeric_limits<int>::min();
int idx = 0;

if( liquids.empty() ) {
for( auto &liquid : liquids ) {
const item *p_item = std::get<0>( liquid );
selectmenu.addentry( idx++, true, MENU_AUTOASSIGN, p_item->tname( std::get<1>( liquid ) ) );
}

if( selectmenu.entries.size() == 1 ) {
choice = selectmenu.entries.front().retval;
} else {
selectmenu.text = message;
selectmenu.query();
choice = selectmenu.ret;
}

if( choice >= 0 && choice < idx ) {
try {
return liquids[static_cast<size_t>( choice )];
} catch( const std::out_of_range & ) {
debugmsg( "Warning! Invalid comestible liquid index" );
gregoranders marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

return item_count_tuple( nullptr, 0 );
}

void vehicle::use_fill_container( const item *comestibale_ptr, bool, bool )
{
if( comestibale_ptr && comestibale_ptr->is_comestible() ) {
itype_id liquid_id = comestibale_ptr->typeId();

g->u.siphon( *this, liquid_id );
}
}

void vehicle::use_faucet( const item *comestible_ptr, bool has_hotplate, bool has_freezer )
{
if( comestible_ptr && comestible_ptr->is_comestible() ) {
itype_id liquid_id = comestible_ptr->typeId();
item liquid( liquid_id, calendar::turn, 1 );

int battery_fuel = fuel_left( "battery", true );

if( comestible_ptr->has_flag( "EATEN_HOT" ) && !comestible_ptr->has_flag( "HOT" )
&& has_hotplate && comestible_ptr->type ) {
int required_charges = comestible_ptr->type->charges_to_use();

if( required_charges <= battery_fuel ) {
discharge_battery( required_charges );
liquid.heat_up();
}
} else if( comestible_ptr->has_flag( "EATEN_COLD" ) && !comestible_ptr->has_flag( "COLD" )
&& has_freezer && comestible_ptr->type ) {
int required_charges = comestible_ptr->type->charges_to_use();

if( required_charges <= battery_fuel ) {
discharge_battery( required_charges );
liquid.cold_up();
}
}

if( g->u.eat( liquid ) ) {
drain( liquid_id, 1 );
g->u.moves -= 250;
}
}
}

void vehicle::use_bike_rack( int part )
{
if( parts[part].is_unavailable() || parts[part].removed ) {
Expand Down Expand Up @@ -1888,6 +2011,9 @@ void vehicle::interact_with( const tripoint &pos, int interact_part )
avail_part_with_feature( interact_part, "ADVANCED_PLANTER", true ) >= 0;
const int workbench_part = avail_part_with_feature( interact_part, "WORKBENCH", true );
const bool has_workbench = workbench_part >= 0;
const std::vector<item_count_tuple> comestible_liquids = get_comestible_liquids();
const bool has_freezer = avail_part_with_feature( interact_part, "FREEZER", true ) >= 0;
const bool has_fridge = avail_part_with_feature( interact_part, "FRIDGE", true ) >= 0;

enum {
EXAMINE, TRACK, CONTROL, CONTROL_ELECTRONICS, GET_ITEMS, GET_ITEMS_ON_GROUND, FOLD_VEHICLE, UNLOAD_TURRET, RELOAD_TURRET,
Expand Down Expand Up @@ -1941,7 +2067,7 @@ void vehicle::interact_with( const tripoint &pos, int interact_part )
if( ( has_kitchen || has_chemlab ) && fuel_left( "battery", true ) > 0 ) {
selectmenu.addentry( USE_HOTPLATE, true, 'h', _( "Use the hotplate" ) );
}
if( has_faucet && fuel_left( "water_clean" ) > 0 ) {
if( has_faucet && !comestible_liquids.empty() ) {
selectmenu.addentry( FILL_CONTAINER, true, 'c', _( "Fill a container with water" ) );
selectmenu.addentry( DRINK, true, 'd', _( "Have a drink" ) );
}
Expand Down Expand Up @@ -2041,14 +2167,20 @@ void vehicle::interact_with( const tripoint &pos, int interact_part )
return;
}
case FILL_CONTAINER: {
g->u.siphon( *this, "water_clean" );
item_count_tuple item_tuple = select_comestible_liquid( comestible_liquids,
_( "Select a liquid" ) );
const item *comestible_ptr = std::get<0>( item_tuple );
if( comestible_ptr ) {
use_fill_container( std::get<0>( item_tuple ), ( has_chemlab || has_kitchen ), ( has_fridge ||
gregoranders marked this conversation as resolved.
Show resolved Hide resolved
has_freezer ) );
}
return;
}
case DRINK: {
item water( "water_clean", 0 );
if( g->u.eat( water ) ) {
drain( "water_clean", 1 );
g->u.moves -= 250;
item_count_tuple item_tuple = select_comestible_liquid( comestible_liquids, _( "Select a drink" ) );
const item *comestible_ptr = std::get<0>( item_tuple );
if( comestible_ptr ) {
use_faucet( comestible_ptr, ( has_chemlab || has_kitchen ), ( has_fridge || has_freezer ) );
}
return;
}
Expand Down
134 changes: 134 additions & 0 deletions tests/vehicle_interact_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,137 @@ TEST_CASE( "repair_vehicle_part" )
test_repair( tools, false );
}
}

TEST_CASE( "water faucet offers comestible liquids", "[water_faucet]" )
{
const tripoint test_origin( 60, 60, 0 );
const tripoint vehicle_origin = test_origin + tripoint_north;
int battery_charge = 10000;

clear_player();
clear_map();

g->place_player( test_origin );

vehicle *veh_ptr = g->m.add_vehicle( vproto_id( "none" ), vehicle_origin, 0, 0, 0 );
REQUIRE( veh_ptr != nullptr );

REQUIRE( veh_ptr->install_part( point_zero, vpart_id( "storage_battery" ), true ) >= 0 );
veh_ptr->charge_battery( battery_charge );

REQUIRE( veh_ptr->install_part( point_zero, vpart_id( "tank_medium" ), true ) >= 0 );
REQUIRE( veh_ptr->install_part( point_zero + point_north, vpart_id( "tank_medium" ), true ) >= 0 );
REQUIRE( veh_ptr->install_part( point_zero + point_east, vpart_id( "tank_medium" ), true ) >= 0 );
REQUIRE( veh_ptr->install_part( point_zero + point_west, vpart_id( "tank_medium" ), true ) >= 0 );

std::vector<vehicle_part *> parts;

vehicle_part *battery_ptr = nullptr;

for( auto &part : veh_ptr->parts ) {
if( part.is_tank() ) {
parts.push_back( std::addressof( part ) );
}
if( part.is_battery() ) {
battery_ptr = std::addressof( part );
}
}

REQUIRE( battery_ptr != nullptr );
REQUIRE( parts.size() == 4 );

std::vector<item_count_tuple> liquids = veh_ptr->get_comestible_liquids();

REQUIRE( liquids.empty() );

item item_water( itype_id( "water" ), calendar::turn, 4 );
item item_water_clean( itype_id( "water_clean" ), calendar::turn, 4 );
item item_pine_tea( itype_id( "pine_tea" ), calendar::turn, 4 );

parts[0]->ammo_set( item_water.typeId(), item_water.charges );
parts[1]->ammo_set( item_water_clean.typeId(), item_water_clean.charges );
parts[2]->ammo_set( item_pine_tea.typeId(), item_pine_tea.charges );

liquids = veh_ptr->get_comestible_liquids();
REQUIRE( liquids.size() == 2 );

// clean water
REQUIRE( item_water_clean.charges == 4 );

veh_ptr->use_faucet( std::addressof( item_water_clean ), false, false );
item_water_clean.charges--;

REQUIRE( parts[1]->ammo_remaining() == item_water_clean.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_water_clean.charges == 3 );

veh_ptr->use_faucet( std::addressof( item_water_clean ), true, true );
item_water_clean.charges--;
battery_charge--;

REQUIRE( parts[1]->ammo_remaining() == item_water_clean.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_water_clean.charges == 2 );

veh_ptr->use_faucet( std::addressof( item_water_clean ), true, false );
item_water_clean.charges--;

REQUIRE( parts[1]->ammo_remaining() == item_water_clean.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_water_clean.charges == 1 );

veh_ptr->use_faucet( std::addressof( item_water_clean ), false, true );
item_water_clean.charges--;
battery_charge--;

REQUIRE( parts[1]->ammo_remaining() == item_water_clean.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_water_clean.charges == 0 );

liquids = veh_ptr->get_comestible_liquids();
REQUIRE( liquids.size() == 1 );

// pine needle tea
REQUIRE( item_pine_tea.charges == 4 );

veh_ptr->use_faucet( std::addressof( item_pine_tea ), false, false );
item_pine_tea.charges--;

REQUIRE( parts[2]->ammo_remaining() == item_pine_tea.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_pine_tea.charges == 3 );

veh_ptr->use_faucet( std::addressof( item_pine_tea ), true, true );
item_pine_tea.charges--;
battery_charge--;

REQUIRE( parts[2]->ammo_remaining() == item_pine_tea.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_pine_tea.charges == 2 );

veh_ptr->use_faucet( std::addressof( item_pine_tea ), true, false );
item_pine_tea.charges--;
battery_charge--;

REQUIRE( parts[2]->ammo_remaining() == item_pine_tea.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_pine_tea.charges == 1 );

veh_ptr->use_faucet( std::addressof( item_pine_tea ), false, true );
item_pine_tea.charges--;

REQUIRE( parts[2]->ammo_remaining() == item_pine_tea.charges );
REQUIRE( battery_ptr->ammo_remaining() == battery_charge );

REQUIRE( item_pine_tea.charges == 0 );

liquids = veh_ptr->get_comestible_liquids();
REQUIRE( liquids.size() == 0 );
}