TrinityCore
Loading...
Searching...
No Matches
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
46
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]->m_itemData->CreatePlayedTime)
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]->m_itemData->CreatePlayedTime)
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 if (Player::IsAccountBankPos(item->GetSlot(), item->GetBagSlot()))
327 {
330 SendTradeStatus(info);
331 return;
332 }
333 }
334
335 if (Item* item = his_trade->GetItem(TradeSlots(i)))
336 {
337 if (!item->CanBeTraded(false, true))
338 {
340 SendTradeStatus(info);
341 return;
342 }
343 //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)
344 //{
345 // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE);
346 // his_trade->SetAccepted(false, true);
347 // return;
348 //}
349
350 if (Player::IsAccountBankPos(item->GetSlot(), item->GetBagSlot()))
351 {
354 SendTradeStatus(info);
355 return;
356 }
357 }
358 }
359
360 if (his_trade->IsAccepted())
361 {
362 setAcceptTradeMode(my_trade, his_trade, myItems, hisItems);
363
364 Spell* my_spell = nullptr;
365 SpellCastTargets my_targets;
366
367 Spell* his_spell = nullptr;
368 SpellCastTargets his_targets;
369
370 // not accept if spell can't be cast now (cheating)
371 if (uint32 my_spell_id = my_trade->GetSpell())
372 {
373 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id, _player->GetMap()->GetDifficultyID());
374 Item* castItem = my_trade->GetSpellCastItem();
375
376 if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) ||
377 (my_trade->HasSpellCastItem() && !castItem))
378 {
379 clearAcceptTradeMode(my_trade, his_trade);
380 clearAcceptTradeMode(myItems, hisItems);
381
382 my_trade->SetSpell(0);
383 return;
384 }
385
386 my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK);
387 my_spell->m_CastItem = castItem;
388 my_targets.SetTradeItemTarget(_player);
389 my_spell->m_targets = my_targets;
390
391 SpellCastResult res = my_spell->CheckCast(true);
392 if (res != SPELL_CAST_OK)
393 {
394 my_spell->SendCastResult(res);
395
396 clearAcceptTradeMode(my_trade, his_trade);
397 clearAcceptTradeMode(myItems, hisItems);
398
399 delete my_spell;
400 my_trade->SetSpell(0);
401 return;
402 }
403 }
404
405 // not accept if spell can't be cast now (cheating)
406 if (uint32 his_spell_id = his_trade->GetSpell())
407 {
408 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id, trader->GetMap()->GetDifficultyID());
409 Item* castItem = his_trade->GetSpellCastItem();
410
411 if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem))
412 {
413 delete my_spell;
414 his_trade->SetSpell(0);
415
416 clearAcceptTradeMode(my_trade, his_trade);
417 clearAcceptTradeMode(myItems, hisItems);
418 return;
419 }
420
421 his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK);
422 his_spell->m_CastItem = castItem;
423 his_targets.SetTradeItemTarget(trader);
424 his_spell->m_targets = his_targets;
425
426 SpellCastResult res = his_spell->CheckCast(true);
427 if (res != SPELL_CAST_OK)
428 {
429 his_spell->SendCastResult(res);
430
431 clearAcceptTradeMode(my_trade, his_trade);
432 clearAcceptTradeMode(myItems, hisItems);
433
434 delete my_spell;
435 delete his_spell;
436
437 his_trade->SetSpell(0);
438 return;
439 }
440 }
441
442 // inform partner client
444 trader->GetSession()->SendTradeStatus(info);
445
446 // test if item will fit in each inventory
447 WorldPackets::Trade::TradeStatus myCanCompleteInfo, hisCanCompleteInfo;
448 hisCanCompleteInfo.BagResult = trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT, &hisCanCompleteInfo.ItemID);
449 myCanCompleteInfo.BagResult = _player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT, &myCanCompleteInfo.ItemID);
450
451 clearAcceptTradeMode(myItems, hisItems);
452
453 // in case of missing space report error
454 if (myCanCompleteInfo.BagResult != EQUIP_ERR_OK)
455 {
456 clearAcceptTradeMode(my_trade, his_trade);
457
458 myCanCompleteInfo.Status = TRADE_STATUS_FAILED;
459 trader->GetSession()->SendTradeStatus(myCanCompleteInfo);
460 myCanCompleteInfo.FailureForYou = true;
461 SendTradeStatus(myCanCompleteInfo);
462 my_trade->SetAccepted(false);
463 his_trade->SetAccepted(false);
464 delete my_spell;
465 delete his_spell;
466 return;
467 }
468 else if (hisCanCompleteInfo.BagResult != EQUIP_ERR_OK)
469 {
470 clearAcceptTradeMode(my_trade, his_trade);
471
472 hisCanCompleteInfo.Status = TRADE_STATUS_FAILED;
473 SendTradeStatus(hisCanCompleteInfo);
474 hisCanCompleteInfo.FailureForYou = true;
475 trader->GetSession()->SendTradeStatus(hisCanCompleteInfo);
476 my_trade->SetAccepted(false);
477 his_trade->SetAccepted(false);
478 delete my_spell;
479 delete his_spell;
480 return;
481 }
482
483 // execute trade: 1. remove
484 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
485 {
486 if (myItems[i])
487 {
488 myItems[i]->SetGiftCreator(_player->GetGUID());
489 _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true);
490 }
491 if (hisItems[i])
492 {
493 hisItems[i]->SetGiftCreator(trader->GetGUID());
494 trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true);
495 }
496 }
497
498 // execute trade: 2. store
499 moveItems(myItems, hisItems);
500
501 // logging money
503 {
504 if (my_trade->GetMoney() > 0)
505 {
506 sLog->OutCommand(_player->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
508 my_trade->GetMoney(),
509 trader->GetName(), trader->GetSession()->GetAccountId());
510 }
511
512 if (his_trade->GetMoney() > 0)
513 {
514 sLog->OutCommand(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
515 trader->GetName(), trader->GetSession()->GetAccountId(),
516 his_trade->GetMoney(),
518 }
519 }
520
521 // update money
522 _player->ModifyMoney(-int64(my_trade->GetMoney()));
523 _player->ModifyMoney(his_trade->GetMoney());
524 trader->ModifyMoney(-int64(his_trade->GetMoney()));
525 trader->ModifyMoney(my_trade->GetMoney());
526
527 if (my_spell)
528 my_spell->prepare(my_targets);
529
530 if (his_spell)
531 his_spell->prepare(his_targets);
532
533 // cleanup
534 clearAcceptTradeMode(my_trade, his_trade);
535 delete _player->m_trade;
536 _player->m_trade = nullptr;
537 delete trader->m_trade;
538 trader->m_trade = nullptr;
539
540 // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
541 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
543 trader->SaveInventoryAndGoldToDB(trans);
544 CharacterDatabase.CommitTransaction(trans);
545
547 trader->GetSession()->SendTradeStatus(info);
548 SendTradeStatus(info);
549 }
550 else
551 {
553 trader->GetSession()->SendTradeStatus(info);
554 }
555}
556
558{
559 TradeData* my_trade = _player->GetTradeData();
560 if (!my_trade)
561 return;
562
563 my_trade->SetAccepted(false, true);
564}
565
567{
568 TradeData* my_trade = _player->m_trade;
569 if (!my_trade)
570 return;
571
574 my_trade->GetTrader()->GetSession()->SendTradeStatus(info);
575 SendTradeStatus(info);
576}
577
587
589{
590 // sent also after LOGOUT COMPLETE
591 if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
592 _player->TradeCancel(true);
593}
594
596{
597 if (GetPlayer()->m_trade)
598 return;
599
601 if (!GetPlayer()->IsAlive())
602 {
604 SendTradeStatus(info);
605 return;
606 }
607
608 if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED))
609 {
611 SendTradeStatus(info);
612 return;
613 }
614
615 if (isLogingOut())
616 {
618 SendTradeStatus(info);
619 return;
620 }
621
622 if (GetPlayer()->IsInFlight())
623 {
625 SendTradeStatus(info);
626 return;
627 }
628
629 if (GetPlayer()->GetLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ))
630 {
633 SendTradeStatus(info);
634 return;
635 }
636
637 Player* pOther = ObjectAccessor::FindPlayer(initiateTrade.Guid);
638 if (!pOther)
639 {
641 SendTradeStatus(info);
642 return;
643 }
644
645 if (pOther == GetPlayer() || pOther->m_trade)
646 {
648 SendTradeStatus(info);
649 return;
650 }
651
652 if (!pOther->IsAlive())
653 {
655 SendTradeStatus(info);
656 return;
657 }
658
659 if (pOther->IsInFlight())
660 {
662 SendTradeStatus(info);
663 return;
664 }
665
666 if (pOther->HasUnitState(UNIT_STATE_STUNNED))
667 {
669 SendTradeStatus(info);
670 return;
671 }
672
673 if (pOther->GetSession()->isLogingOut())
674 {
676 SendTradeStatus(info);
677 return;
678 }
679
680 if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUID(), GetPlayer()->GetSession()->GetAccountGUID()))
681 {
683 SendTradeStatus(info);
684 return;
685 }
686
687 if ((pOther->GetTeam() != _player->GetTeam() ||
690 (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) &&
692 {
694 SendTradeStatus(info);
695 return;
696 }
697
698 if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false))
699 {
701 SendTradeStatus(info);
702 return;
703 }
704
705 if (pOther->GetLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ))
706 {
709 SendTradeStatus(info);
710 return;
711 }
712
713 // OK start trade
714 _player->m_trade = new TradeData(_player, pOther);
715 pOther->m_trade = new TradeData(pOther, _player);
716
718 info.Partner = _player->GetGUID();
719 pOther->GetSession()->SendTradeStatus(info);
720}
721
723{
724 TradeData* my_trade = _player->GetTradeData();
725 if (!my_trade)
726 return;
727
728 my_trade->UpdateClientStateIndex();
729 my_trade->SetMoney(setTradeGold.Coinage);
730}
731
733{
734 TradeData* my_trade = _player->GetTradeData();
735 if (!my_trade)
736 return;
737
739 // invalid slot number
740 if (setTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
741 {
743 SendTradeStatus(info);
744 return;
745 }
746
747 // check cheating, can't fail with correct client operations
748 Item* item = _player->GetItemByPos(setTradeItem.PackSlot, setTradeItem.ItemSlotInPack);
749 if (!item || (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true)))
750 {
752 SendTradeStatus(info);
753 return;
754 }
755
756 ObjectGuid iGUID = item->GetGUID();
757
758 // prevent place single item into many trade slots using cheating and client bugs
759 if (my_trade->HasItem(iGUID))
760 {
761 // cheating attempt
763 SendTradeStatus(info);
764 return;
765 }
766
767 my_trade->UpdateClientStateIndex();
768
769 if (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && item->IsBindedNotWith(my_trade->GetTrader()))
770 {
772 info.TradeSlot = setTradeItem.TradeSlot;
773 SendTradeStatus(info);
774 return;
775 }
776
777 my_trade->SetItem(TradeSlots(setTradeItem.TradeSlot), item);
778}
779
781{
782 TradeData* my_trade = _player->m_trade;
783 if (!my_trade)
784 return;
785
786 my_trade->UpdateClientStateIndex();
787
788 // invalid slot number
789 if (clearTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
790 return;
791
792 my_trade->SetItem(TradeSlots(clearTradeItem.TradeSlot), nullptr);
793}
794
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
uint32_t uint32
Definition Define.h:154
@ PERM_ENCHANTMENT_SLOT
@ USE_ENCHANTMENT_SLOT
@ EQUIP_ERR_TOO_MUCH_GOLD
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ EQUIP_ERR_NOT_ENOUGH_MONEY
Definition ItemDefines.h:56
@ EQUIP_ERR_CANT_TRADE_ACCOUNT_ITEM
@ EQUIP_ERR_TRADE_BOUND_ITEM
@ LANG_TRADE_OTHER_REQ
Definition Language.h:1173
@ LANG_TRADE_REQ
Definition Language.h:1172
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define sLog
Definition Log.h:156
#define TRADE_DISTANCE
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:841
@ PLAYER_FLAGS_EX_MERCENARY_MODE
Definition Player.h:559
constexpr uint64 MAX_MONEY_AMOUNT
Definition Player.h:1044
@ 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.
#define sSpellMgr
Definition SpellMgr.h:812
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:264
@ NULL_BAG
Definition Unit.h:63
@ NULL_SLOT
Definition Unit.h:64
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
Definition Item.h:179
bool CanBeTraded(bool mail=false, bool trade=false) const
Definition Item.cpp:1342
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
UF::UpdateField< UF::ItemData, uint32(WowCS::EntityFragment::CGObject), TYPEID_ITEM > m_itemData
Definition Item.h:459
bool IsBindedNotWith(Player const *player) const
Definition Item.cpp:1769
void SetCreatePlayedTime(uint32 createPlayedTime)
Definition Item.h:321
uint32 GetCount() const
Definition Item.h:283
void SetGiftCreator(ObjectGuid guid)
Definition Item.h:204
void SetInTrade(bool b=true)
Definition Item.h:271
Difficulty GetDifficultyID() const
Definition Map.h:360
uint32 GetEntry() const
Definition Object.h:89
bool HasIgnore(ObjectGuid const &ignoreGuid, ObjectGuid const &ignoreAccountGuid)
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24850
bool HasPlayerFlagEx(PlayerFlagsEx flags) const
Definition Player.h:2915
PlayerSocial * GetSocial() const
Definition Player.h:1290
uint32 GetTotalPlayedTime() const
Definition Player.h:1347
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition Player.cpp:10055
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans)
Definition Player.cpp:20843
InventoryResult CanStoreItems(Item **items, int count, uint32 *offendingItemId) const
Definition Player.cpp:10560
TradeData * m_trade
Definition Player.h:3281
WorldSession * GetSession() const
Definition Player.h:2272
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9630
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:12075
void MoveItemToInventory(ItemPosCountVec const &dest, Item *pItem, bool update, bool in_characterInventoryDB=false)
Definition Player.cpp:12093
Player * GetTrader() const
Definition Player.cpp:25894
TradeData * GetTradeData() const
Definition Player.h:1655
uint64 GetMoney() const
Definition Player.h:1905
void TradeCancel(bool sendback)
Definition Player.cpp:13254
static bool IsAccountBankPos(uint16 pos)
Definition Player.h:1495
Team GetTeam() const
Definition Player.h:2423
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1907
void SetTradeItemTarget(Player *caster)
Definition Spell.cpp:274
Definition Spell.h:277
SpellCastTargets m_targets
Definition Spell.h:651
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:4699
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3419
SpellCastResult CheckCast(bool strict, int32 *param1=nullptr, int32 *param2=nullptr)
Definition Spell.cpp:5799
Item * m_CastItem
Definition Spell.h:600
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)
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)
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:1185
bool IsInFlight() const
Definition Unit.h:1027
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
uint8 GetLevel() const
Definition Unit.h:757
Map * GetMap() const
Definition Object.h:411
std::string const & GetName() const
Definition Object.h:342
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:501
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< TradeItem > Items
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
bool PlayerLogout() const
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:916
@ CONFIG_TRADE_LEVEL_REQ
Definition World.h:325
@ CONFIG_ALLOW_TWO_SIDE_TRADE
Definition World.h:115
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
@ RBAC_PERM_ALLOW_TWO_SIDE_TRADE
Definition RBAC.h:104
@ RBAC_PERM_LOG_GM_TRADE
Definition RBAC.h:64
char const * GetDefaultLocaleName() const
void Initialize(::Item const *item)
Optional< UnwrappedTradeItem > Unwrapped