forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
item_contents.h
398 lines (332 loc) · 17.9 KB
/
item_contents.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
#pragma once
#ifndef CATA_SRC_ITEM_CONTENTS_H
#define CATA_SRC_ITEM_CONTENTS_H
#include <cstddef>
#include <functional>
#include <iosfwd>
#include <list>
#include <map>
#include <set>
#include <utility>
#include <vector>
#include "enums.h"
#include "item_pocket.h"
#include "optional.h"
#include "ret_val.h"
#include "type_id.h"
#include "ui.h"
#include "units_fwd.h"
#include "visitable.h"
class Character;
class JsonOut;
class item;
class item_location;
class iteminfo_query;
struct iteminfo;
struct tripoint;
class item_contents
{
public:
item_contents() = default;
// used for loading itype
explicit item_contents( const std::vector<pocket_data> &pockets );
/**
* returns an item_location and pointer to the best pocket that can contain the item @it
* checks all items contained in every pocket
* only checks CONTAINER pocket type
*/
std::pair<item_location, item_pocket *> best_pocket( const item &it, item_location &this_loc,
const item *avoid = nullptr, bool allow_sealed = false, bool ignore_settings = false,
bool nested = false, bool ignore_rigidity = false );
units::length max_containable_length( bool unrestricted_pockets_only = false ) const;
units::length min_containable_length() const;
units::volume max_containable_volume( bool unrestricted_pockets_only = false ) const;
std::set<flag_id> magazine_flag_restrictions() const;
/**
* returns whether any of the pockets contained is compatible with the specified item.
* Does not check if the item actually fits volume/weight wise
* Ignores mod, migration, corpse pockets
* @param it the item being put in
*/
ret_val<bool> is_compatible( const item &it ) const;
/**
* returns whether an item can be physically stored within these item contents.
* Fails if all pockets are MOD, CORPSE, SOFTWARE, or MIGRATION type, as they are not
* physical pockets.
* @param it the item being put in
* @param ignore_pkt_settings whether to ignore pocket autoinsert settings
*/
ret_val<bool> can_contain( const item &it, bool ignore_pkt_settings = true ) const;
ret_val<bool> can_contain_rigid( const item &it, bool ignore_pkt_settings = true ) const;
bool can_contain_liquid( bool held_or_ground ) const;
bool contains_no_solids() const;
/**
* returns whether any of the pockets can be reloaded with the specified item.
* @param ammo item to be loaded in
* @param now whether the currently contained ammo/magazine should be taken into account
*/
bool can_reload_with( const item &ammo, bool now ) const;
// Returns true if contents are empty (ignoring item mods, since they aren't contents)
bool empty() const;
// Returns true if contents are empty of everything including mods
bool empty_with_no_mods() const;
// ignores all pockets except CONTAINER pockets to check if this contents is empty.
bool empty_container() const;
// checks if CONTAINER pockets are all full
bool full( bool allow_bucket ) const;
// Checks if MAGAZINE pockets are all full
bool is_magazine_full() const;
// are any CONTAINER pockets bigger on the inside than the container's volume?
bool bigger_on_the_inside( const units::volume &container_volume ) const;
// number of pockets
size_t size() const;
private:
/** returns a list of pointers to all top-level items from pockets that match the predicate */
std::list<item *> all_items_top( const std::function<bool( item_pocket & )> &filter );
/** returns a list of pointers to all top-level items from pockets that match the predicate */
std::list<const item *> all_items_top( const std::function<bool( const item_pocket & )> &filter )
const;
public:
/** returns a list of pointers to all top-level items */
/** if unloading is true it ignores items in pockets that are flagged to not unload */
std::list<item *> all_items_top( item_pocket::pocket_type pk_type, bool unloading = false );
/** returns a list of pointers to all top-level items */
std::list<const item *> all_items_top( item_pocket::pocket_type pk_type ) const;
/** returns a list of pointers to all top-level items that are not mods */
std::list<item *> all_items_top();
/** returns a list of pointers to all top-level items that are not mods */
std::list<const item *> all_items_top() const;
/** returns a list of pointers to all visible or remembered content items that are not mods */
std::list<item *> all_known_contents();
std::list<const item *> all_known_contents() const;
/** gets all gunmods in the item */
std::vector<item *> gunmods();
/** gets all gunmods in the item */
std::vector<const item *> gunmods() const;
// checks the pockets if this speedloader is compatible
bool allows_speedloader( const itype_id &speedloader_id ) const;
std::vector<const item *> mods() const;
std::vector<const item *> softwares() const;
std::vector<item *> ebooks();
std::vector<const item *> ebooks() const;
void update_modified_pockets( const cata::optional<const pocket_data *> &mag_or_mag_well,
std::vector<const pocket_data *> container_pockets );
// all magazines compatible with any pockets.
// this only checks MAGAZINE_WELL
std::set<itype_id> magazine_compatible() const;
// returns the default magazine; assumes only one MAGAZINE_WELL. returns NULL_ID if not a magazine well or no compatible magazines.
itype_id magazine_default() const;
/**
* This function is to aid migration to using nested containers.
* The call sites of this function need to be updated to search the
* pockets of the item, or not assume there is only one pocket or item.
*/
item &legacy_front();
const item &legacy_front() const;
units::volume item_size_modifier() const;
units::mass item_weight_modifier() const;
units::length item_length_modifier() const;
// gets the total weight capacity of all pockets
units::mass total_container_weight_capacity( bool unrestricted_pockets_only = false ) const;
/**
* gets the total volume available to be used.
* does not guarantee that an item of that size can be inserted.
*/
units::volume total_container_capacity( bool unrestricted_pockets_only = false ) const;
// Gets the total volume of every is_standard_type container
units::volume total_standard_capacity( bool unrestricted_pockets_only = false ) const;
units::volume remaining_container_capacity( bool unrestricted_pockets_only = false ) const;
units::volume total_contained_volume( bool unrestricted_pockets_only = false ) const;
units::mass remaining_container_capacity_weight( bool unrestricted_pockets_only = false ) const;
units::mass total_contained_weight( bool unrestricted_pockets_only = false ) const;
units::volume get_contents_volume_with_tweaks( const std::map<const item *, int> &without ) const;
units::volume get_nested_content_volume_recursive( const std::map<const item *, int> &without )
const;
// get all holsters
int get_used_holsters() const;
int get_total_holsters() const;
units::volume get_total_holster_volume() const;
units::volume get_used_holster_volume() const;
// gets all CONTAINER pockets contained in this item
std::vector<const item_pocket *> get_all_contained_pockets() const;
std::vector<item_pocket *> get_all_contained_pockets();
std::vector<const item_pocket *> get_all_standard_pockets() const;
std::vector<item_pocket *> get_all_standard_pockets();
std::vector<const item_pocket *>
get_pockets( std::function<bool( item_pocket const & )> const &filter ) const;
std::vector<item_pocket *>
get_pockets( std::function<bool( item_pocket const & )> const &filter );
// called when adding an item as pockets
// to a molle item
void add_pocket( const item &pocket );
// called when removing a molle pocket
// needs the index of the pocket in both
// related vectors
// returns the item that was attached
item remove_pocket( int index );
// retrieves the pocket in contents corresponding to the added pocket item
const item_pocket *get_added_pocket( int index ) const;
std::vector<const item *> get_added_pockets() const;
bool has_additional_pockets() const;
int get_additional_pocket_encumbrance( float mod ) const;
int get_additional_space_used() const;
units::mass get_additional_weight() const;
units::volume get_additional_volume() const;
// Gets all CONTAINER/MAGAZINE/MAGAZINE WELL pockets in this item
std::vector<const item_pocket *> get_all_reloadable_pockets() const;
// gets the number of charges of liquid that can fit into the rest of the space
int remaining_capacity_for_liquid( const item &liquid ) const;
/** If contents should contribute to encumbrance, returns a value
* between 0 and 1 indicating the position between minimum and maximum
* contribution it's currently making. Otherwise, return 0 */
float relative_encumbrance() const;
/** True if every pocket is rigid or we have no pockets */
bool all_pockets_rigid() const;
/** returns the best quality of the id that's contained in the item in CONTAINER pockets */
int best_quality( const quality_id &id ) const;
// what will the move cost be of taking @it out of this container?
// should only be used from item_location if possible, to account for
// player inventory handling penalties from traits
int obtain_cost( const item &it ) const;
// what will the move cost be of storing @it into this container? (CONTAINER pocket type)
int insert_cost( const item &it ) const;
/**
* Attempts to insert an item into these item contents, stipulating that it must go into a
* pocket of the given type. Fails if the contents have no pocket with that type.
*
* With CONTAINER, MAGAZINE, or MAGAZINE_WELL pocket types, items must fit the pocket's
* volume, length, weight, ammo type, and all other physical restrictions. This is
* synonymous with the success of item_contents::can_contain with that item.
*
* For the MOD, CORPSE, SOFTWARE, and MIGRATION pocket types, if contents have such a
* pocket, items will be successfully inserted without regard to volume, length, or any
* other restrictions, since these pockets are not considered to be normal "containers".
*/
ret_val<item_pocket *> insert_item( const item &it, item_pocket::pocket_type pk_type );
void force_insert_item( const item &it, item_pocket::pocket_type pk_type );
bool can_unload_liquid() const;
/**
* returns the number of items stacks in contents
* each item that is not count_by_charges,
* plus whole stacks of items that are
*/
size_t num_item_stacks() const;
/**
* Open a menu for the player to set pocket favorite settings for the pockets in this item_contents
*/
void favorite_settings_menu( item *i );
item_pocket *contained_where( const item &contained );
void on_pickup( Character &guy );
bool spill_contents( const tripoint &pos );
// spill items that don't fit in the container
void overflow( const tripoint &pos );
void clear_items();
// clears all items from magazine type pockets
void clear_magazines();
void update_open_pockets();
/**
* Sets the items contained to their defaults.
*/
void set_item_defaults();
// returns true if any pocket was sealed
bool seal_all_pockets();
bool all_pockets_sealed() const;
bool any_pockets_sealed() const;
// heats up the contents if they have temperature
void heat_up();
// returns amount of ammo consumed
int ammo_consume( int qty, const tripoint &pos );
item *magazine_current();
std::set<ammotype> ammo_types() const;
int ammo_capacity( const ammotype &ammo ) const;
// gets the first ammo in all magazine pockets
// does not support multiple magazine pockets!
item &first_ammo();
// gets the first ammo in all magazine pockets
// does not support multiple magazine pockets!
const item &first_ammo() const;
// spills liquid and other contents from the container. contents may remain
// in the container if the player cancels spilling. removing liquid from
// a magazine requires unload logic.
void handle_liquid_or_spill( Character &guy, const item *avoid = nullptr );
// returns true if any of the pockets will spill if placed into a pocket
bool will_spill() const;
bool will_spill_if_unsealed() const;
bool spill_open_pockets( Character &guy, const item *avoid = nullptr );
void casings_handle( const std::function<bool( item & )> &func );
// gets the item contained IFF one item is contained (CONTAINER pocket), otherwise a null item reference
item &only_item();
const item &only_item() const;
item *get_item_with( const std::function<bool( const item & )> &filter );
void remove_items_if( const std::function<bool( item & )> &filter );
// whether the contents has a pocket with the associated type
bool has_pocket_type( item_pocket::pocket_type pk_type ) const;
bool has_unrestricted_pockets() const;
bool has_any_with( const std::function<bool( const item & )> &filter,
item_pocket::pocket_type pk_type ) const;
/**
* Is part of the recursive call of item::process. see that function for additional comments
* NOTE: this destroys the items that get processed
*/
void process( map &here, Character *carrier, const tripoint &pos, float insulation = 1,
temperature_flag flag = temperature_flag::NORMAL, float spoil_multiplier_parent = 1.0f );
bool item_has_uses_recursive() const;
bool stacks_with( const item_contents &rhs ) const;
bool same_contents( const item_contents &rhs ) const;
// can this item be used as a funnel?
bool is_funnel_container( units::volume &bigger_than ) const;
// the container has restrictions
bool is_restricted_container() const;
bool is_single_restricted_container() const;
/**
* @relates visitable
* NOTE: upon expansion, this may need to be filtered by type enum depending on accessibility
*/
VisitResponse visit_contents( const std::function<VisitResponse( item *, item * )> &func,
item *parent = nullptr );
void remove_internal( const std::function<bool( item & )> &filter,
int &count, std::list<item> &res );
void info( std::vector<iteminfo> &info, const iteminfo_query *parts ) const;
// reads the items in the MOD pocket first
void read_mods( const item_contents &read_input );
void combine( const item_contents &read_input, bool convert = false );
void serialize( JsonOut &json ) const;
void deserialize( const JsonObject &data );
private:
// finds the pocket the item will fit in, given the pocket type.
// this will be where the algorithm picks the best pocket in the contents
// returns nullptr if none is found
ret_val<item_pocket *> find_pocket_for( const item &it,
item_pocket::pocket_type pk_type = item_pocket::pocket_type::CONTAINER );
ret_val<const item_pocket *> find_pocket_for( const item &it,
item_pocket::pocket_type pk_type = item_pocket::pocket_type::CONTAINER ) const;
std::list<item_pocket> contents;
// pockets that have been custom added
std::vector<item> additional_pockets;
// TODO make this work with non torso items
units::volume additional_pockets_volume = 0_ml; // NOLINT(cata-serialize)
// an abstraction for how many 'spaces' of this item have been used attaching additional pockets
int additional_pockets_space_used = 0; // NOLINT(cata-serialize)
struct item_contents_helper;
friend struct item_contents_helper;
};
class pocket_favorite_callback : public uilist_callback
{
private:
std::vector<std::tuple<item_pocket *, int, uilist_entry *>> saved_pockets;
// whitelist or blacklist, for interactions
bool whitelist = true;
std::pair<item *, item_pocket *> item_to_move = { nullptr, nullptr };
bool needs_to_refresh = false;
// items to create pockets for
std::vector<item *> to_organize;
void move_item( uilist *menu, item_pocket *selected_pocket );
void refresh_columns( uilist *menu );
void add_pockets( item &i, uilist &pocket_selector, std::string depth );
public:
explicit pocket_favorite_callback( std::vector<item *> to_organize, uilist &pocket_selector );
void refresh( uilist *menu ) override;
bool key( const input_context &, const input_event &event, int entnum, uilist *menu ) override;
const std::string title = _( "Modify pocket settings and move items between pockets.\n" );
};
#endif // CATA_SRC_ITEM_CONTENTS_H