Skip to content

Commit

Permalink
create new item_location::item_in_container
Browse files Browse the repository at this point in the history
  • Loading branch information
KorGgenT committed Apr 9, 2020
1 parent 023e222 commit 4c2e1c4
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8569,6 +8569,11 @@ void game::wield( item_location &loc )
loc.remove_item();
if( !u.wield( to_wield ) ) {
switch( location_type ) {
case item_location::type::container:
// this will not cause things to spill, as it is inside another item
loc = loc.obtain( g->u );
wield( loc );
break;
case item_location::type::character:
if( worn_index != INT_MIN ) {
auto it = u.worn.begin();
Expand Down
1 change: 1 addition & 0 deletions src/handle_liquid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ static bool perform_liquid_transfer( item &liquid, const tripoint *const source_
case item_location::type::vehicle:
g->m.veh_at( target.item_loc.position() )->vehicle().make_active( target.item_loc );
break;
case item_location::type::container:
case item_location::type::character:
case item_location::type::invalid:
break;
Expand Down
22 changes: 22 additions & 0 deletions src/item_contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,28 @@ std::list<const item *> item_contents::all_items_top() const
return ret;
}

std::list<item *> item_contents::all_items_ptr()
{
std::list<item *> ret;
for( item &it : items ) {
ret.push_back( &it );
std::list<item *> inside = it.contents.all_items_ptr();
ret.insert( ret.end(), inside.begin(), inside.end() );
}
return ret;
}

std::list<const item *> item_contents::all_items_ptr() const
{
std::list<const item *> ret;
for( const item &it : items ) {
ret.push_back( &it );
std::list<const item *> inside = it.contents.all_items_ptr();
ret.insert( ret.end(), inside.begin(), inside.end() );
}
return ret;
}

std::vector<item *> item_contents::gunmods()
{
std::vector<item *> res;
Expand Down
5 changes: 5 additions & 0 deletions src/item_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class item_contents
/** returns a list of pointers to all top-level items */
std::list<const item *> all_items_top() const;

// returns a list of pointers to all items inside recursively
std::list<item *> all_items_ptr();
// returns a list of pointers to all items inside recursively
std::list<const item *> all_items_ptr() const;

/** gets all gunmods in the item */
std::vector<item *> gunmods();
/** gets all gunmods in the item */
Expand Down
114 changes: 114 additions & 0 deletions src/item_location.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class item_location::impl
class item_on_map;
class item_on_person;
class item_on_vehicle;
class item_in_container;

impl() = default;
impl( item *i ) : what( i->get_safe_reference() ), needs_unpacking( false ) {}
Expand All @@ -72,6 +73,9 @@ class item_location::impl
virtual ~impl() = default;

virtual type where() const = 0;
virtual item_location parent_item() const {
return item_location();
}
virtual tripoint position() const = 0;
virtual std::string describe( const Character * ) const = 0;
virtual item_location obtain( Character &, int ) = 0;
Expand Down Expand Up @@ -478,6 +482,97 @@ class item_location::impl::item_on_vehicle : public item_location::impl
}
};

class item_location::impl::item_in_container : public item_location::impl
{
private:
item_location container;

// figures out the index for the item, which is where it is in the total list of contents
// note: could be a better way of handling this?
int calc_index() const {
int idx = 0;
for( const item *it : container->contents.all_items_top() ) {
if( target() == it ) {
return idx;
}
idx++;
}
if( container->contents.empty() ) {
return -1;
}
return idx;
}
public:
item_location parent_item() const override {
return container;
}

item_in_container( const item_location &container, item *which ) :
impl( which ), container( container ) {}

void serialize( JsonOut &js ) const override {
js.start_object();
js.member( "idx", calc_index() );
js.member( "type", "in_container" );
js.member( "parent", container );
js.end_object();
}

item *unpack( int idx ) const override {
if( idx < 0 || static_cast<size_t>( idx ) >= target()->contents.num_item_stacks() ) {
return nullptr;
}
std::list<const item *> all_items = container->contents.all_items_ptr();
auto iter = all_items.begin();
std::advance( iter, idx );
if( iter != all_items.end() ) {
return const_cast<item *>( *iter );
} else {
return nullptr;
}
}

std::string describe( const Character * ) const override {
if( !target() ) {
return std::string();
}
return string_format( _( "inside %s" ), container->tname() );
}

type where() const override {
return type::container;
}

tripoint position() const override {
return container.position();
}

void remove_item() override {
container->remove_item( *target() );
}

item_location obtain( Character &ch, int qty ) override {
ch.mod_moves( -obtain_cost( ch, qty ) );

item obj = target()->split( qty );
if( !obj.is_null() ) {
return item_location( ch, &ch.i_add( obj, should_stack ) );
} else {
item *inv = &ch.i_add( *target(), should_stack );
remove_item();
return item_location( ch, inv );
}
}

int obtain_cost( const Character &ch, int qty ) const override {
if( !target() ) {
return 0;
}
// a temporary measure before pockets
return INVENTORY_HANDLING_PENALTY + container.obtain_cost( ch, qty );
}
};

const item_location item_location::nowhere;

item_location::item_location()
Expand All @@ -492,6 +587,9 @@ item_location::item_location( Character &ch, item *which )
item_location::item_location( const vehicle_cursor &vc, item *which )
: ptr( new impl::item_on_vehicle( vc, which ) ) {}

item_location::item_location( const item_location &container, item *which )
: ptr( new impl::item_in_container( container, which ) ) {}

bool item_location::operator==( const item_location &rhs ) const
{
return ptr->target() == rhs.ptr->target();
Expand Down Expand Up @@ -563,7 +661,23 @@ void item_location::deserialize( JsonIn &js )
if( veh && part >= 0 && part < static_cast<int>( veh->parts.size() ) ) {
ptr.reset( new impl::item_on_vehicle( vehicle_cursor( *veh, part ), idx ) );
}
} else if( type == "in_container" ) {
item_location parent;
obj.read( "parent", parent );
const std::list<item *> parent_contents = parent->contents.all_items_top();
auto iter = parent_contents.begin();
std::advance( iter, idx );
ptr.reset( new impl::item_in_container( parent, *iter ) );
}
}

item_location item_location::parent_item() const
{
if( where() == type::container ) {
return ptr->parent_item();
}
debugmsg( "this item location type has no parent" );
return item_location::nowhere;
}

item_location::type item_location::where() const
Expand Down
7 changes: 6 additions & 1 deletion src/item_location.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class item_location
invalid = 0,
character = 1,
map = 2,
vehicle = 3
vehicle = 3,
container = 4
};

item_location();
Expand All @@ -37,6 +38,7 @@ class item_location
item_location( Character &ch, item *which );
item_location( const map_cursor &mc, item *which );
item_location( const vehicle_cursor &vc, item *which );
item_location( const item_location &container, item *which );

void serialize( JsonOut &js ) const;
void deserialize( JsonIn &js );
Expand Down Expand Up @@ -85,6 +87,9 @@ class item_location

void set_should_stack( bool should_stack ) const;

/** returns the parent item, or an invalid location if it has no parent */
item_location parent_item() const;

private:
class impl;

Expand Down
26 changes: 26 additions & 0 deletions tests/item_location_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <memory>
#include <string>

#include "avatar.h"
#include "catch/catch.hpp"
#include "game.h"
#include "item.h"
Expand Down Expand Up @@ -64,3 +65,28 @@ TEST_CASE( "item_location_doesnt_return_stale_map_item", "[item][item_location]"
m.add_item( pos, item( "jeans" ) );
CHECK( !item_loc );
}

TEST_CASE( "item_in_container", "[item][item_location]" )
{
avatar &dummy = g->u;
item &backpack = dummy.i_add( item( "backpack" ) );
item jeans( "jeans" );

REQUIRE( dummy.has_item( backpack ) );

backpack.put_in( jeans );

item_location backpack_loc( dummy, & **dummy.wear( backpack ) );

REQUIRE( dummy.has_item( *backpack_loc ) );

item_location jeans_loc( backpack_loc, &jeans );

REQUIRE( backpack_loc.where() == item_location::type::character );
REQUIRE( jeans_loc.where() == item_location::type::container );

CHECK( backpack_loc.obtain_cost( dummy ) + INVENTORY_HANDLING_PENALTY == jeans_loc.obtain_cost(
dummy ) );

CHECK( jeans_loc.parent_item() == backpack_loc );
}

0 comments on commit 4c2e1c4

Please sign in to comment.