1 #include "item_location.h"
2 
3 #include <algorithm>
4 #include <cstddef>
5 #include <functional>
6 #include <iosfwd>
7 #include <iterator>
8 #include <list>
9 #include <string>
10 #include <vector>
11 
12 #include "character.h"
13 #include "character_id.h"
14 #include "color.h"
15 #include "debug.h"
16 #include "game.h"
17 #include "game_constants.h"
18 #include "item.h"
19 #include "item_contents.h"
20 #include "item_pocket.h"
21 #include "json.h"
22 #include "line.h"
23 #include "map.h"
24 #include "map_selector.h"
25 #include "optional.h"
26 #include "point.h"
27 #include "ret_val.h"
28 #include "safe_reference.h"
29 #include "string_formatter.h"
30 #include "translations.h"
31 #include "units.h"
32 #include "vehicle.h"
33 #include "vehicle_selector.h"
34 #include "visitable.h"
35 #include "vpart_position.h"
36 
37 template <typename T>
find_index(const T & sel,const item * obj)38 static int find_index( const T &sel, const item *obj )
39 {
40     int idx = -1;
41     sel.visit_items( [&idx, &obj]( const item * e, item * ) {
42         idx++;
43         if( e == obj ) {
44             return VisitResponse::ABORT;
45         }
46         return VisitResponse::NEXT;
47     } );
48     return idx;
49 }
50 
51 template <typename T>
retrieve_index(const T & sel,int idx)52 static item *retrieve_index( const T &sel, int idx )
53 {
54     item *obj = nullptr;
55     sel.visit_items( [&idx, &obj]( const item * e, item * ) {
56         if( idx-- == 0 ) {
57             obj = const_cast<item *>( e );
58             return VisitResponse::ABORT;
59         }
60         return VisitResponse::NEXT;
61     } );
62     return obj;
63 }
64 
65 class item_location::impl
66 {
67     public:
68         class item_in_container;
69         class item_on_map;
70         class item_on_person;
71         class item_on_vehicle;
72         class nowhere;
73 
74         impl() = default;
impl(item * i)75         explicit impl( item *i ) : what( i->get_safe_reference() ) {}
impl(int idx)76         explicit impl( int idx ) : idx( idx ), needs_unpacking( true ) {}
77 
78         virtual ~impl() = default;
79 
80         virtual type where() const = 0;
where_recursive() const81         virtual type where_recursive() const {
82             return where();
83         }
parent_item() const84         virtual item_location parent_item() const {
85             return item_location();
86         }
87         virtual tripoint position() const = 0;
88         virtual std::string describe( const Character * ) const = 0;
89         virtual item_location obtain( Character &, int ) = 0;
90         virtual units::volume volume_capacity() const = 0;
91         virtual units::mass weight_capacity() const = 0;
92         virtual int obtain_cost( const Character &, int ) const = 0;
93         virtual void remove_item() = 0;
94         virtual void on_contents_changed() = 0;
95         virtual void serialize( JsonOut &js ) const = 0;
96         virtual item *unpack( int ) const = 0;
97 
target() const98         item *target() const {
99             ensure_unpacked();
100             return what.get();
101         }
102 
valid() const103         virtual bool valid() const {
104             ensure_unpacked();
105             return !!what;
106         }
107 
108     private:
ensure_unpacked() const109         void ensure_unpacked() const {
110             if( needs_unpacking ) {
111                 if( item *i = unpack( idx ) ) {
112                     what = i->get_safe_reference();
113                 } else {
114                     debugmsg( "item_location lost its target item during a save/load cycle" );
115                 }
116                 needs_unpacking = false;
117             }
118         }
119         mutable safe_reference<item> what;
120         mutable int idx = -1;
121         mutable bool needs_unpacking = false;
122 
123     public:
124         //Flag that controls whether functions like obtain() should stack the obtained item
125         //with similar existing items in the inventory or create a new stack for the item
126         bool should_stack = true;
127 };
128 
129 class item_location::impl::nowhere : public item_location::impl
130 {
131     public:
where() const132         type where() const override {
133             return type::invalid;
134         }
135 
position() const136         tripoint position() const override {
137             debugmsg( "invalid use of nowhere item_location" );
138             return tripoint_min;
139         }
140 
describe(const Character *) const141         std::string describe( const Character * ) const override {
142             debugmsg( "invalid use of nowhere item_location" );
143             return "";
144         }
145 
obtain(Character &,int)146         item_location obtain( Character &, int ) override {
147             debugmsg( "invalid use of nowhere item_location" );
148             return item_location();
149         }
150 
obtain_cost(const Character &,int) const151         int obtain_cost( const Character &, int ) const override {
152             debugmsg( "invalid use of nowhere item_location" );
153             return 0;
154         }
155 
remove_item()156         void remove_item() override {
157             debugmsg( "invalid use of nowhere item_location" );
158         }
159 
on_contents_changed()160         void on_contents_changed() override {
161             debugmsg( "invalid use of nowhere item_location" );
162         }
163 
unpack(int) const164         item *unpack( int ) const override {
165             return nullptr;
166         }
167 
serialize(JsonOut & js) const168         void serialize( JsonOut &js ) const override {
169             js.start_object();
170             js.member( "type", "null" );
171             js.end_object();
172         }
173 
volume_capacity() const174         units::volume volume_capacity() const override {
175             return units::volume();
176         }
177 
weight_capacity() const178         units::mass weight_capacity() const override {
179             return units::mass();
180         }
181 };
182 
183 class item_location::impl::item_on_map : public item_location::impl
184 {
185     private:
186         map_cursor cur;
187 
188     public:
item_on_map(const map_cursor & cur,item * which)189         item_on_map( const map_cursor &cur, item *which ) : impl( which ), cur( cur ) {}
item_on_map(const map_cursor & cur,int idx)190         item_on_map( const map_cursor &cur, int idx ) : impl( idx ), cur( cur ) {}
191 
serialize(JsonOut & js) const192         void serialize( JsonOut &js ) const override {
193             js.start_object();
194             js.member( "type", "map" );
195             js.member( "pos", position() );
196             js.member( "idx", find_index( cur, target() ) );
197             js.end_object();
198         }
199 
unpack(int idx) const200         item *unpack( int idx ) const override {
201             return retrieve_index( cur, idx );
202         }
203 
where() const204         type where() const override {
205             return type::map;
206         }
207 
position() const208         tripoint position() const override {
209             return cur.pos();
210         }
211 
describe(const Character * ch) const212         std::string describe( const Character *ch ) const override {
213             std::string res = get_map().name( cur.pos() );
214             if( ch ) {
215                 res += std::string( " " ) += direction_suffix( ch->pos(), cur.pos() );
216             }
217             return res;
218         }
219 
obtain(Character & ch,int qty)220         item_location obtain( Character &ch, int qty ) override {
221             ch.moves -= obtain_cost( ch, qty );
222 
223             on_contents_changed();
224             item obj = target()->split( qty );
225             const auto get_local_location = []( Character & ch, item * it ) {
226                 if( ch.has_item( *it ) ) {
227                     return item_location( ch, it );
228                 } else {
229                     return item_location{};
230                 }
231             };
232             if( !obj.is_null() ) {
233                 return get_local_location( ch, &ch.i_add( obj, should_stack ) );
234             } else {
235                 item *inv = &ch.i_add( *target(), should_stack );
236                 remove_item();
237                 return get_local_location( ch, inv );
238             }
239         }
240 
obtain_cost(const Character & ch,int qty) const241         int obtain_cost( const Character &ch, int qty ) const override {
242             if( !target() ) {
243                 return 0;
244             }
245 
246             item obj = *target();
247             obj = obj.split( qty );
248             if( obj.is_null() ) {
249                 obj = *target();
250             }
251 
252             int mv = ch.item_handling_cost( obj, true, MAP_HANDLING_PENALTY );
253             mv += 100 * rl_dist( ch.pos(), cur.pos() );
254 
255             // TODO: handle unpacking costs
256 
257             return mv;
258         }
259 
remove_item()260         void remove_item() override {
261             on_contents_changed();
262             cur.remove_item( *what );
263         }
264 
on_contents_changed()265         void on_contents_changed() override {
266             target()->on_contents_changed();
267         }
268 
volume_capacity() const269         units::volume volume_capacity() const override {
270             map_stack stack = get_map().i_at( cur.pos() );
271             return stack.free_volume();
272         }
273 
weight_capacity() const274         units::mass weight_capacity() const override {
275             return units::mass_max;
276         }
277 };
278 
279 class item_location::impl::item_on_person : public item_location::impl
280 {
281     private:
282         character_id who_id;
283         mutable Character *who;
284 
ensure_who_unpacked() const285         bool ensure_who_unpacked() const {
286             if( !who ) {
287                 who = g->critter_by_id<Character>( who_id );
288                 if( !who ) {
289                     // If we failed to find it throw a debug message cause we're probably going to crash soon
290                     debugmsg( "Failed to find item_location owner with character_id %d", who_id.get_value() );
291                     return false;
292                 }
293             }
294             return true;
295         }
296 
297     public:
item_on_person(Character & who,item * which)298         item_on_person( Character &who, item *which ) : impl( which ) {
299             who_id = who.getID();
300             this->who = &who;
301         }
302 
item_on_person(character_id who_id,int idx)303         item_on_person( character_id who_id, int idx ) : impl( idx ), who_id( who_id ), who( nullptr ) {}
304 
serialize(JsonOut & js) const305         void serialize( JsonOut &js ) const override {
306             if( !ensure_who_unpacked() ) {
307                 // Write an invalid item_location to avoid invalid json
308                 js.start_object();
309                 js.member( "type", "null" );
310                 js.end_object();
311                 return;
312             }
313             js.start_object();
314             js.member( "type", "character" );
315             js.member( "character", who_id );
316             js.member( "idx", find_index( *who, target() ) );
317             js.end_object();
318         }
319 
unpack(int idx) const320         item *unpack( int idx ) const override {
321             if( !ensure_who_unpacked() ) {
322                 return nullptr;
323             }
324             return retrieve_index( *who, idx );
325         }
326 
where() const327         type where() const override {
328             return type::character;
329         }
330 
position() const331         tripoint position() const override {
332             if( !ensure_who_unpacked() ) {
333                 return tripoint_zero;
334             }
335             return who->pos();
336         }
337 
describe(const Character * ch) const338         std::string describe( const Character *ch ) const override {
339             if( !target() || !ensure_who_unpacked() ) {
340                 return std::string();
341             }
342 
343             if( ch == who ) {
344                 auto parents = who->parents( *target() );
345                 if( !parents.empty() && who->is_worn( *parents.back() ) ) {
346                     return parents.back()->type_name();
347 
348                 } else if( who->is_worn( *target() ) ) {
349                     return _( "worn" );
350 
351                 } else {
352                     return _( "inventory" );
353                 }
354 
355             } else {
356                 return who->name;
357             }
358         }
359 
obtain(Character & ch,int qty)360         item_location obtain( Character &ch, int qty ) override {
361             ch.mod_moves( -obtain_cost( ch, qty ) );
362 
363             on_contents_changed();
364             if( &ch.i_at( ch.get_item_position( target() ) ) == target() ) {
365                 // item already in target characters inventory at base of stack
366                 return item_location( ch, target() );
367             }
368 
369             item obj = target()->split( qty );
370             if( !obj.is_null() ) {
371                 return item_location( ch, &ch.i_add( obj, should_stack ) );
372             } else {
373                 item *inv = &ch.i_add( *target(), should_stack );
374                 remove_item();  // This also takes off the item from whoever wears it.
375                 return item_location( ch, inv );
376             }
377         }
378 
obtain_cost(const Character & ch,int qty) const379         int obtain_cost( const Character &ch, int qty ) const override {
380             if( !target() || !ensure_who_unpacked() ) {
381                 return 0;
382             }
383 
384             int mv = 0;
385 
386             item obj = *target();
387             obj = obj.split( qty );
388             if( obj.is_null() ) {
389                 obj = *target();
390             }
391 
392             item &target_ref = *target();
393             if( who->is_wielding( target_ref ) ) {
394                 mv = who->item_handling_cost( obj, false, 0 );
395             } else {
396                 // then we are wearing it
397                 mv = who->item_handling_cost( obj, true, INVENTORY_HANDLING_PENALTY / 2 );
398             }
399 
400             if( &ch != who ) {
401                 // TODO: implement movement cost for transferring item between characters
402             }
403 
404             return mv;
405         }
406 
remove_item()407         void remove_item() override {
408             if( !ensure_who_unpacked() ) {
409                 return;
410             }
411             on_contents_changed();
412             who->remove_item( *what );
413         }
414 
on_contents_changed()415         void on_contents_changed() override {
416             target()->on_contents_changed();
417         }
418 
valid() const419         bool valid() const override {
420             ensure_who_unpacked();
421             ensure_unpacked();
422             return !!what && !!who;
423         }
424 
volume_capacity() const425         units::volume volume_capacity() const override {
426             return units::volume_max;
427         }
428 
weight_capacity() const429         units::mass weight_capacity() const override {
430             return units::mass_max;
431         }
432 };
433 
434 class item_location::impl::item_on_vehicle : public item_location::impl
435 {
436     private:
437         vehicle_cursor cur;
438 
439     public:
item_on_vehicle(const vehicle_cursor & cur,item * which)440         item_on_vehicle( const vehicle_cursor &cur, item *which ) : impl( which ), cur( cur ) {}
item_on_vehicle(const vehicle_cursor & cur,int idx)441         item_on_vehicle( const vehicle_cursor &cur, int idx ) : impl( idx ), cur( cur ) {}
442 
serialize(JsonOut & js) const443         void serialize( JsonOut &js ) const override {
444             js.start_object();
445             js.member( "type", "vehicle" );
446             js.member( "pos", position() );
447             js.member( "part", cur.part );
448             if( target() != &cur.veh.part( cur.part ).base ) {
449                 js.member( "idx", find_index( cur, target() ) );
450             }
451             js.end_object();
452         }
453 
unpack(int idx) const454         item *unpack( int idx ) const override {
455             return idx >= 0 ? retrieve_index( cur, idx ) : &cur.veh.part( cur.part ).base;
456         }
457 
where() const458         type where() const override {
459             return type::vehicle;
460         }
461 
position() const462         tripoint position() const override {
463             return cur.veh.global_part_pos3( cur.part );
464         }
465 
describe(const Character * ch) const466         std::string describe( const Character *ch ) const override {
467             vpart_position part_pos( cur.veh, cur.part );
468             std::string res;
469             if( auto label = part_pos.get_label() ) {
470                 res = colorize( *label, c_light_blue ) + " ";
471             }
472             if( auto cargo_part = part_pos.part_with_feature( "CARGO", true ) ) {
473                 res += cargo_part->part().name();
474             } else {
475                 debugmsg( "item in vehicle part without cargo storage" );
476             }
477             if( ch ) {
478                 res += " " + direction_suffix( ch->pos(), part_pos.pos() );
479             }
480             return res;
481         }
482 
obtain(Character & ch,int qty)483         item_location obtain( Character &ch, int qty ) override {
484             ch.moves -= obtain_cost( ch, qty );
485 
486             on_contents_changed();
487             item obj = target()->split( qty );
488             if( !obj.is_null() ) {
489                 return item_location( ch, &ch.i_add( obj, should_stack ) );
490             } else {
491                 item *inv = &ch.i_add( *target(), should_stack );
492                 remove_item();
493                 return item_location( ch, inv );
494             }
495         }
496 
obtain_cost(const Character & ch,int qty) const497         int obtain_cost( const Character &ch, int qty ) const override {
498             if( !target() ) {
499                 return 0;
500             }
501 
502             item obj = *target();
503             obj = obj.split( qty );
504             if( obj.is_null() ) {
505                 obj = *target();
506             }
507 
508             int mv = ch.item_handling_cost( obj, true, VEHICLE_HANDLING_PENALTY );
509             mv += 100 * rl_dist( ch.pos(), cur.veh.global_part_pos3( cur.part ) );
510 
511             // TODO: handle unpacking costs
512 
513             return mv;
514         }
515 
remove_item()516         void remove_item() override {
517             on_contents_changed();
518             item &base = cur.veh.part( cur.part ).base;
519             if( &base == target() ) {
520                 cur.veh.remove_part( cur.part ); // vehicle_part::base
521             } else {
522                 cur.remove_item( *target() ); // item within CARGO
523             }
524         }
525 
on_contents_changed()526         void on_contents_changed() override {
527             target()->on_contents_changed();
528             cur.veh.invalidate_mass();
529         }
530 
volume_capacity() const531         units::volume volume_capacity() const override {
532             return cur.veh.free_volume( cur.part );
533         }
534 
weight_capacity() const535         units::mass weight_capacity() const override {
536             return units::mass_max;
537         }
538 };
539 
540 class item_location::impl::item_in_container : public item_location::impl
541 {
542     private:
543         item_location container;
544 
545         // figures out the index for the item, which is where it is in the total list of contents
546         // note: could be a better way of handling this?
calc_index() const547         int calc_index() const {
548             int idx = 0;
549             for( const item *it : container->contents.all_items_top() ) {
550                 if( target() == it ) {
551                     return idx;
552                 }
553                 idx++;
554             }
555             if( container->contents.empty() ) {
556                 return -1;
557             }
558             return idx;
559         }
560     public:
parent_item() const561         item_location parent_item() const override {
562             return container;
563         }
564 
item_in_container(const item_location & container,item * which)565         item_in_container( const item_location &container, item *which ) :
566             impl( which ), container( container ) {}
567 
serialize(JsonOut & js) const568         void serialize( JsonOut &js ) const override {
569             js.start_object();
570             js.member( "idx", calc_index() );
571             js.member( "type", "in_container" );
572             js.member( "parent", container );
573             js.end_object();
574         }
575 
unpack(int idx) const576         item *unpack( int idx ) const override {
577             if( idx < 0 || static_cast<size_t>( idx ) >= target()->contents.num_item_stacks() ) {
578                 return nullptr;
579             }
580             std::list<const item *> all_items = container->contents.all_items_ptr();
581             auto iter = all_items.begin();
582             std::advance( iter, idx );
583             if( iter != all_items.end() ) {
584                 return const_cast<item *>( *iter );
585             } else {
586                 return nullptr;
587             }
588         }
589 
describe(const Character *) const590         std::string describe( const Character * ) const override {
591             if( !target() ) {
592                 return std::string();
593             }
594             return string_format( _( "inside %s" ), container->tname() );
595         }
596 
where() const597         type where() const override {
598             return type::container;
599         }
600 
where_recursive() const601         type where_recursive() const override {
602             return container.where_recursive();
603         }
604 
position() const605         tripoint position() const override {
606             return container.position();
607         }
608 
remove_item()609         void remove_item() override {
610             on_contents_changed();
611             container->remove_item( *target() );
612         }
613 
on_contents_changed()614         void on_contents_changed() override {
615             target()->on_contents_changed();
616             container->on_contents_changed();
617         }
618 
obtain(Character & ch,const int qty)619         item_location obtain( Character &ch, const int qty ) override {
620             ch.mod_moves( -obtain_cost( ch, qty ) );
621 
622             on_contents_changed();
623             if( container.held_by( ch ) ) {
624                 // we don't need to move it in this case, it's in a pocket
625                 // we just charge the obtain cost and leave it in place. otherwise
626                 // it's liable to end up back in the same pocket, where shenanigans ensue
627                 return item_location( container, target() );
628             }
629             const item obj = target()->split( qty );
630             if( !obj.is_null() ) {
631                 return item_location( ch, &ch.i_add( obj, should_stack,
632                                                      /*avoid=*/nullptr,
633                                                      /*allow_drop=*/false ) );
634             } else {
635                 item *const inv = &ch.i_add( *target(), should_stack,
636                                              /*avoid=*/nullptr,
637                                              /*allow_drop=*/false );
638                 if( inv->is_null() ) {
639                     debugmsg( "failed to add item to character inventory while obtaining from container" );
640                 }
641                 remove_item();
642                 return item_location( ch, inv );
643             }
644         }
645 
obtain_cost(const Character & ch,int qty) const646         int obtain_cost( const Character &ch, int qty ) const override {
647             if( !target() ) {
648                 return 0;
649             }
650 
651             item obj = *target();
652             obj = obj.split( qty );
653             if( obj.is_null() ) {
654                 obj = *target();
655             }
656 
657             const int container_mv = container->contents.obtain_cost( *target() );
658             if( container_mv == 0 ) {
659                 debugmsg( "ERROR: %s does not contain %s", container->tname(), target()->tname() );
660                 return 0;
661             }
662 
663             int primary_cost = ch.mutation_value( "obtain_cost_multiplier" ) * ch.item_handling_cost( *target(),
664                                true, container_mv );
665             int parent_obtain_cost = container.obtain_cost( ch, qty );
666             if( container->get_use( "holster" ) ) {
667                 if( ch.is_worn( *container ) ) {
668                     primary_cost = ch.item_retrieve_cost( *target(), *container, false, container_mv );
669                 } else {
670                     primary_cost = ch.item_retrieve_cost( *target(), *container );
671                 }
672                 // for holsters, we should not include the cost of wielding the holster itself
673                 parent_obtain_cost = 0;
674             } else if( container.where() != item_location::type::container ) {
675                 // a little bonus for grabbing something from what you're wearing
676                 parent_obtain_cost /= 2;
677             }
678             return primary_cost + parent_obtain_cost;
679         }
680 
volume_capacity() const681         units::volume volume_capacity() const override {
682             return container->contained_where( *target() )->remaining_volume();
683         }
684 
weight_capacity() const685         units::mass weight_capacity() const override {
686             return container->contained_where( *target() )->remaining_weight();
687         }
688 };
689 
690 const item_location item_location::nowhere;
691 
item_location()692 item_location::item_location()
693     : ptr( new impl::nowhere() ) {}
694 
item_location(const map_cursor & mc,item * which)695 item_location::item_location( const map_cursor &mc, item *which )
696     : ptr( new impl::item_on_map( mc, which ) ) {}
697 
item_location(Character & ch,item * which)698 item_location::item_location( Character &ch, item *which )
699     : ptr( new impl::item_on_person( ch, which ) ) {}
700 
item_location(const vehicle_cursor & vc,item * which)701 item_location::item_location( const vehicle_cursor &vc, item *which )
702     : ptr( new impl::item_on_vehicle( vc, which ) ) {}
703 
item_location(const item_location & container,item * which)704 item_location::item_location( const item_location &container, item *which )
705     : ptr( new impl::item_in_container( container, which ) ) {}
706 
operator ==(const item_location & rhs) const707 bool item_location::operator==( const item_location &rhs ) const
708 {
709     return ptr->target() == rhs.ptr->target();
710 }
711 
operator !=(const item_location & rhs) const712 bool item_location::operator!=( const item_location &rhs ) const
713 {
714     return ptr->target() != rhs.ptr->target();
715 }
716 
operator bool() const717 item_location::operator bool() const
718 {
719     return ptr->valid();
720 }
721 
operator *()722 item &item_location::operator*()
723 {
724     return *ptr->target();
725 }
726 
operator *() const727 const item &item_location::operator*() const
728 {
729     return *ptr->target();
730 }
731 
operator ->()732 item *item_location::operator->()
733 {
734     return ptr->target();
735 }
736 
operator ->() const737 const item *item_location::operator->() const
738 {
739     return ptr->target();
740 }
741 
serialize(JsonOut & js) const742 void item_location::serialize( JsonOut &js ) const
743 {
744     ptr->serialize( js );
745 }
746 
deserialize(JsonIn & js)747 void item_location::deserialize( JsonIn &js )
748 {
749     JsonObject obj = js.get_object();
750     auto type = obj.get_string( "type" );
751 
752     int idx = -1;
753     tripoint pos = tripoint_min;
754 
755     obj.read( "idx", idx );
756     obj.read( "pos", pos );
757 
758     if( type == "character" ) {
759         character_id who_id;
760         if( obj.has_member( "character" ) ) {
761             obj.read( "character", who_id );
762         } else {
763             // This is for migrating saves before npc item locations were supported and all
764             // character item locations were assumed to be on g->u
765             who_id = get_player_character().getID();
766         }
767         ptr.reset( new impl::item_on_person( who_id, idx ) );
768 
769     } else if( type == "map" ) {
770         ptr.reset( new impl::item_on_map( map_cursor( pos ), idx ) );
771 
772     } else if( type == "vehicle" ) {
773         vehicle *const veh = veh_pointer_or_null( get_map().veh_at( pos ) );
774         int part = obj.get_int( "part" );
775         if( veh && part >= 0 && part < veh->part_count() ) {
776             ptr.reset( new impl::item_on_vehicle( vehicle_cursor( *veh, part ), idx ) );
777         }
778     } else if( type == "in_container" ) {
779         item_location parent;
780         obj.read( "parent", parent );
781         if( !parent.ptr->valid() ) {
782             debugmsg( "parent location does not point to valid item" );
783             ptr.reset( new impl::item_on_map( map_cursor( pos ), idx ) ); // drop on ground
784             return;
785         }
786         const std::list<item *> parent_contents = parent->contents.all_items_top();
787         if( idx > -1 && idx < static_cast<int>( parent_contents.size() ) ) {
788             auto iter = parent_contents.begin();
789             std::advance( iter, idx );
790             ptr.reset( new impl::item_in_container( parent, *iter ) );
791         } else {
792             // probably pointing to the wrong item
793             debugmsg( "contents index greater than contents size" );
794         }
795     }
796 }
797 
parent_item() const798 item_location item_location::parent_item() const
799 {
800     if( where() == type::container ) {
801         return ptr->parent_item();
802     }
803     debugmsg( "this item location type has no parent" );
804     return item_location::nowhere;
805 }
806 
has_parent() const807 bool item_location::has_parent() const
808 {
809     if( where() == type::container ) {
810         return !!ptr->parent_item();
811     }
812     return false;
813 }
814 
parents_can_contain_recursive(item * it) const815 bool item_location::parents_can_contain_recursive( item *it ) const
816 {
817     if( !has_parent() ) {
818         return true;
819     }
820 
821     item_location parent = parent_item();
822     item_pocket *pocket = parent->contents.contained_where( *get_item() );
823 
824     if( pocket->can_contain( *it ).success() ) {
825         return parent.parents_can_contain_recursive( it );
826     }
827 
828     return false;
829 }
830 
max_charges_by_parent_recursive(const item & it) const831 int item_location::max_charges_by_parent_recursive( const item &it ) const
832 {
833     if( !has_parent() ) {
834         return item::INFINITE_CHARGES;
835     }
836 
837     item_location parent = parent_item();
838     item_pocket *pocket = parent->contents.contained_where( *get_item() );
839 
840     return std::min( { it.charges_per_volume( pocket->remaining_volume() ),
841                        it.charges_per_weight( pocket->remaining_weight() ),
842                        pocket->rigid() ? item::INFINITE_CHARGES : parent.max_charges_by_parent_recursive( it )
843                      } );
844 }
845 
eventually_contains(item_location loc) const846 bool item_location::eventually_contains( item_location loc ) const
847 {
848     while( loc.has_parent() ) {
849         if( ( loc = loc.parent_item() ) == *this ) {
850             return true;
851         }
852     }
853     return false;
854 }
855 
where() const856 item_location::type item_location::where() const
857 {
858     return ptr->where();
859 }
860 
where_recursive() const861 item_location::type item_location::where_recursive() const
862 {
863     return ptr->where_recursive();
864 }
865 
position() const866 tripoint item_location::position() const
867 {
868     return ptr->position();
869 }
870 
describe(const Character * ch) const871 std::string item_location::describe( const Character *ch ) const
872 {
873     return ptr->describe( ch );
874 }
875 
obtain(Character & ch,int qty)876 item_location item_location::obtain( Character &ch, int qty )
877 {
878     if( !ptr->valid() ) {
879         debugmsg( "item location does not point to valid item" );
880         return item_location();
881     }
882     return ptr->obtain( ch, qty );
883 }
884 
obtain_cost(const Character & ch,int qty) const885 int item_location::obtain_cost( const Character &ch, int qty ) const
886 {
887     return ptr->obtain_cost( ch, qty );
888 }
889 
remove_item()890 void item_location::remove_item()
891 {
892     if( !ptr->valid() ) {
893         debugmsg( "item location does not point to valid item" );
894         return;
895     }
896     ptr->remove_item();
897     ptr.reset( new impl::nowhere() );
898 }
899 
on_contents_changed()900 void item_location::on_contents_changed()
901 {
902     if( !ptr->valid() ) {
903         debugmsg( "item location does not point to valid item" );
904         return;
905     }
906     ptr->on_contents_changed();
907 }
908 
get_item()909 item *item_location::get_item()
910 {
911     return ptr->target();
912 }
913 
get_item() const914 const item *item_location::get_item() const
915 {
916     return ptr->target();
917 }
918 
set_should_stack(bool should_stack) const919 void item_location::set_should_stack( bool should_stack ) const
920 {
921     ptr->should_stack = should_stack;
922 }
923 
held_by(Character & who) const924 bool item_location::held_by( Character &who ) const
925 {
926     if( where() == type::character && g->critter_at<Character>( position() ) == &who ) {
927         return true;
928     } else if( has_parent() ) {
929         return parent_item().held_by( who );
930     }
931     return false;
932 }
933 
volume_capacity() const934 units::volume item_location::volume_capacity() const
935 {
936     return ptr->volume_capacity();
937 }
938 
weight_capacity() const939 units::mass item_location::weight_capacity() const
940 {
941     return ptr->weight_capacity();
942 }
943