Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
AuctionHouseMgr.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 "AccountMgr.h"
7#include "AuctionHouseMgr.h"
8#include "Common.h"
9#include "DatabaseEnv.h"
10#include "DBCStores.h"
11#include "Item.h"
12#include "Language.h"
13#include "Log.h"
14#include "ObjectMgr.h"
15#include "Player.h"
16#include "ScriptMgr.h"
17#include "World.h"
18#include "WorldPacket.h"
19#include "WorldSession.h"
20#include <vector>
21
26
28{
29 for (ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
30 delete itr->second;
31}
32
34{
36 return &mNeutralAuctions;
37
38 // teams have linked auction houses
39 FactionTemplateEntry const* uEntry = sFactionTemplateStore.LookupEntry(factionTemplateId);
40 if (!uEntry)
41 return &mNeutralAuctions;
42 else if (uEntry->ourMask & FACTION_MASK_ALLIANCE)
43 return &mAllianceAuctions;
44 else if (uEntry->ourMask & FACTION_MASK_HORDE)
45 return &mHordeAuctions;
46 else
47 return &mNeutralAuctions;
48}
49
51{
52 uint32 MSV = pItem->GetTemplate()->SellPrice;
53
54 if (MSV <= 0)
55 return AH_MINIMUM_DEPOSIT;
56
57 float multiplier = CalculatePct(float(entry->depositPercent), 3);
58 uint32 timeHr = (((time / 60) / 60) / 12);
59 //TODO: Fix this arithmetic overflow
60 uint64 deposit = uint64(((multiplier * MSV * count / 3) * timeHr * 3) * sWorld->getRate(Rates::RATE_AUCTION_DEPOSIT));
61
62 SF_LOG_DEBUG("auctionHouse", "MSV: %u", MSV);
63 SF_LOG_DEBUG("auctionHouse", "Items: %u", count);
64 SF_LOG_DEBUG("auctionHouse", "Multiplier: %f", multiplier);
65 SF_LOG_DEBUG("auctionHouse", "Deposit: %lu", deposit);
66
67 if (deposit < AH_MINIMUM_DEPOSIT)
68 return AH_MINIMUM_DEPOSIT;
69 else
70 return deposit;
71}
72
73//does not clear ram
75{
76 Item* pItem = GetAItem(auction->itemGUIDLow);
77 if (!pItem)
78 return;
79
80 uint32 bidderAccId = 0;
81 uint64 bidderGuid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
82 Player* bidder = ObjectAccessor::FindPlayer(bidderGuid);
83 // data for gm.log
84 std::string bidderName;
85 bool logGmTrade = false;
86
87 if (bidder)
88 {
89 bidderAccId = bidder->GetSession()->GetAccountId();
90 bidderName = bidder->GetName();
92 }
93 else
94 {
95 bidderAccId = sObjectMgr->GetPlayerAccountIdByGUID(bidderGuid);
97
98 if (logGmTrade && !sObjectMgr->GetPlayerNameByGUID(bidderGuid, bidderName))
99 bidderName = sObjectMgr->GetSkyFireStringForDBCLocale(LANG_UNKNOWN);
100 }
101
102 if (logGmTrade)
103 {
104 std::string ownerName;
105 if (!sObjectMgr->GetPlayerNameByGUID(auction->owner, ownerName))
106 ownerName = sObjectMgr->GetSkyFireStringForDBCLocale(LANG_UNKNOWN);
107
108 uint32 ownerAccId = sObjectMgr->GetPlayerAccountIdByGUID(auction->owner);
109
110 sLog->outCommand(bidderAccId, "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %lu. Original owner %s (Account: %u)",
111 bidderName.c_str(), bidderAccId, pItem->GetTemplate()->Name1.c_str(), pItem->GetEntry(), pItem->GetCount(), auction->bid, ownerName.c_str(), ownerAccId);
112 }
113
114 // receiver exist
115 if (bidder || bidderAccId)
116 {
117 // set owner to bidder (to prevent delete item with sender char deleting)
118 // owner in `data` will set at mail receive and item extracting
119 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER);
120 stmt->setUInt32(0, auction->bidder);
121 stmt->setUInt32(1, pItem->GetGUIDLow());
122 trans->Append(stmt);
123
124 if (bidder)
125 {
126 bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, bidderGuid, 0, 0, auction->itemEntry);
127 // FIXME: for offline player need also
129 }
130
132 .AddItem(pItem)
133 .SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
134 }
135}
136
138{
139 uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
140 Player* owner = ObjectAccessor::FindPlayer(owner_guid);
141 uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
142 // owner exist (online or offline)
143 if (owner || owner_accId)
145 .SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED);
146}
147
148//call this method to send mail to auction owner, when auction is successful, it does not clear ram
150{
151 uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
152 Player* owner = ObjectAccessor::FindPlayer(owner_guid);
153 uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
154 // owner exist
155 if (owner || owner_accId)
156 {
157 uint64 profit = auction->bid + auction->deposit - auction->GetAuctionCut();
158
159 //FIXME: what do if owner offline
160 if (owner)
161 {
164 //send auction owner notification, bidder must be current!
165 owner->GetSession()->SendAuctionOwnerNotification(auction);
166 }
167
169 .AddMoney(profit)
171 }
172}
173
174//does not clear ram
176{
177 //return an item in auction to its owner by mail
178 Item* pItem = GetAItem(auction->itemGUIDLow);
179 if (!pItem)
180 return;
181
182 uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
183 Player* owner = ObjectAccessor::FindPlayer(owner_guid);
184 uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
185 // owner exist
186 if (owner || owner_accId)
187 {
188 if (owner)
189 owner->GetSession()->SendAuctionOwnerNotification(auction);
190
192 .AddItem(pItem)
193 .SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED, 0);
194 }
195}
196
197//this function sends mail to old bidder
199{
200 uint64 oldBidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
201 Player* oldBidder = ObjectAccessor::FindPlayer(oldBidder_guid);
202
203 uint32 oldBidder_accId = 0;
204 if (!oldBidder)
205 oldBidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(oldBidder_guid);
206
207 // old bidder exist
208 if (oldBidder || oldBidder_accId)
209 {
210 if (oldBidder && newBidder)
211 oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, newBidder->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->itemEntry);
212
214 .AddMoney(auction->bid)
215 .SendMailTo(trans, MailReceiver(oldBidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
216 }
217}
218
219//this function sends mail, when auction is cancelled to old bidder
221{
222 uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
223 Player* bidder = ObjectAccessor::FindPlayer(bidder_guid);
224
225 uint32 bidder_accId = 0;
226 if (!bidder)
227 bidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(bidder_guid);
228
229 if (bidder)
230 bidder->GetSession()->SendAuctionRemovedNotification(auction->Id, auction->itemEntry, item->GetItemRandomPropertyId());
231
232 // bidder exist
233 if (bidder || bidder_accId)
235 .AddMoney(auction->bid)
236 .SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
237}
238
240{
241 uint32 oldMSTime = getMSTime();
242
243 // need to clear in case we are reloading
244 if (!mAitems.empty())
245 {
246 for (ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
247 delete itr->second;
248
249 mAitems.clear();
250 }
251
252 // data needs to be at first place for Item::LoadFromDB
253 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTION_ITEMS);
254 PreparedQueryResult result = CharacterDatabase.Query(stmt);
255
256 if (!result)
257 {
258 SF_LOG_INFO("server.loading", ">> Loaded 0 auction items. DB table `auctionhouse` or `item_instance` is empty!");
259
260 return;
261 }
262
263 uint32 count = 0;
264
265 do
266 {
267 Field* fields = result->Fetch();
268
269 uint32 item_guid = fields[11].GetUInt32();
270 uint32 itemEntry = fields[12].GetUInt32();
271
272 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
273 if (!proto)
274 {
275 SF_LOG_ERROR("misc", "AuctionHouseMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid, itemEntry);
276 continue;
277 }
278
279 Item* item = NewItemOrBag(proto);
280 if (!item->LoadFromDB(item_guid, 0, fields, itemEntry))
281 {
282 delete item;
283 continue;
284 }
285 AddAItem(item);
286
287 ++count;
288 } while (result->NextRow());
289
290 SF_LOG_INFO("server.loading", ">> Loaded %u auction items in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
291}
292
294{
295 uint32 oldMSTime = getMSTime();
296
297 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTIONS);
298 PreparedQueryResult result = CharacterDatabase.Query(stmt);
299
300 if (!result)
301 {
302 SF_LOG_INFO("server.loading", ">> Loaded 0 auctions. DB table `auctionhouse` is empty.");
303
304 return;
305 }
306
307 uint32 count = 0;
308
309 SQLTransaction trans = CharacterDatabase.BeginTransaction();
310 do
311 {
312 Field* fields = result->Fetch();
313
314 AuctionEntry* aItem = new AuctionEntry();
315 if (!aItem->LoadFromDB(fields))
316 {
317 aItem->DeleteFromDB(trans);
318 delete aItem;
319 continue;
320 }
321
323 ++count;
324 } while (result->NextRow());
325
326 CharacterDatabase.CommitTransaction(trans);
327
328 SF_LOG_INFO("server.loading", ">> Loaded %u auctions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
329}
330
332{
333 ASSERT(it);
334 ASSERT(mAitems.find(it->GetGUIDLow()) == mAitems.end());
335 mAitems[it->GetGUIDLow()] = it;
336}
337
339{
340 ItemMap::iterator i = mAitems.find(id);
341 if (i == mAitems.end())
342 return false;
343
344 mAitems.erase(i);
345 return true;
346}
347
349{
350 mHordeAuctions.Update();
351 mAllianceAuctions.Update();
352 mNeutralAuctions.Update();
353}
354
356{
357 uint32 houseid = 7; // goblin auction house
358
360 {
361 // FIXME: found way for proper auctionhouse selection by another way
362 // AuctionHouse.dbc have faction field with _player_ factions associated with auction house races.
363 // but no easy way convert creature faction to player race faction for specific city
364 switch (factionTemplateId)
365 {
366 case 12: houseid = 1; break; // human
367 case 29: houseid = 6; break; // orc, and generic for horde
368 case 55: houseid = 2; break; // dwarf, and generic for alliance
369 case 68: houseid = 4; break; // undead
370 case 80: houseid = 3; break; // n-elf
371 case 104: houseid = 5; break; // trolls
372 case 120: houseid = 7; break; // booty bay, neutral
373 case 474: houseid = 7; break; // gadgetzan, neutral
374 case 855: houseid = 7; break; // everlook, neutral
375 case 1604: houseid = 6; break; // b-elfs,
376 default: // for unknown case
377 {
378 FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
379 if (!u_entry)
380 houseid = 7; // goblin auction house
381 else if (u_entry->ourMask & FACTION_MASK_ALLIANCE)
382 houseid = 1; // human auction house
383 else if (u_entry->ourMask & FACTION_MASK_HORDE)
384 houseid = 6; // orc auction house
385 else
386 houseid = 7; // goblin auction house
387 break;
388 }
389 }
390 }
391
392 return sAuctionHouseStore.LookupEntry(houseid);
393}
394
396{
397 ASSERT(auction);
398
399 AuctionsMap[auction->Id] = auction;
400 sScriptMgr->OnAuctionAdd(this, auction);
401}
402
404{
405 bool wasInMap = AuctionsMap.erase(auction->Id) ? true : false;
406
407 sScriptMgr->OnAuctionRemove(this, auction);
408
409 // we need to delete the entry, it is not referenced any more
410 delete auction;
411
412 return wasInMap;
413}
414
416{
417 time_t curTime = sWorld->GetGameTime();
419
420 // If storage is empty, no need to update. next == NULL in this case.
421 if (AuctionsMap.empty())
422 return;
423
425 stmt->setUInt32(0, (uint32)curTime + 60);
426 PreparedQueryResult result = CharacterDatabase.Query(stmt);
427
428 if (!result)
429 return;
430
431 do
432 {
433 // from auctionhousehandler.cpp, creates auction pointer & player pointer
434 AuctionEntry* auction = GetAuction(result->Fetch()->GetUInt32());
435
436 if (!auction)
437 continue;
438
439 SQLTransaction trans = CharacterDatabase.BeginTransaction();
440
442 if (auction->bidder == 0)
443 {
444 sAuctionMgr->SendAuctionExpiredMail(auction, trans);
445 sScriptMgr->OnAuctionExpire(this, auction);
446 }
448 else
449 {
450 //we should send an "item sold" message if the seller is online
451 //we send the item to the winner
452 //we send the money to the seller
453 sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
454 sAuctionMgr->SendAuctionWonMail(auction, trans);
455 sScriptMgr->OnAuctionSuccessful(this, auction);
456 }
457
458 uint32 itemEntry = auction->itemEntry;
459
461 auction->DeleteFromDB(trans);
462 CharacterDatabase.CommitTransaction(trans);
463
464 sAuctionMgr->RemoveAItem(auction->itemGUIDLow);
465 RemoveAuction(auction, itemEntry);
466 } while (result->NextRow());
467}
468
470{
471 for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
472 {
473 AuctionEntry* Aentry = itr->second;
474 if (Aentry && Aentry->bidder == player->GetGUIDLow())
475 {
476 if (itr->second->BuildAuctionInfo(data))
477 ++count;
478
479 ++totalcount;
480 }
481 }
482}
483
485{
486 for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
487 {
488 AuctionEntry* Aentry = itr->second;
489 if (Aentry && Aentry->owner == player->GetGUIDLow())
490 {
491 if (Aentry->BuildAuctionInfo(data))
492 ++count;
493
494 ++totalcount;
495 }
496 }
497}
498
500 std::wstring const& wsearchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable,
501 uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality,
502 uint32& count, uint32& totalcount)
503{
504 int loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
505 int locdbc_idx = player->GetSession()->GetSessionDbcLocale();
506
507 for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
508 {
509 AuctionEntry* Aentry = itr->second;
510 Item* item = sAuctionMgr->GetAItem(Aentry->itemGUIDLow);
511 if (!item)
512 continue;
513
514 ItemTemplate const* proto = item->GetTemplate();
515
516 if (itemClass != 0xffffffff && proto->Class != itemClass)
517 continue;
518
519 if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass)
520 continue;
521
522 if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType)
523 continue;
524
525 if (quality != 0xffffffff && proto->Quality != quality)
526 continue;
527
528 if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
529 continue;
530
531 if (usable != 0x00 && player->CanUseItem(item) != EQUIP_ERR_OK)
532 continue;
533
534 // Allow search by suffix (ie: of the Monkey) or partial name (ie: Monkey)
535 // No need to do any of this if no search term was entered
536 if (!wsearchedname.empty())
537 {
538 std::string name = proto->Name1;
539 if (name.empty())
540 continue;
541
542 // local name
543 if (loc_idx >= 0)
544 if (ItemLocale const* il = sObjectMgr->GetItemLocale(proto->ItemId))
545 ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
546
547 // DO NOT use GetItemEnchantMod(proto->RandomProperty) as it may return a result
548 // that matches the search but it may not equal item->GetItemRandomPropertyId()
549 // used in BuildAuctionInfo() which then causes wrong items to be listed
550 int32 propRefID = item->GetItemRandomPropertyId();
551
552 if (propRefID)
553 {
554 // Append the suffix to the name (ie: of the Monkey) if one exists
555 // These are found in ItemRandomProperties.dbc, not ItemRandomSuffix.dbc
556 // even though the DBC names seem misleading
557 const ItemRandomPropertiesEntry* itemRandProp = sItemRandomPropertiesStore.LookupEntry(propRefID);
558
559 if (itemRandProp)
560 {
561 char* temp = itemRandProp->nameSuffix;
562
563 // dbc local name
564 if (temp)
565 {
566 // Append the suffix (ie: of the Monkey) to the name using localization
567 // or default enUS if localization is invalid
568 name += ' ';
569 name += temp[locdbc_idx >= 0 ? locdbc_idx : LOCALE_enUS];
570 }
571 }
572 }
573
574 // Perform the search (with or without suffix)
575 if (!Utf8FitTo(name, wsearchedname))
576 continue;
577 }
578
579 // Add the item if no search term or if entered search term was found
580 if (count < 50 && totalcount >= listfrom)
581 {
582 ++count;
583 Aentry->BuildAuctionInfo(data);
584 }
585 ++totalcount;
586 }
587}
588
589//this function inserts to WorldPacket auction's data
591{
592 Item* item = sAuctionMgr->GetAItem(itemGUIDLow);
593 if (!item)
594 {
595 SF_LOG_ERROR("misc", "AuctionEntry::BuildAuctionInfo: Auction %u has a non-existent item: %u", Id, itemGUIDLow);
596 return false;
597 }
598 data << uint32(Id);
599 data << uint32(item->GetEntry());
600
601 for (uint8 i = 0; i < PROP_ENCHANTMENT_SLOT_0; ++i) // PROP_ENCHANTMENT_SLOT_0 = 10
602 {
603 data << uint32(item->GetEnchantmentId(EnchantmentSlot(i)));
606 }
607
608 data << int32(0);
609 data << int32(item->GetItemRandomPropertyId()); // Random item property id
610 data << uint32(item->GetItemSuffixFactor()); // SuffixFactor
611 data << uint32(item->GetCount()); // item->count
612 data << uint32(item->GetSpellCharges()); // item->charge FFFFFFF
613 data << uint32(0); // Unknown
614 data << uint64(owner); // Auction->owner
615 data << uint64(startbid); // Auction->startbid (not sure if useful)
616 data << uint64(bid ? GetAuctionOutBid() : 0);
617 // Minimal outbid
618 data << uint64(buyout); // Auction->buyout
619 data << uint32((expire_time - time(NULL)) * IN_MILLISECONDS); // time left
620 data << uint64(bidder); // auction->bidder current
621 data << uint64(bid); // current bid
622 return true;
623}
624
626{
627 //TODO: Fix this arithmetic overflow.
629 return std::max<uint64>(cut, 0);
630}
631
634{
635 uint64 outbid = CalculatePct(bid, 5);
636 return outbid ? outbid : 1;
637}
638
640{
641 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_AUCTION);
642 stmt->setUInt32(0, Id);
643 trans->Append(stmt);
644}
645
647{
648 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AUCTION);
649 stmt->setUInt32(0, Id);
650 stmt->setUInt32(1, auctioneer);
651 stmt->setUInt32(2, itemGUIDLow);
652 stmt->setUInt32(3, owner);
653 stmt->setUInt64(4, buyout);
654 stmt->setUInt32(5, uint32(expire_time));
655 stmt->setUInt32(6, bidder);
656 stmt->setUInt64(7, bid);
657 stmt->setUInt64(8, startbid);
658 stmt->setUInt64(9, deposit);
659 trans->Append(stmt);
660}
661
663{
664 Id = fields[0].GetUInt32();
665 auctioneer = fields[1].GetUInt32();
666 itemGUIDLow = fields[2].GetUInt32();
667 itemEntry = fields[3].GetUInt32();
668 itemCount = fields[4].GetUInt32();
669 owner = fields[5].GetUInt32();
670 buyout = fields[6].GetUInt64();
671 expire_time = fields[7].GetUInt32();
672 bidder = fields[8].GetUInt32();
673 bid = fields[9].GetUInt64();
674 startbid = fields[10].GetUInt64();
675 deposit = fields[11].GetUInt64();
676
677 CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(auctioneer);
678 if (!auctioneerData)
679 {
680 SF_LOG_ERROR("misc", "Auction %u has not a existing auctioneer (GUID : %u)", Id, auctioneer);
681 return false;
682 }
683
684 CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id);
685 if (!auctioneerInfo)
686 {
687 SF_LOG_ERROR("misc", "Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", Id, auctioneer, auctioneerData->id);
688 return false;
689 }
690
691 factionTemplateId = auctioneerInfo->faction_A;
694 {
695 SF_LOG_ERROR("misc", "Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u", Id, auctioneer, auctioneerData->id, factionTemplateId);
696 return false;
697 }
698
699 // check if sold item exists for guid
700 // and itemEntry in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems)
701 if (!sAuctionMgr->GetAItem(itemGUIDLow))
702 {
703 SF_LOG_ERROR("misc", "Auction %u has not a existing item : %u", Id, itemGUIDLow);
704 return false;
705 }
706 return true;
707}
708
710{
711 // Deletes expired auctions. Should be called at server start before loading auctions.
712
713 // DO NOT USE after auctions are already loaded since this deletes from the DB
714 // and assumes the auctions HAVE NOT been loaded into a list or AuctionEntryMap yet
715
716 uint32 oldMSTime = getMSTime();
717 uint32 expirecount = 0;
718 time_t curTime = sWorld->GetGameTime();
719
720 // Query the DB to see if there are any expired auctions
722 stmt->setUInt32(0, (uint32)curTime + 60);
723 PreparedQueryResult expAuctions = CharacterDatabase.Query(stmt);
724
725 if (!expAuctions)
726 {
727 SF_LOG_INFO("server.loading", ">> No expired auctions to delete");
728
729 return;
730 }
731
732 do
733 {
734 Field* fields = expAuctions->Fetch();
735
736 AuctionEntry* auction = new AuctionEntry();
737
738 // Can't use LoadFromDB() because it assumes the auction map is loaded
739 if (!auction->LoadFromFieldList(fields))
740 {
741 // For some reason the record in the DB is broken (possibly corrupt
742 // faction info). Delete the object and move on.
743 delete auction;
744 continue;
745 }
746
747 SQLTransaction trans = CharacterDatabase.BeginTransaction();
748
749 if (auction->bidder == 0)
750 {
751 // Cancel the auction, there was no bidder
752 sAuctionMgr->SendAuctionExpiredMail(auction, trans);
753 }
754 else
755 {
756 // Send the item to the winner and money to seller
757 sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
758 sAuctionMgr->SendAuctionWonMail(auction, trans);
759 }
760
761 // Call the appropriate AuctionHouseObject script
762 // ** Do we need to do this while core is still loading? **
763 sScriptMgr->OnAuctionExpire(GetAuctionsMap(auction->factionTemplateId), auction);
764
765 // Delete the auction from the DB
766 auction->DeleteFromDB(trans);
767 CharacterDatabase.CommitTransaction(trans);
768
769 // Release memory
770 delete auction;
771 ++expirecount;
772 } while (expAuctions->NextRow());
773
774 SF_LOG_INFO("server.loading", ">> Deleted %u expired auctions in %u ms", expirecount, GetMSTimeDiffToNow(oldMSTime));
775}
776
778{
779 // Loads an AuctionEntry item from a field list. Unlike "LoadFromDB()", this one
780 // does not require the AuctionEntryMap to have been loaded with items. It simply
781 // acts as a wrapper to fill out an AuctionEntry struct from a field list
782
783 Id = fields[0].GetUInt32();
784 auctioneer = fields[1].GetUInt32();
785 itemGUIDLow = fields[2].GetUInt32();
786 itemEntry = fields[3].GetUInt32();
787 itemCount = fields[4].GetUInt32();
788 owner = fields[5].GetUInt32();
789 buyout = fields[6].GetUInt64();
790 expire_time = fields[7].GetUInt32();
791 bidder = fields[8].GetUInt32();
792 bid = fields[9].GetUInt64();
793 startbid = fields[10].GetUInt64();
794 deposit = fields[11].GetUInt64();
795
796 CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(auctioneer);
797 if (!auctioneerData)
798 {
799 SF_LOG_ERROR("misc", "AuctionEntry::LoadFromFieldList() - Auction %u has not a existing auctioneer (GUID : %u)", Id, auctioneer);
800 return false;
801 }
802
803 CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id);
804 if (!auctioneerInfo)
805 {
806 SF_LOG_ERROR("misc", "AuctionEntry::LoadFromFieldList() - Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", Id, auctioneer, auctioneerData->id);
807 return false;
808 }
809
810 factionTemplateId = auctioneerInfo->faction_A;
812
814 {
815 SF_LOG_ERROR("misc", "AuctionEntry::LoadFromFieldList() - Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u", Id, auctioneer, auctioneerData->id, factionTemplateId);
816 return false;
817 }
818
819 return true;
820}
821
823{
824 std::ostringstream strm;
825 strm << itemEntry << ":0:" << uint8(response) << ':' << Id << ':' << itemCount;
826 return strm.str();
827}
828
830{
831 std::ostringstream strm;
832 strm.width(16);
833 strm << std::right << std::hex << MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER); // HIGHGUID_PLAYER always present, even for empty guids
834 strm << std::dec << ':' << bid << ':' << buyout;
835 strm << ':' << deposit << ':' << cut;
836 return strm.str();
837}
eAuctionHouse
@ AH_MINIMUM_DEPOSIT
MailAuctionAnswer
#define sAuctionMgr
Item * NewItemOrBag(ItemTemplate const *proto)
Definition Bag.h:53
@ CHAR_UPD_ITEM_OWNER
@ CHAR_SEL_AUCTION_ITEMS
@ CHAR_DEL_AUCTION
@ CHAR_SEL_AUCTION_BY_TIME
@ CHAR_INS_AUCTION
@ CHAR_SEL_EXPIRED_AUCTIONS
@ CHAR_SEL_AUCTIONS
@ LOCALE_enUS
Definition Common.h:139
@ IN_MILLISECONDS
Definition Common.h:125
@ FACTION_MASK_ALLIANCE
Definition DBCEnums.h:385
@ FACTION_MASK_HORDE
Definition DBCEnums.h:386
@ ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS
Definition DBCEnums.h:241
@ ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS
Definition DBCEnums.h:245
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD
Definition DBCEnums.h:246
DBCStorage< ItemRandomPropertiesEntry > sItemRandomPropertiesStore(ItemRandomPropertiesfmt)
DBCStorage< FactionTemplateEntry > sFactionTemplateStore(FactionTemplateEntryfmt)
DBCStorage< AuctionHouseEntry > sAuctionHouseStore(AuctionHouseEntryfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
#define ASSERT
Definition Errors.h:29
EnchantmentSlot
Definition Item.h:149
@ PROP_ENCHANTMENT_SLOT_0
Definition Item.h:160
@ EQUIP_ERR_OK
Definition Item.h:28
@ LANG_UNKNOWN
Definition Language.h:58
#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
@ HIGHGUID_PLAYER
uint64 MAKE_NEW_GUID(uint32 l, uint32 e, uint32 h)
#define sObjectMgr
Definition ObjectMgr.h:1617
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
Definition QueryResult.h:94
#define sScriptMgr
Definition ScriptMgr.h:764
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:22
uint32 getMSTime()
Definition Timer.h:12
Skyfire::AutoPtr< Transaction, Skyfire::Mutex > SQLTransaction
Definition Transaction.h:42
bool Utf8FitTo(const std::string &str, const std::wstring &search)
Definition Util.cpp:473
T CalculatePct(T base, U pct)
Definition Util.h:103
static bool HasPermission(uint32 accountId, uint32 permission, uint32 realmId)
void SendAuctionSalePendingMail(AuctionEntry *auction, SQLTransaction &trans)
static AuctionHouseEntry const * GetAuctionHouseEntry(uint32 factionTemplateId)
void AddAItem(Item *it)
void SendAuctionSuccessfulMail(AuctionEntry *auction, SQLTransaction &trans)
void DeleteExpiredAuctionsAtStartup()
void SendAuctionCancelledToBidderMail(AuctionEntry *auction, SQLTransaction &trans, Item *item)
void SendAuctionWonMail(AuctionEntry *auction, SQLTransaction &trans)
Item * GetAItem(uint32 id)
AuctionHouseObject * GetAuctionsMap(uint32 factionTemplateId)
AuctionHouseObject mNeutralAuctions
void SendAuctionExpiredMail(AuctionEntry *auction, SQLTransaction &trans)
AuctionHouseObject mHordeAuctions
bool RemoveAItem(uint32 id)
AuctionHouseObject mAllianceAuctions
void SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPrice, Player *newBidder, SQLTransaction &trans)
static uint64 GetAuctionDeposit(AuctionHouseEntry const *entry, uint32 time, Item *pItem, uint32 count)
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)
AuctionEntryMap AuctionsMap
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)
Definition Field.h:16
uint64 GetUInt64() const
Definition Field.h:141
uint32 GetUInt32() const
Definition Field.h:105
Definition Item.h:202
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:287
int32 GetSpellCharges(uint8 index=0) const
Definition Item.h:298
uint32 GetEnchantmentDuration(EnchantmentSlot slot) const
Definition Item.h:288
int32 GetItemRandomPropertyId() const
Definition Item.h:278
ItemTemplate const * GetTemplate() const
Definition Item.cpp:528
uint32 GetItemSuffixFactor() const
Definition Item.h:279
virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, Field *fields, uint32 entry)
Definition Item.cpp:405
uint32 GetEnchantmentCharges(EnchantmentSlot slot) const
Definition Item.h:289
uint32 GetCount() const
Definition Item.h:258
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
MailDraft & AddMoney(uint64 money)
Definition Mail.h:126
static Player * FindPlayer(uint64)
uint64 GetGUID() const
Definition Object.h:119
uint32 GetGUIDLow() const
Definition Object.h:120
uint32 GetEntry() const
Definition Object.h:125
static void GetLocaleString(const StringVector &data, int loc_idx, std::string &value)
Definition ObjectMgr.h:1353
WorldSession * GetSession() const
Definition Player.h:2417
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, Unit *unit=NULL)
Definition Player.cpp:21033
InventoryResult CanUseItem(Item *pItem, bool not_loading=true) const
void setUInt64(const uint8 index, const uint64 value)
void setUInt32(const uint8 index, const uint32 value)
std::string const & GetName() const
Definition Object.h:664
LocaleConstant GetSessionDbLocaleIndex() const
void SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template)
void SendAuctionRemovedNotification(uint32 auctionId, uint32 itemEntry, int32 randomPropertyId)
LocaleConstant GetSessionDbcLocale() const
void SendAuctionOwnerNotification(AuctionEntry *auction)
bool HasPermission(uint32 permissionId)
uint32 GetAccountId() const
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
#define sWorld
Definition World.h:910
uint32 realmID
Id of the realm.
Definition Main.cpp:73
@ CONFIG_MAIL_DELIVERY_DELAY
Definition World.h:255
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION
Definition World.h:100
@ RATE_AUCTION_CUT
Definition World.h:429
@ RATE_AUCTION_DEPOSIT
Definition World.h:428
@ RBAC_PERM_LOG_GM_TRADE
Definition RBAC.h:51
bool BuildAuctionInfo(WorldPacket &data) const
uint32 itemEntry
bool LoadFromFieldList(Field *fields)
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
uint32 factionTemplateId
std::string BuildAuctionMailSubject(MailAuctionAnswer response) const
bool LoadFromDB(Field *fields)
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 depositPercent
uint32 id
Definition Creature.h:260
uint32 faction_A
Definition Creature.h:79
uint32 ourMask
char * nameSuffix
uint32 RequiredLevel
std::string Name1
uint32 InventoryType