From d2b4de66842f394a4405ae68639a78523ca486a7 Mon Sep 17 00:00:00 2001 From: Oren Audeles Date: Sat, 7 Oct 2023 09:05:43 -0500 Subject: [PATCH 1/3] fix: drop if overencumbered, not just overvolume --- src/character.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/character.cpp b/src/character.cpp index 0c67917c7343..5688113d69cb 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3208,6 +3208,51 @@ ret_val Character::can_swap( const item &it ) const return ret_val::make_success(); } +// pretty much the same as inventory::remove_randomly_by_volume but I didn't see a point in +// adding it to the inventory class when it's only called here in Character::drop_invalid_inventory +std::list remove_randomly_by_weight( inventory &, const units::mass & ); +std::list remove_randomly_by_weight( inventory &inv, const units::mass &weight ) { + std::list result; + struct entry { + decltype( inv.slice().begin() ) stack; + decltype( (*stack)->begin() ) stack_it; + }; + std::vector vals; + + auto slice = inv.slice(); + size_t ndx = 0; + for( auto stack = slice.begin(); stack != slice.end(); ++stack ) { + for( auto stack_it = (*stack)->begin(); stack_it != (*stack)->end(); ++stack_it ) { + vals.push_back( { stack, stack_it } ); + } + ++ndx; + } + // shuffle the vector + std::shuffle( vals.begin(), vals.end(), rng_get_engine() ); + // iterate through until we have dropped enough items + auto dropped_weight = 0_gram; + for( auto &e : vals ) { + if( dropped_weight >= weight ) { + break; + } + dropped_weight += e.stack_it->weight(); + result.push_back( std::move( *e.stack_it ) ); + e.stack_it = (*e.stack)->erase( e.stack_it ); + if( e.stack_it == (*e.stack)->begin() && !(*e.stack)->empty() ) { + e.stack_it->invlet = result.back().invlet; + } + } + // iterate through items again so that we can remove any empty groups + ndx = slice.size() - 1; + for( auto stack = slice.rbegin(); stack != slice.rend(); ++stack ) { + if( (*stack)->empty() ) { + inv.reduce_stack( ndx, -1 ); + } + --ndx; + } + return result; +} + void Character::drop_invalid_inventory() { bool dropped_liquid = false; @@ -3228,6 +3273,13 @@ void Character::drop_invalid_inventory() auto items_to_drop = inv.remove_randomly_by_volume( volume_carried() - volume_capacity() ); put_into_vehicle_or_drop( *this, item_drop_reason::tumbling, items_to_drop ); } + // Also drop excess weight + auto wt_carried = weight_carried(); + auto wt_capacity = weight_capacity(); + if( wt_carried > wt_capacity ) { + auto items_to_drop = remove_randomly_by_weight( inv, wt_carried - wt_capacity ); + put_into_vehicle_or_drop( *this, item_drop_reason::too_heavy, items_to_drop ); + } } bool Character::has_artifact_with( const art_effect_passive effect ) const From b9438a2f211b3ec3d4dac60c51385d37b005e3c4 Mon Sep 17 00:00:00 2001 From: Oren Audeles Date: Sat, 7 Oct 2023 09:08:17 -0500 Subject: [PATCH 2/3] fix: don't delete inventory if restock count = 0 --- src/npc.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/npc.cpp b/src/npc.cpp index 066eaf989b50..de70627488ec 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -42,6 +42,7 @@ #include "magic.h" #include "map.h" #include "map_iterator.h" +#include "map_selector.h" #include "mapdata.h" #include "math_defines.h" #include "messages.h" @@ -1708,9 +1709,26 @@ void npc::shop_restock() } } - has_new_items = true; - inv.clear(); - inv.push_back( ret ); + // we have items to restock with, so go ahead and pick up everything so we can clear out properly + // If we don't restock for some reason don't clear out inventory since we'd end up not having anything + // to trade + if( !ret.empty() ) { + // Pick up nearby items as a free action since we'll be immediately deleting these items + const auto pickup_item_filter = [this]( const item &it ) -> bool { + return it.is_owned_by( *this ); + }; + auto old_moves = moves; + for( map_cursor &cursor : map_selector( pos(), PICKUP_RANGE ) ) { + auto pickups = cursor.remove_items_with( pickup_item_filter ); + inv.push_back( pickups ); + } + set_moves( old_moves ); + + // clear out inventory and add in restocked items + has_new_items = true; + inv.clear(); + inv.push_back( ret ); + } } int npc::minimum_item_value() const From cc055ecccc5e1214967d694edfba02040735980d Mon Sep 17 00:00:00 2001 From: Oren Audeles Date: Sat, 7 Oct 2023 09:24:02 -0500 Subject: [PATCH 3/3] astyle --- src/character.cpp | 13 +++++++------ src/npc.cpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/character.cpp b/src/character.cpp index 5688113d69cb..bd45d51f23a9 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3211,18 +3211,19 @@ ret_val Character::can_swap( const item &it ) const // pretty much the same as inventory::remove_randomly_by_volume but I didn't see a point in // adding it to the inventory class when it's only called here in Character::drop_invalid_inventory std::list remove_randomly_by_weight( inventory &, const units::mass & ); -std::list remove_randomly_by_weight( inventory &inv, const units::mass &weight ) { +std::list remove_randomly_by_weight( inventory &inv, const units::mass &weight ) +{ std::list result; struct entry { decltype( inv.slice().begin() ) stack; - decltype( (*stack)->begin() ) stack_it; + decltype( ( *stack )->begin() ) stack_it; }; std::vector vals; auto slice = inv.slice(); size_t ndx = 0; for( auto stack = slice.begin(); stack != slice.end(); ++stack ) { - for( auto stack_it = (*stack)->begin(); stack_it != (*stack)->end(); ++stack_it ) { + for( auto stack_it = ( *stack )->begin(); stack_it != ( *stack )->end(); ++stack_it ) { vals.push_back( { stack, stack_it } ); } ++ndx; @@ -3237,15 +3238,15 @@ std::list remove_randomly_by_weight( inventory &inv, const units::mass &we } dropped_weight += e.stack_it->weight(); result.push_back( std::move( *e.stack_it ) ); - e.stack_it = (*e.stack)->erase( e.stack_it ); - if( e.stack_it == (*e.stack)->begin() && !(*e.stack)->empty() ) { + e.stack_it = ( *e.stack )->erase( e.stack_it ); + if( e.stack_it == ( *e.stack )->begin() && !( *e.stack )->empty() ) { e.stack_it->invlet = result.back().invlet; } } // iterate through items again so that we can remove any empty groups ndx = slice.size() - 1; for( auto stack = slice.rbegin(); stack != slice.rend(); ++stack ) { - if( (*stack)->empty() ) { + if( ( *stack )->empty() ) { inv.reduce_stack( ndx, -1 ); } --ndx; diff --git a/src/npc.cpp b/src/npc.cpp index de70627488ec..c47292f82cdf 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1714,7 +1714,7 @@ void npc::shop_restock() // to trade if( !ret.empty() ) { // Pick up nearby items as a free action since we'll be immediately deleting these items - const auto pickup_item_filter = [this]( const item &it ) -> bool { + const auto pickup_item_filter = [this]( const item & it ) -> bool { return it.is_owned_by( *this ); }; auto old_moves = moves;