Improved Auction house deposit handling.

Including the weird quirks.

Changes:
* Deposit caculated according to same rule as client. (detailed below). Should always match client deposit now
* Deposit for multiple auctions now only collected once. Deferred calculation of deposit until all auctions listed.

Deposit calculation is as follows:

Base deposit calculation = MSV x 15/75% (depending on AH). However this is not rounded. Case to int is used (so always round down)
The remainder is held in a float.
The base is then multiplied by number of items, and the time multiplier (x2 for 24 hour, x4 for 48 hour)
The nearest (no of items or lower) no of items when multiplied by the remainder that creates a whole number is then multiplied by the time multiplier (x1/x2/x4) and then added to deposit.

Example:

Item sell price 1s25. Deposit 18.75c (15% of 1s25). So base deposit = 18, remainder 0.75. Time 24h (x2) Item count 1 = 36c. Remainder = 0.75 (n) Min = 1s. Deposit 1s
Item sell price 1s25. Deposit 18.75c (15% of 1s25). So base deposit = 18, remainder 0.75. Time 24h (x2) Item count 2 = 72c. Remainder = 1.50 (n)  Min = 1s. Deposit 1s
Item sell price 1s25. Deposit 18.75c (15% of 1s25). So base deposit = 18, remainder 0.75. Time 24h (x2) Item count 3 = 108c. Remainder = 2.25 (n) Min = 1s. Deposit 1s08c
Item sell price 1s25. Deposit 18.75c (15% of 1s25). So base deposit = 18, remainder 0.75. Time 24h (x2) Item count 4 = 144c. Remainder = 3.00 (n) Min = 1s. Deposit 1s50c (144c + (3c * 2))

Horrible kludge, to re-create a very weird deposit method.

Closes #15674 (PR)
Closes #15643 (Issue)

(cherry picked from commit 0ac442f19f)

# Conflicts:
#	src/server/game/AuctionHouse/AuctionHouseMgr.h
This commit is contained in:
pete318
2015-10-02 03:20:42 +01:00
committed by DDuarte
parent 9660848385
commit 28f51306d4
6 changed files with 147 additions and 4 deletions

View File

@@ -77,12 +77,23 @@ uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32
float multiplier = CalculatePct(float(entry->DepositRate), 3);
uint32 timeHr = (((time / 60) / 60) / 12);
uint32 deposit = uint32(((multiplier * MSV * count / 3) * timeHr * 3) * sWorld->getRate(RATE_AUCTION_DEPOSIT));
uint32 deposit = uint32(MSV * multiplier * sWorld->getRate(RATE_AUCTION_DEPOSIT));
float remainderbase = float(MSV * multiplier * sWorld->getRate(RATE_AUCTION_DEPOSIT)) - deposit;
deposit *= timeHr * count;
int i = count;
while (i > 0 && (remainderbase * i) != uint32(remainderbase * i))
i--;
if (i)
deposit += remainderbase * i * timeHr;
TC_LOG_DEBUG("auctionHouse", "MSV: %u", MSV);
TC_LOG_DEBUG("auctionHouse", "Items: %u", count);
TC_LOG_DEBUG("auctionHouse", "Multiplier: %f", multiplier);
TC_LOG_DEBUG("auctionHouse", "Deposit: %u", deposit);
TC_LOG_DEBUG("auctionHouse", "Deposit rm: %f", remainderbase * count);
if (deposit < AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT))
return AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT);
@@ -385,6 +396,116 @@ bool AuctionHouseMgr::RemoveAItem(ObjectGuid::LowType id, bool deleteItem)
return true;
}
void AuctionHouseMgr::PendingAuctionAdd(Player* player, AuctionEntry* aEntry)
{
PlayerAuctions* thisAH;
auto itr = pendingAuctionMap.find(player->GetGUID());
if (itr != pendingAuctionMap.end())
thisAH = itr->second.first;
else
{
thisAH = new PlayerAuctions;
pendingAuctionMap[player->GetGUID()] = AuctionPair(thisAH, 0);
}
thisAH->push_back(aEntry);
}
uint32 AuctionHouseMgr::PendingAuctionCount(const Player* player) const
{
auto const itr = pendingAuctionMap.find(player->GetGUID());
if (itr != pendingAuctionMap.end())
return itr->second.first->size();
return 0;
}
void AuctionHouseMgr::PendingAuctionProcess(Player* player)
{
auto iterMap = pendingAuctionMap.find(player->GetGUID());
if (iterMap == pendingAuctionMap.end())
return;
PlayerAuctions* thisAH = iterMap->second.first;
SQLTransaction trans = CharacterDatabase.BeginTransaction();
uint32 totalItems = 0;
for (auto itrAH = thisAH->begin(); itrAH != thisAH->end(); ++itrAH)
{
AuctionEntry* AH = (*itrAH);
totalItems += AH->itemCount;
}
uint32 totaldeposit = 0;
auto itr = (*thisAH->begin());
if (Item* item = GetAItem(itr->itemGUIDLow))
totaldeposit = GetAuctionDeposit(itr->auctionHouseEntry, itr->etime, item, totalItems);
uint32 depositremain = totaldeposit;
for (auto itr = thisAH->begin(); itr != thisAH->end(); ++itr)
{
AuctionEntry* AH = (*itr);
if (next(itr) == thisAH->end())
AH->deposit = depositremain;
else
{
AH->deposit = totaldeposit / thisAH->size();
depositremain -= AH->deposit;
}
AH->DeleteFromDB(trans);
AH->SaveToDB(trans);
}
CharacterDatabase.CommitTransaction(trans);
pendingAuctionMap.erase(player->GetGUID());
delete thisAH;
player->ModifyMoney(-int32(totaldeposit));
}
void AuctionHouseMgr::UpdatePendingAuctions()
{
for (auto itr = pendingAuctionMap.begin(); itr != pendingAuctionMap.end();)
{
ObjectGuid playerGUID = itr->first;
if (Player* player = ObjectAccessor::FindConnectedPlayer(playerGUID))
{
// Check if there were auctions since last update process if not
if (PendingAuctionCount(player) == itr->second.second)
{
++itr;
PendingAuctionProcess(player);
}
else
{
++itr;
pendingAuctionMap[playerGUID].second = PendingAuctionCount(player);
}
}
else
{
// Expire any auctions that we couldn't get a deposit for
TC_LOG_WARN("auctionHouse", "Player %s was offline, unable to retrieve deposit!", playerGUID.ToString().c_str());
PlayerAuctions* thisAH = itr->second.first;
++itr;
SQLTransaction trans = CharacterDatabase.BeginTransaction();
for (auto AHitr = thisAH->begin(); AHitr != thisAH->end();)
{
AuctionEntry* AH = (*AHitr);
++AHitr;
AH->expire_time = time(NULL);
AH->DeleteFromDB(trans);
AH->SaveToDB(trans);
}
CharacterDatabase.CommitTransaction(trans);
pendingAuctionMap.erase(playerGUID);
delete thisAH;
}
}
}
void AuctionHouseMgr::Update()
{
mHordeAuctions.Update();

View File

@@ -24,6 +24,7 @@
#include "DBCStructure.h"
#include "ObjectGuid.h"
#include "AuctionHousePackets.h"
#include <set>
class Item;
class Player;
@@ -77,6 +78,7 @@ struct AuctionEntry
time_t expire_time;
ObjectGuid::LowType bidder;
uint32 deposit; //deposit can be calculated only when creating auction
uint32 etime;
AuctionHouseEntry const* auctionHouseEntry; // in AuctionHouse.dbc
uint32 factionTemplateId;
@@ -143,6 +145,8 @@ class AuctionHouseMgr
static AuctionHouseMgr* instance();
typedef std::unordered_map<ObjectGuid::LowType, Item*> ItemMap;
typedef std::vector<AuctionEntry*> PlayerAuctions;
typedef std::pair<PlayerAuctions*, uint32> AuctionPair;
AuctionHouseObject* GetAuctionsMap(uint32 factionTemplateId);
AuctionHouseObject* GetBidsMap(uint32 factionTemplateId);
@@ -175,7 +179,10 @@ class AuctionHouseMgr
void AddAItem(Item* it);
bool RemoveAItem(ObjectGuid::LowType id, bool deleteItem = false);
void PendingAuctionAdd(Player* player, AuctionEntry* aEntry);
uint32 PendingAuctionCount(const Player* player) const;
void PendingAuctionProcess(Player* player);
void UpdatePendingAuctions();
void Update();
private:
@@ -184,6 +191,8 @@ class AuctionHouseMgr
AuctionHouseObject mAllianceAuctions;
AuctionHouseObject mNeutralAuctions;
std::map<ObjectGuid, AuctionPair> pendingAuctionMap;
ItemMap mAitems;
};

View File

@@ -1362,6 +1362,7 @@ void Player::Update(uint32 p_time)
//because we don't want player's ghost teleported from graveyard
if (IsHasDelayedTeleport() && IsAlive())
TeleportTo(m_teleport_dest, m_teleport_options);
}
void Player::setDeathState(DeathState s)

View File

@@ -258,18 +258,21 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell
AH->buyout = packet.BuyoutPrice;
AH->expire_time = time(NULL) + auctionTime;
AH->deposit = deposit;
AH->etime = etime;
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);
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);
@@ -306,12 +309,14 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell
AH->buyout = packet.BuyoutPrice;
AH->expire_time = time(NULL) + auctionTime;
AH->deposit = deposit;
AH->etime = etime;
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);
sAuctionMgr->PendingAuctionAdd(_player, AH);
for (auto const& packetItem : packet.Items)
{
@@ -351,8 +356,6 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1);
}
_player->ModifyMoney(-int32(deposit));
}
// this function is called when client bids or buys out auction

View File

@@ -1946,6 +1946,7 @@ void World::SetInitialWorldSettings()
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS_PENDING].SetInterval(250);
m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
//Update "uptime" table based on configuration entry in minutes.
m_timers[WUPDATE_CORPSES].SetInterval(20 * MINUTE * IN_MILLISECONDS);
@@ -2195,6 +2196,13 @@ void World::Update(uint32 diff)
sAuctionMgr->Update();
}
if (m_timers[WUPDATE_AUCTIONS_PENDING].Passed())
{
m_timers[WUPDATE_AUCTIONS_PENDING].Reset();
sAuctionMgr->UpdatePendingAuctions();
}
/// <li> Handle AHBot operations
if (m_timers[WUPDATE_AHBOT].Passed())
{

View File

@@ -79,6 +79,7 @@ enum ShutdownExitCode
enum WorldTimers
{
WUPDATE_AUCTIONS,
WUPDATE_AUCTIONS_PENDING,
WUPDATE_WEATHERS,
WUPDATE_UPTIME,
WUPDATE_CORPSES,