TrinityCore
TradeHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "AccountMgr.h"
20#include "Common.h"
21#include "DatabaseEnv.h"
22#include "Item.h"
23#include "Language.h"
24#include "Log.h"
25#include "Map.h"
26#include "ObjectAccessor.h"
27#include "Player.h"
28#include "SocialMgr.h"
29#include "Spell.h"
30#include "SpellMgr.h"
31#include "TradeData.h"
32#include "TradePackets.h"
33#include "World.h"
34
36{
37 info.Clear(); // reuse packet
38 Player* trader = _player->GetTrader();
40 SendPacket(info.Write());
41}
42
44{
45}
46
48{
49}
50
51void WorldSession::SendUpdateTrade(bool trader_data /*= true*/)
52{
53 TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData();
54
56 tradeUpdated.WhichPlayer = trader_data;
57 tradeUpdated.ClientStateIndex = view_trade->GetClientStateIndex();
58 tradeUpdated.CurrentStateIndex = view_trade->GetServerStateIndex();
59 tradeUpdated.Gold = view_trade->GetMoney();
60 tradeUpdated.ProposedEnchantment = view_trade->GetSpell();
61
62 for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
63 {
64 if (Item* item = view_trade->GetItem(TradeSlots(i)))
65 {
67 tradeItem.Slot = i;
68 tradeItem.Item.Initialize(item);
69 tradeItem.StackCount = item->GetCount();
70 tradeItem.GiftCreator = item->GetGiftCreator();
71 if (!item->IsWrapped())
72 {
73 tradeItem.Unwrapped.emplace();
74
75 tradeItem.Unwrapped->EnchantID = item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT);
76 tradeItem.Unwrapped->OnUseEnchantmentID = item->GetEnchantmentId(USE_ENCHANTMENT_SLOT);
77 tradeItem.Unwrapped->Creator = item->GetCreator();
78 tradeItem.Unwrapped->Charges = item->GetSpellCharges();
79 tradeItem.Unwrapped->Lock = item->GetTemplate()->GetLockID() && item->IsLocked();
80 tradeItem.Unwrapped->MaxDurability = item->m_itemData->MaxDurability;
81 tradeItem.Unwrapped->Durability = item->m_itemData->Durability;
82
83 uint8 g = 0;
84 for (UF::SocketedGem const& gemData : item->m_itemData->Gems)
85 {
86 if (gemData.ItemID)
87 {
89 gem.Slot = g;
90 gem.Item.Initialize(&gemData);
91 tradeItem.Unwrapped->Gems.push_back(gem);
92 }
93 ++g;
94 }
95 }
96
97 tradeUpdated.Items.push_back(tradeItem);
98 }
99 }
100
101 SendPacket(tradeUpdated.Write());
102}
103
104//==============================================================
105// transfer the items to the players
106
107void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
108{
109 Player* trader = _player->GetTrader();
110 if (!trader)
111 return;
112
113 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
114 {
115 ItemPosCountVec traderDst;
116 ItemPosCountVec playerDst;
117 bool traderCanTrade = (myItems[i] == nullptr || trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK);
118 bool playerCanTrade = (hisItems[i] == nullptr || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK);
119 if (traderCanTrade && playerCanTrade)
120 {
121 // Ok, if trade item exists and can be stored
122 // If we trade in both directions we had to check, if the trade will work before we actually do it
123 // A roll back is not possible after we stored it
124 if (myItems[i])
125 {
126 // logging
127 TC_LOG_DEBUG("network", "partner storing: {}", myItems[i]->GetGUID().ToString());
129 {
130 sLog->OutCommand(_player->GetSession()->GetAccountId(), "GM {} (Account: {}) trade: {} (Entry: {} Count: {}) to player: {} (Account: {})",
132 myItems[i]->GetTemplate()->GetDefaultLocaleName(), myItems[i]->GetEntry(), myItems[i]->GetCount(),
133 trader->GetName(), trader->GetSession()->GetAccountId());
134 }
135
136 // adjust time (depends on /played)
137 if (myItems[i]->IsBOPTradeable())
138 myItems[i]->SetCreatePlayedTime(trader->GetTotalPlayedTime() - (_player->GetTotalPlayedTime() - myItems[i]->m_itemData->CreatePlayedTime));
139 // store
140 trader->MoveItemToInventory(traderDst, myItems[i], true, true);
141 }
142 if (hisItems[i])
143 {
144 // logging
145 TC_LOG_DEBUG("network", "player storing: {}", hisItems[i]->GetGUID().ToString());
147 {
148 sLog->OutCommand(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) trade: {} (Entry: {} Count: {}) to player: {} (Account: {})",
149 trader->GetName(), trader->GetSession()->GetAccountId(),
150 hisItems[i]->GetTemplate()->GetDefaultLocaleName(), hisItems[i]->GetEntry(), hisItems[i]->GetCount(),
152 }
153
154 // adjust time (depends on /played)
155 if (hisItems[i]->IsBOPTradeable())
156 hisItems[i]->SetCreatePlayedTime(_player->GetTotalPlayedTime() - (trader->GetTotalPlayedTime() - hisItems[i]->m_itemData->CreatePlayedTime));
157 // store
158 _player->MoveItemToInventory(playerDst, hisItems[i], true, true);
159 }
160 }
161 else
162 {
163 // in case of fatal error log error message
164 // return the already removed items to the original owner
165 if (myItems[i])
166 {
167 if (!traderCanTrade)
168 TC_LOG_ERROR("network", "trader can't store item: {}", myItems[i]->GetGUID().ToString());
169 if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK)
170 _player->MoveItemToInventory(playerDst, myItems[i], true, true);
171 else
172 TC_LOG_ERROR("network", "player can't take item back: {}", myItems[i]->GetGUID().ToString());
173 }
174 // return the already removed items to the original owner
175 if (hisItems[i])
176 {
177 if (!playerCanTrade)
178 TC_LOG_ERROR("network", "player can't store item: {}", hisItems[i]->GetGUID().ToString());
179 if (trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK)
180 trader->MoveItemToInventory(traderDst, hisItems[i], true, true);
181 else
182 TC_LOG_ERROR("network", "trader can't take item back: {}", hisItems[i]->GetGUID().ToString());
183 }
184 }
185 }
186}
187
188//==============================================================
189
190static void setAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade, Item* *myItems, Item* *hisItems)
191{
192 myTrade->SetInAcceptProcess(true);
193 hisTrade->SetInAcceptProcess(true);
194
195 // store items in local list and set 'in-trade' flag
196 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
197 {
198 if (Item* item = myTrade->GetItem(TradeSlots(i)))
199 {
200 TC_LOG_DEBUG("network", "player trade item {} bag: {} slot: {}", item->GetGUID().ToString(), item->GetBagSlot(), item->GetSlot());
201 //Can return nullptr
202 myItems[i] = item;
203 myItems[i]->SetInTrade();
204 }
205
206 if (Item* item = hisTrade->GetItem(TradeSlots(i)))
207 {
208 TC_LOG_DEBUG("network", "partner trade item {} bag: {} slot: {}", item->GetGUID().ToString(), item->GetBagSlot(), item->GetSlot());
209 hisItems[i] = item;
210 hisItems[i]->SetInTrade();
211 }
212 }
213}
214
215static void clearAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade)
216{
217 myTrade->SetInAcceptProcess(false);
218 hisTrade->SetInAcceptProcess(false);
219}
220
221static void clearAcceptTradeMode(Item* *myItems, Item* *hisItems)
222{
223 // clear 'in-trade' flag
224 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
225 {
226 if (myItems[i])
227 myItems[i]->SetInTrade(false);
228 if (hisItems[i])
229 hisItems[i]->SetInTrade(false);
230 }
231}
232
234{
235 TradeData* my_trade = _player->m_trade;
236 if (!my_trade)
237 return;
238
239 Player* trader = my_trade->GetTrader();
240
241 TradeData* his_trade = trader->m_trade;
242 if (!his_trade)
243 return;
244
245 Item* myItems[TRADE_SLOT_TRADED_COUNT] = { };
246 Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { };
247
248 // set before checks for propertly undo at problems (it already set in to client)
249 my_trade->SetAccepted(true);
250
252 if (his_trade->GetServerStateIndex() != acceptTrade.StateIndex)
253 {
255 SendTradeStatus(info);
256 my_trade->SetAccepted(false);
257 return;
258 }
259
260 if (!_player->IsWithinDistInMap(trader, TRADE_DISTANCE, false))
261 {
263 SendTradeStatus(info);
264 my_trade->SetAccepted(false);
265 return;
266 }
267
268 // not accept case incorrect money amount
269 if (!_player->HasEnoughMoney(my_trade->GetMoney()))
270 {
273 SendTradeStatus(info);
274 my_trade->SetAccepted(false, true);
275 return;
276 }
277
278 // not accept case incorrect money amount
279 if (!trader->HasEnoughMoney(his_trade->GetMoney()))
280 {
283 trader->GetSession()->SendTradeStatus(info);
284 his_trade->SetAccepted(false, true);
285 return;
286 }
287
288 if (_player->GetMoney() > MAX_MONEY_AMOUNT - his_trade->GetMoney())
289 {
292 SendTradeStatus(info);
293 my_trade->SetAccepted(false, true);
294 return;
295 }
296
297 if (trader->GetMoney() > MAX_MONEY_AMOUNT - my_trade->GetMoney())
298 {
301 trader->GetSession()->SendTradeStatus(info);
302 his_trade->SetAccepted(false, true);
303 return;
304 }
305
306 // not accept if some items now can't be trade (cheating)
307 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
308 {
309 if (Item* item = my_trade->GetItem(TradeSlots(i)))
310 {
311 if (!item->CanBeTraded(false, true))
312 {
314 SendTradeStatus(info);
315 return;
316 }
317
318 if (item->IsBindedNotWith(trader))
319 {
322 SendTradeStatus(info);
323 return;
324 }
325 }
326
327 if (Item* item = his_trade->GetItem(TradeSlots(i)))
328 {
329 if (!item->CanBeTraded(false, true))
330 {
332 SendTradeStatus(info);
333 return;
334 }
335 //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)
336 //{
337 // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE);
338 // his_trade->SetAccepted(false, true);
339 // return;
340 //}
341 }
342 }
343
344 if (his_trade->IsAccepted())
345 {
346 setAcceptTradeMode(my_trade, his_trade, myItems, hisItems);
347
348 Spell* my_spell = nullptr;
349 SpellCastTargets my_targets;
350
351 Spell* his_spell = nullptr;
352 SpellCastTargets his_targets;
353
354 // not accept if spell can't be cast now (cheating)
355 if (uint32 my_spell_id = my_trade->GetSpell())
356 {
357 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id, _player->GetMap()->GetDifficultyID());
358 Item* castItem = my_trade->GetSpellCastItem();
359
360 if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) ||
361 (my_trade->HasSpellCastItem() && !castItem))
362 {
363 clearAcceptTradeMode(my_trade, his_trade);
364 clearAcceptTradeMode(myItems, hisItems);
365
366 my_trade->SetSpell(0);
367 return;
368 }
369
370 my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK);
371 my_spell->m_CastItem = castItem;
372 my_targets.SetTradeItemTarget(_player);
373 my_spell->m_targets = my_targets;
374
375 SpellCastResult res = my_spell->CheckCast(true);
376 if (res != SPELL_CAST_OK)
377 {
378 my_spell->SendCastResult(res);
379
380 clearAcceptTradeMode(my_trade, his_trade);
381 clearAcceptTradeMode(myItems, hisItems);
382
383 delete my_spell;
384 my_trade->SetSpell(0);
385 return;
386 }
387 }
388
389 // not accept if spell can't be cast now (cheating)
390 if (uint32 his_spell_id = his_trade->GetSpell())
391 {
392 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id, trader->GetMap()->GetDifficultyID());
393 Item* castItem = his_trade->GetSpellCastItem();
394
395 if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem))
396 {
397 delete my_spell;
398 his_trade->SetSpell(0);
399
400 clearAcceptTradeMode(my_trade, his_trade);
401 clearAcceptTradeMode(myItems, hisItems);
402 return;
403 }
404
405 his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK);
406 his_spell->m_CastItem = castItem;
407 his_targets.SetTradeItemTarget(trader);
408 his_spell->m_targets = his_targets;
409
410 SpellCastResult res = his_spell->CheckCast(true);
411 if (res != SPELL_CAST_OK)
412 {
413 his_spell->SendCastResult(res);
414
415 clearAcceptTradeMode(my_trade, his_trade);
416 clearAcceptTradeMode(myItems, hisItems);
417
418 delete my_spell;
419 delete his_spell;
420
421 his_trade->SetSpell(0);
422 return;
423 }
424 }
425
426 // inform partner client
428 trader->GetSession()->SendTradeStatus(info);
429
430 // test if item will fit in each inventory
431 WorldPackets::Trade::TradeStatus myCanCompleteInfo, hisCanCompleteInfo;
432 hisCanCompleteInfo.BagResult = trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT, &hisCanCompleteInfo.ItemID);
433 myCanCompleteInfo.BagResult = _player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT, &myCanCompleteInfo.ItemID);
434
435 clearAcceptTradeMode(myItems, hisItems);
436
437 // in case of missing space report error
438 if (myCanCompleteInfo.BagResult != EQUIP_ERR_OK)
439 {
440 clearAcceptTradeMode(my_trade, his_trade);
441
442 myCanCompleteInfo.Status = TRADE_STATUS_FAILED;
443 trader->GetSession()->SendTradeStatus(myCanCompleteInfo);
444 myCanCompleteInfo.FailureForYou = true;
445 SendTradeStatus(myCanCompleteInfo);
446 my_trade->SetAccepted(false);
447 his_trade->SetAccepted(false);
448 delete my_spell;
449 delete his_spell;
450 return;
451 }
452 else if (hisCanCompleteInfo.BagResult != EQUIP_ERR_OK)
453 {
454 clearAcceptTradeMode(my_trade, his_trade);
455
456 hisCanCompleteInfo.Status = TRADE_STATUS_FAILED;
457 SendTradeStatus(hisCanCompleteInfo);
458 hisCanCompleteInfo.FailureForYou = true;
459 trader->GetSession()->SendTradeStatus(hisCanCompleteInfo);
460 my_trade->SetAccepted(false);
461 his_trade->SetAccepted(false);
462 delete my_spell;
463 delete his_spell;
464 return;
465 }
466
467 // execute trade: 1. remove
468 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
469 {
470 if (myItems[i])
471 {
472 myItems[i]->SetGiftCreator(_player->GetGUID());
473 _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true);
474 }
475 if (hisItems[i])
476 {
477 hisItems[i]->SetGiftCreator(trader->GetGUID());
478 trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true);
479 }
480 }
481
482 // execute trade: 2. store
483 moveItems(myItems, hisItems);
484
485 // logging money
487 {
488 if (my_trade->GetMoney() > 0)
489 {
490 sLog->OutCommand(_player->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
492 my_trade->GetMoney(),
493 trader->GetName(), trader->GetSession()->GetAccountId());
494 }
495
496 if (his_trade->GetMoney() > 0)
497 {
498 sLog->OutCommand(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
499 trader->GetName(), trader->GetSession()->GetAccountId(),
500 his_trade->GetMoney(),
502 }
503 }
504
505 // update money
506 _player->ModifyMoney(-int64(my_trade->GetMoney()));
507 _player->ModifyMoney(his_trade->GetMoney());
508 trader->ModifyMoney(-int64(his_trade->GetMoney()));
509 trader->ModifyMoney(my_trade->GetMoney());
510
511 if (my_spell)
512 my_spell->prepare(my_targets);
513
514 if (his_spell)
515 his_spell->prepare(his_targets);
516
517 // cleanup
518 clearAcceptTradeMode(my_trade, his_trade);
519 delete _player->m_trade;
520 _player->m_trade = nullptr;
521 delete trader->m_trade;
522 trader->m_trade = nullptr;
523
524 // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
525 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
527 trader->SaveInventoryAndGoldToDB(trans);
528 CharacterDatabase.CommitTransaction(trans);
529
531 trader->GetSession()->SendTradeStatus(info);
532 SendTradeStatus(info);
533 }
534 else
535 {
537 trader->GetSession()->SendTradeStatus(info);
538 }
539}
540
542{
543 TradeData* my_trade = _player->GetTradeData();
544 if (!my_trade)
545 return;
546
547 my_trade->SetAccepted(false, true);
548}
549
551{
552 TradeData* my_trade = _player->m_trade;
553 if (!my_trade)
554 return;
555
558 my_trade->GetTrader()->GetSession()->SendTradeStatus(info);
559 SendTradeStatus(info);
560}
561
563{
565 return;
566
569 SendTradeStatus(info);
570}
571
573{
574 // sent also after LOGOUT COMPLETE
575 if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
576 _player->TradeCancel(true);
577}
578
580{
581 if (GetPlayer()->m_trade)
582 return;
583
585 if (!GetPlayer()->IsAlive())
586 {
588 SendTradeStatus(info);
589 return;
590 }
591
592 if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED))
593 {
595 SendTradeStatus(info);
596 return;
597 }
598
599 if (isLogingOut())
600 {
602 SendTradeStatus(info);
603 return;
604 }
605
606 if (GetPlayer()->IsInFlight())
607 {
609 SendTradeStatus(info);
610 return;
611 }
612
613 if (GetPlayer()->GetLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ))
614 {
617 SendTradeStatus(info);
618 return;
619 }
620
621 Player* pOther = ObjectAccessor::FindPlayer(initiateTrade.Guid);
622 if (!pOther)
623 {
625 SendTradeStatus(info);
626 return;
627 }
628
629 if (pOther == GetPlayer() || pOther->m_trade)
630 {
632 SendTradeStatus(info);
633 return;
634 }
635
636 if (!pOther->IsAlive())
637 {
639 SendTradeStatus(info);
640 return;
641 }
642
643 if (pOther->IsInFlight())
644 {
646 SendTradeStatus(info);
647 return;
648 }
649
650 if (pOther->HasUnitState(UNIT_STATE_STUNNED))
651 {
653 SendTradeStatus(info);
654 return;
655 }
656
657 if (pOther->GetSession()->isLogingOut())
658 {
660 SendTradeStatus(info);
661 return;
662 }
663
664 if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUID(), GetPlayer()->GetSession()->GetAccountGUID()))
665 {
667 SendTradeStatus(info);
668 return;
669 }
670
671 if ((pOther->GetTeam() != _player->GetTeam() ||
674 (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) &&
676 {
678 SendTradeStatus(info);
679 return;
680 }
681
682 if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false))
683 {
685 SendTradeStatus(info);
686 return;
687 }
688
689 if (pOther->GetLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ))
690 {
693 SendTradeStatus(info);
694 return;
695 }
696
697 // OK start trade
698 _player->m_trade = new TradeData(_player, pOther);
699 pOther->m_trade = new TradeData(pOther, _player);
700
702 info.Partner = _player->GetGUID();
703 pOther->GetSession()->SendTradeStatus(info);
704}
705
707{
708 TradeData* my_trade = _player->GetTradeData();
709 if (!my_trade)
710 return;
711
712 my_trade->UpdateClientStateIndex();
713 my_trade->SetMoney(setTradeGold.Coinage);
714}
715
717{
718 TradeData* my_trade = _player->GetTradeData();
719 if (!my_trade)
720 return;
721
723 // invalid slot number
724 if (setTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
725 {
727 SendTradeStatus(info);
728 return;
729 }
730
731 // check cheating, can't fail with correct client operations
732 Item* item = _player->GetItemByPos(setTradeItem.PackSlot, setTradeItem.ItemSlotInPack);
733 if (!item || (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true)))
734 {
736 SendTradeStatus(info);
737 return;
738 }
739
740 ObjectGuid iGUID = item->GetGUID();
741
742 // prevent place single item into many trade slots using cheating and client bugs
743 if (my_trade->HasItem(iGUID))
744 {
745 // cheating attempt
747 SendTradeStatus(info);
748 return;
749 }
750
751 my_trade->UpdateClientStateIndex();
752
753 if (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && item->IsBindedNotWith(my_trade->GetTrader()))
754 {
756 info.TradeSlot = setTradeItem.TradeSlot;
757 SendTradeStatus(info);
758 return;
759 }
760
761 my_trade->SetItem(TradeSlots(setTradeItem.TradeSlot), item);
762}
763
765{
766 TradeData* my_trade = _player->m_trade;
767 if (!my_trade)
768 return;
769
770 my_trade->UpdateClientStateIndex();
771
772 // invalid slot number
773 if (clearTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
774 return;
775
776 my_trade->SetItem(TradeSlots(clearTradeItem.TradeSlot), nullptr);
777}
778
780{
781}
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
uint32_t uint32
Definition: Define.h:142
@ PERM_ENCHANTMENT_SLOT
Definition: ItemDefines.h:179
@ USE_ENCHANTMENT_SLOT
Definition: ItemDefines.h:186
@ EQUIP_ERR_TOO_MUCH_GOLD
Definition: ItemDefines.h:104
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
@ EQUIP_ERR_NOT_ENOUGH_MONEY
Definition: ItemDefines.h:56
@ EQUIP_ERR_TRADE_BOUND_ITEM
Definition: ItemDefines.h:106
@ LANG_TRADE_OTHER_REQ
Definition: Language.h:1164
@ LANG_TRADE_REQ
Definition: Language.h:1163
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sLog
Definition: Log.h:130
#define TRADE_DISTANCE
Definition: ObjectDefines.h:27
uint64 const MAX_MONEY_AMOUNT
Definition: Player.cpp:158
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
@ PLAYER_FLAGS_EX_MERCENARY_MODE
Definition: Player.h:467
@ TRADE_STATUS_CANCELLED
@ TRADE_STATUS_FAILED
@ TRADE_STATUS_NOT_ON_TAPLIST
@ TRADE_STATUS_PROPOSED
@ TRADE_STATUS_TARGET_DEAD
@ TRADE_STATUS_INITIATED
@ TRADE_STATUS_NO_TARGET
@ TRADE_STATUS_STATE_CHANGED
@ TRADE_STATUS_ACCEPTED
@ TRADE_STATUS_DEAD
@ TRADE_STATUS_LOGGING_OUT
@ TRADE_STATUS_TOO_FAR_AWAY
@ TRADE_STATUS_TARGET_STUNNED
@ TRADE_STATUS_PLAYER_IGNORED
@ TRADE_STATUS_COMPLETE
@ TRADE_STATUS_STUNNED
@ TRADE_STATUS_TARGET_LOGGING_OUT
@ TRADE_STATUS_WRONG_FACTION
@ TRADE_STATUS_PLAYER_BUSY
SpellCastResult
@ SPELL_CAST_OK
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
#define sSpellMgr
Definition: SpellMgr.h:849
TradeSlots
Definition: TradeData.h:24
@ TRADE_SLOT_COUNT
Definition: TradeData.h:25
@ TRADE_SLOT_TRADED_COUNT
Definition: TradeData.h:26
@ TRADE_SLOT_NONTRADED
Definition: TradeData.h:27
static void setAcceptTradeMode(TradeData *myTrade, TradeData *hisTrade, Item **myItems, Item **hisItems)
static void clearAcceptTradeMode(TradeData *myTrade, TradeData *hisTrade)
@ UNIT_STATE_STUNNED
Definition: Unit.h:258
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
Definition: Item.h:170
bool CanBeTraded(bool mail=false, bool trade=false) const
Definition: Item.cpp:1250
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1141
bool IsBindedNotWith(Player const *player) const
Definition: Item.cpp:1672
void SetCreatePlayedTime(uint32 createPlayedTime)
Definition: Item.h:311
uint32 GetCount() const
Definition: Item.h:273
void SetGiftCreator(ObjectGuid guid)
Definition: Item.h:195
UF::UpdateField< UF::ItemData, 0, TYPEID_ITEM > m_itemData
Definition: Item.h:449
void SetInTrade(bool b=true)
Definition: Item.h:261
Difficulty GetDifficultyID() const
Definition: Map.h:324
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
bool HasIgnore(ObjectGuid const &ignoreGuid, ObjectGuid const &ignoreAccountGuid)
Definition: SocialMgr.cpp:189
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
bool HasPlayerFlagEx(PlayerFlagsEx flags) const
Definition: Player.h:2742
PlayerSocial * GetSocial() const
Definition: Player.h:1163
uint32 GetTotalPlayedTime() const
Definition: Player.h:1214
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition: Player.cpp:10037
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20364
InventoryResult CanStoreItems(Item **items, int count, uint32 *offendingItemId) const
Definition: Player.cpp:10668
TradeData * m_trade
Definition: Player.h:3077
WorldSession * GetSession() const
Definition: Player.h:2101
Item * GetItemByPos(uint16 pos) const
Definition: Player.cpp:9582
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
Definition: Player.cpp:12134
void MoveItemToInventory(ItemPosCountVec const &dest, Item *pItem, bool update, bool in_characterInventoryDB=false)
Definition: Player.cpp:12152
Player * GetTrader() const
Definition: Player.cpp:25150
TradeData * GetTradeData() const
Definition: Player.h:1498
uint64 GetMoney() const
Definition: Player.h:1738
void TradeCancel(bool sendback)
Definition: Player.cpp:13376
Team GetTeam() const
Definition: Player.h:2235
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
void SetTradeItemTarget(Player *caster)
Definition: Spell.cpp:306
Definition: Spell.h:255
SpellCastTargets m_targets
Definition: Spell.h:607
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, SpellCastVisual spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, int32 *param1=nullptr, int32 *param2=nullptr)
Definition: Spell.cpp:4643
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition: Spell.cpp:3426
SpellCastResult CheckCast(bool strict, int32 *param1=nullptr, int32 *param2=nullptr)
Definition: Spell.cpp:5641
Item * m_CastItem
Definition: Spell.h:564
Item * GetSpellCastItem() const
Definition: TradeData.cpp:53
bool HasSpellCastItem() const
Definition: TradeData.h:53
void SetSpell(uint32 spell_id, Item *castItem=nullptr)
Definition: TradeData.cpp:84
void SetMoney(uint64 money)
Definition: TradeData.cpp:103
Player * GetTrader() const
Definition: TradeData.h:41
bool HasItem(ObjectGuid itemGuid) const
Definition: TradeData.cpp:35
uint32 GetClientStateIndex() const
Definition: TradeData.h:64
void SetItem(TradeSlots slot, Item *item, bool update=false)
Definition: TradeData.cpp:58
void SetInAcceptProcess(bool state)
Definition: TradeData.h:62
void UpdateClientStateIndex()
Definition: TradeData.h:65
void SetAccepted(bool state, bool forTrader=false)
Definition: TradeData.cpp:135
Item * GetItem(TradeSlots slot) const
Definition: TradeData.cpp:30
bool IsAccepted() const
Definition: TradeData.h:58
uint64 GetMoney() const
Definition: TradeData.h:55
TradeData * GetTraderData() const
Definition: TradeData.cpp:25
uint32 GetSpell() const
Definition: TradeData.h:49
uint32 GetServerStateIndex() const
Definition: TradeData.h:67
bool IsAlive() const
Definition: Unit.h:1164
bool IsInFlight() const
Definition: Unit.h:1012
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
uint8 GetLevel() const
Definition: Unit.h:746
Map * GetMap() const
Definition: Object.h:624
std::string const & GetName() const
Definition: Object.h:555
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< TradeItem > Items
Definition: TradePackets.h:186
void HandleInitiateTradeOpcode(WorldPackets::Trade::InitiateTrade &initiateTrade)
char const * GetTrinityString(uint32 entry) const
void HandleBeginTradeOpcode(WorldPackets::Trade::BeginTrade &beginTrade)
void moveItems(Item *myItems[], Item *hisItems[])
void HandleClearTradeItemOpcode(WorldPackets::Trade::ClearTradeItem &clearTradeItem)
void SendNotification(char const *format,...) ATTR_PRINTF(2
bool isLogingOut() const
Is the user engaged in a log out process?
void HandleSetTradeGoldOpcode(WorldPackets::Trade::SetTradeGold &setTradeGold)
bool PlayerRecentlyLoggedOut() const
Definition: WorldSession.h:972
bool PlayerLogout() const
Definition: WorldSession.h:970
ObjectGuid GetAccountGUID() const
Player * GetPlayer() const
void HandleBusyTradeOpcode(WorldPackets::Trade::BusyTrade &busyTrade)
void HandleCancelTradeOpcode(WorldPackets::Trade::CancelTrade &cancelTrade)
void HandleAcceptTradeOpcode(WorldPackets::Trade::AcceptTrade &acceptTrade)
void SendTradeStatus(WorldPackets::Trade::TradeStatus &status)
bool HasPermission(uint32 permissionId)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetBattlenetAccountId() const
uint32 GetAccountId() const
Player * _player
void HandleIgnoreTradeOpcode(WorldPackets::Trade::IgnoreTrade &ignoreTrade)
void HandleUnacceptTradeOpcode(WorldPackets::Trade::UnacceptTrade &unacceptTrade)
void HandleSetTradeCurrencyOpcode(WorldPackets::Trade::SetTradeCurrency &setTradeCurrency)
void SendUpdateTrade(bool trader_data=true)
void SendCancelTrade()
void HandleSetTradeItemOpcode(WorldPackets::Trade::SetTradeItem &setTradeItem)
#define sWorld
Definition: World.h:931
@ CONFIG_TRADE_LEVEL_REQ
Definition: World.h:327
@ CONFIG_ALLOW_TWO_SIDE_TRADE
Definition: World.h:114
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
std::string ToString(Type &&val, Params &&... params)
@ RBAC_PERM_ALLOW_TWO_SIDE_TRADE
Definition: RBAC.h:104
@ RBAC_PERM_LOG_GM_TRADE
Definition: RBAC.h:64
char const * GetDefaultLocaleName() const
UpdateField< int32, 0, 1 > ItemID
Definition: UpdateFields.h:109
void Initialize(::Item const *item)
Optional< UnwrappedTradeItem > Unwrapped
Definition: TradePackets.h:172