1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
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.
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.
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.
21 //This class represents the inventory of stores (.sto), area containers (.are)
24 #include "Inventory.h"
29 #include "DisplayMessage.h"
32 #include "Interface.h"
34 #include "ScriptEngine.h"
35 #include "Scriptable/Actor.h"
39 static int SLOT_HEAD
= -1;
40 static int SLOT_MAGIC
= -1;
41 static int SLOT_FIST
= -1;
42 static int SLOT_MELEE
= -1;
43 static int LAST_MELEE
= -1;
44 static int SLOT_RANGED
= -1;
45 static int LAST_RANGED
= -1;
46 static int SLOT_QUICK
= -1;
47 static int LAST_QUICK
= -1;
48 static int SLOT_INV
= -1;
49 static int LAST_INV
= -1;
50 static int SLOT_LEFT
= -1;
53 static bool IWD2
= false;
54 static int MagicBit
= 0;
56 static void InvalidSlot(int slot
)
58 printMessage("Inventory"," ",LIGHT_RED
);
59 printf("Invalid slot: %d!\n",slot
);
63 //This inline function returns both an item pointer and the slot data.
64 //slot is a dynamic slot number (SLOT_*)
65 inline Item
*Inventory::GetItemPointer(ieDword slot
, CREItem
*&item
) const
67 item
= GetSlotItem(slot
);
68 if (!item
) return NULL
;
69 if (!item
->ItemResRef
[0]) return NULL
;
70 return gamedata
->GetItem(item
->ItemResRef
);
73 void Inventory::Init(int mb
)
84 //TODO: set this correctly
89 Inventory::Inventory()
92 InventoryType
= INVENTORY_HEAP
;
95 Equipped
= IW_NO_EQUIPPED
;
98 memset(ItemTypes
, 0, sizeof(ItemTypes
));
101 Inventory::~Inventory()
103 for (size_t i
= 0; i
< Slots
.size(); i
++) {
111 CREItem
*Inventory::GetItem(unsigned int slot
)
113 if (slot
>= Slots
.size() ) {
117 CREItem
*item
= Slots
[slot
];
118 Slots
.erase(Slots
.begin()+slot
);
122 //This hack sets the charge counters for non-rechargeable items,
123 //if their charge is zero
124 inline void HackCharges(CREItem
*item
)
126 Item
*itm
= gamedata
->GetItem( item
->ItemResRef
);
128 for (int i
=0;i
<3;i
++) {
129 if (item
->Usages
[i
]) {
132 ITMExtHeader
*h
= itm
->GetExtHeader(i
);
133 if (h
&& !(h
->RechargeFlags
&IE_ITEM_RECHARGE
)) {
134 //HACK: the original (bg2) allows for 0 charged gems
136 item
->Usages
[i
] = h
->Charges
;
142 gamedata
->FreeItem( itm
, item
->ItemResRef
, false );
146 void Inventory::AddItem(CREItem
*item
)
148 if (!item
) return; //invalid items get no slot
149 Slots
.push_back(item
);
151 //Changed=true; //probably not needed, chests got no encumbrance
154 void Inventory::CalculateWeight()
160 for (size_t i
= 0; i
< Slots
.size(); i
++) {
161 CREItem
*slot
= Slots
[i
];
165 if (slot
->Weight
== -1) {
166 Item
*itm
= gamedata
->GetItem( slot
->ItemResRef
);
168 //simply adding the item flags to the slot
169 slot
->Flags
|= (itm
->Flags
<<8);
170 //some slot flags might be affected by the item flags
171 if (!(slot
->Flags
& IE_INV_ITEM_CRITICAL
)) {
172 slot
->Flags
|= IE_INV_ITEM_DESTRUCTIBLE
;
174 //this is for converting IWD items magic flag
176 if (slot
->Flags
&IE_INV_ITEM_UNDROPPABLE
) {
177 slot
->Flags
|=IE_INV_ITEM_MAGICAL
;
178 slot
->Flags
&=~IE_INV_ITEM_UNDROPPABLE
;
182 if (!(slot
->Flags
& IE_INV_ITEM_MOVABLE
)) {
183 slot
->Flags
|= IE_INV_ITEM_UNDROPPABLE
;
186 if (slot
->Flags
& IE_INV_ITEM_STOLEN2
) {
187 slot
->Flags
|= IE_INV_ITEM_STOLEN
;
190 //auto identify basic items
191 if (!itm
->LoreToID
) {
192 slot
->Flags
|= IE_INV_ITEM_IDENTIFIED
;
195 //if item is stacked mark it as so
196 if (itm
->StackAmount
) {
197 slot
->Flags
|= IE_INV_ITEM_STACKED
;
200 slot
->Weight
= itm
->Weight
;
201 slot
->StackAmount
= itm
->StackAmount
;
202 gamedata
->FreeItem( itm
, slot
->ItemResRef
, false );
205 printMessage( "Inventory", " ", LIGHT_RED
);
206 printf("Invalid item: %s!\n", slot
->ItemResRef
);
210 slot
->Flags
&= ~IE_INV_ITEM_ACQUIRED
;
212 if (slot
->Weight
> 0) {
213 Weight
+= slot
->Weight
* ((slot
->Usages
[0] && slot
->StackAmount
> 1) ? slot
->Usages
[0] : 1);
219 void Inventory::AddSlotEffects(ieDword index
)
223 const Item
*itm
= GetItemPointer(index
, slot
);
225 printMessage("Inventory","Invalid item equipped...\n",LIGHT_RED
);
228 ItemExcl
|=itm
->ItemExcl
;
229 ieDword pos
= itm
->ItemType
/32;
230 ieDword bit
= itm
->ItemType
%32;
232 ItemTypes
[pos
]|=1<<bit
;
235 ieWord gradient
= itm
->GetWieldedGradient();
236 if (gradient
!=0xffff) {
237 Owner
->SetBase(IE_COLORS
, gradient
);
240 //get the equipping effects
241 EffectQueue
*eqfx
= itm
->GetEffectBlock(-1, index
, 0);
242 gamedata
->FreeItem( itm
, slot
->ItemResRef
, false );
244 Owner
->RefreshEffects(eqfx
);
245 //call gui for possible paperdoll animation changes
246 if (Owner
->InParty
) {
247 core
->SetEventFlag(EF_UPDATEANIM
);
251 //no need to know the item effects 'personally', the equipping slot
253 void Inventory::RemoveSlotEffects(ieDword index
)
255 Owner
->fxqueue
.RemoveEquippingEffects(index
);
256 Owner
->RefreshEffects(NULL
);
257 //call gui for possible paperdoll animation changes
258 if (Owner
->InParty
) {
259 core
->SetEventFlag(EF_UPDATEANIM
);
263 void Inventory::SetInventoryType(int arg
)
268 void Inventory::SetSlotCount(unsigned int size
)
271 printf("Inventory size changed???\n");
272 //we don't allow reassignment,
273 //if you want this, delete the previous Slots here
276 Slots
.assign((size_t) size
, NULL
);
279 /** if you supply a "" string, then it checks if the slot is empty */
280 bool Inventory::HasItemInSlot(const char *resref
, unsigned int slot
) const
282 if (slot
>= Slots
.size()) {
285 const CREItem
*item
= Slots
[slot
];
292 if (strnicmp( item
->ItemResRef
, resref
, 8 )==0) {
298 bool Inventory::HasItemType(ieDword type
) const
300 if (type
>255) return false;
303 return (ItemTypes
[idx
] & (1<<bit
) )!=0;
306 /** counts the items in the inventory, if stacks == 1 then stacks are
307 accounted for their heap size */
308 int Inventory::CountItems(const char *resref
, bool stacks
) const
311 size_t slot
= Slots
.size();
313 const CREItem
*item
= Slots
[slot
];
317 if (resref
&& resref
[0]) {
318 if (!strnicmp(resref
, item
->ItemResRef
, 8) )
321 if (stacks
&& (item
->Flags
&IE_INV_ITEM_STACKED
) ) {
322 count
+=item
->Usages
[0];
331 /** this function can look for stolen, equipped, identified, destructible
332 etc, items. You just have to specify the flags in the bitmask
333 specifying 1 in a bit signifies a requirement */
334 bool Inventory::HasItem(const char *resref
, ieDword flags
) const
336 size_t slot
= Slots
.size();
338 const CREItem
*item
= Slots
[slot
];
342 if ( (flags
&item
->Flags
)!=flags
) {
345 if (resref
[0] && strnicmp(item
->ItemResRef
, resref
,8) ) {
353 void Inventory::KillSlot(unsigned int index
)
355 if (InventoryType
==INVENTORY_HEAP
) {
356 Slots
.erase(Slots
.begin()+index
);
359 CREItem
*item
= Slots
[index
];
364 //the used up item vanishes from the quickslot bar
365 if (Owner
->InParty
) {
366 core
->SetEventFlag( EF_ACTION
);
370 int effect
= core
->QuerySlotEffects( index
);
374 RemoveSlotEffects( index
);
375 Item
*itm
= gamedata
->GetItem(item
->ItemResRef
);
376 //this cannot happen, but stuff happens!
380 ItemExcl
&= ~itm
->ItemExcl
;
383 case SLOT_EFFECT_LEFT
:
384 UpdateShieldAnimation(0);
386 case SLOT_EFFECT_MISSILE
:
387 //getting a new projectile of the same type
388 if (Equipped
+ SLOT_MELEE
== (int) index
) {
390 //always get the projectile weapon header (this quiver was equipped)
391 ITMExtHeader
*header
= itm
->GetWeaponHeader(true);
392 Equipped
= FindRangedProjectile(header
->ProjectileQualifier
);
393 if (Equipped
!=IW_NO_EQUIPPED
) {
394 EquipItem(Equipped
+SLOT_MELEE
);
396 EquipItem(SLOT_FIST
);
400 UpdateWeaponAnimation();
402 case SLOT_EFFECT_MELEE
:
403 // reset Equipped if it was the removed item
404 if (Equipped
+SLOT_MELEE
== (int)index
)
405 Equipped
= IW_NO_EQUIPPED
;
406 else if (Equipped
< 0) {
407 //always get the projectile weapon header (this is a bow, because Equipped is negative)
408 ITMExtHeader
*header
= itm
->GetWeaponHeader(true);
410 //find the equipped type
411 int type
= header
->ProjectileQualifier
;
412 int weaponslot
= FindTypedRangedWeapon(type
);
413 CREItem
*item2
= Slots
[weaponslot
];
415 Item
*itm2
= gamedata
->GetItem(item2
->ItemResRef
);
417 if (type
== header
->ProjectileQualifier
) {
418 Equipped
= FindRangedProjectile(header
->ProjectileQualifier
);
419 if (Equipped
!=IW_NO_EQUIPPED
) {
420 EquipItem(Equipped
+SLOT_MELEE
);
422 EquipItem(SLOT_FIST
);
425 gamedata
->FreeItem(itm2
, item2
->ItemResRef
, false);
430 // reset Equipped if it is a ranged weapon slot
431 // but not magic weapon slot!
433 UpdateWeaponAnimation();
435 case SLOT_EFFECT_HEAD
:
436 Owner
->SetUsedHelmet("");
438 case SLOT_EFFECT_ITEM
:
439 //remove the armor type only if this item is responsible for it
440 if ((ieDword
) (itm
->AnimationType
[0]-'1') == Owner
->GetBase(IE_ARMOR_TYPE
)) {
441 Owner
->SetBase(IE_ARMOR_TYPE
, 0);
445 gamedata
->FreeItem(itm
, item
->ItemResRef
, false);
447 /** if resref is "", then destroy ALL items
448 this function can look for stolen, equipped, identified, destructible
449 etc, items. You just have to specify the flags in the bitmask
450 specifying 1 in a bit signifies a requirement */
451 unsigned int Inventory::DestroyItem(const char *resref
, ieDword flags
, ieDword count
)
453 unsigned int destructed
= 0;
454 size_t slot
= Slots
.size();
457 //ignore the fist slot
458 if (slot
== (unsigned int)SLOT_FIST
) {
462 CREItem
*item
= Slots
[slot
];
466 // here you can simply destroy all items of a specific type
467 if ( (flags
&item
->Flags
)!=flags
) {
470 if (resref
[0] && strnicmp(item
->ItemResRef
, resref
, 8) ) {
473 //we need to acknowledge that the item was destroyed
474 //use unequip stuff, decrease encumbrance etc,
475 //until that, we simply erase it
478 if (item
->Flags
&IE_INV_ITEM_STACKED
) {
479 removed
=item
->Usages
[0];
480 if (count
&& (removed
+ destructed
> count
) ) {
481 removed
= count
- destructed
;
482 item
= RemoveItem( (unsigned int) slot
, removed
);
485 KillSlot( (unsigned int) slot
);
489 KillSlot( (unsigned int) slot
);
494 if (count
&& (destructed
>=count
) )
497 if (Changed
&& Owner
&& Owner
->InParty
) displaymsg
->DisplayConstantString(STR_LOSTITEM
, 0xbcefbc);
502 CREItem
*Inventory::RemoveItem(unsigned int slot
, unsigned int count
)
506 if (slot
>= Slots
.size() ) {
517 if (!count
|| !(item
->Flags
&IE_INV_ITEM_STACKED
) ) {
521 if (count
>= item
->Usages
[0]) {
526 CREItem
*returned
= new CREItem(*item
);
527 item
->Usages
[0]-=count
;
528 returned
->Usages
[0]=(ieWord
) count
;
532 //flags set disable item transfer
533 //except for undroppable and equipped, which are opposite (and shouldn't be set)
534 int Inventory::RemoveItem(const char *resref
, unsigned int flags
, CREItem
**res_item
)
536 size_t slot
= Slots
.size();
538 CREItem
*item
= Slots
[slot
];
542 unsigned int mask
= (flags
^(IE_INV_ITEM_UNDROPPABLE
|IE_INV_ITEM_EQUIPPED
));
543 if (flags
&& (mask
&item
->Flags
)==flags
) {
546 if (!flags
&& (mask
&item
->Flags
)!=0) {
549 if (resref
[0] && strnicmp(item
->ItemResRef
, resref
, 8) ) {
552 *res_item
=RemoveItem( (unsigned int) slot
, 0);
559 void Inventory::SetSlotItem(CREItem
* item
, unsigned int slot
)
561 if (slot
>= Slots
.size() ) {
574 //update the action bar next time
575 if (Owner
->InParty
) {
576 core
->SetEventFlag( EF_ACTION
);
580 int Inventory::AddSlotItem(CREItem
* item
, int slot
, int slottype
)
582 int twohanded
= item
->Flags
&IE_INV_ITEM_TWOHANDED
;
584 if ((unsigned)slot
>= Slots
.size()) {
589 //check for equipping weapons
590 if (WhyCantEquip(slot
,twohanded
)) {
595 item
->Flags
|= IE_INV_ITEM_ACQUIRED
;
596 SetSlotItem(item
, slot
);
601 CREItem
*myslot
= Slots
[slot
];
602 if (ItemsAreCompatible( myslot
, item
)) {
603 //calculate with the max movable stock
604 int chunk
= item
->Usages
[0];
605 int newamount
= myslot
->Usages
[0]+chunk
;
606 if (newamount
>myslot
->StackAmount
) {
607 newamount
=myslot
->StackAmount
;
608 chunk
= item
->Usages
[0]-newamount
;
613 myslot
->Flags
|= IE_INV_ITEM_ACQUIRED
;
614 myslot
->Usages
[0] = (ieWord
) (myslot
->Usages
[0] + chunk
);
615 item
->Usages
[0] = (ieWord
) (item
->Usages
[0] - chunk
);
618 if (item
->Usages
[0] == 0) {
628 if (slot
==SLOT_AUTOEQUIP
) {
633 int res
= ASI_FAILED
;
634 int max
= (int) Slots
.size();
635 for (int i
= 0;i
<max
;i
++) {
636 //never autoequip in the magic slot!
639 if ((i
<SLOT_INV
|| i
>LAST_INV
)!=which
)
641 if (!(core
->QuerySlotType(i
)&slottype
))
643 //the slot has been disabled for this actor
644 if (i
>=SLOT_MELEE
&& i
<=LAST_MELEE
) {
645 if (Owner
->GetQuickSlot(i
-SLOT_MELEE
)==0xffff) {
649 int part_res
= AddSlotItem (item
, i
);
650 if (part_res
== ASI_SUCCESS
) return ASI_SUCCESS
;
651 else if (part_res
== ASI_PARTIAL
) res
= ASI_PARTIAL
;
658 void Inventory::TryEquipAll(int slot
)
660 for(int i
=SLOT_INV
;i
<=LAST_INV
;i
++) {
661 CREItem
*item
= Slots
[i
];
667 if (AddSlotItem(item
, slot
) == ASI_SUCCESS
) {
670 //try to stuff it back, it should work
671 if (AddSlotItem(item
, i
) != ASI_SUCCESS
) {
677 int Inventory::AddStoreItem(STOItem
* item
, int action
)
682 // item->PurchasedAmount is the number of items bought
683 // (you can still add grouped objects in a single step,
684 // just set up STOItem)
685 while (item
->PurchasedAmount
) {
686 //the first part of a STOItem is essentially a CREItem
687 temp
= new CREItem();
688 memcpy( temp
, item
, sizeof( CREItem
) );
689 //except the Expired flag
691 if (action
==STA_STEAL
) {
692 temp
->Flags
|= IE_INV_ITEM_STOLEN
;
694 temp
->Flags
&= ~IE_INV_ITEM_SELECTED
;
696 ret
= AddSlotItem( temp
, SLOT_ONLYINVENTORY
);
697 if (ret
!= ASI_SUCCESS
) {
701 if (item
->InfiniteSupply
!=-1) {
702 if (!item
->AmountInStock
) {
705 item
->AmountInStock
--;
707 item
->PurchasedAmount
--;
712 /* could the source item be dropped on the target item to merge them */
713 bool Inventory::ItemsAreCompatible(CREItem
* target
, CREItem
* source
) const
716 //this isn't always ok, please check!
717 printMessage("Inventory","Null item encountered by ItemsAreCompatible()",YELLOW
);
721 if (!(source
->Flags
&IE_INV_ITEM_STACKED
) ) {
725 if (!strnicmp( target
->ItemResRef
, source
->ItemResRef
,8 )) {
731 //depletes a magical item
732 //if flags==0 then magical weapons are not harmed
733 int Inventory::DepleteItem(ieDword flags
)
735 for (size_t i
= 0; i
< Slots
.size(); i
++) {
736 CREItem
*item
= Slots
[i
];
741 //don't harm critical items
742 //don't harm nonmagical items
743 //don't harm indestructible items
744 if ( (item
->Flags
&(IE_INV_ITEM_CRITICAL
|IE_INV_DEPLETABLE
)) != IE_INV_DEPLETABLE
) {
748 //if flags = 0 then weapons are not depleted
750 Item
*itm
= gamedata
->GetItem( item
->ItemResRef
);
753 //if the item is usable in weapon slot, then it is weapon
754 int weapon
= core
->CanUseItemType( SLOT_WEAPON
, itm
);
755 gamedata
->FreeItem( itm
, item
->ItemResRef
, false );
767 // if flags is 0, skips undroppable items
768 // if flags is IE_INV_ITEM_UNDROPPABLE, doesn't skip undroppable items
769 // TODO: once all callers have been checked, this can be reversed to make more sense
770 int Inventory::FindItem(const char *resref
, unsigned int flags
) const
772 for (size_t i
= 0; i
< Slots
.size(); i
++) {
773 const CREItem
*item
= Slots
[i
];
777 if ( (flags
^IE_INV_ITEM_UNDROPPABLE
) & item
->Flags
) {
780 if (resref
[0] && strnicmp(item
->ItemResRef
, resref
, 8) ) {
788 bool Inventory::DropItemAtLocation(unsigned int slot
, unsigned int flags
, Map
*map
, const Point
&loc
)
790 if (slot
>= Slots
.size()) {
793 //these slots will never 'drop' the item
794 if ((slot
==(unsigned int) SLOT_FIST
) || (slot
==(unsigned int) SLOT_MAGIC
)) {
798 CREItem
*item
= Slots
[slot
];
802 //if you want to drop undoppable items, simply set IE_INV_UNDROPPABLE
803 //by default, it won't drop them
804 if ( ((flags
^IE_INV_ITEM_UNDROPPABLE
)&item
->Flags
)!=flags
) {
810 map
->AddItemToLocation(loc
, item
);
816 bool Inventory::DropItemAtLocation(const char *resref
, unsigned int flags
, Map
*map
, const Point
&loc
)
818 bool dropped
= false;
824 //this loop is going from start
825 for (size_t i
= 0; i
< Slots
.size(); i
++) {
826 //these slots will never 'drop' the item
827 if ((i
==(unsigned int) SLOT_FIST
) || (i
==(unsigned int) SLOT_MAGIC
)) {
830 CREItem
*item
= Slots
[i
];
834 //if you want to drop undoppable items, simply set IE_INV_UNDROPPABLE
835 //by default, it won't drop them
836 if ( ((flags
^IE_INV_ITEM_UNDROPPABLE
)&item
->Flags
)!=flags
) {
839 if (resref
[0] && strnicmp(item
->ItemResRef
, resref
, 8) ) {
842 // mark it as unequipped, so it doesn't cause problems in stores
843 item
->Flags
&= ~ IE_INV_ITEM_EQUIPPED
;
844 map
->AddItemToLocation(loc
, item
);
847 KillSlot((unsigned int) i
);
848 //if it isn't all items then we stop here
855 CREItem
*Inventory::GetSlotItem(unsigned int slot
) const
857 if (slot
>= Slots
.size() ) {
864 ieDword
Inventory::GetItemFlag(unsigned int slot
) const
866 const CREItem
*item
= GetSlotItem(slot
);
873 bool Inventory::ChangeItemFlag(unsigned int slot
, ieDword arg
, int op
)
875 CREItem
*item
= GetSlotItem(slot
);
880 case BM_SET
: item
->Flags
= arg
; break;
881 case BM_OR
: item
->Flags
|= arg
; break;
882 case BM_NAND
: item
->Flags
&= ~arg
; break;
883 case BM_XOR
: item
->Flags
^= arg
; break;
884 case BM_AND
: item
->Flags
&= arg
; break;
889 //this is the low level equipping
890 //all checks have been made previously
891 bool Inventory::EquipItem(unsigned int slot
)
893 ITMExtHeader
*header
;
896 //maybe assertion too?
899 CREItem
*item
= GetSlotItem(slot
);
906 // add effects of an item just being equipped to actor's effect queue
907 int effect
= core
->QuerySlotEffects( slot
);
908 Item
*itm
= gamedata
->GetItem(item
->ItemResRef
);
910 printf("Invalid item Equipped: %s Slot: %d\n", item
->ItemResRef
, slot
);
914 case SLOT_EFFECT_LEFT
:
915 //no idea if the offhand weapon has style, or simply the right
916 //hand style is dominant
917 UpdateShieldAnimation(itm
);
919 case SLOT_EFFECT_MELEE
:
920 //if weapon is ranged, then find quarrel for it and equip that
924 header
= itm
->GetExtHeader(EquippedHeader
);
925 if (header
&& header
->AttackType
== ITEM_AT_BOW
) {
926 //find the ranged projectile associated with it.
927 slot
= FindRangedProjectile(header
->ProjectileQualifier
);
928 EquippedHeader
= itm
->GetWeaponHeaderNumber(true);
929 } else if (header
&& header
->AttackType
== ITEM_AT_PROJECTILE
) {
930 EquippedHeader
= itm
->GetWeaponHeaderNumber(true);
932 EquippedHeader
= itm
->GetWeaponHeaderNumber(false);
934 header
= itm
->GetExtHeader(EquippedHeader
);
936 SetEquippedSlot(slot
, EquippedHeader
);
937 if (slot
!= IW_NO_EQUIPPED
) {
938 Owner
->SetupQuickSlot(ACT_WEAPON1
+weaponslot
, slot
+SLOT_MELEE
, EquippedHeader
);
940 effect
= 0; // SetEquippedSlot will already call AddSlotEffects
941 UpdateWeaponAnimation();
944 case SLOT_EFFECT_MISSILE
:
945 //Get the ranged header of the projectile (so we theoretically allow shooting of daggers)
946 EquippedHeader
= itm
->GetWeaponHeaderNumber(true);
947 header
= itm
->GetExtHeader(EquippedHeader
);
949 weaponslot
= FindTypedRangedWeapon(header
->ProjectileQualifier
);
950 if (weaponslot
!= SLOT_FIST
) {
951 weaponslot
-= SLOT_MELEE
;
952 SetEquippedSlot((ieWordSigned
) (slot
-SLOT_MELEE
), EquippedHeader
);
953 //It is unsure if we can have multiple equipping headers for bows/arrow
954 //It is unclear which item's header index should go there
955 Owner
->SetupQuickSlot(ACT_WEAPON1
+weaponslot
, slot
, 0);
957 UpdateWeaponAnimation();
960 case SLOT_EFFECT_HEAD
:
961 Owner
->SetUsedHelmet(itm
->AnimationType
);
963 case SLOT_EFFECT_ITEM
:
964 //adjusting armour level if needed
966 int l
= itm
->AnimationType
[0]-'1';
968 Owner
->SetBase(IE_ARMOR_TYPE
, l
);
970 UpdateShieldAnimation(itm
);
975 gamedata
->FreeItem(itm
, item
->ItemResRef
, false);
977 if (item
->Flags
& IE_INV_ITEM_CURSED
) {
978 item
->Flags
|=IE_INV_ITEM_UNDROPPABLE
;
980 AddSlotEffects( slot
);
985 //the removecurse flag will check if it is possible to move the item to the inventory
986 //after a remove curse spell
987 bool Inventory::UnEquipItem(unsigned int slot
, bool removecurse
)
989 CREItem
*item
= GetSlotItem(slot
);
994 if (item
->Flags
& IE_INV_ITEM_MOVABLE
) {
995 item
->Flags
&=~IE_INV_ITEM_UNDROPPABLE
;
997 if (FindCandidateSlot(SLOT_INVENTORY
,0,item
->ItemResRef
)<0) {
1001 if (item
->Flags
& IE_INV_ITEM_UNDROPPABLE
) {
1004 item
->Flags
&= ~IE_INV_ITEM_EQUIPPED
; //no idea if this is needed, won't hurt
1008 // find the projectile
1012 //returns equipped code
1013 int Inventory::FindRangedProjectile(unsigned int type
) const
1015 for(int i
=SLOT_RANGED
;i
<=LAST_RANGED
;i
++) {
1018 const Item
*itm
= GetItemPointer(i
, Slot
);
1020 ITMExtHeader
*ext_header
= itm
->GetExtHeader(0);
1021 unsigned int weapontype
= 0;
1023 weapontype
= ext_header
->ProjectileQualifier
;
1025 gamedata
->FreeItem(itm
, Slot
->ItemResRef
, false);
1026 if (weapontype
& type
) {
1027 return i
-SLOT_MELEE
;
1030 return IW_NO_EQUIPPED
;
1033 // find which bow is attached to the projectile marked by 'Equipped'
1035 int Inventory::FindRangedWeapon() const
1037 if (Equipped
>=0) return SLOT_FIST
;
1038 return FindSlotRangedWeapon(Equipped
+SLOT_MELEE
);
1041 int Inventory::FindSlotRangedWeapon(unsigned int slot
) const
1043 if ((int)slot
>= SLOT_MELEE
) return SLOT_FIST
;
1045 Item
*itm
= GetItemPointer(slot
, Slot
);
1046 if (!itm
) return SLOT_FIST
;
1048 //always look for a ranged header when looking for a projectile/projector
1049 ITMExtHeader
*ext_header
= itm
->GetWeaponHeader(true);
1050 unsigned int type
= 0;
1052 type
= ext_header
->ProjectileQualifier
;
1054 gamedata
->FreeItem(itm
, Slot
->ItemResRef
, false);
1055 return FindTypedRangedWeapon(type
);
1059 // find bow for a specific projectile type
1060 int Inventory::FindTypedRangedWeapon(unsigned int type
) const
1065 for(int i
=SLOT_MELEE
;i
<=LAST_MELEE
;i
++) {
1068 const Item
*itm
= GetItemPointer(i
, Slot
);
1070 //always look for a ranged header when looking for a projectile/projector
1071 ITMExtHeader
*ext_header
= itm
->GetWeaponHeader(true);
1074 weapontype
= ext_header
->ProjectileQualifier
;
1076 gamedata
->FreeItem(itm
, Slot
->ItemResRef
, false);
1077 if (weapontype
& type
) {
1084 void Inventory::SetHeadSlot(int arg
) { SLOT_HEAD
=arg
; }
1085 void Inventory::SetFistSlot(int arg
) { SLOT_FIST
=arg
; }
1086 void Inventory::SetMagicSlot(int arg
) { SLOT_MAGIC
=arg
; }
1087 void Inventory::SetWeaponSlot(int arg
)
1089 if (SLOT_MELEE
==-1) {
1095 //ranged slots should be before MELEE slots
1096 void Inventory::SetRangedSlot(int arg
)
1098 assert(SLOT_MELEE
!=-1);
1099 if (SLOT_RANGED
==-1) {
1105 void Inventory::SetQuickSlot(int arg
)
1107 if (SLOT_QUICK
==-1) {
1113 void Inventory::SetInventorySlot(int arg
)
1121 //multiple shield slots are allowed
1122 //but in this case they should be interspersed with melee slots
1123 void Inventory::SetShieldSlot(int arg
)
1125 if (SLOT_LEFT
!=-1) {
1126 assert(SLOT_MELEE
+1==SLOT_LEFT
);
1133 int Inventory::GetHeadSlot()
1138 int Inventory::GetFistSlot()
1143 int Inventory::GetMagicSlot()
1148 int Inventory::GetWeaponSlot()
1153 int Inventory::GetQuickSlot()
1158 int Inventory::GetInventorySlot()
1163 //if shield slot is empty, call again for fist slot!
1164 int Inventory::GetShieldSlot() const
1167 if (Equipped
>=0 && Equipped
<=3) {
1168 return Equipped
*2+SLOT_MELEE
+1;
1175 int Inventory::GetEquippedSlot() const
1177 if (Equipped
== IW_NO_EQUIPPED
) {
1180 if (IWD2
&& Equipped
>=0) {
1181 //i've absolutely NO idea what is this 4 (Avenger)
1182 //Equipped should be 0-3 in iWD2, no???
1183 if (Equipped
>= 4) {
1186 return Equipped
*2+SLOT_MELEE
;
1188 return Equipped
+SLOT_MELEE
;
1191 bool Inventory::SetEquippedSlot(ieWordSigned slotcode
, ieWord header
)
1193 EquippedHeader
= header
;
1195 //doesn't work if magic slot is used, refresh the magic slot just in case
1196 if (HasItemInSlot("",SLOT_MAGIC
) && (slotcode
!=SLOT_MAGIC
-SLOT_MELEE
)) {
1197 Equipped
= SLOT_MAGIC
-SLOT_MELEE
;
1198 UpdateWeaponAnimation();
1202 //if it is an illegal code, make it fist
1203 if ((size_t) (slotcode
+SLOT_MELEE
)>Slots
.size()) {
1204 slotcode
=IW_NO_EQUIPPED
;
1207 //unequipping (fist slot will be used now)
1208 if (slotcode
== IW_NO_EQUIPPED
|| !HasItemInSlot("",slotcode
+SLOT_MELEE
)) {
1209 if (Equipped
!= IW_NO_EQUIPPED
) {
1210 RemoveSlotEffects( SLOT_MELEE
+Equipped
);
1212 Equipped
= IW_NO_EQUIPPED
;
1213 //fist slot equipping effects
1214 AddSlotEffects(SLOT_FIST
);
1215 UpdateWeaponAnimation();
1219 //equipping a weapon, but remove its effects first
1220 if (Equipped
!= IW_NO_EQUIPPED
) {
1221 RemoveSlotEffects( SLOT_MELEE
+Equipped
);
1224 Equipped
= slotcode
;
1225 int effects
= core
->QuerySlotEffects( SLOT_MELEE
+Equipped
);
1227 CREItem
* item
= GetSlotItem(SLOT_MELEE
+Equipped
);
1228 item
->Flags
|=IE_INV_ITEM_EQUIPPED
;
1229 if (item
->Flags
& IE_INV_ITEM_CURSED
) {
1230 item
->Flags
|=IE_INV_ITEM_UNDROPPABLE
;
1232 AddSlotEffects( SLOT_MELEE
+Equipped
);
1234 UpdateWeaponAnimation();
1238 int Inventory::GetEquipped() const
1243 int Inventory::GetEquippedHeader() const
1245 return EquippedHeader
;
1248 //returns the fist weapon if there is nothing else
1249 //This will return the actual weapon, I mean the bow in the case of bow+arrow combination
1250 CREItem
*Inventory::GetUsedWeapon(bool leftorright
, int &slot
) const
1254 if (SLOT_MAGIC
!=-1) {
1256 ret
= GetSlotItem(slot
);
1257 if (ret
&& ret
->ItemResRef
[0]) {
1263 slot
= GetShieldSlot();
1265 ret
= GetSlotItem(slot
);
1269 //we don't want to return fist for shield slot
1274 slot
= GetEquippedSlot();
1275 if((core
->QuerySlotEffects(slot
) & SLOT_EFFECT_MISSILE
) == SLOT_EFFECT_MISSILE
) {
1276 slot
= FindRangedWeapon();
1278 ret
= GetSlotItem(slot
);
1280 //return fist weapon
1282 ret
= GetSlotItem(slot
);
1287 // Returns index of first empty slot or slot with the same
1288 // item and not full stack. On fail returns -1
1289 // Can be used to check for full inventory
1290 int Inventory::FindCandidateSlot(int slottype
, size_t first_slot
, const char *resref
)
1292 if (first_slot
>= Slots
.size())
1295 for (size_t i
= first_slot
; i
< Slots
.size(); i
++) {
1296 if (!(core
->QuerySlotType( (unsigned int) i
) & slottype
) ) {
1300 CREItem
*item
= Slots
[i
];
1303 return (int) i
; //this is a good empty slot
1308 if (!(item
->Flags
&IE_INV_ITEM_STACKED
) ) {
1311 if (strnicmp( item
->ItemResRef
, resref
, 8 )!=0) {
1314 // check if the item fits in this slot, we use the cached
1315 // stackamount value
1316 if (item
->Usages
[0]<item
->StackAmount
) {
1324 void Inventory::AddSlotItemRes(const ieResRef ItemResRef
, int SlotID
, int Charge0
, int Charge1
, int Charge2
)
1326 CREItem
*TmpItem
= new CREItem();
1327 strnlwrcpy(TmpItem
->ItemResRef
, ItemResRef
, 8);
1329 TmpItem
->Usages
[0]=(ieWord
) Charge0
;
1330 TmpItem
->Usages
[1]=(ieWord
) Charge1
;
1331 TmpItem
->Usages
[2]=(ieWord
) Charge2
;
1333 if (core
->ResolveRandomItem(TmpItem
) && gamedata
->Exists(TmpItem
->ItemResRef
, IE_ITM_CLASS_ID
)) {
1334 AddSlotItem( TmpItem
, SlotID
);
1341 void Inventory::SetSlotItemRes(const ieResRef ItemResRef
, int SlotID
, int Charge0
, int Charge1
, int Charge2
)
1344 CREItem
*TmpItem
= new CREItem();
1345 strnlwrcpy(TmpItem
->ItemResRef
, ItemResRef
, 8);
1347 TmpItem
->Usages
[0]=(ieWord
) Charge0
;
1348 TmpItem
->Usages
[1]=(ieWord
) Charge1
;
1349 TmpItem
->Usages
[2]=(ieWord
) Charge2
;
1351 if (core
->ResolveRandomItem(TmpItem
) && gamedata
->Exists(TmpItem
->ItemResRef
, IE_ITM_CLASS_ID
)) {
1352 SetSlotItem( TmpItem
, SlotID
);
1357 //if the item isn't creatable, we still destroy the old item
1363 void Inventory::BreakItemSlot(ieDword slot
)
1368 const Item
*itm
= GetItemPointer(slot
, Slot
);
1370 //if it is the magic weapon slot, don't break it, just remove it, because it couldn't be removed
1371 if(slot
==(unsigned int) SLOT_MAGIC
) {
1374 memcpy(newItem
, itm
->ReplacementItem
,sizeof(newItem
) );
1376 gamedata
->FreeItem( itm
, Slot
->ItemResRef
, true );
1377 //this depends on setslotitemres using setslotitem
1378 SetSlotItemRes(newItem
, slot
, 0,0,0);
1381 void Inventory::dump()
1383 printf( "INVENTORY:\n" );
1384 for (unsigned int i
= 0; i
< Slots
.size(); i
++) {
1385 CREItem
* itm
= Slots
[i
];
1391 printf ( "%2u: %8.8s - (%d %d %d) %x Wt: %d x %dLb\n", i
, itm
->ItemResRef
, itm
->Usages
[0], itm
->Usages
[1], itm
->Usages
[2], itm
->Flags
, itm
->StackAmount
, itm
->Weight
);
1394 printf( "Equipped: %d\n", Equipped
);
1397 printf( "Total weight: %d\n", Weight
);
1400 void Inventory::EquipBestWeapon(int flags
)
1404 ieDword best_slot
= SLOT_FIST
;
1405 ITMExtHeader
*header
;
1407 char AnimationType
[2]={0,0};
1408 ieWord MeleeAnimation
[3]={100,0,0};
1410 //cannot change equipment when holding magic weapons
1411 if (Equipped
== SLOT_MAGIC
-SLOT_MELEE
) {
1415 if (flags
&EQUIP_RANGED
) {
1416 for(i
=SLOT_RANGED
;i
<LAST_RANGED
;i
++) {
1417 const Item
*itm
= GetItemPointer(i
, Slot
);
1420 int tmp
= itm
->GetDamagePotential(true, header
);
1424 memcpy(AnimationType
,itm
->AnimationType
,sizeof(AnimationType
) );
1425 memcpy(MeleeAnimation
,header
->MeleeAnimation
,sizeof(MeleeAnimation
) );
1427 gamedata
->FreeItem( itm
, Slot
->ItemResRef
, false );
1430 //ranged melee weapons like throwing daggers (not bows!)
1431 for(i
=SLOT_MELEE
;i
<=LAST_MELEE
;i
++) {
1432 const Item
*itm
= GetItemPointer(i
, Slot
);
1435 int tmp
= itm
->GetDamagePotential(true, header
);
1439 memcpy(AnimationType
,itm
->AnimationType
,sizeof(AnimationType
) );
1440 memcpy(MeleeAnimation
,header
->MeleeAnimation
,sizeof(MeleeAnimation
) );
1442 gamedata
->FreeItem( itm
, Slot
->ItemResRef
, false );
1446 if (flags
&EQUIP_MELEE
) {
1447 for(i
=SLOT_MELEE
;i
<=LAST_MELEE
;i
++) {
1448 const Item
*itm
= GetItemPointer(i
, Slot
);
1450 //the Slot flag is enough for this
1451 //though we need animation type/damagepotential anyway
1452 if (Slot
->Flags
&IE_INV_ITEM_BOW
) continue;
1454 int tmp
= itm
->GetDamagePotential(false, header
);
1458 memcpy(AnimationType
,itm
->AnimationType
,sizeof(AnimationType
) );
1459 memcpy(MeleeAnimation
,header
->MeleeAnimation
,sizeof(MeleeAnimation
) );
1461 gamedata
->FreeItem( itm
, Slot
->ItemResRef
, false );
1465 EquipItem(best_slot
);
1466 UpdateWeaponAnimation();
1469 #define ID_NONEED 0 //id is not important
1470 #define ID_NEED 1 //id is important
1471 #define ID_NO 2 //shouldn't id
1473 /* returns true if there are more item usages not fitting in given array */
1474 bool Inventory::GetEquipmentInfo(ItemExtHeader
*array
, int startindex
, int count
)
1478 memset(array
, 0, count
* sizeof(ItemExtHeader
) );
1479 for(unsigned int idx
=0;idx
<Slots
.size();idx
++) {
1480 if (!core
->QuerySlotEffects(idx
)) {
1485 const Item
*itm
= GetItemPointer(idx
, slot
);
1489 for(int ehc
=0;ehc
<itm
->ExtHeaderCount
;ehc
++) {
1490 ITMExtHeader
*ext_header
= itm
->ext_headers
+ehc
;
1491 if (ext_header
->Location
!=ITEM_LOC_EQUIPMENT
) {
1494 //skipping if we cannot use the item
1495 int idreq1
= (slot
->Flags
&IE_INV_ITEM_IDENTIFIED
);
1496 int idreq2
= ext_header
->IDReq
;
1499 if (idreq1
) continue;
1502 if (!idreq1
) continue;
1507 if (actual
>startindex
) {
1509 //store the item, return if we can't store more
1511 gamedata
->FreeItem(itm
, slot
->ItemResRef
, false);
1515 memcpy(array
[pos
].itemname
, slot
->ItemResRef
, sizeof(ieResRef
) );
1516 array
[pos
].slot
= idx
;
1517 array
[pos
].headerindex
= ehc
;
1518 int slen
= ((char *) &(array
[pos
].itemname
)) -((char *) &(array
[pos
].AttackType
));
1519 memcpy(&(array
[pos
].AttackType
), &(ext_header
->AttackType
), slen
);
1520 if (ext_header
->Charges
) {
1521 //don't modify ehc, it is a counter
1522 if (ehc
>=CHARGE_COUNTERS
) {
1523 array
[pos
].Charges
=slot
->Usages
[0];
1525 array
[pos
].Charges
=slot
->Usages
[ehc
];
1528 array
[pos
].Charges
=0xffff;
1533 gamedata
->FreeItem(itm
, slot
->ItemResRef
, false);
1539 //The slot index value is optional, if you supply it,
1540 // then ItemExcl will be returned as if the item was already unequipped
1541 ieDword
Inventory::GetEquipExclusion(int index
) const
1547 const Item
*itm
= GetItemPointer(index
, slot
);
1551 ieDword ret
= ItemExcl
&~itm
->ItemExcl
;
1552 gamedata
->FreeItem(itm
, slot
->ItemResRef
, false);
1556 void Inventory::UpdateShieldAnimation(Item
*it
)
1558 char AnimationType
[2]={0,0};
1559 int WeaponType
= -1;
1562 memcpy(AnimationType
, it
->AnimationType
, 2);
1563 if (core
->CanUseItemType(SLOT_WEAPON
, it
))
1564 WeaponType
= IE_ANI_WEAPON_2W
;
1566 WeaponType
= IE_ANI_WEAPON_1H
;
1568 WeaponType
= IE_ANI_WEAPON_1H
;
1570 Owner
->SetUsedShield(AnimationType
, WeaponType
);
1573 void Inventory::UpdateWeaponAnimation()
1575 int slot
= GetEquippedSlot();
1576 int effect
= core
->QuerySlotEffects( slot
);
1577 if (effect
== SLOT_EFFECT_MISSILE
) {
1579 slot
= FindRangedWeapon();
1581 int WeaponType
= -1;
1583 char AnimationType
[2]={0,0};
1584 ieWord MeleeAnimation
[3]={100,0,0};
1589 ITMExtHeader
*header
= 0;
1590 const Item
*itm
= GetItemPointer(slot
, Slot
);
1592 itm
->GetDamagePotential(false, header
);
1593 memcpy(AnimationType
,itm
->AnimationType
,sizeof(AnimationType
) );
1594 //for twohanded flag, you don't need itm
1595 if (Slot
->Flags
& IE_INV_ITEM_TWOHANDED
)
1596 WeaponType
= IE_ANI_WEAPON_2H
;
1599 // Examine shield slot to check if we're using two weapons
1600 // TODO: for consistency, use same Item* access method as above
1601 bool twoweapon
= false;
1602 int slot
= GetShieldSlot();
1605 si
= GetSlotItem( (ieDword
) slot
);
1608 Item
* it
= gamedata
->GetItem(si
->ItemResRef
);
1609 if (core
->CanUseItemType(SLOT_WEAPON
, it
))
1611 gamedata
->FreeItem(it
, si
->ItemResRef
, false);
1615 WeaponType
= IE_ANI_WEAPON_2W
;
1617 WeaponType
= IE_ANI_WEAPON_1H
;
1622 memcpy(MeleeAnimation
,header
->MeleeAnimation
,
1623 sizeof(MeleeAnimation
) );
1625 gamedata
->FreeItem( itm
, Slot
->ItemResRef
, false );
1626 Owner
->SetUsedWeapon(AnimationType
, MeleeAnimation
, WeaponType
);
1629 //this function will also check disabled slots (if that feature will be imped)
1630 bool Inventory::IsSlotBlocked(int slot
) const
1632 if (slot
<SLOT_MELEE
) return false;
1633 if (slot
>LAST_MELEE
) return false;
1638 otherslot
= SLOT_LEFT
;
1640 return HasItemInSlot("",otherslot
);
1643 inline bool Inventory::TwoHandedInSlot(int slot
) const
1647 item
= GetSlotItem(slot
);
1648 if (!item
) return false;
1649 if (item
->Flags
&IE_INV_ITEM_TWOHANDED
) {
1655 int Inventory::WhyCantEquip(int slot
, int twohanded
) const
1657 // check only for hand slots
1658 if ((slot
<SLOT_MELEE
|| slot
>LAST_MELEE
) && (slot
!= SLOT_LEFT
) ) {
1662 //magic items have the highest priority
1663 if ( HasItemInSlot("", SLOT_MAGIC
)) {
1664 //magic weapon is in use
1665 return STR_MAGICWEAPON
;
1668 //can't equip in shield slot if a weapon slot is twohanded
1669 for (int i
=SLOT_MELEE
; i
<=LAST_MELEE
;i
++) {
1675 otherslot
= SLOT_LEFT
;
1677 if (slot
==otherslot
) {
1678 if (TwoHandedInSlot(i
)) {
1679 return STR_TWOHANDED_USED
;
1686 if (slot
>=SLOT_MELEE
&&slot
<=LAST_MELEE
&& (slot
&1) ) {
1687 return STR_NOT_IN_OFFHAND
;
1690 if (slot
==SLOT_LEFT
) {
1691 return STR_NOT_IN_OFFHAND
;
1694 if (IsSlotBlocked(slot
)) {
1695 //cannot equip two handed while shield slot is in use?
1696 return STR_OFFHAND_USED
;
1702 //recharge items on rest, if rest was partial, recharge only 'hours'
1703 //if this latter functionality is unwanted, then simply don't recharge if
1705 void Inventory::ChargeAllItems(int hours
)
1707 //this loop is going from start
1708 for (size_t i
= 0; i
< Slots
.size(); i
++) {
1709 CREItem
*item
= Slots
[i
];
1714 Item
*itm
= gamedata
->GetItem( item
->ItemResRef
);
1717 for(int h
=0;h
<CHARGE_COUNTERS
;h
++) {
1718 ITMExtHeader
*header
= itm
->GetExtHeader(h
);
1719 if (header
&& (header
->RechargeFlags
&IE_ITEM_RECHARGE
)) {
1720 unsigned short add
= header
->Charges
;
1721 if (hours
&& add
>hours
) add
=hours
;
1722 add
+=item
->Usages
[h
];
1723 if(add
>header
->Charges
) add
=header
->Charges
;
1724 item
->Usages
[h
]=add
;
1727 gamedata
->FreeItem( itm
, item
->ItemResRef
, false );
1731 #define ITM_STEALING (IE_INV_ITEM_UNSTEALABLE | IE_INV_ITEM_MOVABLE)
1732 unsigned int Inventory::FindStealableItem()
1737 slot
= core
->Roll(1, Slots
.size(),-1);
1740 printf("Start Slot: %d, increment: %d\n", slot
, inc
);
1741 //as the unsigned value underflows, it will be greater than Slots.size()
1742 for(;slot
<Slots
.size(); slot
+=inc
) {
1743 CREItem
*item
= Slots
[slot
];
1744 //can't steal empty slot
1745 if (!item
) continue;
1746 //bit 1 is stealable slot
1747 if (!(core
->QuerySlotFlags(slot
)&1) ) continue;
1748 //can't steal equipped weapon
1749 if ((unsigned int) (Equipped
+SLOT_MELEE
) == core
->QuerySlot(slot
)) continue;
1750 //can't steal flagged items
1751 if ((item
->Flags
& ITM_STEALING
) != IE_INV_ITEM_MOVABLE
) continue;
1757 // extension to allow more or less than head gear to avert critical hits:
1758 // If an item with bit 25 set is equipped in a non-helmet slot, aversion is enabled
1759 // If an item with bit 25 set is equipped in a helmet slot, aversion is disabled
1760 bool Inventory::ProvidesCriticalAversion()
1762 for (size_t i
= 0; i
< Slots
.size(); i
++) {
1763 CREItem
*item
= Slots
[i
];
1764 if (!item
|| ! (item
->Flags
& IE_INV_ITEM_EQUIPPED
)) {
1768 Item
*itm
= gamedata
->GetItem(item
->ItemResRef
);
1773 for (int h
= 0; h
< itm
->ExtHeaderCount
; h
++) {
1774 ITMExtHeader
*header
= itm
->GetExtHeader(h
);
1775 if ((int)i
== SLOT_HEAD
) {
1776 if (header
&& (header
->RechargeFlags
& IE_ITEM_TOGGLE_CRITS
)) {
1782 if (header
&& (header
->RechargeFlags
& IE_ITEM_TOGGLE_CRITS
)) {