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 "ObjectDefines.h"
23 #include "WorldPacket.h"
24 #include "Database/DatabaseEnv.h"
25 #include "ItemEnchantmentMgr.h"
27 void AddItemsSetItem(Player
*player
,Item
*item
)
29 ItemPrototype
const *proto
= item
->GetProto();
30 uint32 setid
= proto
->ItemSet
;
32 ItemSetEntry
const *set
= sItemSetStore
.LookupEntry(setid
);
36 sLog
.outErrorDb("Item set %u for item (id %u) not found, mods not applied.",setid
,proto
->ItemId
);
40 if( set
->required_skill_id
&& player
->GetSkillValue(set
->required_skill_id
) < set
->required_skill_value
)
43 ItemSetEffect
*eff
= NULL
;
45 for(size_t x
= 0; x
< player
->ItemSetEff
.size(); ++x
)
47 if(player
->ItemSetEff
[x
] && player
->ItemSetEff
[x
]->setid
== setid
)
49 eff
= player
->ItemSetEff
[x
];
56 eff
= new ItemSetEffect
;
57 memset(eff
,0,sizeof(ItemSetEffect
));
61 for(; x
< player
->ItemSetEff
.size(); x
++)
62 if(!player
->ItemSetEff
[x
])
65 if(x
< player
->ItemSetEff
.size())
66 player
->ItemSetEff
[x
]=eff
;
68 player
->ItemSetEff
.push_back(eff
);
73 for(uint32 x
=0;x
<8;x
++)
77 //not enough for spell
78 if(set
->items_to_triggerspell
[x
] > eff
->item_count
)
83 if(eff
->spells
[z
] && eff
->spells
[z
]->Id
==set
->spells
[x
])
90 for(uint32 y
=0;y
<8;y
++)
92 if(!eff
->spells
[y
]) // free slot
94 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(set
->spells
[x
]);
97 sLog
.outError("WORLD: unknown spell id %u in items set %u effects", set
->spells
[x
],setid
);
101 // spell casted only if fit form requirement, in other case will casted at form change
102 player
->ApplyEquipSpell(spellInfo
,NULL
,true);
103 eff
->spells
[y
] = spellInfo
;
110 void RemoveItemsSetItem(Player
*player
,ItemPrototype
const *proto
)
112 uint32 setid
= proto
->ItemSet
;
114 ItemSetEntry
const *set
= sItemSetStore
.LookupEntry(setid
);
118 sLog
.outErrorDb("Item set #%u for item #%u not found, mods not removed.",setid
,proto
->ItemId
);
122 ItemSetEffect
*eff
= NULL
;
124 for(;setindex
< player
->ItemSetEff
.size(); setindex
++)
126 if(player
->ItemSetEff
[setindex
] && player
->ItemSetEff
[setindex
]->setid
== setid
)
128 eff
= player
->ItemSetEff
[setindex
];
133 // can be in case now enough skill requirement for set appling but set has been appliend when skill requirement not enough
139 for(uint32 x
=0;x
<8;x
++)
145 if(set
->items_to_triggerspell
[x
] <= eff
->item_count
)
148 for(uint32 z
=0;z
<8;z
++)
150 if(eff
->spells
[z
] && eff
->spells
[z
]->Id
==set
->spells
[x
])
152 // spell can be not active if not fit form requirement
153 player
->ApplyEquipSpell(eff
->spells
[z
],NULL
,false);
160 if(!eff
->item_count
) //all items of a set were removed
162 assert(eff
== player
->ItemSetEff
[setindex
]);
164 player
->ItemSetEff
[setindex
] = NULL
;
168 bool ItemCanGoIntoBag(ItemPrototype
const *pProto
, ItemPrototype
const *pBagProto
)
170 if(!pProto
|| !pBagProto
)
173 switch(pBagProto
->Class
)
175 case ITEM_CLASS_CONTAINER
:
176 switch(pBagProto
->SubClass
)
178 case ITEM_SUBCLASS_CONTAINER
:
180 case ITEM_SUBCLASS_SOUL_CONTAINER
:
181 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_SOUL_SHARDS
))
184 case ITEM_SUBCLASS_HERB_CONTAINER
:
185 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_HERBS
))
188 case ITEM_SUBCLASS_ENCHANTING_CONTAINER
:
189 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_ENCHANTING_SUPP
))
192 case ITEM_SUBCLASS_MINING_CONTAINER
:
193 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_MINING_SUPP
))
196 case ITEM_SUBCLASS_ENGINEERING_CONTAINER
:
197 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_ENGINEERING_SUPP
))
200 case ITEM_SUBCLASS_GEM_CONTAINER
:
201 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_GEMS
))
204 case ITEM_SUBCLASS_LEATHERWORKING_CONTAINER
:
205 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_LEATHERWORKING_SUPP
))
208 case ITEM_SUBCLASS_INSCRIPTION_CONTAINER
:
209 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_INSCRIPTION_SUPP
))
215 case ITEM_CLASS_QUIVER
:
216 switch(pBagProto
->SubClass
)
218 case ITEM_SUBCLASS_QUIVER
:
219 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_ARROWS
))
222 case ITEM_SUBCLASS_AMMO_POUCH
:
223 if(!(pProto
->BagFamily
& BAG_FAMILY_MASK_BULLETS
))
235 m_objectType
|= TYPEMASK_ITEM
;
236 m_objectTypeId
= TYPEID_ITEM
;
238 m_updateFlag
= UPDATEFLAG_HIGHGUID
;
240 m_valuesCount
= ITEM_END
;
245 m_lootGenerated
= false;
249 bool Item::Create( uint32 guidlow
, uint32 itemid
, Player
const* owner
)
251 Object::_Create( guidlow
, 0, HIGHGUID_ITEM
);
254 SetFloatValue(OBJECT_FIELD_SCALE_X
, 1.0f
);
256 SetUInt64Value(ITEM_FIELD_OWNER
, owner
? owner
->GetGUID() : 0);
257 SetUInt64Value(ITEM_FIELD_CONTAINED
, owner
? owner
->GetGUID() : 0);
259 ItemPrototype
const *itemProto
= ObjectMgr::GetItemPrototype(itemid
);
263 SetUInt32Value(ITEM_FIELD_STACK_COUNT
, 1);
264 SetUInt32Value(ITEM_FIELD_MAXDURABILITY
, itemProto
->MaxDurability
);
265 SetUInt32Value(ITEM_FIELD_DURABILITY
, itemProto
->MaxDurability
);
267 for(int i
= 0; i
< MAX_ITEM_PROTO_SPELLS
; ++i
)
268 SetSpellCharges(i
,itemProto
->Spells
[i
].SpellCharges
);
270 SetUInt32Value(ITEM_FIELD_FLAGS
, itemProto
->Flags
);
271 SetUInt32Value(ITEM_FIELD_DURATION
, abs(itemProto
->Duration
));
276 void Item::UpdateDuration(Player
* owner
, uint32 diff
)
278 if (!GetUInt32Value(ITEM_FIELD_DURATION
))
281 sLog
.outDebug("Item::UpdateDuration Item (Entry: %u Duration %u Diff %u)",GetEntry(),GetUInt32Value(ITEM_FIELD_DURATION
),diff
);
283 if (GetUInt32Value(ITEM_FIELD_DURATION
)<=diff
)
285 owner
->DestroyItem(GetBagSlot(), GetSlot(), true);
289 SetUInt32Value(ITEM_FIELD_DURATION
, GetUInt32Value(ITEM_FIELD_DURATION
) - diff
);
290 SetState(ITEM_CHANGED
, owner
); // save new time in database
293 void Item::SaveToDB()
295 uint32 guid
= GetGUIDLow();
300 CharacterDatabase
.PExecute( "DELETE FROM item_instance WHERE guid = '%u'", guid
);
301 std::ostringstream ss
;
302 ss
<< "INSERT INTO item_instance (guid,owner_guid,data) VALUES (" << guid
<< "," << GUID_LOPART(GetOwnerGUID()) << ",'";
303 for(uint16 i
= 0; i
< m_valuesCount
; ++i
)
304 ss
<< GetUInt32Value(i
) << " ";
306 CharacterDatabase
.Execute( ss
.str().c_str() );
310 std::ostringstream ss
;
311 ss
<< "UPDATE item_instance SET data = '";
312 for(uint16 i
= 0; i
< m_valuesCount
; ++i
)
313 ss
<< GetUInt32Value(i
) << " ";
314 ss
<< "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid
<< "'";
316 CharacterDatabase
.Execute( ss
.str().c_str() );
318 if(HasFlag(ITEM_FIELD_FLAGS
, ITEM_FLAGS_WRAPPED
))
319 CharacterDatabase
.PExecute("UPDATE character_gifts SET guid = '%u' WHERE item_guid = '%u'", GUID_LOPART(GetOwnerGUID()),GetGUIDLow());
323 if (GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID
) > 0 )
324 CharacterDatabase
.PExecute("DELETE FROM item_text WHERE id = '%u'", GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID
));
325 CharacterDatabase
.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid
);
326 if(HasFlag(ITEM_FIELD_FLAGS
, ITEM_FLAGS_WRAPPED
))
327 CharacterDatabase
.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
334 SetState(ITEM_UNCHANGED
);
337 bool Item::LoadFromDB(uint32 guid
, uint64 owner_guid
, QueryResult
*result
)
339 // create item before any checks for store correct guid
340 // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
341 Object::_Create(guid
, 0, HIGHGUID_ITEM
);
343 bool delete_result
= false;
346 result
= CharacterDatabase
.PQuery("SELECT data FROM item_instance WHERE guid = '%u'", guid
);
347 delete_result
= true;
352 sLog
.outError("Item (GUID: %u owner: %u) not found in table `item_instance`, can't load. ",guid
,GUID_LOPART(owner_guid
));
356 Field
*fields
= result
->Fetch();
358 if(!LoadValues(fields
[0].GetString()))
360 sLog
.outError("Item #%d have broken data in `data` field. Can't be loaded.",guid
);
361 if (delete_result
) delete result
;
365 bool need_save
= false; // need explicit save data at load fixes
367 // overwrite possible wrong/corrupted guid
368 uint64 new_item_guid
= MAKE_NEW_GUID(guid
,0, HIGHGUID_ITEM
);
369 if(GetUInt64Value(OBJECT_FIELD_GUID
) != new_item_guid
)
371 SetUInt64Value(OBJECT_FIELD_GUID
, MAKE_NEW_GUID(guid
,0, HIGHGUID_ITEM
));
375 if (delete_result
) delete result
;
377 ItemPrototype
const* proto
= GetProto();
381 // update max durability (and durability) if need
382 if(proto
->MaxDurability
!= GetUInt32Value(ITEM_FIELD_MAXDURABILITY
))
384 SetUInt32Value(ITEM_FIELD_MAXDURABILITY
,proto
->MaxDurability
);
385 if(GetUInt32Value(ITEM_FIELD_DURABILITY
) > proto
->MaxDurability
)
386 SetUInt32Value(ITEM_FIELD_DURABILITY
,proto
->MaxDurability
);
391 // recalculate suffix factor
392 if(GetItemRandomPropertyId() < 0)
394 if(UpdateItemSuffixFactor())
398 // Remove bind flag for items vs NO_BIND set
399 if (IsSoulBound() && proto
->Bonding
== NO_BIND
)
401 ApplyModFlag(ITEM_FIELD_FLAGS
,ITEM_FLAGS_BINDED
, false);
405 // update duration if need, and remove if not need
406 if((proto
->Duration
==0) != (GetUInt32Value(ITEM_FIELD_DURATION
)==0))
408 SetUInt32Value(ITEM_FIELD_DURATION
,abs(proto
->Duration
));
413 if(owner_guid
!= 0 && GetOwnerGUID() != owner_guid
)
415 SetOwnerGUID(owner_guid
);
419 if(need_save
) // normal item changed state set not work at loading
421 std::ostringstream ss
;
422 ss
<< "UPDATE item_instance SET data = '";
423 for(uint16 i
= 0; i
< m_valuesCount
; ++i
)
424 ss
<< GetUInt32Value(i
) << " ";
425 ss
<< "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid
<< "'";
427 CharacterDatabase
.Execute( ss
.str().c_str() );
433 void Item::DeleteFromDB()
435 CharacterDatabase
.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
438 void Item::DeleteFromInventoryDB()
440 CharacterDatabase
.PExecute("DELETE FROM character_inventory WHERE item = '%u'",GetGUIDLow());
443 ItemPrototype
const *Item::GetProto() const
445 return ObjectMgr::GetItemPrototype(GetEntry());
448 Player
* Item::GetOwner()const
450 return sObjectMgr
.GetPlayer(GetOwnerGUID());
453 uint32
Item::GetSkill()
455 const static uint32 item_weapon_skills
[MAX_ITEM_SUBCLASS_WEAPON
] =
457 SKILL_AXES
, SKILL_2H_AXES
, SKILL_BOWS
, SKILL_GUNS
, SKILL_MACES
,
458 SKILL_2H_MACES
, SKILL_POLEARMS
, SKILL_SWORDS
, SKILL_2H_SWORDS
, 0,
459 SKILL_STAVES
, 0, 0, SKILL_UNARMED
, 0,
460 SKILL_DAGGERS
, SKILL_THROWN
, SKILL_ASSASSINATION
, SKILL_CROSSBOWS
, SKILL_WANDS
,
464 const static uint32 item_armor_skills
[MAX_ITEM_SUBCLASS_ARMOR
] =
466 0,SKILL_CLOTH
,SKILL_LEATHER
,SKILL_MAIL
,SKILL_PLATE_MAIL
,0,SKILL_SHIELD
,0,0,0,0
469 ItemPrototype
const* proto
= GetProto();
471 switch (proto
->Class
)
473 case ITEM_CLASS_WEAPON
:
474 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_WEAPON
)
477 return item_weapon_skills
[proto
->SubClass
];
479 case ITEM_CLASS_ARMOR
:
480 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_ARMOR
)
483 return item_armor_skills
[proto
->SubClass
];
490 uint32
Item::GetSpell()
492 ItemPrototype
const* proto
= GetProto();
494 switch (proto
->Class
)
496 case ITEM_CLASS_WEAPON
:
497 switch (proto
->SubClass
)
499 case ITEM_SUBCLASS_WEAPON_AXE
: return 196;
500 case ITEM_SUBCLASS_WEAPON_AXE2
: return 197;
501 case ITEM_SUBCLASS_WEAPON_BOW
: return 264;
502 case ITEM_SUBCLASS_WEAPON_GUN
: return 266;
503 case ITEM_SUBCLASS_WEAPON_MACE
: return 198;
504 case ITEM_SUBCLASS_WEAPON_MACE2
: return 199;
505 case ITEM_SUBCLASS_WEAPON_POLEARM
: return 200;
506 case ITEM_SUBCLASS_WEAPON_SWORD
: return 201;
507 case ITEM_SUBCLASS_WEAPON_SWORD2
: return 202;
508 case ITEM_SUBCLASS_WEAPON_STAFF
: return 227;
509 case ITEM_SUBCLASS_WEAPON_DAGGER
: return 1180;
510 case ITEM_SUBCLASS_WEAPON_THROWN
: return 2567;
511 case ITEM_SUBCLASS_WEAPON_SPEAR
: return 3386;
512 case ITEM_SUBCLASS_WEAPON_CROSSBOW
:return 5011;
513 case ITEM_SUBCLASS_WEAPON_WAND
: return 5009;
516 case ITEM_CLASS_ARMOR
:
517 switch(proto
->SubClass
)
519 case ITEM_SUBCLASS_ARMOR_CLOTH
: return 9078;
520 case ITEM_SUBCLASS_ARMOR_LEATHER
: return 9077;
521 case ITEM_SUBCLASS_ARMOR_MAIL
: return 8737;
522 case ITEM_SUBCLASS_ARMOR_PLATE
: return 750;
523 case ITEM_SUBCLASS_ARMOR_SHIELD
: return 9116;
530 int32
Item::GenerateItemRandomPropertyId(uint32 item_id
)
532 ItemPrototype
const *itemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(item_id
);
537 // item must have one from this field values not null if it can have random enchantments
538 if((!itemProto
->RandomProperty
) && (!itemProto
->RandomSuffix
))
541 // item can have not null only one from field values
542 if((itemProto
->RandomProperty
) && (itemProto
->RandomSuffix
))
544 sLog
.outErrorDb("Item template %u have RandomProperty==%u and RandomSuffix==%u, but must have one from field =0",itemProto
->ItemId
,itemProto
->RandomProperty
,itemProto
->RandomSuffix
);
548 // RandomProperty case
549 if(itemProto
->RandomProperty
)
551 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomProperty
);
552 ItemRandomPropertiesEntry
const *random_id
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
555 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in 'ItemRandomProperties.dbc'",randomPropId
);
559 return random_id
->ID
;
564 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomSuffix
);
565 ItemRandomSuffixEntry
const *random_id
= sItemRandomSuffixStore
.LookupEntry(randomPropId
);
568 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in sItemRandomSuffixStore.",randomPropId
);
572 return -int32(random_id
->ID
);
576 void Item::SetItemRandomProperties(int32 randomPropId
)
583 ItemRandomPropertiesEntry
const *item_rand
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
586 if(GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != int32(item_rand
->ID
))
588 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,item_rand
->ID
);
589 SetState(ITEM_CHANGED
);
591 for(uint32 i
= PROP_ENCHANTMENT_SLOT_2
; i
< PROP_ENCHANTMENT_SLOT_2
+ 3; ++i
)
592 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_2
],0,0);
597 ItemRandomSuffixEntry
const *item_rand
= sItemRandomSuffixStore
.LookupEntry(-randomPropId
);
600 if( GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != -int32(item_rand
->ID
) ||
601 !GetItemSuffixFactor())
603 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,-int32(item_rand
->ID
));
604 UpdateItemSuffixFactor();
605 SetState(ITEM_CHANGED
);
608 for(uint32 i
= PROP_ENCHANTMENT_SLOT_0
; i
< PROP_ENCHANTMENT_SLOT_0
+ 3; ++i
)
609 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_0
],0,0);
614 bool Item::UpdateItemSuffixFactor()
616 uint32 suffixFactor
= GenerateEnchSuffixFactor(GetEntry());
617 if(GetItemSuffixFactor()==suffixFactor
)
619 SetUInt32Value(ITEM_FIELD_PROPERTY_SEED
,suffixFactor
);
623 void Item::SetState(ItemUpdateState state
, Player
*forplayer
)
625 if (uState
== ITEM_NEW
&& state
== ITEM_REMOVED
)
627 // pretend the item never existed
628 RemoveFromUpdateQueueOf(forplayer
);
633 if (state
!= ITEM_UNCHANGED
)
635 // new items must stay in new state until saved
636 if (uState
!= ITEM_NEW
) uState
= state
;
637 AddToUpdateQueueOf(forplayer
);
642 // the item must be removed from the queue manually
644 uState
= ITEM_UNCHANGED
;
648 void Item::AddToUpdateQueueOf(Player
*player
)
650 if (IsInUpdateQueue()) return;
657 sLog
.outError("Item::AddToUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
662 if (player
->GetGUID() != GetOwnerGUID())
664 sLog
.outError("Item::AddToUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
668 if (player
->m_itemUpdateQueueBlocked
) return;
670 player
->m_itemUpdateQueue
.push_back(this);
671 uQueuePos
= player
->m_itemUpdateQueue
.size()-1;
674 void Item::RemoveFromUpdateQueueOf(Player
*player
)
676 if (!IsInUpdateQueue()) return;
683 sLog
.outError("Item::RemoveFromUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
688 if (player
->GetGUID() != GetOwnerGUID())
690 sLog
.outError("Item::RemoveFromUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
694 if (player
->m_itemUpdateQueueBlocked
) return;
696 player
->m_itemUpdateQueue
[uQueuePos
] = NULL
;
700 uint8
Item::GetBagSlot() const
702 return m_container
? m_container
->GetSlot() : uint8(INVENTORY_SLOT_BAG_0
);
705 bool Item::IsEquipped() const
707 return !IsInBag() && m_slot
< EQUIPMENT_SLOT_END
;
710 bool Item::CanBeTraded(bool mail
) const
712 if ((!mail
|| !IsBoundAccountWide()) && IsSoulBound())
715 if (IsBag() && (Player::IsBagPos(GetPos()) || !((Bag
const*)this)->IsEmpty()) )
718 if (Player
* owner
= GetOwner())
720 if (owner
->CanUnequipItem(GetPos(),false) != EQUIP_ERR_OK
)
722 if (owner
->GetLootGUID()==GetGUID())
726 if (IsBoundByEnchant())
732 bool Item::IsBoundByEnchant() const
734 // Check all enchants for soulbound
735 for(uint32 enchant_slot
= PERM_ENCHANTMENT_SLOT
; enchant_slot
< MAX_ENCHANTMENT_SLOT
; ++enchant_slot
)
737 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
741 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
745 if(enchantEntry
->slot
& ENCHANTMENT_CAN_SOULBOUND
)
751 bool Item::IsFitToSpellRequirements(SpellEntry
const* spellInfo
) const
753 ItemPrototype
const* proto
= GetProto();
755 if (spellInfo
->EquippedItemClass
!= -1) // -1 == any item class
757 if(spellInfo
->EquippedItemClass
!= int32(proto
->Class
))
758 return false; // wrong item class
760 if(spellInfo
->EquippedItemSubClassMask
!= 0) // 0 == any subclass
762 if((spellInfo
->EquippedItemSubClassMask
& (1 << proto
->SubClass
)) == 0)
763 return false; // subclass not present in mask
767 if(spellInfo
->EquippedItemInventoryTypeMask
!= 0) // 0 == any inventory type
769 if((spellInfo
->EquippedItemInventoryTypeMask
& (1 << proto
->InventoryType
)) == 0)
770 return false; // inventory type not present in mask
776 bool Item::IsTargetValidForItemUse(Unit
* pUnitTarget
)
778 ItemRequiredTargetMapBounds bounds
= sObjectMgr
.GetItemRequiredTargetMapBounds(GetProto()->ItemId
);
780 if (bounds
.first
== bounds
.second
)
786 for(ItemRequiredTargetMap::const_iterator itr
= bounds
.first
; itr
!= bounds
.second
; ++itr
)
787 if(itr
->second
.IsFitToRequirements(pUnitTarget
))
793 void Item::SetEnchantment(EnchantmentSlot slot
, uint32 id
, uint32 duration
, uint32 charges
)
795 // Better lost small time at check in comparison lost time at item save to DB.
796 if((GetEnchantmentId(slot
) == id
) && (GetEnchantmentDuration(slot
) == duration
) && (GetEnchantmentCharges(slot
) == charges
))
799 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_ID_OFFSET
,id
);
800 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
801 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
802 SetState(ITEM_CHANGED
);
805 void Item::SetEnchantmentDuration(EnchantmentSlot slot
, uint32 duration
)
807 if(GetEnchantmentDuration(slot
) == duration
)
810 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
811 SetState(ITEM_CHANGED
);
814 void Item::SetEnchantmentCharges(EnchantmentSlot slot
, uint32 charges
)
816 if(GetEnchantmentCharges(slot
) == charges
)
819 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
820 SetState(ITEM_CHANGED
);
823 void Item::ClearEnchantment(EnchantmentSlot slot
)
825 if(!GetEnchantmentId(slot
))
828 for(uint8 x
= 0; x
< 3; ++x
)
829 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ x
, 0);
830 SetState(ITEM_CHANGED
);
833 bool Item::GemsFitSockets() const
836 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
838 uint8 SocketColor
= GetProto()->Socket
[enchant_slot
-SOCK_ENCHANTMENT_SLOT
].Color
;
840 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
843 if(SocketColor
) fits
&= false;
847 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
850 if(SocketColor
) fits
&= false;
856 uint32 gemid
= enchantEntry
->GemID
;
859 ItemPrototype
const* gemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(gemid
);
862 GemPropertiesEntry
const* gemProperty
= sGemPropertiesStore
.LookupEntry(gemProto
->GemProperties
);
864 GemColor
= gemProperty
->color
;
868 fits
&= (GemColor
& SocketColor
) ? true : false;
873 uint8
Item::GetGemCountWithID(uint32 GemID
) const
876 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
878 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
882 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
886 if(GemID
== enchantEntry
->GemID
)
892 uint8
Item::GetGemCountWithLimitCategory(uint32 limitCategory
) const
895 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
897 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
901 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
905 ItemPrototype
const* gemProto
= ObjectMgr::GetItemPrototype(enchantEntry
->GemID
);
909 if(gemProto
->ItemLimitCategory
==limitCategory
)
915 bool Item::IsLimitedToAnotherMapOrZone( uint32 cur_mapId
, uint32 cur_zoneId
) const
917 ItemPrototype
const* proto
= GetProto();
918 return proto
&& (proto
->Map
&& proto
->Map
!= cur_mapId
|| proto
->Area
&& proto
->Area
!= cur_zoneId
);
921 // Though the client has the information in the item's data field,
922 // we have to send SMSG_ITEM_TIME_UPDATE to display the remaining
924 void Item::SendTimeUpdate(Player
* owner
)
926 if (!GetUInt32Value(ITEM_FIELD_DURATION
))
929 WorldPacket
data(SMSG_ITEM_TIME_UPDATE
, (8+4));
930 data
<< (uint64
)GetGUID();
931 data
<< (uint32
)GetUInt32Value(ITEM_FIELD_DURATION
);
932 owner
->GetSession()->SendPacket(&data
);
935 Item
* Item::CreateItem( uint32 item
, uint32 count
, Player
const* player
)
938 return NULL
; //don't create item at zero count
940 ItemPrototype
const *pProto
= ObjectMgr::GetItemPrototype( item
);
943 if ( count
> pProto
->GetMaxStackSize())
944 count
= pProto
->GetMaxStackSize();
946 assert(count
!=0 && "pProto->Stackable==0 but checked at loading already");
948 Item
*pItem
= NewItemOrBag( pProto
);
949 if( pItem
->Create(sObjectMgr
.GenerateLowGuid(HIGHGUID_ITEM
), item
, player
) )
951 pItem
->SetCount( count
);
960 Item
* Item::CloneItem( uint32 count
, Player
const* player
) const
962 Item
* newItem
= CreateItem( GetEntry(), count
, player
);
966 newItem
->SetUInt32Value( ITEM_FIELD_CREATOR
, GetUInt32Value( ITEM_FIELD_CREATOR
) );
967 newItem
->SetUInt32Value( ITEM_FIELD_GIFTCREATOR
, GetUInt32Value( ITEM_FIELD_GIFTCREATOR
) );
968 newItem
->SetUInt32Value( ITEM_FIELD_FLAGS
, GetUInt32Value( ITEM_FIELD_FLAGS
) );
969 newItem
->SetUInt32Value( ITEM_FIELD_DURATION
, GetUInt32Value( ITEM_FIELD_DURATION
) );
970 newItem
->SetItemRandomProperties(GetItemRandomPropertyId());
974 bool Item::IsBindedNotWith( Player
const* player
) const
981 if(GetOwnerGUID()== player
->GetGUID())
985 if(!IsBoundAccountWide())
989 if(Player
* owner
= sObjectMgr
.GetPlayer(GetOwnerGUID()))
991 return owner
->GetSession()->GetAccountId() != player
->GetSession()->GetAccountId();
996 return sObjectMgr
.GetPlayerAccountIdByGUID(GetOwnerGUID()) != player
->GetSession()->GetAccountId();
1000 void Item::AddToClientUpdateList()
1002 if (Player
* pl
= GetOwner())
1003 pl
->GetMap()->AddUpdateObject(this);
1006 void Item::RemoveFromClientUpdateList()
1008 if (Player
* pl
= GetOwner())
1009 pl
->GetMap()->RemoveUpdateObject(this);
1012 void Item::BuildUpdateData(UpdateDataMapType
& update_players
)
1014 if (Player
* pl
= GetOwner())
1015 BuildUpdateDataForPlayer(pl
, update_players
);
1017 ClearUpdateMask(false);
1020 bool ItemRequiredTarget::IsFitToRequirements( Unit
* pUnitTarget
) const
1022 if(pUnitTarget
->GetTypeId() != TYPEID_UNIT
)
1025 if(pUnitTarget
->GetEntry() != m_uiTargetEntry
)
1030 case ITEM_TARGET_TYPE_CREATURE
:
1031 return pUnitTarget
->isAlive();
1032 case ITEM_TARGET_TYPE_DEAD
:
1033 return !pUnitTarget
->isAlive();