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

Backport #72703 #73688

Merged
merged 1 commit into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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 @@
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,74 +4388,96 @@
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
// but for now this should at least work as intended
item_location pseudo_loc( map_cursor( examp ), &pseudo );
std::vector<item::reload_option> ammo_list;

Check failure on line 4452 in src/iexamine.cpp

View workflow job for this annotation

GitHub Actions / Basic Build and Test (Clang 10, Ubuntu, Curses)

redefinition of 'ammo_list' with a different type: 'vector<item::reload_option>' vs 'const vector<const itype *>'
for( item_location &ammo : you.find_ammo( pseudo, false, PICKUP_RANGE ) ) {
// Only allow the same type to reload if partially loaded.
if( ( amount_in_furn > 0 || !use_ammotype ) && ammo_itypeID != ammo.get_item()->typeId() ) {

Check failure on line 4455 in src/iexamine.cpp

View workflow job for this annotation

GitHub Actions / Basic Build and Test (Clang 10, Ubuntu, Curses)

use of undeclared identifier 'ammo_itypeID'
continue;
}
if( pseudo.can_reload_with( *ammo, true ) ) {
ammo_list.emplace_back( &you, pseudo_loc, std::move( ammo ) );

Check failure on line 4459 in src/iexamine.cpp

View workflow job for this annotation

GitHub Actions / Basic Build and Test (Clang 10, Ubuntu, Curses)

no matching member function for call to 'emplace_back'
}
}

if( ammo_list.empty() ) {
//~ Reloading or restocking a piece of furniture, for example a forge.
add_msg( m_info, _( "You need some %1$s to reload this %2$s." ), ammo->nname( 2 ),

Check failure on line 4465 in src/iexamine.cpp

View workflow job for this annotation

GitHub Actions / Basic Build and Test (Clang 10, Ubuntu, Curses)

use of undeclared identifier 'ammo'
f.name() );
return;
}

item::reload_option opt = you.select_ammo( pseudo_loc, std::move( ammo_list ), f.name() );

Check failure on line 4470 in src/iexamine.cpp

View workflow job for this annotation

GitHub Actions / Basic Build and Test (Clang 10, Ubuntu, Curses)

no matching member function for call to 'select_ammo'
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 @@

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 @@
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
Loading