Skip to content

Commit

Permalink
Fix: Count charges in all nearby smoking racks to crafting inventory
Browse files Browse the repository at this point in the history
Fixes an issue where only the charges from one nearby smoking rack would
be counted to the crafting inventory, even if there were other smoking
racks nearby that had sufficient charges to perform a selected crafting
recipe.

The issue before was:
1. Part of building crafting inventory calls `inventory::form_from_map`
2. `inventory::form_from_map` has the following checks for pseudo tools
   from furniture:
   ```
   const furn_t &f = m.furn( p ).obj();
   if( item *furn_item = provide_pseudo_item( f.crafting_pseudo_item ) ) {
        const itype *ammo = f.crafting_ammo_item_type();
   ```
3. `inventory::provide_pseudo_item` returns `nullptr` if the crafting
   inventory already has a tool of the same type:
4. So `inventory::form_from_map` would only get a pseudo tool back in
   `furn_item` for the first furniture that was examined.
5. The ammo amount being calculated in `inventory::form_from_map` would
   therefore only be for that furniture.

This commit instead changes `inventory::provide_pseudo_item` so that if
a pseudo tool is provided more than once, the second call will return
the pseudo tool from the first call, instead of `nullptr` as before.
This makes it possible for `inventory::form_from_map` to keep adding
ammo (charcoal charges) to the same pseudo smoking rack as it builds up
the crafting inventory. In effect, if there are two smoking racks with
charges nearby, the crafting inventory will now still contain only one
pseudo tool for smoking rack, but its ammo will be the sum of all nearby
smoking racks' charges.
  • Loading branch information
inogenous committed Dec 31, 2023
1 parent ff71dff commit 6fa798a
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,13 @@ extern void remove_stale_inventory_quick_shortcuts();
item *inventory::provide_pseudo_item( const item &tool )
{
if( !provisioned_pseudo_tools.insert( tool.typeId() ).second ) {
return nullptr; // already provided tool -> bail out
// already provided tool -> return existing
for( auto &stack : items ) {
if( stack.front().typeId() == tool.typeId() ) {
return &stack.front();
}
}
return nullptr;
}
item *res = &add_item( tool );
res->set_flag( flag_PSEUDO );
Expand Down
115 changes: 115 additions & 0 deletions tests/crafting_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "type_id.h"
#include "value_ptr.h"
#include "veh_appliance.h"
#include "veh_type.h"
#include "vehicle.h"

static const activity_id ACT_CRAFT( "ACT_CRAFT" );
Expand All @@ -48,6 +49,7 @@ static const flag_id json_flag_USE_UPS( "USE_UPS" );
static const itype_id itype_awl_bone( "awl_bone" );
static const itype_id itype_candle( "candle" );
static const itype_id itype_cash_card( "cash_card" );
static const itype_id itype_charcoal( "charcoal" );
static const itype_id itype_chisel( "chisel" );
static const itype_id itype_fake_anvil( "fake_anvil" );
static const itype_id itype_hacksaw( "hacksaw" );
Expand All @@ -59,7 +61,9 @@ static const itype_id itype_sheet_cotton( "sheet_cotton" );
static const itype_id itype_test_cracklins( "test_cracklins" );
static const itype_id itype_test_gum( "test_gum" );
static const itype_id itype_thread( "thread" );
static const itype_id itype_water( "water" );
static const itype_id itype_water_clean( "water_clean" );
static const itype_id itype_water_faucet( "water_faucet" );

static const morale_type morale_food_good( "morale_food_good" );

Expand Down Expand Up @@ -112,6 +116,9 @@ static const skill_id skill_survival( "survival" );
static const trait_id trait_DEBUG_CNF( "DEBUG_CNF" );

static const vpart_id vpart_ap_test_storage_battery( "ap_test_storage_battery" );
static const vpart_id vpart_water_faucet( "water_faucet" );

static const vproto_id vehicle_prototype_test_rv( "test_rv" );

TEST_CASE( "recipe_subset" )
{
Expand Down Expand Up @@ -2282,3 +2289,111 @@ TEST_CASE( "variant_crafting_recipes", "[crafting][slow]" )
CHECK( specific_variant_count == max_iters );
}
}

TEST_CASE( "pseudo_tools_in_crafting_inventory", "[crafting][tools]" )
{
clear_map();
map &here = get_map();

clear_vehicles();
clear_avatar();
avatar &player = get_avatar();
player.setpos( tripoint( 60, 58, 0 ) );
const tripoint veh_pos( 60, 60, 0 );
const tripoint furn1_pos( 60, 57, 0 );
const tripoint furn2_pos( 60, 56, 0 );

const itype_id pseudo_tool = f_smoking_rack.obj().crafting_pseudo_item;

GIVEN( "a vehicle with a liquid tank" ) {
vehicle *veh = here.add_vehicle( vehicle_prototype_test_rv, veh_pos, 0_degrees, 0, 0 );
REQUIRE( veh != nullptr );
for( const vpart_reference &door : veh->get_avail_parts( VPFLAG_OPENABLE ) ) {
door.part().open = true;
}

WHEN( "the tank contains liquid" ) {
REQUIRE( veh->fuel_left( itype_water ) == 0 );
int charges = 50;
for( const vpart_reference &tank : veh->get_avail_parts( vpart_bitflags::VPFLAG_FLUIDTANK ) ) {
tank.part().ammo_set( itype_water, charges );
charges = 0;
}
REQUIRE( veh->fuel_left( itype_water ) == 50 );

THEN( "crafting inventory does not contain the liquid" ) {
player.invalidate_crafting_inventory();
CHECK( player.crafting_inventory().count_item( itype_water_faucet ) == 0 );
CHECK( player.crafting_inventory().charges_of( itype_water ) == 0 );
}
WHEN( "the vehicle has a water faucet part" ) {
REQUIRE( veh->install_part( point_zero, vpart_water_faucet ) >= 0 );
THEN( "crafting inventory contains the liquid" ) {
player.invalidate_crafting_inventory();
CHECK( player.crafting_inventory().count_item( itype_water_faucet ) == 1 );
CHECK( player.crafting_inventory().charges_of( itype_water ) == 50 );
}
}
WHEN( "the vehicle has two water faucets" ) {
REQUIRE( veh->install_part( point_south, vpart_water_faucet ) >= 0 );
THEN( "crafting inventory contains the liquid" ) {
player.invalidate_crafting_inventory();
CHECK( player.crafting_inventory().count_item( itype_water_faucet ) == 1 );
CHECK( player.crafting_inventory().charges_of( itype_water ) == 50 );
}
}
}
clear_vehicles();
}
GIVEN( "a smoking rack" ) {
REQUIRE( here.furn_set( furn1_pos, f_smoking_rack ) );
WHEN( "the smoking rack does not contain any charcoal" ) {
REQUIRE( here.i_at( furn1_pos ).empty() );
THEN( "crafting inventory contains pseudo tool for the smoker, but without any ammo" ) {
player.invalidate_crafting_inventory();
CHECK( player.crafting_inventory().count_item( pseudo_tool ) == 1 );
const int pos = player.crafting_inventory().position_by_type( pseudo_tool );
REQUIRE( pos >= 0 );
const item &rack = player.crafting_inventory().find_item( pos );
CHECK( rack.ammo_remaining() == 0 );
}
}
WHEN( "the smoking rack contains charcoal" ) {
here.add_item( furn1_pos, item( itype_charcoal, calendar::turn_zero, 200 ) );
THEN( "crafting inventory contains pseudo tool for the smoker, with ammo" ) {
player.invalidate_crafting_inventory();
CHECK( player.crafting_inventory().count_item( pseudo_tool ) == 1 );
const int pos = player.crafting_inventory().position_by_type( pseudo_tool );
REQUIRE( pos >= 0 );
const item &rack = player.crafting_inventory().find_item( pos );
CHECK( rack.ammo_remaining() == 200 );
}
GIVEN( "an additional smoking rack" ) {
REQUIRE( here.furn_set( furn2_pos, f_smoking_rack ) );
WHEN( "the second smoking rack does not contain any charcoal" ) {
REQUIRE( here.i_at( furn2_pos ).empty() );
THEN( "crafting inventory contains pseudo tool for smoking rack, with ammo" ) {
player.invalidate_crafting_inventory();
CHECK( player.crafting_inventory().count_item( pseudo_tool ) == 1 );
const int pos = player.crafting_inventory().position_by_type( pseudo_tool );
REQUIRE( pos >= 0 );
const item &rack = player.crafting_inventory().find_item( pos );
CHECK( rack.ammo_remaining() == 200 );
}
}
WHEN( "the second smoking rack also contains charcoal" ) {
here.add_item( furn2_pos, item( itype_charcoal, calendar::turn_zero, 100 ) );
THEN( "crafting inventory contains pseudo tool for smoking rack, with ammo" ) {
player.invalidate_crafting_inventory();
CHECK( player.crafting_inventory().count_item( pseudo_tool ) == 1 );
const int pos = player.crafting_inventory().position_by_type( pseudo_tool );
REQUIRE( pos >= 0 );
const item &rack = player.crafting_inventory().find_item( pos );
CHECK( rack.ammo_remaining() == 300 );
}
}
}
}
clear_map();
}
}

0 comments on commit 6fa798a

Please sign in to comment.