Core/Players: Updated trading

* Use special Uniq ObjectGuid::TradeItem for enchanting trade items
* Added additional validation of trade state
* Fixed an ancient bug in trade display causing pending enchantment to never update clientside if too many operations were done in a trading session
This commit is contained in:
Shauren
2015-04-04 00:07:16 +02:00
parent be016b94aa
commit 89007ac1d0
9 changed files with 510 additions and 349 deletions
+17 -10
View File
@@ -97,6 +97,7 @@
#include "ItemPackets.h"
#include "QuestPackets.h"
#include "LootPackets.h"
#include "TradePackets.h"
#define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
@@ -315,6 +316,8 @@ void TradeData::SetItem(TradeSlots slot, Item* item)
SetAccepted(false);
GetTraderData()->SetAccepted(false);
UpdateServerStateIndex();
Update();
// need remove possible trader spell applied to changed item
@@ -338,6 +341,8 @@ void TradeData::SetSpell(uint32 spell_id, Item* castItem /*= NULL*/)
SetAccepted(false);
GetTraderData()->SetAccepted(false);
UpdateServerStateIndex();
Update(true); // send spell info to item owner
Update(false); // send spell info to caster self
}
@@ -349,9 +354,9 @@ void TradeData::SetMoney(uint64 money)
if (!m_player->HasEnoughMoney(money))
{
TradeStatusInfo info;
info.Status = TRADE_STATUS_CLOSE_WINDOW;
info.Result = EQUIP_ERR_NOT_ENOUGH_MONEY;
WorldPackets::Trade::TradeStatus info;
info.Status = TRADE_STATUS_FAILED;
info.BagResult = EQUIP_ERR_NOT_ENOUGH_MONEY;
m_player->GetSession()->SendTradeStatus(info);
return;
}
@@ -361,6 +366,8 @@ void TradeData::SetMoney(uint64 money)
SetAccepted(false);
GetTraderData()->SetAccepted(false);
UpdateServerStateIndex();
Update(true);
}
@@ -378,8 +385,8 @@ void TradeData::SetAccepted(bool state, bool crosssend /*= false*/)
if (!state)
{
TradeStatusInfo info;
info.Status = TRADE_STATUS_BACK_TO_TRADE;
WorldPackets::Trade::TradeStatus info;
info.Status = TRADE_STATUS_UNACCEPTED;
if (crosssend)
m_trader->GetSession()->SendTradeStatus(info);
else
@@ -10157,7 +10164,7 @@ bool Player::HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32
return false;
}
InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count /*= NULL*/, uint32* itemLimitCategory /*= NULL*/) const
InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count /*= nullptr*/, uint32* offendingItemId /*= nullptr*/) const
{
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry);
if (!pProto)
@@ -10203,8 +10210,8 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item
{
if (no_space_count)
*no_space_count = count + curcount - limitEntry->Quantity;
if (itemLimitCategory)
*itemLimitCategory = pProto->GetItemLimitCategory();
if (offendingItemId)
*offendingItemId = pProto->GetId();
return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS;
}
}
@@ -10735,7 +10742,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des
}
//////////////////////////////////////////////////////////////////////////
InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimitCategory) const
InventoryResult Player::CanStoreItems(Item** items, int count, uint32* offendingItemId) const
{
Item* item2;
@@ -10789,7 +10796,7 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit
ItemTemplate const* pBagProto;
// item is 'one item only'
InventoryResult res = CanTakeMoreSimilarItems(item, itemLimitCategory);
InventoryResult res = CanTakeMoreSimilarItems(item, offendingItemId);
if (res != EQUIP_ERR_OK)
return res;
+14 -18
View File
@@ -1148,19 +1148,6 @@ struct BGData
bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; }
};
struct TradeStatusInfo
{
TradeStatusInfo() : Status(TRADE_STATUS_BUSY), TraderGuid(), Result(EQUIP_ERR_OK),
IsTargetResult(false), ItemLimitCategoryId(0), Slot(0) { }
TradeStatus Status;
ObjectGuid TraderGuid;
InventoryResult Result;
bool IsTargetResult;
uint32 ItemLimitCategoryId;
uint8 Slot;
};
struct VoidStorageItem
{
VoidStorageItem()
@@ -1192,7 +1179,7 @@ class TradeData
public: // constructors
TradeData(Player* player, Player* trader) :
m_player(player), m_trader(trader), m_accepted(false), m_acceptProccess(false),
m_money(0), m_spell(0), m_spellCastItem() { }
m_money(0), m_spell(0), m_spellCastItem(), m_clientStateIndex(1), m_serverStateIndex(1) { }
Player* GetTrader() const { return m_trader; }
TradeData* GetTraderData() const;
@@ -1217,6 +1204,12 @@ class TradeData
bool IsInAcceptProcess() const { return m_acceptProccess; }
void SetInAcceptProcess(bool state) { m_acceptProccess = state; }
uint32 GetClientStateIndex() const { return m_clientStateIndex; }
void UpdateClientStateIndex() { ++m_clientStateIndex; }
uint32 GetServerStateIndex() const { return m_serverStateIndex; }
void UpdateServerStateIndex() { m_serverStateIndex = rand32(); }
private: // internal functions
void Update(bool for_trader = true);
@@ -1235,6 +1228,9 @@ class TradeData
ObjectGuid m_spellCastItem; // applied spell cast by item use
ObjectGuid m_items[TRADE_SLOT_COUNT]; // traded items from m_player side including non-traded slot
uint32 m_clientStateIndex;
uint32 m_serverStateIndex;
};
struct ResurrectionData
@@ -1480,11 +1476,11 @@ class Player : public Unit, public GridObject<Player>
bool CanNoReagentCast(SpellInfo const* spellInfo) const;
bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot = NULL_SLOT) const;
bool HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const;
InventoryResult CanTakeMoreSimilarItems(Item* pItem, uint32* itemLimitCategory = NULL) const { return CanTakeMoreSimilarItems(pItem->GetEntry(), pItem->GetCount(), pItem, NULL, itemLimitCategory); }
InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, uint32* itemLimitCategory = NULL) const { return CanTakeMoreSimilarItems(entry, count, NULL, NULL, itemLimitCategory); }
InventoryResult CanTakeMoreSimilarItems(Item* pItem, uint32* offendingItemId = nullptr) const { return CanTakeMoreSimilarItems(pItem->GetEntry(), pItem->GetCount(), pItem, nullptr, offendingItemId); }
InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, uint32* offendingItemId = nullptr) const { return CanTakeMoreSimilarItems(entry, count, nullptr, nullptr, offendingItemId); }
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL) const;
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap = false) const;
InventoryResult CanStoreItems(Item** items, int count, uint32* itemLimitCategory) const;
InventoryResult CanStoreItems(Item** items, int count, uint32* offendingItemId) const;
InventoryResult CanEquipNewItem(uint8 slot, uint16& dest, uint32 item, bool swap) const;
InventoryResult CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading = true) const;
@@ -1508,7 +1504,7 @@ class Player : public Unit, public GridObject<Player>
void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false) { AutoStoreLoot(NULL_BAG, NULL_SLOT, loot_id, store, broadcast); }
void StoreLootItem(uint8 lootSlot, Loot* loot);
InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL, uint32* itemLimitCategory = NULL) const;
InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = nullptr, uint32* offendingItemId = nullptr) const;
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item* pItem = NULL, bool swap = false, uint32* no_space_count = NULL) const;
void AddRefundReference(ObjectGuid it);
+116 -243
View File
@@ -31,65 +31,19 @@
#include "AccountMgr.h"
#include "TradePackets.h"
void WorldSession::SendTradeStatus(TradeStatusInfo const& info)
void WorldSession::SendTradeStatus(WorldPackets::Trade::TradeStatus& info)
{
Player* trader = GetPlayer()->GetTrader();
WorldPacket data(SMSG_TRADE_STATUS, 13);
data.WriteBit(trader ? (trader->GetSession()->GetBattlenetAccountId() == GetBattlenetAccountId()) : 0); // IsSameBnetAccount, used for trading heirlooms and other battle.net bound items with your other accounts
data.WriteBits(info.Status, 5);
switch (info.Status)
{
case TRADE_STATUS_BEGIN_TRADE:
data.WriteBit(info.TraderGuid[2]);
data.WriteBit(info.TraderGuid[4]);
data.WriteBit(info.TraderGuid[6]);
data.WriteBit(info.TraderGuid[0]);
data.WriteBit(info.TraderGuid[1]);
data.WriteBit(info.TraderGuid[3]);
data.WriteBit(info.TraderGuid[7]);
data.WriteBit(info.TraderGuid[5]);
data.WriteByteSeq(info.TraderGuid[4]);
data.WriteByteSeq(info.TraderGuid[1]);
data.WriteByteSeq(info.TraderGuid[2]);
data.WriteByteSeq(info.TraderGuid[3]);
data.WriteByteSeq(info.TraderGuid[0]);
data.WriteByteSeq(info.TraderGuid[7]);
data.WriteByteSeq(info.TraderGuid[6]);
data.WriteByteSeq(info.TraderGuid[5]);
break;
case TRADE_STATUS_OPEN_WINDOW:
data << uint32(0); // CGTradeInfo::m_tradeID
break;
case TRADE_STATUS_CLOSE_WINDOW:
data.WriteBit(info.IsTargetResult); // bool isTargetError; used for: EQUIP_ERR_BAG_FULL, EQUIP_ERR_CANT_CARRY_MORE_OF_THIS, EQUIP_ERR_MISSING_REAGENT, EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED
data << uint32(info.Result); // InventoryResult
data << uint32(info.ItemLimitCategoryId); // ItemLimitCategory.dbc entry
break;
case TRADE_STATUS_WRONG_REALM:
case TRADE_STATUS_NOT_ON_TAPLIST:
data << uint8(info.Slot); // Trade slot; -1 here clears CGTradeInfo::m_tradeMoney
break;
case TRADE_STATUS_CURRENCY: // Not implemented
case TRADE_STATUS_CURRENCY_NOT_TRADABLE: // Not implemented
// Blizzard never implemented these, you can only trade currency with the field9 & 1 in CurrencyTypes.DBC, and only two test currencies have that flag
data << uint32(0); // Trading Currency Id
data << uint32(0); // Trading Currency Amount
default:
data.FlushBits();
break;
}
SendPacket(&data);
info.Clear(); // reuse packet
Player* trader = _player->GetTrader();
info.PartnerIsSameBnetAccount = trader && trader->GetSession()->GetBattlenetAccountId() == GetBattlenetAccountId();
SendPacket(info.Write());
}
void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/)
void WorldSession::HandleIgnoreTradeOpcode(WorldPackets::Trade::IgnoreTrade& /*ignoreTrade*/)
{
}
void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/)
void WorldSession::HandleBusyTradeOpcode(WorldPackets::Trade::BusyTrade& /*busyTrade*/)
{
}
@@ -97,106 +51,44 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/)
{
TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData();
ByteBuffer itemData(7*2 + 7*4 + 3*4 + 3*4 + 1);
uint8 count = 0;
for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
if (view_trade->GetItem(TradeSlots(i)))
++count;
WorldPacket data(SMSG_TRADE_UPDATED, 4*6 + 8 + 1 + 3 + count * 70);
data << uint32(0); // CGTradeInfo::m_tradeID
data << uint32(0); // unk 2
data << uint64(view_trade->GetMoney()); // trader gold
data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item
data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases
data << uint32(0); // unk 5
data << uint8(trader_data); // 1 means traders data, 0 means own
data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases
data.WriteBits(count, 22);
WorldPackets::Trade::TradeUpdated tradeUpdated;
tradeUpdated.WhichPlayer = trader_data;
tradeUpdated.ClientStateIndex = view_trade->GetClientStateIndex();
tradeUpdated.CurrentStateIndex = view_trade->GetServerStateIndex();
tradeUpdated.Gold = view_trade->GetMoney();
tradeUpdated.ProposedEnchantment = view_trade->GetSpell();
for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
{
Item* item = view_trade->GetItem(TradeSlots(i));
if (!item)
continue;
ObjectGuid giftCreatorGuid = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR);
ObjectGuid creatorGuid = item->GetGuidValue(ITEM_FIELD_CREATOR);
data.WriteBit(giftCreatorGuid[7]);
data.WriteBit(giftCreatorGuid[1]);
bool notWrapped = data.WriteBit(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED));
data.WriteBit(giftCreatorGuid[3]);
if (notWrapped)
if (Item* item = view_trade->GetItem(TradeSlots(i)))
{
data.WriteBit(creatorGuid[7]);
data.WriteBit(creatorGuid[1]);
data.WriteBit(creatorGuid[4]);
data.WriteBit(creatorGuid[6]);
data.WriteBit(creatorGuid[2]);
data.WriteBit(creatorGuid[3]);
data.WriteBit(creatorGuid[5]);
data.WriteBit(item->GetTemplate()->GetLockID() != 0);
data.WriteBit(creatorGuid[0]);
WorldPackets::Trade::TradeUpdated::TradeItem tradeItem;
tradeItem.Slot = i;
tradeItem.EntryID = item->GetEntry();
tradeItem.StackCount = item->GetCount();
tradeItem.GiftCreator = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR);
if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
{
WorldPackets::Trade::TradeUpdated::UnwrappedTradeItem* unwrappedItem = &tradeItem.Unwrapped.Value;
unwrappedItem->Item.Initalize(item);
unwrappedItem->EnchantID = item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT);
unwrappedItem->OnUseEnchantmentID = item->GetEnchantmentId(USE_ENCHANTMENT_SLOT);
unwrappedItem->Creator = item->GetGuidValue(ITEM_FIELD_CREATOR);
unwrappedItem->Charges = item->GetSpellCharges();
unwrappedItem->Lock = item->GetTemplate()->GetLockID() && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED);
unwrappedItem->MaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
unwrappedItem->Durability = item->GetUInt32Value(ITEM_FIELD_DURABILITY);
for (uint32 s = SOCK_ENCHANTMENT_SLOT; s < MAX_GEM_SOCKETS; ++s)
unwrappedItem->SocketEnchant[s] = item->GetEnchantmentId(EnchantmentSlot(s + SOCK_ENCHANTMENT_SLOT));
itemData.WriteByteSeq(creatorGuid[1]);
tradeItem.Unwrapped.HasValue = true;
}
itemData << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS /*3*/; ++enchant_slot)
itemData << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot)));
itemData << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
itemData.WriteByteSeq(creatorGuid[6]);
itemData.WriteByteSeq(creatorGuid[2]);
itemData.WriteByteSeq(creatorGuid[7]);
itemData.WriteByteSeq(creatorGuid[4]);
itemData << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY));
itemData << uint32(item->GetItemRandomPropertyId());
itemData.WriteByteSeq(creatorGuid[3]);
itemData << uint32(0); // unk7
itemData.WriteByteSeq(creatorGuid[0]);
itemData << uint32(item->GetSpellCharges());
itemData << uint32(item->GetItemSuffixFactor());
itemData.WriteByteSeq(creatorGuid[5]);
tradeUpdated.Items.push_back(tradeItem);
}
data.WriteBit(giftCreatorGuid[6]);
data.WriteBit(giftCreatorGuid[4]);
data.WriteBit(giftCreatorGuid[2]);
data.WriteBit(giftCreatorGuid[0]);
data.WriteBit(giftCreatorGuid[5]);
itemData.WriteByteSeq(giftCreatorGuid[6]);
itemData.WriteByteSeq(giftCreatorGuid[1]);
itemData.WriteByteSeq(giftCreatorGuid[7]);
itemData.WriteByteSeq(giftCreatorGuid[4]);
itemData << uint32(item->GetTemplate()->GetId());
itemData.WriteByteSeq(giftCreatorGuid[0]);
itemData << uint32(item->GetCount());
itemData.WriteByteSeq(giftCreatorGuid[5]);
itemData << uint8(i);
itemData.WriteByteSeq(giftCreatorGuid[2]);
itemData.WriteByteSeq(giftCreatorGuid[3]);
}
data.FlushBits();
data.append(itemData);
SendPacket(&data);
SendPacket(tradeUpdated.Write());
}
//==============================================================
@@ -328,7 +220,7 @@ static void clearAcceptTradeMode(Item* *myItems, Item* *hisItems)
}
}
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
void WorldSession::HandleAcceptTradeOpcode(WorldPackets::Trade::AcceptTrade& acceptTrade)
{
TradeData* my_trade = _player->m_trade;
if (!my_trade)
@@ -346,10 +238,18 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
// set before checks for propertly undo at problems (it already set in to client)
my_trade->SetAccepted(true);
TradeStatusInfo info;
WorldPackets::Trade::TradeStatus info;
if (his_trade->GetServerStateIndex() != acceptTrade.StateIndex)
{
info.Status = TRADE_STATUS_STATE_CHANGED;
SendTradeStatus(info);
my_trade->SetAccepted(false);
return;
}
if (!_player->IsWithinDistInMap(trader, TRADE_DISTANCE, false))
{
info.Status = TRADE_STATUS_TARGET_TO_FAR;
info.Status = TRADE_STATUS_TOO_FAR_AWAY;
SendTradeStatus(info);
my_trade->SetAccepted(false);
return;
@@ -358,8 +258,8 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
// not accept case incorrect money amount
if (!_player->HasEnoughMoney(my_trade->GetMoney()))
{
info.Status = TRADE_STATUS_CLOSE_WINDOW;
info.Result = EQUIP_ERR_NOT_ENOUGH_MONEY;
info.Status = TRADE_STATUS_FAILED;
info.BagResult = EQUIP_ERR_NOT_ENOUGH_MONEY;
SendTradeStatus(info);
my_trade->SetAccepted(false, true);
return;
@@ -368,8 +268,8 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
// not accept case incorrect money amount
if (!trader->HasEnoughMoney(his_trade->GetMoney()))
{
info.Status = TRADE_STATUS_CLOSE_WINDOW;
info.Result = EQUIP_ERR_NOT_ENOUGH_MONEY;
info.Status = TRADE_STATUS_FAILED;
info.BagResult = EQUIP_ERR_NOT_ENOUGH_MONEY;
trader->GetSession()->SendTradeStatus(info);
his_trade->SetAccepted(false, true);
return;
@@ -377,8 +277,8 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
if (_player->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - his_trade->GetMoney())
{
info.Status = TRADE_STATUS_CLOSE_WINDOW;
info.Result = EQUIP_ERR_TOO_MUCH_GOLD;
info.Status = TRADE_STATUS_FAILED;
info.BagResult = EQUIP_ERR_TOO_MUCH_GOLD;
SendTradeStatus(info);
my_trade->SetAccepted(false, true);
return;
@@ -386,8 +286,8 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
if (trader->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - my_trade->GetMoney())
{
info.Status = TRADE_STATUS_CLOSE_WINDOW;
info.Result = EQUIP_ERR_TOO_MUCH_GOLD;
info.Status = TRADE_STATUS_FAILED;
info.BagResult = EQUIP_ERR_TOO_MUCH_GOLD;
trader->GetSession()->SendTradeStatus(info);
his_trade->SetAccepted(false, true);
return;
@@ -400,15 +300,15 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
{
if (!item->CanBeTraded(false, true))
{
info.Status = TRADE_STATUS_TRADE_CANCELED;
info.Status = TRADE_STATUS_CANCELLED;
SendTradeStatus(info);
return;
}
if (item->IsBindedNotWith(trader))
{
info.Status = TRADE_STATUS_CLOSE_WINDOW;
info.Result = EQUIP_ERR_TRADE_BOUND_ITEM;
info.Status = TRADE_STATUS_FAILED;
info.BagResult = EQUIP_ERR_TRADE_BOUND_ITEM;
SendTradeStatus(info);
return;
}
@@ -418,7 +318,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
{
if (!item->CanBeTraded(false, true))
{
info.Status = TRADE_STATUS_TRADE_CANCELED;
info.Status = TRADE_STATUS_CANCELLED;
SendTradeStatus(info);
return;
}
@@ -514,36 +414,36 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
}
// inform partner client
info.Status = TRADE_STATUS_TRADE_ACCEPT;
info.Status = TRADE_STATUS_ACCEPTED;
trader->GetSession()->SendTradeStatus(info);
// test if item will fit in each inventory
TradeStatusInfo myCanCompleteInfo, hisCanCompleteInfo;
hisCanCompleteInfo.Result = trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT, &hisCanCompleteInfo.ItemLimitCategoryId);
myCanCompleteInfo.Result = _player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT, &myCanCompleteInfo.ItemLimitCategoryId);
WorldPackets::Trade::TradeStatus myCanCompleteInfo, hisCanCompleteInfo;
hisCanCompleteInfo.BagResult = trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT, &hisCanCompleteInfo.ItemID);
myCanCompleteInfo.BagResult = _player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT, &myCanCompleteInfo.ItemID);
clearAcceptTradeMode(myItems, hisItems);
// in case of missing space report error
if (myCanCompleteInfo.Result != EQUIP_ERR_OK)
if (myCanCompleteInfo.BagResult != EQUIP_ERR_OK)
{
clearAcceptTradeMode(my_trade, his_trade);
myCanCompleteInfo.Status = TRADE_STATUS_CLOSE_WINDOW;
myCanCompleteInfo.Status = TRADE_STATUS_FAILED;
trader->GetSession()->SendTradeStatus(myCanCompleteInfo);
myCanCompleteInfo.IsTargetResult = true;
myCanCompleteInfo.FailureForYou = true;
SendTradeStatus(myCanCompleteInfo);
my_trade->SetAccepted(false);
his_trade->SetAccepted(false);
return;
}
else if (hisCanCompleteInfo.Result != EQUIP_ERR_OK)
else if (hisCanCompleteInfo.BagResult != EQUIP_ERR_OK)
{
clearAcceptTradeMode(my_trade, his_trade);
hisCanCompleteInfo.Status = TRADE_STATUS_CLOSE_WINDOW;
hisCanCompleteInfo.Status = TRADE_STATUS_FAILED;
SendTradeStatus(hisCanCompleteInfo);
hisCanCompleteInfo.IsTargetResult = true;
hisCanCompleteInfo.FailureForYou = true;
trader->GetSession()->SendTradeStatus(hisCanCompleteInfo);
my_trade->SetAccepted(false);
his_trade->SetAccepted(false);
@@ -613,18 +513,18 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
trader->SaveInventoryAndGoldToDB(trans);
CharacterDatabase.CommitTransaction(trans);
info.Status = TRADE_STATUS_TRADE_COMPLETE;
info.Status = TRADE_STATUS_COMPLETE;
trader->GetSession()->SendTradeStatus(info);
SendTradeStatus(info);
}
else
{
info.Status = TRADE_STATUS_TRADE_ACCEPT;
info.Status = TRADE_STATUS_ACCEPTED;
trader->GetSession()->SendTradeStatus(info);
}
}
void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/)
void WorldSession::HandleUnacceptTradeOpcode(WorldPackets::Trade::UnacceptTrade& /*unacceptTrade*/)
{
TradeData* my_trade = _player->GetTradeData();
if (!my_trade)
@@ -633,14 +533,14 @@ void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/)
my_trade->SetAccepted(false, true);
}
void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
void WorldSession::HandleBeginTradeOpcode(WorldPackets::Trade::BeginTrade& /*beginTrade*/)
{
TradeData* my_trade = _player->m_trade;
if (!my_trade)
return;
TradeStatusInfo info;
info.Status = TRADE_STATUS_OPEN_WINDOW;
WorldPackets::Trade::TradeStatus info;
info.Status = TRADE_STATUS_INITIATED;
my_trade->GetTrader()->GetSession()->SendTradeStatus(info);
SendTradeStatus(info);
}
@@ -650,8 +550,8 @@ void WorldSession::SendCancelTrade()
if (PlayerRecentlyLoggedOut() || PlayerLogout())
return;
TradeStatusInfo info;
info.Status = TRADE_STATUS_TRADE_CANCELED;
WorldPackets::Trade::TradeStatus info;
info.Status = TRADE_STATUS_CANCELLED;
SendTradeStatus(info);
}
@@ -662,56 +562,36 @@ void WorldSession::HandleCancelTradeOpcode(WorldPackets::Trade::CancelTrade& /*c
_player->TradeCancel(true);
}
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
void WorldSession::HandleInitiateTradeOpcode(WorldPackets::Trade::InitiateTrade& initiateTrade)
{
ObjectGuid guid;
guid[0] = recvPacket.ReadBit();
guid[3] = recvPacket.ReadBit();
guid[5] = recvPacket.ReadBit();
guid[1] = recvPacket.ReadBit();
guid[4] = recvPacket.ReadBit();
guid[6] = recvPacket.ReadBit();
guid[7] = recvPacket.ReadBit();
guid[2] = recvPacket.ReadBit();
recvPacket.ReadByteSeq(guid[7]);
recvPacket.ReadByteSeq(guid[4]);
recvPacket.ReadByteSeq(guid[3]);
recvPacket.ReadByteSeq(guid[5]);
recvPacket.ReadByteSeq(guid[1]);
recvPacket.ReadByteSeq(guid[2]);
recvPacket.ReadByteSeq(guid[6]);
recvPacket.ReadByteSeq(guid[0]);
if (GetPlayer()->m_trade)
return;
TradeStatusInfo info;
WorldPackets::Trade::TradeStatus info;
if (!GetPlayer()->IsAlive())
{
info.Status = TRADE_STATUS_YOU_DEAD;
info.Status = TRADE_STATUS_DEAD;
SendTradeStatus(info);
return;
}
if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED))
{
info.Status = TRADE_STATUS_YOU_STUNNED;
info.Status = TRADE_STATUS_STUNNED;
SendTradeStatus(info);
return;
}
if (isLogingOut())
{
info.Status = TRADE_STATUS_YOU_LOGOUT;
info.Status = TRADE_STATUS_LOGGING_OUT;
SendTradeStatus(info);
return;
}
if (GetPlayer()->IsInFlight())
{
info.Status = TRADE_STATUS_TARGET_TO_FAR;
info.Status = TRADE_STATUS_TOO_FAR_AWAY;
SendTradeStatus(info);
return;
}
@@ -722,8 +602,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
return;
}
Player* pOther = ObjectAccessor::FindPlayer(guid);
Player* pOther = ObjectAccessor::FindPlayer(initiateTrade.Guid);
if (!pOther)
{
info.Status = TRADE_STATUS_NO_TARGET;
@@ -733,7 +612,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
if (pOther == GetPlayer() || pOther->m_trade)
{
info.Status = TRADE_STATUS_BUSY;
info.Status = TRADE_STATUS_PLAYER_BUSY;
SendTradeStatus(info);
return;
}
@@ -747,7 +626,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
if (pOther->IsInFlight())
{
info.Status = TRADE_STATUS_TARGET_TO_FAR;
info.Status = TRADE_STATUS_TOO_FAR_AWAY;
SendTradeStatus(info);
return;
}
@@ -761,14 +640,14 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
if (pOther->GetSession()->isLogingOut())
{
info.Status = TRADE_STATUS_TARGET_LOGOUT;
info.Status = TRADE_STATUS_TARGET_LOGGING_OUT;
SendTradeStatus(info);
return;
}
if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUID()))
{
info.Status = TRADE_STATUS_IGNORE_YOU;
info.Status = TRADE_STATUS_PLAYER_IGNORED;
SendTradeStatus(info);
return;
}
@@ -784,7 +663,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false))
{
info.Status = TRADE_STATUS_TARGET_TO_FAR;
info.Status = TRADE_STATUS_TOO_FAR_AWAY;
SendTradeStatus(info);
return;
}
@@ -799,52 +678,41 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
_player->m_trade = new TradeData(_player, pOther);
pOther->m_trade = new TradeData(pOther, _player);
info.Status = TRADE_STATUS_BEGIN_TRADE;
info.TraderGuid = _player->GetGUID();
info.Status = TRADE_STATUS_PROPOSED;
info.Partner = _player->GetGUID();
pOther->GetSession()->SendTradeStatus(info);
}
void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket)
void WorldSession::HandleSetTradeGoldOpcode(WorldPackets::Trade::SetTradeGold& setTradeGold)
{
uint64 gold;
recvPacket >> gold;
TradeData* my_trade = _player->GetTradeData();
if (!my_trade)
return;
my_trade->SetMoney(gold);
my_trade->UpdateClientStateIndex();
my_trade->SetMoney(setTradeGold.Coinage);
}
void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket)
void WorldSession::HandleSetTradeItemOpcode(WorldPackets::Trade::SetTradeItem& setTradeItem)
{
// send update
uint8 tradeSlot;
uint8 bag;
uint8 slot;
recvPacket >> slot;
recvPacket >> tradeSlot;
recvPacket >> bag;
TradeData* my_trade = _player->GetTradeData();
if (!my_trade)
return;
TradeStatusInfo info;
WorldPackets::Trade::TradeStatus info;
// invalid slot number
if (tradeSlot >= TRADE_SLOT_COUNT)
if (setTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
{
info.Status = TRADE_STATUS_TRADE_CANCELED;
info.Status = TRADE_STATUS_CANCELLED;
SendTradeStatus(info);
return;
}
// check cheating, can't fail with correct client operations
Item* item = _player->GetItemByPos(bag, slot);
if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true)))
Item* item = _player->GetItemByPos(setTradeItem.PackSlot, setTradeItem.ItemSlotInPack);
if (!item || (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true)))
{
info.Status = TRADE_STATUS_TRADE_CANCELED;
info.Status = TRADE_STATUS_CANCELLED;
SendTradeStatus(info);
return;
}
@@ -855,34 +723,39 @@ void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket)
if (my_trade->HasItem(iGUID))
{
// cheating attempt
info.Status = TRADE_STATUS_TRADE_CANCELED;
info.Status = TRADE_STATUS_CANCELLED;
SendTradeStatus(info);
return;
}
if (tradeSlot != TRADE_SLOT_NONTRADED && item->IsBindedNotWith(my_trade->GetTrader()))
my_trade->UpdateClientStateIndex();
if (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && item->IsBindedNotWith(my_trade->GetTrader()))
{
info.Status = TRADE_STATUS_NOT_ON_TAPLIST;
info.Slot = tradeSlot;
info.TradeSlot = setTradeItem.TradeSlot;
SendTradeStatus(info);
return;
}
my_trade->SetItem(TradeSlots(tradeSlot), item);
my_trade->SetItem(TradeSlots(setTradeItem.TradeSlot), item);
}
void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket)
void WorldSession::HandleClearTradeItemOpcode(WorldPackets::Trade::ClearTradeItem& clearTradeItem)
{
uint8 tradeSlot;
recvPacket >> tradeSlot;
TradeData* my_trade = _player->m_trade;
if (!my_trade)
return;
my_trade->UpdateClientStateIndex();
// invalid slot number
if (tradeSlot >= TRADE_SLOT_COUNT)
if (clearTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
return;
my_trade->SetItem(TradeSlots(tradeSlot), NULL);
my_trade->SetItem(TradeSlots(clearTradeItem.TradeSlot), NULL);
}
void WorldSession::HandleSetTradeCurrencyOpcode(WorldPackets::Trade::SetTradeCurrency& /*setTradeCurrency*/)
{
}
+26 -32
View File
@@ -4659,38 +4659,32 @@ enum SpellFamilyNames
enum TradeStatus
{
TRADE_STATUS_OPEN_WINDOW = 0,
// 1 - Related to EVENT_PLAYER_MONEY
TRADE_STATUS_NOT_ON_TAPLIST = 2, // Related to trading soulbound loot items
TRADE_STATUS_YOU_LOGOUT = 3,
TRADE_STATUS_IGNORE_YOU = 4,
TRADE_STATUS_TARGET_DEAD = 5,
TRADE_STATUS_TRADE_ACCEPT = 6,
TRADE_STATUS_TARGET_LOGOUT = 7,
// 8 - nonexistent
TRADE_STATUS_TRADE_COMPLETE = 9,
TRADE_STATUS_TRIAL_ACCOUNT = 10, // Trial accounts can not perform that action
// 11 - nonexistent
TRADE_STATUS_BEGIN_TRADE = 12,
TRADE_STATUS_YOU_DEAD = 13,
// 14 - nonexistent
// 15 - nonexistent
TRADE_STATUS_TARGET_TO_FAR = 16,
TRADE_STATUS_NO_TARGET = 17,
TRADE_STATUS_BUSY_2 = 18,
TRADE_STATUS_CURRENCY_NOT_TRADABLE = 19, // new 4.x
TRADE_STATUS_WRONG_FACTION = 20,
TRADE_STATUS_BUSY = 21,
// 22 - equivalent to 335 unk status 9
TRADE_STATUS_TRADE_CANCELED = 23,
TRADE_STATUS_CURRENCY = 24, // new 4.x
TRADE_STATUS_BACK_TO_TRADE = 25,
TRADE_STATUS_WRONG_REALM = 26, // You can only trade conjured items... (cross realm BG related).
TRADE_STATUS_YOU_STUNNED = 27,
// 28 - nonexistent
TRADE_STATUS_TARGET_STUNNED = 29,
// 30 - nonexistent
TRADE_STATUS_CLOSE_WINDOW = 31,
TRADE_STATUS_STUNNED = 0,
TRADE_STATUS_TARGET_DEAD = 2,
TRADE_STATUS_PLAYER_IGNORED = 3,
TRADE_STATUS_STATE_CHANGED = 4,
TRADE_STATUS_PETITION = 5,
TRADE_STATUS_FAILED = 6,
TRADE_STATUS_NOT_ENOUGH_CURRENCY = 7,
TRADE_STATUS_TARGET_LOGGING_OUT = 8,
TRADE_STATUS_PROPOSED = 9,
TRADE_STATUS_RESTRICTED_ACCOUNT = 10,
TRADE_STATUS_WRONG_REALM = 12,
TRADE_STATUS_ALREADY_TRADING = 14,
TRADE_STATUS_COMPLETE = 15,
TRADE_STATUS_TARGET_STUNNED = 16,
TRADE_STATUS_ACCEPTED = 17,
TRADE_STATUS_NO_TARGET = 18,
TRADE_STATUS_CURRENCY_NOT_TRADABLE = 19,
TRADE_STATUS_WRONG_FACTION = 20,
TRADE_STATUS_NOT_ON_TAPLIST = 21,
TRADE_STATUS_UNACCEPTED = 23,
TRADE_STATUS_LOGGING_OUT = 24,
TRADE_STATUS_CANCELLED = 26,
TRADE_STATUS_TOO_FAR_AWAY = 27,
TRADE_STATUS_DEAD = 28,
TRADE_STATUS_INITIATED = 29,
TRADE_STATUS_PLAYER_BUSY = 30
};
enum XPColorChar
@@ -0,0 +1,129 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* 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 "TradePackets.h"
void WorldPackets::Trade::AcceptTrade::Read()
{
_worldPacket >> StateIndex;
}
void WorldPackets::Trade::ClearTradeItem::Read()
{
_worldPacket >> TradeSlot;
}
void WorldPackets::Trade::InitiateTrade::Read()
{
_worldPacket >> Guid;
}
void WorldPackets::Trade::SetTradeCurrency::Read()
{
_worldPacket >> Type >> Quantity;
}
void WorldPackets::Trade::SetTradeGold::Read()
{
_worldPacket >> Coinage;
}
void WorldPackets::Trade::SetTradeItem::Read()
{
_worldPacket >> TradeSlot >> PackSlot >> ItemSlotInPack;
}
WorldPacket const* WorldPackets::Trade::TradeStatus::Write()
{
_worldPacket.WriteBit(PartnerIsSameBnetAccount);
_worldPacket.WriteBits(Status, 5);
switch (Status)
{
case TRADE_STATUS_FAILED:
_worldPacket.WriteBit(FailureForYou);
_worldPacket << int32(BagResult);
_worldPacket << int32(ItemID);
break;
case TRADE_STATUS_INITIATED:
_worldPacket << uint32(ID);
break;
case TRADE_STATUS_PROPOSED:
_worldPacket << Partner;
_worldPacket << PartnerAccount;
break;
case TRADE_STATUS_WRONG_REALM:
case TRADE_STATUS_NOT_ON_TAPLIST:
_worldPacket << uint8(TradeSlot);
break;
case TRADE_STATUS_NOT_ENOUGH_CURRENCY:
case TRADE_STATUS_CURRENCY_NOT_TRADABLE:
_worldPacket << int32(CurrencyType);
_worldPacket << int32(CurrencyQuantity);
break;
default:
_worldPacket.FlushBits();
break;
}
return &_worldPacket;
}
ByteBuffer& operator<<(ByteBuffer& buffer, WorldPackets::Trade::TradeUpdated::UnwrappedTradeItem const& unwrappedTradeItem)
{
buffer << unwrappedTradeItem.Item;
buffer << int32(unwrappedTradeItem.EnchantID);
buffer << int32(unwrappedTradeItem.OnUseEnchantmentID);
buffer.append(unwrappedTradeItem.SocketEnchant, MAX_GEM_SOCKETS);
buffer << unwrappedTradeItem.Creator;
buffer << int32(unwrappedTradeItem.Charges);
buffer << uint32(unwrappedTradeItem.MaxDurability);
buffer << uint32(unwrappedTradeItem.Durability);
buffer.WriteBit(unwrappedTradeItem.Lock);
buffer.FlushBits();
return buffer;
}
ByteBuffer& operator<<(ByteBuffer& buffer, WorldPackets::Trade::TradeUpdated::TradeItem const& tradeItem)
{
buffer << uint8(tradeItem.Slot);
buffer << uint32(tradeItem.EntryID);
buffer << uint32(tradeItem.StackCount);
buffer << tradeItem.GiftCreator;
if (buffer.WriteBit(tradeItem.Unwrapped.HasValue))
buffer << tradeItem.Unwrapped.Value;
return buffer;
}
WorldPacket const* WorldPackets::Trade::TradeUpdated::Write()
{
_worldPacket << uint8(WhichPlayer);
_worldPacket << uint32(ID);
_worldPacket << uint32(ClientStateIndex);
_worldPacket << uint32(CurrentStateIndex);
_worldPacket << uint64(Gold);
_worldPacket << int32(CurrencyType);
_worldPacket << int32(CurrencyQuantity);
_worldPacket << int32(ProposedEnchantment);
_worldPacket << uint32(Items.size());
for (TradeItem const& item : Items)
_worldPacket << item;
return &_worldPacket;
}
+171 -16
View File
@@ -1,29 +1,55 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* 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/>.
*/
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* 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/>.
*/
#ifndef TradePackets_h__
#define TradePackets_h__
#include "Packet.h"
#include "ItemPackets.h"
namespace WorldPackets
{
namespace Trade
{
class AcceptTrade final : public ClientPacket
{
public:
AcceptTrade(WorldPacket&& packet) : ClientPacket(CMSG_ACCEPT_TRADE, std::move(packet)) { }
void Read() override;
uint32 StateIndex = 0;
};
class BeginTrade final : public ClientPacket
{
public:
BeginTrade(WorldPacket&& packet) : ClientPacket(CMSG_BEGIN_TRADE, std::move(packet)) { }
void Read() override { }
};
class BusyTrade final : public ClientPacket
{
public:
BusyTrade(WorldPacket&& packet) : ClientPacket(CMSG_BUSY_TRADE, std::move(packet)) { }
void Read() override { }
};
class CancelTrade final : public ClientPacket
{
public:
@@ -31,6 +57,135 @@ namespace WorldPackets
void Read() override { }
};
class ClearTradeItem final : public ClientPacket
{
public:
ClearTradeItem(WorldPacket&& packet) : ClientPacket(CMSG_CLEAR_TRADE_ITEM, std::move(packet)) { }
void Read() override;
uint8 TradeSlot = 0;
};
class IgnoreTrade final : public ClientPacket
{
public:
IgnoreTrade(WorldPacket&& packet) : ClientPacket(CMSG_IGNORE_TRADE, std::move(packet)) { }
void Read() override { }
};
class InitiateTrade final : public ClientPacket
{
public:
InitiateTrade(WorldPacket&& packet) : ClientPacket(CMSG_INITIATE_TRADE, std::move(packet)) { }
void Read() override;
ObjectGuid Guid;
};
class SetTradeCurrency final : public ClientPacket
{
public:
SetTradeCurrency(WorldPacket&& packet) : ClientPacket(CMSG_SET_TRADE_CURRENCY, std::move(packet)) { }
void Read() override;
uint32 Type = 0;
uint32 Quantity = 0;
};
class SetTradeGold final : public ClientPacket
{
public:
SetTradeGold(WorldPacket&& packet) : ClientPacket(CMSG_SET_TRADE_GOLD, std::move(packet)) { }
void Read() override;
uint64 Coinage = 0;
};
class SetTradeItem final : public ClientPacket
{
public:
SetTradeItem(WorldPacket&& packet) : ClientPacket(CMSG_SET_TRADE_ITEM, std::move(packet)) { }
void Read() override;
uint8 TradeSlot = 0;
uint8 PackSlot = 0;
uint8 ItemSlotInPack = 0;
};
class UnacceptTrade final : public ClientPacket
{
public:
UnacceptTrade(WorldPacket&& packet) : ClientPacket(CMSG_UNACCEPT_TRADE, std::move(packet)) { }
void Read() override { }
};
class TradeStatus final : public ServerPacket
{
public:
TradeStatus() : ServerPacket(SMSG_TRADE_STATUS, 1 + 1 + 16 + 4 + 4 + 1 + 4 + 4 + 4 + 1) { }
WorldPacket const* Write() override;
::TradeStatus Status = TRADE_STATUS_INITIATED;
uint8 TradeSlot = 0;
ObjectGuid PartnerAccount;
ObjectGuid Partner;
int32 CurrencyType = 0;
int32 CurrencyQuantity = 0;
bool FailureForYou = false;
int32 BagResult = 0;
uint32 ItemID = 0;
uint32 ID = 0;
bool PartnerIsSameBnetAccount = false;
};
class TradeUpdated final : public ServerPacket
{
public:
TradeUpdated() : ServerPacket(SMSG_TRADE_UPDATED) { }
WorldPacket const* Write() override;
struct UnwrappedTradeItem
{
WorldPackets::Item::ItemInstance Item;
int32 EnchantID = 0;
int32 OnUseEnchantmentID = 0;
ObjectGuid Creator;
int32 Charges = 0;
bool Lock = false;
uint32 MaxDurability = 0;
uint32 Durability = 0;
int32 SocketEnchant[MAX_GEM_SOCKETS] = { };
};
struct TradeItem
{
uint8 Slot = 0;
int32 EntryID = 0;
int32 StackCount = 0;
ObjectGuid GiftCreator;
Optional<UnwrappedTradeItem> Unwrapped;
};
uint64 Gold = 0;
uint32 CurrentStateIndex = 0;
uint8 WhichPlayer = 0;
uint32 ClientStateIndex = 0;
std::vector<TradeItem> Items;
int32 CurrencyType = 0;
uint32 ID = 0;
int32 ProposedEnchantment = 0;
int32 CurrencyQuantity = 0;
};
}
}
+12 -12
View File
@@ -145,7 +145,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_ACCEPT_GUILD_INVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Guild::AcceptGuildInvite, &WorldSession::HandleGuildAcceptInvite);
DEFINE_OPCODE_HANDLER_OLD(CMSG_ACCEPT_LEVEL_GRANT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptGrantLevel );
DEFINE_OPCODE_HANDLER_OLD(CMSG_ACCEPT_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode );
DEFINE_HANDLER(CMSG_ACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::AcceptTrade, &WorldSession::HandleAcceptTradeOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_ACCEPT_WARGAME_INVITE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_ACTIVATE_TAXI, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_ADD_BATTLENET_FRIEND, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -200,7 +200,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PET_SET_FLAGS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PET_SUMMON, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PET_UPDATE_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_BEGIN_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBeginTradeOpcode );
DEFINE_HANDLER(CMSG_BEGIN_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::BeginTrade, &WorldSession::HandleBeginTradeOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_BF_MGR_ENTRY_INVITE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleBfEntryInviteResponse );
DEFINE_OPCODE_HANDLER_OLD(CMSG_BF_MGR_QUEUE_EXIT_REQUEST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleBfExitRequest);
DEFINE_OPCODE_HANDLER_OLD(CMSG_BF_MGR_QUEUE_INVITE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleBfQueueInviteResponse );
@@ -210,7 +210,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_BLACK_MARKET_OPEN, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::BlackMarket::BlackMarketOpen, &WorldSession::HandleBlackMarketOpen);
DEFINE_OPCODE_HANDLER_OLD(CMSG_BLACK_MARKET_REQUEST_ITEMS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_BUG_REPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBugReportOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_BUSY_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBusyTradeOpcode );
DEFINE_HANDLER(CMSG_BUSY_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::BusyTrade, &WorldSession::HandleBusyTradeOpcode);
DEFINE_HANDLER(CMSG_BUY_BACK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::BuyBackItem, &WorldSession::HandleBuybackItem);
DEFINE_HANDLER(CMSG_BUY_BANK_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Bank::BuyBankSlot, &WorldSession::HandleBuyBankSlotOpcode);
DEFINE_HANDLER(CMSG_BUY_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::BuyItem, &WorldSession::HandleBuyItemOpcode);
@@ -307,7 +307,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHECK_WOW_TOKEN_VETERAN_ELIGIBILITY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHOICE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CLEAR_RAID_MARKER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CLEAR_TRADE_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleClearTradeItemOpcode );
DEFINE_HANDLER(CMSG_CLEAR_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::ClearTradeItem, &WorldSession::HandleClearTradeItemOpcode);
DEFINE_HANDLER(CMSG_CLIENT_PORT_GRAVEYARD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Misc::PortGraveyard, &WorldSession::HandlePortGraveyard);
DEFINE_OPCODE_HANDLER_OLD(CMSG_CLOSE_INTERACTION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_COMMENTATOR_ENABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -447,10 +447,10 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_GUILD_UPDATE_INFO_TEXT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Guild::GuildUpdateInfoText, &WorldSession::HandleGuildUpdateInfoText);
DEFINE_HANDLER(CMSG_GUILD_UPDATE_MOTD_TEXT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Guild::GuildUpdateMotdText, &WorldSession::HandleGuildUpdateMotdText);
DEFINE_OPCODE_HANDLER_OLD(CMSG_HEARTH_AND_RESURRECT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleHearthAndResurrect );
DEFINE_OPCODE_HANDLER_OLD(CMSG_IGNORE_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleIgnoreTradeOpcode );
DEFINE_HANDLER(CMSG_IGNORE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::IgnoreTrade, &WorldSession::HandleIgnoreTradeOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_INCREASE_CAST_TIME_FOR_SPELL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_INITIATE_ROLE_POLL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRolePollBeginOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_INITIATE_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleInitiateTradeOpcode );
DEFINE_HANDLER(CMSG_INITIATE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::InitiateTrade, &WorldSession::HandleInitiateTradeOpcode);
DEFINE_HANDLER(CMSG_INSPECT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Inspect::Inspect, &WorldSession::HandleInspectOpcode);
DEFINE_HANDLER(CMSG_INSPECT_PVP, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Inspect::InspectPVPRequest, &WorldSession::HandleInspectPVP);
DEFINE_OPCODE_HANDLER_OLD(CMSG_INSTANCE_LOCK_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleInstanceLockResponse);
@@ -738,9 +738,9 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_SET_SPECIALIZATION, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Talent::SetSpecialization, &WorldSession::HandleSetSpecializationOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_TAXI_BENCHMARK_MODE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTaxiBenchmarkOpcode );
DEFINE_HANDLER(CMSG_SET_TITLE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Character::SetTitle, &WorldSession::HandleSetTitleOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_TRADE_CURRENCY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_TRADE_GOLD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeGoldOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_TRADE_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeItemOpcode );
DEFINE_HANDLER(CMSG_SET_TRADE_CURRENCY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::SetTradeCurrency, &WorldSession::HandleSetTradeCurrencyOpcode);
DEFINE_HANDLER(CMSG_SET_TRADE_GOLD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::SetTradeGold, &WorldSession::HandleSetTradeGoldOpcode);
DEFINE_HANDLER(CMSG_SET_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::SetTradeItem, &WorldSession::HandleSetTradeItemOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_USING_PARTY_GARRISON, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_WATCHED_FACTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetWatchedFactionOpcode );
DEFINE_HANDLER(CMSG_SHOWING_CLOAK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Character::ShowingCloak, &WorldSession::HandleShowingCloakOpcode);
@@ -792,7 +792,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_TWITTER_DISCONNECT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_TWITTER_POST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_HANDLER(CMSG_UI_TIME_REQUEST, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::UITimeRequest, &WorldSession::HandleUITimeRequest);
DEFINE_OPCODE_HANDLER_OLD(CMSG_UNACCEPT_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode );
DEFINE_HANDLER(CMSG_UNACCEPT_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Trade::UnacceptTrade, &WorldSession::HandleUnacceptTradeOpcode);
DEFINE_HANDLER(CMSG_UNDELETE_CHARACTER, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::UndeleteCharacter, &WorldSession::HandleCharUndeleteOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_UNLEARN_SKILL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnlearnSkillOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_UNLEARN_SPECIALIZATION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -1675,8 +1675,8 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOKEN_UNK1, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOTEM_CREATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOTEM_MOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_STATUS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_UPDATED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_BUY_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_ABORTED, STATUS_NEVER, CONNECTION_TYPE_REALM);
+22 -11
View File
@@ -55,7 +55,6 @@ struct AuctionEntry;
struct DeclinedName;
struct ItemTemplate;
struct MovementInfo;
struct TradeStatusInfo;
namespace lfg
{
@@ -393,7 +392,18 @@ namespace WorldPackets
namespace Trade
{
class AcceptTrade;
class BeginTrade;
class BusyTrade;
class CancelTrade;
class ClearTradeItem;
class IgnoreTrade;
class InitiateTrade;
class SetTradeCurrency;
class SetTradeGold;
class SetTradeItem;
class UnacceptTrade;
class TradeStatus;
}
namespace Who
@@ -658,7 +668,7 @@ class WorldSession
void SendBattleGroundList(ObjectGuid guid, BattlegroundTypeId bgTypeId = BATTLEGROUND_RB);
void SendTradeStatus(TradeStatusInfo const& status);
void SendTradeStatus(WorldPackets::Trade::TradeStatus& status);
void SendUpdateTrade(bool trader_data = true);
void SendCancelTrade();
@@ -1033,16 +1043,17 @@ class WorldSession
void HandleDuelAccepted();
void HandleDuelCancelled();
void HandleAcceptTradeOpcode(WorldPacket& recvPacket);
void HandleBeginTradeOpcode(WorldPacket& recvPacket);
void HandleBusyTradeOpcode(WorldPacket& recvPacket);
void HandleAcceptTradeOpcode(WorldPackets::Trade::AcceptTrade& acceptTrade);
void HandleBeginTradeOpcode(WorldPackets::Trade::BeginTrade& beginTrade);
void HandleBusyTradeOpcode(WorldPackets::Trade::BusyTrade& busyTrade);
void HandleCancelTradeOpcode(WorldPackets::Trade::CancelTrade& cancelTrade);
void HandleClearTradeItemOpcode(WorldPacket& recvPacket);
void HandleIgnoreTradeOpcode(WorldPacket& recvPacket);
void HandleInitiateTradeOpcode(WorldPacket& recvPacket);
void HandleSetTradeGoldOpcode(WorldPacket& recvPacket);
void HandleSetTradeItemOpcode(WorldPacket& recvPacket);
void HandleUnacceptTradeOpcode(WorldPacket& recvPacket);
void HandleClearTradeItemOpcode(WorldPackets::Trade::ClearTradeItem& clearTradeItem);
void HandleIgnoreTradeOpcode(WorldPackets::Trade::IgnoreTrade& ignoreTrade);
void HandleInitiateTradeOpcode(WorldPackets::Trade::InitiateTrade& initiateTrade);
void HandleSetTradeCurrencyOpcode(WorldPackets::Trade::SetTradeCurrency& setTradeCurrency);
void HandleSetTradeGoldOpcode(WorldPackets::Trade::SetTradeGold& setTradeGold);
void HandleSetTradeItemOpcode(WorldPackets::Trade::SetTradeItem& setTradeItem);
void HandleUnacceptTradeOpcode(WorldPackets::Trade::UnacceptTrade& unacceptTrade);
void HandleAuctionHelloOpcode(WorldPackets::AuctionHouse::AuctionHelloRequest& packet);
void HandleAuctionListItems(WorldPacket& recvData);
+3 -7
View File
@@ -365,7 +365,7 @@ void SpellCastTargets::SetItemTarget(Item* item)
void SpellCastTargets::SetTradeItemTarget(Player* caster)
{
m_itemTargetGUID.SetRawValue({ uint8(TRADE_SLOT_NONTRADED), 0, 0, 0, 0, 0, 0, 0 });
m_itemTargetGUID = ObjectGuid::TradeItem;
m_itemTargetEntry = 0;
m_targetMask |= TARGET_FLAG_TRADE_ITEM;
@@ -489,9 +489,7 @@ void SpellCastTargets::Update(Unit* caster)
m_itemTarget = player->GetItemByGuid(m_itemTargetGUID);
else if (m_targetMask & TARGET_FLAG_TRADE_ITEM)
{
ObjectGuid nonTradedGuid;
nonTradedGuid.SetRawValue(uint64(0), uint64(TRADE_SLOT_NONTRADED));
if (m_itemTargetGUID == nonTradedGuid) // here it is not guid but slot. Also prevents hacking slots
if (m_itemTargetGUID == ObjectGuid::TradeItem)
if (TradeData* pTrade = player->GetTradeData())
m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
}
@@ -5543,9 +5541,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!my_trade)
return SPELL_FAILED_NOT_TRADING;
// Item target guid contains trade slot until m_targets.UpdateTradeSlotItem() is called
TradeSlots slot = TradeSlots(m_targets.GetItemTargetGUID().GetRawValue().at(0));
if (slot != TRADE_SLOT_NONTRADED)
if (m_targets.GetItemTargetGUID() != ObjectGuid::TradeItem)
return SPELL_FAILED_BAD_TARGETS;
if (!IsTriggered())