2009-02-13 19:53:59 -06:00
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
2009-06-04 21:41:07 +02:00
#include "ObjectMgr.h"
#include "Player.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
2009-02-13 19:53:59 -06:00
#include "Database/DatabaseEnv.h"
#include "Database/SQLStorage.h"
2009-06-04 21:41:07 +02:00
#include "Policies/SingletonImp.h"
2009-03-27 09:58:20 -06:00
#include "DBCStores.h"
2009-02-13 19:53:59 -06:00
#include "AccountMgr.h"
#include "AuctionHouseMgr.h"
#include "Item.h"
#include "Language.h"
#include "Log.h"
2009-06-04 21:41:07 +02:00
#include "ProgressBar.h"
2009-02-13 19:53:59 -06:00
INSTANTIATE_SINGLETON_1 ( AuctionHouseMgr );
AuctionHouseMgr :: AuctionHouseMgr ()
{
}
AuctionHouseMgr ::~ AuctionHouseMgr ()
{
2009-04-29 00:26:07 -05:00
for ( ItemMap :: const_iterator itr = mAitems . begin (); itr != mAitems . end (); ++ itr )
2009-02-13 19:53:59 -06:00
delete itr -> second ;
}
AuctionHouseObject * AuctionHouseMgr :: GetAuctionsMap ( uint32 factionTemplateId )
{
2009-02-27 12:25:52 -06:00
if ( sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION ))
return & mNeutralAuctions ;
2009-02-13 19:53:59 -06:00
// team have linked auction houses
FactionTemplateEntry const * u_entry = sFactionTemplateStore . LookupEntry ( factionTemplateId );
if ( ! u_entry )
return & mNeutralAuctions ;
else if ( u_entry -> ourMask & FACTION_MASK_ALLIANCE )
return & mAllianceAuctions ;
else if ( u_entry -> ourMask & FACTION_MASK_HORDE )
return & mHordeAuctions ;
else
return & mNeutralAuctions ;
}
uint32 AuctionHouseMgr :: GetAuctionDeposit ( AuctionHouseEntry const * entry , uint32 time , Item * pItem )
{
2009-06-03 19:43:11 -04:00
uint32 MSV = pItem -> GetProto () -> SellPrice ;
double deposit ;
double faction_pct ;
if ( MSV > 0 )
{
if ( sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION ))
faction_pct = ( 0.75 * ( double ) sWorld . getRate ( RATE_AUCTION_DEPOSIT ));
else
{
FactionTemplateEntry const * u_entry = sFactionTemplateStore . LookupEntry ( entry -> houseId );
if ( ! u_entry )
faction_pct = ( 0.75 * ( double ) sWorld . getRate ( RATE_AUCTION_DEPOSIT ));
else if ( u_entry -> ourMask & FACTION_MASK_ALLIANCE )
faction_pct = ( 0.15 * ( double ) sWorld . getRate ( RATE_AUCTION_DEPOSIT ));
else if ( u_entry -> ourMask & FACTION_MASK_HORDE )
faction_pct = ( 0.15 * ( double ) sWorld . getRate ( RATE_AUCTION_DEPOSIT ));
else
faction_pct = ( 0.75 * ( double ) sWorld . getRate ( RATE_AUCTION_DEPOSIT ));
}
deposit = (( double ) MSV * faction_pct * ( double ) pItem -> GetCount ()) * ( double )( time / MIN_AUCTION_TIME );
}
else
{
faction_pct = 0.0f ;
deposit = 0.0f ;
}
2009-06-05 20:51:45 -04:00
sLog . outDebug ( "SellPrice: \t\t %u" , MSV );
sLog . outDebug ( "Deposit Percent: \t %f" , faction_pct );
sLog . outDebug ( "Auction Time1: \t\t %u" , time );
sLog . outDebug ( "Auction Time2: \t\t %u" , MIN_AUCTION_TIME );
sLog . outDebug ( "Auction Time3: \t\t %u" , ( time / MIN_AUCTION_TIME ));
sLog . outDebug ( "Count: \t\t\t %u" , pItem -> GetCount ());
sLog . outDebug ( "Deposit: \t\t %f" , deposit );
2009-06-03 19:43:11 -04:00
if ( deposit > 0 )
return ( uint32 ) deposit ;
else
return 0 ;
2009-02-13 19:53:59 -06:00
}
//does not clear ram
void AuctionHouseMgr :: SendAuctionWonMail ( AuctionEntry * auction )
{
Item * pItem = GetAItem ( auction -> item_guidlow );
if ( ! pItem )
return ;
uint64 bidder_guid = MAKE_NEW_GUID ( auction -> bidder , 0 , HIGHGUID_PLAYER );
Player * bidder = objmgr . GetPlayer ( bidder_guid );
uint32 bidder_accId = 0 ;
// data for gm.log
if ( sWorld . getConfig ( CONFIG_GM_LOG_TRADE ) )
{
uint32 bidder_security = 0 ;
std :: string bidder_name ;
if ( bidder )
{
bidder_accId = bidder -> GetSession () -> GetAccountId ();
bidder_security = bidder -> GetSession () -> GetSecurity ();
bidder_name = bidder -> GetName ();
}
else
{
bidder_accId = objmgr . GetPlayerAccountIdByGUID ( bidder_guid );
bidder_security = accmgr . GetSecurity ( bidder_accId );
2009-02-28 17:42:29 -05:00
if ( bidder_security > SEC_PLAYER ) // not do redundant DB requests
2009-02-13 19:53:59 -06:00
{
if ( ! objmgr . GetPlayerNameByGUID ( bidder_guid , bidder_name ))
bidder_name = objmgr . GetTrinityStringForDBCLocale ( LANG_UNKNOWN );
}
}
if ( bidder_security > SEC_PLAYER )
{
std :: string owner_name ;
if ( ! objmgr . GetPlayerNameByGUID ( auction -> owner , owner_name ))
owner_name = objmgr . GetTrinityStringForDBCLocale ( LANG_UNKNOWN );
uint32 owner_accid = objmgr . GetPlayerAccountIdByGUID ( auction -> owner );
sLog . outCommand ( bidder_accId , "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)" ,
bidder_name . c_str (), bidder_accId , pItem -> GetProto () -> Name1 , pItem -> GetEntry (), pItem -> GetCount (), auction -> bid , owner_name . c_str (), owner_accid );
}
}
else if ( ! bidder )
bidder_accId = objmgr . GetPlayerAccountIdByGUID ( bidder_guid );
// receiver exist
if ( bidder || bidder_accId )
{
std :: ostringstream msgAuctionWonSubject ;
msgAuctionWonSubject << auction -> item_template << ":0:" << AUCTION_WON ;
std :: ostringstream msgAuctionWonBody ;
msgAuctionWonBody . width ( 16 );
msgAuctionWonBody << std :: right << std :: hex << auction -> owner ;
msgAuctionWonBody << std :: dec << ":" << auction -> bid << ":" << auction -> buyout ;
sLog . outDebug ( "AuctionWon body string : %s" , msgAuctionWonBody . str (). c_str () );
//prepare mail data... :
uint32 itemTextId = objmgr . CreateItemText ( msgAuctionWonBody . str () );
// set owner to bidder (to prevent delete item with sender char deleting)
// owner in `data` will set at mail receive and item extracting
CharacterDatabase . PExecute ( "UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'" , auction -> bidder , pItem -> GetGUIDLow ());
CharacterDatabase . CommitTransaction ();
MailItemsInfo mi ;
mi . AddItem ( auction -> item_guidlow , auction -> item_template , pItem );
if ( bidder )
bidder -> GetSession () -> SendAuctionBidderNotification ( auction -> GetHouseId (), auction -> Id , bidder_guid , 0 , 0 , auction -> item_template );
else
2009-02-28 17:42:29 -05:00
RemoveAItem ( pItem -> GetGUIDLow ()); // we have to remove the item, before we delete it !!
2009-02-13 19:53:59 -06:00
// will delete item or place to receiver mail list
WorldSession :: SendMailTo ( bidder , MAIL_AUCTION , MAIL_STATIONERY_AUCTION , auction -> GetHouseId (), auction -> bidder , msgAuctionWonSubject . str (), itemTextId , & mi , 0 , 0 , MAIL_CHECK_MASK_AUCTION );
}
// receiver not exist
else
{
CharacterDatabase . PExecute ( "DELETE FROM item_instance WHERE guid='%u'" , pItem -> GetGUIDLow ());
2009-02-28 17:42:29 -05:00
RemoveAItem ( pItem -> GetGUIDLow ()); // we have to remove the item, before we delete it !!
2009-02-13 19:53:59 -06:00
delete pItem ;
}
}
void AuctionHouseMgr :: SendAuctionSalePendingMail ( AuctionEntry * auction )
{
uint64 owner_guid = MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER );
Player * owner = objmgr . GetPlayer ( owner_guid );
// owner exist (online or offline)
if ( owner || objmgr . GetPlayerAccountIdByGUID ( owner_guid ))
{
std :: ostringstream msgAuctionSalePendingSubject ;
msgAuctionSalePendingSubject << auction -> item_template << ":0:" << AUCTION_SALE_PENDING ;
std :: ostringstream msgAuctionSalePendingBody ;
uint32 auctionCut = auction -> GetAuctionCut ();
time_t distrTime = time ( NULL ) + HOUR ;
msgAuctionSalePendingBody . width ( 16 );
msgAuctionSalePendingBody << std :: right << std :: hex << auction -> bidder ;
msgAuctionSalePendingBody << std :: dec << ":" << auction -> bid << ":" << auction -> buyout ;
msgAuctionSalePendingBody << ":" << auction -> deposit << ":" << auctionCut << ":0:" ;
msgAuctionSalePendingBody << secsToTimeBitFields ( distrTime );
sLog . outDebug ( "AuctionSalePending body string : %s" , msgAuctionSalePendingBody . str (). c_str ());
uint32 itemTextId = objmgr . CreateItemText ( msgAuctionSalePendingBody . str () );
WorldSession :: SendMailTo ( owner , MAIL_AUCTION , MAIL_STATIONERY_AUCTION , auction -> GetHouseId (), auction -> owner , msgAuctionSalePendingSubject . str (), itemTextId , NULL , 0 , 0 , MAIL_CHECK_MASK_AUCTION );
}
}
//call this method to send mail to auction owner, when auction is successful, it does not clear ram
void AuctionHouseMgr :: SendAuctionSuccessfulMail ( AuctionEntry * auction )
{
uint64 owner_guid = MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER );
Player * owner = objmgr . GetPlayer ( owner_guid );
uint32 owner_accId = 0 ;
if ( ! owner )
owner_accId = objmgr . GetPlayerAccountIdByGUID ( owner_guid );
// owner exist
if ( owner || owner_accId )
{
std :: ostringstream msgAuctionSuccessfulSubject ;
msgAuctionSuccessfulSubject << auction -> item_template << ":0:" << AUCTION_SUCCESSFUL ;
std :: ostringstream auctionSuccessfulBody ;
uint32 auctionCut = auction -> GetAuctionCut ();
auctionSuccessfulBody . width ( 16 );
auctionSuccessfulBody << std :: right << std :: hex << auction -> bidder ;
auctionSuccessfulBody << std :: dec << ":" << auction -> bid << ":" << auction -> buyout ;
auctionSuccessfulBody << ":" << auction -> deposit << ":" << auctionCut ;
sLog . outDebug ( "AuctionSuccessful body string : %s" , auctionSuccessfulBody . str (). c_str ());
uint32 itemTextId = objmgr . CreateItemText ( auctionSuccessfulBody . str () );
uint32 profit = auction -> bid + auction -> deposit - auctionCut ;
if ( owner )
{
2009-03-05 09:22:43 -06:00
//FIXME: what do if owner offline
owner -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD , auction -> bid );
2009-02-13 19:53:59 -06:00
//send auction owner notification, bidder must be current!
owner -> GetSession () -> SendAuctionOwnerNotification ( auction );
}
WorldSession :: SendMailTo ( owner , MAIL_AUCTION , MAIL_STATIONERY_AUCTION , auction -> GetHouseId (), auction -> owner , msgAuctionSuccessfulSubject . str (), itemTextId , NULL , profit , 0 , MAIL_CHECK_MASK_AUCTION , HOUR );
}
}
//does not clear ram
void AuctionHouseMgr :: SendAuctionExpiredMail ( AuctionEntry * auction )
2009-02-28 17:42:29 -05:00
{ //return an item in auction to its owner by mail
2009-02-13 19:53:59 -06:00
Item * pItem = GetAItem ( auction -> item_guidlow );
if ( ! pItem )
{
sLog . outError ( "Auction item (GUID: %u) not found, and lost." , auction -> item_guidlow );
return ;
}
uint64 owner_guid = MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER );
Player * owner = objmgr . GetPlayer ( owner_guid );
uint32 owner_accId = 0 ;
if ( ! owner )
owner_accId = objmgr . GetPlayerAccountIdByGUID ( owner_guid );
// owner exist
if ( owner || owner_accId )
{
std :: ostringstream subject ;
subject << auction -> item_template << ":0:" << AUCTION_EXPIRED ;
if ( owner )
owner -> GetSession () -> SendAuctionOwnerNotification ( auction );
else
RemoveAItem ( pItem -> GetGUIDLow ()); // we have to remove the item, before we delete it !!
MailItemsInfo mi ;
mi . AddItem ( auction -> item_guidlow , auction -> item_template , pItem );
// will delete item or place to receiver mail list
WorldSession :: SendMailTo ( owner , MAIL_AUCTION , MAIL_STATIONERY_AUCTION , auction -> GetHouseId (), GUID_LOPART ( owner_guid ), subject . str (), 0 , & mi , 0 , 0 , MAIL_CHECK_MASK_NONE );
}
// owner not found
else
{
CharacterDatabase . PExecute ( "DELETE FROM item_instance WHERE guid='%u'" , pItem -> GetGUIDLow ());
2009-02-28 17:42:29 -05:00
RemoveAItem ( pItem -> GetGUIDLow ()); // we have to remove the item, before we delete it !!
2009-02-13 19:53:59 -06:00
delete pItem ;
}
}
void AuctionHouseMgr :: LoadAuctionItems ()
{
// data needs to be at first place for Item::LoadFromDB
QueryResult * result = CharacterDatabase . Query ( "SELECT data,itemguid,item_template FROM auctionhouse JOIN item_instance ON itemguid = guid" );
if ( ! result )
{
barGoLink bar ( 1 );
bar . step ();
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-13 19:53:59 -06:00
sLog . outString ( ">> Loaded 0 auction items" );
return ;
}
barGoLink bar ( result -> GetRowCount () );
uint32 count = 0 ;
Field * fields ;
do
{
bar . step ();
fields = result -> Fetch ();
uint32 item_guid = fields [ 1 ]. GetUInt32 ();
uint32 item_template = fields [ 2 ]. GetUInt32 ();
ItemPrototype const * proto = objmgr . GetItemPrototype ( item_template );
if ( ! proto )
{
sLog . outError ( "ObjectMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped." , item_guid , item_template );
continue ;
}
Item * item = NewItemOrBag ( proto );
if ( ! item -> LoadFromDB ( item_guid , 0 , result ))
{
delete item ;
continue ;
}
AddAItem ( item );
++ count ;
}
while ( result -> NextRow () );
delete result ;
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-13 19:53:59 -06:00
sLog . outString ( ">> Loaded %u auction items" , count );
}
void AuctionHouseMgr :: LoadAuctions ()
{
QueryResult * result = CharacterDatabase . Query ( "SELECT COUNT(*) FROM auctionhouse" );
if ( ! result )
{
barGoLink bar ( 1 );
bar . step ();
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-13 19:53:59 -06:00
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 ();
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-13 19:53:59 -06:00
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 ();
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-13 19:53:59 -06:00
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 = objmgr . 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 = objmgr . 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 ObjectMgr::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 ;
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-13 19:53:59 -06:00
sLog . outString ( ">> Loaded %u auctions" , AuctionCount );
}
void AuctionHouseMgr :: AddAItem ( Item * it )
{
ASSERT ( it );
ASSERT ( mAitems . find ( it -> GetGUIDLow ()) == mAitems . end ());
mAitems [ it -> GetGUIDLow ()] = it ;
}
bool AuctionHouseMgr :: RemoveAItem ( uint32 id )
{
ItemMap :: iterator i = mAitems . find ( id );
if ( i == mAitems . end ())
{
return false ;
}
mAitems . erase ( i );
return true ;
}
void AuctionHouseMgr :: Update ()
{
mHordeAuctions . Update ();
mAllianceAuctions . Update ();
mNeutralAuctions . Update ();
}
AuctionHouseEntry const * AuctionHouseMgr :: GetAuctionHouseEntry ( uint32 factionTemplateId )
{
2009-02-28 17:42:29 -05:00
uint32 houseid = 7 ; // goblin auction house
2009-02-13 19:53:59 -06:00
if ( ! sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION ))
{
//FIXME: found way for proper auctionhouse selection by another way
2009-02-28 17:42:29 -05:00
// AuctionHouse.dbc have faction field with _player_ factions associated with auction house races.
2009-02-13 19:53:59 -06:00
// but no easy way convert creature faction to player race faction for specific city
switch ( factionTemplateId )
{
2009-02-28 17:42:29 -05:00
case 12 : houseid = 1 ; break ; // human
case 29 : houseid = 6 ; break ; // orc, and generic for horde
case 55 : houseid = 2 ; break ; // dwarf, and generic for alliance
case 68 : houseid = 4 ; break ; // undead
case 80 : houseid = 3 ; break ; // n-elf
case 104 : houseid = 5 ; break ; // trolls
case 120 : houseid = 7 ; break ; // booty bay, neutral
case 474 : houseid = 7 ; break ; // gadgetzan, neutral
case 855 : houseid = 7 ; break ; // everlook, neutral
case 1604 : houseid = 6 ; break ; // b-elfs,
default : // for unknown case
2009-02-13 19:53:59 -06:00
{
FactionTemplateEntry const * u_entry = sFactionTemplateStore . LookupEntry ( factionTemplateId );
if ( ! u_entry )
2009-02-28 17:42:29 -05:00
houseid = 7 ; // goblin auction house
2009-02-13 19:53:59 -06:00
else if ( u_entry -> ourMask & FACTION_MASK_ALLIANCE )
2009-02-28 17:42:29 -05:00
houseid = 1 ; // human auction house
2009-02-13 19:53:59 -06:00
else if ( u_entry -> ourMask & FACTION_MASK_HORDE )
2009-02-28 17:42:29 -05:00
houseid = 6 ; // orc auction house
2009-02-13 19:53:59 -06:00
else
2009-02-28 17:42:29 -05:00
houseid = 7 ; // goblin auction house
2009-02-13 19:53:59 -06:00
break ;
}
}
}
return sAuctionHouseStore . LookupEntry ( houseid );
}
void AuctionHouseObject :: Update ()
{
time_t curTime = sWorld . GetGameTime ();
///- Handle expired auctions
AuctionEntryMap :: iterator next ;
for ( AuctionEntryMap :: iterator itr = AuctionsMap . begin (); itr != AuctionsMap . end (); itr = next )
{
next = itr ;
++ next ;
if ( curTime > ( itr -> second -> expire_time ))
{
///- Either cancel the auction if there was no bidder
if ( itr -> second -> bidder == 0 )
{
auctionmgr . SendAuctionExpiredMail ( itr -> second );
}
///- 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
auctionmgr . SendAuctionSuccessfulMail ( itr -> second );
auctionmgr . SendAuctionWonMail ( itr -> second );
}
///- In any case clear the auction
itr -> second -> DeleteFromDB ();
auctionmgr . RemoveAItem ( itr -> second -> item_guidlow );
delete itr -> second ;
RemoveAuction ( itr -> first );
}
}
}
void AuctionHouseObject :: BuildListBidderItems ( WorldPacket & data , Player * player , uint32 & count , uint32 & totalcount )
{
for ( AuctionEntryMap :: const_iterator itr = AuctionsMap . begin (); itr != AuctionsMap . end (); ++ itr )
{
AuctionEntry * Aentry = itr -> second ;
if ( Aentry && Aentry -> bidder == player -> GetGUIDLow () )
{
if ( itr -> second -> BuildAuctionInfo ( data ))
++ count ;
++ totalcount ;
}
}
}
void AuctionHouseObject :: BuildListOwnerItems ( WorldPacket & data , Player * player , uint32 & count , uint32 & totalcount )
{
for ( AuctionEntryMap :: const_iterator itr = AuctionsMap . begin (); itr != AuctionsMap . end (); ++ itr )
{
AuctionEntry * Aentry = itr -> second ;
if ( Aentry && Aentry -> owner == player -> GetGUIDLow () )
{
if ( Aentry -> BuildAuctionInfo ( data ))
++ count ;
++ totalcount ;
}
}
}
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 = auctionmgr . GetAItem ( Aentry -> item_guidlow );
if ( ! item )
continue ;
ItemPrototype const * proto = item -> GetProto ();
2009-02-24 11:14:28 -06:00
if ( itemClass != 0xffffffff && proto -> Class != itemClass )
2009-02-13 19:53:59 -06:00
continue ;
2009-02-24 11:14:28 -06:00
if ( itemSubClass != 0xffffffff && proto -> SubClass != itemSubClass )
2009-02-13 19:53:59 -06:00
continue ;
2009-02-24 11:14:28 -06:00
if ( inventoryType != 0xffffffff && proto -> InventoryType != inventoryType )
2009-02-13 19:53:59 -06:00
continue ;
2009-02-24 11:14:28 -06:00
if ( quality != 0xffffffff && proto -> Quality != quality )
2009-02-13 19:53:59 -06:00
continue ;
2009-02-24 11:14:28 -06:00
if ( levelmin != 0x00 && ( proto -> RequiredLevel < levelmin || ( levelmax != 0x00 && proto -> RequiredLevel > levelmax )))
2009-02-13 19:53:59 -06:00
continue ;
2009-02-24 11:14:28 -06:00
if ( usable != 0x00 && player -> CanUseItem ( item ) != EQUIP_ERR_OK )
2009-02-13 19:53:59 -06:00
continue ;
std :: string name = proto -> Name1 ;
if ( name . empty ())
continue ;
// local name
if ( loc_idx >= 0 )
{
ItemLocale const * il = objmgr . GetItemLocale ( proto -> ItemId );
if ( il )
{
if ( il -> Name . size () > size_t ( loc_idx ) && ! il -> Name [ loc_idx ]. empty ())
name = il -> Name [ loc_idx ];
}
}
2009-02-24 11:14:28 -06:00
if ( ! wsearchedname . empty () && ! Utf8FitTo ( name , wsearchedname ) )
2009-02-13 19:53:59 -06:00
continue ;
2009-02-24 11:14:28 -06:00
if ( count < 50 && totalcount >= listfrom )
2009-02-13 19:53:59 -06:00
{
++ count ;
Aentry -> BuildAuctionInfo ( data );
}
++ totalcount ;
}
}
//this function inserts to WorldPacket auction's data
bool AuctionEntry :: BuildAuctionInfo ( WorldPacket & data ) const
{
Item * pItem = auctionmgr . GetAItem ( item_guidlow );
if ( ! pItem )
{
sLog . outError ( "auction to item, that doesn't exist !!!!" );
return false ;
}
2009-03-02 16:53:50 -06:00
data << uint32 ( Id );
data << uint32 ( pItem -> GetEntry ());
2009-02-13 19:53:59 -06:00
2009-04-29 00:26:07 -05:00
for ( uint8 i = 0 ; i < MAX_INSPECTED_ENCHANTMENT_SLOT ; ++ i )
2009-02-13 19:53:59 -06:00
{
2009-03-02 16:53:50 -06:00
data << uint32 ( pItem -> GetEnchantmentId ( EnchantmentSlot ( i )));
data << uint32 ( pItem -> GetEnchantmentDuration ( EnchantmentSlot ( i )));
data << uint32 ( pItem -> GetEnchantmentCharges ( EnchantmentSlot ( i )));
2009-02-13 19:53:59 -06:00
}
2009-03-02 16:53:50 -06:00
data << uint32 ( pItem -> GetItemRandomPropertyId ()); //random item property id
data << uint32 ( pItem -> GetItemSuffixFactor ()); //SuffixFactor
data << uint32 ( pItem -> GetCount ()); //item->count
data << uint32 ( pItem -> GetSpellCharges ()); //item->charge FFFFFFF
data << uint32 ( 0 ); //Unknown
2009-03-02 17:03:36 -06:00
data << uint64 ( owner ); //Auction->owner
2009-03-02 16:53:50 -06:00
data << uint32 ( startbid ); //Auction->startbid (not sure if useful)
data << uint32 ( bid ? GetAuctionOutBid () : 0 );
2009-02-13 19:53:59 -06:00
//minimal outbid
2009-03-02 16:53:50 -06:00
data << uint32 ( buyout ); //auction->buyout
data << uint32 (( expire_time - time ( NULL )) * IN_MILISECONDS ); //time left
data << uint64 ( bidder ) ; //auction->bidder current
data << uint32 ( bid ); //current bid
2009-02-13 19:53:59 -06:00
return true ;
}
uint32 AuctionEntry :: GetAuctionCut () const
{
2009-05-21 10:52:35 -05:00
return uint32 ( auctionHouseEntry -> cutPercent * bid * sWorld . getRate ( RATE_AUCTION_CUT ) / 100.0f );
2009-02-13 19:53:59 -06:00
}
/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
uint32 AuctionEntry :: GetAuctionOutBid () const
{
uint32 outbid = ( bid / 100 ) * 5 ;
if ( ! outbid )
outbid = 1 ;
return outbid ;
}
void AuctionEntry :: DeleteFromDB () const
{
//No SQL injection (Id is integer)
CharacterDatabase . PExecute ( "DELETE FROM auctionhouse WHERE id = '%u'" , Id );
}
void AuctionEntry :: SaveToDB () const
{
//No SQL injection (no strings)
CharacterDatabase . PExecute ( "INSERT INTO auctionhouse (id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit) "
2009-05-31 16:15:12 -05:00
"VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" UI64FMTD "', '%u', '%u', '%u', '%u')" ,
2009-02-13 19:53:59 -06:00
Id , auctioneer , item_guidlow , item_template , owner , buyout , ( uint64 ) expire_time , bidder , bid , startbid , deposit );
}