aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Entities/Item/Item.cpp111
-rwxr-xr-xsrc/server/game/Entities/Item/Item.h7
-rwxr-xr-xsrc/server/game/Entities/Item/ItemPrototype.h3
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h1
-rwxr-xr-xsrc/server/game/Handlers/ItemHandler.cpp169
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp3
-rwxr-xr-xsrc/server/game/Server/Protocol/Opcodes.h4
-rwxr-xr-xsrc/server/game/Server/WorldSession.h4
8 files changed, 298 insertions, 4 deletions
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 248b080bfdd..130aac50935 100755
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -1196,3 +1196,114 @@ bool Item::CheckSoulboundTradeExpire()
return false;
}
+
+bool Item::CanBeTransmogrified() const
+{
+ ItemTemplate const* proto = GetTemplate();
+
+ if (!proto)
+ return false;
+
+ if (proto->Quality == ITEM_QUALITY_LEGENDARY)
+ return false;
+
+ if (proto->Class != ITEM_CLASS_ARMOR &&
+ proto->Class != ITEM_CLASS_WEAPON)
+ return false;
+
+ if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
+ return false;
+
+ if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG)
+ return false;
+
+ if (!HasStats())
+ return false;
+
+ return true;
+}
+
+bool Item::CanTransmogrify() const
+{
+ ItemTemplate const* proto = GetTemplate();
+
+ if (!proto)
+ return false;
+
+ if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG)
+ return false;
+
+ if (proto->Quality == ITEM_QUALITY_LEGENDARY)
+ return false;
+
+ if (proto->Class != ITEM_CLASS_ARMOR &&
+ proto->Class != ITEM_CLASS_WEAPON)
+ return false;
+
+ if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
+ return false;
+
+ if (proto->Flags2 & ITEM_FLAGS_EXTRA_CAN_TRANSMOG)
+ return true;
+
+ if (!HasStats())
+ return false;
+
+ return true;
+}
+
+bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* transmogrifier)
+{
+ if (!transmogrifier || !transmogrified)
+ return false;
+
+ ItemTemplate const* proto1 = transmogrifier->GetTemplate(); // source
+ ItemTemplate const* proto2 = transmogrified->GetTemplate(); // dest
+
+ if (proto1->ItemId == proto2->ItemId)
+ return false;
+
+ if (!transmogrified->CanTransmogrify() || !transmogrifier->CanBeTransmogrified())
+ return false;
+
+ if (proto1->InventoryType == INVTYPE_BAG ||
+ proto1->InventoryType == INVTYPE_RELIC ||
+ proto1->InventoryType == INVTYPE_BODY ||
+ proto1->InventoryType == INVTYPE_FINGER ||
+ proto1->InventoryType == INVTYPE_TRINKET ||
+ proto1->InventoryType == INVTYPE_AMMO ||
+ proto1->InventoryType == INVTYPE_QUIVER)
+ return false;
+
+ if (proto1->SubClass != proto2->SubClass && (proto1->Class != ITEM_CLASS_WEAPON || !transmogrified->IsRangedWeapon() || !transmogrifier->IsRangedWeapon()))
+ return false;
+
+ if (proto1->InventoryType != proto2->InventoryType &&
+ (proto1->Class != ITEM_CLASS_WEAPON || (proto2->InventoryType != INVTYPE_WEAPONMAINHAND && proto2->InventoryType != INVTYPE_WEAPONOFFHAND)))
+ return false;
+
+ return true;
+}
+
+bool Item::HasStats() const
+{
+ if (GetItemRandomPropertyId() != 0)
+ return true;
+
+ for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
+ if (GetTemplate()->ItemStat[i].ItemStatValue != 0)
+ return true;
+
+ return false;
+}
+
+bool Item::IsRangedWeapon() const
+{
+ ItemTemplate const* proto = GetTemplate();
+ if (proto && proto->Class == ITEM_CLASS_WEAPON)
+ return proto->SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
+ proto->SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
+ proto->SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW;
+
+ return false;
+}
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index d38e8c32e30..2f9d10bb9d5 100755
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -317,10 +317,12 @@ class Item : public Object
bool hasQuest(uint32 quest_id) const { return GetTemplate()->StartQuest == quest_id; }
bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; }
+ bool HasStats() const;
bool IsPotion() const { return GetTemplate()->IsPotion(); }
bool IsWeaponVellum() const { return GetTemplate()->IsWeaponVellum(); }
bool IsArmorVellum() const { return GetTemplate()->IsArmorVellum(); }
bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); }
+ bool IsRangedWeapon() const;
// Item Refund system
void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = NULL);
@@ -343,6 +345,11 @@ class Item : public Object
void BuildUpdate(UpdateDataMapType&);
uint32 GetScriptId() const { return GetTemplate()->ScriptId; }
+
+ bool CanBeTransmogrified() const;
+ bool CanTransmogrify() const;
+ static bool CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* transmogrifier);
+
private:
std::string m_text;
uint8 m_slot;
diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h
index 9e14dcb7733..7bfe43e0691 100755
--- a/src/server/game/Entities/Item/ItemPrototype.h
+++ b/src/server/game/Entities/Item/ItemPrototype.h
@@ -197,6 +197,9 @@ enum ItemFlagsExtra
ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100,
ITEM_FLAGS_EXTRA_CASTER_WEAPON = 0x00000200,
ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND = 0x00020000,
+ ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG = 0x00200000,
+ ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG = 0x00400000,
+ ITEM_FLAGS_EXTRA_CAN_TRANSMOG = 0x00800000,
};
enum ItemFlagsCustom
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index a010a119017..3133d75fa07 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -662,6 +662,7 @@ enum NPCFlags
UNIT_NPC_FLAG_SPELLCLICK = 0x01000000, // cause client to send 1015 opcode (spell click)
UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x02000000, // players with mounts that have vehicle data should have it set
UNIT_NPC_FLAG_REFORGER = 0x08000000, // reforging
+ UNIT_NPC_FLAG_TRANSMOGRIFIER = 0x10000000, // transmogrification
UNIT_NPC_FLAG_VAULTKEEPER = 0x20000000, // void storage
};
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index bcb3601ee48..0b21363a783 100755
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -237,7 +237,7 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPacket & recv_data)
void WorldSession::HandleDestroyItemOpcode(WorldPacket & recv_data)
{
- //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_DESTROYITEM");
+ //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_DESTROY_ITEM");
uint8 bag, slot, count, data1, data2, data3;
recv_data >> bag >> slot >> count >> data1 >> data2 >> data3;
@@ -1457,3 +1457,170 @@ void WorldSession::HandleItemTextQuery(WorldPacket & recv_data )
SendPacket(&data);
}
+
+void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData)
+{
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_TRANSMOGRIFY_ITEMS");
+ Player* player = GetPlayer();
+
+ // Read data
+
+ uint32 count = recvData.ReadBits(22);
+
+ if (count < EQUIPMENT_SLOT_START || count >= EQUIPMENT_SLOT_END)
+ {
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) sent a wrong count (%u) when transmogrifying items.", player->GetGUIDLow(), player->GetName(), count);
+ recvData.rfinish();
+ return;
+ }
+
+ ObjectGuid* itemGuids = new ObjectGuid[count];
+ uint32* newEntries = new uint32[count];
+ uint32* slots = new uint32[count];
+
+ for (uint8 i = 0; i < count; ++i)
+ {
+ itemGuids[i][0] = recvData.ReadBit();
+ itemGuids[i][5] = recvData.ReadBit();
+ itemGuids[i][6] = recvData.ReadBit();
+ itemGuids[i][2] = recvData.ReadBit();
+ itemGuids[i][3] = recvData.ReadBit();
+ itemGuids[i][7] = recvData.ReadBit();
+ itemGuids[i][4] = recvData.ReadBit();
+ itemGuids[i][1] = recvData.ReadBit();
+ }
+
+ ObjectGuid npcGuid;
+ npcGuid[7] = recvData.ReadBit();
+ npcGuid[3] = recvData.ReadBit();
+ npcGuid[5] = recvData.ReadBit();
+ npcGuid[6] = recvData.ReadBit();
+ npcGuid[1] = recvData.ReadBit();
+ npcGuid[4] = recvData.ReadBit();
+ npcGuid[0] = recvData.ReadBit();
+ npcGuid[2] = recvData.ReadBit();
+
+ recvData.FlushBits();
+
+ for (uint32 i = 0; i < count; ++i)
+ {
+ recvData >> uint32(newEntries[i]);
+
+ recvData.ReadByteSeq(itemGuids[i][1]);
+ recvData.ReadByteSeq(itemGuids[i][5]);
+ recvData.ReadByteSeq(itemGuids[i][0]);
+ recvData.ReadByteSeq(itemGuids[i][4]);
+ recvData.ReadByteSeq(itemGuids[i][6]);
+ recvData.ReadByteSeq(itemGuids[i][7]);
+ recvData.ReadByteSeq(itemGuids[i][3]);
+ recvData.ReadByteSeq(itemGuids[i][2]);
+
+ recvData >> uint32(slots[i]);
+ }
+
+ recvData.ReadByteSeq(npcGuid[7]);
+ recvData.ReadByteSeq(npcGuid[2]);
+ recvData.ReadByteSeq(npcGuid[5]);
+ recvData.ReadByteSeq(npcGuid[4]);
+ recvData.ReadByteSeq(npcGuid[3]);
+ recvData.ReadByteSeq(npcGuid[1]);
+ recvData.ReadByteSeq(npcGuid[6]);
+ recvData.ReadByteSeq(npcGuid[0]);
+
+ // Validate
+
+ if (!player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_TRANSMOGRIFIER))
+ {
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid));
+ return;
+ }
+
+ for (uint8 i = 0; i < count; ++i)
+ {
+ // slot of the transmogrified item
+ if (slots[i] < EQUIPMENT_SLOT_START || slots[i] >= EQUIPMENT_SLOT_END)
+ {
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an item (lowguid: %u) with a wrong slot (%u) when transmogrifying items.", player->GetGUIDLow(), player->GetName(), GUID_LOPART(itemGuids[i]), slots[i]);
+ return;
+ }
+
+ // entry of the transmogrifier item, if it's not 0
+ if (newEntries[i])
+ {
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newEntries[i]);
+ if (!proto)
+ {
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify to an invalid item (entry: %u).", player->GetGUIDLow(), player->GetName(), newEntries[i]);
+ return;
+ }
+ }
+
+ Item* itemTransmogrifier = NULL;
+ // guid of the transmogrifier item, if it's not 0
+ if (itemGuids[i])
+ {
+ itemTransmogrifier = player->GetItemByGuid(itemGuids[i]);
+ if (!itemTransmogrifier)
+ {
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify with an invalid item (guid: "UI64FMTD").", player->GetGUIDLow(), player->GetName(), itemGuids[i]);
+ return;
+ }
+ }
+
+ // transmogrified item
+ Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slots[i]);
+ if (!itemTransmogrified)
+ {
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUIDLow(), player->GetName(), slots[i]);
+ return;
+ }
+
+ // uint16 tempDest;
+ //// has to be able to equip item transmogrified item
+ //if (!player->CanEquipItem(slots[i], tempDest, itemTransmogrified, true, true))
+ //{
+ // sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the item to be transmogrified (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName(), slots[i], itemTransmogrified->GetEntry());
+ // return;
+ //}
+ //
+ //// has to be able to equip item transmogrifier item
+ //if (!player->CanEquipItem(slots[i], tempDest, itemTransmogrifier, true, true))
+ //{
+ // sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the transmogrifier item (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName(), slots[i], itemTransmogrifier->GetEntry());
+ // return;
+ //}
+
+ if (!newEntries[i]) // reset look
+ {
+ player->SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slots[i] * 2), itemTransmogrified->GetEntry());
+ itemTransmogrified->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_10_1, 0);
+ }
+ else
+ {
+ if (!Item::CanTransmogrifyItemWithItem(itemTransmogrified, itemTransmogrifier))
+ {
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUIDLow(), player->GetName(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry());
+ return;
+ }
+
+ // All okay, proceed
+
+ player->SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slots[i] * 2), newEntries[i]);
+ itemTransmogrified->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_10_1, newEntries[i]);
+
+ itemTransmogrified->UpdatePlayedTime(player);
+
+ itemTransmogrified->SetOwnerGUID(player->GetGUID());
+ itemTransmogrified->SetNotRefundable(player);
+ itemTransmogrified->ClearSoulboundTradeable(player);
+
+ itemTransmogrifier->SetOwnerGUID(player->GetGUID());
+ itemTransmogrifier->SetNotRefundable(player);
+ itemTransmogrifier->ClearSoulboundTradeable(player);
+ }
+ }
+
+ delete[] itemGuids;
+ delete[] newEntries;
+ delete[] slots;
+}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index aa959a7666a..166a9ad5601 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -227,7 +227,7 @@ void InitOpcodes()
//DEFINE_OPCODE_HANDLER(CMSG_DEL_IGNORE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDelIgnoreOpcode );
//DEFINE_OPCODE_HANDLER(CMSG_DEL_PVP_MEDAL_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_OPCODE_HANDLER(CMSG_DEL_VOICE_IGNORE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- //DEFINE_OPCODE_HANDLER(CMSG_DESTROYITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDestroyItemOpcode );
+ DEFINE_OPCODE_HANDLER(CMSG_DESTROY_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDestroyItemOpcode );
//DEFINE_OPCODE_HANDLER(CMSG_DESTROYMONSTER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_OPCODE_HANDLER(CMSG_DESTROY_ITEMS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_OPCODE_HANDLER(CMSG_DISABLE_PVP_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -650,6 +650,7 @@ void InitOpcodes()
//DEFINE_OPCODE_HANDLER(CMSG_TOGGLE_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP );
//DEFINE_OPCODE_HANDLER(CMSG_TOGGLE_XP_GAIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_OPCODE_HANDLER(CMSG_TOTEM_DESTROYED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTotemDestroyed );
+ DEFINE_OPCODE_HANDLER(CMSG_TRANSMOGRIFY_ITEMS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTransmogrifyItems );
//DEFINE_OPCODE_HANDLER(CMSG_TRAINER_BUY_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerBuySpellOpcode );
//DEFINE_OPCODE_HANDLER(CMSG_TRAINER_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerListOpcode );
//DEFINE_OPCODE_HANDLER(CMSG_TRIGGER_CINEMATIC_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index d286e33fcbb..b1790d096b8 100755
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -182,8 +182,8 @@ enum Opcodes
CMSG_DEL_FRIEND = 0x6A15,
CMSG_DEL_IGNORE = 0x4727,
CMSG_DEL_VOICE_IGNORE = 0x0024,
- CMSG_DESTROYITEM = 0x0000,
- CMSG_DESTROY_ITEMS = 0x4A27,
+ CMSG_DESTROY_ITEM = 0x4A27,
+ CMSG_DESTROY_ITEMS = 0x0000,
CMSG_DISMISS_CONTROLLED_VEHICLE = 0x3218,
CMSG_DISMISS_CRITTER = 0x4227,
CMSG_DUEL_ACCEPTED = 0x2136,
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index c215063fefa..38351e8340b 100755
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -918,6 +918,10 @@ class WorldSession
void HandleVoidSwapItem(WorldPacket& recvData);
void SendVoidStorageTransferResult(VoidTransferError result);
+ // Transmogrification
+ void HandleTransmogrifyItems(WorldPacket& recvData);
+
+ // Miscellaneous
void HandleSpellClick(WorldPacket& recv_data);
void HandleMirrorImageDataRequest(WorldPacket& recv_data);
void HandleAlterAppearance(WorldPacket& recv_data);