1 /* GemRB - Infinity Engine Emulator
2  * Copyright (C) 2003 The GemRB Project
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  *
19  */
20 
21 /**
22  * @file Inventory.h
23  * Declares Inventory, class implementing creatures' and containers'
24  * inventory and item management
25  * @author The GemRB Project
26  */
27 
28 #ifndef INVENTORY_H
29 #define INVENTORY_H
30 
31 #include "exports.h"
32 #include "ie_types.h"
33 
34 #include "Item.h"  //needs item for itmextheader
35 #include "Store.h"
36 
37 #include <vector>
38 
39 namespace GemRB {
40 
41 class Map;
42 class StringBuffer;
43 
44 //AddSlotItem return values
45 #define ASI_FAILED     0
46 #define ASI_PARTIAL    1
47 #define ASI_SUCCESS    2
48 #define ASI_SWAPPED    3 //not returned normally, but Gui uses this value
49 
50 //AddSlotItem extra slot ID's
51 #define SLOT_AUTOEQUIP     -1
52 #define SLOT_ONLYINVENTORY -3
53 
54 //slottypes (bitfield)
55 #define SLOT_HELM      1
56 #define SLOT_ARMOUR    2
57 #define SLOT_SHIELD    4
58 #define SLOT_GLOVE     8
59 #define SLOT_RING      16
60 #define SLOT_AMULET    32
61 #define SLOT_BELT      64
62 #define SLOT_BOOT      128
63 #define SLOT_WEAPON    256
64 #define SLOT_QUIVER    512
65 #define SLOT_CLOAK     1024
66 #define SLOT_ITEM      2048  //quick item
67 #define SLOT_SCROLL    4096
68 #define SLOT_BAG       8192
69 #define SLOT_POTION    16384
70 #define SLOT_ANY       32767
71 #define SLOT_INVENTORY 32768
72 #define SLOT_ALL       65535
73 
74 //weapon slot types (1000==not equipped)
75 #define IW_NO_EQUIPPED  1000
76 
77 /** Inventory types */
78 typedef enum ieInventoryType {
79 	INVENTORY_HEAP = 0,
80 	INVENTORY_CREATURE = 1
81 } ieInventoryType;
82 
83 // !!! Keep these synchronized with GUIDefines.py !!!
84 typedef enum ieCREItemFlagBits : uint32_t {
85 	IE_INV_ITEM_IDENTIFIED = 1,
86 	IE_INV_ITEM_UNSTEALABLE = 2,
87 	IE_INV_ITEM_STOLEN = 4, // denotes steel items in pst
88 	//in iwd/iwd2 this flag means 'magical', some hack is needed
89 	IE_INV_ITEM_UNDROPPABLE =8,
90 	//just recently acquired
91 	IE_INV_ITEM_ACQUIRED = 0x10,	//this is a gemrb extension
92 	//is this item destructible normally?
93 	IE_INV_ITEM_DESTRUCTIBLE = 0x20,//this is a gemrb extension
94 	//is this item already equipped?
95 	IE_INV_ITEM_EQUIPPED = 0x40,	//this is a gemrb extension
96 	//selected for sale, using the same bit, hope it is ok
97 	IE_INV_ITEM_SELECTED = 0x40,    //this is a gemrb extension
98 	//is this item stackable?
99 	IE_INV_ITEM_STACKED = 0x80,	//this is a gemrb extension
100 	//these flags are coming from the original item, but these are immutable
101 	IE_INV_ITEM_CRITICAL = 0x100, //coming from original item
102 	IE_INV_ITEM_TWOHANDED = 0x200,
103 	IE_INV_ITEM_MOVABLE = 0x400, //same as undroppable
104 	IE_INV_ITEM_RESELLABLE = 0x800, //item will appear in shop when sold
105 	IE_INV_ITEM_CURSED = 0x1000, //item is cursed
106 	IE_INV_ITEM_UNKNOWN2000 = 0x2000, //totally unknown
107 	IE_INV_ITEM_MAGICAL = 0x4000, //magical
108 	IE_INV_ITEM_BOW = 0x8000, //
109 	IE_INV_ITEM_SILVER = 0x10000,
110 	IE_INV_ITEM_COLDIRON = 0x20000,
111 	IE_INV_ITEM_STOLEN2 = 0x40000, //same as 4
112 	IE_INV_ITEM_CONVERSABLE = 0x80000,
113 	IE_INV_ITEM_PULSATING = 0x100000
114 } ieCREItemFlagBits;
115 
116 #define IE_INV_DEPLETABLE (IE_INV_ITEM_MAGICAL|IE_INV_ITEM_DESTRUCTIBLE)
117 
118 //equip flags
119 #define EQUIP_ANY   0
120 #define EQUIP_MELEE 1
121 #define EQUIP_RANGED 2
122 
123 //FIXME:
124 //actually this header shouldn't be THIS large, i was just
125 //lazy to pick the interesting elements
126 //it could be possible that some elements need to be added from the
127 //item header itself
128 struct ItemExtHeader {
129 	ieDword slot;
130 	ieDword headerindex;
131 	//from itmextheader
132 	ieByte AttackType;
133 	ieByte IDReq;
134 	ieByte Location;
135 	ieByte unknown1;
136 	ieResRef UseIcon;
137 	ieStrRef Tooltip;
138 	ieByte Target;
139 	ieByte TargetNumber;
140 	ieWord Range;
141 	//This was commented out in ITMExtHeader
142 	//ieWord ProjectileType;
143 	ieWord Speed;
144 	ieWord THAC0Bonus;
145 	ieWord DiceSides;
146 	ieWord DiceThrown;
147 	ieWordSigned DamageBonus; //this must be signed!!!
148 	ieWord DamageType;
149 	ieWord FeatureCount;
150 	ieWord FeatureOffset;
151 	ieWord Charges;
152 	ieWord ChargeDepletion;
153 	ieDword RechargeFlags; //this is a bitfield with many bits
154 	ieWord ProjectileAnimation;
155 	ieWord MeleeAnimation[3];
156 	int ProjectileQualifier; //this is a derived value determined on load time
157 	//other data
158 	ieResRef itemname;
159 };
160 
161 /**
162  * @class CREItem
163  * Class holding Item instance specific values and providing link between
164  * an Inventory and a stack of Items.
165  * It's keeping info on whether Item was identified, for example.
166  */
167 
168 class GEM_EXPORT CREItem {
169 public:
170 	ieResRef ItemResRef;
171 	//recent research showed that this field is used by the create item
172 	//for days effect. This field shows the expiration in gametime hours
173 	ieWord Expired;
174 	ieWord Usages[CHARGE_COUNTERS];
175 	uint32_t Flags;
176 	// 2 cached values from associated item. LEAVE IT SIGNED!
177 	/** Weight of each item in the stack */
178 	int Weight;
179 	/** Maximum amount of items in this stack */
180 	int MaxStackAmount;
181 
CREItem()182 	CREItem()
183 	{
184 		Weight=-1; //invalid weight
185 		MaxStackAmount=0;
186 		Flags = 0;
187 		Expired = 0;
188 	};
CREItem(STOItem * item)189 	CREItem(STOItem *item)
190 	{
191 		CopySTOItem(item);
192 	};
CopySTOItem(STOItem * item)193 	void CopySTOItem(STOItem *item)
194 	{
195 		CopyResRef(ItemResRef, item->ItemResRef);
196 		Expired = 0; // PurchasedAmount in STOItem
197 		memcpy(Usages, item->Usages, sizeof(ieWord)*CHARGE_COUNTERS);
198 		Flags = item->Flags;
199 		Weight = item->Weight;
200 		MaxStackAmount = item->MaxStackAmount;
201 	};
202 };
203 
204 /**
205  * @class Inventory
206  * Class implementing creatures' and containers' inventory and item management
207  */
208 
209 class GEM_EXPORT Inventory {
210 private:
211 	std::vector<CREItem*> Slots;
212 	Actor* Owner;
213 	int InventoryType;
214 	/** Total weight of all items in Inventory */
215 	int Weight;
216 
217 	ieWordSigned Equipped;
218 	ieWord EquippedHeader;
219 	/** this isn't saved */
220 	ieDword ItemExcl;
221 	ieDword ItemTypes[8]; //256 bits
222 public:
223 	Inventory();
224 	virtual ~Inventory();
225 
226 	/** duplicates the source inventory into the current one, marking items as undroppable */
227 	void CopyFrom(const Actor *source);
228 	/** Removes an item from the inventory, destroys slot.
229 	 * Use it for containers only */
230 	CREItem *GetItem(unsigned int idx);
231 	/** adds an item to the inventory */
232 	void AddItem(CREItem *item);
233 	/** Returns number of items in the inventory */
234 	int CountItems(const char *resref, bool charges) const;
235 	/** looks for a particular item in a slot */
236 	bool HasItemInSlot(const char *resref, unsigned int slot) const;
237 	/** returns true if contains one itemtype equipped */
238 	bool HasItemType(ieDword type) const;
239 	/** Looks for a particular item in the inventory.
240 	 * flags: see ieCREItemFlagBits */
241 	bool HasItem(const char *resref, ieDword flags) const;
242 
243 	void SetInventoryType(int arg);
SetOwner(Actor * act)244 	void SetOwner(Actor* act) { Owner = act; }
245 
246 	/** returns number of all slots in the inventory */
GetSlotCount()247 	int GetSlotCount() const { return (int)Slots.size(); }
248 
249 	/** sets inventory size, for the first time */
250 	void SetSlotCount(unsigned int size);
251 
252 
253 	/** Returns CREItem in specified slot.
254 	 * If count !=0 it splits the item and returns only requested amount */
255 	CREItem* RemoveItem(unsigned int slot, unsigned int count = 0);
256 	/** returns slot of removed item, you can delete the removed item */
257 	int RemoveItem(const char* resref, unsigned int flags, CREItem **res_item, int count = 0);
258 
259 	/** adds CREItem to the inventory. If slot == -1, finds
260 	** first eligible slot, eventually splitting the item to
261 	** more slots. If slot == -3 then finds the first empty inventory slot
262 	** Returns 2 if completely successful, 1 if partially, 0 else.
263 	** slottype is an optional filter for searching eligible slots */
264 	int AddSlotItem(CREItem* item, int slot, int slottype = -1, bool ranged = false);
265 	/** tries to equip all inventory items in a given slot */
266 	void TryEquipAll(int slot);
267 	/** Adds STOItem to the inventory, it is never wielded, action might be STA_STEAL or STA_BUY */
268 	/** The amount of items is stored in PurchasedAmount */
269 	int AddStoreItem(STOItem* item, int action);
270 
271 	/** flags: see ieCREItemFlagBits */
272 	/** count == ~0 means to destroy all */
273 	/** returns the number of destroyed items */
274 	unsigned int DestroyItem(const char *resref, ieDword flags, ieDword count);
275 	void SetSlotItem(CREItem* item, unsigned int slot);
GetWeight()276 	int GetWeight() const {return Weight;}
277 
278 	bool ItemsAreCompatible(const CREItem* target, const CREItem* source) const;
279 	//depletes charged items
280 	int DepleteItem(ieDword flags);
281 	//charges recharging items
282 	void ChargeAllItems(int hours);
283 	/** Finds the first slot of named item, if resref is empty, finds the first filled! slot */
284 	int FindItem(const char *resref, unsigned int flags, unsigned int skip=0) const;
285 	bool DropItemAtLocation(unsigned int slot, unsigned int flags, Map *map, const Point &loc);
286 	bool DropItemAtLocation(const char *resref, unsigned int flags, Map *map, const Point &loc);
287 	bool SetEquippedSlot(ieWordSigned slotcode, ieWord header, bool noFX=false);
288 	int GetEquipped() const;
289 	int GetEquippedHeader() const;
290 	ITMExtHeader *GetEquippedExtHeader(int header=0) const;
291 	void SetEquipped(ieWordSigned slot, ieWord header);
292 	//right hand
293 	int GetEquippedSlot() const;
294 	//left hand
295 	int GetShieldSlot() const;
296 	void AddSlotEffects( ieDword slot);
297 	//void AddAllEffects();
298 	/** Returns item in specified slot. Does NOT change inventory */
299 	CREItem* GetSlotItem(ieDword slot) const;
300 	/** Returns the item's inventory flags */
301 	ieDword GetItemFlag(unsigned int slot) const;
302 	/** Changes the inventory flags */
303 	/** flags: see ieCREItemFlagBits */
304 	bool ChangeItemFlag(ieDword slot, ieDword value, int mode);
305 	/** Equips the item, don't use it directly for weapons */
306 	bool EquipItem(ieDword slot);
307 	bool UnEquipItem(ieDword slot, bool removecurse) const;
308 	/** Returns equipped weapon, also its slot */
309 	CREItem *GetUsedWeapon(bool leftorright, int &slot) const;
310 	/** returns slot of launcher weapon currently equipped */
311 	int FindRangedWeapon() const;
312 	/** returns slot of launcher weapon for specified projectile type */
313 	int FindTypedRangedWeapon(unsigned int type) const;
314 	/** returns slot of launcher weapon for projectile in specified slot */
315 	int FindSlotRangedWeapon(ieDword slot) const;
316 	/** Returns a slot which might be empty, or capable of holding item (or part of it) */
317 	int FindCandidateSlot(int slottype, size_t first_slot, const char *resref = NULL) const;
318 	/** Creates an item in the slot*/
319 	void SetSlotItemRes(const ieResRef ItemResRef, int Slot, int Charge0=1, int Charge1=0, int Charge2=0);
320 	/** Adds item to slot*/
321 	void AddSlotItemRes(const ieResRef ItemResRef, int Slot, int Charge0=1, int Charge1=0, int Charge2=0);
322 	/** returns the itemtype held in the left hand */
323 	ieWord GetShieldItemType() const;
324 	/** returns the itemtype of the item in the armor slot, mostly used in IWD2 */
325 	ieWord GetArmorItemType() const;
326 	/** breaks the item (weapon) in slot */
327 	void BreakItemSlot(ieDword slot);
328 	/** Lists all items in the Inventory on terminal for debugging */
329 	void dump() const;
330 	/// List all items in the Inventory to the given buffer */
331 	void dump(StringBuffer&) const;
332 	/** Equips best weapon */
333 	void EquipBestWeapon(int flags);
334 	/** returns the struct of the usable items, returns true if there are more */
335 	bool GetEquipmentInfo(ItemExtHeader *array, int startindex, int count);
336 	/** returns the exclusion bits */
337 	ieDword GetEquipExclusion(int index) const;
338 	/** returns if a slot is temporarily blocked */
339 	bool IsSlotBlocked(int slot) const;
340 	/** returns true if a two handed weapon is in slot */
341 	inline bool TwoHandedInSlot(int slot) const;
342 	/** returns the strref for the reason why the item cannot be equipped */
343 	int WhyCantEquip(int slot, int twohanded, bool ranged = false) const;
344 	/** returns a slot that has a stealable item */
345 	int FindStealableItem();
346 	/** checks if any equipped item provides critical hit aversion */
347 	bool ProvidesCriticalAversion();
348 	/** tries to merge the passed item with the one in the passed slot */
349 	int MergeItems(int slot, CREItem *item);
350 	bool FistsEquipped() const;
351 	bool MagicSlotEquipped() const;
352 	//setting important constants
353 	static void Init();
354 	static void SetArmorSlot(int arg);
355 	static void SetHeadSlot(int arg);
356 	static void SetFistSlot(int arg);
357 	static void SetMagicSlot(int arg);
358 	static void SetWeaponSlot(int arg);
359 	static void SetRangedSlot(int arg);
360 	static void SetQuickSlot(int arg);
361 	static void SetInventorySlot(int arg);
362 	static void SetShieldSlot(int arg);
363 	static int GetArmorSlot();
364 	static int GetHeadSlot();
365 	static int GetFistSlot();
366 	static int GetMagicSlot();
367 	static int GetWeaponSlot();
368 	static int GetWeaponQuickSlot(int weaponslot);
369 	static int GetWeaponSlot(int quickslot);
370 	static int GetRangedSlot();
371 	static int GetQuickSlot();
372 	static int GetInventorySlot();
373 private:
374 	void CalculateWeight(void);
375 	int FindRangedProjectile(unsigned int type) const;
376 	// called by KillSlot
377 	void RemoveSlotEffects( /*CREItem* slot*/ ieDword slot );
378 	void KillSlot(unsigned int index);
379 	inline Item *GetItemPointer(ieDword slot, CREItem *&Slot) const;
380 	void UpdateWeaponAnimation();
381 	void UpdateShieldAnimation(const Item *it);
382 };
383 
384 }
385 
386 #endif
387