diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/server/game/Entities/Item/Item.cpp | 111 | ||||
-rwxr-xr-x | src/server/game/Entities/Item/Item.h | 7 | ||||
-rwxr-xr-x | src/server/game/Entities/Item/ItemPrototype.h | 3 | ||||
-rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 1 | ||||
-rwxr-xr-x | src/server/game/Handlers/ItemHandler.cpp | 169 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 3 | ||||
-rwxr-xr-x | src/server/game/Server/Protocol/Opcodes.h | 4 | ||||
-rwxr-xr-x | src/server/game/Server/WorldSession.h | 4 |
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); |