// 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(); }
void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) { AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config.GetHouseType()); PrepareListOfEntry(config); time_t now = time(nullptr); uint32 buyCycles; if (config.CheckedEntry.size() > sAuctionBotConfig->GetItemPerCycleBoost()) { buyCycles = sAuctionBotConfig->GetItemPerCycleBoost(); TC_LOG_DEBUG("ahbot", "AHBot: Boost value used for Buyer! (if this happens often adjust both ItemsPerCycle in worldserver.conf)"); } else buyCycles = sAuctionBotConfig->GetItemPerCycleNormal(); for (CheckEntryMap::iterator itr = config.CheckedEntry.begin(); itr != config.CheckedEntry.end();) { AuctionEntry* auction = auctionHouse->GetAuction(itr->second.AuctionId); if (!auction) // is auction not active now { TC_LOG_DEBUG("ahbot", "AHBot: Entry %u doesn't exists, perhaps bought already?", itr->second.AuctionId); config.CheckedEntry.erase(itr++); continue; } if (itr->second.LastChecked != 0 && (now - itr->second.LastChecked) <= _checkInterval) { TC_LOG_DEBUG("ahbot", "AHBot: In time interval wait for entry %u!", auction->Id); ++itr; continue; } if (buyCycles == 0) break; uint32 maxChance = 5000; Item* item = sAuctionMgr->GetAItem(auction->itemGUIDLow); if (!item) // auction item not accessible, possible auction in payment pending mode { config.CheckedEntry.erase(itr++); continue; } ItemTemplate const* prototype = item->GetTemplate(); uint32 basePrice = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_BUYER) ? prototype->BuyPrice : prototype->SellPrice; basePrice *= item->GetCount(); uint32 maxBuyablePrice = (basePrice * config.BuyerPriceRatio) / 100; BuyerItemInfoMap::iterator sameItemItr = config.SameItemInfo.find(item->GetEntry()); uint32 buyoutPrice = auction->buyout / item->GetCount(); uint32 bidPrice; uint32 bidPriceByItem; uint32 minBidPrice; uint32 minBuyPrice; if (auction->bid >= auction->startbid) { bidPrice = auction->GetAuctionOutBid(); bidPriceByItem = auction->bid / item->GetCount(); } else { bidPrice = auction->startbid; bidPriceByItem = auction->startbid / item->GetCount(); } double inGameBuyPrice; double inGameBidPrice; if (sameItemItr == config.SameItemInfo.end()) { inGameBuyPrice = 0; inGameBidPrice = 0; minBidPrice = 0; minBuyPrice = 0; } else { if (sameItemItr->second.ItemCount == 1) maxBuyablePrice = maxBuyablePrice * 5; // if only one item exist can be bought if the price is high too. inGameBuyPrice = sameItemItr->second.BuyPrice / sameItemItr->second.ItemCount; inGameBidPrice = sameItemItr->second.BidPrice / sameItemItr->second.ItemCount; minBidPrice = sameItemItr->second.MinBidPrice; minBuyPrice = sameItemItr->second.MinBuyPrice; } uint32 maxBidablePrice = maxBuyablePrice - (maxBuyablePrice / 30); // Max Bidable price defined to 70% of max buyable price TC_LOG_DEBUG("ahbot", "AHBot: Auction added with data:"); TC_LOG_DEBUG("ahbot", "AHBot: MaxPrice of Entry %u is %.1fg.", itr->second.AuctionId, double(maxBuyablePrice) / 10000.0); TC_LOG_DEBUG("ahbot", "AHBot: GamePrice buy=%.1fg, bid=%.1fg.", inGameBuyPrice / 10000, inGameBidPrice / 10000); TC_LOG_DEBUG("ahbot", "AHBot: Minimal price see in AH Buy=%ug, Bid=%ug.", minBuyPrice / 10000, minBidPrice / 10000); TC_LOG_DEBUG("ahbot", "AHBot: Actual Entry price, Buy=%ug, Bid=%ug.", buyoutPrice / 10000, bidPrice / 10000); if (!auction->owner) // Original auction owner maxChance = maxChance / 5; // if Owner is AHBot this mean player placed bid on this auction. We divide by 5 chance for AhBuyer to place bid on it. (This make more challenge than ignore entry) if (auction->buyout != 0) // Is the item directly buyable? { if (IsBuyableEntry(buyoutPrice, inGameBuyPrice, maxBuyablePrice, minBuyPrice, maxChance, config.FactionChance)) { if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance / 2, config.FactionChance)) { if (urand(0, 5) == 0) PlaceBidToEntry(auction, bidPrice); else BuyEntry(auction); } else BuyEntry(auction); } else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance / 2, config.FactionChance)) PlaceBidToEntry(auction, bidPrice); } else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance, config.FactionChance)) PlaceBidToEntry(auction, bidPrice); itr->second.LastChecked = now; --buyCycles; ++itr; } }