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 "ObjectAccessor.h"
26#include "Player.h"
27#include "Spell.h"
28#include "SpellMgr.h"
29#include "SocialMgr.h"
30#include "TradeData.h"
31#include "TradePackets.h"
32#include "World.h"
33#include "WorldPacket.h"
34
36{
38 data << uint32(info.Status);
39
40 switch (info.Status)
41 {
43 data << info.TraderGuid; // CGTradeInfo::m_tradingPlayer
44 break;
46 data << uint32(0); // CGTradeInfo::m_tradeID
47 break;
49 data << uint32(info.Result); // InventoryResult
50 data << uint8(info.IsTargetResult); // bool isTargetError; used for: EQUIP_ERR_BAG_FULL, EQUIP_ERR_CANT_CARRY_MORE_OF_THIS, EQUIP_ERR_MISSING_REAGENT, EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED
51 data << uint32(info.ItemLimitCategoryId); // ItemLimitCategory.dbc entry
52 break;
55 data << uint8(info.Slot); // Trade slot; -1 here clears CGTradeInfo::m_tradeMoney
56 break;
57 default:
58 break;
59 }
60
61 SendPacket(&data);
62}
63
68
73
74void WorldSession::SendUpdateTrade(bool trader_data /*= true*/)
75{
76 TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData();
77
78 WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4));
79 data << uint8(trader_data); // 1 means traders data, 0 means own
80 data << uint32(0); // CGTradeInfo::m_tradeID
81 data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases
82 data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases
83 data << uint32(view_trade->GetMoney()); // trader gold
84 data << uint32(view_trade->GetSpell()); // spell cast on lowest slot item
85
86 for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
87 {
88 data << uint8(i); // trade slot number, if not specified, then end of packet
89
90 if (Item* item = view_trade->GetItem(TradeSlots(i)))
91 {
92 data << uint32(item->GetTemplate()->ItemId); // entry
93 data << uint32(item->GetTemplate()->DisplayInfoID);// display id
94 data << uint32(item->GetCount()); // stack count
95 // wrapped: hide stats but show giftcreator name
96 data << uint32(item->IsWrapped() ? 1 : 0);
97 data << item->GetGuidValue(ITEM_FIELD_GIFTCREATOR);
98 // perm. enchantment and gems
99 data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
100 for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
101 data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot)));
102 // creator
103 data << item->GetGuidValue(ITEM_FIELD_CREATOR);
104 data << uint32(item->GetSpellCharges()); // charges
105 data << uint32(item->GetItemSuffixFactor()); // SuffixFactor
106 data << uint32(item->GetItemRandomPropertyId());// random properties id
107 data << uint32(item->GetTemplate()->LockID); // lock id
108 // max durability
109 data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
110 // durability
111 data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY));
112 }
113 else
114 {
115 for (uint8 j = 0; j < 18; ++j)
116 data << uint32(0);
117 }
118 }
119 SendPacket(&data);
120}
121
122//==============================================================
123// transfer the items to the players
124
125void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
126{
127 Player* trader = _player->GetTrader();
128 if (!trader)
129 return;
130
131 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
132 {
133 ItemPosCountVec traderDst;
134 ItemPosCountVec playerDst;
135 bool traderCanTrade = (myItems[i] == nullptr || trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK);
136 bool playerCanTrade = (hisItems[i] == nullptr || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK);
137 if (traderCanTrade && playerCanTrade)
138 {
139 // Ok, if trade item exists and can be stored
140 // If we trade in both directions we had to check, if the trade will work before we actually do it
141 // A roll back is not possible after we stored it
142 if (myItems[i])
143 {
144 // logging
145 TC_LOG_DEBUG("network", "partner storing: {}", myItems[i]->GetGUID().ToString());
147 {
148 sLog->OutCommand(_player->GetSession()->GetAccountId(), "GM {} (Account: {}) trade: {} (Entry: {} Count: {}) to player: {} (Account: {})",
150 myItems[i]->GetTemplate()->Name1, myItems[i]->GetEntry(), myItems[i]->GetCount(),
151 trader->GetName(), trader->GetSession()->GetAccountId());
152 }
153
154 // adjust time (depends on /played)
155 if (myItems[i]->IsBOPTradeable())
157 // store
158 trader->MoveItemToInventory(traderDst, myItems[i], true, true);
159 }
160 if (hisItems[i])
161 {
162 // logging
163 TC_LOG_DEBUG("network", "player storing: {}", hisItems[i]->GetGUID().ToString());
165 {
166 sLog->OutCommand(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) trade: {} (Entry: {} Count: {}) to player: {} (Account: {})",
167 trader->GetName(), trader->GetSession()->GetAccountId(),
168 hisItems[i]->GetTemplate()->Name1, hisItems[i]->GetEntry(), hisItems[i]->GetCount(),
170 }
171
172 // adjust time (depends on /played)
173 if (hisItems[i]->IsBOPTradeable())
175 // store
176 _player->MoveItemToInventory(playerDst, hisItems[i], true, true);
177 }
178 }
179 else
180 {
181 // in case of fatal error log error message
182 // return the already removed items to the original owner
183 if (myItems[i])
184 {
185 if (!traderCanTrade)
186 TC_LOG_ERROR("network", "trader can't store item: {}", myItems[i]->GetGUID().ToString());
187 if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK)
188 _player->MoveItemToInventory(playerDst, myItems[i], true, true);
189 else
190 TC_LOG_ERROR("network", "player can't take item back: {}", myItems[i]->GetGUID().ToString());
191 }
192 // return the already removed items to the original owner
193 if (hisItems[i])
194 {
195 if (!playerCanTrade)
196 TC_LOG_ERROR("network", "player can't store item: {}", hisItems[i]->GetGUID().ToString());
197 if (trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK)
198 trader->MoveItemToInventory(traderDst, hisItems[i], true, true);
199 else
200 TC_LOG_ERROR("network", "trader can't take item back: {}", hisItems[i]->GetGUID().ToString());
201 }
202 }
203 }
204}
205
206//==============================================================
207
208static void setAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade, Item* *myItems, Item* *hisItems)
209{
210 myTrade->SetInAcceptProcess(true);
211 hisTrade->SetInAcceptProcess(true);
212
213 // store items in local list and set 'in-trade' flag
214 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
215 {
216 if (Item* item = myTrade->GetItem(TradeSlots(i)))
217 {
218 TC_LOG_DEBUG("network", "player trade item {} bag: {} slot: {}", item->GetGUID().ToString(), item->GetBagSlot(), item->GetSlot());
219 //Can return nullptr
220 myItems[i] = item;
221 myItems[i]->SetInTrade();
222 }
223
224 if (Item* item = hisTrade->GetItem(TradeSlots(i)))
225 {
226 TC_LOG_DEBUG("network", "partner trade item {} bag: {} slot: {}", item->GetGUID().ToString(), item->GetBagSlot(), item->GetSlot());
227 hisItems[i] = item;
228 hisItems[i]->SetInTrade();
229 }
230 }
231}
232
233static void clearAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade)
234{
235 myTrade->SetInAcceptProcess(false);
236 hisTrade->SetInAcceptProcess(false);
237}
238
239static void clearAcceptTradeMode(Item* *myItems, Item* *hisItems)
240{
241 // clear 'in-trade' flag
242 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
243 {
244 if (myItems[i])
245 myItems[i]->SetInTrade(false);
246 if (hisItems[i])
247 hisItems[i]->SetInTrade(false);
248 }
249}
250
252{
253 TradeData* my_trade = _player->m_trade;
254 if (!my_trade)
255 return;
256
257 Player* trader = my_trade->GetTrader();
258
259 TradeData* his_trade = trader->m_trade;
260 if (!his_trade)
261 return;
262
263 Item* myItems[TRADE_SLOT_TRADED_COUNT] = { };
264 Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { };
265
266 // set before checks for propertly undo at problems (it already set in to client)
267 my_trade->SetAccepted(true);
268
269 TradeStatusInfo info;
270 if (!_player->IsWithinDistInMap(trader, TRADE_DISTANCE, false))
271 {
273 SendTradeStatus(info);
274 my_trade->SetAccepted(false);
275 return;
276 }
277
278 // not accept case incorrect money amount
279 if (!_player->HasEnoughMoney(my_trade->GetMoney()))
280 {
283 SendTradeStatus(info);
284 my_trade->SetAccepted(false, true);
285 return;
286 }
287
288 // not accept case incorrect money amount
289 if (!trader->HasEnoughMoney(his_trade->GetMoney()))
290 {
293 trader->GetSession()->SendTradeStatus(info);
294 his_trade->SetAccepted(false, true);
295 return;
296 }
297
298 if (_player->GetMoney() >= MAX_MONEY_AMOUNT - his_trade->GetMoney())
299 {
302 SendTradeStatus(info);
303 my_trade->SetAccepted(false, true);
304 return;
305 }
306
307 if (trader->GetMoney() >= MAX_MONEY_AMOUNT - my_trade->GetMoney())
308 {
311 trader->GetSession()->SendTradeStatus(info);
312 his_trade->SetAccepted(false, true);
313 return;
314 }
315
316 // not accept if some items now can't be trade (cheating)
317 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
318 {
319 if (Item* item = my_trade->GetItem(TradeSlots(i)))
320 {
321 if (!item->CanBeTraded(false, true))
322 {
324 SendTradeStatus(info);
325 return;
326 }
327
328 if (item->IsBindedNotWith(trader))
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 }
353
354 if (his_trade->IsAccepted())
355 {
356 setAcceptTradeMode(my_trade, his_trade, myItems, hisItems);
357
358 Spell* my_spell = nullptr;
359 SpellCastTargets my_targets;
360
361 Spell* his_spell = nullptr;
362 SpellCastTargets his_targets;
363
364 // not accept if spell can't be cast now (cheating)
365 if (uint32 my_spell_id = my_trade->GetSpell())
366 {
367 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id);
368 Item* castItem = my_trade->GetSpellCastItem();
369
370 if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) ||
371 (my_trade->HasSpellCastItem() && !castItem))
372 {
373 clearAcceptTradeMode(my_trade, his_trade);
374 clearAcceptTradeMode(myItems, hisItems);
375
376 my_trade->SetSpell(0);
377 return;
378 }
379
380 my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK);
381 my_spell->m_CastItem = castItem;
382 my_targets.SetTradeItemTarget(_player);
383 my_spell->m_targets = my_targets;
384
385 SpellCastResult res = my_spell->CheckCast(true);
386 if (res != SPELL_CAST_OK)
387 {
388 my_spell->SendCastResult(res);
389
390 clearAcceptTradeMode(my_trade, his_trade);
391 clearAcceptTradeMode(myItems, hisItems);
392
393 delete my_spell;
394 my_trade->SetSpell(0);
395 return;
396 }
397 }
398
399 // not accept if spell can't be cast now (cheating)
400 if (uint32 his_spell_id = his_trade->GetSpell())
401 {
402 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id);
403 Item* castItem = his_trade->GetSpellCastItem();
404
405 if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem))
406 {
407 delete my_spell;
408 his_trade->SetSpell(0);
409
410 clearAcceptTradeMode(my_trade, his_trade);
411 clearAcceptTradeMode(myItems, hisItems);
412 return;
413 }
414
415 his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK);
416 his_spell->m_CastItem = castItem;
417 his_targets.SetTradeItemTarget(trader);
418 his_spell->m_targets = his_targets;
419
420 SpellCastResult res = his_spell->CheckCast(true);
421 if (res != SPELL_CAST_OK)
422 {
423 his_spell->SendCastResult(res);
424
425 clearAcceptTradeMode(my_trade, his_trade);
426 clearAcceptTradeMode(myItems, hisItems);
427
428 delete my_spell;
429 delete his_spell;
430
431 his_trade->SetSpell(0);
432 return;
433 }
434 }
435
436 // inform partner client
438 trader->GetSession()->SendTradeStatus(info);
439
440 // test if item will fit in each inventory
441 TradeStatusInfo myCanCompleteInfo, hisCanCompleteInfo;
442 hisCanCompleteInfo.Result = trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT, &hisCanCompleteInfo.ItemLimitCategoryId);
443 myCanCompleteInfo.Result = _player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT, &myCanCompleteInfo.ItemLimitCategoryId);
444
445 clearAcceptTradeMode(myItems, hisItems);
446
447 // in case of missing space report error
448 if (myCanCompleteInfo.Result != EQUIP_ERR_OK)
449 {
450 clearAcceptTradeMode(my_trade, his_trade);
451
452 myCanCompleteInfo.Status = TRADE_STATUS_CLOSE_WINDOW;
453 trader->GetSession()->SendTradeStatus(myCanCompleteInfo);
454 myCanCompleteInfo.IsTargetResult = true;
455 SendTradeStatus(myCanCompleteInfo);
456 my_trade->SetAccepted(false);
457 his_trade->SetAccepted(false);
458 delete my_spell;
459 delete his_spell;
460 return;
461 }
462 else if (hisCanCompleteInfo.Result != EQUIP_ERR_OK)
463 {
464 clearAcceptTradeMode(my_trade, his_trade);
465
466 hisCanCompleteInfo.Status = TRADE_STATUS_CLOSE_WINDOW;
467 SendTradeStatus(hisCanCompleteInfo);
468 hisCanCompleteInfo.IsTargetResult = true;
469 trader->GetSession()->SendTradeStatus(hisCanCompleteInfo);
470 my_trade->SetAccepted(false);
471 his_trade->SetAccepted(false);
472 delete my_spell;
473 delete his_spell;
474 return;
475 }
476
477 // execute trade: 1. remove
478 for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
479 {
480 if (myItems[i])
481 {
483 _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true);
484 }
485 if (hisItems[i])
486 {
487 hisItems[i]->SetGuidValue(ITEM_FIELD_GIFTCREATOR, trader->GetGUID());
488 trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true);
489 }
490 }
491
492 // execute trade: 2. store
493 moveItems(myItems, hisItems);
494
495 // logging money
497 {
498 if (my_trade->GetMoney() > 0)
499 {
500 sLog->OutCommand(_player->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
502 my_trade->GetMoney(),
503 trader->GetName(), trader->GetSession()->GetAccountId());
504 }
505
506 if (his_trade->GetMoney() > 0)
507 {
508 sLog->OutCommand(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) give money (Amount: {}) to player: {} (Account: {})",
509 trader->GetName(), trader->GetSession()->GetAccountId(),
510 his_trade->GetMoney(),
512 }
513 }
514
515 // update money
516 _player->ModifyMoney(-int32(my_trade->GetMoney()));
517 _player->ModifyMoney(his_trade->GetMoney());
518 trader->ModifyMoney(-int32(his_trade->GetMoney()));
519 trader->ModifyMoney(my_trade->GetMoney());
520
521 if (my_spell)
522 my_spell->prepare(my_targets);
523
524 if (his_spell)
525 his_spell->prepare(his_targets);
526
527 // cleanup
528 clearAcceptTradeMode(my_trade, his_trade);
529 delete _player->m_trade;
530 _player->m_trade = nullptr;
531 delete trader->m_trade;
532 trader->m_trade = nullptr;
533
534 // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
535 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
537 trader->SaveInventoryAndGoldToDB(trans);
538 CharacterDatabase.CommitTransaction(trans);
539
541 trader->GetSession()->SendTradeStatus(info);
542 SendTradeStatus(info);
543 }
544 else
545 {
547 trader->GetSession()->SendTradeStatus(info);
548 }
549}
550
552{
553 TradeData* my_trade = _player->GetTradeData();
554 if (!my_trade)
555 return;
556
557 my_trade->SetAccepted(false, true);
558}
559
561{
562 TradeData* my_trade = _player->m_trade;
563 if (!my_trade)
564 return;
565
566 TradeStatusInfo info;
568 my_trade->GetTrader()->GetSession()->SendTradeStatus(info);
569 SendTradeStatus(info);
570}
571
573{
575 return;
576
577 TradeStatusInfo info;
578 info.Status = status;
579 SendTradeStatus(info);
580}
581
583{
584 // sended also after LOGOUT COMPLETE
585 if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
586 _player->TradeCancel(true);
587}
588
590{
591 ObjectGuid ID;
592 recvPacket >> ID;
593
594 if (GetPlayer()->m_trade)
595 return;
596
597 TradeStatusInfo info;
598 if (!GetPlayer()->IsAlive())
599 {
601 SendTradeStatus(info);
602 return;
603 }
604
605 if (GetPlayer()->HasUnitState(UNIT_STATE_STUNNED))
606 {
608 SendTradeStatus(info);
609 return;
610 }
611
612 if (isLogingOut())
613 {
615 SendTradeStatus(info);
616 return;
617 }
618
619 if (GetPlayer()->IsInFlight())
620 {
622 SendTradeStatus(info);
623 return;
624 }
625
626 if (GetPlayer()->GetLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ))
627 {
630 SendTradeStatus(info);
631 return;
632 }
633
635
636 if (!pOther)
637 {
639 SendTradeStatus(info);
640 return;
641 }
642
643 if (pOther == GetPlayer() || pOther->m_trade)
644 {
646 SendTradeStatus(info);
647 return;
648 }
649
650 if (!pOther->IsAlive())
651 {
653 SendTradeStatus(info);
654 return;
655 }
656
657 if (pOther->IsInFlight())
658 {
660 SendTradeStatus(info);
661 return;
662 }
663
664 if (pOther->HasUnitState(UNIT_STATE_STUNNED))
665 {
667 SendTradeStatus(info);
668 return;
669 }
670
671 if (pOther->GetSession()->isLogingOut())
672 {
674 SendTradeStatus(info);
675 return;
676 }
677
678 if (pOther->GetTeam() != _player->GetTeam() &&
679 (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) &&
681 {
683 SendTradeStatus(info);
684 return;
685 }
686
687 if (!pOther->IsWithinDistInMap(_player, TRADE_DISTANCE, false))
688 {
690 SendTradeStatus(info);
691 return;
692 }
693
694 // OK start trade
695 _player->m_trade = new TradeData(_player, pOther);
696 pOther->m_trade = new TradeData(pOther, _player);
697
699 info.TraderGuid = _player->GetGUID();
700 pOther->GetSession()->SendTradeStatus(info);
701}
702
704{
705 uint32 gold;
706 recvPacket >> gold;
707
708 TradeData* my_trade = _player->GetTradeData();
709 if (!my_trade)
710 return;
711
712 my_trade->SetMoney(gold);
713}
714
716{
717 // send update
718 uint8 tradeSlot;
719 uint8 bag;
720 uint8 slot;
721
722 recvPacket >> tradeSlot;
723 recvPacket >> bag;
724 recvPacket >> slot;
725
726 TradeData* my_trade = _player->GetTradeData();
727 if (!my_trade)
728 return;
729
730 TradeStatusInfo info;
731 // invalid slot number
732 if (tradeSlot >= TRADE_SLOT_COUNT)
733 {
735 SendTradeStatus(info);
736 return;
737 }
738
739 // check cheating, can't fail with correct client operations
740 Item* item = _player->GetItemByPos(bag, slot);
741 if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true)))
742 {
744 SendTradeStatus(info);
745 return;
746 }
747
748 ObjectGuid iGUID = item->GetGUID();
749
750 // prevent place single item into many trade slots using cheating and client bugs
751 if (my_trade->HasItem(iGUID))
752 {
753 // cheating attempt
755 SendTradeStatus(info);
756 return;
757 }
758
759 if (tradeSlot != TRADE_SLOT_NONTRADED && item->IsBindedNotWith(my_trade->GetTrader()))
760 {
762 info.Slot = tradeSlot;
763 SendTradeStatus(info);
764 return;
765 }
766
767 my_trade->SetItem(TradeSlots(tradeSlot), item);
768}
769
771{
772 uint8 tradeSlot;
773 recvPacket >> tradeSlot;
774
775 TradeData* my_trade = _player->m_trade;
776 if (!my_trade)
777 return;
778
779 // invalid slot number
780 if (tradeSlot >= TRADE_SLOT_COUNT)
781 return;
782
783 my_trade->SetItem(TradeSlots(tradeSlot), nullptr);
784}
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
EnchantmentSlot
@ PERM_ENCHANTMENT_SLOT
@ SOCK_ENCHANTMENT_SLOT
@ EQUIP_ERR_TOO_MUCH_GOLD
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ EQUIP_ERR_NOT_ENOUGH_MONEY
Definition ItemDefines.h:55
@ EQUIP_ERR_TRADE_BOUND_ITEM
#define MAX_GEM_SOCKETS
Definition Item.h:40
@ LANG_TRADE_REQ
Definition Language.h:1166
#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
uint32 const MAX_MONEY_AMOUNT
Definition Player.cpp:119
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:624
TradeStatus
@ TRADE_STATUS_YOU_STUNNED
@ TRADE_STATUS_IGNORE_YOU
@ TRADE_STATUS_TRADE_COMPLETE
@ TRADE_STATUS_YOU_DEAD
@ TRADE_STATUS_NOT_ON_TAPLIST
@ TRADE_STATUS_YOU_LOGOUT
@ TRADE_STATUS_TARGET_DEAD
@ TRADE_STATUS_TRADE_ACCEPT
@ TRADE_STATUS_WRONG_REALM
@ TRADE_STATUS_NO_TARGET
@ TRADE_STATUS_BEGIN_TRADE
@ TRADE_STATUS_TARGET_LOGOUT
@ TRADE_STATUS_TARGET_STUNNED
@ TRADE_STATUS_TRADE_CANCELED
@ TRADE_STATUS_TARGET_TO_FAR
@ TRADE_STATUS_BUSY
@ TRADE_STATUS_OPEN_WINDOW
@ TRADE_STATUS_WRONG_FACTION
@ TRADE_STATUS_CLOSE_WINDOW
SpellCastResult
@ SPELL_CAST_OK
@ TRIGGERED_FULL_MASK
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
#define sSpellMgr
Definition SpellMgr.h:738
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:223
@ NULL_BAG
Definition Unit.h:61
@ NULL_SLOT
Definition Unit.h:62
@ ITEM_FIELD_DURABILITY
@ ITEM_FIELD_MAXDURABILITY
@ ITEM_FIELD_CREATOR
@ ITEM_FIELD_GIFTCREATOR
@ ITEM_FIELD_CREATE_PLAYED_TIME
Definition Item.h:62
bool CanBeTraded(bool mail=false, bool trade=false) const
Definition Item.cpp:721
ItemTemplate const * GetTemplate() const
Definition Item.cpp:535
bool IsBindedNotWith(Player const *player) const
Definition Item.cpp:1087
uint32 GetCount() const
Definition Item.h:119
void SetInTrade(bool b=true)
Definition Item.h:107
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:249
void SetGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:699
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:585
uint32 GetTeam() const
Definition Player.h:1832
uint32 GetTotalPlayedTime() const
Definition Player.h:1036
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition Player.cpp:9994
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans)
Definition Player.cpp:19311
InventoryResult CanStoreItems(Item **items, int count, uint32 *itemLimitCategory) const
Definition Player.cpp:10658
bool ModifyMoney(int32 amount, bool sendError=true)
Definition Player.cpp:22339
TradeData * m_trade
Definition Player.h:2435
WorldSession * GetSession() const
Definition Player.h:1719
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9552
void TradeCancel(bool sendback, TradeStatus status=TRADE_STATUS_TRADE_CANCELED)
Definition Player.cpp:13232
bool HasEnoughMoney(uint32 amount) const
Definition Player.h:1410
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:12068
void MoveItemToInventory(ItemPosCountVec const &dest, Item *pItem, bool update, bool in_characterInventoryDB=false)
Definition Player.cpp:12085
Player * GetTrader() const
Definition Player.cpp:23192
TradeData * GetTradeData() const
Definition Player.h:1210
uint32 GetMoney() const
Definition Player.h:1408
void SetTradeItemTarget(Player *caster)
Definition Spell.cpp:317
Definition Spell.h:152
SpellCastTargets m_targets
Definition Spell.h:402
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3070
Item * m_CastItem
Definition Spell.h:396
SpellCastResult CheckCast(bool strict, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:5178
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:4177
Item * GetSpellCastItem() const
Definition TradeData.cpp:51
void SetMoney(uint32 money)
Definition TradeData.cpp:97
bool HasSpellCastItem() const
Definition TradeData.h:53
void SetSpell(uint32 spell_id, Item *castItem=nullptr)
Definition TradeData.cpp:80
Player * GetTrader() const
Definition TradeData.h:41
bool HasItem(ObjectGuid itemGuid) const
Definition TradeData.cpp:33
void SetItem(TradeSlots slot, Item *item, bool update=false)
Definition TradeData.cpp:56
void SetInAcceptProcess(bool state)
Definition TradeData.h:62
uint32 GetMoney() const
Definition TradeData.h:55
void SetAccepted(bool state, bool forTrader=false)
Item * GetItem(TradeSlots slot) const
Definition TradeData.cpp:28
bool IsAccepted() const
Definition TradeData.h:58
TradeData * GetTraderData() const
Definition TradeData.cpp:23
uint32 GetSpell() const
Definition TradeData.h:49
bool IsAlive() const
Definition Unit.h:1234
bool IsInFlight() const
Definition Unit.h:1119
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
std::string const & GetName() const
Definition Object.h:382
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1192
char const * GetTrinityString(uint32 entry) const
void moveItems(Item *myItems[], Item *hisItems[])
void SendTradeStatus(TradeStatusInfo const &status)
void HandleIgnoreTradeOpcode(WorldPacket &recvPacket)
bool isLogingOut() const
Is the user engaged in a log out process?
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
void SendNotification(const char *format,...) ATTR_PRINTF(2
void HandleClearTradeItemOpcode(WorldPacket &recvPacket)
void HandleSetTradeItemOpcode(WorldPacket &recvPacket)
void HandleUnacceptTradeOpcode(WorldPacket &recvPacket)
bool PlayerRecentlyLoggedOut() const
bool PlayerLogout() const
void HandleSetTradeGoldOpcode(WorldPacket &recvPacket)
Player * GetPlayer() const
void HandleBusyTradeOpcode(WorldPacket &recvPacket)
void SendCancelTrade(TradeStatus status)
void HandleBeginTradeOpcode(WorldPacket &recvPacket)
void HandleCancelTradeOpcode(WorldPackets::Trade::CancelTrade &cancelTrade)
bool HasPermission(uint32 permissionId)
void HandleAcceptTradeOpcode(WorldPacket &recvPacket)
uint32 GetAccountId() const
Player * _player
void HandleInitiateTradeOpcode(WorldPacket &recvPacket)
void SendUpdateTrade(bool trader_data=true)
@ SMSG_TRADE_STATUS
Definition Opcodes.h:317
@ SMSG_TRADE_STATUS_EXTENDED
Definition Opcodes.h:318
#define sWorld
Definition World.h:900
@ CONFIG_TRADE_LEVEL_REQ
Definition World.h:301
@ CONFIG_ALLOW_TWO_SIDE_TRADE
Definition World.h:101
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
std::string Name1
bool IsTargetResult
Definition Player.h:879
TradeStatus Status
Definition Player.h:876
uint32 ItemLimitCategoryId
Definition Player.h:880
InventoryResult Result
Definition Player.h:878
ObjectGuid TraderGuid
Definition Player.h:877