Files
Viano-Core/src/server/game/Handlers/ItemHandler.cpp
T
Gacko 01b705c844 Core/Player: Fix armor calculation - 2nd try
Base armor value from WDB data includes the ArmorDamageModifier. Items of
same item level, required level, armor type and equiptment slot should
have (nearly) the same armor values.

See following links for further proofs:
http://pastebin.com/fqNJLYj4
http://www.wowhead.com/item=50466#comments:id=889035:reply=444786

The shown item should have a base armor value of 177 as similar items and
a bonus armor value of 560 which equals 737 - like in DB atm.
2013-01-01 21:43:17 +01:00

1445 lines
50 KiB
C++

/*
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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 2 of the License, or (at your
* option) 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 <http://www.gnu.org/licenses/>.
*/
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "Item.h"
#include "UpdateData.h"
#include "ObjectAccessor.h"
#include "SpellInfo.h"
void WorldSession::HandleSplitItemOpcode(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SPLIT_ITEM");
uint8 srcbag, srcslot, dstbag, dstslot;
uint32 count;
recvData >> srcbag >> srcslot >> dstbag >> dstslot >> count;
//sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count);
uint16 src = ((srcbag << 8) | srcslot);
uint16 dst = ((dstbag << 8) | dstslot);
if (src == dst)
return;
if (count == 0)
return; //check count - if zero it's fake packet
if (!_player->IsValidPos(srcbag, srcslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
if (!_player->IsValidPos(dstbag, dstslot, false)) // can be autostore pos
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
}
_player->SplitItem(src, dst, count);
}
void WorldSession::HandleSwapInvItemOpcode(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SWAP_INV_ITEM");
uint8 srcslot, dstslot;
recvData >> dstslot >> srcslot;
//sLog->outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot);
// prevent attempt swap same item to current position generated by client at special checting sequence
if (srcslot == dstslot)
return;
if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, srcslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
}
uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot);
_player->SwapItem(src, dst);
}
void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPacket& recvData)
{
uint64 itemguid;
uint8 dstslot;
recvData >> itemguid >> dstslot;
// cheating attempt, client should never send opcode in that case
if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot))
return;
Item* item = _player->GetItemByGuid(itemguid);
uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8);
if (!item || item->GetPos() == dstpos)
return;
_player->SwapItem(item->GetPos(), dstpos);
}
void WorldSession::HandleSwapItem(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SWAP_ITEM");
uint8 dstbag, dstslot, srcbag, srcslot;
recvData >> dstbag >> dstslot >> srcbag >> srcslot;
//sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot);
uint16 src = ((srcbag << 8) | srcslot);
uint16 dst = ((dstbag << 8) | dstslot);
// prevent attempt swap same item to current position generated by client at special checting sequence
if (src == dst)
return;
if (!_player->IsValidPos(srcbag, srcslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
if (!_player->IsValidPos(dstbag, dstslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
}
_player->SwapItem(src, dst);
}
void WorldSession::HandleAutoEquipItemOpcode(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_AUTOEQUIP_ITEM");
uint8 srcbag, srcslot;
recvData >> srcbag >> srcslot;
//sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
Item* pSrcItem = _player->GetItemByPos(srcbag, srcslot);
if (!pSrcItem)
return; // only at cheat
uint16 dest;
InventoryResult msg = _player->CanEquipItem(NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag());
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pSrcItem, NULL);
return;
}
uint16 src = pSrcItem->GetPos();
if (dest == src) // prevent equip in same slot, only at cheat
return;
Item* pDstItem = _player->GetItemByPos(dest);
if (!pDstItem) // empty slot, simple case
{
_player->RemoveItem(srcbag, srcslot, true);
_player->EquipItem(dest, pSrcItem, true);
_player->AutoUnequipOffhandIfNeed();
}
else // have currently equipped item, not simple case
{
uint8 dstbag = pDstItem->GetBagSlot();
uint8 dstslot = pDstItem->GetSlot();
msg = _player->CanUnequipItem(dest, !pSrcItem->IsBag());
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pDstItem, NULL);
return;
}
// check dest->src move possibility
ItemPosCountVec sSrc;
uint16 eSrc = 0;
if (_player->IsInventoryPos(src))
{
msg = _player->CanStoreItem(srcbag, srcslot, sSrc, pDstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanStoreItem(srcbag, NULL_SLOT, sSrc, pDstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true);
}
else if (_player->IsBankPos(src))
{
msg = _player->CanBankItem(srcbag, srcslot, sSrc, pDstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanBankItem(srcbag, NULL_SLOT, sSrc, pDstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true);
}
else if (_player->IsEquipmentPos(src))
{
msg = _player->CanEquipItem(srcslot, eSrc, pDstItem, true);
if (msg == EQUIP_ERR_OK)
msg = _player->CanUnequipItem(eSrc, true);
}
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pDstItem, pSrcItem);
return;
}
// now do moves, remove...
_player->RemoveItem(dstbag, dstslot, false);
_player->RemoveItem(srcbag, srcslot, false);
// add to dest
_player->EquipItem(dest, pSrcItem, true);
// add to src
if (_player->IsInventoryPos(src))
_player->StoreItem(sSrc, pDstItem, true);
else if (_player->IsBankPos(src))
_player->BankItem(sSrc, pDstItem, true);
else if (_player->IsEquipmentPos(src))
_player->EquipItem(eSrc, pDstItem, true);
_player->AutoUnequipOffhandIfNeed();
}
}
void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_DESTROYITEM");
uint8 bag, slot, count, data1, data2, data3;
recvData >> bag >> slot >> count >> data1 >> data2 >> data3;
//sLog->outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count);
uint16 pos = (bag << 8) | slot;
// prevent drop unequipable items (in combat, for example) and non-empty bags
if (_player->IsEquipmentPos(pos) || _player->IsBagPos(pos))
{
InventoryResult msg = _player->CanUnequipItem(pos, false);
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, _player->GetItemByPos(pos), NULL);
return;
}
}
Item* pItem = _player->GetItemByPos(bag, slot);
if (!pItem)
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
if (pItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_INDESTRUCTIBLE)
{
_player->SendEquipError(EQUIP_ERR_CANT_DROP_SOULBOUND, NULL, NULL);
return;
}
if (count)
{
uint32 i_count = count;
_player->DestroyItemCount(pItem, i_count, true);
}
else
_player->DestroyItem(bag, slot, true);
}
// Only _static_ data send in this packet !!!
void WorldSession::HandleItemQuerySingleOpcode(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_ITEM_QUERY_SINGLE");
uint32 item;
recvData >> item;
sLog->outInfo(LOG_FILTER_NETWORKIO, "STORAGE: Item Query = %u", item);
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
if (pProto)
{
std::string Name = pProto->Name1;
std::string Description = pProto->Description;
int loc_idx = GetSessionDbLocaleIndex();
if (loc_idx >= 0)
{
if (ItemLocale const* il = sObjectMgr->GetItemLocale(pProto->ItemId))
{
ObjectMgr::GetLocaleString(il->Name, loc_idx, Name);
ObjectMgr::GetLocaleString(il->Description, loc_idx, Description);
}
}
// guess size
WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600);
data << pProto->ItemId;
data << pProto->Class;
data << pProto->SubClass;
data << pProto->SoundOverrideSubclass;
data << Name;
data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00);
data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00);
data << pProto->DisplayInfoID;
data << pProto->Quality;
data << pProto->Flags;
data << pProto->Flags2;
data << pProto->BuyPrice;
data << pProto->SellPrice;
data << pProto->InventoryType;
data << pProto->AllowableClass;
data << pProto->AllowableRace;
data << pProto->ItemLevel;
data << pProto->RequiredLevel;
data << pProto->RequiredSkill;
data << pProto->RequiredSkillRank;
data << pProto->RequiredSpell;
data << pProto->RequiredHonorRank;
data << pProto->RequiredCityRank;
data << pProto->RequiredReputationFaction;
data << pProto->RequiredReputationRank;
data << int32(pProto->MaxCount);
data << int32(pProto->Stackable);
data << pProto->ContainerSlots;
data << pProto->StatsCount; // item stats count
for (uint32 i = 0; i < pProto->StatsCount; ++i)
{
data << pProto->ItemStat[i].ItemStatType;
data << pProto->ItemStat[i].ItemStatValue;
}
data << pProto->ScalingStatDistribution; // scaling stats distribution
data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column
for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
data << pProto->Damage[i].DamageMin;
data << pProto->Damage[i].DamageMax;
data << pProto->Damage[i].DamageType;
}
// resistances (7)
data << pProto->Armor;
data << pProto->HolyRes;
data << pProto->FireRes;
data << pProto->NatureRes;
data << pProto->FrostRes;
data << pProto->ShadowRes;
data << pProto->ArcaneRes;
data << pProto->Delay;
data << pProto->AmmoType;
data << pProto->RangedModRange;
for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
// use `item_template` or if not set then only use spell cooldowns
SpellInfo const* spell = sSpellMgr->GetSpellInfo(pProto->Spells[s].SpellId);
if (spell)
{
bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0;
data << pProto->Spells[s].SpellId;
data << pProto->Spells[s].SpellTrigger;
data << uint32(-abs(pProto->Spells[s].SpellCharges));
if (db_data)
{
data << uint32(pProto->Spells[s].SpellCooldown);
data << uint32(pProto->Spells[s].SpellCategory);
data << uint32(pProto->Spells[s].SpellCategoryCooldown);
}
else
{
data << uint32(spell->RecoveryTime);
data << uint32(spell->Category);
data << uint32(spell->CategoryRecoveryTime);
}
}
else
{
data << uint32(0);
data << uint32(0);
data << uint32(0);
data << uint32(-1);
data << uint32(0);
data << uint32(-1);
}
}
data << pProto->Bonding;
data << Description;
data << pProto->PageText;
data << pProto->LanguageID;
data << pProto->PageMaterial;
data << pProto->StartQuest;
data << pProto->LockID;
data << int32(pProto->Material);
data << pProto->Sheath;
data << pProto->RandomProperty;
data << pProto->RandomSuffix;
data << pProto->Block;
data << pProto->ItemSet;
data << pProto->MaxDurability;
data << pProto->Area;
data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch
data << pProto->BagFamily;
data << pProto->TotemCategory;
for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
{
data << pProto->Socket[s].Color;
data << pProto->Socket[s].Content;
}
data << pProto->socketBonus;
data << pProto->GemProperties;
data << pProto->RequiredDisenchantSkill;
data << pProto->ArmorDamageModifier;
data << pProto->Duration; // added in 2.4.2.8209, duration (seconds)
data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory
data << pProto->HolidayId; // Holiday.dbc?
SendPacket(&data);
}
else
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item);
WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4);
data << uint32(item | 0x80000000);
SendPacket(&data);
}
}
void WorldSession::HandleReadItem(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_READ_ITEM");
uint8 bag, slot;
recvData >> bag >> slot;
//sLog->outInfo(LOG_FILTER_NETWORKIO, "STORAGE: Read bag = %u, slot = %u", bag, slot);
Item* pItem = _player->GetItemByPos(bag, slot);
if (pItem && pItem->GetTemplate()->PageText)
{
WorldPacket data;
InventoryResult msg = _player->CanUseItem(pItem);
if (msg == EQUIP_ERR_OK)
{
data.Initialize (SMSG_READ_ITEM_OK, 8);
sLog->outInfo(LOG_FILTER_NETWORKIO, "STORAGE: Item page sent");
}
else
{
data.Initialize(SMSG_READ_ITEM_FAILED, 8);
sLog->outInfo(LOG_FILTER_NETWORKIO, "STORAGE: Unable to read item");
_player->SendEquipError(msg, pItem, NULL);
}
data << pItem->GetGUID();
SendPacket(&data);
}
else
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
}
void WorldSession::HandlePageQuerySkippedOpcode(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PAGE_TEXT_QUERY");
uint32 itemid;
uint64 guid;
recvData >> itemid >> guid;
sLog->outInfo(LOG_FILTER_NETWORKIO, "Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u",
itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid));
}
void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_SELL_ITEM");
uint64 vendorguid, itemguid;
uint32 count;
recvData >> vendorguid >> itemguid >> count;
if (!itemguid)
return;
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
if (!creature)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid)));
_player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0);
return;
}
// remove fake death
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
Item* pItem = _player->GetItemByGuid(itemguid);
if (pItem)
{
// prevent sell not owner item
if (_player->GetGUID() != pItem->GetOwnerGUID())
{
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
return;
}
// prevent sell non empty bag by drag-and-drop at vendor's item list
if (pItem->IsNotEmptyBag())
{
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
return;
}
// prevent sell currently looted item
if (_player->GetLootGUID() == pItem->GetGUID())
{
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
return;
}
// prevent selling item for sellprice when the item is still refundable
// this probably happens when right clicking a refundable item, the client sends both
// CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified)
if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE))
return; // Therefore, no feedback to client
// special case at auto sell (sell all)
if (count == 0)
count = pItem->GetCount();
else
{
// prevent sell more items that exist in stack (possible only not from client)
if (count > pItem->GetCount())
{
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
return;
}
}
ItemTemplate const* pProto = pItem->GetTemplate();
if (pProto)
{
if (pProto->SellPrice > 0)
{
if (count < pItem->GetCount()) // need split items
{
Item* pNewItem = pItem->CloneItem(count, _player);
if (!pNewItem)
{
sLog->outError(LOG_FILTER_NETWORKIO, "WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count);
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
return;
}
pItem->SetCount(pItem->GetCount() - count);
_player->ItemRemovedQuestCheck(pItem->GetEntry(), count);
if (_player->IsInWorld())
pItem->SendUpdateToPlayer(_player);
pItem->SetState(ITEM_CHANGED, _player);
_player->AddItemToBuyBackSlot(pNewItem);
if (_player->IsInWorld())
pNewItem->SendUpdateToPlayer(_player);
}
else
{
_player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
_player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
pItem->RemoveFromUpdateQueueOf(_player);
_player->AddItemToBuyBackSlot(pItem);
}
uint32 money = pProto->SellPrice * count;
_player->ModifyMoney(money);
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money);
}
else
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
return;
}
}
_player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, itemguid, 0);
return;
}
void WorldSession::HandleBuybackItem(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUYBACK_ITEM");
uint64 vendorguid;
uint32 slot;
recvData >> vendorguid >> slot;
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
if (!creature)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid)));
_player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
return;
}
// remove fake death
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
Item* pItem = _player->GetItemFromBuyBackSlot(slot);
if (pItem)
{
uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START);
if (!_player->HasEnoughMoney(price))
{
_player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, pItem->GetEntry(), 0);
return;
}
ItemPosCountVec dest;
InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
if (msg == EQUIP_ERR_OK)
{
_player->ModifyMoney(-(int32)price);
_player->RemoveItemFromBuyBackSlot(slot, false);
_player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount());
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount());
_player->StoreItem(dest, pItem, true);
}
else
_player->SendEquipError(msg, pItem, NULL);
return;
}
else
_player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, 0, 0);
}
void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUY_ITEM_IN_SLOT");
uint64 vendorguid, bagguid;
uint32 item, slot, count;
uint8 bagslot;
recvData >> vendorguid >> item >> slot >> bagguid >> bagslot >> count;
// client expects count starting at 1, and we send vendorslot+1 to client already
if (slot > 0)
--slot;
else
return; // cheating
uint8 bag = NULL_BAG; // init for case invalid bagGUID
// find bag slot by bag guid
if (bagguid == _player->GetGUID())
bag = INVENTORY_SLOT_BAG_0;
else
{
for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
if (Bag* pBag = _player->GetBagByPos(i))
{
if (bagguid == pBag->GetGUID())
{
bag = i;
break;
}
}
}
}
// bag not found, cheating?
if (bag == NULL_BAG)
return;
GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, bag, bagslot);
}
void WorldSession::HandleBuyItemOpcode(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUY_ITEM");
uint64 vendorguid;
uint32 item, slot, count;
uint8 unk1;
recvData >> vendorguid >> item >> slot >> count >> unk1;
// client expects count starting at 1, and we send vendorslot+1 to client already
if (slot > 0)
--slot;
else
return; // cheating
GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, NULL_BAG, NULL_SLOT);
}
void WorldSession::HandleListInventoryOpcode(WorldPacket& recvData)
{
uint64 guid;
recvData >> guid;
if (!GetPlayer()->isAlive())
return;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LIST_INVENTORY");
SendListInventory(guid);
}
void WorldSession::SendListInventory(uint64 vendorGuid)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY");
Creature* vendor = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR);
if (!vendor)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorGuid)));
_player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
return;
}
// remove fake death
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// Stop the npc if moving
if (vendor->HasUnitState(UNIT_STATE_MOVING))
vendor->StopMoving();
VendorItemData const* items = vendor->GetVendorItems();
if (!items)
{
WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1);
data << uint64(vendorGuid);
data << uint8(0); // count == 0, next will be error code
data << uint8(0); // "Vendor has no inventory"
SendPacket(&data);
return;
}
uint8 itemCount = items->GetItemCount();
uint8 count = 0;
WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4);
data << uint64(vendorGuid);
size_t countPos = data.wpos();
data << uint8(count);
float discountMod = _player->GetReputationPriceDiscount(vendor);
for (uint8 slot = 0; slot < itemCount; ++slot)
{
if (VendorItem const* item = items->GetItem(slot))
{
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item->item))
{
if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster())
continue;
// Only display items in vendor lists for the team the
// player is on. If GM on, display all items.
if (!_player->isGameMaster() && ((itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || (itemTemplate->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE)))
continue;
// Items sold out are not displayed in list
uint32 leftInStock = !item->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(item);
if (!_player->isGameMaster() && !leftInStock)
continue;
ConditionList conditions = sConditionMgr->GetConditionsForNpcVendorEvent(vendor->GetEntry(), item->item);
if (!sConditionMgr->IsObjectMeetToConditions(_player, vendor, conditions))
{
sLog->outDebug(LOG_FILTER_CONDITIONSYS, "SendListInventory: conditions not met for creature entry %u item %u", vendor->GetEntry(), item->item);
continue;
}
++count;
// reputation discount
int32 price = item->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0;
data << uint32(slot + 1); // client expects counting to start at 1
data << uint32(item->item);
data << uint32(itemTemplate->DisplayInfoID);
data << int32(leftInStock);
data << uint32(price);
data << uint32(itemTemplate->MaxDurability);
data << uint32(itemTemplate->BuyCount);
data << uint32(item->ExtendedCost);
}
}
}
if (count == 0)
{
data << uint8(0);
SendPacket(&data);
return;
}
data.put<uint8>(countPos, count);
SendPacket(&data);
}
void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket& recvData)
{
//sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_AUTOSTORE_BAG_ITEM");
uint8 srcbag, srcslot, dstbag;
recvData >> srcbag >> srcslot >> dstbag;
//sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag);
Item* pItem = _player->GetItemByPos(srcbag, srcslot);
if (!pItem)
return;
if (!_player->IsValidPos(dstbag, NULL_SLOT, false)) // can be autostore pos
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
}
uint16 src = pItem->GetPos();
// check unequip potability for equipped items and bank bags
if (_player->IsEquipmentPos (src) || _player->IsBagPos (src))
{
InventoryResult msg = _player->CanUnequipItem(src, !_player->IsBagPos (src));
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pItem, NULL);
return;
}
}
ItemPosCountVec dest;
InventoryResult msg = _player->CanStoreItem(dstbag, NULL_SLOT, dest, pItem, false);
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pItem, NULL);
return;
}
// no-op: placed in same slot
if (dest.size() == 1 && dest[0].pos == src)
{
// just remove grey item state
_player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL);
return;
}
_player->RemoveItem(srcbag, srcslot, true);
_player->StoreItem(dest, pItem, true);
}
void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_BUY_BANK_SLOT");
uint64 guid;
recvPacket >> guid;
// cheating protection
/* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command.
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER);
if (!creature)
{
sLog->outDebug("WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
return;
}
*/
uint32 slot = _player->GetBankBagSlotCount();
// next slot
++slot;
sLog->outInfo(LOG_FILTER_NETWORKIO, "PLAYER: Buy bank bag slot, slot number = %u", slot);
BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot);
WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4);
if (!slotEntry)
{
data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY);
SendPacket(&data);
return;
}
uint32 price = slotEntry->price;
if (!_player->HasEnoughMoney(price))
{
data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS);
SendPacket(&data);
return;
}
_player->SetBankBagSlotCount(slot);
_player->ModifyMoney(-int32(price));
data << uint32(ERR_BANKSLOT_OK);
SendPacket(&data);
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT);
}
void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOBANK_ITEM");
uint8 srcbag, srcslot;
recvPacket >> srcbag >> srcslot;
sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
Item* pItem = _player->GetItemByPos(srcbag, srcslot);
if (!pItem)
return;
ItemPosCountVec dest;
InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pItem, NULL);
return;
}
if (dest.size() == 1 && dest[0].pos == pItem->GetPos())
{
_player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL);
return;
}
_player->RemoveItem(srcbag, srcslot, true);
_player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
_player->BankItem(dest, pItem, true);
}
void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_BANK_ITEM");
uint8 srcbag, srcslot;
recvPacket >> srcbag >> srcslot;
sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
Item* pItem = _player->GetItemByPos(srcbag, srcslot);
if (!pItem)
return;
if (_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory
{
ItemPosCountVec dest;
InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pItem, NULL);
return;
}
_player->RemoveItem(srcbag, srcslot, true);
_player->StoreItem(dest, pItem, true);
_player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount());
}
else // moving from inventory to bank
{
ItemPosCountVec dest;
InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, pItem, NULL);
return;
}
_player->RemoveItem(srcbag, srcslot, true);
_player->BankItem(dest, pItem, true);
}
}
void WorldSession::HandleSetAmmoOpcode(WorldPacket& recvData)
{
if (!GetPlayer()->isAlive())
{
GetPlayer()->SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL);
return;
}
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SET_AMMO");
uint32 item;
recvData >> item;
if (!item)
GetPlayer()->RemoveAmmo();
else
GetPlayer()->SetAmmo(item);
}
void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster, uint32 ItemID, uint32 SpellID)
{
WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10
data << uint64(Target);
data << uint64(Caster);
data << uint32(ItemID);
data << uint32(SpellID);
data << uint8(0);
SendPacket(&data);
}
void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid, uint32 slot, uint32 Duration)
{
// last check 2.0.10
WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8));
data << uint64(Itemguid);
data << uint32(slot);
data << uint32(Duration);
data << uint64(Playerguid);
SendPacket(&data);
}
void WorldSession::HandleItemNameQueryOpcode(WorldPacket& recvData)
{
uint32 itemid;
recvData >> itemid;
recvData.read_skip<uint64>(); // guid
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_NAME_QUERY %u", itemid);
ItemSetNameEntry const* pName = sObjectMgr->GetItemSetNameEntry(itemid);
if (pName)
{
std::string Name = pName->name;
int loc_idx = GetSessionDbLocaleIndex();
if (loc_idx >= 0)
if (ItemSetNameLocale const* isnl = sObjectMgr->GetItemSetNameLocale(itemid))
ObjectMgr::GetLocaleString(isnl->Name, loc_idx, Name);
WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+Name.size()+1+4));
data << uint32(itemid);
data << Name;
data << uint32(pName->InventoryType);
SendPacket(&data);
}
}
void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_WRAP_ITEM");
uint8 gift_bag, gift_slot, item_bag, item_slot;
recvData >> gift_bag >> gift_slot; // paper
recvData >> item_bag >> item_slot; // item
sLog->outDebug(LOG_FILTER_NETWORKIO, "WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot);
Item* gift = _player->GetItemByPos(gift_bag, gift_slot);
if (!gift)
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL);
return;
}
if (!(gift->GetTemplate()->Flags & ITEM_PROTO_FLAG_WRAPPER)) // cheating: non-wrapper wrapper
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL);
return;
}
Item* item = _player->GetItemByPos(item_bag, item_slot);
if (!item)
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL);
return;
}
if (item == gift) // not possable with pacjket from real client
{
_player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL);
return;
}
if (item->IsEquipped())
{
_player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL);
return;
}
if (item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
{
_player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL);
return;
}
if (item->IsBag())
{
_player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL);
return;
}
if (item->IsSoulBound())
{
_player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL);
return;
}
if (item->GetMaxStackCount() != 1)
{
_player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL);
return;
}
// maybe not correct check (it is better than nothing)
if (item->GetTemplate()->MaxCount>0)
{
_player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL);
return;
}
SQLTransaction trans = CharacterDatabase.BeginTransaction();
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GIFT);
stmt->setUInt32(0, GUID_LOPART(item->GetOwnerGUID()));
stmt->setUInt32(1, item->GetGUIDLow());
stmt->setUInt32(2, item->GetEntry());
stmt->setUInt32(3, item->GetUInt32Value(ITEM_FIELD_FLAGS));
trans->Append(stmt);
item->SetEntry(gift->GetEntry());
switch (item->GetEntry())
{
case 5042: item->SetEntry(5043); break;
case 5048: item->SetEntry(5044); break;
case 17303: item->SetEntry(17302); break;
case 17304: item->SetEntry(17305); break;
case 17307: item->SetEntry(17308); break;
case 21830: item->SetEntry(21831); break;
}
item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID());
item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED);
item->SetState(ITEM_CHANGED, _player);
if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance`
{
// after save it will be impossible to remove the item from the queue
item->RemoveFromUpdateQueueOf(_player);
item->SaveToDB(trans); // item gave inventory record unchanged and can be save standalone
}
CharacterDatabase.CommitTransaction(trans);
uint32 count = 1;
_player->DestroyItemCount(gift, count, true);
}
void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SOCKET_GEMS");
uint64 item_guid;
uint64 gem_guids[MAX_GEM_SOCKETS];
recvData >> item_guid;
if (!item_guid)
return;
for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
recvData >> gem_guids[i];
//cheat -> tried to socket same gem multiple times
if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) ||
(gem_guids[1] && (gem_guids[1] == gem_guids[2])))
return;
Item* itemTarget = _player->GetItemByGuid(item_guid);
if (!itemTarget) //missing item to socket
return;
ItemTemplate const* itemProto = itemTarget->GetTemplate();
if (!itemProto)
return;
//this slot is excepted when applying / removing meta gem bonus
uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT);
Item* Gems[MAX_GEM_SOCKETS];
for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL;
GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS];
for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage
GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetTemplate()->GemProperties) : NULL;
for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe
{
if (!GemProps[i])
continue;
// tried to put gem in socket where no socket exists (take care about prismatic sockets)
if (!itemProto->Socket[i].Color)
{
// no prismatic socket
if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
return;
// not first not-colored (not normaly used) socket
if (i != 0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color))
return;
// ok, this is first not colored socket for item with prismatic socket
}
// tried to put normal gem in meta socket
if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META)
return;
// tried to put meta gem in normal socket
if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META)
return;
}
uint32 GemEnchants[MAX_GEM_SOCKETS];
uint32 OldEnchants[MAX_GEM_SOCKETS];
for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments
{
GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0;
OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i));
}
// check unique-equipped conditions
for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
{
if (!Gems[i])
continue;
// continue check for case when attempt add 2 similar unique equipped gems in one item.
ItemTemplate const* iGemProto = Gems[i]->GetTemplate();
// unique item (for new and already placed bit removed enchantments
if (iGemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED)
{
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
{
if (i == j) // skip self
continue;
if (Gems[j])
{
if (iGemProto->ItemId == Gems[j]->GetEntry())
{
_player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL);
return;
}
}
else if (OldEnchants[j])
{
if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
{
if (iGemProto->ItemId == enchantEntry->GemID)
{
_player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL);
return;
}
}
}
}
}
// unique limit type item
int32 limit_newcount = 0;
if (iGemProto->ItemLimitCategory)
{
if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory))
{
// NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
{
if (Gems[j])
{
// new gem
if (iGemProto->ItemLimitCategory == Gems[j]->GetTemplate()->ItemLimitCategory)
++limit_newcount;
}
else if (OldEnchants[j])
{
// existing gem
if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(enchantEntry->GemID))
if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
++limit_newcount;
}
}
if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount)
{
_player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL);
return;
}
}
}
// for equipped item check all equipment for duplicate equipped gems
if (itemTarget->IsEquipped())
{
if (InventoryResult res = _player->CanEquipUniqueItem(Gems[i], slot, std::max(limit_newcount, 0)))
{
_player->SendEquipError(res, itemTarget, NULL);
return;
}
}
}
bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus
_player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item)
//if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met
//remove ALL enchants
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot)
_player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false);
for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
{
if (GemEnchants[i])
{
itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i], 0, 0);
if (Item* guidItem = _player->GetItemByGuid(gem_guids[i]))
_player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true);
}
}
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
_player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true);
bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change...
{
_player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false);
itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->socketBonus : 0), 0, 0);
_player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true);
//it is not displayed, client has an inbuilt system to determine if the bonus is activated
}
_player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item)
_player->RemoveTradeableItem(itemTarget);
itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag
}
void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT");
uint32 eslot;
recvData >> eslot;
// apply only to equipped item
if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, eslot))
return;
Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot);
if (!item)
return;
if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
return;
GetPlayer()->ApplyEnchantment(item, TEMP_ENCHANTMENT_SLOT, false);
item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT);
}
void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_REFUND_INFO");
uint64 guid;
recvData >> guid; // item guid
Item* item = _player->GetItemByGuid(guid);
if (!item)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "Item refund: item not found!");
return;
}
GetPlayer()->SendRefundInfo(item);
}
void WorldSession::HandleItemRefund(WorldPacket &recvData)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_REFUND");
uint64 guid;
recvData >> guid; // item guid
Item* item = _player->GetItemByGuid(guid);
if (!item)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "Item refund: item not found!");
return;
}
GetPlayer()->RefundItem(item);
}
/**
* Handles the packet sent by the client when requesting information about item text.
*
* This function is called when player clicks on item which has some flag set
*/
void WorldSession::HandleItemTextQuery(WorldPacket& recvData )
{
uint64 itemGuid;
recvData >> itemGuid;
sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ITEM_TEXT_QUERY item guid: %u", GUID_LOPART(itemGuid));
WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4+10)); // guess size
if (Item* item = _player->GetItemByGuid(itemGuid))
{
data << uint8(0); // has text
data << uint64(itemGuid); // item guid
data << item->GetText();
}
else
{
data << uint8(1); // no text
}
SendPacket(&data);
}