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 // update max durability (and durability) if need
381 if(proto
->MaxDurability
!= GetUInt32Value(ITEM_FIELD_MAXDURABILITY
))
383 SetUInt32Value(ITEM_FIELD_MAXDURABILITY
,proto
->MaxDurability
);
384 if(GetUInt32Value(ITEM_FIELD_DURABILITY
) > proto
->MaxDurability
)
385 SetUInt32Value(ITEM_FIELD_DURABILITY
,proto
->MaxDurability
);
390 // recalculate suffix factor
391 if(GetItemRandomPropertyId() < 0)
393 if(UpdateItemSuffixFactor())
397 // Remove bind flag for items vs NO_BIND set
398 if (IsSoulBound() && proto
->Bonding
== NO_BIND
)
400 ApplyModFlag(ITEM_FIELD_FLAGS
,ITEM_FLAGS_BINDED
, false);
404 // update duration if need, and remove if not need
405 if((proto
->Duration
==0) != (GetUInt32Value(ITEM_FIELD_DURATION
)==0))
407 SetUInt32Value(ITEM_FIELD_DURATION
,abs(proto
->Duration
));
412 if(owner_guid
!= 0 && GetOwnerGUID() != owner_guid
)
414 SetOwnerGUID(owner_guid
);
418 if(need_save
) // normal item changed state set not work at loading
420 std::ostringstream ss
;
421 ss
<< "UPDATE item_instance SET data = '";
422 for(uint16 i
= 0; i
< m_valuesCount
; ++i
)
423 ss
<< GetUInt32Value(i
) << " ";
424 ss
<< "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid
<< "'";
426 CharacterDatabase
.Execute( ss
.str().c_str() );
432 void Item::DeleteFromDB()
434 CharacterDatabase
.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
437 void Item::DeleteFromInventoryDB()
439 CharacterDatabase
.PExecute("DELETE FROM character_inventory WHERE item = '%u'",GetGUIDLow());
442 ItemPrototype
const *Item::GetProto() const
444 return objmgr
.GetItemPrototype(GetEntry());
447 Player
* Item::GetOwner()const
449 return objmgr
.GetPlayer(GetOwnerGUID());
452 uint32
Item::GetSkill()
454 const static uint32 item_weapon_skills
[MAX_ITEM_SUBCLASS_WEAPON
] =
456 SKILL_AXES
, SKILL_2H_AXES
, SKILL_BOWS
, SKILL_GUNS
, SKILL_MACES
,
457 SKILL_2H_MACES
, SKILL_POLEARMS
, SKILL_SWORDS
, SKILL_2H_SWORDS
, 0,
458 SKILL_STAVES
, 0, 0, SKILL_UNARMED
, 0,
459 SKILL_DAGGERS
, SKILL_THROWN
, SKILL_ASSASSINATION
, SKILL_CROSSBOWS
, SKILL_WANDS
,
463 const static uint32 item_armor_skills
[MAX_ITEM_SUBCLASS_ARMOR
] =
465 0,SKILL_CLOTH
,SKILL_LEATHER
,SKILL_MAIL
,SKILL_PLATE_MAIL
,0,SKILL_SHIELD
,0,0,0,0
468 ItemPrototype
const* proto
= GetProto();
470 switch (proto
->Class
)
472 case ITEM_CLASS_WEAPON
:
473 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_WEAPON
)
476 return item_weapon_skills
[proto
->SubClass
];
478 case ITEM_CLASS_ARMOR
:
479 if( proto
->SubClass
>= MAX_ITEM_SUBCLASS_ARMOR
)
482 return item_armor_skills
[proto
->SubClass
];
489 uint32
Item::GetSpell()
491 ItemPrototype
const* proto
= GetProto();
493 switch (proto
->Class
)
495 case ITEM_CLASS_WEAPON
:
496 switch (proto
->SubClass
)
498 case ITEM_SUBCLASS_WEAPON_AXE
: return 196;
499 case ITEM_SUBCLASS_WEAPON_AXE2
: return 197;
500 case ITEM_SUBCLASS_WEAPON_BOW
: return 264;
501 case ITEM_SUBCLASS_WEAPON_GUN
: return 266;
502 case ITEM_SUBCLASS_WEAPON_MACE
: return 198;
503 case ITEM_SUBCLASS_WEAPON_MACE2
: return 199;
504 case ITEM_SUBCLASS_WEAPON_POLEARM
: return 200;
505 case ITEM_SUBCLASS_WEAPON_SWORD
: return 201;
506 case ITEM_SUBCLASS_WEAPON_SWORD2
: return 202;
507 case ITEM_SUBCLASS_WEAPON_STAFF
: return 227;
508 case ITEM_SUBCLASS_WEAPON_DAGGER
: return 1180;
509 case ITEM_SUBCLASS_WEAPON_THROWN
: return 2567;
510 case ITEM_SUBCLASS_WEAPON_SPEAR
: return 3386;
511 case ITEM_SUBCLASS_WEAPON_CROSSBOW
:return 5011;
512 case ITEM_SUBCLASS_WEAPON_WAND
: return 5009;
515 case ITEM_CLASS_ARMOR
:
516 switch(proto
->SubClass
)
518 case ITEM_SUBCLASS_ARMOR_CLOTH
: return 9078;
519 case ITEM_SUBCLASS_ARMOR_LEATHER
: return 9077;
520 case ITEM_SUBCLASS_ARMOR_MAIL
: return 8737;
521 case ITEM_SUBCLASS_ARMOR_PLATE
: return 750;
522 case ITEM_SUBCLASS_ARMOR_SHIELD
: return 9116;
529 int32
Item::GenerateItemRandomPropertyId(uint32 item_id
)
531 ItemPrototype
const *itemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(item_id
);
536 // item must have one from this field values not null if it can have random enchantments
537 if((!itemProto
->RandomProperty
) && (!itemProto
->RandomSuffix
))
540 // item can have not null only one from field values
541 if((itemProto
->RandomProperty
) && (itemProto
->RandomSuffix
))
543 sLog
.outErrorDb("Item template %u have RandomProperty==%u and RandomSuffix==%u, but must have one from field =0",itemProto
->ItemId
,itemProto
->RandomProperty
,itemProto
->RandomSuffix
);
547 // RandomProperty case
548 if(itemProto
->RandomProperty
)
550 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomProperty
);
551 ItemRandomPropertiesEntry
const *random_id
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
554 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in 'ItemRandomProperties.dbc'",randomPropId
);
558 return random_id
->ID
;
563 uint32 randomPropId
= GetItemEnchantMod(itemProto
->RandomSuffix
);
564 ItemRandomSuffixEntry
const *random_id
= sItemRandomSuffixStore
.LookupEntry(randomPropId
);
567 sLog
.outErrorDb("Enchantment id #%u used but it doesn't have records in sItemRandomSuffixStore.",randomPropId
);
571 return -int32(random_id
->ID
);
575 void Item::SetItemRandomProperties(int32 randomPropId
)
582 ItemRandomPropertiesEntry
const *item_rand
= sItemRandomPropertiesStore
.LookupEntry(randomPropId
);
585 if(GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != int32(item_rand
->ID
))
587 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,item_rand
->ID
);
588 SetState(ITEM_CHANGED
);
590 for(uint32 i
= PROP_ENCHANTMENT_SLOT_2
; i
< PROP_ENCHANTMENT_SLOT_2
+ 3; ++i
)
591 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_2
],0,0);
596 ItemRandomSuffixEntry
const *item_rand
= sItemRandomSuffixStore
.LookupEntry(-randomPropId
);
599 if( GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
) != -int32(item_rand
->ID
) ||
600 !GetItemSuffixFactor())
602 SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID
,-int32(item_rand
->ID
));
603 UpdateItemSuffixFactor();
604 SetState(ITEM_CHANGED
);
607 for(uint32 i
= PROP_ENCHANTMENT_SLOT_0
; i
< PROP_ENCHANTMENT_SLOT_0
+ 3; ++i
)
608 SetEnchantment(EnchantmentSlot(i
),item_rand
->enchant_id
[i
- PROP_ENCHANTMENT_SLOT_0
],0,0);
613 bool Item::UpdateItemSuffixFactor()
615 uint32 suffixFactor
= GenerateEnchSuffixFactor(GetEntry());
616 if(GetItemSuffixFactor()==suffixFactor
)
618 SetUInt32Value(ITEM_FIELD_PROPERTY_SEED
,suffixFactor
);
622 void Item::SetState(ItemUpdateState state
, Player
*forplayer
)
624 if (uState
== ITEM_NEW
&& state
== ITEM_REMOVED
)
626 // pretend the item never existed
627 RemoveFromUpdateQueueOf(forplayer
);
632 if (state
!= ITEM_UNCHANGED
)
634 // new items must stay in new state until saved
635 if (uState
!= ITEM_NEW
) uState
= state
;
636 AddToUpdateQueueOf(forplayer
);
641 // the item must be removed from the queue manually
643 uState
= ITEM_UNCHANGED
;
647 void Item::AddToUpdateQueueOf(Player
*player
)
649 if (IsInUpdateQueue()) return;
656 sLog
.outError("Item::AddToUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
661 if (player
->GetGUID() != GetOwnerGUID())
663 sLog
.outError("Item::AddToUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
667 if (player
->m_itemUpdateQueueBlocked
) return;
669 player
->m_itemUpdateQueue
.push_back(this);
670 uQueuePos
= player
->m_itemUpdateQueue
.size()-1;
673 void Item::RemoveFromUpdateQueueOf(Player
*player
)
675 if (!IsInUpdateQueue()) return;
682 sLog
.outError("Item::RemoveFromUpdateQueueOf - GetPlayer didn't find a player matching owner's guid (%u)!", GUID_LOPART(GetOwnerGUID()));
687 if (player
->GetGUID() != GetOwnerGUID())
689 sLog
.outError("Item::RemoveFromUpdateQueueOf - Owner's guid (%u) and player's guid (%u) don't match!", GUID_LOPART(GetOwnerGUID()), player
->GetGUIDLow());
693 if (player
->m_itemUpdateQueueBlocked
) return;
695 player
->m_itemUpdateQueue
[uQueuePos
] = NULL
;
699 uint8
Item::GetBagSlot() const
701 return m_container
? m_container
->GetSlot() : uint8(INVENTORY_SLOT_BAG_0
);
704 bool Item::IsEquipped() const
706 return !IsInBag() && m_slot
< EQUIPMENT_SLOT_END
;
709 bool Item::CanBeTraded(bool mail
) const
711 if ((!mail
|| !IsBoundAccountWide()) && IsSoulBound())
714 if (IsBag() && (Player::IsBagPos(GetPos()) || !((Bag
const*)this)->IsEmpty()) )
717 if (Player
* owner
= GetOwner())
719 if (owner
->CanUnequipItem(GetPos(),false) != EQUIP_ERR_OK
)
721 if (owner
->GetLootGUID()==GetGUID())
725 if (IsBoundByEnchant())
731 bool Item::IsBoundByEnchant() const
733 // Check all enchants for soulbound
734 for(uint32 enchant_slot
= PERM_ENCHANTMENT_SLOT
; enchant_slot
< MAX_ENCHANTMENT_SLOT
; ++enchant_slot
)
736 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
740 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
744 if(enchantEntry
->slot
& ENCHANTMENT_CAN_SOULBOUND
)
750 bool Item::IsFitToSpellRequirements(SpellEntry
const* spellInfo
) const
752 ItemPrototype
const* proto
= GetProto();
754 if (spellInfo
->EquippedItemClass
!= -1) // -1 == any item class
756 if(spellInfo
->EquippedItemClass
!= int32(proto
->Class
))
757 return false; // wrong item class
759 if(spellInfo
->EquippedItemSubClassMask
!= 0) // 0 == any subclass
761 if((spellInfo
->EquippedItemSubClassMask
& (1 << proto
->SubClass
)) == 0)
762 return false; // subclass not present in mask
766 if(spellInfo
->EquippedItemInventoryTypeMask
!= 0) // 0 == any inventory type
768 if((spellInfo
->EquippedItemInventoryTypeMask
& (1 << proto
->InventoryType
)) == 0)
769 return false; // inventory type not present in mask
775 bool Item::IsTargetValidForItemUse(Unit
* pUnitTarget
)
777 ItemRequiredTargetMapBounds bounds
= objmgr
.GetItemRequiredTargetMapBounds(GetProto()->ItemId
);
779 if (bounds
.first
== bounds
.second
)
785 for(ItemRequiredTargetMap::const_iterator itr
= bounds
.first
; itr
!= bounds
.second
; ++itr
)
786 if(itr
->second
.IsFitToRequirements(pUnitTarget
))
792 void Item::SetEnchantment(EnchantmentSlot slot
, uint32 id
, uint32 duration
, uint32 charges
)
794 // Better lost small time at check in comparison lost time at item save to DB.
795 if((GetEnchantmentId(slot
) == id
) && (GetEnchantmentDuration(slot
) == duration
) && (GetEnchantmentCharges(slot
) == charges
))
798 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_ID_OFFSET
,id
);
799 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
800 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
801 SetState(ITEM_CHANGED
);
804 void Item::SetEnchantmentDuration(EnchantmentSlot slot
, uint32 duration
)
806 if(GetEnchantmentDuration(slot
) == duration
)
809 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_DURATION_OFFSET
,duration
);
810 SetState(ITEM_CHANGED
);
813 void Item::SetEnchantmentCharges(EnchantmentSlot slot
, uint32 charges
)
815 if(GetEnchantmentCharges(slot
) == charges
)
818 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ ENCHANTMENT_CHARGES_OFFSET
,charges
);
819 SetState(ITEM_CHANGED
);
822 void Item::ClearEnchantment(EnchantmentSlot slot
)
824 if(!GetEnchantmentId(slot
))
827 for(uint8 x
= 0; x
< 3; ++x
)
828 SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1
+ slot
*MAX_ENCHANTMENT_OFFSET
+ x
, 0);
829 SetState(ITEM_CHANGED
);
832 bool Item::GemsFitSockets() const
835 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
837 uint8 SocketColor
= GetProto()->Socket
[enchant_slot
-SOCK_ENCHANTMENT_SLOT
].Color
;
839 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
842 if(SocketColor
) fits
&= false;
846 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
849 if(SocketColor
) fits
&= false;
855 uint32 gemid
= enchantEntry
->GemID
;
858 ItemPrototype
const* gemProto
= sItemStorage
.LookupEntry
<ItemPrototype
>(gemid
);
861 GemPropertiesEntry
const* gemProperty
= sGemPropertiesStore
.LookupEntry(gemProto
->GemProperties
);
863 GemColor
= gemProperty
->color
;
867 fits
&= (GemColor
& SocketColor
) ? true : false;
872 uint8
Item::GetGemCountWithID(uint32 GemID
) const
875 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
877 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
881 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
885 if(GemID
== enchantEntry
->GemID
)
891 uint8
Item::GetGemCountWithLimitCategory(uint32 limitCategory
) const
894 for(uint32 enchant_slot
= SOCK_ENCHANTMENT_SLOT
; enchant_slot
< SOCK_ENCHANTMENT_SLOT
+MAX_GEM_SOCKETS
; ++enchant_slot
)
896 uint32 enchant_id
= GetEnchantmentId(EnchantmentSlot(enchant_slot
));
900 SpellItemEnchantmentEntry
const* enchantEntry
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
904 ItemPrototype
const* gemProto
= ObjectMgr::GetItemPrototype(enchantEntry
->GemID
);
908 if(gemProto
->ItemLimitCategory
==limitCategory
)
914 bool Item::IsLimitedToAnotherMapOrZone( uint32 cur_mapId
, uint32 cur_zoneId
) const
916 ItemPrototype
const* proto
= GetProto();
917 return proto
&& (proto
->Map
&& proto
->Map
!= cur_mapId
|| proto
->Area
&& proto
->Area
!= cur_zoneId
);
920 // Though the client has the information in the item's data field,
921 // we have to send SMSG_ITEM_TIME_UPDATE to display the remaining
923 void Item::SendTimeUpdate(Player
* owner
)
925 if (!GetUInt32Value(ITEM_FIELD_DURATION
))
928 WorldPacket
data(SMSG_ITEM_TIME_UPDATE
, (8+4));
929 data
<< (uint64
)GetGUID();
930 data
<< (uint32
)GetUInt32Value(ITEM_FIELD_DURATION
);
931 owner
->GetSession()->SendPacket(&data
);
934 Item
* Item::CreateItem( uint32 item
, uint32 count
, Player
const* player
)
937 return NULL
; //don't create item at zero count
939 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype( item
);
942 if ( count
> pProto
->GetMaxStackSize())
943 count
= pProto
->GetMaxStackSize();
945 assert(count
!=0 && "pProto->Stackable==0 but checked at loading already");
947 Item
*pItem
= NewItemOrBag( pProto
);
948 if( pItem
->Create(objmgr
.GenerateLowGuid(HIGHGUID_ITEM
), item
, player
) )
950 pItem
->SetCount( count
);
959 Item
* Item::CloneItem( uint32 count
, Player
const* player
) const
961 Item
* newItem
= CreateItem( GetEntry(), count
, player
);
965 newItem
->SetUInt32Value( ITEM_FIELD_CREATOR
, GetUInt32Value( ITEM_FIELD_CREATOR
) );
966 newItem
->SetUInt32Value( ITEM_FIELD_GIFTCREATOR
, GetUInt32Value( ITEM_FIELD_GIFTCREATOR
) );
967 newItem
->SetUInt32Value( ITEM_FIELD_FLAGS
, GetUInt32Value( ITEM_FIELD_FLAGS
) );
968 newItem
->SetUInt32Value( ITEM_FIELD_DURATION
, GetUInt32Value( ITEM_FIELD_DURATION
) );
969 newItem
->SetItemRandomProperties(GetItemRandomPropertyId());
973 bool Item::IsBindedNotWith( Player
const* player
) const
980 if(GetOwnerGUID()== player
->GetGUID())
984 if(!IsBoundAccountWide())
988 if(Player
* owner
= objmgr
.GetPlayer(GetOwnerGUID()))
990 return owner
->GetSession()->GetAccountId() != player
->GetSession()->GetAccountId();
995 return objmgr
.GetPlayerAccountIdByGUID(GetOwnerGUID()) != player
->GetSession()->GetAccountId();
999 bool ItemRequiredTarget::IsFitToRequirements( Unit
* pUnitTarget
) const
1001 if(pUnitTarget
->GetTypeId() != TYPEID_UNIT
)
1004 if(pUnitTarget
->GetEntry() != m_uiTargetEntry
)
1009 case ITEM_TARGET_TYPE_CREATURE
:
1010 return pUnitTarget
->isAlive();
1011 case ITEM_TARGET_TYPE_DEAD
:
1012 return !pUnitTarget
->isAlive();