/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "StdAfx.h" Item::Item( )//this is called when constructing as container { m_itemProto = NULL; m_owner = NULL; loot = NULL; locked = false; } Item::Item(uint32 high,uint32 low) { m_objectTypeId = TYPEID_ITEM; m_valuesCount = ITEM_END; m_uint32Values = _fields; memset(m_uint32Values, 0,(ITEM_END)*sizeof(uint32)); m_updateMask.SetCount(ITEM_END); SetUInt32Value( OBJECT_FIELD_TYPE,TYPE_ITEM|TYPE_OBJECT); SetUInt32Value( OBJECT_FIELD_GUID,low); SetUInt32Value( OBJECT_FIELD_GUID+1,high); m_wowGuid.Init(GetGUID()); SetFloatValue( OBJECT_FIELD_SCALE_X, 1 );//always 1 m_itemProto = NULL; m_owner = NULL; loot = NULL; locked = false; m_isDirty = true; } Item::~Item() { if(loot != NULL) delete loot; sEventMgr.RemoveEvents(this); EnchantmentMap::iterator itr; for(itr = Enchantments.begin(); itr != Enchantments.end(); ++itr) { if(itr->second.Enchantment->type == 0 && itr->second.Slot == 0 && itr->second.ApplyTime == 0 && itr->second.Duration == 0) { delete itr->second.Enchantment; itr->second.Enchantment = NULL; } } if(IsInWorld()) RemoveFromWorld(); } void Item::Create( uint32 itemid, Player *owner ) { SetUInt32Value( OBJECT_FIELD_ENTRY, itemid ); SetUInt64Value( ITEM_FIELD_OWNER, owner->GetGUID() ); SetUInt64Value( ITEM_FIELD_CONTAINED, owner->GetGUID() ); SetUInt32Value( ITEM_FIELD_STACK_COUNT, 1 ); m_itemProto = ItemPrototypeStorage.LookupEntry( itemid ); ASSERT(m_itemProto); SetUInt32Value( ITEM_FIELD_SPELL_CHARGES , m_itemProto->Spells[0].Charges ); SetUInt32Value( ITEM_FIELD_SPELL_CHARGES_01 , m_itemProto->Spells[1].Charges ); SetUInt32Value( ITEM_FIELD_SPELL_CHARGES_02 , m_itemProto->Spells[2].Charges ); SetUInt32Value( ITEM_FIELD_SPELL_CHARGES_03 , m_itemProto->Spells[3].Charges ); SetUInt32Value( ITEM_FIELD_SPELL_CHARGES_04 , m_itemProto->Spells[4].Charges ); SetUInt32Value( ITEM_FIELD_MAXDURABILITY, m_itemProto->MaxDurability); SetUInt32Value( ITEM_FIELD_DURABILITY, m_itemProto->MaxDurability); m_owner = owner; if(m_itemProto->LockId > 1) locked = true; else locked = false; } void Item::LoadFromDB( Field *fields, Player * plr, bool light) { uint32 itemid=fields[2].GetUInt32(); m_itemProto = ItemPrototypeStorage.LookupEntry( itemid ); ASSERT(m_itemProto); if(m_itemProto->LockId > 1) locked = true; else locked = false; SetUInt32Value( OBJECT_FIELD_ENTRY, itemid ); m_owner = plr; SetUInt32Value( ITEM_FIELD_CREATOR, fields[3].GetUInt32() ); SetUInt32Value( ITEM_FIELD_STACK_COUNT, fields[4].GetUInt32()); for(uint32 x=0;x<5;x++) if(m_itemProto->Spells[x].Id) { SetUInt32Value( ITEM_FIELD_SPELL_CHARGES+x , fields[5].GetUInt32() ); break; } SetUInt32Value( ITEM_FIELD_FLAGS, fields[6].GetUInt32()); SetUInt32Value( ITEM_FIELD_RANDOM_PROPERTIES_ID, fields[7].GetUInt32()); SetUInt32Value( ITEM_FIELD_ITEM_TEXT_ID, fields[8].GetUInt32()); SetUInt32Value( ITEM_FIELD_MAXDURABILITY, m_itemProto->MaxDurability); SetUInt32Value( ITEM_FIELD_DURABILITY, fields[9].GetUInt32()); if(light) return; string enchant_field = fields[12].GetString(); vector enchants = StrSplit(enchant_field, ";"); uint32 enchant_id; EnchantEntry * entry; uint32 time_left; uint32 enchslot; for(vector::iterator itr = enchants.begin(); itr != enchants.end(); ++itr) { if(sscanf((*itr).c_str(), "%u,%u,%u", (unsigned int*)&enchant_id, (unsigned int*)&time_left, (unsigned int*)&enchslot) == 3) { entry = sEnchantStore.LookupEntry(enchant_id); if(entry && entry->Id == enchant_id) AddEnchantment(entry, time_left, (time_left==0),false,false,enchslot); //(enchslot != 2) ? false : true, false); else {/* EnchantEntry *pEnchant = new EnchantEntry; memset(pEnchant,0,sizeof(EnchantEntry)); pEnchant->Id = enchant_id; if(enchslot != 2) AddEnchantment(pEnchant,0,true, false); else AddEnchantment(pEnchant,0,false,false);*/ } } } ApplyRandomProperties(); // Charter stuff if(m_uint32Values[OBJECT_FIELD_ENTRY] == ITEM_ENTRY_GUILD_CHARTER) { SetUInt32Value(ITEM_FIELD_FLAGS, 1); SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1); SetUInt32Value(ITEM_FIELD_PROPERTY_SEED, 57813883); if(plr->m_charter) SetUInt32Value(ITEM_FIELD_ENCHANTMENT, plr->m_charter->GetID()); } } void Item::ApplyRandomProperties() { // apply random properties if(m_uint32Values[ITEM_FIELD_RANDOM_PROPERTIES_ID] != 0) { RandomProps *rp= sRandomPropStore.LookupEntry(m_uint32Values[ITEM_FIELD_RANDOM_PROPERTIES_ID]); if(rp) { for (int k=0;k<3;k++) { if (rp->spells[k] != 0) { EnchantEntry * ee = sEnchantStore.LookupEntry(rp->spells[k]); if(HasEnchantment(ee->Id) < 0) { uint32 Slot = FindFreeEnchantSlot(ee); AddEnchantment(ee, 0, false, false, true, Slot); } } } } } } void Item::SaveToDB(int8 containerslot, int8 slot, bool firstsave) { if(!m_isDirty && !firstsave) return; std::stringstream ss; ss << "REPLACE INTO playeritems VALUES("; ss << m_uint32Values[ITEM_FIELD_OWNER] << ","; ss << GetGUIDLow() << ","; ss << m_uint32Values[OBJECT_FIELD_ENTRY] << ","; ss << GetUInt32Value(ITEM_FIELD_CREATOR) << ","; ss << GetUInt32Value(ITEM_FIELD_STACK_COUNT) << ","; ss << GetChargesLeft() << ","; ss << GetUInt32Value(ITEM_FIELD_FLAGS) << ","; ss << GetUInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID) << ","; ss << GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID) << ","; ss << GetUInt32Value(ITEM_FIELD_DURABILITY) << ","; ss << static_cast(containerslot) << ","; ss << static_cast(slot) << ",'"; // Pack together enchantment fields EnchantmentMap::iterator itr = Enchantments.begin(); for(; itr != Enchantments.end(); ++itr) { if(itr->second.RemoveAtLogout) continue; uint32 elapsed_duration = time(NULL) - itr->second.ApplyTime; int32 remaining_duration = itr->second.Duration - elapsed_duration; if(remaining_duration < 0) remaining_duration = 0; /* if(!itr->second.RemoveAtLogout && (remaining_duration > 5 && itr->second.Slot != 2) || itr->second.Slot == 2) // no point saving stuff with < 5 seconds... unless is perm enchant { ss << itr->second.Enchantment->Id << ","; ss << remaining_duration << ","; ss << itr->second.Slot << ";"; }*/ if (itr->second.Enchantment && (remaining_duration && remaining_duration >5) || (itr->second.Duration==0)) { ss << itr->second.Enchantment->Id << ","; ss << remaining_duration << ","; ss << itr->second.Slot << ";"; } } ss << "')"; if(firstsave) CharacterDatabase.WaitExecute(ss.str().c_str()); else CharacterDatabase.Execute( ss.str().c_str()); m_isDirty = false; } void Item::DeleteFromDB() { if(m_itemProto->ContainerSlots>0) { /* deleting a container */ for(uint32 i = 0; i < m_itemProto->ContainerSlots; ++i) { if(((Container*)this)->GetItem(i) != NULL) { #ifdef WIN32 OutputCrashLogLine("Delting bag with inventority items still!!!! ItemId %u containerslots %u", m_itemProto->ItemId, m_itemProto->ContainerSlots); CStackWalker ws; ws.ShowCallstack(); #endif /* abort the delete */ return; } } } CharacterDatabase.Execute("DELETE FROM playeritems WHERE guid = %u", GetGUIDLow()); } uint32 GetSkillByProto(uint32 Class, uint32 SubClass) { const static uint32 arm_skills[7]={0,SKILL_CLOTH,SKILL_LEATHER,SKILL_MAIL,SKILL_PLATE_MAIL,0,SKILL_SHIELD}; const static uint32 weap_skills[21]={SKILL_AXES,SKILL_2H_AXES,SKILL_BOWS,SKILL_GUNS,SKILL_MACES,SKILL_2H_MACES, SKILL_POLEARMS,SKILL_SWORDS,SKILL_2H_SWORDS,0,SKILL_STAVES,0,0,SKILL_FIST_WEAPONS,0,//<-13 SKILL_DAGGERS,SKILL_THROWN,SKILL_SPEARS,SKILL_CROSSBOWS,SKILL_WANDS,SKILL_FISHING}; //14--used by professions if(Class == 4 && SubClass < 7) { return arm_skills[SubClass]; } else if(Class == 2) { if(SubClass < 20)//no skill for fishing { return weap_skills[SubClass]; } } return 0; } //This map is used for profess. //Prof packe strcut: {SMSG_SET_PROFICIENCY,(uint8)item_class,(uint32)1<Class) { case ITEM_CLASS_WEAPON: case ITEM_CLASS_CONSUMABLE: case ITEM_CLASS_PROJECTILE: // as far as i can tell these can't be sold at all { cost = (proto->SellPrice * ((count < 1) ? 1 : count)) / proto->MaxCount; }break; default: { cost = ( proto->SellPrice * ((count < 1) ? 1 : count) ); }break; } return cost; } uint32 GetBuyPriceForItem(ItemPrototype *proto, uint32 count, uint32 vendorcount) { int32 cost; switch(proto->Class) { case ITEM_CLASS_WEAPON: case ITEM_CLASS_PROJECTILE: case ITEM_CLASS_CONSUMABLE: { cost = ( proto->BuyPrice * ((count < 1) ? 1 : count) ) / proto->MaxCount; }break; default: { cost = ( proto->BuyPrice * ((count < 1) ? 1 : count)); }break; } return cost; } uint32 GetSellPriceForItem(uint32 itemid, uint32 count) { if(ItemPrototype *proto = ItemPrototypeStorage.LookupEntry(itemid)) return GetSellPriceForItem(proto, count); else return 1; } uint32 GetBuyPriceForItem(uint32 itemid, uint32 count, uint32 vendorcount) { if(ItemPrototype *proto = ItemPrototypeStorage.LookupEntry(itemid)) return GetBuyPriceForItem(proto, count, vendorcount); else return 1; } void Item::RemoveFromWorld() { // if we have an owner->send destroy if(m_owner) { DestroyForPlayer(m_owner); } if(!IsInWorld()) return; mSemaphoreTeleport = true; m_mapMgr->RemoveObject(this); m_mapMgr = NULL; // update our event holder event_Relocate(); } void Item::SetOwner(Player *owner) { if(owner) SetUInt64Value(ITEM_FIELD_OWNER,((Object*)owner)->GetGUID()); else SetUInt64Value(ITEM_FIELD_OWNER,0); m_owner = owner; } int32 Item::AddEnchantment(EnchantEntry * Enchantment, uint32 Duration, bool Perm /* = false */, bool apply /* = true */, bool RemoveAtLogout /* = false */,uint32 Slot_) { int32 Slot = Slot_; m_isDirty = true; /* if(Perm) { if(Slot_) { Slot=Slot_; } else { Slot = FindFreeEnchantSlot(Enchantment); } } else { if(Enchantment->EnchantGroups > 1) // replaceable temp enchants { Slot = 1; RemoveEnchantment(1); } else { Slot = FindFreeEnchantSlot(Enchantment);*/ /* Slot = Enchantment->type ? 3 : 0; //that's 's code for(uint32 Index = ITEM_FIELD_ENCHANTMENT_09; Index < ITEM_FIELD_ENCHANTMENT_32; Index += 3) { if(m_uint32Values[Index] == 0) break;; ++Slot; } //Slot = FindFreeEnchantSlot(Enchantment); // reach max of temp enchants if(Slot >= 11) return -1; */ /*} } */ // Create the enchantment struct. EnchantmentInstance Instance; Instance.ApplyTime = time(NULL); Instance.BonusApplied = false; Instance.Slot = Slot; Instance.Enchantment = Enchantment; Instance.Duration = Duration; Instance.RemoveAtLogout = RemoveAtLogout; // Set the enchantment in the item fields. uint32 EnchantBase = Slot * 3 + ITEM_FIELD_ENCHANTMENT; SetUInt32Value(EnchantBase , Enchantment->Id); SetUInt32Value(EnchantBase + 1, Instance.ApplyTime); SetUInt32Value(EnchantBase + 2, 0); // charges // Add it to our map. Enchantments[Slot] = Instance; if(m_owner == 0) return Slot; // Add the removal event. if(Duration) { sEventMgr.AddEvent(this, &Item::RemoveEnchantment, uint32(Slot), EVENT_REMOVE_ENCHANTMENT1 + Slot, Duration * 1000, 1,0); } // No need to send the log packet, if the owner isn't in world (we're still loading) if(!m_owner->IsInWorld()) return Slot; if(apply) { WorldPacket EnchantLog(SMSG_ENCHANTMENTLOG, 25); EnchantLog << m_owner->GetGUID(); EnchantLog << m_owner->GetGUID(); EnchantLog << m_uint32Values[OBJECT_FIELD_ENTRY]; EnchantLog << Enchantment->Id; EnchantLog << uint8(0); m_owner->GetSession()->SendPacket(&EnchantLog); if(m_owner->GetTradeTarget()) { m_owner->SendTradeUpdate(); } /* Only apply the enchantment bonus if we're equipped */ uint8 slot = m_owner->GetItemInterface()->GetInventorySlotByGuid(GetGUID()); if(slot > EQUIPMENT_SLOT_START && slot < EQUIPMENT_SLOT_END) ApplyEnchantmentBonus(Slot, APPLY); } return Slot; } void Item::RemoveEnchantment(uint32 EnchantmentSlot) { // Make sure we actually exist. EnchantmentMap::iterator itr = Enchantments.find(EnchantmentSlot); if(itr == Enchantments.end()) return; m_isDirty = true; uint32 Slot = itr->first; if(itr->second.BonusApplied) ApplyEnchantmentBonus(EnchantmentSlot, REMOVE); // Unset the item fields. uint32 EnchantBase = Slot * 3 + ITEM_FIELD_ENCHANTMENT; SetUInt32Value(EnchantBase + 0, 0); SetUInt32Value(EnchantBase + 1, 0); SetUInt32Value(EnchantBase + 2, 0); // Remove the enchantment event for removal. event_RemoveEvents(EVENT_REMOVE_ENCHANTMENT1 + Slot); // Remove the enchantment instance. Enchantments.erase(itr); } void Item::ApplyEnchantmentBonus(uint32 Slot, bool Apply) { EnchantmentMap::iterator itr = Enchantments.find(Slot); if(itr == Enchantments.end()) return; EnchantEntry * Entry = itr->second.Enchantment; if(itr->second.BonusApplied == Apply) return; itr->second.BonusApplied = Apply; if(Apply) { // Send the enchantment time update packet. SendEnchantTimeUpdate(itr->second.Slot, itr->second.Duration); } // Apply the visual on the player. uint32 ItemSlot = m_owner->GetItemInterface()->GetInventorySlotByGuid(GetGUID()) * 16; uint32 VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + ItemSlot; m_owner->SetUInt32Value(VisibleBase + 1 + Slot, Apply ? Entry->Id : 0); for(uint32 c=0;c<3;c++) if(Entry->type[c]) { // Depending on the enchantment type, take the appropriate course of action. switch(Entry->type[c]) { case 1: // Trigger spell on melee attack. { if(Apply && Entry->spell[c] != 0) { // Create a proc trigger spell ProcTriggerSpell TS; TS.caster = m_owner->GetGUID(); TS.origId = 0; TS.procFlags = PROC_ON_MELEE_ATTACK; TS.procCharges = 0; TS.procChance = Entry->min[c] ? Entry->min[c] : 35; TS.deleted = false; TS.spellId = Entry->spell[c]; m_owner->m_procSpells.push_back(TS); } else { // Remove the proctriggerspell uint32 SpellId; list::iterator itr/*, itr2*/; for(itr = m_owner->m_procSpells.begin(); itr != m_owner->m_procSpells.end();) { SpellId = itr->spellId; /*itr2 = itr++;*/ if(SpellId == Entry->spell[c] ) { //m_owner->m_procSpells.erase(itr2); itr->deleted = true; } itr++; } } }break; case 2: // Mod damage done. { if(Apply) m_owner->ModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, Entry->min[c]); else m_owner->ModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, -Entry->min[c]); m_owner->CalcDamage(); }break; case 3: // Cast spell (usually means apply aura) { if(Apply) { SpellCastTargets targets(m_owner->GetGUID()); SpellEntry * sp; Spell * spell; if(Entry->spell[c] != 0) { sp = sSpellStore.LookupEntry(Entry->spell[c]); if(!sp) continue; spell = new Spell(m_owner, sp, true, 0); spell->prepare(&targets); } } else { if(Entry->spell[c] != 0) m_owner->RemoveAura(Entry->spell[c]); } }break; case 4: // Modify physical resistance { if(Apply) { m_owner->FlatResistanceModifierPos[0] += Entry->min[c]; } else { m_owner->FlatResistanceModifierPos[0] -= Entry->min[c]; } m_owner->CalcResistance(0); }break; case 5: //Modify rating ...order is PLAYER_FIELD_COMBAT_RATING_1 and above { //spellid is enum ITEM_STAT_TYPE //min=max is amount m_owner->ModifyBonuses(Entry->spell[c], Apply ? Entry->min[c] : -Entry->min[c]); m_owner->UpdateStats(); }break; case 6: // Rockbiter weapon (increase damage per second... how the hell do you calc that) { if(Apply) { // m_owner->ModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, Entry->min[c]); //if i'm not wrong then we should apply DMPS formula for this. This will have somewhat a larger value 28->34 int32 value=GetProto()->Delay*Entry->min[c]/1000; m_owner->ModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, value); } else { int32 value=-(int32)(GetProto()->Delay*Entry->min[c]/1000); m_owner->ModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, value); } m_owner->CalcDamage(); }break; default: { sLog.outError("Unknown enchantment type: %u (%u)", Entry->type[c], Entry->Id); }break; } } } void Item::ApplyEnchantmentBonuses() { EnchantmentMap::iterator itr; for(itr = Enchantments.begin(); itr != Enchantments.end(); ++itr) { ApplyEnchantmentBonus(itr->first, APPLY); } } void Item::RemoveEnchantmentBonuses() { EnchantmentMap::iterator itr; for(itr = Enchantments.begin(); itr != Enchantments.end(); ++itr) { ApplyEnchantmentBonus(itr->first, REMOVE); } } void Item::EventRemoveEnchantment(uint32 Slot) { // Remove the enchantment. RemoveEnchantment(Slot); } int32 Item::FindFreeEnchantSlot(EnchantEntry * Enchantment) { //if(!Enchantment) return -1; /* uint32 Slot = Enchantment->type ? 3 : 0; for(uint32 Index = ITEM_FIELD_ENCHANTMENT_09; Index < ITEM_FIELD_ENCHANTMENT_32; Index += 3) { if(m_uint32Values[Index] == 0) return Slot; ++Slot; }*/ uint32 GemSlotsReserve=GetSocketsCount(); if(GetProto()->SocketBonus) GemSlotsReserve++; for(uint32 Slot = GemSlotsReserve+2;Slot<11; Slot++) { if(m_uint32Values[ITEM_FIELD_ENCHANTMENT + Slot*3] == 0) return Slot; } return -1; } int32 Item::HasEnchantment(uint32 Id) { for(uint32 Slot = 0;Slot<11;Slot++) { if(m_uint32Values[ITEM_FIELD_ENCHANTMENT+Slot*3] == Id) return Slot; } return -1; } void Item::ModifyEnchantmentTime(uint32 Slot, uint32 Duration) { EnchantmentMap::iterator itr = Enchantments.find(Slot); if(itr == Enchantments.end()) return; // Reset the apply time. itr->second.ApplyTime = time(NULL); itr->second.Duration = Duration; // Change the event timer. event_ModifyTimeAndTimeLeft(EVENT_REMOVE_ENCHANTMENT1 + Slot, Duration * 1000); // Send update packet SendEnchantTimeUpdate(itr->second.Slot, Duration); } void Item::SendEnchantTimeUpdate(uint32 Slot, uint32 Duration) { /* {SERVER} Packet: (0x01EB) SMSG_ITEM_ENCHANT_TIME_UPDATE Size = 24 |------------------------------------------------|----------------| |00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |0123456789ABCDEF| |------------------------------------------------|----------------| |69 32 F0 35 00 00 00 40 01 00 00 00 08 07 00 00 |i2.5...@........| |51 46 35 00 00 00 00 00 |QF5..... | ------------------------------------------------------------------- uint64 item_guid uint32 count? uint32 time_in_seconds uint64 player_guid */ WorldPacket *data = new WorldPacket(SMSG_ITEM_ENCHANT_TIME_UPDATE, 24); *data << GetGUID(); *data << Slot; *data << Duration; *data << m_owner->GetGUID(); m_owner->delayedPackets.add(data); } void Item::RemoveAllEnchantments(bool OnlyTemporary) { EnchantmentMap::iterator itr, it2; for(itr = Enchantments.begin(); itr != Enchantments.end();) { it2 = itr++; if(OnlyTemporary && it2->second.Duration == 0) continue; RemoveEnchantment(it2->first); } } void Item::RemoveRelatedEnchants(EnchantEntry * newEnchant) { EnchantmentMap::iterator itr,itr2; for(itr = Enchantments.begin(); itr != Enchantments.end();) { itr2 = itr++; if(itr2->second.Enchantment->Id == newEnchant->Id || (itr2->second.Enchantment->EnchantGroups > 1 && newEnchant->EnchantGroups > 1 )) { RemoveEnchantment(itr2->first); } } } void Item::RemoveProfessionEnchant() { EnchantmentMap::iterator itr; for(itr = Enchantments.begin(); itr != Enchantments.end();itr++) { if(itr->second.Duration!=0)// not perm continue; if(IsGemRelated(itr->second.Enchantment)) continue; RemoveEnchantment(itr->first); return; } } void Item::RemoveSocketBonusEnchant() { EnchantmentMap::iterator itr; for(itr = Enchantments.begin(); itr != Enchantments.end();itr++) { if(itr->second.Enchantment->Id == GetProto()->SocketBonus) { RemoveEnchantment(itr->first); return; } } } EnchantmentInstance * Item::GetEnchantment(uint32 slot) { EnchantmentMap::iterator itr = Enchantments.find(slot); if(itr != Enchantments.end()) return &itr->second; else return NULL; } bool Item::IsGemRelated(EnchantEntry * Enchantment) { if(GetProto()->SocketBonus == Enchantment->Id) return true; return (Enchantment->GemEntry!=0); } uint32 Item::GetSocketsCount() { uint32 c=0; for(uint32 x=0;x<3;x++) if(GetProto()->Sockets[x].SocketColor) c++; return c; }