Skip to content

Commit

Permalink
Merge pull request #73688 from Procyonae/Backport72703
Browse files Browse the repository at this point in the history
Backport #72703
  • Loading branch information
I-am-Erk authored May 21, 2024
2 parents e932d80 + 7fc710f commit 4410096
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 80 deletions.
17 changes: 6 additions & 11 deletions data/json/items/basecamp.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 } } ]
Expand All @@ -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 } } ]
Expand All @@ -32,41 +30,38 @@
"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
},
{
"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
Expand Down
98 changes: 63 additions & 35 deletions src/iexamine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const itype *> furn_t::crafting_ammo_item_types() const
{
const itype *pseudo = crafting_pseudo_item_type();
std::vector<const itype *> 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;
}

/**
Expand Down Expand Up @@ -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<const itype *> 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<const itype *> &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<item_location> 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<item_location> 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
Expand Down Expand Up @@ -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?" ),
Expand Down Expand Up @@ -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<const itype *> 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;
Expand All @@ -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;

Expand Down
30 changes: 17 additions & 13 deletions src/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,20 +535,24 @@ void inventory::form_from_map( map &m, std::vector<tripoint> 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 ) ) {
Expand Down
40 changes: 21 additions & 19 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<item>, 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<item>, nullptr, in_tools ) ) {
stack.erase( iter );
} else {
iter->charges = furn_item.ammo_remaining();
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/mapdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<const itype *> crafting_ammo_item_types() const;

furn_t();

Expand Down

0 comments on commit 4410096

Please sign in to comment.