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
*/
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
#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-10-17 15:51:44 -07:00
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-10-12 18:54:43 -07:00
#include <vector>
2009-02-13 19:53:59 -06:00
2009-09-22 20:40:34 -04:00
INSTANTIATE_SINGLETON_1 ( AuctionHouseMgr );
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
using namespace std ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
AuctionHouseMgr :: AuctionHouseMgr ()
{
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
AuctionHouseMgr ::~ AuctionHouseMgr ()
{
2009-09-22 20:40:34 -04:00
for ( ItemMap :: const_iterator itr = mAitems . begin (); itr != mAitems . end (); ++ itr )
2009-02-13 19:53:59 -06:00
delete itr -> second ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
AuctionHouseObject * AuctionHouseMgr :: GetAuctionsMap ( uint32 factionTemplateId )
2009-02-13 19:53:59 -06:00
{
2009-09-22 20:40:34 -04:00
if ( sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION ))
2009-02-27 12:25:52 -06:00
return & mNeutralAuctions ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
// team have linked auction houses
FactionTemplateEntry const * u_entry = sFactionTemplateStore . LookupEntry ( factionTemplateId );
2009-09-22 20:40:34 -04:00
if ( ! u_entry )
2009-02-13 19:53:59 -06:00
return & mNeutralAuctions ;
2009-09-22 20:40:34 -04:00
else if ( u_entry -> ourMask & FACTION_MASK_ALLIANCE )
2009-02-13 19:53:59 -06:00
return & mAllianceAuctions ;
2009-09-22 20:40:34 -04:00
else if ( u_entry -> ourMask & FACTION_MASK_HORDE )
2009-02-13 19:53:59 -06:00
return & mHordeAuctions ;
else
return & mNeutralAuctions ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
uint32 AuctionHouseMgr :: GetAuctionDeposit ( AuctionHouseEntry const * entry , uint32 time , Item * pItem )
{
2009-06-03 19:43:11 -04:00
uint32 MSV = pItem -> GetProto () -> SellPrice ;
2009-09-22 20:40:34 -04:00
int32 deposit ;
uint32 timeHr = ((( time / 60 ) / 60 ) / 12 );
2009-10-17 15:51:44 -07:00
2009-06-03 19:43:11 -04:00
if ( MSV > 0 )
2009-09-22 20:40:34 -04:00
deposit = ( int32 ) floor (( double ) MSV * ((( double )( entry -> depositPercent * 3 ) / 100.0f * ( double ) sWorld . getRate ( RATE_AUCTION_DEPOSIT ) * ( double ) pItem -> GetCount ()))) * timeHr ;
2009-06-03 19:43:11 -04:00
else
2009-09-22 20:40:34 -04:00
deposit = 0 ;
2009-10-17 15:51:44 -07:00
2009-06-05 20:51:45 -04:00
sLog . outDebug ( "SellPrice: \t\t %u" , MSV );
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "Deposit Percent: \t %f" , (( double ) entry -> depositPercent / 100.0f ));
2009-06-05 20:51:45 -04:00
sLog . outDebug ( "Auction Time1: \t\t %u" , time );
sLog . outDebug ( "Auction Time2: \t\t %u" , MIN_AUCTION_TIME );
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "Auction Time3: \t\t %u" , timeHr );
2009-06-05 20:51:45 -04:00
sLog . outDebug ( "Count: \t\t\t %u" , pItem -> GetCount ());
2009-06-03 19:43:11 -04:00
if ( deposit > 0 )
2009-09-22 20:40:34 -04:00
{
sLog . outDebug ( "Deposit: \t\t %u" , deposit );
return deposit ;
}
2009-06-03 19:43:11 -04:00
else
2009-09-22 20:40:34 -04:00
{
sLog . outDebug ( "Deposit: \t\t 0" );
2009-06-03 19:43:11 -04:00
return 0 ;
2009-09-22 20:40:34 -04:00
}
2009-02-13 19:53:59 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
//does not clear ram
2009-09-22 20:40:34 -04:00
void AuctionHouseMgr :: SendAuctionWonMail ( AuctionEntry * auction )
2009-02-13 19:53:59 -06:00
{
Item * pItem = GetAItem ( auction -> item_guidlow );
2009-09-22 20:40:34 -04:00
if ( ! pItem )
2009-02-13 19:53:59 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
uint32 bidder_accId = 0 ;
uint32 bidder_security = 0 ;
2009-02-13 19:53:59 -06:00
uint64 bidder_guid = MAKE_NEW_GUID ( auction -> bidder , 0 , HIGHGUID_PLAYER );
Player * bidder = objmgr . GetPlayer ( bidder_guid );
// data for gm.log
2009-09-22 20:40:34 -04:00
if ( sWorld . getConfig ( CONFIG_GM_LOG_TRADE ))
2009-02-13 19:53:59 -06:00
{
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-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( bidder_security > SEC_PLAYER ) // not do redundant DB requests
2009-02-13 19:53:59 -06:00
{
2009-09-22 20:40:34 -04:00
if ( ! objmgr . GetPlayerNameByGUID ( bidder_guid , bidder_name ))
2009-02-13 19:53:59 -06:00
bidder_name = objmgr . GetTrinityStringForDBCLocale ( LANG_UNKNOWN );
}
}
2009-09-22 20:40:34 -04:00
if ( bidder_security > SEC_PLAYER )
2009-02-13 19:53:59 -06:00
{
std :: string owner_name ;
2009-09-22 20:40:34 -04:00
if ( ! objmgr . GetPlayerNameByGUID ( auction -> owner , owner_name ))
2009-02-13 19:53:59 -06:00
owner_name = objmgr . GetTrinityStringForDBCLocale ( LANG_UNKNOWN );
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
uint32 owner_accid = objmgr . GetPlayerAccountIdByGUID ( auction -> owner );
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
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 );
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
// receiver exist
2009-09-22 20:40:34 -04:00
if ( bidder || bidder_accId )
2009-02-13 19:53:59 -06:00
{
std :: ostringstream msgAuctionWonSubject ;
msgAuctionWonSubject << auction -> item_template << ":0:" << AUCTION_WON ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
std :: ostringstream msgAuctionWonBody ;
msgAuctionWonBody . width ( 16 );
msgAuctionWonBody << std :: right << std :: hex << auction -> owner ;
msgAuctionWonBody << std :: dec << ":" << auction -> bid << ":" << auction -> buyout ;
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "AuctionWon body string : %s" , msgAuctionWonBody . str (). c_str ());
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
// 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 ();
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
if ( bidder )
2009-09-22 20:40:34 -04:00
bidder -> GetSession () -> SendAuctionBidderNotification ( auction -> GetHouseId (), auction -> Id , bidder_guid , 0 , 0 , auction -> item_template );
2009-10-17 15:51:44 -07:00
2010-04-11 11:16:42 +04:00
MailDraft ( msgAuctionWonSubject . str (), msgAuctionWonBody . str ())
2009-12-16 18:58:36 +02:00
. AddItem ( pItem )
2010-04-11 11:16:42 +04:00
. SendMailTo ( MailReceiver ( bidder , auction -> bidder ), MailSender ( auction ), MAIL_CHECK_MASK_NONE );
2009-02-13 19:53:59 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
void AuctionHouseMgr :: SendAuctionSalePendingMail ( AuctionEntry * auction )
2009-02-13 19:53:59 -06:00
{
uint64 owner_guid = MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER );
Player * owner = objmgr . GetPlayer ( owner_guid );
2009-09-22 20:40:34 -04:00
uint32 owner_accId = objmgr . GetPlayerAccountIdByGUID ( owner_guid );
2009-02-13 19:53:59 -06:00
// owner exist (online or offline)
2009-09-22 20:40:34 -04:00
if ( owner || owner_accId )
2009-02-13 19:53:59 -06:00
{
std :: ostringstream msgAuctionSalePendingSubject ;
msgAuctionSalePendingSubject << auction -> item_template << ":0:" << AUCTION_SALE_PENDING ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
std :: ostringstream msgAuctionSalePendingBody ;
uint32 auctionCut = auction -> GetAuctionCut ();
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
time_t distrTime = time ( NULL ) + sWorld . getConfig ( CONFIG_MAIL_DELIVERY_DELAY );
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
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 );
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
sLog . outDebug ( "AuctionSalePending body string : %s" , msgAuctionSalePendingBody . str (). c_str ());
2009-10-17 15:51:44 -07:00
2010-04-11 11:16:42 +04:00
MailDraft ( msgAuctionSalePendingSubject . str (), msgAuctionSalePendingBody . str ())
. SendMailTo ( MailReceiver ( owner , auction -> owner ), auction , MAIL_CHECK_MASK_NONE );
2009-02-13 19:53:59 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
//call this method to send mail to auction owner, when auction is successful, it does not clear ram
2009-09-22 20:40:34 -04:00
void AuctionHouseMgr :: SendAuctionSuccessfulMail ( AuctionEntry * auction )
2009-02-13 19:53:59 -06:00
{
uint64 owner_guid = MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER );
Player * owner = objmgr . GetPlayer ( owner_guid );
2009-09-22 20:40:34 -04:00
uint32 owner_accId = objmgr . GetPlayerAccountIdByGUID ( owner_guid );
2009-02-13 19:53:59 -06:00
// owner exist
2009-09-22 20:40:34 -04:00
if ( owner || owner_accId )
2009-02-13 19:53:59 -06:00
{
std :: ostringstream msgAuctionSuccessfulSubject ;
msgAuctionSuccessfulSubject << auction -> item_template << ":0:" << AUCTION_SUCCESSFUL ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
std :: ostringstream auctionSuccessfulBody ;
uint32 auctionCut = auction -> GetAuctionCut ();
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
auctionSuccessfulBody . width ( 16 );
auctionSuccessfulBody << std :: right << std :: hex << auction -> bidder ;
auctionSuccessfulBody << std :: dec << ":" << auction -> bid << ":" << auction -> buyout ;
auctionSuccessfulBody << ":" << auction -> deposit << ":" << auctionCut ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
sLog . outDebug ( "AuctionSuccessful body string : %s" , auctionSuccessfulBody . str (). c_str ());
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
uint32 profit = auction -> bid + auction -> deposit - auctionCut ;
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
//FIXME: what do if owner offline
if ( owner && owner -> GetGUIDLow () != auctionbot . GetAHBplayerGUID ())
2009-02-13 19:53:59 -06:00
{
2009-03-05 09:22:43 -06:00
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!
2009-09-22 20:40:34 -04:00
owner -> GetSession () -> SendAuctionOwnerNotification ( auction );
2009-02-13 19:53:59 -06:00
}
2010-04-11 11:16:42 +04:00
MailDraft ( msgAuctionSuccessfulSubject . str (), auctionSuccessfulBody . str ())
2009-12-16 18:58:36 +02:00
. AddMoney ( profit )
2010-04-11 11:16:42 +04:00
. SendMailTo ( MailReceiver ( owner , auction -> owner ), auction , MAIL_CHECK_MASK_NONE , sWorld . getConfig ( CONFIG_MAIL_DELIVERY_DELAY ));
2009-02-13 19:53:59 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
//does not clear ram
2009-09-22 20:40:34 -04:00
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 );
2009-09-22 20:40:34 -04:00
if ( ! pItem )
2009-02-13 19:53:59 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
uint64 owner_guid = MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER );
Player * owner = objmgr . GetPlayer ( owner_guid );
2009-09-22 20:40:34 -04:00
uint32 owner_accId = objmgr . GetPlayerAccountIdByGUID ( owner_guid );
2009-02-13 19:53:59 -06:00
// owner exist
2009-09-22 20:40:34 -04:00
if ( owner || owner_accId )
2009-02-13 19:53:59 -06:00
{
std :: ostringstream subject ;
2010-04-11 11:16:42 +04:00
subject << auction -> item_template << ":0:" << AUCTION_EXPIRED << ":0:0" ;
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( owner && owner -> GetGUIDLow () != auctionbot . GetAHBplayerGUID ())
owner -> GetSession () -> SendAuctionOwnerNotification ( auction );
2009-10-17 15:51:44 -07:00
2010-04-11 11:16:42 +04:00
MailDraft ( subject . str (), "" ) // TODO: fix body
2009-12-16 18:58:36 +02:00
. AddItem ( pItem )
. SendMailTo ( MailReceiver ( owner , auction -> owner ), auction );
2009-02-13 19:53:59 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionHouseMgr :: LoadAuctionItems ()
{
// data needs to be at first place for Item::LoadFromDB
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr result = CharacterDatabase . Query ( "SELECT data,itemguid,item_template FROM auctionhouse JOIN item_instance ON itemguid = guid" );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! result )
2009-02-13 19:53:59 -06:00
{
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 ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
barGoLink bar ( result -> GetRowCount ());
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
Field * fields ;
do
{
bar . step ();
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
fields = result -> Fetch ();
uint32 item_guid = fields [ 1 ]. GetUInt32 ();
uint32 item_template = fields [ 2 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
ItemPrototype const * proto = objmgr . GetItemPrototype ( item_template );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! proto )
2009-02-13 19:53:59 -06:00
{
2009-10-09 20:48:55 -07:00
sLog . outError ( "AuctionHouseMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped." , item_guid , item_template );
2009-02-13 19:53:59 -06:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
Item * item = NewItemOrBag ( proto );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! item -> LoadFromDB ( item_guid , 0 , result ))
2009-02-13 19:53:59 -06:00
{
delete item ;
continue ;
}
AddAItem ( item );
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
++ count ;
2009-10-12 18:54:43 -07:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-09-22 20:40:34 -04:00
sLog . outString ( ">> Loaded %u auction items" , count );
2009-02-13 19:53:59 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionHouseMgr :: LoadAuctions ()
{
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr result = CharacterDatabase . Query ( "SELECT COUNT(*) FROM auctionhouse" );
2009-09-22 20:40:34 -04:00
if ( ! result )
2009-02-13 19:53:59 -06:00
{
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 ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
Field * fields = result -> Fetch ();
uint32 AuctionCount = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! AuctionCount )
2009-02-13 19:53:59 -06:00
{
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 ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
result = CharacterDatabase . Query ( "SELECT id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit FROM auctionhouse" );
if ( ! result )
2009-02-13 19:53:59 -06:00
{
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 ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
barGoLink bar ( AuctionCount );
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
AuctionEntry * aItem ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
do
{
fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
bar . step ();
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
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 ();
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
CreatureData const * auctioneerData = objmgr . GetCreatureData ( aItem -> auctioneer );
2009-09-22 20:40:34 -04:00
if ( ! auctioneerData )
2009-02-13 19:53:59 -06:00
{
aItem -> DeleteFromDB ();
sLog . outError ( "Auction %u has not a existing auctioneer (GUID : %u)" , aItem -> Id , aItem -> auctioneer );
delete aItem ;
continue ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
CreatureInfo const * auctioneerInfo = objmgr . GetCreatureTemplate ( auctioneerData -> id );
2009-09-22 20:40:34 -04:00
if ( ! auctioneerInfo )
2009-02-13 19:53:59 -06:00
{
aItem -> DeleteFromDB ();
sLog . outError ( "Auction %u has not a existing auctioneer (GUID : %u Entry: %u)" , aItem -> Id , aItem -> auctioneer , auctioneerData -> id );
delete aItem ;
continue ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
aItem -> auctionHouseEntry = AuctionHouseMgr :: GetAuctionHouseEntry ( auctioneerInfo -> faction_A );
2009-09-22 20:40:34 -04:00
if ( ! aItem -> auctionHouseEntry )
2009-02-13 19:53:59 -06:00
{
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 ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
// check if sold item exists for guid
2009-10-09 20:48:55 -07:00
// and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems)
2009-09-22 20:40:34 -04:00
if ( ! GetAItem ( aItem -> item_guidlow ))
2009-02-13 19:53:59 -06:00
{
aItem -> DeleteFromDB ();
sLog . outError ( "Auction %u has not a existing item : %u" , aItem -> Id , aItem -> item_guidlow );
delete aItem ;
continue ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
GetAuctionsMap ( auctioneerInfo -> faction_A ) -> AddAuction ( aItem );
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-09-22 20:40:34 -04:00
sLog . outString ( ">> Loaded %u auctions" , AuctionCount );
2009-02-13 19:53:59 -06:00
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
void AuctionHouseMgr :: AddAItem ( Item * it )
2009-02-13 19:53:59 -06:00
{
2009-09-22 20:40:34 -04:00
ASSERT ( it );
ASSERT ( mAitems . find ( it -> GetGUIDLow ()) == mAitems . end ());
2009-02-13 19:53:59 -06:00
mAitems [ it -> GetGUIDLow ()] = it ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
bool AuctionHouseMgr :: RemoveAItem ( uint32 id )
2009-02-13 19:53:59 -06:00
{
ItemMap :: iterator i = mAitems . find ( id );
if ( i == mAitems . end ())
return false ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
mAitems . erase ( i );
return true ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionHouseMgr :: Update ()
{
mHordeAuctions . Update ();
mAllianceAuctions . Update ();
mNeutralAuctions . Update ();
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
AuctionHouseEntry const * AuctionHouseMgr :: GetAuctionHouseEntry ( uint32 factionTemplateId )
{
2009-02-28 17:42:29 -05:00
uint32 houseid = 7 ; // goblin auction house
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION ))
2009-02-13 19:53:59 -06:00
{
//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 );
2009-09-22 20:40:34 -04:00
if ( ! u_entry )
2009-02-28 17:42:29 -05:00
houseid = 7 ; // goblin auction house
2009-09-22 20:40:34 -04:00
else if ( u_entry -> ourMask & FACTION_MASK_ALLIANCE )
2009-02-28 17:42:29 -05:00
houseid = 1 ; // human auction house
2009-09-22 20:40:34 -04: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 ;
}
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
return sAuctionHouseStore . LookupEntry ( houseid );
}
2009-09-23 00:05:52 -04:00
void AuctionHouseObject :: AddAuction ( AuctionEntry * ah )
{
ASSERT ( ah );
AuctionsMap [ ah -> Id ] = ah ;
auctionbot . IncrementItemCounts ( ah );
}
2009-10-17 15:51:44 -07:00
2009-09-23 00:05:52 -04:00
bool AuctionHouseObject :: RemoveAuction ( AuctionEntry * auction , uint32 item_template )
{
auctionbot . DecrementItemCounts ( auction , item_template );
return AuctionsMap . erase ( auction -> Id ) ? true : false ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionHouseObject :: Update ()
{
2009-12-24 10:20:15 +01:00
time_t curTime = sWorld . GetGameTime ();
2009-02-13 19:53:59 -06:00
///- Handle expired auctions
2009-10-17 15:51:44 -07:00
2009-10-05 16:36:53 +02:00
// If storage is empty, no need to update. next == NULL in this case.
2009-10-05 16:20:02 +02:00
if ( AuctionsMap . empty ())
return ;
2009-10-17 15:51:44 -07:00
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr result = CharacterDatabase . PQuery ( "SELECT id FROM auctionhouse WHERE time <= %u ORDER BY TIME ASC" , ( uint32 ) curTime + 60 );
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
if ( ! result )
return ;
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
if ( result -> GetRowCount () == 0 )
return ;
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
vector < uint32 > expiredAuctions ;
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
do
2009-02-13 19:53:59 -06:00
{
2009-10-12 18:54:43 -07:00
uint32 tmpdata = result -> Fetch () -> GetUInt32 ();
expiredAuctions . push_back ( tmpdata );
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2009-10-13 18:35:36 -04:00
while ( ! expiredAuctions . empty ())
2009-10-12 18:54:43 -07:00
{
2009-10-31 16:00:47 -07:00
vector < uint32 >:: iterator iter = expiredAuctions . begin ();
2009-10-12 18:54:43 -07:00
// from auctionhousehandler.cpp, creates auction pointer & player pointer
AuctionEntry * auction = GetAuction ( * iter );
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
// Erase the auction from the vector.
expiredAuctions . erase ( iter );
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
if ( ! auction )
continue ;
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
///- Either cancel the auction if there was no bidder
if ( auction -> bidder == 0 )
auctionmgr . 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
auctionmgr . SendAuctionSuccessfulMail ( auction );
auctionmgr . SendAuctionWonMail ( auction );
}
2009-10-17 15:51:44 -07:00
2009-10-12 18:54:43 -07:00
///- In any case clear the auction
auction -> DeleteFromDB ();
uint32 item_template = auction -> item_template ;
auctionmgr . RemoveAItem ( auction -> item_guidlow );
RemoveAuction ( auction , item_template );
2009-02-13 19:53:59 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionHouseObject :: BuildListBidderItems ( WorldPacket & data , Player * player , uint32 & count , uint32 & totalcount )
{
2009-10-17 16:20:24 -07:00
for ( AuctionEntryMap :: const_iterator itr = AuctionsMap . begin (); itr != AuctionsMap . end (); ++ itr )
2009-02-13 19:53:59 -06:00
{
AuctionEntry * Aentry = itr -> second ;
2009-09-22 20:40:34 -04:00
if ( Aentry && Aentry -> bidder == player -> GetGUIDLow ())
2009-02-13 19:53:59 -06:00
{
if ( itr -> second -> BuildAuctionInfo ( data ))
++ count ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
++ totalcount ;
}
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionHouseObject :: BuildListOwnerItems ( WorldPacket & data , Player * player , uint32 & count , uint32 & totalcount )
{
2009-10-17 16:20:24 -07:00
for ( AuctionEntryMap :: const_iterator itr = AuctionsMap . begin (); itr != AuctionsMap . end (); ++ itr )
2009-02-13 19:53:59 -06:00
{
AuctionEntry * Aentry = itr -> second ;
2009-09-22 20:40:34 -04:00
if ( Aentry && Aentry -> owner == player -> GetGUIDLow ())
2009-02-13 19:53:59 -06:00
{
2009-09-22 20:40:34 -04:00
if ( Aentry -> BuildAuctionInfo ( data ))
2009-02-13 19:53:59 -06:00
++ count ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
++ totalcount ;
}
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionHouseObject :: BuildListAuctionItems ( WorldPacket & data , Player * player ,
2009-11-01 23:01:26 -08:00
std :: wstring const & wsearchedname , uint32 listfrom , uint8 levelmin , uint8 levelmax , uint8 usable ,
2009-02-13 19:53:59 -06:00
uint32 inventoryType , uint32 itemClass , uint32 itemSubClass , uint32 quality ,
uint32 & count , uint32 & totalcount )
{
int loc_idx = player -> GetSession () -> GetSessionDbLocaleIndex ();
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( AuctionEntryMap :: const_iterator itr = AuctionsMap . begin (); itr != AuctionsMap . end (); ++ itr )
2009-02-13 19:53:59 -06:00
{
AuctionEntry * Aentry = itr -> second ;
Item * item = auctionmgr . GetAItem ( Aentry -> item_guidlow );
if ( ! item )
continue ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
ItemPrototype const * proto = item -> GetProto ();
2009-10-17 15:51:44 -07:00
2009-02-24 11:14:28 -06:00
if ( itemClass != 0xffffffff && proto -> Class != itemClass )
2009-02-13 19:53:59 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-02-24 11:14:28 -06:00
if ( itemSubClass != 0xffffffff && proto -> SubClass != itemSubClass )
2009-02-13 19:53:59 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-02-24 11:14:28 -06:00
if ( inventoryType != 0xffffffff && proto -> InventoryType != inventoryType )
2009-02-13 19:53:59 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-02-24 11:14:28 -06:00
if ( quality != 0xffffffff && proto -> Quality != quality )
2009-02-13 19:53:59 -06:00
continue ;
2009-10-17 15:51:44 -07:00
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-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( usable != 0x00 && player -> CanUseItem ( item ) != EQUIP_ERR_OK )
2009-02-13 19:53:59 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
std :: string name = proto -> Name1 ;
2009-09-22 20:40:34 -04:00
if ( name . empty ())
2009-02-13 19:53:59 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
// local name
2009-09-22 20:40:34 -04:00
if ( loc_idx >= 0 )
2009-02-13 19:53:59 -06:00
{
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-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! wsearchedname . empty () && ! Utf8FitTo ( name , wsearchedname ))
2009-02-13 19:53:59 -06:00
continue ;
2009-10-17 15:51:44 -07:00
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 ;
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
//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-10-17 15:51:44 -07: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-10-17 15:51:44 -07:00
2009-12-21 14:48:30 -07:00
data << int32 ( pItem -> GetItemRandomPropertyId ()); //random item property id
2009-03-02 16:53:50 -06:00
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
2009-12-24 10:20:15 +01:00
data << uint32 (( expire_time - time ( NULL )) * IN_MILISECONDS ); //time left
2009-03-02 16:53:50 -06:00
data << uint64 ( bidder ) ; //auction->bidder current
data << uint32 ( bid ); //current bid
2009-02-13 19:53:59 -06:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
uint32 AuctionEntry :: GetAuctionCut () const
{
2009-09-22 20:40:34 -04:00
int32 cut = int32 ((( double ) auctionHouseEntry -> cutPercent / 100.0f ) * ( double ) sWorld . getRate ( RATE_AUCTION_CUT )) * bid ;
if ( cut > 0 )
return cut ;
else
return 0 ;
2009-02-13 19:53:59 -06:00
}
2009-10-17 15:51:44 -07:00
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
{
2009-09-22 20:40:34 -04:00
uint32 outbid = ( uint32 )(( double ) bid / 100.0f ) * 5 ;
2009-02-13 19:53:59 -06:00
if ( ! outbid )
outbid = 1 ;
return outbid ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
void AuctionEntry :: DeleteFromDB () const
{
//No SQL injection (Id is integer)
CharacterDatabase . PExecute ( "DELETE FROM auctionhouse WHERE id = '%u'" , Id );
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:53:59 -06:00
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 );
}