diff options
author | Nay <dnpd.dd@gmail.com> | 2012-07-24 00:06:49 +0100 |
---|---|---|
committer | Nay <dnpd.dd@gmail.com> | 2012-07-24 00:06:49 +0100 |
commit | c4bb17e78d62e46da09d131466f25bd04c27758d (patch) | |
tree | 3b59be7f8b8dc76d13c518e9da3f4efac0ed7ed8 | |
parent | 370c982cc044dd970682a5fdd251d05b79fdb0c3 (diff) |
Core/NPCs: Fix vendors
Enable CMSG_LIST_INVENTORY and SMSG_LIST_INVENTORY
Update and rewrite SMSG_LIST_INVENTORY
-rwxr-xr-x | src/server/game/Handlers/ItemHandler.cpp | 189 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 4 |
2 files changed, 104 insertions, 89 deletions
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index edd0d396e2f..2b2526ef1fd 100755 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -27,6 +27,7 @@ #include "UpdateData.h" #include "ObjectAccessor.h" #include "SpellInfo.h" +#include <list> void WorldSession::HandleSplitItemOpcode(WorldPacket & recv_data) { @@ -722,6 +723,19 @@ void WorldSession::HandleListInventoryOpcode(WorldPacket & recv_data) SendListInventory(guid); } +struct VendorItemHelper +{ + uint32 Slot; + uint32 Type; + uint32 Entry; + uint32 DisplayId; + uint32 Durability; + uint32 ExtendedCost; + uint32 Price; + int32 LeftInStock; + uint32 BuyCount; +}; + void WorldSession::SendListInventory(uint64 vendorGuid) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY"); @@ -742,111 +756,112 @@ void WorldSession::SendListInventory(uint64 vendorGuid) if (vendor->HasUnitState(UNIT_STATE_MOVING)) vendor->StopMoving(); - uint8* bytes = (uint8*)&vendorGuid; + // build list of available items + VendorItemData const* vendorItems = vendor->GetVendorItems(); + std::list<VendorItemHelper> items; + uint8 rawItemCount = vendorItems ? vendorItems->GetItemCount() : 0; - VendorItemData const* items = vendor->GetVendorItems(); - if (!items) - { - WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1); - data.WriteBit(bytes[5]); - data.WriteBit(bytes[6]); - data.WriteBit(bytes[1]); - data.WriteBit(bytes[2]); - data.WriteBit(bytes[3]); - data.WriteBit(bytes[0]); - data.WriteBit(bytes[7]); - data.WriteBit(bytes[4]); - - data.WriteByteSeq(bytes[2]); - data.WriteByteSeq(bytes[3]); - - data << uint8(0); // count == 0, next will be error code - data << uint8(0xA0); // Only seen 0xA0 (160) so far ( should we send 0 here?) - - data.WriteByteSeq(bytes[4]); - data.WriteByteSeq(bytes[7]); - data.WriteByteSeq(bytes[6]); - SendPacket(&data); - return; - } + //if (rawItemCount > 300), + // rawItemCount = 300; // client cap but uint8 max value is 255 - uint8 itemCount = items->GetItemCount(); + const float discountMod = _player->GetReputationPriceDiscount(vendor); uint8 count = 0; + for (uint8 slot = 0; slot < rawItemCount; ++slot) + { + VendorItem const* vendorItem = vendorItems->GetItem(slot); + if (!vendorItem) continue; - WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4); + ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(vendorItem->item); + if (!itemTemplate) continue; - data.WriteBit(bytes[5]); - data.WriteBit(bytes[6]); - data.WriteBit(bytes[1]); - data.WriteBit(bytes[2]); - data.WriteBit(bytes[3]); - data.WriteBit(bytes[0]); - data.WriteBit(bytes[7]); - data.WriteBit(bytes[4]); + if (!_player->isGameMaster()) // ignore conditions if GM on + { + // Respect allowed class + if (!(itemTemplate->AllowableClass & _player->getClassMask())) + continue; + + // Do not sell BOP items + if (itemTemplate->Bonding == BIND_WHEN_PICKED_UP) + continue; + + // Only display items in vendor lists for the team the player is on + if ((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 = !vendorItem->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(vendorItem); + if (leftInStock == 0) + continue; + } + + int32 price = vendorItem->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0; + uint32 leftInStock = !vendorItem->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(vendorItem); + + VendorItemHelper item; + item.Slot = count + 1; // client expects counting to start at 1 + item.Type = 1; // 1 is items, 2 is currency (FIXME: currency isn't implemented) + item.Entry = vendorItem->item; + item.DisplayId = itemTemplate->DisplayInfoID; + item.Durability = itemTemplate->MaxDurability; + item.ExtendedCost = vendorItem->ExtendedCost; + item.Price = price; + item.LeftInStock = leftInStock; + item.BuyCount = itemTemplate->BuyCount; + + items.push_back(item); + } - data.WriteByteSeq(bytes[2]); - data.WriteByteSeq(bytes[3]); + uint8* guidBytes = (uint8*)&vendorGuid; - size_t countPos = data.wpos(); - data << uint32(count); + WorldPacket data(SMSG_LIST_INVENTORY, 12 + 33 * items.size()); - data.WriteByteSeq(bytes[5]); - data.WriteByteSeq(bytes[0]); - data.WriteByteSeq(bytes[1]); + data.WriteBit(guidBytes[1]); + data.WriteBit(guidBytes[0]); - data << uint8(0xA0); // Only seen 0xA0 (160) so far + data.WriteBits(items.size(), 21); // item count - data.WriteByteSeq(bytes[4]); - data.WriteByteSeq(bytes[7]); - data.WriteByteSeq(bytes[6]); + data.WriteBit(guidBytes[3]); + data.WriteBit(guidBytes[6]); + data.WriteBit(guidBytes[5]); + data.WriteBit(guidBytes[2]); + data.WriteBit(guidBytes[7]); + for (std::list<VendorItemHelper>::const_iterator itr = items.begin(); itr != items.end(); ++itr) + { + data.WriteBit((*itr).ExtendedCost == 0); + data.WriteBit(1); // unk "enabler" + } - float discountMod = _player->GetReputationPriceDiscount(vendor); + data.WriteBit(guidBytes[4]); - for (uint8 slot = 0; slot < itemCount; ++slot) + for (std::list<VendorItemHelper>::const_iterator itr = items.begin(); itr != items.end(); ++itr) { - 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; + data << uint32((*itr).Slot); + data << uint32((*itr).Durability); + if ((*itr).ExtendedCost != 0) + data << uint32((*itr).ExtendedCost); + data << uint32((*itr).Entry); + data << uint32((*itr).Type); + data << uint32((*itr).Price); + data << uint32((*itr).DisplayId); + // if (!unk "enabler") data << uint32(something); + data << int32((*itr).LeftInStock); + data << uint32((*itr).BuyCount); + } - // Items sold out are not displayed in list - uint32 leftInStock = !item->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(item); - if (!_player->isGameMaster() && !leftInStock) - continue; + data.WriteByteSeq(guidBytes[5]); + data.WriteByteSeq(guidBytes[4]); + data.WriteByteSeq(guidBytes[1]); + data.WriteByteSeq(guidBytes[0]); + data.WriteByteSeq(guidBytes[6]); - ++count; - - // reputation discount - int32 price = item->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0; - - data << uint32(itemTemplate->MaxDurability); - data << uint32(slot + 1); // client expects counting to start at 1 - data << uint32(item->item); - data << uint32(0); // Always 0? - data << uint32(itemTemplate->DisplayInfoID); - data << int32(leftInStock); - data << uint32(itemTemplate->BuyCount); - data << uint32(item->ExtendedCost); - data << uint32(1); // Always 1? - data << uint32(price); - } - } - } + data << uint8(items.size() == 0); // unk byte, item count 0: 1, item count != 0: 0 or some "random" value below 300 - if (count == 0) - { - SendPacket(&data); - return; - } + data.WriteByteSeq(guidBytes[2]); + data.WriteByteSeq(guidBytes[3]); + data.WriteByteSeq(guidBytes[7]); - data.put<uint32>(countPos, count); SendPacket(&data); } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index ab2b327ffcd..94568f00c6f 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -380,7 +380,7 @@ void InitOpcodes() //DEFINE_OPCODE_HANDLER(CMSG_LFG_SET_NEEDS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_LFG_SET_ROLES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetRolesOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_LFG_TELEPORT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgTeleportOpcode ); - //DEFINE_OPCODE_HANDLER(CMSG_LIST_INVENTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleListInventoryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LIST_INVENTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleListInventoryOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_LOAD_DANCES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER(CMSG_LOAD_SCREEN, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleLoadScreenOpcode ); DEFINE_OPCODE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutCancelOpcode ); @@ -1068,7 +1068,7 @@ void InitOpcodes() //DEFINE_OPCODE_HANDLER(SMSG_LFG_UPDATE_PARTY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_LFG_UPDATE_PLAYER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_LFG_UPDATE_SEARCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //DEFINE_OPCODE_HANDLER(SMSG_LIST_INVENTORY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LIST_INVENTORY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_LOGIN_SETTIMESPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_LOGIN_VERIFY_WORLD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_LOGOUT_CANCEL_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); |