From 7fc710f87496070b0ca2fa86cf8a4ec2c261dad0 Mon Sep 17 00:00:00 2001 From: Procyonae <45432782+Procyonae@users.noreply.github.com> Date: Sat, 11 May 2024 22:26:26 +0100 Subject: [PATCH] Fixing reload_furniture to allow reloading with ammo other than the default Co-Authored-By: Kate <24497894+katemonster33@users.noreply.github.com> Co-Authored-By: RenechCDDA <84619419+renechcdda@users.noreply.github.com> Co-Authored-By: Jeremy Rose --- data/json/items/basecamp.json | 17 +++--- src/iexamine.cpp | 98 ++++++++++++++++++++++------------- src/inventory.cpp | 30 ++++++----- src/map.cpp | 40 +++++++------- src/mapdata.h | 4 +- 5 files changed, 109 insertions(+), 80 deletions(-) diff --git a/data/json/items/basecamp.json b/data/json/items/basecamp.json index d1fe1f06c19e6..1412d4901b3e5 100644 --- a/data/json/items/basecamp.json +++ b/data/json/items/basecamp.json @@ -3,11 +3,10 @@ "id": "fake_char_kiln", "//": "The stationary object needs a larger capacity than the portable base object", "type": "TOOL", - "copy-from": "fake_item", + "copy-from": "fake_crafting_tool", "name": { "str": "basecamp kiln" }, "description": "A fake kiln used for basecamps.", "sub": "char_kiln", - "extend": { "flags": [ "ALLOWS_REMOTE_USE" ] }, "ammo": [ "charcoal" ], "//1": "250 liters of materials can produce 100 liters of charcoal.", "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "charcoal": 20000 } } ] @@ -16,11 +15,10 @@ "id": "fake_char_smoker", "//": "The stationary object needs a larger capacity than the portable base object", "type": "TOOL", - "copy-from": "fake_item", + "copy-from": "fake_crafting_tool", "name": { "str": "basecamp charcoal smoker" }, "description": "A fake charcoal smoker used for basecamps.", "sub": "char_smoker", - "extend": { "flags": [ "ALLOWS_REMOTE_USE" ] }, "ammo": [ "charcoal" ], "//1": "holds 450 liters of charcoal. a full smoking rack cycle of 20L of stuff would consume 15,000 charcoal (75 liters, 15.6kg of charcoal)", "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "charcoal": 90000 } } ] @@ -32,29 +30,27 @@ "name": { "str": "basecamp forge" }, "copy-from": "char_forge", "description": "A fake charcoal forge used for basecamps.", - "extend": { "flags": [ "ALLOWS_REMOTE_USE", "ZERO_WEIGHT" ] }, + "extend": { "flags": [ "ALLOWS_REMOTE_USE", "ZERO_WEIGHT", "PSEUDO" ] }, "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "charcoal": 2000, "coal": 10000 } } ] }, { "id": "fake_clay_kiln", "//": "The stationary object needs a larger capacity than the portable base object", "type": "TOOL", - "copy-from": "fake_item", + "copy-from": "fake_crafting_tool", "name": { "str": "basecamp clay kiln" }, "description": "A fake clay kiln used for basecamps.", "sub": "brick_kiln", - "extend": { "flags": [ "ALLOWS_REMOTE_USE" ] }, "ammo": [ "charcoal", "coal" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "charcoal": 2000, "coal": 10000 } } ] }, { "id": "fake_fireplace", "type": "TOOL", - "copy-from": "fake_item", + "copy-from": "fake_crafting_tool", "name": { "str": "basecamp fireplace" }, "description": "A fake fireplace used for basecamps.", "sub": "hotplate", - "extend": { "flags": [ "ALLOWS_REMOTE_USE" ] }, "ammo": [ "tinder" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "tinder": 50000 } } ], "charge_factor": 25 @@ -62,11 +58,10 @@ { "id": "fake_woodstove", "type": "TOOL", - "copy-from": "fake_item", + "copy-from": "fake_crafting_tool", "name": { "str": "basecamp stove" }, "description": "A fake stove used for basecamps.", "sub": "hotplate", - "extend": { "flags": [ "ALLOWS_REMOTE_USE" ] }, "ammo": [ "tinder" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "tinder": 50000 } } ], "charge_factor": 10 diff --git a/src/iexamine.cpp b/src/iexamine.cpp index eb9b6bd38fc24..f9867cf21c149 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -4329,13 +4329,19 @@ const itype *furn_t::crafting_pseudo_item_type() const return item::find_type( crafting_pseudo_item ); } -const itype *furn_t::crafting_ammo_item_type() const +std::vector furn_t::crafting_ammo_item_types() const { const itype *pseudo = crafting_pseudo_item_type(); + std::vector output; if( pseudo && pseudo->tool && !pseudo->tool->ammo_id.empty() ) { - return item::find_type( ammotype( *pseudo->tool->ammo_id.begin() )->default_ammotype() ); + for( const ammotype &atype : pseudo->tool->ammo_id ) { + const itype *itype = item::find_type( atype->default_ammotype() ); + if( itype != nullptr ) { + output.push_back( itype ); + } + } } - return nullptr; + return output; } /** @@ -4382,47 +4388,62 @@ static void reload_furniture( Character &you, const tripoint &examp, bool allow_ map &here = get_map(); const furn_t &f = here.furn( examp ).obj(); const itype *pseudo_type = f.crafting_pseudo_item_type(); - const itype *ammo = f.crafting_ammo_item_type(); + const std::vector ammo_list = f.crafting_ammo_item_types(); bool use_ammotype = f.has_flag( ter_furn_flag::TFLAG_AMMOTYPE_RELOAD ); - if( pseudo_type == nullptr || ammo == nullptr || !ammo->ammo ) { + auto can_be_reloaded = []( const std::vector &lst ) { + for( const itype *atype : lst ) { + if( atype != nullptr && atype->ammo ) { + return true; + } + } + return false; + }; + if( pseudo_type == nullptr || !can_be_reloaded( ammo_list ) ) { add_msg( m_info, _( "This %s can not be reloaded!" ), f.name() ); return; } - itype_id ammo_itypeID( ammo->get_id() ); - int amount_in_furn = use_ammotype ? + const itype *ammo_loaded = nullptr; + int amount_in_furn = 0; + for( const itype *ammo : ammo_list ) { + itype_id ammo_itypeID( ammo->get_id() ); + int amount_tmp = use_ammotype ? count_charges_in_list( &ammo->ammo->type, here.i_at( examp ), ammo_itypeID ) : count_charges_in_list( ammo, here.i_at( examp ) ); - if( allow_unload && amount_in_furn > 0 ) { - if( you.query_yn( _( "The %1$s contains %2$d %3$s. Unload?" ), f.name(), amount_in_furn, - ammo_itypeID->nname( amount_in_furn ) ) ) { - map_stack items = here.i_at( examp ); - for( map_stack::iterator itm = items.begin(); itm != items.end(); ) { - if( itm->typeId() == ammo_itypeID ) { - if( you.can_stash( *itm ) ) { - std::vector target_items{ item_location( map_cursor( examp ), &*itm ) }; - you.assign_activity( pickup_activity_actor( target_items, { 0 }, you.pos(), false ) ); - return; + if( allow_unload && amount_tmp > 0 ) { + ammo_loaded = ammo; + amount_in_furn = amount_tmp; + if( you.query_yn( _( "The %1$s contains %2$d %3$s. Unload?" ), f.name(), amount_in_furn, + ammo_itypeID->nname( amount_in_furn ) ) ) { + map_stack items = here.i_at( examp ); + for( map_stack::iterator itm = items.begin(); itm != items.end(); ) { + if( itm->typeId() == ammo_itypeID ) { + if( you.can_stash( *itm ) ) { + std::vector target_items{ item_location( map_cursor( examp ), &*itm ) }; + you.assign_activity( pickup_activity_actor( target_items, { 0 }, you.pos(), false ) ); + return; + } else { + // get handling cost before the item reference is invalidated + const int handling_cost = -you.item_handling_cost( *itm ); + + add_msg( _( "You remove %1$s from the %2$s." ), itm->tname(), f.name() ); + here.add_item_or_charges( you.pos(), *itm ); + itm = items.erase( itm ); + you.mod_moves( handling_cost ); + return; + } } else { - // get handling cost before the item reference is invalidated - const int handling_cost = -you.item_handling_cost( *itm ); - - add_msg( _( "You remove %1$s from the %2$s." ), itm->tname(), f.name() ); - here.add_item_or_charges( you.pos(), *itm ); - itm = items.erase( itm ); - you.mod_moves( handling_cost ); - return; + itm++; } - } else { - itm++; } } } } - - const int max_amount_in_furn = item( pseudo_type ).ammo_capacity( ammo->ammo->type ); - const int max_reload_amount = max_amount_in_furn - amount_in_furn; - if( max_reload_amount <= 0 ) { - return; + if( ammo_loaded ) { + const int max_amount_in_furn = item( pseudo_type ).ammo_capacity( ammo_loaded->ammo->type ); + if( amount_in_furn >= max_amount_in_furn ) { + add_msg( m_info, _( "The %s is full, cannot reload." ), f.name() ); + return; + } } item pseudo( pseudo_type ); // maybe at some point we need a pseudo item_location or something @@ -4450,6 +4471,13 @@ static void reload_furniture( Character &you, const tripoint &examp, bool allow_ if( !opt ) { return; } + + if( ammo_loaded && opt.ammo->type != ammo_loaded ) { + add_msg( m_info, _( "This %s is already loaded with %s!" ), f.name(), ammo_loaded->nname( 0 ) ); + return; + } + const int max_reload_amount = item( pseudo_type ).ammo_capacity( + opt.ammo->ammo_type() ) - amount_in_furn; const itype *opt_type = opt.ammo->type; const int max_amount = std::min( opt.qty(), max_reload_amount ); const std::string popupmsg = string_format( _( "Put how many of the %1$s into the %2$s?" ), @@ -6423,7 +6451,7 @@ void iexamine::smoker_options( Character &you, const tripoint &examp ) const furn_t &f = here.furn( examp ).obj(); const itype *type = f.crafting_pseudo_item_type(); - const itype *ammo = f.crafting_ammo_item_type(); + std::vector ammo_list = f.crafting_ammo_item_types(); const bool empty = f_volume == 0_ml; const bool full = f_volume >= sm_rack::MAX_FOOD_VOLUME; const bool full_portable = f_volume >= sm_rack::MAX_FOOD_VOLUME_PORTABLE; @@ -6432,8 +6460,8 @@ void iexamine::smoker_options( Character &you, const tripoint &examp ) const bool has_coal_in_inventory = you.crafting_inventory().charges_of( itype_charcoal ) > 0; const int coal_charges = count_charges_in_list( item::find_type( itype_charcoal ), items_here ); const int need_charges = get_charcoal_charges( f_volume ); - const int max_charges = type == nullptr || ammo == nullptr || - !ammo->ammo ? 0 : item( type ).ammo_capacity( ammo->ammo->type ); + const int max_charges = type == nullptr || ammo_list.empty() || + !ammo_list[0]->ammo ? 0 : item( type ).ammo_capacity( ammo_list[0]->ammo->type ); const bool has_coal = coal_charges > 0; const bool has_enough_coal = coal_charges >= need_charges; diff --git a/src/inventory.cpp b/src/inventory.cpp index b62ae9b46b25c..32dfb57edd328 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -535,20 +535,24 @@ void inventory::form_from_map( map &m, std::vector pts, const Characte } 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(); - if( furn_item->has_pocket_type( pocket_type::MAGAZINE ) ) { - // NOTE: This only works if the pseudo item has a MAGAZINE pocket, not a MAGAZINE_WELL! - const bool using_ammotype = f.has_flag( ter_furn_flag::TFLAG_AMMOTYPE_RELOAD ); - int amount = 0; - itype_id ammo_id = ammo->get_id(); - // Some furniture can consume more than one item type. - if( using_ammotype ) { - amount = count_charges_in_list( &ammo->ammo->type, m.i_at( p ), ammo_id ); - } else { - amount = count_charges_in_list( ammo, m.i_at( p ) ); + for( const itype *ammo : f.crafting_ammo_item_types() ) { + if( furn_item->has_pocket_type( pocket_type::MAGAZINE ) ) { + // NOTE: This only works if the pseudo item has a MAGAZINE pocket, not a MAGAZINE_WELL! + const bool using_ammotype = f.has_flag( ter_furn_flag::TFLAG_AMMOTYPE_RELOAD ); + int amount = 0; + itype_id ammo_id = ammo->get_id(); + // Some furniture can consume more than one item type. + // This might be redundant now that we iterate over the ammotypes. + if( using_ammotype ) { + amount = count_charges_in_list( &ammo->ammo->type, m.i_at( p ), ammo_id ); + } else { + amount = count_charges_in_list( ammo, m.i_at( p ) ); + } + if( amount > 0 ) { + item furn_ammo( ammo_id, calendar::turn, amount ); + furn_item->put_in( furn_ammo, pocket_type::MAGAZINE ); + } } - item furn_ammo( ammo_id, calendar::turn, amount ); - furn_item->put_in( furn_ammo, pocket_type::MAGAZINE ); } } if( m.accessible_items( p ) ) { diff --git a/src/map.cpp b/src/map.cpp index 5b8fdfc4e48d3..38d70ff03ce08 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -5917,28 +5917,30 @@ static void use_charges_from_furn( const furn_t &f, const itype_id &type, int &q const itype *itt = f.crafting_pseudo_item_type(); if( itt != nullptr && itt->tool && !itt->tool->ammo_id.empty() ) { - const itype_id ammo = ammotype( *itt->tool->ammo_id.begin() )->default_ammotype(); const bool using_ammotype = f.has_flag( ter_furn_flag::TFLAG_AMMOTYPE_RELOAD ); map_stack stack = m->i_at( p ); - auto iter = std::find_if( stack.begin(), stack.end(), - [ammo, using_ammotype]( const item & i ) { - if( using_ammotype && i.type->ammo && ammo->ammo ) { - return i.type->ammo->type == ammo->ammo->type; - } else { - return i.typeId() == ammo; - } - } ); - if( iter != stack.end() ) { - item furn_item( itt, calendar::turn_zero ); - furn_item.ammo_set( ammo, iter->charges ); + for( const itype *ammo_itype : f.crafting_ammo_item_types() ) { + itype_id ammo = ammo_itype->get_id(); + auto iter = std::find_if( stack.begin(), stack.end(), + [ammo, using_ammotype]( const item & i ) { + if( using_ammotype && i.type->ammo && ammo->ammo ) { + return i.type->ammo->type == ammo->ammo->type; + } else { + return i.typeId() == ammo; + } + } ); + if( iter != stack.end() ) { + item furn_item( itt, calendar::turn_zero ); + furn_item.ammo_set( ammo, iter->charges ); - if( !filter( furn_item ) ) { - return; - } - if( furn_item.use_charges( type, quantity, ret, p, return_true, nullptr, in_tools ) ) { - stack.erase( iter ); - } else { - iter->charges = furn_item.ammo_remaining(); + if( !filter( furn_item ) ) { + return; + } + if( furn_item.use_charges( type, quantity, ret, p, return_true, nullptr, in_tools ) ) { + stack.erase( iter ); + } else { + iter->charges = furn_item.ammo_remaining(); + } } } } diff --git a/src/mapdata.h b/src/mapdata.h index fa3d44da61fe8..267b1c91aaaad 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -662,8 +662,8 @@ struct furn_t : map_data_common_t { // May return NULL const itype *crafting_pseudo_item_type() const; - // May return NULL - const itype *crafting_ammo_item_type() const; + // May return an empty container if no valid ammotype + std::vector crafting_ammo_item_types() const; furn_t();