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
47
52
53void WorldSession::SendUpdateTrade(bool trader_data /*= true*/)
54{
55 TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData();
56
58 tradeUpdated.WhichPlayer = trader_data;
59 tradeUpdated.ClientStateIndex = view_trade->GetClientStateIndex();
60 tradeUpdated.CurrentStateIndex = view_trade->GetServerStateIndex();
61 tradeUpdated.Gold = view_trade->GetMoney();
62 tradeUpdated.ProposedEnchantment = view_trade->GetSpell();
63
64 for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
65 {
66 if (Item* item = view_trade->GetItem(TradeSlots(i)))
67 {
69 tradeItem.Slot = i;
70 tradeItem.Item.Initialize(item);
71 tradeItem.StackCount = item->GetCount();
72 tradeItem.GiftCreator = item->GetGiftCreator();
73 if (!item->IsWrapped())
74 {
75 tradeItem.Unwrapped.emplace();
76
77 tradeItem.Unwrapped->EnchantID = item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT);
78 tradeItem.Unwrapped->OnUseEnchantmentID = item->GetEnchantmentId(USE_ENCHANTMENT_SLOT);
79 tradeItem.Unwrapped->Creator = item->GetCreator();
80 tradeItem.Unwrapped->Charges = item->GetSpellCharges();
81 tradeItem.Unwrapped->Lock = item->GetTemplate()->GetLockID() && item->IsLocked();
82 tradeItem.Unwrapped->MaxDurability = item->m_itemData->MaxDurability;
83 tradeItem.Unwrapped->Durability = item->m_itemData->Durability;
84
85 uint8 g = 0;
86 for (UF::SocketedGem const& gemData : item->m_itemData->Gems)
87 {
88 if (gemData.ItemID)
89 {
91 gem.Slot = g;
92 gem.Item.Initialize(&gemData);
93 tradeItem.Unwrapped->Gems.push_back(gem);
94 }
95 ++g;
96 }
97 }
98
99 tradeUpdated.Items.push_back(tradeItem);
100 }
101 }
102
103 SendPacket(tradeUpdated.Write());
104}
105
106//==============================================================
107// transfer the items to the players
108
109void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
110{
111 Player* trader = _player->GetTrader();
112 if (!trader)
113 return;
114
115 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
116 {
117 ItemPosCountVec traderDst;
118 ItemPosCountVec playerDst;
119 bool traderCanTrade = (myItems[i] == nullptr || trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK);
120 bool playerCanTrade = (hisItems[i] == nullptr || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK);
121 if (traderCanTrade && playerCanTrade)
122 {
123 // Ok, if trade item exists and can be stored
124 // If we trade in both directions we had to check, if the trade will work before we actually do it
125 // A roll back is not possible after we stored it
126 if (myItems[i])
127 {
128 // logging
129 TC_LOG_DEBUG("network", "partner storing: {}", myItems[i]->GetGUID().ToString());
131 {
132 sLog->OutCommand(_player->GetSession()->GetAccountId(), "GM {} (Account: {}) trade: {} (Entry: {} Count: {}) to player: {} (Account: {})",
134 myItems[i]->GetTemplate()->GetDefaultLocaleName(), myItems[i]->GetEntry(), myItems[i]->GetCount(),
135 trader->GetName(), trader->GetSession()->GetAccountId());
136 }
137
138 // adjust time (depends on /played)
139 if (*myItems[i]->m_itemData->CreatePlayedTime)
140 myItems[i]->SetCreatePlayedTime(trader->GetTotalPlayedTime() - (_player->GetTotalPlayedTime() - myItems[i]->m_itemData->CreatePlayedTime));
141 // store
142 trader->MoveItemToInventory(traderDst, myItems[i], true, true);
143 }
144 if (hisItems[i])
145 {
146 // logging
147 TC_LOG_DEBUG("network", "player storing: {}", hisItems[i]->GetGUID().ToString());
149 {
150 sLog->OutCommand(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) trade: {} (Entry: {} Count: {}) to player: {} (Account: {})",
151 trader->GetName(), trader->GetSession()->GetAccountId(),
152 hisItems[i]->GetTemplate()->GetDefaultLocaleName(), hisItems[i]->GetEntry(), hisItems[i]->GetCount(),
154 }
155
156 // adjust time (depends on /played)
157 if (*hisItems[i]->m_itemData->CreatePlayedTime)
158 hisItems[i]->SetCreatePlayedTime(_player->GetTotalPlayedTime() - (trader->GetTotalPlayedTime() - hisItems[i]->m_itemData->CreatePlayedTime));
159 // store
160 _player->MoveItemToInventory(playerDst, hisItems[i], true, true);
161 }
162 }
163 else
164 {
165 // in case of fatal error log error message
166 // return the already removed items to the original owner
167 if (myItems[i])
168 {
169 if (!traderCanTrade)
170 TC_LOG_ERROR("network", "trader can't store item: {}", myItems[i]->GetGUID().ToString());
171 if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK)
172 _player->MoveItemToInventory(playerDst, myItems[i], true, true);
173 else
174 TC_LOG_ERROR("network", "player can't take item back: {}", myItems[i]->GetGUID().ToString());
175 }
176 // return the already removed items to the original owner
177 if (hisItems[i])
178 {
179 if (!playerCanTrade)
180 TC_LOG_ERROR("network", "player can't store item: {}", hisItems[i]->GetGUID().ToString());
181 if (trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK)
182 trader->MoveItemToInventory(traderDst, hisItems[i], true, true);
183 else
184 TC_LOG_ERROR("network", "trader can't take item back: {}", hisItems[i]->GetGUID().ToString());
185 }
186 }
187 }
188}
189
190//==============================================================
191
192static void setAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade, Item* *myItems, Item* *hisItems)
193{
194 myTrade->SetInAcceptProcess(true);
195 hisTrade->SetInAcceptProcess(true);
196
197 // store items in local list and set 'in-trade' flag
198 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
199 {
200 if (Item* item = myTrade->GetItem(TradeSlots(i)))
201 {
202 TC_LOG_DEBUG("network", "player trade item {} bag: {} slot: {}", item->GetGUID().ToString(), item->GetBagSlot(), item->GetSlot());
203 //Can return nullptr
204 myItems[i] = item;
205 myItems[i]->SetInTrade();
206 }
207
208 if (Item* item = hisTrade->GetItem(TradeSlots(i)))
209 {
210 TC_LOG_DEBUG("network", "partner trade item {} bag: {} slot: {}", item->GetGUID().ToString(), item->GetBagSlot(), item->GetSlot());
211 hisItems[i] = item;
212 hisItems[i]->SetInTrade();
213 }
214 }
215}
216
217static void clearAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade)
218{
219 myTrade->SetInAcceptProcess(false);
220 hisTrade->SetInAcceptProcess(false);
221}
222
223static void clearAcceptTradeMode(Item* *myItems, Item* *hisItems)
224{
225 // clear 'in-trade' flag
226 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
227 {
228 if (myItems[i])
229 myItems[i]->SetInTrade(false);
230 if (hisItems[i])
231 hisItems[i]->SetInTrade(false);
232 }
233}
234
236{
237 TradeData* my_trade = _player->m_trade;
238 if (!my_trade)
239 return;
240
241 Player* trader = my_trade->GetTrader();
242
243 TradeData* his_trade = trader->m_trade;
244 if (!his_trade)
245 return;
246
247 Item* myItems[TRADE_SLOT_TRADED_COUNT] = { };
248 Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { };
249
250 // set before checks for propertly undo at problems (it already set in to client)
251 my_trade->SetAccepted(true);
252
254 if (his_trade->GetServerStateIndex() != acceptTrade.StateIndex)
255 {
257 SendTradeStatus(info);
258 my_trade->SetAccepted(false);
259 return;
260 }
261
262 if (!_player->IsWithinDistInMap(trader, TRADE_DISTANCE, false))
263 {
265 SendTradeStatus(info);
266 my_trade->SetAccepted(false);
267 return;
268 }
269
270 // not accept case incorrect money amount
271 if (!_player->HasEnoughMoney(my_trade->GetMoney()))
272 {
275 SendTradeStatus(info);
276 my_trade->SetAccepted(false, true);
277 return;
278 }
279
280 // not accept case incorrect money amount
281 if (!trader->HasEnoughMoney(his_trade->GetMoney()))
282 {
285 trader->GetSession()->SendTradeStatus(info);
286 his_trade->SetAccepted(false, true);
287 return;
288 }
289
290 if (_player->GetMoney() > MAX_MONEY_AMOUNT - his_trade->GetMoney())
291 {
294 SendTradeStatus(info);
295 my_trade->SetAccepted(false, true);
296 return;
297 }
298
299 if (trader->GetMoney() > MAX_MONEY_AMOUNT - my_trade->GetMoney())
300 {
303 trader->GetSession()->SendTradeStatus(info);
304 his_trade->SetAccepted(false, true);
305 return;
306 }
307
308 // not accept if some items now can't be trade (cheating)
309 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
310 {
311 if (Item* item = my_trade->GetItem(TradeSlots(i)))
312 {
313 if (!item->CanBeTraded(false, true))
314 {
316 SendTradeStatus(info);
317 return;
318 }
319
320 if (item->IsBindedNotWith(trader))
321 {
324 SendTradeStatus(info);
325 return;
326 }
327
328 if (Player::IsAccountBankPos(item->GetSlot(), item->GetBagSlot()))
329 {
332 SendTradeStatus(info);
333 return;
334 }
335 }
336
337 if (Item* item = his_trade->GetItem(TradeSlots(i)))
338 {
339 if (!item->CanBeTraded(false, true))
340 {
342 SendTradeStatus(info);
343 return;
344 }
345 //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)
346 //{
347 // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE);
348 // his_trade->SetAccepted(false, true);
349 // return;
350 //}
351
352 if (Player::IsAccountBankPos(item->GetSlot(), item->GetBagSlot()))
353 {
356 SendTradeStatus(info);
357 return;
358 }
359 }
360 }
361
362 if (his_trade->IsAccepted())
363 {
364 setAcceptTradeMode(my_trade, his_trade, myItems, hisItems);
365
366 Spell* my_spell = nullptr;
367 SpellCastTargets my_targets;
368
369 Spell* his_spell = nullptr;
370 SpellCastTargets his_targets;
371
372 // not accept if spell can't be cast now (cheating)
373 if (uint32 my_spell_id = my_trade->GetSpell())
374 {
375 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id, _player->GetMap()->GetDifficultyID());
376 Item* castItem = my_trade->GetSpellCastItem();
377
378 if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) ||
379 (my_trade->HasSpellCastItem() && !castItem))
380 {
381 clearAcceptTradeMode(my_trade, his_trade);
382 clearAcceptTradeMode(myItems, hisItems);
383
384 my_trade->SetSpell(0);
385 return;
386 }
387
388 my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK);
389 my_spell->m_CastItem = castItem;
390 my_targets.SetTradeItemTarget(_player);
391 my_spell->m_targets = my_targets;
392
393 SpellCastResult res = my_spell->CheckCast(true);
394 if (res != SPELL_CAST_OK)
395 {
396 my_spell->SendCastResult(res);
397
398 clearAcceptTradeMode(my_trade, his_trade);
399 clearAcceptTradeMode(myItems, hisItems);
400
401 delete my_spell;
402 my_trade->SetSpell(0);
403 return;
404 }
405 }
406
407 // not accept if spell can't be cast now (cheating)
408 if (uint32 his_spell_id = his_trade->GetSpell())
409 {
410 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id, trader->GetMap()->GetDifficultyID());
411 Item* castItem = his_trade->GetSpellCastItem();
412
413 if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem))
414 {
415 delete my_spell;
416 his_trade->SetSpell(0);
417
418 clearAcceptTradeMode(my_trade, his_trade);
419 clearAcceptTradeMode(myItems, hisItems);
420 return;
421 }
422
423 his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK);
424 his_spell->m_CastItem = castItem;
425 his_targets.SetTradeItemTarget(trader);
426 his_spell->m_targets = his_targets;
427
428 SpellCastResult res = his_spell->CheckCast(true);
429 if (res != SPELL_CAST_OK)
430 {
431 his_spell->SendCastResult(res);
432
433 clearAcceptTradeMode(my_trade, his_trade);
434 clearAcceptTradeMode(myItems, hisItems);
435
436 delete my_spell;
437 delete his_spell;
438
439 his_trade->SetSpell(0);
440 return;
441 }
442 }
443
444 // inform partner client
446 trader->GetSession()->SendTradeStatus(info);
447
448 // test if item will fit in each inventory
449 WorldPackets::Trade::TradeStatus myCanCompleteInfo, hisCanCompleteInfo;
450 hisCanCompleteInfo.BagResult = trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT, &hisCanCompleteInfo.ItemID);
451 myCanCompleteInfo.BagResult = _player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT, &myCanCompleteInfo.ItemID);
452
453 clearAcceptTradeMode(myItems, hisItems);
454
455 // in case of missing space report error
456 if (myCanCompleteInfo.BagResult != EQUIP_ERR_OK)
457 {
458 clearAcceptTradeMode(my_trade, his_trade);
459
460 myCanCompleteInfo.Status = TRADE_STATUS_FAILED;
461 trader->GetSession()->SendTradeStatus(myCanCompleteInfo);
462 myCanCompleteInfo.FailureForYou = true;
463 SendTradeStatus(myCanCompleteInfo);
464 my_trade->SetAccepted(false);
465 his_trade->SetAccepted(false);
466 delete my_spell;
467 delete his_spell;
468 return;
469 }
470 else if (hisCanCompleteInfo.BagResult != EQUIP_ERR_OK)
471 {
472 clearAcceptTradeMode(my_trade, his_trade);
473
474 hisCanCompleteInfo.Status = TRADE_STATUS_FAILED;
475 SendTradeStatus(hisCanCompleteInfo);
476 hisCanCompleteInfo.FailureForYou = true;
477 trader->GetSession()->SendTradeStatus(hisCanCompleteInfo);
478 my_trade->SetAccepted(false);
479 his_trade->SetAccepted(false);
480 delete my_spell;
481 delete his_spell;
482 return;
483 }
484
485 // execute trade: 1. remove
486 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
487 {
488 if (myItems[i])
489 {
490 myItems[i]->SetGiftCreator(_player->GetGUID());
491 _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true);
492 }
493 if (hisItems[i])
494 {
495 hisItems[i]->SetGiftCreator(trader->GetGUID());
496 trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true);
497 }
498 }
499
500 // execute trade: 2. store
501 moveItems(myItems, hisItems);
502
503 // logging money
505 {
506 if (my_trade->GetMoney() > 0)
507 {
508 sLog->OutCommand(_player->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
510 my_trade->GetMoney(),
511 trader->GetName(), trader->GetSession()->GetAccountId());
512 }
513
514 if (his_trade->GetMoney() > 0)
515 {
516 sLog->OutCommand(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
517 trader->GetName(), trader->GetSession()->GetAccountId(),
518 his_trade->GetMoney(),
520 }
521 }
522
523 // update money
524 _player->ModifyMoney(-int64(my_trade->GetMoney()));
525 _player->ModifyMoney(his_trade->GetMoney());
526 trader->ModifyMoney(-int64(his_trade->GetMoney()));
527 trader->ModifyMoney(my_trade->GetMoney());
528
529 if (my_spell)
530 my_spell->prepare(my_targets);
531
532 if (his_spell)
533 his_spell->prepare(his_targets);
534
535 // cleanup
536 clearAcceptTradeMode(my_trade, his_trade);
537 delete _player->m_trade;
538 _player->m_trade = nullptr;
539 delete trader->m_trade;
540 trader->m_trade = nullptr;
541
542 // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
543 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
545 trader->SaveInventoryAndGoldToDB(trans);
546 CharacterDatabase.CommitTransaction(trans);
547
549 trader->GetSession()->SendTradeStatus(info);
550 SendTradeStatus(info);
551 }
552 else
553 {
555 trader->GetSession()->SendTradeStatus(info);
556 }
557}
558
560{
561 TradeData* my_trade = _player->GetTradeData();
562 if (!my_trade)
563 return;
564
565 my_trade->SetAccepted(false, true);
566}
567
569{
570 TradeData* my_trade = _player->m_trade;
571 if (!my_trade)
572 return;
573
576 my_trade->GetTrader()->GetSession()->SendTradeStatus(info);
577 SendTradeStatus(info);
578}
579
581{
583 return;
584
586 info.Status = status;
587 SendTradeStatus(info);
588}
589
591{
592 // sent also after LOGOUT COMPLETE
593 if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
594 _player->TradeCancel(true);
595}
596
598{
599 if (GetPlayer()->m_trade)
600 return;
601
603 if (!GetPlayer()->IsAlive())
604 {
606 SendTradeStatus(info);
607 return;
608 }
609
610 if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED))
611 {
613 SendTradeStatus(info);
614 return;
615 }
616
617 if (isLogingOut())
618 {
620 SendTradeStatus(info);
621 return;
622 }
623
624 if (GetPlayer()->IsInFlight())
625 {
627 SendTradeStatus(info);
628 return;
629 }
630
631 if (GetPlayer()->GetLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ))
632 {
635 SendTradeStatus(info);
636 return;
637 }
638
639 Player* pOther = ObjectAccessor::FindPlayer(initiateTrade.Guid);
640 if (!pOther)
641 {
643 SendTradeStatus(info);
644 return;
645 }
646
647 if (pOther == GetPlayer() || pOther->m_trade)
648 {
650 SendTradeStatus(info);
651 return;
652 }
653
654 if (!pOther->IsAlive())
655 {
657 SendTradeStatus(info);
658 return;
659 }
660
661 if (pOther->IsInFlight())
662 {
664 SendTradeStatus(info);
665 return;
666 }
667
668 if (pOther->HasUnitState(UNIT_STATE_STUNNED))
669 {
671 SendTradeStatus(info);
672 return;
673 }
674
675 if (pOther->GetSession()->isLogingOut())
676 {
678 SendTradeStatus(info);
679 return;
680 }
681
682 if ((pOther->GetTeam() != _player->GetTeam() ||
685 (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) &&
687 {
689 SendTradeStatus(info);
690 return;
691 }
692
693 if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false))
694 {
696 SendTradeStatus(info);
697 return;
698 }
699
700 if (pOther->GetLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ))
701 {
704 SendTradeStatus(info);
705 return;
706 }
707
708 // OK start trade
709 _player->m_trade = new TradeData(_player, pOther);
710 pOther->m_trade = new TradeData(pOther, _player);
711
713 info.Partner = _player->GetGUID();
714 pOther->GetSession()->SendTradeStatus(info);
715}
716
718{
719 TradeData* my_trade = _player->GetTradeData();
720 if (!my_trade)
721 return;
722
723 my_trade->UpdateClientStateIndex();
724 my_trade->SetMoney(setTradeGold.Coinage);
725}
726
728{
729 TradeData* my_trade = _player->GetTradeData();
730 if (!my_trade)
731 return;
732
734 // invalid slot number
735 if (setTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
736 {
738 SendTradeStatus(info);
739 return;
740 }
741
742 // check cheating, can't fail with correct client operations
743 Item* item = _player->GetItemByPos(setTradeItem.PackSlot, setTradeItem.ItemSlotInPack);
744 if (!item || (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true)))
745 {
747 SendTradeStatus(info);
748 return;
749 }
750
751 ObjectGuid iGUID = item->GetGUID();
752
753 // prevent place single item into many trade slots using cheating and client bugs
754 if (my_trade->HasItem(iGUID))
755 {
756 // cheating attempt
758 SendTradeStatus(info);
759 return;
760 }
761
762 my_trade->UpdateClientStateIndex();
763
764 if (setTradeItem.TradeSlot != TRADE_SLOT_NONTRADED && item->IsBindedNotWith(my_trade->GetTrader()))
765 {
767 info.TradeSlot = setTradeItem.TradeSlot;
768 SendTradeStatus(info);
769 return;
770 }
771
772 my_trade->SetItem(TradeSlots(setTradeItem.TradeSlot), item);
773}
774
776{
777 TradeData* my_trade = _player->m_trade;
778 if (!my_trade)
779 return;
780
781 my_trade->UpdateClientStateIndex();
782
783 // invalid slot number
784 if (clearTradeItem.TradeSlot >= TRADE_SLOT_COUNT)
785 return;
786
787 my_trade->SetItem(TradeSlots(clearTradeItem.TradeSlot), nullptr);
788}
789
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:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define sLog
Definition Log.h:156
#define TRADE_DISTANCE
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:827
@ PLAYER_FLAGS_EX_MERCENARY_MODE
Definition Player.h:551
constexpr uint64 MAX_MONEY_AMOUNT
Definition Player.h:1028
TradeStatus
@ 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:278
@ NULL_BAG
Definition Unit.h:63
@ NULL_SLOT
Definition Unit.h:64
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
Definition Item.h:185
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:464
bool IsBindedNotWith(Player const *player) const
Definition Item.cpp:1769
void SetCreatePlayedTime(uint32 createPlayedTime)
Definition Item.h:327
uint32 GetCount() const
Definition Item.h:289
void SetGiftCreator(ObjectGuid guid)
Definition Item.h:210
void SetInTrade(bool b=true)
Definition Item.h:277
Difficulty GetDifficultyID() const
Definition Map.h:363
uint32 GetEntry() const
Definition Object.h:89
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24800
bool HasPlayerFlagEx(PlayerFlagsEx flags) const
Definition Player.h:2900
uint32 GetTotalPlayedTime() const
Definition Player.h:1331
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition Player.cpp:9975
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans)
Definition Player.cpp:20790
InventoryResult CanStoreItems(Item **items, int count, uint32 *offendingItemId) const
Definition Player.cpp:10482
TradeData * m_trade
Definition Player.h:3266
void TradeCancel(bool sendback, TradeStatus status=TRADE_STATUS_CANCELLED)
Definition Player.cpp:13212
WorldSession * GetSession() const
Definition Player.h:2256
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9538
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:11993
void MoveItemToInventory(ItemPosCountVec const &dest, Item *pItem, bool update, bool in_characterInventoryDB=false)
Definition Player.cpp:12011
Player * GetTrader() const
Definition Player.cpp:25825
TradeData * GetTradeData() const
Definition Player.h:1640
uint64 GetMoney() const
Definition Player.h:1890
static bool IsAccountBankPos(uint16 pos)
Definition Player.h:1479
Team GetTeam() const
Definition Player.h:2406
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1892
void SetTradeItemTarget(Player *caster)
Definition Spell.cpp:274
Definition Spell.h:277
SpellCastTargets m_targets
Definition Spell.h:651
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3432
SpellCastResult CheckCast(bool strict, int32 *param1=nullptr, int32 *param2=nullptr)
Definition Spell.cpp:5745
static void SendCastResult(Player const *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:4641
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:1205
bool IsInFlight() const
Definition Unit.h:1042
bool HasUnitState(const uint32 f) const
Definition Unit.h:755
uint8 GetLevel() const
Definition Unit.h:769
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:499
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
Player * GetPlayer() const
void HandleBusyTradeOpcode(WorldPackets::Trade::BusyTrade &busyTrade)
void SendCancelTrade(TradeStatus status)
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 HandleSetTradeItemOpcode(WorldPackets::Trade::SetTradeItem &setTradeItem)
#define sWorld
Definition World.h:919
@ 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