void WorldSession::BuildListAuctionItems(std::list<AuctionEntry*> &auctions, WorldPacket& data, std::wstring const& wsearchedname, uint32 listfrom, uint32 levelmin, uint32 levelmax, uint32 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32& count, uint32& totalcount, bool isFull) { int loc_idx = _player->GetSession()->GetSessionDbLocaleIndex(); for (std::list<AuctionEntry*>::const_iterator itr = auctions.begin(); itr != auctions.end();++itr) { AuctionEntry *Aentry = *itr; if (Aentry->moneyDeliveryTime) continue; Item *item = sAuctionMgr.GetAItem(Aentry->itemGuidLow); if (!item) continue; if (isFull) { ++count; Aentry->BuildAuctionInfo(data); } else { ItemPrototype const *proto = item->GetProto(); if (itemClass != 0xffffffff && proto->Class != itemClass) continue; if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass) continue; if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType) continue; if (quality != 0xffffffff && proto->Quality < quality) continue; if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) continue; if (usable != 0x00 && _player->CanUseItem(item) != EQUIP_ERR_OK) continue; std::string name = proto->Name1; if (name.empty()) continue; // local name if (loc_idx >= 0) { ItemLocale const *il = sObjectMgr.GetItemLocale(proto->ItemId); if (il) { if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty()) name = il->Name[loc_idx]; } } if (!wsearchedname.empty() && !Utf8FitTo(name, wsearchedname)) continue; if (count < 50 && totalcount >= listfrom) { ++count; Aentry->BuildAuctionInfo(data); } } ++totalcount; } }
// this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) { uint64 auctioneer, item; uint64 bid, buyout; uint32 etime, count; uint32 unk = 1; recv_data >> auctioneer; // uint64 recv_data >> unk; // 1 recv_data >> item; // uint64 recv_data >> count; // 3.2.2, number of items being auctioned recv_data >> bid; // uint64, 4.0.6 recv_data >> buyout; // uint64, 4.0.6 recv_data >> etime; // uint32 Player *pl = GetPlayer(); if (!item || !bid || !etime) return; //check for cheaters Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!pCreature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(pCreature->getFaction()); if (!auctionHouseEntry) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer))); return; } sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - ETIME: %u", etime); // client send time in minutes, convert to common used sec time etime *= MINUTE; sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - ETIME: %u", etime); // client understand only 3 auction time switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item *it = pl->GetItemByGuid(item); //do not allow to sell already auctioned items if (sAuctionMgr->GetAItem(GUID_LOPART(item))) { sLog->outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) if (!it) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if (!it->CanBeTraded()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if (it->GetProto()->Flags & ITEM_PROTO_FLAG_CONJURED || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if (it->IsBag() && !((Bag*)it)->IsEmpty()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(pCreature->getFaction()); //we have to take deposit : uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, it, count); if (!pl->HasEnoughMoney(deposit)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), it->GetProto()->Name1, it->GetEntry(), count); } pl->ModifyMoney(-int32(deposit)); uint32 auction_time = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionEntry *AH = new AuctionEntry; AH->Id = sObjectMgr->GenerateAuctionID(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = 23442; else AH->auctioneer = GUID_LOPART(auctioneer); AH->item_guidlow = GUID_LOPART(item); AH->item_template = it->GetEntry(); AH->owner = pl->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auction_time; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; sLog->outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), AH->auctioneer, bid, buyout, auction_time, AH->GetHouseId()); sAuctionMgr->AddAItem(it); auctionHouse->AddAuction(AH); pl->MoveItemFromInventory(it->GetBagSlot(), it->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); it->DeleteFromInventoryDB(trans); it->SaveToDB(trans); // recursive and not have transaction guard into self, not in inventiory and can be save standalone AH->SaveToDB(trans); pl->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); }
//this void is called when auction_owner cancels his auction void WorldSession::HandleAuctionRemoveItem(WorldPacket & recv_data) { uint64 auctioneer; uint32 auctionId; recv_data >> auctioneer; recv_data >> auctionId; //sLog->outDebug(LOG_FILTER_NETWORKIO, "Cancel AUCTION AuctionID: %u", auctionId); Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!pCreature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(pCreature->getFaction()); AuctionEntry *auction = auctionHouse->GetAuction(auctionId); Player *pl = GetPlayer(); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (auction && auction->owner == pl->GetGUIDLow()) { Item *pItem = sAuctionMgr->GetAItem(auction->item_guidlow); if (pItem) { if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid { uint32 auctionCut = auction->GetAuctionCut(); if (!pl->HasEnoughMoney(auctionCut)) //player doesn't have enough money, maybe message needed return; //some auctionBidderNotification would be needed, but don't know that parts.. sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans); pl->ModifyMoney(-int32(auctionCut)); } // Return the item by mail std::ostringstream msgAuctionCanceledOwner; msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED << ":0:0"; // item will deleted or added to received mail list MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body .AddItem(pItem) .SendMailTo(trans, pl, auction, MAIL_CHECK_MASK_COPIED); } else { sLog->outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->item_guidlow); SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); return; } } else { SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); //this code isn't possible ... maybe there should be assert sLog->outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", pl->GetGUIDLow(), auctionId); return; } //inform player, that auction is removed SendAuctionCommandResult(auction->Id, AUCTION_CANCEL, AUCTION_OK); // Now remove the auction pl->SaveInventoryAndGoldToDB(trans); auction->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); uint32 item_template = auction->item_template; sAuctionMgr->RemoveAItem(auction->item_guidlow); auctionHouse->RemoveAuction(auction, item_template); }
// this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data ) { DEBUG_LOG("WORLD: HandleAuctionSellItem"); ObjectGuid auctioneerGuid; uint64 item; uint32 etime, bid, buyout; recv_data >> auctioneerGuid; recv_data.read_skip<uint32>(); // const 1? recv_data >> item; recv_data.read_skip<uint32>(); // stack size recv_data >> bid; recv_data >> buyout; recv_data >> etime; if (!item || !bid || !etime) return; // check for cheaters Player *pl = GetPlayer(); AuctionHouseEntry const* auctionHouseEntry = GetCheckedAuctionHouseForAuctioneer(auctioneerGuid); if (!auctionHouseEntry) return; // always return pointer AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(auctionHouseEntry); // client send time in minutes, convert to common used sec time etime *= MINUTE; // client understand only 3 auction time switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); Item *it = pl->GetItemByGuid( item ); // do not allow to sell already auctioned items if(sAuctionMgr.GetAItem(GUID_LOPART(item))) { sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to auction) if(!it) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if(!it->CanBeTraded()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if ((it->GetProto()->Flags & ITEM_FLAG_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } //we have to take deposit : uint32 deposit = AuctionHouseMgr::GetAuctionDeposit( auctionHouseEntry, etime, it ); if ( pl->GetMoney() < deposit ) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE) ) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), it->GetProto()->Name1, it->GetEntry(), it->GetCount()); } pl->ModifyMoney( -int32(deposit) ); uint32 auction_time = uint32(etime * sWorld.getConfig(CONFIG_FLOAT_RATE_AUCTION_TIME)); AuctionEntry *AH = new AuctionEntry; AH->Id = sObjectMgr.GenerateAuctionID(); AH->item_guidlow = GUID_LOPART(item); AH->item_template = it->GetEntry(); AH->owner = pl->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auction_time; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; DETAIL_LOG("selling item %u to auctioneer %s with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), auctioneerGuid.GetString().c_str(), bid, buyout, auction_time, AH->GetHouseId()); auctionHouse->AddAuction(AH); sAuctionMgr.AddAItem(it); pl->MoveItemFromInventory( it->GetBagSlot(), it->GetSlot(), true); CharacterDatabase.BeginTransaction(); it->DeleteFromInventoryDB(); it->SaveToDB(); // recursive and not have transaction guard into self, not in inventiory and can be save standalone AH->SaveToDB(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); }
// this void is called when auction_owner cancels his auction void WorldSession::HandleAuctionRemoveItem( WorldPacket & recv_data ) { DEBUG_LOG("WORLD: HandleAuctionRemoveItem"); ObjectGuid auctioneerGuid; uint32 auctionId; recv_data >> auctioneerGuid; recv_data >> auctionId; //DEBUG_LOG( "Cancel AUCTION AuctionID: %u", auctionId); AuctionHouseEntry const* auctionHouseEntry = GetCheckedAuctionHouseForAuctioneer(auctioneerGuid); if (!auctionHouseEntry) return; // always return pointer AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(auctionHouseEntry); // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); AuctionEntry *auction = auctionHouse->GetAuction(auctionId); Player *pl = GetPlayer(); if (auction && auction->owner == pl->GetGUIDLow()) { Item *pItem = sAuctionMgr.GetAItem(auction->item_guidlow); if (pItem) { if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid { uint32 auctionCut = auction->GetAuctionCut(); if ( pl->GetMoney() < auctionCut ) //player doesn't have enough money, maybe message needed return; //some auctionBidderNotification would be needed, but don't know that parts.. SendAuctionCancelledToBidderMail( auction ); pl->ModifyMoney( -int32(auctionCut) ); } // Return the item by mail std::ostringstream msgAuctionCanceledOwner; msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED << ":0:0"; // item will deleted or added to received mail list MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body .AddItem(pItem) .SendMailTo(pl, auction, MAIL_CHECK_MASK_COPIED); } else { sLog.outError("Auction id: %u has nonexistent item (item guid : %u)!!!", auction->Id, auction->item_guidlow); SendAuctionCommandResult( 0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR ); return; } } else { SendAuctionCommandResult( 0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR ); //this code isn't possible ... maybe there should be ASSERT sLog.outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", pl->GetGUIDLow(), auctionId ); return; } //inform player, that auction is removed SendAuctionCommandResult( auction->Id, AUCTION_CANCEL, AUCTION_OK ); // Now remove the auction CharacterDatabase.BeginTransaction(); auction->DeleteFromDB(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); sAuctionMgr.RemoveAItem( auction->item_guidlow ); auctionHouse->RemoveAuction( auction->Id ); delete auction; }
void AuctionHouseMgr::LoadAuctions() { QueryResult* result = CharacterDatabase.Query("SELECT COUNT(*) FROM auction"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auction` is empty."); return; } Field* fields = result->Fetch(); uint32 AuctionCount = fields[0].GetUInt32(); delete result; if (!AuctionCount) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auction` is empty."); return; } result = CharacterDatabase.Query("SELECT id,houseid,itemguid,item_template,item_count,item_randompropertyid,itemowner,buyoutprice,time,moneyTime,buyguid,lastbid,startbid,deposit FROM auction"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auction` is empty."); return; } BarGoLink bar(AuctionCount); typedef std::map<uint32, std::wstring> PlayerNames; PlayerNames playerNames; // caching for load time do { fields = result->Fetch(); bar.step(); AuctionEntry* auction = new AuctionEntry; auction->Id = fields[0].GetUInt32(); uint32 houseid = fields[1].GetUInt32(); auction->itemGuidLow = fields[2].GetUInt32(); auction->itemTemplate = fields[3].GetUInt32(); auction->itemCount = fields[4].GetUInt32(); auction->itemRandomPropertyId = fields[5].GetUInt32(); auction->owner = fields[6].GetUInt32(); if (auction->owner) { std::wstring& plWName = playerNames[auction->owner]; if (plWName.empty()) { std::string plName; if (!sObjectMgr.GetPlayerNameByGUID(ObjectGuid(HIGHGUID_PLAYER, auction->owner), plName)) plName = sObjectMgr.GetMangosStringForDBCLocale(LANG_UNKNOWN); Utf8toWStr(plName, plWName); } auction->ownerName = plWName; } auction->buyout = fields[7].GetUInt64(); auction->expireTime = time_t(fields[8].GetUInt64()); auction->moneyDeliveryTime = time_t(fields[9].GetUInt64()); auction->bidder = fields[10].GetUInt32(); auction->bid = fields[11].GetUInt64(); auction->startbid = fields[12].GetUInt64(); auction->deposit = fields[13].GetUInt64(); auction->auctionHouseEntry = NULL; // init later if (auction->moneyDeliveryTime) auction->itemGuidLow = 0; // must be 0 if auction delivery pending else { // check if sold item exists for guid // and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems) Item* pItem = GetAItem(auction->itemGuidLow); if (!pItem) { auction->DeleteFromDB(); sLog.outError("Auction %u has not a existing item : %u, deleted", auction->Id, auction->itemGuidLow); delete auction; continue; } // overwrite by real item data if ((auction->itemTemplate != pItem->GetEntry()) || (auction->itemCount != pItem->GetCount()) || (auction->itemRandomPropertyId != pItem->GetItemRandomPropertyId())) { auction->itemTemplate = pItem->GetEntry(); auction->itemCount = pItem->GetCount(); auction->itemRandomPropertyId = pItem->GetItemRandomPropertyId(); // No SQL injection (no strings) CharacterDatabase.PExecute("UPDATE auction SET item_template = %u, item_count = %u, item_randompropertyid = %i WHERE itemguid = %u", auction->itemTemplate, auction->itemCount, auction->itemRandomPropertyId, auction->itemGuidLow); } } auction->auctionHouseEntry = sAuctionHouseStore.LookupEntry(houseid); if (!auction->auctionHouseEntry) { // need for send mail, use goblin auctionhouse auction->auctionHouseEntry = sAuctionHouseStore.LookupEntry(7); // Attempt send item back to owner std::ostringstream msgAuctionCanceledOwner; msgAuctionCanceledOwner << auction->itemTemplate << ":" << auction->itemRandomPropertyId << ":" << AUCTION_CANCELED << ":" << auction->Id << ":" << auction->itemCount; if (auction->itemGuidLow) { Item* pItem = GetAItem(auction->itemGuidLow); RemoveAItem(auction->itemGuidLow); auction->itemGuidLow = 0; // item will deleted or added to received mail list MailDraft(msgAuctionCanceledOwner.str(), "")// TODO: fix body .AddItem(pItem) .SendMailTo(MailReceiver(ObjectGuid(HIGHGUID_PLAYER, auction->owner)), auction, MAIL_CHECK_MASK_COPIED); } auction->DeleteFromDB(); delete auction; continue; } GetAuctionsMap(auction->auctionHouseEntry)->AddAuction(auction); } while (result->NextRow()); delete result; sLog.outString(); sLog.outString(">> Loaded %u auctions", AuctionCount); }
// this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPacket& recv_data) { DEBUG_LOG("WORLD: HandleAuctionPlaceBid"); ObjectGuid auctioneerGuid; uint32 auctionId; uint32 price; recv_data >> auctioneerGuid; recv_data >> auctionId >> price; if (!auctionId || !price) return; // check for cheaters AuctionHouseEntry const* auctionHouseEntry = GetCheckedAuctionHouseForAuctioneer(auctioneerGuid); if (!auctionHouseEntry) return; // always return pointer AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(auctionHouseEntry); AuctionEntry* auction = auctionHouse->GetAuction(auctionId); Player* pl = GetPlayer(); if (!auction || auction->owner == pl->GetGUIDLow()) { // you cannot bid your own auction: SendAuctionCommandResult(nullptr, AUCTION_BID_PLACED, AUCTION_ERR_BID_OWN); return; } ObjectGuid ownerGuid = ObjectGuid(HIGHGUID_PLAYER, auction->owner); // impossible have online own another character (use this for speedup check in case online owner) Player* auction_owner = sObjectMgr.GetPlayer(ownerGuid); if (!auction_owner && sObjectMgr.GetPlayerAccountIdByGUID(ownerGuid) == pl->GetSession()->GetAccountId()) { // you cannot bid your another character auction: SendAuctionCommandResult(nullptr, AUCTION_BID_PLACED, AUCTION_ERR_BID_OWN); return; } // cheating or client lags if (price <= auction->bid) { // client test but possible in result lags SendAuctionCommandResult(auction, AUCTION_BID_PLACED, AUCTION_ERR_HIGHER_BID); return; } // price too low for next bid if not buyout if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { // client test but possible in result lags SendAuctionCommandResult(auction, AUCTION_BID_PLACED, AUCTION_ERR_BID_INCREMENT); return; } if (price > pl->GetMoney()) { // you don't have enough money!, client tests! // SendAuctionCommandResult(auction->auctionId, AUCTION_ERR_INVENTORY, EQUIP_ERR_NOT_ENOUGH_MONEY); return; } // cheating if (price < auction->startbid) return; SendAuctionCommandResult(auction, AUCTION_BID_PLACED, AUCTION_OK); auction->UpdateBid(price, pl); }
// this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlaceBid& packet) { if (!packet.AuctionItemID || !packet.BidAmount) return; // check for cheaters Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionPlaceBid - %s not found or you can't interact with him.", packet.Auctioneer.ToString().c_str()); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); AuctionEntry* auction = auctionHouse->GetAuction(packet.AuctionItemID); Player* player = GetPlayer(); if (!auction || auction->owner == player->GetGUID().GetCounter()) { //you cannot bid your own auction: SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; } // impossible have online own another character (use this for speedup check in case online owner) ObjectGuid ownerGuid = ObjectGuid::Create<HighGuid::Player>(auction->owner); Player* auction_owner = ObjectAccessor::FindPlayer(ownerGuid); if (!auction_owner && ObjectMgr::GetPlayerAccountIdByGUID(ownerGuid) == player->GetSession()->GetAccountId()) { //you cannot bid your another character auction: SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; } // cheating if (packet.BidAmount <= auction->bid || packet.BidAmount < auction->startbid) return; // price too low for next bid if not buyout if ((packet.BidAmount < auction->buyout || auction->buyout == 0) && packet.BidAmount < auction->bid + auction->GetAuctionOutBid()) { // client already test it but just in case ... SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_HIGHER_BID); return; } if (!player->HasEnoughMoney(packet.BidAmount)) { // client already test it but just in case ... SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (packet.BidAmount < auction->buyout || auction->buyout == 0) { if (auction->bidder) { if (auction->bidder == player->GetGUID().GetCounter()) player->ModifyMoney(-int64(packet.BidAmount - auction->bid)); else { // mail to last bidder and return money sAuctionMgr->SendAuctionOutbiddedMail(auction, packet.BidAmount, GetPlayer(), trans); player->ModifyMoney(-int64(packet.BidAmount)); } } else player->ModifyMoney(-int64(packet.BidAmount)); auction->bidder = player->GetGUID().GetCounter(); auction->bid = packet.BidAmount; GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, packet.BidAmount); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); stmt->setUInt64(0, auction->bidder); stmt->setUInt32(1, auction->bid); stmt->setUInt32(2, auction->Id); trans->Append(stmt); SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); // Not sure if we must send this now. Player* owner = sObjectAccessor->FindConnectedPlayer(ObjectGuid::Create<HighGuid::Player>(auction->owner)); Item* item = sAuctionMgr->GetAItem(auction->itemGUIDLow); if (owner && item) owner->GetSession()->SendAuctionOwnerBidNotification(auction, item); } else { //buyout: if (player->GetGUID().GetCounter() == auction->bidder) player->ModifyMoney(-int64(auction->buyout - auction->bid)); else { player->ModifyMoney(-int64(auction->buyout)); if (auction->bidder) //buyout for bidded auction .. sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans); } auction->bidder = player->GetGUID().GetCounter(); auction->bid = auction->buyout; GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); //- Mails must be under transaction control too to prevent data loss sAuctionMgr->SendAuctionSalePendingMail(auction, trans); sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); sAuctionMgr->SendAuctionWonMail(auction, trans); auction->DeleteFromDB(trans); sAuctionMgr->RemoveAItem(auction->itemGUIDLow); auctionHouse->RemoveAuction(auction); } player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
void WorldSession::BuildListAuctionItems(std::vector<AuctionEntry*> const& auctions, WorldPacket& data, std::wstring const& wsearchedname, uint32 listfrom, uint32 levelmin, uint32 levelmax, uint32 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32& count, uint32& totalcount, bool isFull) { int loc_idx = _player->GetSession()->GetSessionDbLocaleIndex(); for (std::vector<AuctionEntry*>::const_iterator itr = auctions.begin(); itr != auctions.end(); ++itr) { AuctionEntry* Aentry = *itr; Item* item = sAuctionMgr.GetAItem(Aentry->itemGuidLow); if (!item) continue; if (isFull) { ++count; Aentry->BuildAuctionInfo(data); } else { ItemPrototype const* proto = item->GetProto(); if (itemClass != 0xffffffff && proto->Class != itemClass) continue; if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass) continue; if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType) continue; if (quality != 0xffffffff && proto->Quality < quality) continue; if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) continue; if (usable != 0x00) { if (_player->CanUseItem(item) != EQUIP_ERR_OK) continue; if (proto->Class == ITEM_CLASS_RECIPE) { if (SpellEntry const* spell = sSpellStore.LookupEntry(proto->Spells[0].SpellId)) { if (_player->HasSpell(spell->EffectTriggerSpell[EFFECT_INDEX_0])) continue; } } } std::string name = proto->Name1; sObjectMgr.GetItemLocaleStrings(proto->ItemId, loc_idx, &name); if (!wsearchedname.empty() && !Utf8FitTo(name, wsearchedname)) continue; if (count < 50 && totalcount >= listfrom) { ++count; Aentry->BuildAuctionInfo(data); } } ++totalcount; } }
// Tries to bid and buy items based on their prices and chances set in configs void AuctionBotBuyer::BuyAndBidItems(BuyerConfiguration& config) { time_t now = time(nullptr); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config.GetHouseType()); CheckEntryMap& items = config.EligibleItems; // Max amount of items to buy or bid uint32 cycles = sAuctionBotConfig->GetItemPerCycleNormal(); if (items.size() > sAuctionBotConfig->GetItemPerCycleBoost()) { // set more cycles if there is a huge influx of items cycles = sAuctionBotConfig->GetItemPerCycleBoost(); TC_LOG_DEBUG("ahbot", "AHBot: Boost value used for Buyer! (if this happens often adjust both ItemsPerCycle in worldserver.conf)"); } // Process items eligible to be bidded or bought CheckEntryMap::iterator itr = items.begin(); while (cycles && itr != items.end()) { AuctionEntry* auction = auctionHouse->GetAuction(itr->second.AuctionId); if (!auction) { TC_LOG_DEBUG("ahbot", "AHBot: Entry %u doesn't exists, perhaps bought already?", itr->second.AuctionId); items.erase(itr++); continue; } // Check if the item has been checked once before // If it has been checked and it was recently, skip it if (itr->second.LastChecked && (now - itr->second.LastChecked) <= _checkInterval) { TC_LOG_DEBUG("ahbot", "AHBot: In time interval wait for entry %u!", auction->Id); ++itr; continue; } Item* item = sAuctionMgr->GetAItem(auction->itemGUIDLow); if (!item) { // auction item not accessible, possible auction in payment pending mode items.erase(itr++); continue; } // price to bid if bidding uint32 bidPrice; if (auction->bid >= auction->startbid) { // get bid price to outbid previous bidder bidPrice = auction->bid + auction->GetAuctionOutBid(); } else { // no previous bidders - use starting bid bidPrice = auction->startbid; } const BuyerItemInfo* ahInfo = nullptr; BuyerItemInfoMap::const_iterator sameItemItr = config.SameItemInfo.find(item->GetEntry()); if (sameItemItr != config.SameItemInfo.end()) ahInfo = &sameItemItr->second; TC_LOG_DEBUG("ahbot", "AHBot: Rolling for AHentry %u:", auction->Id); // Roll buy and bid chances bool successBuy = RollBuyChance(ahInfo, item, auction, bidPrice); bool successBid = RollBidChance(ahInfo, item, auction, bidPrice); // If roll bidding succesfully and bid price is above buyout -> buyout // If roll for buying was successful but not for bid, buyout directly // If roll bidding was also successful, buy the entry with 20% chance // - Better bid than buy since the item is bought by bot if no player bids after // Otherwise bid if roll for bid was successful if ((auction->buyout && successBid && bidPrice >= auction->buyout) || (successBuy && (!successBid || urand(1, 5) == 1))) BuyEntry(auction, auctionHouse); // buyout else if (successBid) PlaceBidToEntry(auction, bidPrice); // bid itr->second.LastChecked = now; --cycles; ++itr; } // Clear not needed entries config.SameItemInfo.clear(); }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSellItem& packet) { if (packet.Items.size() > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } for (auto const& item : packet.Items) if (!item.Guid || !item.UseCount || item.UseCount > 1000) return; if (!packet.MinBid || !packet.RunTime) return; if (packet.MinBid > MAX_MONEY_AMOUNT || packet.BuyoutPrice > MAX_MONEY_AMOUNT) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Player %s (%s) attempted to sell item with higher price than max gold amount.", _player->GetName().c_str(), _player->GetGUID().ToString().c_str()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) not found or you can't interact with him.", packet.Auctioneer.ToString().c_str()); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) has wrong faction.", packet.Auctioneer.ToString().c_str()); return; } packet.RunTime *= MINUTE; switch (packet.RunTime) { case 1 * MIN_AUCTION_TIME: case 2 * MIN_AUCTION_TIME: case 4 * MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); uint32 finalCount = 0; for (auto const& packetItem : packet.Items) { Item* item = _player->GetItemByGuid(packetItem.Guid); if (!item) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); return; } if (sAuctionMgr->GetAItem(item->GetGUID().GetCounter()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->GetFlags() & ITEM_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < packetItem.UseCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } finalCount += packetItem.UseCount; } if (packet.Items.empty()) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } if (!finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } // check if there are 2 identical guids, in this case user is most likely cheating for (uint32 i = 0; i < packet.Items.size() - 1; ++i) { for (uint32 j = i + 1; j < packet.Items.size(); ++j) { if (packet.Items[i].Guid == packet.Items[j].Guid) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } } for (auto const& packetItem : packet.Items) { Item* item = _player->GetItemByGuid(packetItem.Guid); if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } Item* item = _player->GetItemByGuid(packet.Items[0].Guid); uint32 auctionTime = uint32(packet.RunTime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, packet.RunTime, item, finalCount); if (!_player->HasEnoughMoney((uint64)deposit)) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } AuctionEntry* AH = new AuctionEntry(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = UI64LIT(23442); ///@TODO - HARDCODED DB GUID, BAD BAD BAD else AH->auctioneer = packet.Auctioneer.GetCounter(); // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (packet.Items.size() == 1 && item->GetCount() == packet.Items[0].UseCount) { if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = item->GetGUID().GetCounter(); AH->itemEntry = item->GetEntry(); AH->itemCount = item->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = packet.MinBid; AH->bidder = UI64LIT(0); AH->bid = 0; AH->buyout = packet.BuyoutPrice; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: %s %s is selling item %s %s to auctioneer " UI64FMTD " with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetGUID().ToString().c_str(), _player->GetName().c_str(), item->GetGUID().ToString().c_str(), item->GetTemplate()->GetDefaultLocaleName(), AH->auctioneer, item->GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->GetDefaultLocaleName(), newItem->GetEntry(), newItem->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = newItem->GetGUID().GetCounter(); AH->itemEntry = newItem->GetEntry(); AH->itemCount = newItem->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = packet.MinBid; AH->bidder = UI64LIT(0); AH->bid = 0; AH->buyout = packet.BuyoutPrice; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: %s %s is selling %s %s to auctioneer " UI64FMTD " with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetGUID().ToString().c_str(), _player->GetName().c_str(), newItem->GetGUID().ToString().c_str(), newItem->GetTemplate()->GetDefaultLocaleName(), AH->auctioneer, newItem->GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); for (auto const& packetItem : packet.Items) { Item* item2 = _player->GetItemByGuid(packetItem.Guid); // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2->GetCount() == packetItem.UseCount) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); delete item2; } else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { item2->SetCount(item2->GetCount() - packetItem.UseCount); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), packetItem.UseCount); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } _player->ModifyMoney(-int32(deposit)); }
//this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_PLACE_BID"); uint64 auctioneer; uint32 auctionId; uint32 priceTmp; uint64 price; recv_data >> auctioneer; recv_data >> auctionId >> priceTmp; price = priceTmp; if (!auctionId || !price) return; //check for cheaters Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); AuctionEntry* auction = auctionHouse->GetAuction(auctionId); Player* player = GetPlayer(); if (!auction || auction->owner == player->GetGUIDLow()) { //you cannot bid your own auction: SendAuctionCommandResult(0, AUCTION_PLACE_BID, ERR_AUCTION_DATABASE_ERROR); return; } // impossible have online own another character (use this for speedup check in case online owner) Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == player->GetSession()->GetAccountId()) { //you cannot bid your another character auction: SendAuctionCommandResult(0, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; } // cheating if (price <= auction->bid || price < auction->startbid) return; // price too low for next bid if not buyout if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { //auction has already higher bid, client tests it! return; } if (!player->HasEnoughMoney(price)) { //you don't have enought money!, client tests! //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); return; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (price < auction->buyout || auction->buyout == 0) { if (auction->bidder > 0) { if (auction->bidder == player->GetGUIDLow()) player->ModifyMoney(-int32(price - auction->bid)); else { // mail to last bidder and return money sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans); player->ModifyMoney(-int32(price)); } } else player->ModifyMoney(-int32(price)); auction->bidder = player->GetGUIDLow(); auction->bid = (price >> 32); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); trans->PAppend("UPDATE auctionhouse SET buyguid = '%u', lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0); } else { //buyout: if (player->GetGUIDLow() == auction->bidder)
void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player, std::wstring const& wsearchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32& count, uint32& totalcount, bool getall) { int loc_idx = player->GetSession()->GetSessionDbLocaleIndex(); int locdbc_idx = player->GetSession()->GetSessionDbcLocale(); time_t curTime = GameTime::GetGameTime(); PlayerGetAllThrottleMap::const_iterator itr = GetAllThrottleMap.find(player->GetGUID()); time_t throttleTime = itr != GetAllThrottleMap.end() ? itr->second : curTime; if (getall && throttleTime <= curTime) { for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr) { AuctionEntry* Aentry = itr->second; // Skip expired auctions if (Aentry->expire_time < curTime) continue; Item* item = sAuctionMgr->GetAItem(Aentry->itemGUIDLow); if (!item) continue; ++count; ++totalcount; Aentry->BuildAuctionInfo(data, item); if (count >= MAX_GETALL_RETURN) break; } GetAllThrottleMap[player->GetGUID()] = curTime + sWorld->getIntConfig(CONFIG_AUCTION_GETALL_DELAY); return; } for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr) { AuctionEntry* Aentry = itr->second; // Skip expired auctions if (Aentry->expire_time < curTime) continue; Item* item = sAuctionMgr->GetAItem(Aentry->itemGUIDLow); if (!item) continue; ItemTemplate const* proto = item->GetTemplate(); if (itemClass != 0xffffffff && proto->Class != itemClass) continue; if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass) continue; if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType) continue; if (quality != 0xffffffff && proto->Quality != quality) continue; if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) continue; if (usable != 0x00 && player->CanUseItem(item) != EQUIP_ERR_OK) continue; // Allow search by suffix (ie: of the Monkey) or partial name (ie: Monkey) // No need to do any of this if no search term was entered if (!wsearchedname.empty()) { std::string name = proto->Name1; if (name.empty()) continue; // local name if (loc_idx >= 0) if (ItemLocale const* il = sObjectMgr->GetItemLocale(proto->ItemId)) ObjectMgr::GetLocaleString(il->Name, loc_idx, name); // DO NOT use GetItemEnchantMod(proto->RandomProperty) as it may return a result // that matches the search but it may not equal item->GetItemRandomPropertyId() // used in BuildAuctionInfo() which then causes wrong items to be listed int32 propRefID = item->GetItemRandomPropertyId(); if (propRefID) { // Append the suffix to the name (ie: of the Monkey) if one exists // These are found in ItemRandomSuffix.dbc and ItemRandomProperties.dbc // even though the DBC names seem misleading char* const* suffix = nullptr; if (propRefID < 0) { const ItemRandomSuffixEntry* itemRandSuffix = sItemRandomSuffixStore.LookupEntry(-propRefID); if (itemRandSuffix) suffix = itemRandSuffix->nameSuffix; } else { const ItemRandomPropertiesEntry* itemRandProp = sItemRandomPropertiesStore.LookupEntry(propRefID); if (itemRandProp) suffix = itemRandProp->nameSuffix; } // dbc local name if (suffix) { // Append the suffix (ie: of the Monkey) to the name using localization // or default enUS if localization is invalid name += ' '; name += suffix[locdbc_idx >= 0 ? locdbc_idx : LOCALE_enUS]; } } // Perform the search (with or without suffix) if (!Utf8FitTo(name, wsearchedname)) continue; } // Add the item if no search term or if entered search term was found if (count < 50 && totalcount >= listfrom) { ++count; Aentry->BuildAuctionInfo(data, item); } ++totalcount; } }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) { ObjectGuid auctioneer; uint32 itemsCount, etime, bid, buyout; recvData >> auctioneer; recvData >> itemsCount; ObjectGuid itemGUIDs[MAX_AUCTION_ITEMS]; // 160 slot = 4x 36 slot bag + backpack 16 slot uint32 count[MAX_AUCTION_ITEMS]; memset(count, 0, sizeof(count)); if (itemsCount > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); recvData.rfinish(); return; } for (uint32 i = 0; i < itemsCount; ++i) { recvData >> itemGUIDs[i]; recvData >> count[i]; if (!itemGUIDs[i] || !count[i] || count[i] > 1000) { recvData.rfinish(); return; } } recvData >> bid; recvData >> buyout; recvData >> etime; if (!bid || !etime) return; if (bid > MAX_MONEY_AMOUNT || buyout > MAX_MONEY_AMOUNT) { TC_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->GetGUID().GetCounter()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) not found or you can't interact with him.", auctioneer.ToString().c_str()); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) has wrong faction.", auctioneer.ToString().c_str()); return; } etime *= MINUTE; switch (etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item* items[MAX_AUCTION_ITEMS]; uint32 finalCount = 0; uint32 itemEntry = 0; for (uint32 i = 0; i < itemsCount; ++i) { Item* item = _player->GetItemByGuid(itemGUIDs[i]); if (!item) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); return; } if (itemEntry == 0) itemEntry = item->GetTemplate()->ItemId; if (sAuctionMgr->GetAItem(item->GetGUID().GetCounter()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < count[i] || itemEntry != item->GetTemplate()->ItemId) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } items[i] = item; finalCount += count[i]; } if (!finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } // check if there are 2 identical guids, in this case user is most likely cheating for (uint32 i = 0; i < itemsCount - 1; ++i) { for (uint32 j = i + 1; j < itemsCount; ++j) { if (itemGUIDs[i] == itemGUIDs[j]) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } Item* item = items[0]; uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); if (!_player->HasEnoughMoney(deposit)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } AuctionEntry* AH = new AuctionEntry(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->houseId = AUCTIONHOUSE_NEUTRAL; else { CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(creature->GetSpawnId()); if (!auctioneerData) { TC_LOG_ERROR("misc", "Data for auctioneer not found (%s)", auctioneer.ToString().c_str()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id); if (!auctioneerInfo) { TC_LOG_ERROR("misc", "Non existing auctioneer (%s)", auctioneer.ToString().c_str()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } const AuctionHouseEntry* AHEntry = sAuctionMgr->GetAuctionHouseEntry(auctioneerInfo->faction); AH->houseId = AHEntry->houseId; } // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (itemsCount == 1 && item->GetCount() == count[0]) { if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = item->GetGUID().GetCounter(); AH->itemEntry = item->GetEntry(); AH->itemCount = item->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->etime = etime; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUID().GetCounter(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUID().GetCounter(), item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); sAuctionMgr->PendingAuctionAdd(_player, AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = newItem->GetGUID().GetCounter(); AH->itemEntry = newItem->GetEntry(); AH->itemCount = newItem->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->etime = etime; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUID().GetCounter(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUID().GetCounter(), newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); sAuctionMgr->PendingAuctionAdd(_player, AH); for (uint32 j = 0; j < itemsCount; ++j) { Item* item2 = items[j]; // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2->GetCount() == count[j]) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); delete item2; } else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { item2->SetCount(item2->GetCount() - count[j]); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } }
void AuctionHouseMgr::LoadAuctions() { QueryResult *result = CharacterDatabase.Query("SELECT COUNT(*) FROM auction"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auction` is empty."); return; } Field *fields = result->Fetch(); uint32 AuctionCount=fields[0].GetUInt32(); delete result; if (!AuctionCount) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auction` is empty."); return; } result = CharacterDatabase.Query("SELECT id,houseid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit FROM auction"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auction` is empty."); return; } BarGoLink bar(AuctionCount); do { fields = result->Fetch(); bar.step(); AuctionEntry *auction = new AuctionEntry; auction->Id = fields[0].GetUInt32(); uint32 houseid = fields[1].GetUInt32(); auction->itemGuidLow = fields[2].GetUInt32(); auction->itemTemplate = fields[3].GetUInt32(); auction->owner = fields[4].GetUInt32(); auction->buyout = fields[5].GetUInt32(); auction->expireTime = fields[6].GetUInt32(); auction->bidder = fields[7].GetUInt32(); auction->bid = fields[8].GetUInt32(); auction->startbid = fields[9].GetUInt32(); auction->deposit = fields[10].GetUInt32(); auction->auctionHouseEntry = NULL; // init later // check if sold item exists for guid // and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems) Item* pItem = GetAItem(auction->itemGuidLow); if (!pItem) { auction->DeleteFromDB(); sLog.outError("Auction %u has not a existing item : %u, deleted", auction->Id, auction->itemGuidLow); delete auction; continue; } auction->auctionHouseEntry = sAuctionHouseStore.LookupEntry(houseid); if (!houseid) { // need for send mail, use goblin auctionhouse auction->auctionHouseEntry = sAuctionHouseStore.LookupEntry(7); // Attempt send item back to owner std::ostringstream msgAuctionCanceledOwner; msgAuctionCanceledOwner << auction->itemTemplate << ":0:" << AUCTION_CANCELED; // item will deleted or added to received mail list MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body .AddItem(pItem) .SendMailTo(MailReceiver(ObjectGuid(HIGHGUID_PLAYER, auction->owner)), auction, MAIL_CHECK_MASK_COPIED); RemoveAItem(auction->itemGuidLow); auction->DeleteFromDB(); delete auction; continue; } GetAuctionsMap(auction->auctionHouseEntry)->AddAuction(auction); } while (result->NextRow()); delete result; sLog.outString(); sLog.outString(">> Loaded %u auctions", AuctionCount); }
//this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data ) { uint64 auctioneer; uint32 auctionId; uint32 price; recv_data >> auctioneer; recv_data >> auctionId >> price; if (!auctionId || !price) return; //check for cheaters Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER); if (!pCreature) { sLog.outDebug( "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) ); return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap( pCreature->getFaction() ); AuctionEntry *auction = auctionHouse->GetAuction(auctionId); Player *pl = GetPlayer(); if( !auction || auction->owner == pl->GetGUIDLow() ) { //you cannot bid your own auction: SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR ); return; } // impossible have online own another character (use this for speedup check in case online owner) Player* auction_owner = objmgr.GetPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); if( !auction_owner && objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == pl->GetSession()->GetAccountId()) { //you cannot bid your another character auction: SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR ); return; } // cheating if(price <= auction->bid) return; // price too low for next bid if not buyout if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { //auction has already higher bid, client tests it! return; } if (price > pl->GetMoney()) { //you don't have enought money!, client tests! //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); return; } if ((price < auction->buyout) || (auction->buyout == 0)) { if (auction->bidder > 0) { if ( auction->bidder == pl->GetGUIDLow() ) { pl->ModifyMoney( -int32(price - auction->bid)); } else { // mail to last bidder and return money SendAuctionOutbiddedMail( auction , price ); pl->ModifyMoney( -int32(price) ); } } else { pl->ModifyMoney( -int32(price) ); } auction->bidder = pl->GetGUIDLow(); auction->bid = price; // after this update we should save player's money ... CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0 ); } else { //buyout: if (pl->GetGUIDLow() == auction->bidder ) { pl->ModifyMoney(-int32(auction->buyout - auction->bid)); } else { pl->ModifyMoney(-int32(auction->buyout)); if ( auction->bidder ) //buyout for bidded auction .. { SendAuctionOutbiddedMail( auction, auction->buyout ); } } auction->bidder = pl->GetGUIDLow(); auction->bid = auction->buyout; auctionmgr.SendAuctionSalePendingMail( auction ); auctionmgr.SendAuctionSuccessfulMail( auction ); auctionmgr.SendAuctionWonMail( auction ); SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK); auctionmgr.RemoveAItem(auction->item_guidlow); auctionHouse->RemoveAuction(auction->Id); auction->DeleteFromDB(); delete auction; } CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); }
void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player, std::wstring const& wsearchedname, uint32 listfrom, uint32 levelmin, uint32 levelmax, uint32 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32& count, uint32& totalcount) { int loc_idx = player->GetSession()->GetSessionDbLocaleIndex(); for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin();itr != AuctionsMap.end();++itr) { AuctionEntry *Aentry = itr->second; Item *item = sAuctionMgr.GetAItem(Aentry->itemGuidLow); if (!item) continue; { ItemPrototype const *proto = item->GetProto(); if (itemClass != 0xffffffff && proto->Class != itemClass) continue; if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass) continue; if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType) continue; if (quality != 0xffffffff && proto->Quality < quality) continue; if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) continue; if (usable != 0x00 && player->CanUseItem(item) != EQUIP_ERR_OK) continue; if (usable != 0x00 && proto->Class == ITEM_CLASS_RECIPE) if (SpellEntry const* spell = sSpellStore.LookupEntry(proto->Spells[0].SpellId)) if (player->HasSpell(spell->EffectTriggerSpell[EFFECT_INDEX_0])) continue; std::string name = proto->Name1; if (name.empty()) continue; // local name if (loc_idx >= 0) { ItemLocale const *il = sObjectMgr.GetItemLocale(proto->ItemId); if (il) { if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty()) name = il->Name[loc_idx]; } } if (!wsearchedname.empty() && !Utf8FitTo(name, wsearchedname)) continue; if (count < 50 && totalcount >= listfrom) { ++count; Aentry->BuildAuctionInfo(data); } } ++totalcount; } }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data ) { uint64 auctioneer, item; uint32 etime, bid, buyout; recv_data >> auctioneer >> item; recv_data >> bid >> buyout >> etime; Player *pl = GetPlayer(); if (!item || !bid || !etime) return; //check for cheaters Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER); if (!pCreature) { sLog.outDebug( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) ); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(pCreature->getFaction()); if(!auctionHouseEntry) { sLog.outDebug( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer)) ); return; } // client send time in minutes, convert to common used sec time etime *= MINUTE; // client understand only 3 auction time switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); Item *it = pl->GetItemByGuid( item ); //do not allow to sell already auctioned items if(auctionmgr.GetAItem(GUID_LOPART(item))) { sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) if(!it) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if(!it->CanBeTraded()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap( pCreature->getFaction() ); //we have to take deposit : uint32 deposit = auctionmgr.GetAuctionDeposit( auctionHouseEntry, etime, it ); if ( pl->GetMoney() < deposit ) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount()); } pl->ModifyMoney( -int32(deposit) ); uint32 auction_time = uint32(etime * sWorld.getRate(RATE_AUCTION_TIME)); AuctionEntry *AH = new AuctionEntry; AH->Id = objmgr.GenerateAuctionID(); AH->auctioneer = GUID_LOPART(auctioneer); AH->item_guidlow = GUID_LOPART(item); AH->item_template = it->GetEntry(); AH->owner = pl->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auction_time; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; sLog.outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), GUID_LOPART(auctioneer), bid, buyout, auction_time, AH->GetHouseId()); auctionHouse->AddAuction(AH); auctionmgr.AddAItem(it); pl->MoveItemFromInventory( it->GetBagSlot(), it->GetSlot(), true); CharacterDatabase.BeginTransaction(); it->DeleteFromInventoryDB(); it->SaveToDB(); // recursive and not have transaction guard into self, not in inventiory and can be save standalone AH->SaveToDB(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); }
void AuctionHouseMgr::DeleteExpiredAuctionsAtStartup() { // Deletes expired auctions. Should be called at server start before loading auctions. // DO NOT USE after auctions are already loaded since this deletes from the DB // and assumes the auctions HAVE NOT been loaded into a list or AuctionEntryMap yet uint32 oldMSTime = getMSTime(); uint32 expirecount = 0; time_t curTime = sWorld->GetGameTime(); // Query the DB to see if there are any expired auctions PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_AUCTIONS); stmt->setUInt32(0, (uint32)curTime+60); PreparedQueryResult expAuctions = CharacterDatabase.Query(stmt); if (!expAuctions) { TC_LOG_INFO("server.loading", ">> No expired auctions to delete"); return; } do { Field* fields = expAuctions->Fetch(); AuctionEntry* auction = new AuctionEntry(); // Can't use LoadFromDB() because it assumes the auction map is loaded if (!auction->LoadFromFieldList(fields)) { // For some reason the record in the DB is broken (possibly corrupt // faction info). Delete the object and move on. delete auction; continue; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (auction->bidder==0) { // Cancel the auction, there was no bidder sAuctionMgr->SendAuctionExpiredMail(auction, trans); } else { // Send the item to the winner and money to seller sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); sAuctionMgr->SendAuctionWonMail(auction, trans); } // Call the appropriate AuctionHouseObject script // ** Do we need to do this while core is still loading? ** sScriptMgr->OnAuctionExpire(GetAuctionsMap(auction->factionTemplateId), auction); // Delete the auction from the DB auction->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); // Release memory delete auction; ++expirecount; } while (expAuctions->NextRow()); TC_LOG_INFO("server.loading", ">> Deleted %u expired auctions in %u ms", expirecount, GetMSTimeDiffToNow(oldMSTime)); }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) { ObjectGuid auctioneer; uint64 bid, buyout; uint32 etime; uint8 itemCount; // 32 slots, value sent as 5 bits ObjectGuid itemGuids[MAX_AUCTION_ITEMS]; uint32 count[MAX_AUCTION_ITEMS]; recvData >> auctioneer; // auctioneer GUID recvData >> bid; recvData >> buyout; recvData >> etime; if (!bid || !etime) { recvData.rfinish(); return; } if (bid > MAX_MONEY_AMOUNT || buyout > MAX_MONEY_AMOUNT) { TC_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()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); recvData.rfinish(); return; } itemCount = recvData.ReadBits(5); // Item Counts recvData.FlushBits(); if (itemCount > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); recvData.rfinish(); return; } for (uint8 i = 0; i < itemCount; i++) { recvData >> itemGuids[i]; // Item GUID recvData >> count[i]; // Count of Item if (!itemGuids[i] || !count[i] || count[i] > 1000) { recvData.rfinish(); return; } } Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(auctioneer)); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", GUID_LOPART(auctioneer)); return; } etime *= MINUTE; switch (etime) { case 1 * MIN_AUCTION_TIME: case 2 * MIN_AUCTION_TIME: case 4 * MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item* items[MAX_AUCTION_ITEMS]; uint32 finalCount = 0; for (uint32 i = 0; i < itemCount; ++i) { Item* item = _player->GetItemByGuid(itemGuids[i]); if (!item) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); return; } if (sAuctionMgr->GetAItem(item->GetGUIDLow()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_EXPIRATION) || item->GetCount() < count[i]) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } items[i] = item; finalCount += count[i]; } if (!finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } for (uint32 i = 0; i < itemCount; ++i) { Item* item = items[i]; if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } Item* item = items[0]; uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); if (!_player->HasEnoughMoney((uint64)deposit)) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } AuctionEntry* AH = new AuctionEntry(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = 23442; ///@TODO - HARDCODED DB GUID, BAD BAD BAD else AH->auctioneer = GUID_LOPART(auctioneer); // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (itemCount == 1 && item->GetCount() == count[0]) { if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } AH->autcionId = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = item->GetGUIDLow(); AH->itemEntry = item->GetEntry(); AH->itemCount = item->GetCount(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) " "to auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); } AH->autcionId = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = newItem->GetGUIDLow(); AH->itemEntry = newItem->GetEntry(); AH->itemCount = newItem->GetCount(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to " "auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); for (uint32 j = 0; j < itemCount; ++j) { Item* item2 = items[j]; // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2->GetCount() == count[j]) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); } else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { item2->SetCount(item2->GetCount() - count[j]); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } _player->ModifyMoney(-int32(deposit)); }
// this void is called when auction_owner cancels his auction void WorldSession::HandleAuctionRemoveItem(WorldPacket& recv_data) { DEBUG_LOG("WORLD: HandleAuctionRemoveItem"); ObjectGuid auctioneerGuid; uint32 auctionId; recv_data >> auctioneerGuid; recv_data >> auctionId; // DEBUG_LOG("Cancel AUCTION AuctionID: %u", auctionId); AuctionHouseEntry const* auctionHouseEntry = GetCheckedAuctionHouseForAuctioneer(auctioneerGuid); if (!auctionHouseEntry) return; // always return pointer AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(auctionHouseEntry); AuctionEntry* auction = auctionHouse->GetAuction(auctionId); Player* pl = GetPlayer(); if (!auction || auction->owner != pl->GetGUIDLow()) { SendAuctionCommandResult(nullptr, AUCTION_REMOVED, AUCTION_ERR_DATABASE); sLog.outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is nullptr", pl->GetGUIDLow(), auctionId); return; } Item* pItem = sAuctionMgr.GetAItem(auction->itemGuidLow); if (!pItem) { sLog.outError("Auction id: %u has nonexistent item (item guid : %u)!!!", auction->Id, auction->itemGuidLow); SendAuctionCommandResult(nullptr, AUCTION_REMOVED, AUCTION_ERR_INVENTORY, EQUIP_ERR_ITEM_NOT_FOUND); return; } if (auction->bid) // If we have a bid, we have to send him the money he paid { uint32 auctionCut = auction->GetAuctionCut(); if (pl->GetMoney() < auctionCut) // player doesn't have enough money, maybe message needed return; if (auction->bidder) // if auction have real existed bidder send mail SendAuctionCancelledToBidderMail(auction); pl->ModifyMoney(-int32(auctionCut)); } // Return the item by mail std::ostringstream msgAuctionCanceledOwner; msgAuctionCanceledOwner << auction->itemTemplate << ":" << auction->itemRandomPropertyId << ":" << AUCTION_CANCELED; // item will deleted or added to received mail list MailDraft(msgAuctionCanceledOwner.str()) .AddItem(pItem) .SendMailTo(pl, auction, MAIL_CHECK_MASK_COPIED); // inform player, that auction is removed SendAuctionCommandResult(auction, AUCTION_REMOVED, AUCTION_OK); // Now remove the auction CharacterDatabase.BeginTransaction(); auction->DeleteFromDB(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); sAuctionMgr.RemoveAItem(auction->itemGuidLow); auctionHouse->RemoveAuction(auction->Id); delete auction; }
// this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_PLACE_BID"); ObjectGuid auctioneer; uint32 auctionId; uint64 price; recvData >> auctioneer; recvData >> auctionId; recvData >> price; if (!auctionId || !price) return; // check for cheaters Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); AuctionEntry* auction = auctionHouse->GetAuction(auctionId); Player* player = GetPlayer(); if (!auction || auction->owner == player->GetGUIDLow()) { //you cannot bid your own auction: SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; } // impossible have online own another character (use this for speedup check in case online owner) /*Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == player->GetSession()->GetAccountId()) { //you cannot bid your another character auction: SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; }*/ // cheating if (price <= auction->bid || price < auction->startbid) return; // price too low for next bid if not buyout if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { // client already test it but just in case ... SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_HIGHER_BID); return; } if (!player->HasEnoughMoney(price)) { // client already test it but just in case ... SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (price < auction->buyout || auction->buyout == 0) { if (auction->bidder > 0) { if (auction->bidder == player->GetGUIDLow()) player->ModifyMoney(-int64(price - auction->bid)); else { // mail to last bidder and return money sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans); player->ModifyMoney(-int64(price)); } } else player->ModifyMoney(-int64(price)); auction->bidder = player->GetGUIDLow(); auction->bid = price; GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); stmt->setUInt32(0, auction->bidder); stmt->setUInt32(1, auction->bid); stmt->setUInt32(2, auction->autcionId); trans->Append(stmt); SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); } else { //buyout: if (player->GetGUIDLow() == auction->bidder) player->ModifyMoney(-int64(auction->buyout - auction->bid)); else { player->ModifyMoney(-int64(auction->buyout)); if (auction->bidder) //buyout for bidded auction .. sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans); } auction->bidder = player->GetGUIDLow(); auction->bid = auction->buyout; GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); //- Mails must be under transaction control too to prevent data loss sAuctionMgr->SendAuctionSalePendingMail(auction, trans); sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); sAuctionMgr->SendAuctionWonMail(auction, trans); SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); auction->DeleteFromDB(trans); uint32 itemEntry = auction->itemEntry; sAuctionMgr->RemoveAItem(auction->itemGUIDLow); auctionHouse->RemoveAuction(auction, itemEntry); } player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
// this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data ) { DEBUG_LOG("WORLD: HandleAuctionPlaceBid"); ObjectGuid auctioneerGuid; uint32 auctionId; uint32 price; recv_data >> auctioneerGuid; recv_data >> auctionId >> price; if (!auctionId || !price) return; // check for cheaters AuctionHouseEntry const* auctionHouseEntry = GetCheckedAuctionHouseForAuctioneer(auctioneerGuid); if (!auctionHouseEntry) return; // always return pointer AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(auctionHouseEntry); // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); AuctionEntry *auction = auctionHouse->GetAuction(auctionId); Player *pl = GetPlayer(); if( !auction || auction->owner == pl->GetGUIDLow() ) { // you cannot bid your own auction: SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR ); return; } ObjectGuid ownerGuid = ObjectGuid(HIGHGUID_PLAYER, auction->owner); // impossible have online own another character (use this for speedup check in case online owner) Player* auction_owner = sObjectMgr.GetPlayer(ownerGuid); if (!auction_owner && sObjectMgr.GetPlayerAccountIdByGUID(ownerGuid) == pl->GetSession()->GetAccountId()) { // you cannot bid your another character auction: SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR ); return; } // cheating if(price <= auction->bid || price < auction->startbid) return; // price too low for next bid if not buyout if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { // auction has already higher bid, client tests it! return; } if (price > pl->GetMoney()) { // you don't have enough money!, client tests! // SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); return; } if ((price < auction->buyout) || (auction->buyout == 0)) { if (auction->bidder > 0) { if ( auction->bidder == pl->GetGUIDLow() ) { pl->ModifyMoney( -int32(price - auction->bid)); } else { // mail to last bidder and return money SendAuctionOutbiddedMail( auction , price ); pl->ModifyMoney( -int32(price) ); } } else { pl->ModifyMoney( -int32(price) ); } auction->bidder = pl->GetGUIDLow(); auction->bid = price; GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); // after this update we should save player's money ... CharacterDatabase.PExecute("UPDATE auction SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0 ); } else { // buyout: if (pl->GetGUIDLow() == auction->bidder ) { pl->ModifyMoney(-int32(auction->buyout - auction->bid)); } else { pl->ModifyMoney(-int32(auction->buyout)); if ( auction->bidder ) // buyout for bidded auction .. { SendAuctionOutbiddedMail( auction, auction->buyout ); } } auction->bidder = pl->GetGUIDLow(); auction->bid = auction->buyout; GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); sAuctionMgr.SendAuctionSalePendingMail( auction ); sAuctionMgr.SendAuctionSuccessfulMail( auction ); sAuctionMgr.SendAuctionWonMail( auction ); SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK); sAuctionMgr.RemoveAItem(auction->item_guidlow); auctionHouse->RemoveAuction(auction->Id); auction->DeleteFromDB(); delete auction; } CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); }
//this void is called when auction_owner cancels his auction void WorldSession::HandleAuctionRemoveItem(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_REMOVE_ITEM"); ObjectGuid auctioneer; uint32 auctionId; recvData >> auctioneer; recvData >> auctionId; Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); AuctionEntry* auction = auctionHouse->GetAuction(auctionId); Player* player = GetPlayer(); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (auction && auction->owner == player->GetGUIDLow()) { Item* pItem = sAuctionMgr->GetAItem(auction->itemGUIDLow); if (pItem) { if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid { uint32 auctionCut = auction->GetAuctionCut(); if (!player->HasEnoughMoney((uint64)auctionCut)) //player doesn't have enough money, maybe message needed return; sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans, pItem); player->ModifyMoney(-int64(auctionCut)); } // item will deleted or added to received mail list MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELED), AuctionEntry::BuildAuctionMailBody(0, 0, auction->buyout, auction->deposit, 0)) .AddItem(pItem) .SendMailTo(trans, player, auction, MAIL_CHECK_MASK_COPIED); } else { TC_LOG_ERROR("network", "Auction id: %u got non existing item (item guid : %u)!", auction->autcionId, auction->itemGUIDLow); SendAuctionCommandResult(NULL, AUCTION_CANCEL, ERR_AUCTION_DATABASE_ERROR); return; } } else { SendAuctionCommandResult(NULL, AUCTION_CANCEL, ERR_AUCTION_DATABASE_ERROR); //this code isn't possible ... maybe there should be assert TC_LOG_ERROR("network", "CHEATER: %u tried to cancel auction (id: %u) of another player or auction is NULL", player->GetGUIDLow(), auctionId); return; } //inform player, that auction is removed SendAuctionCommandResult(auction, AUCTION_CANCEL, ERR_AUCTION_OK); // Now remove the auction player->SaveInventoryAndGoldToDB(trans); auction->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); uint32 itemEntry = auction->itemEntry; sAuctionMgr->RemoveAItem(auction->itemGUIDLow); auctionHouse->RemoveAuction(auction, itemEntry); }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) { uint64 auctioneer; uint32 itemsCount, etime, bid, buyout; recv_data >> auctioneer; recv_data >> itemsCount; uint64 itemGUIDs[MAX_AUCTION_ITEMS]; // 160 slot = 4x 36 slot bag + backpack 16 slot uint32 count[MAX_AUCTION_ITEMS]; if (itemsCount > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } for (uint32 i = 0; i < itemsCount; ++i) { recv_data >> itemGUIDs[i]; recv_data >> count[i]; if (!itemGUIDs[i] || !count[i] || count[i] > 1000 ) return; } recv_data >> bid; recv_data >> buyout; recv_data >> etime; if (!bid || !etime) return; Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(auctioneer)); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", GUID_LOPART(auctioneer)); return; } etime *= MINUTE; switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item* items[MAX_AUCTION_ITEMS]; uint32 finalCount = 0; for (uint32 i = 0; i < itemsCount; ++i) { Item* item = _player->GetItemByGuid(itemGUIDs[i]); if (!item) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if (sAuctionMgr->GetAItem(item->GetGUIDLow()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < count[i]) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } items[i] = item; finalCount += count[i]; } if (!finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); if (!_player->HasEnoughMoney(deposit)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } _player->ModifyMoney(-int32(deposit)); AuctionEntry* AH = new AuctionEntry; AH->Id = sObjectMgr->GenerateAuctionID(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = 23442; else AH->auctioneer = GUID_LOPART(auctioneer); // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (itemsCount == 1 && item->GetCount() == count[i]) { if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } AH->item_guidlow = item->GetGUIDLow(); AH->item_template = item->GetEntry(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; if((sIRC.BOTMASK & 1024) != 0) sIRC.AHFunc(item->GetEntry(), item->GetTemplate()->Name1, _player->GetName(), AH->GetHouseId()); sLog->outDetail("CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); return; } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { sLog->outError("CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); } AH->item_guidlow = newItem->GetGUIDLow(); AH->item_template = newItem->GetEntry(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; if((sIRC.BOTMASK & 1024) != 0) sIRC.AHFunc(newItem->GetEntry(), newItem->GetTemplate()->Name1, _player->GetName(), AH->GetHouseId()); sLog->outDetail("CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); for (uint32 j = 0; j < itemsCount; ++j) { Item* item2 = items[j]; // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2->GetCount() == count[j]) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); } else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { item2->SetCount(item2->GetCount() - count[j]); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); return; } } }
//called when player lists his bids void WorldSession::HandleAuctionListBidderItems(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_LIST_BIDDER_ITEMS"); ObjectGuid auctioneer; uint32 listFrom; // page of auctions uint8 outbiddedCount; // count of outbidded auctions uint32 outbiddedAuctionIds[128]; recvData >> auctioneer; recvData >> listFrom; // not used in fact (this list not have page control in client) outbiddedCount = recvData.ReadBits(7); recvData.FlushBits(); for (uint8 i = 0; i < outbiddedCount; i++) recvData >> outbiddedAuctionIds[i]; /*if (recvData.size() != (16 + outbiddedCount * 4)) { TC_LOG_ERROR("network", "Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)", outbiddedCount, (unsigned long)recvData.size(), (16 + outbiddedCount * 4)); outbiddedCount = 0; }*/ Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); recvData.rfinish(); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 count = 0; uint32 totalcount = 0; WorldPacket data(SMSG_AUCTION_BIDDER_LIST_RESULT, 500); // guess size data << uint32(0); // amount place holder data << uint32(AUCTION_SEARCH_DELAY); data << totalcount; for (uint8 i = 0; i < outbiddedCount; i++) { AuctionEntry* auction = auctionHouse->GetAuction(outbiddedAuctionIds[i]); if (auction && auction->BuildAuctionInfo(data)) { ++totalcount; ++count; } } auctionHouse->BuildListBidderItems(data, GetPlayer(), count, totalcount); data.put<uint32>(0, count); // add count to placeholder SendPacket(&data); }
//this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) { uint64 auctioneer; uint32 auctionId; uint64 price; recv_data >> auctioneer; recv_data >> auctionId >> price; if (!auctionId || !price) return; //check for cheaters Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!pCreature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject *auctionHouse = sAuctionMgr->GetAuctionsMap(pCreature->getFaction()); AuctionEntry *auction = auctionHouse->GetAuction(auctionId); Player *pl = GetPlayer(); if (!auction || auction->owner == pl->GetGUIDLow()) { //you cannot bid your own auction: SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); return; } // impossible have online own another character (use this for speedup check in case online owner) Player* auction_owner = sObjectMgr->GetPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == pl->GetSession()->GetAccountId()) { //you cannot bid your another character auction: SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); return; } // cheating if (price <= auction->bid || price < auction->startbid) return; // price too low for next bid if not buyout if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { //auction has already higher bid, client tests it! return; } if (!pl->HasEnoughMoney((uint32)price)) { //you don't have enought money!, client tests! //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); return; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (price < auction->buyout || auction->buyout == 0) { if (auction->bidder > 0) { if (auction->bidder == pl->GetGUIDLow()) pl->ModifyMoney(-int32(price - auction->bid)); else { // mail to last bidder and return money sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans); pl->ModifyMoney(-int32(price)); } } else pl->ModifyMoney(-int32(price)); auction->bidder = pl->GetGUIDLow(); auction->bid = price; GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); trans->PAppend("UPDATE auctionhouse SET buyguid = '%u', lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0); } else { //buyout: if (pl->GetGUIDLow() == auction->bidder) pl->ModifyMoney(-int32(auction->buyout - auction->bid)); else { pl->ModifyMoney(-int32(auction->buyout)); if (auction->bidder) //buyout for bidded auction .. sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans); } auction->bidder = pl->GetGUIDLow(); auction->bid = auction->buyout; GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); //- Mails must be under transaction control too to prevent data loss sAuctionMgr->SendAuctionSalePendingMail(auction, trans); sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); sAuctionMgr->SendAuctionWonMail(auction, trans); SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK); auction->DeleteFromDB(trans); uint32 item_template = auction->item_template; sAuctionMgr->RemoveAItem(auction->item_guidlow); auctionHouse->RemoveAuction(auction, item_template); } pl->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
void AuctionHouseMgr::LoadAuctions() { QueryResult *result = CharacterDatabase.Query("SELECT COUNT(*) FROM auctionhouse"); if( !result ) { barGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auctionhouse` is empty."); return; } Field *fields = result->Fetch(); uint32 AuctionCount=fields[0].GetUInt32(); delete result; if(!AuctionCount) { barGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auctionhouse` is empty."); return; } result = CharacterDatabase.Query( "SELECT id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit FROM auctionhouse" ); if( !result ) { barGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 auctions. DB table `auctionhouse` is empty."); return; } barGoLink bar( AuctionCount ); AuctionEntry *aItem; do { fields = result->Fetch(); bar.step(); aItem = new AuctionEntry; aItem->Id = fields[0].GetUInt32(); aItem->auctioneer = fields[1].GetUInt32(); aItem->item_guidlow = fields[2].GetUInt32(); aItem->item_template = fields[3].GetUInt32(); aItem->owner = fields[4].GetUInt32(); aItem->buyout = fields[5].GetUInt32(); aItem->expire_time = fields[6].GetUInt32(); aItem->bidder = fields[7].GetUInt32(); aItem->bid = fields[8].GetUInt32(); aItem->startbid = fields[9].GetUInt32(); aItem->deposit = fields[10].GetUInt32(); CreatureData const* auctioneerData = sObjectMgr.GetCreatureData(aItem->auctioneer); if(!auctioneerData) { aItem->DeleteFromDB(); sLog.outError("Auction %u has not a existing auctioneer (GUID : %u)", aItem->Id, aItem->auctioneer); delete aItem; continue; } CreatureInfo const* auctioneerInfo = ObjectMgr::GetCreatureTemplate(auctioneerData->id); if(!auctioneerInfo) { aItem->DeleteFromDB(); sLog.outError("Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", aItem->Id, aItem->auctioneer,auctioneerData->id); delete aItem; continue; } aItem->auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(auctioneerInfo->faction_A); if(!aItem->auctionHouseEntry) { aItem->DeleteFromDB(); sLog.outError("Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u", aItem->Id, aItem->auctioneer,auctioneerData->id,auctioneerInfo->faction_A); delete aItem; continue; } // check if sold item exists for guid // and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems) if ( !GetAItem( aItem->item_guidlow ) ) { aItem->DeleteFromDB(); sLog.outError("Auction %u has not a existing item : %u", aItem->Id, aItem->item_guidlow); delete aItem; continue; } GetAuctionsMap( auctioneerInfo->faction_A )->AddAuction(aItem); } while (result->NextRow()); delete result; sLog.outString(); sLog.outString( ">> Loaded %u auctions", AuctionCount ); }
void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player, std::wstring const& wsearchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32& count, uint32& totalcount) { int loc_idx = player->GetSession()->GetSessionDbLocaleIndex(); int locdbc_idx = player->GetSession()->GetSessionDbcLocale(); for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr) { AuctionEntry *Aentry = itr->second; Item *item = sAuctionMgr->GetAItem(Aentry->item_guidlow); if (!item) continue; ItemPrototype const *proto = item->GetProto(); if (itemClass != 0xffffffff && proto->Class != itemClass) continue; if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass) continue; if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType) continue; if (quality != 0xffffffff && proto->Quality != quality) continue; if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) continue; if (usable != 0x00 && player->CanUseItem(item) != EQUIP_ERR_OK) continue; // Allow search by suffix (ie: of the Monkey) or partial name (ie: Monkey) // No need to do any of this if no search term was entered if (!wsearchedname.empty()) { std::string name = proto->Name1; if (name.empty()) continue; // local name if (loc_idx >= 0) if (ItemLocale const *il = sObjectMgr->GetItemLocale(proto->ItemId)) sObjectMgr->GetLocaleString(il->Name, loc_idx, name); // DO NOT use GetItemEnchantMod(proto->RandomProperty) as it may return a result // that matches the search but it may not equal item->GetItemRandomPropertyId() // used in BuildAuctionInfo() which then causes wrong items to be listed int32 propRefID = item->GetItemRandomPropertyId(); if (propRefID) { // Append the suffix to the name (ie: of the Monkey) if one exists // These are found in ItemRandomProperties.dbc, not ItemRandomSuffix.dbc // even though the DBC names seem misleading const ItemRandomPropertiesEntry *itemRandProp = sItemRandomPropertiesStore.LookupEntry(propRefID); if (itemRandProp) { char* const* temp = itemRandProp->nameSuffix; //char* temp = itemRandProp->nameSuffix; // dbc local name if (temp) { if (locdbc_idx >= 0) { // Append the suffix (ie: of the Monkey) to the name using localization name += " "; name += temp[locdbc_idx]; } else { // Invalid localization? Append the suffix using default enUS name += " "; name += temp[LOCALE_enUS]; } } } } // Perform the search (with or without suffix) if (!Utf8FitTo(name, wsearchedname)) continue; } // Add the item if no search term or if entered search term was found if (count < 50 && totalcount >= listfrom) { ++count; Aentry->BuildAuctionInfo(data); } ++totalcount; } }
void AuctionHouseObject::Update() { time_t curTime = sWorld.GetGameTime(); // Handle expired auctions // If storage is empty, no need to update. next == NULL in this case. if (AuctionsMap.empty()) return; QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT id FROM auctionhouse WHERE time <= %u ORDER BY TIME ASC", (uint32)curTime + 60); if (!result) return; if (result->GetRowCount() == 0) return; vector<uint32> expiredAuctions; do { uint32 tmpdata = result->Fetch()->GetUInt32(); expiredAuctions.push_back(tmpdata); } while (result->NextRow()); while (!expiredAuctions.empty()) { vector<uint32>::iterator iter = expiredAuctions.begin(); // from auctionhousehandler.cpp, creates auction pointer & player pointer AuctionEntry* auction = GetAuction(*iter); // Erase the auction from the vector. expiredAuctions.erase(iter); if (!auction) continue; ///- Either cancel the auction if there was no bidder if (auction->bidder == 0) sAuctionMgr->SendAuctionExpiredMail(auction); ///- Or perform the transaction else { //we should send an "item sold" message if the seller is online //we send the item to the winner //we send the money to the seller sAuctionMgr->SendAuctionSuccessfulMail(auction); sAuctionMgr->SendAuctionWonMail(auction); } ///- In any case clear the auction CharacterDatabase.BeginTransaction(); auction->DeleteFromDB(); uint32 item_template = auction->item_template; sAuctionMgr->RemoveAItem(auction->item_guidlow); RemoveAuction(auction, item_template); CharacterDatabase.CommitTransaction(); } }