void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket) { uint8 tradeSlot; recvPacket >> tradeSlot; TradeData* my_trade = _player->m_trade; if (!my_trade) return; // invalid slot number if (tradeSlot >= TRADE_SLOT_COUNT) return; my_trade->SetItem(TradeSlots(tradeSlot), NULL); }
void WorldSession::HandleClearTradeItemOpcode(WorldPackets::Trade::ClearTradeItem& clearTradeItem) { TradeData* my_trade = _player->m_trade; if (!my_trade) return; my_trade->UpdateClientStateIndex(); // invalid slot number if (clearTradeItem.TradeSlot >= TRADE_SLOT_COUNT) return; my_trade->SetItem(TradeSlots(clearTradeItem.TradeSlot), NULL); }
static void setAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade, Item **myItems, Item **hisItems) { myTrade->SetInAcceptProcess(true); hisTrade->SetInAcceptProcess(true); // store items in local list and set 'in-trade' flag for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = myTrade->GetItem(TradeSlots(i))) { sLog->outStaticDebug("player trade item %u bag: %u slot: %u", item->GetGUIDLow(), item->GetBagSlot(), item->GetSlot()); //Can return NULL myItems[i] = item; myItems[i]->SetInTrade(); } if (Item* item = hisTrade->GetItem(TradeSlots(i))) { sLog->outStaticDebug("partner trade item %u bag: %u slot: %u", item->GetGUIDLow(), item->GetBagSlot(), item->GetSlot()); hisItems[i] = item; hisItems[i]->SetInTrade(); } } }
static void setAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade, Item* *myItems, Item* *hisItems) { myTrade->SetInAcceptProcess(true); hisTrade->SetInAcceptProcess(true); // store items in local list and set 'in-trade' flag for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = myTrade->GetItem(TradeSlots(i))) { TC_LOG_DEBUG("network", "player trade %s bag: %u slot: %u", item->GetGUID().ToString().c_str(), item->GetBagSlot(), item->GetSlot()); //Can return NULL myItems[i] = item; myItems[i]->SetInTrade(); } if (Item* item = hisTrade->GetItem(TradeSlots(i))) { TC_LOG_DEBUG("network", "partner trade %s bag: %u slot: %u", item->GetGUID().ToString().c_str(), item->GetBagSlot(), item->GetSlot()); hisItems[i] = item; hisItems[i]->SetInTrade(); } } }
void WorldSession::HandleSetTradeItemOpcode(WorldPackets::Trade::SetTradeItem& setTradeItem) { TradeData* my_trade = _player->GetTradeData(); if (!my_trade) return; WorldPackets::Trade::TradeStatus info; // invalid slot number if (setTradeItem.TradeSlot >= TRADE_SLOT_COUNT) { info.Status = TRADE_STATUS_CANCELLED; SendTradeStatus(info); return; } // check cheating, can't fail with correct client operations Item* item = _player->GetItemByPos(setTradeItem.PackSlot, setTradeItem.ItemSlotInPack); if (!item || (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true))) { info.Status = TRADE_STATUS_CANCELLED; SendTradeStatus(info); return; } ObjectGuid iGUID = item->GetGUID(); // prevent place single item into many trade slots using cheating and client bugs if (my_trade->HasItem(iGUID)) { // cheating attempt info.Status = TRADE_STATUS_CANCELLED; SendTradeStatus(info); return; } my_trade->UpdateClientStateIndex(); if (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && item->IsBindedNotWith(my_trade->GetTrader())) { info.Status = TRADE_STATUS_NOT_ON_TAPLIST; info.TradeSlot = setTradeItem.TradeSlot; SendTradeStatus(info); return; } my_trade->SetItem(TradeSlots(setTradeItem.TradeSlot), item); }
void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) { // send update uint8 tradeSlot; uint8 bag; uint8 slot; recvPacket >> slot; recvPacket >> tradeSlot; recvPacket >> bag; std::cout << "Unk1 : " << (int)tradeSlot << " Unk2: " << (int)slot << " unk3 : " << (int)bag << std::endl; TradeData* my_trade = _player->GetTradeData(); if (!my_trade) return; // invalid slot number if (tradeSlot >= TRADE_SLOT_COUNT) { std::cout << "Ery : test1" << std::endl; SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); 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))) { std::cout << "Ery : test2" << std::endl; SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } uint64 iGUID = item->GetGUID(); // prevent place single item into many trade slots using cheating and client bugs if (my_trade->HasItem(iGUID)) { std::cout << "Ery : test3" << std::endl; // cheating attempt SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } my_trade->SetItem(TradeSlots(tradeSlot), item); }
void WorldSession::SendUpdateTrade(bool trader_state /*= true*/) { TradeData* view_trade = trader_state ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size data << uint8(trader_state ? 1 : 0); // send trader or own trade windows state (last need for proper show spell apply to non-trade slot) data << uint32(0); // CGTradeInfo::m_tradeID data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases data << uint32(view_trade->GetMoney()); // trader gold data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { data << uint8(i); // trade slot number, if not specified, then end of packet if (Item* item = view_trade->GetItem(TradeSlots(i))) { data << uint32(item->GetProto()->ItemId); // entry data << uint32(item->GetProto()->DisplayInfoID);// display id data << uint32(item->GetCount()); // stack count // wrapped: hide stats but show giftcreator name data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED) ? 1 : 0); data << item->GetGuidValue(ITEM_FIELD_GIFTCREATOR); data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); // creator data << item->GetGuidValue(ITEM_FIELD_CREATOR); data << uint32(item->GetSpellCharges()); // charges data << uint32(item->GetItemSuffixFactor()); // SuffixFactor data << uint32(item->GetItemRandomPropertyId());// random properties id data << uint32(item->GetProto()->LockID); // lock id // max durability data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // durability data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); } else { for (uint8 j = 0; j < 18; ++j) data << uint32(0); } } SendPacket(&data); }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); data << uint8(trader_data); // 1 means traders data, 0 means own data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases data << uint32(view_trade->GetMoney()); // trader gold data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { data << uint8(i); // trade slot number, if not specified, then end of packet if (Item* item = view_trade->GetItem(TradeSlots(i))) { data << uint32(item->GetTemplate()->ItemId); // entry data << uint32(item->GetTemplate()->DisplayInfoID);// display id data << uint32(item->GetCount()); // stack count // wrapped: hide stats but show giftcreator name data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED) ? 1 : 0); data << uint64(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)); // perm. enchantment and gems data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); // creator data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); data << uint32(item->GetSpellCharges()); // charges data << uint32(item->GetItemSuffixFactor()); // SuffixFactor data << uint32(item->GetItemRandomPropertyId());// random properties id data << uint32(item->GetTemplate()->LockID); // lock id // max durability data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // durability data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); } else { for (uint8 j = 0; j < 18; ++j) data << uint32(0); } } SendPacket(&data); }
void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) { // send update uint8 tradeSlot; uint8 bag; uint8 slot; recvPacket >> tradeSlot; recvPacket >> bag; recvPacket >> slot; TradeData* my_trade = _player->m_trade; if (!my_trade) return; TradeStatusInfo info; // invalid slot number if (tradeSlot >= TRADE_SLOT_COUNT) { info.Status = TRADE_STATUS_TRADE_CANCELED; 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())) { info.Status = TRADE_STATUS_TRADE_CANCELED; SendTradeStatus(info); return; } // prevent place single item into many trade slots using cheating and client bugs if (my_trade->HasItem(item->GetObjectGuid())) { // cheating attempt info.Status = TRADE_STATUS_TRADE_CANCELED; SendTradeStatus(info); return; } my_trade->SetItem(TradeSlots(tradeSlot), item); }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); 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) { if (Item* item = view_trade->GetItem(TradeSlots(i))) { 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_FIELD_FLAG_WRAPPED)) { tradeItem.Unwrapped = boost::in_place(); tradeItem.Unwrapped->Item.Initialize(item); tradeItem.Unwrapped->EnchantID = item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT); tradeItem.Unwrapped->OnUseEnchantmentID = item->GetEnchantmentId(USE_ENCHANTMENT_SLOT); tradeItem.Unwrapped->Creator = item->GetGuidValue(ITEM_FIELD_CREATOR); tradeItem.Unwrapped->Charges = item->GetSpellCharges(); tradeItem.Unwrapped->Lock = item->GetTemplate()->GetLockID() && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED); tradeItem.Unwrapped->MaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); tradeItem.Unwrapped->Durability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); for (uint32 s = SOCK_ENCHANTMENT_SLOT; s < MAX_GEM_SOCKETS; ++s) tradeItem.Unwrapped->SocketEnchant[s] = item->GetEnchantmentId(EnchantmentSlot(s + SOCK_ENCHANTMENT_SLOT)); } tradeUpdated.Items.push_back(tradeItem); } } SendPacket(tradeUpdated.Write()); }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& recvPacket) { recvPacket.read_skip<uint32>(); TradeData* my_trade = _player->m_trade; if (!my_trade) return; Player* trader = my_trade->GetTrader(); TradeData* his_trade = trader->m_trade; if (!his_trade) return; Item* myItems[TRADE_SLOT_TRADED_COUNT] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; // set before checks to properly undo at problems (it already set in to client) my_trade->SetAccepted(true); TradeStatusInfo info; if (!_player->IsWithinDistInMap(trader, TRADE_DISTANCE, false)) { info.Status = TRADE_STATUS_TARGET_TO_FAR; SendTradeStatus(info); my_trade->SetAccepted(false); return; } // not accept case incorrect money amount if (my_trade->GetMoney() > _player->GetMoney()) { info.Status = TRADE_STATUS_CLOSE_WINDOW; info.Result = EQUIP_ERR_NOT_ENOUGH_MONEY; SendTradeStatus(info); my_trade->SetAccepted(false, true); return; } // not accept case incorrect money amount if (his_trade->GetMoney() > trader->GetMoney()) { info.Status = TRADE_STATUS_CLOSE_WINDOW; info.Result = EQUIP_ERR_NOT_ENOUGH_MONEY; trader->GetSession()->SendTradeStatus(info); his_trade->SetAccepted(false, true); return; } // not accept if some items now can't be trade (cheating) for (int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = my_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded()) { info.Status = TRADE_STATUS_TRADE_CANCELED; SendTradeStatus(info); return; } } if (Item* item = his_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded()) { info.Status = TRADE_STATUS_TRADE_CANCELED; SendTradeStatus(info); return; } } } if (his_trade->IsAccepted()) { setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); Spell* my_spell = nullptr; SpellCastTargets my_targets; Spell* his_spell = nullptr; SpellCastTargets his_targets; // not accept if spell can't be casted now (cheating) if (uint32 my_spell_id = my_trade->GetSpell()) { SpellEntry const* spellEntry = sSpellStore.LookupEntry(my_spell_id); Item* castItem = my_trade->GetSpellCastItem(); if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || (my_trade->HasSpellCastItem() && !castItem)) { clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); my_trade->SetSpell(0); return; } my_spell = new Spell(_player, spellEntry, true); my_spell->m_CastItem = castItem; my_targets.setTradeItemTarget(_player); my_spell->m_targets = my_targets; SpellCastResult res = my_spell->CheckCast(true); if (res != SPELL_CAST_OK) { my_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; my_trade->SetSpell(0); return; } } // not accept if spell can't be casted now (cheating) if (uint32 his_spell_id = his_trade->GetSpell()) { SpellEntry const* spellEntry = sSpellStore.LookupEntry(his_spell_id); Item* castItem = his_trade->GetSpellCastItem(); if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) { delete my_spell; his_trade->SetSpell(0); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); return; } his_spell = new Spell(trader, spellEntry, true); his_spell->m_CastItem = castItem; his_targets.setTradeItemTarget(trader); his_spell->m_targets = his_targets; SpellCastResult res = his_spell->CheckCast(true); if (res != SPELL_CAST_OK) { his_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; delete his_spell; his_trade->SetSpell(0); return; } } // inform partner client info.Status = TRADE_STATUS_TRADE_ACCEPT; trader->GetSession()->SendTradeStatus(info); // test if item will fit in each inventory TradeStatusInfo myCanCompleteInfo, hisCanCompleteInfo; hisCanCompleteInfo.Result = trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT); myCanCompleteInfo.Result = _player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT); clearAcceptTradeMode(myItems, hisItems); // in case of missing space report error if (myCanCompleteInfo.Result != EQUIP_ERR_OK) { clearAcceptTradeMode(my_trade, his_trade); myCanCompleteInfo.Status = TRADE_STATUS_CLOSE_WINDOW; trader->GetSession()->SendTradeStatus(myCanCompleteInfo); myCanCompleteInfo.IsTargetResult = true; SendTradeStatus(myCanCompleteInfo); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } else if (hisCanCompleteInfo.Result != EQUIP_ERR_OK) { clearAcceptTradeMode(my_trade, his_trade); hisCanCompleteInfo.Status = TRADE_STATUS_CLOSE_WINDOW; SendTradeStatus(hisCanCompleteInfo); hisCanCompleteInfo.IsTargetResult = true; trader->GetSession()->SendTradeStatus(hisCanCompleteInfo); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } std::stringstream stadelst1; std::stringstream stadelst2; // execute trade: 1. remove for (int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = myItems[i]) { stadelst1 << item->GetProto()->ItemId << ";"; item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetObjectGuid()); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); } if (Item* item = hisItems[i]) { stadelst2 << item->GetProto()->ItemId << ";"; item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, trader->GetObjectGuid()); trader->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); } } if (my_trade->GetMoney() > 0 || !stadelst1.str().empty()) { CharacterDatabase.PExecute("REPLACE INTO trade_log(sguid, rguid, gold, itemlist, tm) VALUES(%u,%u,%u,'%s',NOW())", _player->GetObjectGuid().GetCounter(), trader->GetObjectGuid().GetCounter(), my_trade->GetMoney(), stadelst1.str().c_str()); } if (his_trade->GetMoney() > 0 || !stadelst2.str().empty()) { CharacterDatabase.PExecute("REPLACE INTO trade_log(sguid, rguid, gold, itemlist, tm) VALUES(%u,%u,%u,'%s',NOW())", trader->GetObjectGuid().GetCounter(), _player->GetObjectGuid().GetCounter(), his_trade->GetMoney(), stadelst2.str().c_str()); } // execute trade: 2. store moveItems(myItems, hisItems); // logging money if (sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { if (_player->GetSession()->GetSecurity() > SEC_PLAYER && my_trade->GetMoney() > 0) { sLog.outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", _player->GetName(), _player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName(), trader->GetSession()->GetAccountId()); } if (trader->GetSession()->GetSecurity() > SEC_PLAYER && his_trade->GetMoney() > 0) { sLog.outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", trader->GetName(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName(), _player->GetSession()->GetAccountId()); } } // update money _player->ModifyMoney(-int32(my_trade->GetMoney())); _player->ModifyMoney(his_trade->GetMoney()); trader->ModifyMoney(-int32(his_trade->GetMoney())); trader->ModifyMoney(my_trade->GetMoney()); if (my_spell) my_spell->SpellStart(&my_targets); if (his_spell) his_spell->SpellStart(&his_targets); // cleanup clearAcceptTradeMode(my_trade, his_trade); delete _player->m_trade; _player->m_trade = nullptr; delete trader->m_trade; trader->m_trade = nullptr; // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(); trader->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); info.Status = TRADE_STATUS_TRADE_COMPLETE; trader->GetSession()->SendTradeStatus(info); SendTradeStatus(info); } else { info.Status = TRADE_STATUS_TRADE_ACCEPT; trader->GetSession()->SendTradeStatus(info); } }
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_STATUS_EXTENDED, 4*6 + 8 + 1 + 3 + count * 70); data << uint32(0); // this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) 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); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { Item* item = view_trade->GetItem(TradeSlots(i)); if (!item) continue; ObjectGuid giftCreatorGuid = item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); ObjectGuid creatorGuid = item->GetUInt64Value(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) { 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()->LockID != 0); data.WriteBit(creatorGuid[0]); itemData.WriteByteSeq(creatorGuid[1]); 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->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)); 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]); } 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()->ItemId); 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); }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); data << uint32(0); data << uint32(0); data << uint8(1); data << uint32(0); data << uint32(0); data << uint32(0); // trade ID? has to match what we sent in TRADE_STATUS for TRADE_STATUS_OPEN_WINDOW data << uint32(TRADE_SLOT_COUNT); // slot count data << uint64(view_trade->GetMoney()); // trade money data << uint32(0); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { uint32 id = 0; if (Item* item = view_trade->GetItem(TradeSlots(i))) { uint32 id = item->GetTemplate()->ItemId; data << uint32(0); data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); // Creator GUID data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); // Permanent Enchantment data << uint32(id); data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+1))); // First gem socket enchant data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); // Current Durability data << uint32(0); data << uint8(0); // If 1, then the item wont display any sockets, even if it has them data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // Max durability data << uint32(item->GetCount()); // Stack count data << uint32(0); data << uint32(item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); // Temporal enchantment data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+2))); // Second socket gem data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+3))); // Third socket gem data << uint32(0); } else { data << uint32(0); data << uint64(0); data << uint32(0); data << uint32(id); data << uint32(0); data << uint32(0); data << uint32(0); data << uint8(0); data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); } } SendPacket(&data); }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) { TradeData* my_trade = _player->m_trade; if (!my_trade) return; Player* trader = my_trade->GetTrader(); TradeData* his_trade = trader->m_trade; if (!his_trade) return; Item* myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; bool myCanCompleteTrade = true, hisCanCompleteTrade = true; // set before checks for propertly undo at problems (it already set in to client) my_trade->SetAccepted(true); // not accept case incorrect money amount if (!_player->HasEnoughMoney(my_trade->GetMoney())) { SendNotification(LANG_NOT_ENOUGH_GOLD); my_trade->SetAccepted(false, true); return; } // not accept case incorrect money amount if (!trader->HasEnoughMoney(his_trade->GetMoney())) { trader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); his_trade->SetAccepted(false, true); return; } // not accept if some items now can't be trade (cheating) for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = my_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded(false, true)) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } if (item->IsBindedNotWith(trader)) { SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); SendTradeStatus(TRADE_STATUS_CLOSE_WINDOW/*TRADE_STATUS_TRADE_CANCELED*/); return; } } if (Item* item = his_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded(false, true)) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } //if (item->IsBindedNotWith(_player)) // dont mark as invalid when his item isnt good (not exploitable because if item is invalid trade will fail anyway later on the same check) //{ // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); // his_trade->SetAccepted(false, true); // return; //} } } if (his_trade->IsAccepted()) { setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); Spell* my_spell = NULL; SpellCastTargets my_targets; Spell* his_spell = NULL; SpellCastTargets his_targets; // not accept if spell can't be casted now (cheating) if (uint32 my_spell_id = my_trade->GetSpell()) { SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id); Item* castItem = my_trade->GetSpellCastItem(); if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || (my_trade->HasSpellCastItem() && !castItem)) { clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); my_trade->SetSpell(0); return; } my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK); my_spell->m_CastItem = castItem; my_targets.SetTradeItemTarget(_player); my_spell->m_targets = my_targets; SpellCastResult res = my_spell->CheckCast(true); if (res != SPELL_CAST_OK) { my_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; my_trade->SetSpell(0); return; } } // not accept if spell can't be casted now (cheating) if (uint32 his_spell_id = his_trade->GetSpell()) { SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id); Item* castItem = his_trade->GetSpellCastItem(); if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) { delete my_spell; his_trade->SetSpell(0); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); return; } his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK); his_spell->m_CastItem = castItem; his_targets.SetTradeItemTarget(trader); his_spell->m_targets = his_targets; SpellCastResult res = his_spell->CheckCast(true); if (res != SPELL_CAST_OK) { his_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; delete his_spell; his_trade->SetSpell(0); return; } } // inform partner client trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // test if item will fit in each inventory hisCanCompleteTrade = (trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); myCanCompleteTrade = (_player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); clearAcceptTradeMode(myItems, hisItems); // in case of missing space report error if (!myCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_FREE_TRADE_SLOTS); trader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } else if (!hisCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); trader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } // execute trade: 1. remove for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (myItems[i]) { myItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true); } if (hisItems[i]) { hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, trader->GetGUID()); trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true); } } // execute trade: 2. store moveItems(myItems, hisItems); // logging money if (sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { if (!AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) && my_trade->GetMoney() > 0) { sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", _player->GetName(), _player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName(), trader->GetSession()->GetAccountId()); } if (!AccountMgr::IsPlayerAccount(trader->GetSession()->GetSecurity()) && his_trade->GetMoney() > 0) { sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", trader->GetName(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName(), _player->GetSession()->GetAccountId()); } } // update money _player->ModifyMoney(-int32(my_trade->GetMoney())); _player->ModifyMoney(his_trade->GetMoney()); trader->ModifyMoney(-int32(his_trade->GetMoney())); trader->ModifyMoney(my_trade->GetMoney()); if (my_spell) my_spell->prepare(&my_targets); if (his_spell) his_spell->prepare(&his_targets); // cleanup clearAcceptTradeMode(my_trade, his_trade); delete _player->m_trade; _player->m_trade = NULL; delete trader->m_trade; trader->m_trade = NULL; // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) SQLTransaction trans = CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(trans); trader->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); } else { trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); } }
void WorldSession::HandleAcceptTradeOpcode(WorldPackets::Trade::AcceptTrade& acceptTrade) { TradeData* my_trade = _player->m_trade; if (!my_trade) return; Player* trader = my_trade->GetTrader(); TradeData* his_trade = trader->m_trade; if (!his_trade) return; Item* myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; // set before checks for propertly undo at problems (it already set in to client) my_trade->SetAccepted(true); 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_TOO_FAR_AWAY; SendTradeStatus(info); my_trade->SetAccepted(false); return; } // not accept case incorrect money amount if (!_player->HasEnoughMoney(my_trade->GetMoney())) { info.Status = TRADE_STATUS_FAILED; info.BagResult = EQUIP_ERR_NOT_ENOUGH_MONEY; SendTradeStatus(info); my_trade->SetAccepted(false, true); return; } // not accept case incorrect money amount if (!trader->HasEnoughMoney(his_trade->GetMoney())) { info.Status = TRADE_STATUS_FAILED; info.BagResult = EQUIP_ERR_NOT_ENOUGH_MONEY; trader->GetSession()->SendTradeStatus(info); his_trade->SetAccepted(false, true); return; } if (_player->GetMoney() > MAX_MONEY_AMOUNT - his_trade->GetMoney()) { info.Status = TRADE_STATUS_FAILED; info.BagResult = EQUIP_ERR_TOO_MUCH_GOLD; SendTradeStatus(info); my_trade->SetAccepted(false, true); return; } if (trader->GetMoney() > MAX_MONEY_AMOUNT - my_trade->GetMoney()) { info.Status = TRADE_STATUS_FAILED; info.BagResult = EQUIP_ERR_TOO_MUCH_GOLD; trader->GetSession()->SendTradeStatus(info); his_trade->SetAccepted(false, true); return; } // not accept if some items now can't be trade (cheating) for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = my_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded(false, true)) { info.Status = TRADE_STATUS_CANCELLED; SendTradeStatus(info); return; } if (item->IsBindedNotWith(trader)) { info.Status = TRADE_STATUS_FAILED; info.BagResult = EQUIP_ERR_TRADE_BOUND_ITEM; SendTradeStatus(info); return; } } if (Item* item = his_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded(false, true)) { info.Status = TRADE_STATUS_CANCELLED; SendTradeStatus(info); return; } //if (item->IsBindedNotWith(_player)) // dont mark as invalid when his item isnt good (not exploitable because if item is invalid trade will fail anyway later on the same check) //{ // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); // his_trade->SetAccepted(false, true); // return; //} } } if (his_trade->IsAccepted()) { setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); Spell* my_spell = NULL; SpellCastTargets my_targets; Spell* his_spell = NULL; SpellCastTargets his_targets; // not accept if spell can't be cast now (cheating) if (uint32 my_spell_id = my_trade->GetSpell()) { SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id); Item* castItem = my_trade->GetSpellCastItem(); if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || (my_trade->HasSpellCastItem() && !castItem)) { clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); my_trade->SetSpell(0); return; } my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK); my_spell->m_CastItem = castItem; my_targets.SetTradeItemTarget(_player); my_spell->m_targets = my_targets; SpellCastResult res = my_spell->CheckCast(true); if (res != SPELL_CAST_OK) { my_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; my_trade->SetSpell(0); return; } } // not accept if spell can't be cast now (cheating) if (uint32 his_spell_id = his_trade->GetSpell()) { SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id); Item* castItem = his_trade->GetSpellCastItem(); if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) { delete my_spell; his_trade->SetSpell(0); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); return; } his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK); his_spell->m_CastItem = castItem; his_targets.SetTradeItemTarget(trader); his_spell->m_targets = his_targets; SpellCastResult res = his_spell->CheckCast(true); if (res != SPELL_CAST_OK) { his_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; delete his_spell; his_trade->SetSpell(0); return; } } // inform partner client info.Status = TRADE_STATUS_ACCEPTED; trader->GetSession()->SendTradeStatus(info); // test if item will fit in each inventory 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.BagResult != EQUIP_ERR_OK) { clearAcceptTradeMode(my_trade, his_trade); myCanCompleteInfo.Status = TRADE_STATUS_FAILED; trader->GetSession()->SendTradeStatus(myCanCompleteInfo); myCanCompleteInfo.FailureForYou = true; SendTradeStatus(myCanCompleteInfo); my_trade->SetAccepted(false); his_trade->SetAccepted(false); delete my_spell; delete his_spell; return; } else if (hisCanCompleteInfo.BagResult != EQUIP_ERR_OK) { clearAcceptTradeMode(my_trade, his_trade); hisCanCompleteInfo.Status = TRADE_STATUS_FAILED; SendTradeStatus(hisCanCompleteInfo); hisCanCompleteInfo.FailureForYou = true; trader->GetSession()->SendTradeStatus(hisCanCompleteInfo); my_trade->SetAccepted(false); his_trade->SetAccepted(false); delete my_spell; delete his_spell; return; } // execute trade: 1. remove for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (myItems[i]) { myItems[i]->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true); } if (hisItems[i]) { hisItems[i]->SetGuidValue(ITEM_FIELD_GIFTCREATOR, trader->GetGUID()); trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true); } } // execute trade: 2. store moveItems(myItems, hisItems); // logging money if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { if (my_trade->GetMoney() > 0) { sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: " UI64FMTD ") to player: %s (Account: %u)", _player->GetName().c_str(), _player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName().c_str(), trader->GetSession()->GetAccountId()); } if (his_trade->GetMoney() > 0) { sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: " UI64FMTD ") to player: %s (Account: %u)", trader->GetName().c_str(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName().c_str(), _player->GetSession()->GetAccountId()); } } // update money _player->ModifyMoney(-int64(my_trade->GetMoney())); _player->ModifyMoney(his_trade->GetMoney()); trader->ModifyMoney(-int64(his_trade->GetMoney())); trader->ModifyMoney(my_trade->GetMoney()); if (my_spell) my_spell->prepare(&my_targets); if (his_spell) his_spell->prepare(&his_targets); // cleanup clearAcceptTradeMode(my_trade, his_trade); delete _player->m_trade; _player->m_trade = NULL; delete trader->m_trade; trader->m_trade = NULL; // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) SQLTransaction trans = CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(trans); trader->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); info.Status = TRADE_STATUS_COMPLETE; trader->GetSession()->SendTradeStatus(info); SendTradeStatus(info); } else { info.Status = TRADE_STATUS_ACCEPTED; trader->GetSession()->SendTradeStatus(info); } }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& recvPacket) { recvPacket.read_skip<uint32>(); TradeData* my_trade = _player->m_trade; if (!my_trade) return; Player* trader = my_trade->GetTrader(); TradeData* his_trade = trader->m_trade; if (!his_trade) return; Item *myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; Item *hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; bool myCanCompleteTrade=true,hisCanCompleteTrade=true; // Check the validity of the users inventory before completeing the trade. bool error = false; for(size_t i = 0; i < _player->GetItemUpdateQueue().size(); ++i) { Item *item = _player->GetItemUpdateQueue()[i]; if(!item || item->GetState() == ITEM_REMOVED) continue; Item *test = _player->GetItemByPos( item->GetBagSlot(), item->GetSlot()); if (test == NULL) { error = true; } else if (test != item) { error = true; } } for(size_t i = 0; i < trader->GetItemUpdateQueue().size(); ++i) { Item *item = trader->GetItemUpdateQueue()[i]; if(!item || item->GetState() == ITEM_REMOVED) continue; Item *test = trader->GetItemByPos( item->GetBagSlot(), item->GetSlot()); if (test == NULL) { error = true; } else if (test != item) { error = true; } } // If there was an error we might have a item duplication attempt. Kick the players and write an entry in the log. if (error) { sLog.outError("SECURITY WARNING: There was an inventory error during a trade between %s and %s and they have been kicked. This could possibly be an item duplication attempt!", _player->GetName(), trader->GetName()); sLog.outError("The players tried to trade items with the following GUIDs:"); // not accept if some items now can't be trade (cheating) for(int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = my_trade->GetItem(TradeSlots(i))) { sLog.outError("%li", item->GetGUID()); } if (Item* item = his_trade->GetItem(TradeSlots(i))) { sLog.outError("%li", item->GetGUID()); } } my_trade->SetAccepted(false); his_trade->SetAccepted(false); _player->GetSession()->KickPlayer(); trader->GetSession()->KickPlayer(); } // set before checks to properly undo at problems (it already set in to client) my_trade->SetAccepted(true); // not accept case incorrect money amount if (my_trade->GetMoney() > _player->GetMoney()) { SendNotification(LANG_NOT_ENOUGH_GOLD); my_trade->SetAccepted(false, true); return; } // not accept case incorrect money amount if (his_trade->GetMoney() > trader->GetMoney()) { trader->GetSession( )->SendNotification(LANG_NOT_ENOUGH_GOLD); his_trade->SetAccepted(false, true); return; } // not accept if some items now can't be trade (cheating) for(int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = my_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } if (Item* item = his_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } } if (his_trade->IsAccepted()) { setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); Spell* my_spell = NULL; SpellCastTargets my_targets; Spell* his_spell = NULL; SpellCastTargets his_targets; // not accept if spell can't be casted now (cheating) if (uint32 my_spell_id = my_trade->GetSpell()) { SpellEntry const* spellEntry = sSpellStore.LookupEntry(my_spell_id); Item* castItem = my_trade->GetSpellCastItem(); if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || (my_trade->HasSpellCastItem() && !castItem)) { clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); my_trade->SetSpell(0); return; } my_spell = new Spell(_player, spellEntry, true); my_spell->m_CastItem = castItem; my_targets.setTradeItemTarget(_player); my_spell->m_targets = my_targets; SpellCastResult res = my_spell->CheckCast(true); if (res != SPELL_CAST_OK) { my_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; my_trade->SetSpell(0); return; } } // not accept if spell can't be casted now (cheating) if (uint32 his_spell_id = his_trade->GetSpell()) { SpellEntry const* spellEntry = sSpellStore.LookupEntry(his_spell_id); Item* castItem = his_trade->GetSpellCastItem(); if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) { delete my_spell; his_trade->SetSpell(0); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); return; } his_spell = new Spell(trader, spellEntry, true); his_spell->m_CastItem = castItem; his_targets.setTradeItemTarget(trader); his_spell->m_targets = his_targets; SpellCastResult res = his_spell->CheckCast(true); if (res != SPELL_CAST_OK) { his_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; delete his_spell; his_trade->SetSpell(0); return; } } // inform partner client trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // test if item will fit in each inventory hisCanCompleteTrade = (trader->CanStoreItems( myItems,TRADE_SLOT_TRADED_COUNT )== EQUIP_ERR_OK); myCanCompleteTrade = (_player->CanStoreItems( hisItems,TRADE_SLOT_TRADED_COUNT ) == EQUIP_ERR_OK); clearAcceptTradeMode(myItems, hisItems); // in case of missing space report error if(!myCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_FREE_TRADE_SLOTS); trader->GetSession( )->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } else if (!hisCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); trader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } // execute trade: 1. remove for(int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = myItems[i]) { item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetObjectGuid()); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); } if (Item* item = hisItems[i]) { item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, trader->GetObjectGuid()); trader->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); } } // execute trade: 2. store moveItems(myItems, hisItems); // logging money if (sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { if (_player->GetSession()->GetSecurity() > SEC_PLAYER && my_trade->GetMoney() > 0) { sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", _player->GetName(),_player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName(), trader->GetSession()->GetAccountId()); } if (trader->GetSession()->GetSecurity() > SEC_PLAYER && his_trade->GetMoney() > 0) { sLog.outCommand(trader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", trader->GetName(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName(),_player->GetSession()->GetAccountId()); } } // update money _player->ModifyMoney( -int32(my_trade->GetMoney()) ); _player->ModifyMoney(his_trade->GetMoney()); trader->ModifyMoney( -int32(his_trade->GetMoney()) ); trader->ModifyMoney(my_trade->GetMoney()); if (my_spell) my_spell->prepare(&my_targets); if (his_spell) his_spell->prepare(&his_targets); // cleanup clearAcceptTradeMode(my_trade, his_trade); delete _player->m_trade; _player->m_trade = NULL; delete trader->m_trade; trader->m_trade = NULL; // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(); trader->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); } else { trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); } }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& recvPacket) { recvPacket.read_skip<uint32>(); TradeData* my_trade = _player->m_trade; if (!my_trade) return; Player* trader = my_trade->GetTrader(); TradeData* his_trade = trader->m_trade; if (!his_trade) return; if (!_player->IsWithinDistInMap(trader, TRADE_DISTANCE, false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); my_trade->SetAccepted(false); return; } Item *myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; Item *hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; bool myCanCompleteTrade=true,hisCanCompleteTrade=true; // set before checks to properly undo at problems (it already set in to client) my_trade->SetAccepted(true); // not accept case incorrect money amount if (my_trade->GetMoney() > _player->GetMoney()) { SendNotification(LANG_NOT_ENOUGH_GOLD); my_trade->SetAccepted(false, true); return; } // not accept case incorrect money amount if (his_trade->GetMoney() > trader->GetMoney()) { trader->GetSession( )->SendNotification(LANG_NOT_ENOUGH_GOLD); his_trade->SetAccepted(false, true); return; } // not accept if some items now can't be trade (cheating) for(int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = my_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } if (Item* item = his_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } } if (his_trade->IsAccepted()) { setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); std::shared_ptr<Spell> my_spell = NULL; SpellCastTargets my_targets; std::shared_ptr<Spell> his_spell = NULL; SpellCastTargets his_targets; // not accept if spell can't be casted now (cheating) if (uint32 my_spell_id = my_trade->GetSpell()) { SpellEntry const* spellEntry = sSpellStore.LookupEntry(my_spell_id); Item* castItem = my_trade->GetSpellCastItem(); if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || (my_trade->HasSpellCastItem() && !castItem)) { clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); my_trade->SetSpell(0); return; } my_spell = std::make_shared<Spell>(_player, spellEntry, true); my_spell->m_CastItem = castItem; my_targets.setTradeItemTarget(_player); my_spell->m_targets = my_targets; SpellCastResult res = my_spell->CheckCast(true); if (res != SPELL_CAST_OK) { my_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); my_trade->SetSpell(0); return; } } // not accept if spell can't be casted now (cheating) if (uint32 his_spell_id = his_trade->GetSpell()) { SpellEntry const* spellEntry = sSpellStore.LookupEntry(his_spell_id); Item* castItem = his_trade->GetSpellCastItem(); if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) { his_trade->SetSpell(0); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); return; } his_spell = std::make_shared<Spell>(trader, spellEntry, true); his_spell->m_CastItem = castItem; his_targets.setTradeItemTarget(trader); his_spell->m_targets = his_targets; SpellCastResult res = his_spell->CheckCast(true); if (res != SPELL_CAST_OK) { his_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); his_trade->SetSpell(0); return; } } // inform partner client trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // test if item will fit in each inventory hisCanCompleteTrade = (trader->CanStoreItems( myItems,TRADE_SLOT_TRADED_COUNT )== EQUIP_ERR_OK); myCanCompleteTrade = (_player->CanStoreItems( hisItems,TRADE_SLOT_TRADED_COUNT ) == EQUIP_ERR_OK); clearAcceptTradeMode(myItems, hisItems); // in case of missing space report error if(!myCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_FREE_TRADE_SLOTS); trader->GetSession( )->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } else if (!hisCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); trader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } // execute trade: 1. remove for(int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = myItems[i]) { item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetObjectGuid()); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); //CharacterDatabase.PExecute("INSERT INTO character_destroyedItem VALUES ( %I64u, %u, %u, %u, CURRENT_TIMESTAMP )", _player->GetGUID(), item->GetEntry(), item->GetCount(), 0); } if (Item* item = hisItems[i]) { item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, trader->GetObjectGuid()); trader->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); //CharacterDatabase.PExecute("INSERT INTO character_destroyedItem VALUES ( %I64u, %u, %u, %u, CURRENT_TIMESTAMP )", _player->GetGUID(), item->GetEntry(), item->GetCount(), 0); } } // execute trade: 2. store moveItems(myItems, hisItems); // logging money if (sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { if (_player->GetSession()->GetSecurity() > SEC_PLAYER && my_trade->GetMoney() > 0) { sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", _player->GetName(),_player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName(), trader->GetSession()->GetAccountId()); } if (trader->GetSession()->GetSecurity() > SEC_PLAYER && his_trade->GetMoney() > 0) { sLog.outCommand(trader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", trader->GetName(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName(),_player->GetSession()->GetAccountId()); } } // update money _player->ModifyMoney( -int32(my_trade->GetMoney()) ); _player->ModifyMoney(his_trade->GetMoney()); trader->ModifyMoney( -int32(his_trade->GetMoney()) ); trader->ModifyMoney(my_trade->GetMoney()); if (my_spell) my_spell->prepare(&my_targets); if (his_spell) his_spell->prepare(&his_targets); // cleanup clearAcceptTradeMode(my_trade, his_trade); delete _player->m_trade; _player->m_trade = NULL; delete trader->m_trade; trader->m_trade = NULL; // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(); trader->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); } else { trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); } }
void WorldSession::SendUpdateTrade(bool trader_state /*= true*/) { TradeData* view_trade = trader_state ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) 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? data << uint32(0); // unk 5 data << uint8(trader_state ? 1 : 0); // send trader or own trade windows state (last need for proper show spell apply to non-trade slot) data << uint32(TRADE_SLOT_COUNT); // trade slots count/number? uint8 itemCount = 0; for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) if (Item* item = view_trade->GetItem(TradeSlots(i))) ++itemCount; data.WriteBits(itemCount, 22); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { if (Item* item = view_trade->GetItem(TradeSlots(i))) { ObjectGuid creatorGuid = item->GetGuidValue(ITEM_FIELD_CREATOR); ObjectGuid giftCreatorGuid = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR); data.WriteGuidMask<7, 1>(giftCreatorGuid); data.WriteBit(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)); data.WriteGuidMask<3>(giftCreatorGuid); if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { data.WriteGuidMask<7, 1, 4, 6, 2, 3, 5>(creatorGuid); data.WriteBit(item->GetProto()->LockID && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED)); data.WriteGuidMask<0>(creatorGuid); } data.WriteGuidMask<6, 4, 2, 0, 5>(giftCreatorGuid); } } for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { if (Item* item = view_trade->GetItem(TradeSlots(i))) { ObjectGuid creatorGuid = item->GetGuidValue(ITEM_FIELD_CREATOR); ObjectGuid giftCreatorGuid = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR); if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { data.WriteGuidBytes<1>(creatorGuid); data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); data.WriteGuidBytes<6, 2, 7, 4>(creatorGuid); data << uint32(item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)); // reforge Id data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); data << uint32(item->GetItemRandomPropertyId()); data.WriteGuidBytes<3>(creatorGuid); data << uint32(0); // unk data.WriteGuidBytes<0>(creatorGuid); data << uint32(item->GetSpellCharges()); // charges data << uint32(item->GetItemSuffixFactor()); data.WriteGuidBytes<5>(creatorGuid); } data.WriteGuidBytes<6, 1, 7, 4>(giftCreatorGuid); data << uint32(item->GetProto()->ItemId); // entry data.WriteGuidBytes<0>(giftCreatorGuid); data << uint32(item->GetCount()); // stack count data.WriteGuidBytes<5>(giftCreatorGuid); data << uint8(i); // slot id data.WriteGuidBytes<2, 3>(giftCreatorGuid); } } SendPacket(&data); }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); data << uint32(0); data << uint32(0); data << uint8(1); data << uint32(0); data << uint32(0); data << uint32(0); // trade ID? has to match what we sent in TRADE_STATUS for TRADE_STATUS_OPEN_WINDOW data << uint32(TRADE_SLOT_COUNT); // slot count data << uint64(view_trade->GetMoney()); // trade money data << uint32(0); // old structure. meaning of new structure fields has to be researched /*data << uint8(trader_data); // 1 means traders data, 0 means own data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases data << uint32(view_trade->GetMoney()); // trader gold data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item*/ for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { uint32 id = 0; if (Item* item = view_trade->GetItem(TradeSlots(i))) { uint32 id = item->GetTemplate()->ItemId; data << uint32(0); data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); // Creator GUID data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); // Permanent Enchantment data << uint32(id); data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+1))); // First gem socket enchant data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); // Current Durability data << uint32(0); data << uint8(0); // If 1, then the item wont display any sockets, even if it has them data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // Max durability data << uint32(item->GetCount()); // Stack count data << uint32(0); data << uint32(item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); // Temporal enchantment data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+2))); // Second socket gem data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+3))); // Third socket gem data << uint32(0); } else data << uint32(0); data << uint64(0); data << uint32(0); data << uint32(id); data << uint32(0); data << uint32(0); data << uint32(0); data << uint8(0); data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); // old structure /*data << uint8(i); // trade slot number, if not specified, then end of packet if (Item* item = view_trade->GetItem(TradeSlots(i))) { data << uint32(item->GetTemplate()->ItemId); // entry data << uint32(item->GetTemplate()->DisplayInfoID);// display id data << uint32(item->GetCount()); // stack count // wrapped: hide stats but show giftcreator name data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED) ? 1 : 0); data << uint64(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)); // perm. enchantment and gems data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); // creator data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); data << uint32(item->GetSpellCharges()); // charges data << uint32(item->GetItemSuffixFactor()); // SuffixFactor data << uint32(item->GetItemRandomPropertyId());// random properties id data << uint32(item->GetTemplate()->LockID); // lock id // max durability data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // durability data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); } else { for (uint8 j = 0; j < 18; ++j) data << uint32(0); }*/ } SendPacket(&data); }