2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "ObjectMgr.h"
22 #include "WorldPacket.h"
23 #include "Database/DatabaseEnv.h"
24 #include "ItemEnchantmentMgr.h"
26 void AddItemsSetItem(Player
*player
,Item
*item
)
28 ItemPrototype
const *proto
= item
->GetProto();
29 uint32 setid
= proto
->ItemSet
;
31 ItemSetEntry
const *set
= sItemSetStore
.LookupEntry(setid
);
35 sLog
.outErrorDb("Item set %u for item (id %u) not found, mods not applied.",setid
,proto
->ItemId
);
39 if( set
->required_skill_id
&& player
->GetSkillValue(set
->required_skill_id
) < set
->required_skill_value
)
42 ItemSetEffect
*eff
= NULL
;
44 for(size_t x
= 0; x
< player
->ItemSetEff
.size(); ++x
)
46 if(player
->ItemSetEff
[x
] && player
->ItemSetEff
[x
]->setid
== setid
)
48 eff
= player
->ItemSetEff
[x
];
55 eff
= new ItemSetEffect
;
56 memset(eff
,0,sizeof(ItemSetEffect
));
60 for(; x
< player
->ItemSetEff
.size(); x
++)
61 if(!player
->ItemSetEff
[x
])
64 if(x
< player
->ItemSetEff
.size())
65 player
->ItemSetEff
[x
]=eff
;
67 player
->ItemSetEff
.push_back(eff
);
72 for(uint32 x
=0;x
<8;x
++)
76 //not enough for spell
77 if(set
->items_to_triggerspell
[x
] > eff
->item_count
)
82 if(eff
->spells
[z
] && eff
->spells
[z
]->Id
==set
->spells
[x
])
89 for(uint32 y
=0;y
<8;y
++)
91 if(!eff
->spells
[y
]) // free slot
93 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(set
->spells
[x
]);
96 sLog
.outError("WORLD: unknown spell id %u in items set %u effects", set
->spells
[x
],setid
);
100 // spell casted only if fit form requirement, in other case will casted at form change
101 player
->ApplyEquipSpell(spellInfo
,NULL
,true);
102 eff
->spells
[y
] = spellInfo
;
109 void RemoveItemsSetItem(Player
*player
,ItemPrototype
const *proto
)
111 uint32 setid
= proto
->ItemSet
;
113 ItemSetEntry
const *set
= sItemSetStore
.LookupEntry(setid
);
117 sLog
.outErrorDb("Item set #%u for item #%u not found, mods not removed.",setid
,proto
->ItemId
);
121 ItemSetEffect
*eff
= NULL
;
123 for(;setindex
< player
->ItemSetEff
.size(); setindex
++)
125 if(player
->ItemSetEff
[setindex
] && player
->ItemSetEff
[setindex
]->setid
== setid
)
127 eff
= player
->ItemSetEff
[setindex
];
132 // can be in case now enough skill requirement for set appling but set has been appliend when skill requirement not enough
138 for(uint32 x
=0;x
<8;x
++)
144 if(set
->items_to_triggerspell
[x
] <= eff
->item_count
)
147 for(uint32 z
=0;z
<8;z
++)
149 if(eff
->spells
[z
] && eff
->spells
[z
]->Id
==set
->spells
[x
])
151 // spell can be not active if not fit form requirement
152 player
->ApplyEquipSpell(eff
->spells
[z
],NULL
,false);
159 if(!eff
->item_count
) //all items of a set were removed
161 assert(eff
== player
->ItemSetEff
[setindex
]);
163 player
->ItemSetEff
[setindex
] = NULL
;
167 bool ItemCanGoIntoBag(ItemPrototype
const *pProto
, ItemPrototype
const *pBagProto
)
169 if(!pProto
|| !pBagProto
)
172 switch(pBagProto
->Class
)
174 case ITEM_CLASS_CONTAINER
:
175 switch(pBagProto
->SubClass
)
177 case ITEM_SUBCLASS_CONTAINER
:
179 case ITEM_SUBCLASS_SOUL_CONTAINER
:
180 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_SOUL_SHARDS
))
183 case ITEM_SUBCLASS_HERB_CONTAINER
:
184 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_HERBS
))
187 case ITEM_SUBCLASS_ENCHANTING_CONTAINER
:
188 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_ENCHANTING_SUPP
))
191 case ITEM_SUBCLASS_MINING_CONTAINER
:
192 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_MINING_SUPP
))
195 case ITEM_SUBCLASS_ENGINEERING_CONTAINER
:
196 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_ENGINEERING_SUPP
))
199 case ITEM_SUBCLASS_GEM_CONTAINER
:
200 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_GEMS
))
203 case ITEM_SUBCLASS_LEATHERWORKING_CONTAINER
:
204 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_LEATHERWORKING_SUPP
))
210 case ITEM_CLASS_QUIVER
:
211 switch(pBagProto
->SubClass
)
213 case ITEM_SUBCLASS_QUIVER
:
214 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_ARROWS
))
217 case ITEM_SUBCLASS_AMMO_POUCH
:
218 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_BULLETS
))
230 m_objectType
|= TYPEMASK_ITEM
;
231 m_objectTypeId
= TYPEID_ITEM
;
233 m_updateFlag
= (UPDATEFLAG_LOWGUID
| UPDATEFLAG_HIGHGUID
);
235 m_valuesCount
= ITEM_END
;
240 m_lootGenerated
= false;
244 bool Item::Create( uint32 guidlow
, uint32 itemid
, Player
const* owner
)
246 Object::_Create( guidlow
, 0, HIGHGUID_ITEM
);
249 SetFloatValue(OBJECT_FIELD_SCALE_X
, 1.0f
);
251 SetUInt64Value(ITEM_FIELD_OWNER
, owner
? owner
->GetGUID() : 0);
252 SetUInt64Value(ITEM_FIELD_CONTAINED
, owner
? owner
->GetGUID() : 0);
254 ItemPrototype
const *itemProto
= objmgr
.GetItemPrototype(itemid
);
258 SetUInt32Value(ITEM_FIELD_STACK_COUNT
, 1);
259 SetUInt32Value(ITEM_FIELD_MAXDURABILITY
, itemProto
->MaxDurability
);
260 SetUInt32Value(ITEM_FIELD_DURABILITY
, itemProto
->MaxDurability
);
262 for(int i
= 0; i
< 5; ++i
)
263 SetSpellCharges(i
,itemProto
->Spells
[i
].SpellCharges
);
265 SetUInt32Value(ITEM_FIELD_FLAGS
, itemProto
->Flags
);
266 SetUInt32Value(ITEM_FIELD_DURATION
, abs(itemProto
->Duration
));
271 void Item::UpdateDuration(Player
* owner
, uint32 diff
)
273 if (!GetUInt32Value(ITEM_FIELD_DURATION
))
276 sLog
.outDebug("Item::UpdateDuration Item (Entry: %u Duration %u Diff %u)",GetEntry(),GetUInt32Value(ITEM_FIELD_DURATION
),diff
);
278 if (GetUInt32Value(ITEM_FIELD_DURATION
)<=diff
)
280 owner
->DestroyItem(GetBagSlot(), GetSlot(), true);
284 SetUInt32Value(ITEM_FIELD_DURATION
, GetUInt32Value(ITEM_FIELD_DURATION
) - diff
);
285 SetState(ITEM_CHANGED
); // save new time in database
288 void Item::SaveToDB()
290 uint32 guid
= GetGUIDLow();
295 CharacterDatabase
.PExecute( "DELETE FROM item_instance WHERE guid = '%u'", guid
);
296 std::ostringstream ss
;
297 ss
<< "INSERT INTO item_instance (guid,owner_guid,data) VALUES (" << guid
<< "," << GUID_LOPART(GetOwnerGUID()) << ",'";
298 for(uint16 i
= 0; i
< m_valuesCount
; i
++ )
299 ss
<< GetUInt32Value(i
) << " ";
301 CharacterDatabase
.Execute( ss
.str().c_str() );
305 std::ostringstream ss
;
306 ss
<< "UPDATE item_instance SET data = '";
307 for(uint16 i
= 0; i
< m_valuesCount
; i
++ )
308 ss
<< GetUInt32Value(i
) << " ";
309 ss
<< "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid
<< "'";
311 CharacterDatabase
.Execute( ss
.str().c_str() );
313 if(HasFlag(ITEM_FIELD_FLAGS
, ITEM_FLAGS_WRAPPED
))
314 CharacterDatabase
.PExecute("UPDATE character_gifts SET guid = '%u' WHERE item_guid = '%u'", GUID_LOPART(GetOwnerGUID()),GetGUIDLow());
318 if (GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID
) > 0 )
319 CharacterDatabase
.PExecute("DELETE FROM item_text WHERE id = '%u'", GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID
));
320 CharacterDatabase
.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid
);
321 if(HasFlag(ITEM_FIELD_FLAGS
, ITEM_FLAGS_WRAPPED
))
322 CharacterDatabase
.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
329 SetState(ITEM_UNCHANGED
);
332 bool Item::LoadFromDB(uint32 guid
, uint64 owner_guid
, QueryResult
*result
)
334 // create item before any checks for store correct guid
335 // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
336 Object::_Create(guid
, 0, HIGHGUID_ITEM
);
338 bool delete_result
= false;
341 result
= CharacterDatabase
.PQuery("SELECT data FROM item_instance WHERE guid = '%u'", guid
);
342 delete_result
= true;
347 sLog
.outError("ERROR: Item (GUID: %u owner: %u) not found in table `item_instance`, can't load. ",guid
,GUID_LOPART(owner_guid
));
351 Field
*fields
= result
->Fetch();
353 if(!LoadValues(fields
[0].GetString()))
355 sLog
.outError("ERROR: Item #%d have broken data in `data` field. Can't be loaded.",guid
);
356 if (delete_result
) delete result
;
360 bool need_save
= false; // need explicit save data at load fixes
362 // overwrite possible wrong/corrupted guid
363 uint64 new_item_guid
= MAKE_NEW_GUID(guid
,0, HIGHGUID_ITEM
);
364 if(GetUInt64Value(OBJECT_FIELD_GUID
) != new_item_guid
)
366 SetUInt64Value(OBJECT_FIELD_GUID
, MAKE_NEW_GUID(guid
,0, HIGHGUID_ITEM
));
370 if (delete_result
) delete result
;
372 ItemPrototype
const* proto
= GetProto();
376 // recalculate suffix factor
377 if(GetItemRandomPropertyId() < 0)
379 if(UpdateItemSuffixFactor())
383 // Remove bind flag for items vs NO_BIND set
384 if (IsSoulBound() && proto
->Bonding
== NO_BIND
)
386 ApplyModFlag(ITEM_FIELD_FLAGS
,ITEM_FLAGS_BINDED
, false);
390 // update duration if need, and remove if not need
391 if((proto
->Duration
==0) != (GetUInt32Value(ITEM_FIELD_DURATION
)==0))
393 SetUInt32Value(ITEM_FIELD_DURATION
,abs(proto
->Duration
));
398 if(owner_guid
!= 0 && GetOwnerGUID() != owner_guid
)
400 SetOwnerGUID(owner_guid
);
404 if(need_save
) // normal item changed state set not work at loading
406 std::ostringstream ss
;
407 ss
<< "UPDATE item_instance SET data = '";
408 for(uint16 i
= 0; i
< m_valuesCount
; i
++ )
409 ss
<< GetUInt32Value(i
) << " ";
410 ss
<< "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid
<< "'";
412 CharacterDatabase
.Execute( ss
.str().c_str() );
418 void Item::DeleteFromDB()
420 CharacterDatabase
.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
423 void Item::DeleteFromInventoryDB()
425 CharacterDatabase
.PExecute("DELETE FROM character_inventory WHERE item = '%u'",GetGUIDLow());
428 ItemPrototype
const *Item::GetProto() const
430 return objmgr
.GetItemPrototype(GetEntry());
433 Player
* Item::GetOwner()const
435 return objmgr
.GetPlayer(GetOwnerGUID());
438 uint32
Item::GetSkill()
440 const static uint32 item_weapon_skills
[MAX_ITEM_SUBCLASS_WEAPON
] =
442 SKILL_AXES
, SKILL_2H_AXES
, SKILL_BOWS
, SKILL_GUNS
, SKILL_MACES
,
443 SKILL_2H_MACES
, SKILL_POLEARMS
, SKILL_SWORDS
, SKILL_2H_SWORDS
, 0,
444 SKILL_STAVES
, 0, 0, SKILL_UNARMED
, 0,
445 SKILL_DAGGERS
, SKILL_THROWN
, SKILL_ASSASSINATION
, SKILL_CROSSBOWS
, SKILL_WANDS
,
449 const static uint32 item_armor_skills
[MAX_ITEM_SUBCLASS_ARMOR
] =
451 0,SKILL_CLOTH
,SKILL_LEATHER
,SKILL_MAIL
,SKILL_PLATE_MAIL
,0,SKILL_SHIELD
,0,0,0
454 ItemPrototype
const* proto
= GetProto();
456 switch (proto
->Class
)
458 case ITEM_CLASS_WEAPON
:
459 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_WEAPON
)
462 return item_weapon_skills
[proto
->SubClass
];
464 case ITEM_CLASS_ARMOR
:
465 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_ARMOR
)
468 return item_armor_skills
[proto
->SubClass
];
475 uint32
Item::GetSpell()
477 ItemPrototype
const* proto
= GetProto();
479 switch (proto
->Class
)
481 case ITEM_CLASS_WEAPON
:
482 switch (proto
->SubClass
)
484 case ITEM_SUBCLASS_WEAPON_AXE
: return 196;
485 case ITEM_SUBCLASS_WEAPON_AXE2
: return 197;
486 case ITEM_SUBCLASS_WEAPON_BOW
: return 264;
487 case ITEM_SUBCLASS_WEAPON_GUN
: return 266;
488 case ITEM_SUBCLASS_WEAPON_MACE
: return 198;
489 case ITEM_SUBCLASS_WEAPON_MACE2
: return 199;
490 case ITEM_SUBCLASS_WEAPON_POLEARM
: return 200;
491 case ITEM_SUBCLASS_WEAPON_SWORD
: return 201;
492 case ITEM_SUBCLASS_WEAPON_SWORD2
: return 202;
493 case ITEM_SUBCLASS_WEAPON_STAFF
: return 227;
494 case ITEM_SUBCLASS_WEAPON_DAGGER
: return 1180;
495 case ITEM_SUBCLASS_WEAPON_THROWN
: return 2567;
496 case ITEM_SUBCLASS_WEAPON_SPEAR
: return 3386;
497 case ITEM_SUBCLASS_WEAPON_CROSSBOW
:return 5011;
498 case ITEM_SUBCLASS_WEAPON_WAND
: return 5009;
501 case ITEM_CLASS_ARMOR
:
502 switch(proto
->SubClass
)
504 case ITEM_SUBCLASS_ARMOR_CLOTH
: return 9078;
505 case ITEM_SUBCLASS_ARMOR_LEATHER
: return 9077;
506 case ITEM_SUBCLASS_ARMOR_MAIL
: return 8737;
507 case ITEM_SUBCLASS_ARMOR_PLATE
: return 750;
508 case ITEM_SUBCLASS_ARMOR_SHIELD
: return 9116;
515 int32
Item::GenerateItemRandomPropertyId(uint32 item_id
)
517 ItemPrototype
const *itemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(item_id
);
522 // item must have one from this field values not null if it can have random enchantments
523 if((!itemProto
->RandomProperty
) && (!itemProto
->RandomSuffix
))
526 // item can have not null only one from field values
527 if((itemProto
->RandomProperty
) && (itemProto
->RandomSuffix
))
529 sLog
.outErrorDb("Item template %u have RandomProperty==%u and RandomSuffix==%u, but must have one from field =0",itemProto
->ItemId
,itemProto
->RandomProperty
,itemProto
->RandomSuffix
);
533 // RandomProperty case
534 if(itemProto
->RandomProperty
)
536 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomProperty
);
537 ItemRandomPropertiesEntry
const *random_id
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
540 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in 'ItemRandomProperties.dbc'",randomPropId
);
544 return random_id
->ID
;
549 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomSuffix
);
550 ItemRandomSuffixEntry
const *random_id
= sItemRandomSuffixStore
.LookupEntry(randomPropId
);
553 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in sItemRandomSuffixStore.",randomPropId
);
557 return -int32(random_id
->ID
);
561 void Item::SetItemRandomProperties(int32 randomPropId
)
568 ItemRandomPropertiesEntry
const *item_rand
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
571 if(GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != int32(item_rand
->ID
))
573 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,item_rand
->ID
);
574 SetState(ITEM_CHANGED
);
576 for(uint32 i
= PROP_ENCHANTMENT_SLOT_2
; i
< PROP_ENCHANTMENT_SLOT_2
+ 3; ++i
)
577 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_2
],0,0);
582 ItemRandomSuffixEntry
const *item_rand
= sItemRandomSuffixStore
.LookupEntry(-randomPropId
);
585 if( GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != -int32(item_rand
->ID
) ||
586 !GetItemSuffixFactor())
588 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,-int32(item_rand
->ID
));
589 UpdateItemSuffixFactor();
590 SetState(ITEM_CHANGED
);
593 for(uint32 i
= PROP_ENCHANTMENT_SLOT_0
; i
< PROP_ENCHANTMENT_SLOT_0
+ 3; ++i
)
594 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_0
],0,0);
599 bool Item::UpdateItemSuffixFactor()
601 uint32 suffixFactor
= GenerateEnchSuffixFactor(GetEntry());
602 if(GetItemSuffixFactor()==suffixFactor
)
604 SetUInt32Value(ITEM_FIELD_PROPERTY_SEED
,suffixFactor
);
608 void Item::SetState(ItemUpdateState state
, Player
*forplayer
)
610 if (uState
== ITEM_NEW
&& state
== ITEM_REMOVED
)
612 // pretend the item never existed
613 RemoveFromUpdateQueueOf(forplayer
);
618 if (state
!= ITEM_UNCHANGED
)
620 // new items must stay in new state until saved
621 if (uState
!= ITEM_NEW
) uState
= state
;
622 AddToUpdateQueueOf(forplayer
);
627 // the item must be removed from the queue manually
629 uState
= ITEM_UNCHANGED
;
633 void Item::AddToUpdateQueueOf(Player
*player
)
635 if (IsInUpdateQueue()) return;
642 sLog
.outError("Item::AddToUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
647 if (player
->GetGUID() != GetOwnerGUID())
649 sLog
.outError("Item::AddToUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
653 if (player
->m_itemUpdateQueueBlocked
) return;
655 player
->m_itemUpdateQueue
.push_back(this);
656 uQueuePos
= player
->m_itemUpdateQueue
.size()-1;
659 void Item::RemoveFromUpdateQueueOf(Player
*player
)
661 if (!IsInUpdateQueue()) return;
668 sLog
.outError("Item::RemoveFromUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
673 if (player
->GetGUID() != GetOwnerGUID())
675 sLog
.outError("Item::RemoveFromUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
679 if (player
->m_itemUpdateQueueBlocked
) return;
681 player
->m_itemUpdateQueue
[uQueuePos
] = NULL
;
685 uint8
Item::GetBagSlot() const
687 return m_container
? m_container
->GetSlot() : uint8(INVENTORY_SLOT_BAG_0
);
690 bool Item::IsEquipped() const
692 return !IsInBag() && m_slot
< EQUIPMENT_SLOT_END
;
695 bool Item::CanBeTraded() const
699 if(IsBag() && (Player::IsBagPos(GetPos()) || !((Bag
const*)this)->IsEmpty()) )
702 if(Player
* owner
= GetOwner())
704 if(owner
->CanUnequipItem(GetPos(),false) != EQUIP_ERR_OK
)
706 if(owner
->GetLootGUID()==GetGUID())
710 if (IsBoundByEnchant())
716 bool Item::IsBoundByEnchant() const
718 // Check all enchants for soulbound
719 for(uint32 enchant_slot
= PERM_ENCHANTMENT_SLOT
; enchant_slot
< MAX_ENCHANTMENT_SLOT
; ++enchant_slot
)
721 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
725 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
729 if(enchantEntry
->slot
& ENCHANTMENT_CAN_SOULBOUND
)
735 bool Item::IsFitToSpellRequirements(SpellEntry
const* spellInfo
) const
737 ItemPrototype
const* proto
= GetProto();
739 if (spellInfo
->EquippedItemClass
!= -1) // -1 == any item class
741 if(spellInfo
->EquippedItemClass
!= int32(proto
->Class
))
742 return false; // wrong item class
744 if(spellInfo
->EquippedItemSubClassMask
!= 0) // 0 == any subclass
746 if((spellInfo
->EquippedItemSubClassMask
& (1 << proto
->SubClass
)) == 0)
747 return false; // subclass not present in mask
751 if(spellInfo
->EquippedItemInventoryTypeMask
!= 0) // 0 == any inventory type
753 if((spellInfo
->EquippedItemInventoryTypeMask
& (1 << proto
->InventoryType
)) == 0)
754 return false; // inventory type not present in mask
760 void Item::SetEnchantment(EnchantmentSlot slot
, uint32 id
, uint32 duration
, uint32 charges
)
762 // Better lost small time at check in comparison lost time at item save to DB.
763 if((GetEnchantmentId(slot
) == id
) && (GetEnchantmentDuration(slot
) == duration
) && (GetEnchantmentCharges(slot
) == charges
))
766 SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_ID_OFFSET
,id
);
767 SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
768 SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
769 SetState(ITEM_CHANGED
);
772 void Item::SetEnchantmentDuration(EnchantmentSlot slot
, uint32 duration
)
774 if(GetEnchantmentDuration(slot
) == duration
)
777 SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
778 SetState(ITEM_CHANGED
);
781 void Item::SetEnchantmentCharges(EnchantmentSlot slot
, uint32 charges
)
783 if(GetEnchantmentCharges(slot
) == charges
)
786 SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
787 SetState(ITEM_CHANGED
);
790 void Item::ClearEnchantment(EnchantmentSlot slot
)
792 if(!GetEnchantmentId(slot
))
795 for(uint8 x
= 0; x
< 3; ++x
)
796 SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+ slot
*MAX_ENCHANTMENT_OFFSET
+ x
, 0);
797 SetState(ITEM_CHANGED
);
800 bool Item::GemsFitSockets() const
803 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+3; ++enchant_slot
)
805 uint8 SocketColor
= GetProto()->Socket
[enchant_slot
-SOCK_ENCHANTMENT_SLOT
].Color
;
807 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
810 if(SocketColor
) fits
&= false;
814 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
817 if(SocketColor
) fits
&= false;
823 uint32 gemid
= enchantEntry
->GemID
;
826 ItemPrototype
const* gemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(gemid
);
829 GemPropertiesEntry
const* gemProperty
= sGemPropertiesStore
.LookupEntry(gemProto
->GemProperties
);
831 GemColor
= gemProperty
->color
;
835 fits
&= (GemColor
& SocketColor
) ? true : false;
840 uint8
Item::GetGemCountWithID(uint32 GemID
) const
843 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+3; ++enchant_slot
)
845 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
849 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
853 if(GemID
== enchantEntry
->GemID
)
859 bool Item::IsLimitedToAnotherMapOrZone( uint32 cur_mapId
, uint32 cur_zoneId
) const
861 ItemPrototype
const* proto
= GetProto();
862 return proto
&& (proto
->Map
&& proto
->Map
!= cur_mapId
|| proto
->Area
&& proto
->Area
!= cur_zoneId
);
865 // Though the client has the information in the item's data field,
866 // we have to send SMSG_ITEM_TIME_UPDATE to display the remaining
868 void Item::SendTimeUpdate(Player
* owner
)
870 if (!GetUInt32Value(ITEM_FIELD_DURATION
))
873 WorldPacket
data(SMSG_ITEM_TIME_UPDATE
, (8+4));
874 data
<< (uint64
)GetGUID();
875 data
<< (uint32
)GetUInt32Value(ITEM_FIELD_DURATION
);
876 owner
->GetSession()->SendPacket(&data
);
879 Item
* Item::CreateItem( uint32 item
, uint32 count
, Player
const* player
)
882 return NULL
; //don't create item at zero count
884 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype( item
);
887 if ( count
> pProto
->Stackable
)
888 count
= pProto
->Stackable
;
890 assert(count
!=0 && "pProto->Stackable==0 but checked at loading already");
892 Item
*pItem
= NewItemOrBag( pProto
);
893 if( pItem
->Create(objmgr
.GenerateLowGuid(HIGHGUID_ITEM
), item
, player
) )
895 pItem
->SetCount( count
);
904 Item
* Item::CloneItem( uint32 count
, Player
const* player
) const
906 Item
* newItem
= CreateItem( GetEntry(), count
, player
);
910 newItem
->SetUInt32Value( ITEM_FIELD_CREATOR
, GetUInt32Value( ITEM_FIELD_CREATOR
) );
911 newItem
->SetUInt32Value( ITEM_FIELD_GIFTCREATOR
, GetUInt32Value( ITEM_FIELD_GIFTCREATOR
) );
912 newItem
->SetUInt32Value( ITEM_FIELD_FLAGS
, GetUInt32Value( ITEM_FIELD_FLAGS
) );
913 newItem
->SetUInt32Value( ITEM_FIELD_DURATION
, GetUInt32Value( ITEM_FIELD_DURATION
) );
914 newItem
->SetItemRandomProperties(GetItemRandomPropertyId());