Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
AuctionHouseHandler.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "ObjectMgr.h"
7#include "Player.h"
8#include "World.h"
9#include "WorldPacket.h"
10#include "WorldSession.h"
11
12#include "AccountMgr.h"
13#include "AuctionHouseMgr.h"
14#include "Language.h"
15#include "Log.h"
16#include "Opcodes.h"
17#include "UpdateMask.h"
18#include "Util.h"
19
20//void called when player click on auctioneer npc
22{
23 SF_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_HELLO_REQUEST");
24
25 ObjectGuid guid; //NPC guid
26
27 recvData.ReadGuidMask(guid, 1, 5, 2, 0, 3, 6, 4, 7);
28 recvData.ReadGuidBytes(guid, 2, 7, 1, 3, 5, 0, 4, 6);
29
31 if (!unit)
32 {
33 SF_LOG_DEBUG("network", "WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
34 return;
35 }
36
37 // remove fake death
38 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
40
41 SendAuctionHello(guid, unit);
42}
43
44//this void causes that auction window is opened
46{
47 if (GetPlayer()->getLevel() < sWorld->getIntConfig(WorldIntConfigs::CONFIG_AUCTION_LEVEL_REQ))
48 {
50 return;
51 }
52
54 if (!ahEntry)
55 return;
56
57 WorldPacket data(SMSG_AUCTION_HELLO, 1 + 1 + 8 + 4);
58 data.WriteBit(guid[6]);
59 data.WriteBit(guid[7]);
60 data.WriteBit(guid[3]);
61 data.WriteBit(1); // 1 - AH enabled, 0 - AH disabled
62 data.WriteBit(guid[4]);
63 data.WriteBit(guid[2]);
64 data.WriteBit(guid[5]);
65 data.WriteBit(guid[0]);
66 data.WriteBit(guid[1]);
67 data.FlushBits();
68
69 data.WriteByteSeq(guid[3]);
70 data << uint32(ahEntry->houseId);
71 data.WriteByteSeq(guid[4]);
72 data.WriteByteSeq(guid[2]);
73 data.WriteByteSeq(guid[7]);
74 data.WriteByteSeq(guid[1]);
75 data.WriteByteSeq(guid[0]);
76 data.WriteByteSeq(guid[6]);
77 data.WriteByteSeq(guid[5]);
78
79 SendPacket(&data);
80}
81
82//call this method when player bids, creates, or deletes auction
83void WorldSession::SendAuctionCommandResult(AuctionEntry* auction, uint32 action, uint32 errorCode, uint32 bidError)
84{
85 ObjectGuid guid = GetPlayer()->GetGUID();
86
87 WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 1 + 1 + 8 + 4 + 4 + 4 + 4 + 8 + 8);
88 data.WriteBit(1);
89 data.WriteBit(1);
90 data.WriteBit(1);
91
92 data.WriteBit(guid[1]);
93 data.WriteBit(guid[4]);
94 data.WriteBit(guid[0]);
95 data.WriteBit(guid[6]);
96 data.WriteBit(guid[3]);
97 data.WriteBit(guid[5]);
98 data.WriteBit(guid[2]);
99 data.WriteBit(guid[7]);
100 data.FlushBits();
101
102 data.WriteByteSeq(guid[3]);
103 data.WriteByteSeq(guid[0]);
104 data.WriteByteSeq(guid[7]);
105 data.WriteByteSeq(guid[1]);
106 data.WriteByteSeq(guid[4]);
107 data.WriteByteSeq(guid[6]);
108 data.WriteByteSeq(guid[5]);
109 data.WriteByteSeq(guid[2]);
110
111 data << uint32(errorCode);
112 data << uint32(action);
113 data << uint32(auction ? auction->Id : 0);
114 data << uint32(40); // bag result
115
116 SendPacket(&data);
117
118 /*data << uint32(auction ? auction->Id : 0);
119 data << uint32(action);
120 data << uint32(errorCode);
121
122 switch (errorCode)
123 {
124 case ERR_AUCTION_OK:
125 if (action == AUCTION_PLACE_BID)
126 data << uint64(auction->bid ? auction->GetAuctionOutBid() : 0);
127 break;
128 case ERR_AUCTION_INVENTORY:
129 data << uint32(bidError);
130 break;
131 case ERR_AUCTION_HIGHER_BID:
132 data << uint64(auction->bidder);
133 data << uint64(auction->bid);
134 data << uint64(auction->bid ? auction->GetAuctionOutBid() : 0);
135 break;
136 }*/
137}
138
139//this function sends notification, if bidder is online
140void WorldSession::SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 itemEntry)
141{
142 ObjectGuid guid = bidder;
143
144 WorldPacket data(SMSG_AUCTION_BIDDER_NOTIFICATION, 1 + 8 + 4 + 4 + 4 + 4 + 4);
145 data.WriteGuidMask(guid, 5, 4, 7, 6, 0, 1, 2, 3);
146
147 data.WriteGuidBytes(guid, 7, 3);
148 data << uint32(itemEntry);
149 data.WriteGuidBytes(guid, 1, 2);
150 data << uint32(location);
151 data.WriteGuidBytes(guid, 0);
152 data << uint32(0);
153 data.WriteGuidBytes(guid, 5, 4, 6);
154 data << uint32(0);
155 data << uint32(auctionId);
156
157 SendPacket(&data);
158}
159
160// this void causes on client to display: "Your auction sold"
162{
163 WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, 4 + 4 + 4 + 4 + 4 + 8 + 1);
164 data << uint32(0);
165 data << uint32(auction->Id);
166 data << uint32(auction->itemEntry);
167 data << uint32(0);
168 data << float(3600); // mail delay
169 data << uint64(auction->bid);
170
171 data.WriteBit(1); // sold
172 data.FlushBits();
173
174 SendPacket(&data);
175}
176
177void WorldSession::SendAuctionRemovedNotification(uint32 auctionId, uint32 itemEntry, int32 randomPropertyId)
178{
180 data << uint32(auctionId);
181 data << uint32(itemEntry);
182 data << uint32(randomPropertyId);
183 SendPacket(&data);
184}
185
186//this void creates new auction and adds auction to some auctionhouse
188{
189 ObjectGuid auctioneer;
190 uint64 bid, buyout;
191 uint32 etime;
192 uint8 itemCount;
193
194 // 32 slots, value sent as 5 bits
195 ObjectGuid itemGuids[MAX_AUCTION_ITEMS];
197
198 recvData >> buyout >> bid;
199 recvData >> etime;
200
201 if (!bid || !etime)
202 {
203 recvData.rfinish();
204 return;
205 }
206
207 if (bid > MAX_MONEY_AMOUNT || buyout > MAX_MONEY_AMOUNT)
208 {
209 SF_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Player %s (GUID %u) attempted to sell item with higher price than max gold amount.", _player->GetName().c_str(), _player->GetGUIDLow());
211 recvData.rfinish();
212 return;
213 }
214
215 auctioneer[3] = recvData.ReadBit();
216 itemCount = recvData.ReadBits(5);
217
218 if (itemCount > MAX_AUCTION_ITEMS)
219 {
221 recvData.rfinish();
222 return;
223 }
224
225 auctioneer[0] = recvData.ReadBit();
226
227 for (uint8 i = 0; i < itemCount; i++)
228 {
229 itemGuids[i][4] = recvData.ReadBit();
230 itemGuids[i][6] = recvData.ReadBit();
231 itemGuids[i][2] = recvData.ReadBit();
232 itemGuids[i][3] = recvData.ReadBit();
233 itemGuids[i][5] = recvData.ReadBit();
234 itemGuids[i][7] = recvData.ReadBit();
235 itemGuids[i][1] = recvData.ReadBit();
236 itemGuids[i][0] = recvData.ReadBit();
237 }
238
239 auctioneer[6] = recvData.ReadBit();
240 auctioneer[2] = recvData.ReadBit();
241 auctioneer[1] = recvData.ReadBit();
242 auctioneer[4] = recvData.ReadBit();
243 auctioneer[5] = recvData.ReadBit();
244 auctioneer[7] = recvData.ReadBit();
245
246 for (uint8 i = 0; i < itemCount; i++)
247 {
248 recvData.ReadByteSeq(itemGuids[i][3]);
249 recvData.ReadByteSeq(itemGuids[i][1]);
250 recvData >> count[i];
251 recvData.ReadByteSeq(itemGuids[i][6]);
252 recvData.ReadByteSeq(itemGuids[i][4]);
253 recvData.ReadByteSeq(itemGuids[i][5]);
254 recvData.ReadByteSeq(itemGuids[i][0]);
255 recvData.ReadByteSeq(itemGuids[i][2]);
256 recvData.ReadByteSeq(itemGuids[i][7]);
257
258 if (!itemGuids[i] || !count[i] || count[i] > 1000)
259 {
260 recvData.rfinish();
261 return;
262 }
263 }
264
265 recvData.ReadByteSeq(auctioneer[3]);
266 recvData.ReadByteSeq(auctioneer[7]);
267 recvData.ReadByteSeq(auctioneer[2]);
268 recvData.ReadByteSeq(auctioneer[5]);
269 recvData.ReadByteSeq(auctioneer[6]);
270 recvData.ReadByteSeq(auctioneer[1]);
271 recvData.ReadByteSeq(auctioneer[0]);
272 recvData.ReadByteSeq(auctioneer[4]);
273
275 if (!creature)
276 {
277 SF_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(auctioneer));
278 return;
279 }
280
281 AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction());
282 if (!auctionHouseEntry)
283 {
284 SF_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", GUID_LOPART(auctioneer));
285 return;
286 }
287
288 etime *= MINUTE;
289
290 switch (etime)
291 {
292 case 1 * MIN_AUCTION_TIME:
293 case 2 * MIN_AUCTION_TIME:
294 case 4 * MIN_AUCTION_TIME:
295 break;
296 default:
297 return;
298 }
299
300 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
302
303 Item* items[MAX_AUCTION_ITEMS];
304
305 uint32 finalCount = 0;
306
307 for (uint32 i = 0; i < itemCount; ++i)
308 {
309 Item* item = _player->GetItemByGuid(itemGuids[i]);
310
311 if (!item)
312 {
314 return;
315 }
316
317 if (sAuctionMgr->GetAItem(item->GetGUIDLow()) || !item->CanBeTraded() || item->IsNotEmptyBag() ||
319 item->GetCount() < count[i])
320 {
322 return;
323 }
324
325 items[i] = item;
326 finalCount += count[i];
327 }
328
329 if (!finalCount)
330 {
332 return;
333 }
334
335 for (uint32 i = 0; i < itemCount; ++i)
336 {
337 Item* item = items[i];
338
339 if (item->GetMaxStackCount() < finalCount)
340 {
342 return;
343 }
344 }
345
346 Item* item = items[0];
347
348 uint32 auctionTime = uint32(etime * sWorld->getRate(Rates::RATE_AUCTION_TIME));
349 AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
350
351 uint64 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount);
352 if (!_player->HasEnoughMoney((uint64)deposit))
353 {
355 return;
356 }
357
358 AuctionEntry* AH = new AuctionEntry();
359
361 AH->auctioneer = 23442;
362 else
363 AH->auctioneer = GUID_LOPART(auctioneer);
364
365 // Required stack size of auction matches to current item stack size, just move item to auctionhouse
366 if (itemCount == 1 && item->GetCount() == count[0])
367 {
369 {
370 sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
371 GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount());
372 }
373
374 AH->Id = sObjectMgr->GenerateAuctionID();
375 AH->itemGUIDLow = item->GetGUIDLow();
376 AH->itemEntry = item->GetEntry();
377 AH->itemCount = item->GetCount();
378 AH->owner = _player->GetGUIDLow();
379 AH->startbid = bid;
380 AH->bidder = 0;
381 AH->bid = 0;
382 AH->buyout = buyout;
383 AH->expire_time = time(NULL) + auctionTime;
384 AH->deposit = deposit;
385 AH->auctionHouseEntry = auctionHouseEntry;
386
387 SF_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) "
388 "to auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u",
389 _player->GetName().c_str(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(),
390 AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
391 sAuctionMgr->AddAItem(item);
392 auctionHouse->AddAuction(AH);
393
394 _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
395
396 SQLTransaction trans = CharacterDatabase.BeginTransaction();
397 item->DeleteFromInventoryDB(trans);
398 item->SaveToDB(trans);
399 AH->SaveToDB(trans);
400 _player->SaveInventoryAndGoldToDB(trans);
401 CharacterDatabase.CommitTransaction(trans);
402
404
406 }
407 else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size
408 {
409 Item* newItem = item->CloneItem(finalCount, _player);
410 if (!newItem)
411 {
412 SF_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry());
414 delete AH;
415 return;
416 }
417
419 {
420 sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
421 GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount());
422 }
423
424 AH->Id = sObjectMgr->GenerateAuctionID();
425 AH->itemGUIDLow = newItem->GetGUIDLow();
426 AH->itemEntry = newItem->GetEntry();
427 AH->itemCount = newItem->GetCount();
428 AH->owner = _player->GetGUIDLow();
429 AH->startbid = bid;
430 AH->bidder = 0;
431 AH->bid = 0;
432 AH->buyout = buyout;
433 AH->expire_time = time(NULL) + auctionTime;
434 AH->deposit = deposit;
435 AH->auctionHouseEntry = auctionHouseEntry;
436
437 SF_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to "
438 "auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u",
439 _player->GetName().c_str(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(),
440 newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
441 sAuctionMgr->AddAItem(newItem);
442 auctionHouse->AddAuction(AH);
443
444 for (uint32 j = 0; j < itemCount; ++j)
445 {
446 Item* item2 = items[j];
447
448 // Item stack count equals required count, ready to delete item - cloned item will be used for auction
449 if (item2->GetCount() == count[j])
450 {
451 _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true);
452
453 SQLTransaction trans = CharacterDatabase.BeginTransaction();
454 item2->DeleteFromInventoryDB(trans);
455 item2->DeleteFromDB(trans);
456 CharacterDatabase.CommitTransaction(trans);
457 }
458 else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction
459 {
460 item2->SetCount(item2->GetCount() - count[j]);
462 _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]);
464
465 SQLTransaction trans = CharacterDatabase.BeginTransaction();
466 item2->SaveToDB(trans);
467 CharacterDatabase.CommitTransaction(trans);
468 }
469 }
470
471 SQLTransaction trans = CharacterDatabase.BeginTransaction();
472 newItem->SaveToDB(trans);
473 AH->SaveToDB(trans);
474 _player->SaveInventoryAndGoldToDB(trans);
475 CharacterDatabase.CommitTransaction(trans);
476
478
480 }
481
482 _player->ModifyMoney(-int32(deposit));
483}
484
485// this function is called when client bids or buys out auction
487{
488 SF_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_PLACE_BID");
489
490 ObjectGuid auctioneer;
491 uint32 auctionId;
492 uint64 price;
493
494 recvData >> auctionId;
495 recvData >> price;
496
497 recvData.ReadGuidMask(auctioneer, 1, 6, 3, 7, 2, 4, 0, 5);
498 recvData.ReadGuidBytes(auctioneer, 3, 2, 1, 4, 6, 5, 7, 0);
499
500 if (!auctionId || !price)
501 return; // check for cheaters
502
504 if (!creature)
505 {
506 SF_LOG_DEBUG("network", "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)));
507 return;
508 }
509
510 // remove fake death
511 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
513
514 AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
515
516 AuctionEntry* auction = auctionHouse->GetAuction(auctionId);
517 Player* player = GetPlayer();
518
519 if (!auction || auction->owner == player->GetGUIDLow())
520 {
521 //you cannot bid your own auction:
523 return;
524 }
525
526 // impossible have online own another character (use this for speedup check in case online owner)
527 /*Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER));
528 if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == player->GetSession()->GetAccountId())
529 {
530 //you cannot bid your another character auction:
531 SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN);
532 return;
533 }*/
534
535 // cheating
536 if (price <= auction->bid || price < auction->startbid)
537 return;
538
539 // price too low for next bid if not buyout
540 if ((price < auction->buyout || auction->buyout == 0) &&
541 price < auction->bid + auction->GetAuctionOutBid())
542 {
543 // client already test it but just in case ...
545 return;
546 }
547
548 if (!player->HasEnoughMoney(price))
549 {
550 // client already test it but just in case ...
552 return;
553 }
554
555 SQLTransaction trans = CharacterDatabase.BeginTransaction();
556
557 if (price < auction->buyout || auction->buyout == 0)
558 {
559 if (auction->bidder > 0)
560 {
561 if (auction->bidder == player->GetGUIDLow())
562 player->ModifyMoney(-int64(price - auction->bid));
563 else
564 {
565 // mail to last bidder and return money
566 sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans);
567 player->ModifyMoney(-int64(price));
568 }
569 }
570 else
571 player->ModifyMoney(-int64(price));
572
573 auction->bidder = player->GetGUIDLow();
574 auction->bid = price;
576
577 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID);
578 stmt->setUInt32(0, auction->bidder);
579 stmt->setUInt64(1, auction->bid);
580 stmt->setUInt32(2, auction->Id);
581 trans->Append(stmt);
582
584 }
585 else
586 {
587 //buyout:
588 if (player->GetGUIDLow() == auction->bidder)
589 player->ModifyMoney(-int64(auction->buyout - auction->bid));
590 else
591 {
592 player->ModifyMoney(-int64(auction->buyout));
593 if (auction->bidder) //buyout for bidded auction ..
594 sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans);
595 }
596 auction->bidder = player->GetGUIDLow();
597 auction->bid = auction->buyout;
599
600 //- Mails must be under transaction control too to prevent data loss
601 sAuctionMgr->SendAuctionSalePendingMail(auction, trans);
602 sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
603 sAuctionMgr->SendAuctionWonMail(auction, trans);
604
606
607 auction->DeleteFromDB(trans);
608
609 uint32 itemEntry = auction->itemEntry;
610 sAuctionMgr->RemoveAItem(auction->itemGUIDLow);
611 auctionHouse->RemoveAuction(auction, itemEntry);
612 }
613 player->SaveInventoryAndGoldToDB(trans);
614 CharacterDatabase.CommitTransaction(trans);
615}
616
617//this void is called when auction_owner cancels his auction
619{
620 SF_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_REMOVE_ITEM");
621
622 ObjectGuid auctioneer;
623 uint32 auctionId;
624
625 recvData >> auctionId;
626
627 recvData.ReadGuidMask(auctioneer, 6, 4, 2, 3, 7, 5, 1, 0);
628 recvData.ReadGuidBytes(auctioneer, 3, 2, 6, 5, 4, 7, 0, 1);
629
631 if (!creature)
632 {
633 SF_LOG_DEBUG("network", "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)));
634 return;
635 }
636
637 // remove fake death
638 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
640
641 AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
642
643 AuctionEntry* auction = auctionHouse->GetAuction(auctionId);
644 Player* player = GetPlayer();
645
646 SQLTransaction trans = CharacterDatabase.BeginTransaction();
647 if (auction && auction->owner == player->GetGUIDLow())
648 {
649 Item* pItem = sAuctionMgr->GetAItem(auction->itemGUIDLow);
650 if (pItem)
651 {
652 if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid
653 {
654 uint32 auctionCut = auction->GetAuctionCut();
655 if (!player->HasEnoughMoney((uint64)auctionCut)) //player doesn't have enough money, maybe message needed
656 return;
657 sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans, pItem);
658 player->ModifyMoney(-int64(auctionCut));
659 }
660
661 // item will deleted or added to received mail list
663 .AddItem(pItem)
664 .SendMailTo(trans, player, auction, MAIL_CHECK_MASK_COPIED);
665 }
666 else
667 {
668 SF_LOG_ERROR("network", "Auction id: %u got non existing item (item guid : %u)!", auction->Id, auction->itemGUIDLow);
670 return;
671 }
672 }
673 else
674 {
676 //this code isn't possible ... maybe there should be assert
677 SF_LOG_ERROR("network", "CHEATER: %u tried to cancel auction (id: %u) of another player or auction is NULL", player->GetGUIDLow(), auctionId);
678 return;
679 }
680
681 //inform player, that auction is removed
683
684 // Now remove the auction
685
686 player->SaveInventoryAndGoldToDB(trans);
687 auction->DeleteFromDB(trans);
688 CharacterDatabase.CommitTransaction(trans);
689
690 uint32 itemEntry = auction->itemEntry;
691 sAuctionMgr->RemoveAItem(auction->itemGUIDLow);
692 auctionHouse->RemoveAuction(auction, itemEntry);
693}
694
695//called when player lists his bids
697{
698 SF_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_LIST_BIDDER_ITEMS");
699
700 ObjectGuid auctioneer;
701 uint32 listFrom; // page of auctions
702 uint8 outbiddedCount; // count of outbidded auctions
703 uint32 outbiddedAuctionIds[128];
704
705 recvData >> listFrom; // not used in fact (this list not have page control in client)
706
707 recvData.ReadGuidMask(auctioneer, 3, 4, 1, 5, 6, 2);
708 outbiddedCount = recvData.ReadBits(7);
709 recvData.ReadGuidMask(auctioneer, 7, 0);
710
711 recvData.ReadGuidBytes(auctioneer, 3, 4, 1, 0, 2, 5);
712
713 for (uint8 i = 0; i < outbiddedCount; i++)
714 recvData >> outbiddedAuctionIds[i];
715
716 recvData.ReadGuidBytes(auctioneer, 7, 6);
717
718 /*if (recvData.size() != (16 + outbiddedCount * 4))
719 {
720 SF_LOG_ERROR("network", "Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)", outbiddedCount, (unsigned long)recvData.size(), (16 + outbiddedCount * 4));
721 outbiddedCount = 0;
722 }*/
723
725 if (!creature)
726 {
727 SF_LOG_DEBUG("network", "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)));
728 recvData.rfinish();
729 return;
730 }
731
732 // remove fake death
733 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
735
736 AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
737
738 uint32 count = 0;
739 uint32 totalcount = 0;
740
741 WorldPacket data(SMSG_AUCTION_BIDDER_LIST_RESULT, 500); // guess size
742 data << uint32(0); // amount place holder
743
744 for (uint8 i = 0; i < outbiddedCount; i++)
745 {
746 AuctionEntry* auction = auctionHouse->GetAuction(outbiddedAuctionIds[i]);
747 if (auction && auction->BuildAuctionInfo(data))
748 {
749 ++totalcount;
750 ++count;
751 }
752 }
753
754 auctionHouse->BuildListBidderItems(data, GetPlayer(), count, totalcount);
755 data.put<uint32>(0, count); // add count to placeholder
756 data << totalcount;
758 SendPacket(&data);
759}
760
761//this void sends player info about his auctions
763{
764 SF_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_LIST_OWNER_ITEMS");
765
766 uint32 listfrom;
767 ObjectGuid auctioneer;
768
769 recvData >> listfrom; // not used in fact (this list not have page control in client)
770
771 recvData.ReadGuidMask(auctioneer, 4, 5, 2, 1, 7, 0, 3, 6);
772 recvData.ReadGuidBytes(auctioneer, 5, 7, 3, 6, 4, 2, 0, 1);
773
775 if (!creature)
776 {
777 SF_LOG_DEBUG("network", "WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)));
778 return;
779 }
780
781 // remove fake death
782 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
784
785 AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
786
787 uint32 count = 0;
788 uint32 totalcount = 0;
789
790 WorldPacket data(SMSG_AUCTION_OWNER_LIST_RESULT, 500); // guess size
791 data << uint32(0); // amount place holder
792
793 auctionHouse->BuildListOwnerItems(data, _player, count, totalcount);
794 data.put<uint32>(0, count);
795 data << uint32(totalcount);
797 SendPacket(&data);
798}
799
800//this void is called when player clicks on search button
802{
803 SF_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_LIST_ITEMS");
804
805 ObjectGuid auctioneer;
806 std::string searchString;
807 uint8 levelMin, levelMax, searchStringLen;
808 uint32 listFrom, auctionSlotId, auctionMainCategory, auctionSubCategory, quality, sortCount;
809 bool usableItems, exactMatch;
810
811 recvData >> auctionSlotId;
812 recvData >> listFrom; // start, used for page control listing by 50 elements
813 recvData >> auctionMainCategory;
814 recvData.read_skip<uint8>();
815 recvData >> levelMax >> levelMin;
816 recvData >> quality;
817 recvData >> auctionSubCategory;
818 recvData >> sortCount;
819
820 // this block looks like it uses some lame byte packing or similar...
821 for (uint8 i = 0; i < sortCount; i++)
822 recvData.read_skip<uint8>(); // sorts currently unhandled
823
824 recvData.ReadGuidMask(auctioneer, 3, 4, 5, 2);
825 exactMatch = recvData.ReadBit();
826 usableItems = recvData.ReadBit();
827 recvData.ReadGuidMask(auctioneer, 7, 0);
828 searchStringLen = recvData.ReadBits(8);
829 recvData.ReadGuidMask(auctioneer, 1, 6);
830
831 recvData.ReadGuidBytes(auctioneer, 6, 3, 4, 0, 7, 2);
832 searchString = recvData.ReadString(searchStringLen);
833 recvData.ReadGuidBytes(auctioneer, 1, 5);
834
836 if (!creature)
837 {
838 SF_LOG_DEBUG("network", "WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)));
839 return;
840 }
841
842 // remove fake death
843 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
845
846 AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
847
848 //SF_LOG_DEBUG("misc", "Auctionhouse search (GUID: %u TypeId: %u)",, list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u",
849 // GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid)), listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable);
850
851 uint32 count = 0;
852 uint32 totalcount = 0;
853
854 WorldPacket data(SMSG_AUCTION_LIST_RESULT, 500); // guess size
855 data << uint32(0); // amount place holder
856
857 // converting string that we try to find to lower case
858 std::wstring wsearchedname;
859 if (!Utf8toWStr(searchString, wsearchedname))
860 return;
861
862 wstrToLower(wsearchedname);
863
864 auctionHouse->BuildListAuctionItems(data, _player,
865 wsearchedname, listFrom, levelMin, levelMax, usableItems,
866 auctionSlotId, auctionMainCategory, auctionSubCategory, quality,
867 count, totalcount);
868
869 data.put<uint32>(0, count);
870 data << uint32(totalcount);
872 SendPacket(&data);
873}
874
876{
877 SF_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_LIST_PENDING_SALES");
878
879 uint32 count = 0;
880
882 data << uint32(count); // count
883 /*for (uint32 i = 0; i < count; ++i)
884 {
885 data << ""; // string
886 data << ""; // string
887 data << uint64(0);
888 data << uint32(0);
889 data << float(0);
890 }*/
891 SendPacket(&data);
892}
#define AUCTION_SEARCH_DELAY
#define MIN_AUCTION_TIME
@ AUCTION_SELL_ITEM
@ AUCTION_PLACE_BID
@ AUCTION_CANCEL
#define MAX_AUCTION_ITEMS
#define sAuctionMgr
@ ERR_AUCTION_NOT_ENOUGHT_MONEY
@ ERR_AUCTION_OK
@ ERR_AUCTION_HIGHER_BID
@ ERR_AUCTION_BID_OWN
@ ERR_AUCTION_ITEM_NOT_FOUND
@ ERR_AUCTION_DATABASE_ERROR
@ CHAR_UPD_AUCTION_BID
@ MINUTE
Definition Common.h:119
@ ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION
Definition DBCEnums.h:243
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID
Definition DBCEnums.h:244
std::int32_t int32
Definition Define.h:73
#define UI64FMTD
Definition Define.h:64
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
std::int64_t int64
Definition Define.h:72
@ ITEM_CHANGED
Definition Item.h:192
@ ITEM_PROTO_FLAG_CONJURED
@ LANG_AUCTION_REQ
Definition Language.h:1113
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
#define sLog
Definition Log.h:106
@ MAIL_CHECK_MASK_COPIED
This mail was returned. Do not allow returning mail back again.
Definition Mail.h:37
uint32 GUID_LOPART(uint64 x)
#define sObjectMgr
Definition ObjectMgr.h:1617
#define MAX_MONEY_AMOUNT
Definition Player.h:927
@ SPELL_AURA_FEIGN_DEATH
Skyfire::AutoPtr< Transaction, Skyfire::Mutex > SQLTransaction
Definition Transaction.h:42
@ UNIT_NPC_FLAG_AUCTIONEER
Definition Unit.h:708
@ UNIT_STATE_DIED
Definition Unit.h:512
@ ITEM_FIELD_EXPIRATION
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition Util.cpp:305
void wstrToLower(std::wstring &str)
Definition Util.h:314
static AuctionHouseEntry const * GetAuctionHouseEntry(uint32 factionTemplateId)
void BuildListBidderItems(WorldPacket &data, Player *player, uint32 &count, uint32 &totalcount)
void BuildListAuctionItems(WorldPacket &data, Player *player, std::wstring const &searchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32 &count, uint32 &totalcount)
AuctionEntry * GetAuction(uint32 id) const
void AddAuction(AuctionEntry *auction)
void BuildListOwnerItems(WorldPacket &data, Player *player, uint32 &count, uint32 &totalcount)
bool RemoveAuction(AuctionEntry *auction, uint32 itemEntry)
void WriteGuidBytes(const ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:264
bool WriteBit(uint32 bit)
Definition ByteBuffer.h:164
void read_skip()
Definition ByteBuffer.h:502
void put(size_t pos, T value)
Definition ByteBuffer.h:233
void WriteGuidMask(const ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:248
uint32 ReadBits(size_t bits)
Definition ByteBuffer.h:198
void ReadGuidBytes(ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:256
void ReadByteSeq(uint8 &b)
Definition ByteBuffer.h:215
void rfinish()
Definition ByteBuffer.h:478
std::string ReadString(size_t length)
Definition ByteBuffer.h:565
void ReadGuidMask(ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:240
void WriteByteSeq(uint8 b)
Definition ByteBuffer.h:227
void FlushBits()
Definition ByteBuffer.h:154
bool ReadBit()
Definition ByteBuffer.h:180
Definition Item.h:202
uint8 GetSlot() const
Definition Item.h:265
void SetState(ItemUpdateState state, Player *forplayer=NULL)
Definition Item.cpp:667
Item * CloneItem(uint32 count, Player const *player=NULL) const
Definition Item.cpp:1039
bool CanBeTraded(bool mail=false, bool trade=false) const
Definition Item.cpp:744
virtual void SaveToDB(SQLTransaction &trans)
Definition Item.cpp:305
void SetCount(uint32 value)
Definition Item.h:259
ItemTemplate const * GetTemplate() const
Definition Item.cpp:528
static void DeleteFromInventoryDB(SQLTransaction &trans, uint32 itemGuid)
Definition Item.cpp:516
bool IsNotEmptyBag() const
Definition Item.cpp:280
uint32 GetCount() const
Definition Item.h:258
uint8 GetBagSlot() const
Definition Item.cpp:734
uint32 GetMaxStackCount() const
Definition Item.h:260
static void DeleteFromDB(SQLTransaction &trans, uint32 itemGuid)
Definition Item.cpp:499
void SendMailTo(SQLTransaction &trans, MailReceiver const &receiver, MailSender const &sender, MailCheckMask checked=MAIL_CHECK_MASK_NONE, uint32 deliver_delay=0)
Definition Mail.cpp:162
MailDraft & AddItem(Item *item)
Definition Mail.cpp:70
uint64 GetGUID() const
Definition Object.h:119
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:325
uint32 GetGUIDLow() const
Definition Object.h:120
uint32 GetEntry() const
Definition Object.h:125
void SendUpdateToPlayer(Player *player)
Definition Object.cpp:259
void SaveInventoryAndGoldToDB(SQLTransaction &trans)
Definition Player.cpp:14609
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:18342
Creature * GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask)
Definition Player.cpp:2836
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, Unit *unit=NULL)
Definition Player.cpp:21033
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1950
void setUInt64(const uint8 index, const uint64 value)
void setUInt32(const uint8 index, const uint32 value)
uint32 getFaction() const
Definition Unit.h:1695
void RemoveAurasByType(AuraType auraType, uint64 casterGUID=0, Aura *except=NULL, bool negative=true, bool positive=true)
void SendAuctionHello(ObjectGuid guid, Creature *unit)
void HandleAuctionListPendingSales(WorldPacket &recvData)
void HandleAuctionListItems(WorldPacket &recvData)
void HandleAuctionListOwnerItems(WorldPacket &recvData)
const char * GetSkyFireString(int32 entry) const
void SendNotification(const char *format,...) ATTR_PRINTF(2
void SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template)
void SendAuctionRemovedNotification(uint32 auctionId, uint32 itemEntry, int32 randomPropertyId)
void HandleAuctionSellItem(WorldPacket &recvData)
void SendAuctionOwnerNotification(AuctionEntry *auction)
Player * GetPlayer() const
void SendAuctionCommandResult(AuctionEntry *auction, uint32 Action, uint32 ErrorCode, uint32 bidError=0)
void HandleAuctionHelloOpcode(WorldPacket &recvPacket)
bool HasPermission(uint32 permissionId)
void HandleAuctionListBidderItems(WorldPacket &recvData)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetAccountId() const
Player * _player
void HandleAuctionRemoveItem(WorldPacket &recvData)
void HandleAuctionPlaceBid(WorldPacket &recvData)
std::string const & GetPlayerName() const
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
@ SMSG_AUCTION_HELLO
Definition Opcodes.h:526
@ SMSG_AUCTION_BIDDER_LIST_RESULT
Definition Opcodes.h:523
@ SMSG_AUCTION_BIDDER_NOTIFICATION
Definition Opcodes.h:524
@ SMSG_AUCTION_LIST_RESULT
Definition Opcodes.h:528
@ SMSG_AUCTION_COMMAND_RESULT
Definition Opcodes.h:525
@ SMSG_AUCTION_REMOVED_NOTIFICATION
Definition Opcodes.h:531
@ SMSG_AUCTION_OWNER_LIST_RESULT
Definition Opcodes.h:529
@ SMSG_AUCTION_LIST_PENDING_SALES
Definition Opcodes.h:527
@ SMSG_AUCTION_OWNER_NOTIFICATION
Definition Opcodes.h:530
#define sWorld
Definition World.h:910
@ CONFIG_AUCTION_LEVEL_REQ
Definition World.h:282
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION
Definition World.h:100
@ RATE_AUCTION_TIME
Definition World.h:427
@ RBAC_PERM_LOG_GM_TRADE
Definition RBAC.h:51
bool BuildAuctionInfo(WorldPacket &data) const
uint32 itemEntry
uint64 deposit
AuctionHouseEntry const * auctionHouseEntry
uint32 itemGUIDLow
uint32 GetHouseId() const
uint32 bidder
uint32 auctioneer
time_t expire_time
uint32 owner
static std::string BuildAuctionMailBody(uint32 lowGuid, uint64 bid, uint64 buyout, uint64 deposit, uint64 cut)
uint32 Id
uint32 itemCount
uint64 GetAuctionCut() const
uint64 bid
std::string BuildAuctionMailSubject(MailAuctionAnswer response) const
void SaveToDB(SQLTransaction &trans) const
uint64 buyout
uint64 GetAuctionOutBid() const
the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
void DeleteFromDB(SQLTransaction &trans) const
uint64 startbid
uint32 houseId
std::string Name1