2 * Copyright (C) 2005-2009 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
))
207 case ITEM_SUBCLASS_INSCRIPTION_CONTAINER
:
208 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_INSCRIPTION_SUPP
))
214 case ITEM_CLASS_QUIVER
:
215 switch(pBagProto
->SubClass
)
217 case ITEM_SUBCLASS_QUIVER
:
218 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_ARROWS
))
221 case ITEM_SUBCLASS_AMMO_POUCH
:
222 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_BULLETS
))
234 m_objectType
|= TYPEMASK_ITEM
;
235 m_objectTypeId
= TYPEID_ITEM
;
237 m_updateFlag
= UPDATEFLAG_HIGHGUID
;
239 m_valuesCount
= ITEM_END
;
244 m_lootGenerated
= false;
248 bool Item::Create( uint32 guidlow
, uint32 itemid
, Player
const* owner
)
250 Object::_Create( guidlow
, 0, HIGHGUID_ITEM
);
253 SetFloatValue(OBJECT_FIELD_SCALE_X
, 1.0f
);
255 SetUInt64Value(ITEM_FIELD_OWNER
, owner
? owner
->GetGUID() : 0);
256 SetUInt64Value(ITEM_FIELD_CONTAINED
, owner
? owner
->GetGUID() : 0);
258 ItemPrototype
const *itemProto
= objmgr
.GetItemPrototype(itemid
);
262 SetUInt32Value(ITEM_FIELD_STACK_COUNT
, 1);
263 SetUInt32Value(ITEM_FIELD_MAXDURABILITY
, itemProto
->MaxDurability
);
264 SetUInt32Value(ITEM_FIELD_DURABILITY
, itemProto
->MaxDurability
);
266 for(int i
= 0; i
< MAX_ITEM_PROTO_SPELLS
; ++i
)
267 SetSpellCharges(i
,itemProto
->Spells
[i
].SpellCharges
);
269 SetUInt32Value(ITEM_FIELD_FLAGS
, itemProto
->Flags
);
270 SetUInt32Value(ITEM_FIELD_DURATION
, abs(itemProto
->Duration
));
275 void Item::UpdateDuration(Player
* owner
, uint32 diff
)
277 if (!GetUInt32Value(ITEM_FIELD_DURATION
))
280 sLog
.outDebug("Item::UpdateDuration Item (Entry: %u Duration %u Diff %u)",GetEntry(),GetUInt32Value(ITEM_FIELD_DURATION
),diff
);
282 if (GetUInt32Value(ITEM_FIELD_DURATION
)<=diff
)
284 owner
->DestroyItem(GetBagSlot(), GetSlot(), true);
288 SetUInt32Value(ITEM_FIELD_DURATION
, GetUInt32Value(ITEM_FIELD_DURATION
) - diff
);
289 SetState(ITEM_CHANGED
, owner
); // save new time in database
292 void Item::SaveToDB()
294 uint32 guid
= GetGUIDLow();
299 CharacterDatabase
.PExecute( "DELETE FROM item_instance WHERE guid = '%u'", guid
);
300 std::ostringstream ss
;
301 ss
<< "INSERT INTO item_instance (guid,owner_guid,data) VALUES (" << guid
<< "," << GUID_LOPART(GetOwnerGUID()) << ",'";
302 for(uint16 i
= 0; i
< m_valuesCount
; ++i
)
303 ss
<< GetUInt32Value(i
) << " ";
305 CharacterDatabase
.Execute( ss
.str().c_str() );
309 std::ostringstream ss
;
310 ss
<< "UPDATE item_instance SET data = '";
311 for(uint16 i
= 0; i
< m_valuesCount
; ++i
)
312 ss
<< GetUInt32Value(i
) << " ";
313 ss
<< "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid
<< "'";
315 CharacterDatabase
.Execute( ss
.str().c_str() );
317 if(HasFlag(ITEM_FIELD_FLAGS
, ITEM_FLAGS_WRAPPED
))
318 CharacterDatabase
.PExecute("UPDATE character_gifts SET guid = '%u' WHERE item_guid = '%u'", GUID_LOPART(GetOwnerGUID()),GetGUIDLow());
322 if (GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID
) > 0 )
323 CharacterDatabase
.PExecute("DELETE FROM item_text WHERE id = '%u'", GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID
));
324 CharacterDatabase
.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid
);
325 if(HasFlag(ITEM_FIELD_FLAGS
, ITEM_FLAGS_WRAPPED
))
326 CharacterDatabase
.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
333 SetState(ITEM_UNCHANGED
);
336 bool Item::LoadFromDB(uint32 guid
, uint64 owner_guid
, QueryResult
*result
)
338 // create item before any checks for store correct guid
339 // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
340 Object::_Create(guid
, 0, HIGHGUID_ITEM
);
342 bool delete_result
= false;
345 result
= CharacterDatabase
.PQuery("SELECT data FROM item_instance WHERE guid = '%u'", guid
);
346 delete_result
= true;
351 sLog
.outError("Item (GUID: %u owner: %u) not found in table `item_instance`, can't load. ",guid
,GUID_LOPART(owner_guid
));
355 Field
*fields
= result
->Fetch();
357 if(!LoadValues(fields
[0].GetString()))
359 sLog
.outError("Item #%d have broken data in `data` field. Can't be loaded.",guid
);
360 if (delete_result
) delete result
;
364 bool need_save
= false; // need explicit save data at load fixes
366 // overwrite possible wrong/corrupted guid
367 uint64 new_item_guid
= MAKE_NEW_GUID(guid
,0, HIGHGUID_ITEM
);
368 if(GetUInt64Value(OBJECT_FIELD_GUID
) != new_item_guid
)
370 SetUInt64Value(OBJECT_FIELD_GUID
, MAKE_NEW_GUID(guid
,0, HIGHGUID_ITEM
));
374 if (delete_result
) delete result
;
376 ItemPrototype
const* proto
= GetProto();
380 // recalculate suffix factor
381 if(GetItemRandomPropertyId() < 0)
383 if(UpdateItemSuffixFactor())
387 // Remove bind flag for items vs NO_BIND set
388 if (IsSoulBound() && proto
->Bonding
== NO_BIND
)
390 ApplyModFlag(ITEM_FIELD_FLAGS
,ITEM_FLAGS_BINDED
, false);
394 // update duration if need, and remove if not need
395 if((proto
->Duration
==0) != (GetUInt32Value(ITEM_FIELD_DURATION
)==0))
397 SetUInt32Value(ITEM_FIELD_DURATION
,abs(proto
->Duration
));
402 if(owner_guid
!= 0 && GetOwnerGUID() != owner_guid
)
404 SetOwnerGUID(owner_guid
);
408 if(need_save
) // normal item changed state set not work at loading
410 std::ostringstream ss
;
411 ss
<< "UPDATE item_instance SET data = '";
412 for(uint16 i
= 0; i
< m_valuesCount
; ++i
)
413 ss
<< GetUInt32Value(i
) << " ";
414 ss
<< "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid
<< "'";
416 CharacterDatabase
.Execute( ss
.str().c_str() );
422 void Item::DeleteFromDB()
424 CharacterDatabase
.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
427 void Item::DeleteFromInventoryDB()
429 CharacterDatabase
.PExecute("DELETE FROM character_inventory WHERE item = '%u'",GetGUIDLow());
432 ItemPrototype
const *Item::GetProto() const
434 return objmgr
.GetItemPrototype(GetEntry());
437 Player
* Item::GetOwner()const
439 return objmgr
.GetPlayer(GetOwnerGUID());
442 uint32
Item::GetSkill()
444 const static uint32 item_weapon_skills
[MAX_ITEM_SUBCLASS_WEAPON
] =
446 SKILL_AXES
, SKILL_2H_AXES
, SKILL_BOWS
, SKILL_GUNS
, SKILL_MACES
,
447 SKILL_2H_MACES
, SKILL_POLEARMS
, SKILL_SWORDS
, SKILL_2H_SWORDS
, 0,
448 SKILL_STAVES
, 0, 0, SKILL_UNARMED
, 0,
449 SKILL_DAGGERS
, SKILL_THROWN
, SKILL_ASSASSINATION
, SKILL_CROSSBOWS
, SKILL_WANDS
,
453 const static uint32 item_armor_skills
[MAX_ITEM_SUBCLASS_ARMOR
] =
455 0,SKILL_CLOTH
,SKILL_LEATHER
,SKILL_MAIL
,SKILL_PLATE_MAIL
,0,SKILL_SHIELD
,0,0,0,0
458 ItemPrototype
const* proto
= GetProto();
460 switch (proto
->Class
)
462 case ITEM_CLASS_WEAPON
:
463 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_WEAPON
)
466 return item_weapon_skills
[proto
->SubClass
];
468 case ITEM_CLASS_ARMOR
:
469 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_ARMOR
)
472 return item_armor_skills
[proto
->SubClass
];
479 uint32
Item::GetSpell()
481 ItemPrototype
const* proto
= GetProto();
483 switch (proto
->Class
)
485 case ITEM_CLASS_WEAPON
:
486 switch (proto
->SubClass
)
488 case ITEM_SUBCLASS_WEAPON_AXE
: return 196;
489 case ITEM_SUBCLASS_WEAPON_AXE2
: return 197;
490 case ITEM_SUBCLASS_WEAPON_BOW
: return 264;
491 case ITEM_SUBCLASS_WEAPON_GUN
: return 266;
492 case ITEM_SUBCLASS_WEAPON_MACE
: return 198;
493 case ITEM_SUBCLASS_WEAPON_MACE2
: return 199;
494 case ITEM_SUBCLASS_WEAPON_POLEARM
: return 200;
495 case ITEM_SUBCLASS_WEAPON_SWORD
: return 201;
496 case ITEM_SUBCLASS_WEAPON_SWORD2
: return 202;
497 case ITEM_SUBCLASS_WEAPON_STAFF
: return 227;
498 case ITEM_SUBCLASS_WEAPON_DAGGER
: return 1180;
499 case ITEM_SUBCLASS_WEAPON_THROWN
: return 2567;
500 case ITEM_SUBCLASS_WEAPON_SPEAR
: return 3386;
501 case ITEM_SUBCLASS_WEAPON_CROSSBOW
:return 5011;
502 case ITEM_SUBCLASS_WEAPON_WAND
: return 5009;
505 case ITEM_CLASS_ARMOR
:
506 switch(proto
->SubClass
)
508 case ITEM_SUBCLASS_ARMOR_CLOTH
: return 9078;
509 case ITEM_SUBCLASS_ARMOR_LEATHER
: return 9077;
510 case ITEM_SUBCLASS_ARMOR_MAIL
: return 8737;
511 case ITEM_SUBCLASS_ARMOR_PLATE
: return 750;
512 case ITEM_SUBCLASS_ARMOR_SHIELD
: return 9116;
519 int32
Item::GenerateItemRandomPropertyId(uint32 item_id
)
521 ItemPrototype
const *itemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(item_id
);
526 // item must have one from this field values not null if it can have random enchantments
527 if((!itemProto
->RandomProperty
) && (!itemProto
->RandomSuffix
))
530 // item can have not null only one from field values
531 if((itemProto
->RandomProperty
) && (itemProto
->RandomSuffix
))
533 sLog
.outErrorDb("Item template %u have RandomProperty==%u and RandomSuffix==%u, but must have one from field =0",itemProto
->ItemId
,itemProto
->RandomProperty
,itemProto
->RandomSuffix
);
537 // RandomProperty case
538 if(itemProto
->RandomProperty
)
540 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomProperty
);
541 ItemRandomPropertiesEntry
const *random_id
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
544 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in 'ItemRandomProperties.dbc'",randomPropId
);
548 return random_id
->ID
;
553 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomSuffix
);
554 ItemRandomSuffixEntry
const *random_id
= sItemRandomSuffixStore
.LookupEntry(randomPropId
);
557 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in sItemRandomSuffixStore.",randomPropId
);
561 return -int32(random_id
->ID
);
565 void Item::SetItemRandomProperties(int32 randomPropId
)
572 ItemRandomPropertiesEntry
const *item_rand
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
575 if(GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != int32(item_rand
->ID
))
577 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,item_rand
->ID
);
578 SetState(ITEM_CHANGED
);
580 for(uint32 i
= PROP_ENCHANTMENT_SLOT_2
; i
< PROP_ENCHANTMENT_SLOT_2
+ 3; ++i
)
581 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_2
],0,0);
586 ItemRandomSuffixEntry
const *item_rand
= sItemRandomSuffixStore
.LookupEntry(-randomPropId
);
589 if( GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != -int32(item_rand
->ID
) ||
590 !GetItemSuffixFactor())
592 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,-int32(item_rand
->ID
));
593 UpdateItemSuffixFactor();
594 SetState(ITEM_CHANGED
);
597 for(uint32 i
= PROP_ENCHANTMENT_SLOT_0
; i
< PROP_ENCHANTMENT_SLOT_0
+ 3; ++i
)
598 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_0
],0,0);
603 bool Item::UpdateItemSuffixFactor()
605 uint32 suffixFactor
= GenerateEnchSuffixFactor(GetEntry());
606 if(GetItemSuffixFactor()==suffixFactor
)
608 SetUInt32Value(ITEM_FIELD_PROPERTY_SEED
,suffixFactor
);
612 void Item::SetState(ItemUpdateState state
, Player
*forplayer
)
614 if (uState
== ITEM_NEW
&& state
== ITEM_REMOVED
)
616 // pretend the item never existed
617 RemoveFromUpdateQueueOf(forplayer
);
622 if (state
!= ITEM_UNCHANGED
)
624 // new items must stay in new state until saved
625 if (uState
!= ITEM_NEW
) uState
= state
;
626 AddToUpdateQueueOf(forplayer
);
631 // the item must be removed from the queue manually
633 uState
= ITEM_UNCHANGED
;
637 void Item::AddToUpdateQueueOf(Player
*player
)
639 if (IsInUpdateQueue()) return;
646 sLog
.outError("Item::AddToUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
651 if (player
->GetGUID() != GetOwnerGUID())
653 sLog
.outError("Item::AddToUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
657 if (player
->m_itemUpdateQueueBlocked
) return;
659 player
->m_itemUpdateQueue
.push_back(this);
660 uQueuePos
= player
->m_itemUpdateQueue
.size()-1;
663 void Item::RemoveFromUpdateQueueOf(Player
*player
)
665 if (!IsInUpdateQueue()) return;
672 sLog
.outError("Item::RemoveFromUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
677 if (player
->GetGUID() != GetOwnerGUID())
679 sLog
.outError("Item::RemoveFromUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
683 if (player
->m_itemUpdateQueueBlocked
) return;
685 player
->m_itemUpdateQueue
[uQueuePos
] = NULL
;
689 uint8
Item::GetBagSlot() const
691 return m_container
? m_container
->GetSlot() : uint8(INVENTORY_SLOT_BAG_0
);
694 bool Item::IsEquipped() const
696 return !IsInBag() && m_slot
< EQUIPMENT_SLOT_END
;
699 bool Item::CanBeTraded() const
703 if(IsBag() && (Player::IsBagPos(GetPos()) || !((Bag
const*)this)->IsEmpty()) )
706 if(Player
* owner
= GetOwner())
708 if(owner
->CanUnequipItem(GetPos(),false) != EQUIP_ERR_OK
)
710 if(owner
->GetLootGUID()==GetGUID())
714 if (IsBoundByEnchant())
720 bool Item::IsBoundByEnchant() const
722 // Check all enchants for soulbound
723 for(uint32 enchant_slot
= PERM_ENCHANTMENT_SLOT
; enchant_slot
< MAX_ENCHANTMENT_SLOT
; ++enchant_slot
)
725 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
729 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
733 if(enchantEntry
->slot
& ENCHANTMENT_CAN_SOULBOUND
)
739 bool Item::IsFitToSpellRequirements(SpellEntry
const* spellInfo
) const
741 ItemPrototype
const* proto
= GetProto();
743 if (spellInfo
->EquippedItemClass
!= -1) // -1 == any item class
745 if(spellInfo
->EquippedItemClass
!= int32(proto
->Class
))
746 return false; // wrong item class
748 if(spellInfo
->EquippedItemSubClassMask
!= 0) // 0 == any subclass
750 if((spellInfo
->EquippedItemSubClassMask
& (1 << proto
->SubClass
)) == 0)
751 return false; // subclass not present in mask
755 if(spellInfo
->EquippedItemInventoryTypeMask
!= 0) // 0 == any inventory type
757 if((spellInfo
->EquippedItemInventoryTypeMask
& (1 << proto
->InventoryType
)) == 0)
758 return false; // inventory type not present in mask
764 void Item::SetEnchantment(EnchantmentSlot slot
, uint32 id
, uint32 duration
, uint32 charges
)
766 // Better lost small time at check in comparison lost time at item save to DB.
767 if((GetEnchantmentId(slot
) == id
) && (GetEnchantmentDuration(slot
) == duration
) && (GetEnchantmentCharges(slot
) == charges
))
770 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_ID_OFFSET
,id
);
771 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
772 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
773 SetState(ITEM_CHANGED
);
776 void Item::SetEnchantmentDuration(EnchantmentSlot slot
, uint32 duration
)
778 if(GetEnchantmentDuration(slot
) == duration
)
781 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
782 SetState(ITEM_CHANGED
);
785 void Item::SetEnchantmentCharges(EnchantmentSlot slot
, uint32 charges
)
787 if(GetEnchantmentCharges(slot
) == charges
)
790 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
791 SetState(ITEM_CHANGED
);
794 void Item::ClearEnchantment(EnchantmentSlot slot
)
796 if(!GetEnchantmentId(slot
))
799 for(uint8 x
= 0; x
< 3; ++x
)
800 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ x
, 0);
801 SetState(ITEM_CHANGED
);
804 bool Item::GemsFitSockets() const
807 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
809 uint8 SocketColor
= GetProto()->Socket
[enchant_slot
-SOCK_ENCHANTMENT_SLOT
].Color
;
811 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
814 if(SocketColor
) fits
&= false;
818 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
821 if(SocketColor
) fits
&= false;
827 uint32 gemid
= enchantEntry
->GemID
;
830 ItemPrototype
const* gemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(gemid
);
833 GemPropertiesEntry
const* gemProperty
= sGemPropertiesStore
.LookupEntry(gemProto
->GemProperties
);
835 GemColor
= gemProperty
->color
;
839 fits
&= (GemColor
& SocketColor
) ? true : false;
844 uint8
Item::GetGemCountWithID(uint32 GemID
) const
847 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
849 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
853 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
857 if(GemID
== enchantEntry
->GemID
)
863 uint8
Item::GetGemCountWithLimitCategory(uint32 limitCategory
) const
866 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
868 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
872 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
876 ItemPrototype
const* gemProto
= ObjectMgr::GetItemPrototype(enchantEntry
->GemID
);
880 if(gemProto
->ItemLimitCategory
==limitCategory
)
886 bool Item::IsLimitedToAnotherMapOrZone( uint32 cur_mapId
, uint32 cur_zoneId
) const
888 ItemPrototype
const* proto
= GetProto();
889 return proto
&& (proto
->Map
&& proto
->Map
!= cur_mapId
|| proto
->Area
&& proto
->Area
!= cur_zoneId
);
892 // Though the client has the information in the item's data field,
893 // we have to send SMSG_ITEM_TIME_UPDATE to display the remaining
895 void Item::SendTimeUpdate(Player
* owner
)
897 if (!GetUInt32Value(ITEM_FIELD_DURATION
))
900 WorldPacket
data(SMSG_ITEM_TIME_UPDATE
, (8+4));
901 data
<< (uint64
)GetGUID();
902 data
<< (uint32
)GetUInt32Value(ITEM_FIELD_DURATION
);
903 owner
->GetSession()->SendPacket(&data
);
906 Item
* Item::CreateItem( uint32 item
, uint32 count
, Player
const* player
)
909 return NULL
; //don't create item at zero count
911 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype( item
);
914 if ( count
> pProto
->GetMaxStackSize())
915 count
= pProto
->GetMaxStackSize();
917 assert(count
!=0 && "pProto->Stackable==0 but checked at loading already");
919 Item
*pItem
= NewItemOrBag( pProto
);
920 if( pItem
->Create(objmgr
.GenerateLowGuid(HIGHGUID_ITEM
), item
, player
) )
922 pItem
->SetCount( count
);
931 Item
* Item::CloneItem( uint32 count
, Player
const* player
) const
933 Item
* newItem
= CreateItem( GetEntry(), count
, player
);
937 newItem
->SetUInt32Value( ITEM_FIELD_CREATOR
, GetUInt32Value( ITEM_FIELD_CREATOR
) );
938 newItem
->SetUInt32Value( ITEM_FIELD_GIFTCREATOR
, GetUInt32Value( ITEM_FIELD_GIFTCREATOR
) );
939 newItem
->SetUInt32Value( ITEM_FIELD_FLAGS
, GetUInt32Value( ITEM_FIELD_FLAGS
) );
940 newItem
->SetUInt32Value( ITEM_FIELD_DURATION
, GetUInt32Value( ITEM_FIELD_DURATION
) );
941 newItem
->SetItemRandomProperties(GetItemRandomPropertyId());