void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) { // send update uint8 tradeSlot; uint8 bag; uint8 slot; recvPacket >> tradeSlot; recvPacket >> bag; recvPacket >> slot; TradeData* my_trade = _player->GetTradeData(); if (!my_trade) return; // invalid slot number if (tradeSlot >= TRADE_SLOT_COUNT) { 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))) { 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)) { // cheating attempt SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } my_trade->SetItem(TradeSlots(tradeSlot), item); }
void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/) { TradeData* my_trade = _player->m_trade; if (!my_trade) return; TradeStatusInfo info; info.Status = TRADE_STATUS_OPEN_WINDOW; my_trade->GetTrader()->GetSession()->SendTradeStatus(info); SendTradeStatus(info); }
void WorldSession::HandleBeginTradeOpcode(WorldPackets::Trade::BeginTrade& /*beginTrade*/) { TradeData* my_trade = _player->m_trade; if (!my_trade) return; WorldPackets::Trade::TradeStatus info; info.Status = TRADE_STATUS_INITIATED; my_trade->GetTrader()->GetSession()->SendTradeStatus(info); SendTradeStatus(info); }
void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/) { if (!_player->pTrader) return; _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); _player->pTrader->ClearTrade(); SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); _player->ClearTrade(); }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& recvPacket) { 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; uint16 dst; if ( !GetPlayer()->pTrader ) return; // not accept case incorrect money amount if( _player->tradeGold > _player->GetMoney() ) { SendNotification( "You do not have enough gold" ); _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->acceptTrade = false; return; } // not accept case incorrect money amount if( _player->pTrader->tradeGold > _player->pTrader->GetMoney() ) { _player->pTrader->GetSession( )->SendNotification( "You do not have enough gold" ); SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->pTrader->acceptTrade = false; return; } _player->acceptTrade = true; if (_player->pTrader->acceptTrade ) { // inform partner client _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // store items in local list and set 'in-trade' flag for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++) { if(_player->tradeItems[i] != NULL_SLOT ) { sLog.outDebug("player trade item bag: %u slot: %u",_player->tradeItems[i] >> 8, _player->tradeItems[i] & 255 ); //Can return NULL myItems[i]=_player->GetItemByPos( _player->tradeItems[i] ); if (myItems[i]) myItems[i]->SetInTrade(); } if(_player->pTrader->tradeItems[i] != NULL_SLOT) { sLog.outDebug("partner trade item bag: %u slot: %u",_player->pTrader->tradeItems[i] >> 8,_player->pTrader->tradeItems[i] & 255); //Can return NULL hisItems[i]=_player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i]); if(hisItems[i]) hisItems[i]->SetInTrade(); }
void WorldSession::HandleInitiateTrade(WorldPacket & recv_data) { CHECK_INWORLD_RETURN; CHECK_PACKET_SIZE(recv_data, 8); uint64 guid; recv_data >> guid; uint32 TradeStatus = TRADE_STATUS_PROPOSED; PlayerPointer pTarget = _player->GetMapMgr()->GetPlayer((uint32)guid); if(pTarget == NULL || !pTarget->IsInWorld()) TradeStatus = TRADE_STATUS_PLAYER_NOT_FOUND; else { // Handle possible error outcomes if(_player->isDead()) TradeStatus = TRADE_STATUS_DEAD; if(pTarget->isDead()) TradeStatus = TRADE_STATUS_TARGET_DEAD; else if(pTarget->mTradeTarget != 0) TradeStatus = TRADE_STATUS_ALREADY_TRADING; else if(pTarget->GetTeam() != _player->GetTeam() && GetPermissionCount() == 0) TradeStatus = TRADE_STATUS_WRONG_FACTION; else if(_player->CalcDistance(pTarget) > 10.0f) // This needs to be checked TradeStatus = TRADE_STATUS_TOO_FAR_AWAY; } if(TradeStatus != TRADE_STATUS_PROPOSED) { _player->ResetTradeVariables(); SendTradeStatus(TradeStatus); } else { _player->ResetTradeVariables(); pTarget->ResetTradeVariables(); pTarget->mTradeTarget = _player->GetLowGUID(); _player->mTradeTarget = pTarget->GetLowGUID(); pTarget->mTradeStatus = TradeStatus; _player->mTradeStatus = TradeStatus; WorldPacket data(SMSG_TRADE_STATUS, 12); data << TradeStatus; data << _player->GetGUID(); if(pTarget->m_session && pTarget->m_session->GetSocket()) pTarget->m_session->SendPacket(&data); } }
void WorldSession::HandleIgnoreTrade(WorldPacket & recv_data) { if(!_player->IsInWorld() || _player->mTradeTarget == 0) return; uint32 TradeStatus = TRADE_STATUS_PLAYER_IGNORED; Player* pTarget = _player->GetTradeTarget(); if(pTarget == NULL || !pTarget->IsInWorld()) TradeStatus = TRADE_STATUS_PLAYER_NOT_FOUND; _player->ResetTradeVariables(); SendTradeStatus(TradeStatus); }
void WorldSession::HandleUnacceptTrade(WorldPacket & recv_data) { if(!_player->IsInWorld() || _player->mTradeTarget == 0) return; uint32 TradeStatus = TRADE_STATUS_UNACCEPTED; Player* pTarget = _player->GetTradeTarget(); if(pTarget == NULL || !pTarget->IsInWorld()) { TradeStatus = TRADE_STATUS_PLAYER_NOT_FOUND; _player->ResetTradeVariables(); SendTradeStatus(TradeStatus); } else { pTarget->mTradeStatus = TradeStatus; _player->mTradeStatus = TradeStatus; SendTradeStatus(TradeStatus); if( pTarget->m_session && pTarget->m_session->GetSocket()) pTarget->m_session->SendTradeStatus(TradeStatus); } }
void WorldSession::HandleBeginTrade(WorldPacket & recv_data) { Player* pTarget = NULLPLR; uint32 TradeStatus = TRADE_STATUS_INITIATED; if(!_player->IsInWorld() || _player->mTradeTarget == 0) TradeStatus = TRADE_STATUS_PLAYER_NOT_FOUND; else { pTarget = _player->GetTradeTarget(); if(pTarget == NULL || !pTarget->IsInWorld() ) TradeStatus = TRADE_STATUS_PLAYER_NOT_FOUND; else if( _player->CalcDistance( pTarget ) > 10.0f ) TradeStatus = TRADE_STATUS_TOO_FAR_AWAY; } //Abort if not ok if( TradeStatus != TRADE_STATUS_INITIATED) { TradeStatus = TRADE_STATUS_PLAYER_NOT_FOUND; _player->ResetTradeVariables(); SendTradeStatus(TradeStatus); } else { //Update status WorldPacket data(SMSG_TRADE_STATUS, 8); data << TradeStatus << uint32(0x19); SendPacket(&data); if(pTarget->m_session && pTarget->m_session->GetSocket()) pTarget->m_session->SendPacket(&data); _player->mTradeStatus = TradeStatus; pTarget->mTradeStatus = TradeStatus; } }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) { 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; if ( !GetPlayer()->pTrader ) return; // not accept case incorrect money amount if( _player->tradeGold > _player->GetMoney() ) { SendNotification(LANG_NOT_ENOUGH_GOLD); _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->acceptTrade = false; return; } // not accept case incorrect money amount if( _player->pTrader->tradeGold > _player->pTrader->GetMoney() ) { _player->pTrader->GetSession( )->SendNotification(LANG_NOT_ENOUGH_GOLD); SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->pTrader->acceptTrade = false; return; } // not accept if some items now can't be trade (cheating) for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i) { if(_player->tradeItems[i] != NULL_SLOT ) { if(Item* item =_player->GetItemByPos( _player->tradeItems[i] )) { if(!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } } if(_player->pTrader->tradeItems[i] != NULL_SLOT) { if(Item* item =_player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i]) ) { if(!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } } } _player->acceptTrade = true; if (_player->pTrader->acceptTrade ) { // inform partner client _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // store items in local list and set 'in-trade' flag for (int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i) { if(_player->tradeItems[i] != NULL_SLOT ) { sLog.outDebug("player trade item bag: %u slot: %u",_player->tradeItems[i] >> 8, _player->tradeItems[i] & 255 ); //Can return NULL myItems[i]=_player->GetItemByPos( _player->tradeItems[i] ); if (myItems[i]) myItems[i]->SetInTrade(); } if(_player->pTrader->tradeItems[i] != NULL_SLOT) { sLog.outDebug("partner trade item bag: %u slot: %u",_player->pTrader->tradeItems[i] >> 8,_player->pTrader->tradeItems[i] & 255); //Can return NULL hisItems[i]=_player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i]); if(hisItems[i]) hisItems[i]->SetInTrade(); }
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { ObjectGuid otherGuid; recvPacket >> otherGuid; if (GetPlayer()->m_trade) return; TradeStatusInfo info; if (!GetPlayer()->isAlive()) { info.Status = TRADE_STATUS_YOU_DEAD; SendTradeStatus(info); return; } if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) { info.Status = TRADE_STATUS_YOU_STUNNED; SendTradeStatus(info); return; } if (isLogingOut()) { info.Status = TRADE_STATUS_YOU_LOGOUT; SendTradeStatus(info); return; } if (GetPlayer()->IsTaxiFlying()) { info.Status = TRADE_STATUS_TARGET_TO_FAR; SendTradeStatus(info); return; } Player* pOther = ObjectAccessor::FindPlayer(otherGuid); if (!pOther) { info.Status = TRADE_STATUS_NO_TARGET; SendTradeStatus(info); return; } if (pOther == GetPlayer() || pOther->m_trade) { info.Status = TRADE_STATUS_BUSY; SendTradeStatus(info); return; } if (!pOther->isAlive()) { info.Status = TRADE_STATUS_TARGET_DEAD; SendTradeStatus(info); return; } if (pOther->IsTaxiFlying()) { info.Status = TRADE_STATUS_TARGET_TO_FAR; SendTradeStatus(info); return; } if (pOther->hasUnitState(UNIT_STAT_STUNNED)) { info.Status = TRADE_STATUS_TARGET_STUNNED; SendTradeStatus(info); return; } if (pOther->GetSession()->isLogingOut()) { info.Status = TRADE_STATUS_TARGET_LOGOUT; SendTradeStatus(info); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetObjectGuid())) { info.Status = TRADE_STATUS_IGNORE_YOU; SendTradeStatus(info); return; } if (pOther->GetTeam() != _player->GetTeam()) { info.Status = TRADE_STATUS_WRONG_FACTION; SendTradeStatus(info); return; } if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false)) { info.Status = TRADE_STATUS_TARGET_TO_FAR; SendTradeStatus(info); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); info.Status = TRADE_STATUS_BEGIN_TRADE; info.TraderGuid = _player->GetObjectGuid(); pOther->GetSession()->SendTradeStatus(info); }
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; 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::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { uint64 ID; recvPacket >> ID; if (GetPlayer()->m_trade) return; if (!GetPlayer()->isAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } if (GetPlayer()->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } Player* pOther = ObjectAccessor::FindPlayer( ID ); if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } if (pOther == GetPlayer() || pOther->m_trade) { SendTradeStatus(TRADE_STATUS_BUSY); return; } if (!pOther->isAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } if (pOther->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; } if (pOther->GetTeam() !=_player->GetTeam() ) { SendTradeStatus(TRADE_STATUS_WRONG_FACTION); return; } if (!pOther->IsWithinDistInMap(_player,10.0f,false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); WorldPacket data(SMSG_TRADE_STATUS, 12); data << (uint32) TRADE_STATUS_BEGIN_TRADE; data << (uint64)_player->GetGUID(); pOther->GetSession()->SendPacket(&data); }
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { uint64 ID; recvPacket >> ID; if (GetPlayer()->pTrader) return; if (!GetPlayer()->isAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } if (GetPlayer()->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } Player* pOther = ObjectAccessor::FindPlayer(ID); if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } if (pOther == GetPlayer() || pOther->pTrader) { SendTradeStatus(TRADE_STATUS_BUSY); return; } if (!pOther->isAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } if (pOther->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; } if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() != _player->GetTeam()) { SendTradeStatus(TRADE_STATUS_WRONG_FACTION); return; } if (pOther->GetDistance2d(_player) > 10.0f) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } // OK start trade _player->pTrader = pOther; pOther->pTrader =_player; WorldPacket data(SMSG_TRADE_STATUS, 12); data << (uint32) TRADE_STATUS_BEGIN_TRADE; data << (uint64)_player->GetGUID(); _player->pTrader->GetSession()->SendPacket(&data); }
void WorldSession::SendCancelTrade() { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& recvPacket) { recvPacket.read_skip<uint32>(); 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; if (!GetPlayer()->pTrader) return; // not accept case incorrect money amount if (_player->tradeGold > _player->GetMoney()) { SendNotification(LANG_NOT_ENOUGH_GOLD); _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->acceptTrade = false; return; } // not accept case incorrect money amount if (_player->pTrader->tradeGold > _player->pTrader->GetMoney()) { _player->pTrader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->pTrader->acceptTrade = false; return; } // not accept if some items now can't be trade (cheating) for (int i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (_player->tradeItems[i] != 0) { if (Item* item =_player->GetItemByGuid(_player->tradeItems[i])) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } } if (_player->pTrader->tradeItems[i] != 0) { if (Item* item =_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i])) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } } } _player->acceptTrade = true; if (_player->pTrader->acceptTrade) { // inform partner client _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // store items in local list and set 'in-trade' flag for (int i=0; i<TRADE_SLOT_TRADED_COUNT; i++) { if (_player->tradeItems[i] != 0 ) { //Can return NULL myItems[i]=_player->GetItemByGuid( _player->tradeItems[i] ); if (myItems[i]) { myItems[i]->SetInTrade(); sLog.outDebug("Player trade item bag: %u slot: %u", myItems[i]->GetBagSlot(), myItems[i]->GetSlot()); } } if (_player->pTrader->tradeItems[i] != 0) { //Can return NULL hisItems[i]=_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]); if (hisItems[i]) { hisItems[i]->SetInTrade(); sLog.outDebug("Player trade item bag: %u slot: %u", hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot()); } } } // test if item will fit in each inventory hisCanCompleteTrade = (_player->pTrader->CanStoreItems(myItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); myCanCompleteTrade = (_player->CanStoreItems(hisItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); // clear 'in-trade' flag for (int i=0; i<TRADE_SLOT_TRADED_COUNT; i++) { if (myItems[i]) myItems[i]->SetInTrade(false); if (hisItems[i]) hisItems[i]->SetInTrade(false); } // in case of missing space report error if (!myCanCompleteTrade) { SendNotification(LANG_NOT_FREE_TRADE_SLOTS); GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); return; } else if (!hisCanCompleteTrade) { SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); return; } // execute trade: 1. remove for(int i = 0; i < TRADE_SLOT_TRADED_COUNT; i++) { Item* iPtr = NULL; if (myItems[i]) { myItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR,_player->GetGUID()); iPtr = _player->GetItemByGuid(_player->tradeItems[i]); _player->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true); } if (hisItems[i]) { hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR,_player->pTrader->GetGUID()); iPtr = _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]); _player->pTrader->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true); } } // execute trade: 2. store moveItems(myItems, hisItems); // logging money if (sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { if (_player->GetSession()->GetSecurity() > SEC_PLAYER && _player->tradeGold > 0) { sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", _player->GetName(),_player->GetSession()->GetAccountId(), _player->tradeGold, _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId()); } if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && _player->pTrader->tradeGold > 0) { sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(), _player->pTrader->tradeGold, _player->GetName(),_player->GetSession()->GetAccountId()); } } // update money _player->ModifyMoney(-int32(_player->tradeGold)); _player->ModifyMoney(_player->pTrader->tradeGold); _player->pTrader->ModifyMoney(-int32(_player->pTrader->tradeGold)); _player->pTrader->ModifyMoney(_player->tradeGold); _player->ClearTrade(); _player->pTrader->ClearTrade(); // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(); _player->pTrader->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); _player->pTrader->pTrader = NULL; _player->pTrader = NULL; } else { _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); } }
void WorldSession::SendCancelTrade() { if (m_playerRecentlyLogout) return; SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); }
void WorldSession::HandleAcceptTrade(WorldPacket & recv_data) { if(!_player->IsInWorld() || _player->mTradeTarget == 0) return; uint32 TradeStatus = TRADE_STATUS_ACCEPTED; Player* pTarget = _player->GetTradeTarget(); if(pTarget == NULL || !pTarget->IsInWorld()) TradeStatus = TRADE_STATUS_PLAYER_NOT_FOUND; // Tell the other player we're green. if(pTarget->m_session && pTarget->m_session->GetSocket()) pTarget->m_session->SendTradeStatus(TradeStatus); _player->mTradeStatus = TradeStatus; //Both sides accepted? Let's trade! if(_player->mTradeStatus == TRADE_STATUS_ACCEPTED && pTarget->mTradeStatus == TRADE_STATUS_ACCEPTED) { // Ready! uint32 ItemCount = 0; uint32 TargetItemCount = 0; Item* pItem; // Count items on both sides, check if bags are empty. for(uint32 Index = 0; Index < 6; Index++) { if(_player->mTradeItems[Index] != NULL) { pItem = _player->mTradeItems[Index]; if( pItem != NULL && pItem->IsContainer() && TO_CONTAINER(pItem)->HasItems()) { sWorld.LogCheater(this, "%s involved in bag-trick trade with %s", _player->GetName(),pTarget->GetName()); _player->GetItemInterface()->BuildInventoryChangeError( pItem, NULLITEM, INV_ERR_CANT_TRADE_EQUIP_BAGS); TradeStatus = TRADE_STATUS_CANCELLED; break; } else ++ItemCount; } if(pTarget->mTradeItems[Index] != NULL) { pItem = pTarget->mTradeItems[Index]; if( pItem != NULL && pItem->IsContainer() && TO_CONTAINER(pItem)->HasItems() ) { sWorld.LogCheater(this, "%s involved in bag-trick trade with %s.", pTarget->GetName(),_player->GetName()); pTarget->GetItemInterface()->BuildInventoryChangeError( pItem, NULLITEM, INV_ERR_CANT_TRADE_EQUIP_BAGS); TradeStatus = TRADE_STATUS_CANCELLED; break; } else ++TargetItemCount; } } //Do we have something to trade? if( ItemCount == 0 && TargetItemCount == 0 && _player->mTradeGold == 0 && pTarget->mTradeGold == 0 ) TradeStatus = TRADE_STATUS_CANCELLED; //Do we have enough free slots on both sides? else if((_player->m_ItemInterface->CalculateFreeSlots(NULL) + ItemCount) < TargetItemCount || (pTarget->m_ItemInterface->CalculateFreeSlots(NULL) + TargetItemCount) < ItemCount ) TradeStatus = TRADE_STATUS_CANCELLED; //Everything still ok? if(TradeStatus == TRADE_STATUS_ACCEPTED) { uint64 Guid; //Swapp 6 itemslots (7th will not trade) for(uint32 Index = 0; Index < 6; Index++) { Guid = _player->mTradeItems[Index] ? _player->mTradeItems[Index]->GetGUID() : 0; if(Guid != 0) { if( _player->mTradeItems[Index]->IsSoulbound()) _player->GetItemInterface()->BuildInventoryChangeError( _player->mTradeItems[Index], NULLITEM, INV_ERR_CANNOT_TRADE_THAT); else { //Remove from player pItem = _player->m_ItemInterface->SafeRemoveAndRetreiveItemByGuidRemoveStats(Guid, true); //and add to pTarget if(pItem != NULL) { pItem->SetOwner(pTarget); if( !pTarget->m_ItemInterface->AddItemToFreeSlot(pItem) ) { pItem->DeleteMe(); pItem = NULL; } } if(GetPermissionCount()>0 || pTarget->GetSession()->GetPermissionCount()>0) sWorld.LogGM(this, "trade item %s with %s (soulbound = %d)", _player->mTradeItems[Index]->GetProto()->Name1, pTarget->GetName()); } } Guid = pTarget->mTradeItems[Index] ? pTarget->mTradeItems[Index]->GetGUID() : 0; if(Guid != 0) { if( pTarget->mTradeItems[Index]->IsSoulbound()) pTarget->GetItemInterface()->BuildInventoryChangeError( pTarget->mTradeItems[Index], NULLITEM, INV_ERR_CANNOT_TRADE_THAT); else { //Remove from pTarget pItem = pTarget->m_ItemInterface->SafeRemoveAndRetreiveItemByGuidRemoveStats(Guid, true); //and add to initiator if(pItem != NULL) { pItem->SetOwner(_player); if( !_player->m_ItemInterface->AddItemToFreeSlot(pItem) ) { pItem->DeleteMe(); pItem = NULL; } } if(GetPermissionCount()>0 || pTarget->GetSession()->GetPermissionCount()>0) sWorld.LogGM(this, "trade item %s with %s", pTarget->mTradeItems[Index]->GetProto()->Name1, _player->GetName()); } } } // Trade Gold if(_player->mTradeGold) { pTarget->ModUnsigned32Value(PLAYER_FIELD_COINAGE, _player->mTradeGold); _player->ModUnsigned32Value(PLAYER_FIELD_COINAGE, -(int32)_player->mTradeGold); } if(pTarget->mTradeGold) { _player->ModUnsigned32Value(PLAYER_FIELD_COINAGE, pTarget->mTradeGold); pTarget->ModUnsigned32Value(PLAYER_FIELD_COINAGE, -(int32)pTarget->mTradeGold); } pTarget->SaveToDB(false); _player->SaveToDB(false); TradeStatus = TRADE_STATUS_COMPLETE; } SendTradeStatus(TradeStatus); if(pTarget->m_session && pTarget->m_session->GetSocket()) pTarget->m_session->SendTradeStatus(TradeStatus); // Reset Trade Vars _player->ResetTradeVariables(); pTarget->ResetTradeVariables(); } }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) { 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; if (!GetPlayer()->pTrader) return; // not accept case incorrect money amount if (_player->tradeGold > _player->GetMoney()) { SendNotification(LANG_NOT_ENOUGH_GOLD); _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->acceptTrade = false; return; } // not accept case incorrect money amount if (_player->pTrader->tradeGold > _player->pTrader->GetMoney()) { _player->pTrader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); _player->pTrader->acceptTrade = false; return; } // not accept if some items now can't be trade (cheating) for (int i=0; i<TRADE_SLOT_TRADED_COUNT; i++) { if (_player->tradeItems[i] != NULL_SLOT) { if (Item* item =_player->GetItemByPos(_player->tradeItems[i])) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } else { // if not found item and slot was other than NULL (cheating) // jeszcze jest jeden exploit na trade itemów innych ni¿ s¹ pokazane, // ale te cipy na to nie wpadn¹ jak im ktoœ nie da gotowego hacka SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); std::string accountname; if (AccountMgr::GetName(_player->GetSession()->GetAccountId(), accountname)) { std::string duration = "-1"; std::string reason = "GM INFO - trade hack/exploit"; std::string name = "CONSOLE"; sWorld.BanAccount(BAN_ACCOUNT, accountname.c_str(), duration.c_str(), reason.c_str(), name.c_str()); } return; } } if (_player->pTrader->tradeItems[i] != NULL_SLOT) { if (Item* item =_player->pTrader->GetItemByPos(_player->pTrader->tradeItems[i])) { if (!item->CanBeTraded()) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } } else { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); std::string accountname; if (AccountMgr::GetName(_player->GetSession()->GetAccountId(), accountname)) { std::string duration = "-1"; std::string reason = "GM INFO - trade hack/exploit"; std::string name = "CONSOLE"; sWorld.BanAccount(BAN_ACCOUNT, accountname.c_str(), duration.c_str(), reason.c_str(), name.c_str()); } return; } } } _player->acceptTrade = true; if (_player->pTrader->acceptTrade) { // inform partner client _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // store items in local list and set 'in-trade' flag for (int i=0; i<TRADE_SLOT_TRADED_COUNT; i++) { if (_player->tradeItems[i] != NULL_SLOT) { sLog.outDebug("player trade item bag: %u slot: %u",_player->tradeItems[i] >> 8, _player->tradeItems[i] & 255); //Can return NULL myItems[i]=_player->GetItemByPos(_player->tradeItems[i]); if (myItems[i]) myItems[i]->SetInTrade(); } if (_player->pTrader->tradeItems[i] != NULL_SLOT) { sLog.outDebug("partner trade item bag: %u slot: %u",_player->pTrader->tradeItems[i] >> 8,_player->pTrader->tradeItems[i] & 255); //Can return NULL hisItems[i]=_player->pTrader->GetItemByPos(_player->pTrader->tradeItems[i]); if (hisItems[i]) hisItems[i]->SetInTrade(); }
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { ObjectGuid otherGuid; recvPacket.ReadGuidMask<0, 3, 5, 1, 4, 6, 7, 2>(otherGuid); recvPacket.ReadGuidBytes<7, 4, 3, 5, 1, 2, 6, 0>(otherGuid); if (GetPlayer()->m_trade) return; if (!GetPlayer()->IsAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } if (GetPlayer()->IsTaxiFlying()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } Player* pOther = ObjectAccessor::FindPlayer(otherGuid); if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } if (pOther == GetPlayer() || pOther->m_trade) { SendTradeStatus(TRADE_STATUS_BUSY); return; } if (!pOther->IsAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } if (pOther->IsTaxiFlying()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetObjectGuid())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; } if (pOther->GetTeam() != _player->GetTeam()) { SendTradeStatus(TRADE_STATUS_WRONG_FACTION); return; } if (!pOther->IsWithinDistInMap(_player, 10.0f, false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); WorldPacket data(SMSG_TRADE_STATUS, 12); data.WriteBit(false); data.WriteBits(TRADE_STATUS_BEGIN_TRADE, 5); data.WriteGuidMask<2, 4, 6, 0, 1, 3, 7, 5>(_player->GetObjectGuid()); data.WriteGuidBytes<4, 1, 2, 3, 0, 7, 6, 5>(_player->GetObjectGuid()); data << uint32(0); pOther->GetSession()->SendPacket(&data); }
void WorldSession::HandleInitiateTradeOpcode(WorldPackets::Trade::InitiateTrade& initiateTrade) { if (GetPlayer()->m_trade) return; WorldPackets::Trade::TradeStatus info; if (!GetPlayer()->IsAlive()) { info.Status = TRADE_STATUS_DEAD; SendTradeStatus(info); return; } if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED)) { info.Status = TRADE_STATUS_STUNNED; SendTradeStatus(info); return; } if (isLogingOut()) { info.Status = TRADE_STATUS_LOGGING_OUT; SendTradeStatus(info); return; } if (GetPlayer()->IsInFlight()) { info.Status = TRADE_STATUS_TOO_FAR_AWAY; SendTradeStatus(info); return; } if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } Player* pOther = ObjectAccessor::FindPlayer(initiateTrade.Guid); if (!pOther) { info.Status = TRADE_STATUS_NO_TARGET; SendTradeStatus(info); return; } if (pOther == GetPlayer() || pOther->m_trade) { info.Status = TRADE_STATUS_PLAYER_BUSY; SendTradeStatus(info); return; } if (!pOther->IsAlive()) { info.Status = TRADE_STATUS_TARGET_DEAD; SendTradeStatus(info); return; } if (pOther->IsInFlight()) { info.Status = TRADE_STATUS_TOO_FAR_AWAY; SendTradeStatus(info); return; } if (pOther->HasUnitState(UNIT_STATE_STUNNED)) { info.Status = TRADE_STATUS_TARGET_STUNNED; SendTradeStatus(info); return; } if (pOther->GetSession()->isLogingOut()) { info.Status = TRADE_STATUS_TARGET_LOGGING_OUT; SendTradeStatus(info); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUID())) { info.Status = TRADE_STATUS_PLAYER_IGNORED; SendTradeStatus(info); return; } if ((pOther->GetTeam() != _player->GetTeam() || pOther->HasFlag(PLAYER_FLAGS_EX, PLAYER_FLAGS_EX_MERCENARY_MODE) || _player->HasFlag(PLAYER_FLAGS_EX, PLAYER_FLAGS_EX_MERCENARY_MODE)) && (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && !HasPermission(rbac::RBAC_PERM_ALLOW_TWO_SIDE_TRADE))) { info.Status = TRADE_STATUS_WRONG_FACTION; SendTradeStatus(info); return; } if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false)) { info.Status = TRADE_STATUS_TOO_FAR_AWAY; SendTradeStatus(info); return; } if (pOther->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); info.Status = TRADE_STATUS_PROPOSED; info.Partner = _player->GetGUID(); pOther->GetSession()->SendTradeStatus(info); }
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { ObjectGuid otherGuid; recvPacket >> otherGuid; if (GetPlayer()->m_trade) return; if (!GetPlayer()->isAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } if (GetPlayer()->IsTaxiFlying()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } Player* pOther = ObjectAccessor::FindPlayer( otherGuid ); if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } if (pOther == GetPlayer() || pOther->m_trade) { SendTradeStatus(TRADE_STATUS_BUSY); return; } if (!pOther->isAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } if (pOther->IsTaxiFlying()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetObjectGuid())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; } if (!sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_TRADE) && pOther->GetTeam() !=_player->GetTeam() ) { SendTradeStatus(TRADE_STATUS_WRONG_FACTION); return; } if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); WorldPacket data(SMSG_TRADE_STATUS, 12); data << uint32(TRADE_STATUS_BEGIN_TRADE); data << ObjectGuid(_player->GetObjectGuid()); pOther->GetSession()->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::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { ObjectGuid ID; recvPacket >> ID; if (GetPlayer()->m_trade) return; TradeStatusInfo info; if (!GetPlayer()->IsAlive()) { info.Status = TRADE_STATUS_YOU_DEAD; SendTradeStatus(info); return; } if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED)) { info.Status = TRADE_STATUS_YOU_STUNNED; SendTradeStatus(info); return; } if (isLogingOut()) { info.Status = TRADE_STATUS_YOU_LOGOUT; SendTradeStatus(info); return; } if (GetPlayer()->IsInFlight()) { info.Status = TRADE_STATUS_TARGET_TO_FAR; SendTradeStatus(info); return; } if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } Player* pOther = ObjectAccessor::FindPlayer(ID); if (!pOther) { info.Status = TRADE_STATUS_NO_TARGET; SendTradeStatus(info); return; } if (pOther == GetPlayer() || pOther->m_trade) { info.Status = TRADE_STATUS_BUSY; SendTradeStatus(info); return; } if (!pOther->IsAlive()) { info.Status = TRADE_STATUS_TARGET_DEAD; SendTradeStatus(info); return; } if (pOther->IsInFlight()) { info.Status = TRADE_STATUS_TARGET_TO_FAR; SendTradeStatus(info); return; } if (pOther->HasUnitState(UNIT_STATE_STUNNED)) { info.Status = TRADE_STATUS_TARGET_STUNNED; SendTradeStatus(info); return; } if (pOther->GetSession()->isLogingOut()) { info.Status = TRADE_STATUS_TARGET_LOGOUT; SendTradeStatus(info); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { info.Status = TRADE_STATUS_IGNORE_YOU; SendTradeStatus(info); return; } if (pOther->GetTeam() != _player->GetTeam() && (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && !GetPlayer()->GetSession()->HasPermission(rbac::RBAC_PERM_ALLOW_TWO_SIDE_TRADE))) { info.Status = TRADE_STATUS_WRONG_FACTION; SendTradeStatus(info); return; } if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false)) { info.Status = TRADE_STATUS_TARGET_TO_FAR; SendTradeStatus(info); return; } if (pOther->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); info.Status = TRADE_STATUS_BEGIN_TRADE; info.TraderGuid = _player->GetGUID(); pOther->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] = { 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::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { ObjectGuid guid; guid[2] = recvPacket.ReadBit(); guid[7] = recvPacket.ReadBit(); guid[0] = recvPacket.ReadBit(); guid[6] = recvPacket.ReadBit(); guid[5] = recvPacket.ReadBit(); guid[3] = recvPacket.ReadBit(); guid[1] = recvPacket.ReadBit(); guid[4] = recvPacket.ReadBit(); recvPacket.ReadByteSeq(guid[2]); recvPacket.ReadByteSeq(guid[6]); recvPacket.ReadByteSeq(guid[4]); recvPacket.ReadByteSeq(guid[7]); recvPacket.ReadByteSeq(guid[0]); recvPacket.ReadByteSeq(guid[1]); recvPacket.ReadByteSeq(guid[3]); recvPacket.ReadByteSeq(guid[5]); if (GetPlayer()->m_trade) return; if (!GetPlayer()->isAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } if (GetPlayer()->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } Player* pOther = ObjectAccessor::FindPlayer(guid); if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } if (pOther == GetPlayer() || pOther->m_trade) { SendTradeStatus(TRADE_STATUS_BUSY); return; } if (!pOther->isAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } if (pOther->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->HasUnitState(UNIT_STATE_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; } if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam()) { SendTradeStatus(TRADE_STATUS_WRONG_FACTION); return; } if (!pOther->IsWithinDistInMap(_player, 10.0f, false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); WorldPacket data(SMSG_TRADE_STATUS, 2+7); data.WriteBit(0); // unk bit, usually 0 data.WriteBits(TRADE_STATUS_BEGIN_TRADE, 5); ObjectGuid playerGuid = _player->GetGUID(); // WTB StartBitStream... data.WriteBit(playerGuid[2]); data.WriteBit(playerGuid[4]); data.WriteBit(playerGuid[6]); data.WriteBit(playerGuid[0]); data.WriteBit(playerGuid[1]); data.WriteBit(playerGuid[3]); data.WriteBit(playerGuid[7]); data.WriteBit(playerGuid[5]); data.WriteByteSeq(playerGuid[5]); data.WriteByteSeq(playerGuid[7]); data.WriteByteSeq(playerGuid[3]); data.WriteByteSeq(playerGuid[6]); data.WriteByteSeq(playerGuid[4]); data.WriteByteSeq(playerGuid[2]); data.WriteByteSeq(playerGuid[0]); data.WriteByteSeq(playerGuid[1]); pOther->GetSession()->SendPacket(&data); }
void WorldSession::SendUpdateTrade() { Item *item = NULL; if( !_player || !_player->pTrader ) return; // reset trade status if (_player->acceptTrade) { _player->acceptTrade = false; SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); } if (_player->pTrader->acceptTrade) { _player->pTrader->acceptTrade = false; _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); } WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size data << (uint8 ) 1; // can be different (only seen 0 and 1) 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) _player->pTrader->tradeGold; // trader gold data << (uint32) 0; // spell casted on lowest slot item for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { item = (_player->pTrader->tradeItems[i] != NULL_SLOT ? _player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i] ) : NULL); data << (uint8) i; // trade slot number, if not specified, then end of packet if(item) { data << (uint32) item->GetProto()->ItemId; // entry // display id data << (uint32) item->GetProto()->DisplayInfoID; // stack count data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT); data << (uint32) 0; // probably gift=1, created_by=0? // gift creator data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT); for (uint8 j = 0; j < 3; ++j) data << (uint32) 0; // enchantment id (permanent/gems?) // creator data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR); data << (uint32) item->GetSpellCharges(); // charges data << (uint32) item->GetItemSuffixFactor(); // SuffixFactor // random properties id data << (uint32) item->GetItemRandomPropertyId(); 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::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { uint64 ID; recvPacket >> ID; if (GetPlayer()->m_trade) return; if (!GetPlayer()->isAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } if (GetPlayer()->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } Player* pOther = ObjectAccessor::FindPlayer(ID); if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } if (pOther == GetPlayer() || pOther->m_trade) { SendTradeStatus(TRADE_STATUS_BUSY); return; } if (!pOther->isAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } if (pOther->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->HasUnitState(UNIT_STATE_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; } if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam()) { SendTradeStatus(TRADE_STATUS_WRONG_FACTION); return; } if (!pOther->IsWithinDistInMap(_player, 10.0f, false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } if (pOther->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); return; } // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); WorldPacket data(SMSG_TRADE_STATUS, 12); data << uint32(TRADE_STATUS_BEGIN_TRADE); data << uint64(_player->GetGUID()); pOther->GetSession()->SendPacket(&data); }
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); } }