2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* 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
2008-11-20 16:16:57 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* 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
2008-11-20 16:16:57 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2009-06-04 21:41:07 +02:00
#include "ObjectMgr.h"
#include "Player.h"
#include "World.h"
2008-10-02 16:23:55 -05:00
#include "WorldPacket.h"
#include "WorldSession.h"
2009-10-17 15:51:44 -07:00
2009-06-04 21:41:07 +02:00
#include "AuctionHouseBot.h"
#include "AuctionHouseMgr.h"
2008-10-02 16:23:55 -05:00
#include "Log.h"
2009-06-04 21:41:07 +02:00
#include "Opcodes.h"
2008-10-02 16:23:55 -05:00
#include "UpdateMask.h"
#include "Util.h"
2009-06-04 21:41:07 +02:00
2008-10-02 16:23:55 -05:00
//please DO NOT use iterator++, because it is slower than ++iterator!!!
//post-incrementation is always slower than pre-incrementation !
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//void called when player click on auctioneer npc
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionHelloOpcode ( WorldPacket & recv_data )
2008-10-02 16:23:55 -05:00
{
uint64 guid ; //NPC guid
recv_data >> guid ;
2009-10-17 15:51:44 -07:00
2009-04-19 18:23:10 -05:00
Creature * unit = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! unit )
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( guid )));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remove fake death
2009-09-22 20:40:34 -04:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
SendAuctionHello ( guid , unit );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this void causes that auction window is opened
2009-09-22 20:40:34 -04:00
void WorldSession :: SendAuctionHello ( uint64 guid , Creature * unit )
2008-10-02 16:23:55 -05:00
{
2010-03-09 12:58:48 +01:00
if ( GetPlayer () -> getLevel () < sWorld . getConfig ( CONFIG_AUCTION_LEVEL_REQ ))
{
SendNotification ( GetTrinityString ( LANG_AUCTION_REQ ), sWorld . getConfig ( CONFIG_AUCTION_LEVEL_REQ ));
return ;
}
2009-02-13 19:50:20 -06:00
AuctionHouseEntry const * ahEntry = AuctionHouseMgr :: GetAuctionHouseEntry ( unit -> getFaction ());
2009-09-22 20:40:34 -04:00
if ( ! ahEntry )
2009-02-13 19:50:20 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
WorldPacket data ( MSG_AUCTION_HELLO , 12 );
2010-04-11 20:20:38 +02:00
data << uint64 ( guid );
data << uint32 ( ahEntry -> houseId );
2010-04-11 11:13:08 +04:00
data << uint8 ( 1 ); // 3.3.3: 1 - AH enabled, 0 - AH disabled
2009-09-22 20:40:34 -04:00
SendPacket ( & data );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//call this method when player bids, creates, or deletes auction
2009-09-22 20:40:34 -04:00
void WorldSession :: SendAuctionCommandResult ( uint32 auctionId , uint32 Action , uint32 ErrorCode , uint32 bidError )
2008-10-02 16:23:55 -05:00
{
2009-09-22 20:40:34 -04:00
WorldPacket data ( SMSG_AUCTION_COMMAND_RESULT , 16 );
2008-10-02 16:23:55 -05:00
data << auctionId ;
data << Action ;
data << ErrorCode ;
2009-09-22 20:40:34 -04:00
if ( ! ErrorCode && Action )
2008-10-02 16:23:55 -05:00
data << bidError ; //when bid, then send 0, once...
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this function sends notification, if bidder is online
2009-09-22 20:40:34 -04:00
void WorldSession :: SendAuctionBidderNotification ( uint32 location , uint32 auctionId , uint64 bidder , uint32 bidSum , uint32 diff , uint32 item_template )
2008-10-02 16:23:55 -05:00
{
WorldPacket data ( SMSG_AUCTION_BIDDER_NOTIFICATION , ( 8 * 4 ));
2009-02-09 22:08:06 -06:00
data << uint32 ( location );
data << uint32 ( auctionId );
data << uint64 ( bidder );
data << uint32 ( bidSum );
data << uint32 ( diff );
data << uint32 ( item_template );
data << uint32 ( 0 );
2008-10-02 16:23:55 -05:00
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this void causes on client to display: "Your auction sold"
2009-09-22 20:40:34 -04:00
void WorldSession :: SendAuctionOwnerNotification ( AuctionEntry * auction )
2008-10-02 16:23:55 -05:00
{
WorldPacket data ( SMSG_AUCTION_OWNER_NOTIFICATION , ( 7 * 4 ));
data << auction -> Id ;
data << auction -> bid ;
data << ( uint32 ) 0 ; //unk
data << ( uint32 ) 0 ; //unk
data << ( uint32 ) 0 ; //unk
data << auction -> item_template ;
data << ( uint32 ) 0 ; //unk
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this function sends mail to old bidder
void WorldSession :: SendAuctionOutbiddedMail ( AuctionEntry * auction , uint32 newPrice )
{
uint64 oldBidder_guid = MAKE_NEW_GUID ( auction -> bidder , 0 , HIGHGUID_PLAYER );
Player * oldBidder = objmgr . GetPlayer ( oldBidder_guid );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 oldBidder_accId = 0 ;
2009-09-22 20:40:34 -04:00
if ( ! oldBidder )
2008-10-02 16:23:55 -05:00
oldBidder_accId = objmgr . GetPlayerAccountIdByGUID ( oldBidder_guid );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// old bidder exist
2009-09-22 20:40:34 -04:00
if ( oldBidder || oldBidder_accId )
2008-10-02 16:23:55 -05:00
{
std :: ostringstream msgAuctionOutbiddedSubject ;
2010-04-11 11:16:42 +04:00
msgAuctionOutbiddedSubject << auction -> item_template << ":0:" << AUCTION_OUTBIDDED << ":0:0" ;
2009-10-17 15:51:44 -07:00
2009-01-20 16:44:05 -06:00
if ( oldBidder && ! _player )
2009-09-22 20:40:34 -04:00
oldBidder -> GetSession () -> SendAuctionBidderNotification ( auction -> GetHouseId (), auction -> Id , auctionbot . GetAHBplayerGUID (), newPrice , auction -> GetAuctionOutBid (), auction -> item_template );
2009-10-17 15:51:44 -07:00
2009-01-20 16:44:05 -06:00
if ( oldBidder && _player )
2009-09-22 20:40:34 -04:00
oldBidder -> GetSession () -> SendAuctionBidderNotification ( auction -> GetHouseId (), auction -> Id , _player -> GetGUID (), newPrice , auction -> GetAuctionOutBid (), auction -> item_template );
2009-10-17 15:51:44 -07:00
2010-04-11 11:16:42 +04:00
MailDraft ( msgAuctionOutbiddedSubject . str (), "" ) // TODO: fix body
2009-12-16 18:58:36 +02:00
. AddMoney ( auction -> bid )
2010-04-14 19:06:37 +02:00
. SendMailTo ( MailReceiver ( oldBidder , auction -> bidder ), auction , MAIL_CHECK_MASK_COPIED );
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-28 17:42:29 -05:00
//this function sends mail, when auction is cancelled to old bidder
2009-09-22 20:40:34 -04:00
void WorldSession :: SendAuctionCancelledToBidderMail ( AuctionEntry * auction )
2008-10-02 16:23:55 -05:00
{
uint64 bidder_guid = MAKE_NEW_GUID ( auction -> bidder , 0 , HIGHGUID_PLAYER );
Player * bidder = objmgr . GetPlayer ( bidder_guid );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 bidder_accId = 0 ;
2009-09-22 20:40:34 -04:00
if ( ! bidder )
2008-10-02 16:23:55 -05:00
bidder_accId = objmgr . GetPlayerAccountIdByGUID ( bidder_guid );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// bidder exist
2009-09-22 20:40:34 -04:00
if ( bidder || bidder_accId )
2008-10-02 16:23:55 -05:00
{
std :: ostringstream msgAuctionCancelledSubject ;
2010-04-11 11:16:42 +04:00
msgAuctionCancelledSubject << auction -> item_template << ":0:" << AUCTION_CANCELLED_TO_BIDDER << ":0:0" ;
2009-10-17 15:51:44 -07:00
2010-04-11 11:16:42 +04:00
MailDraft ( msgAuctionCancelledSubject . str (), "" ) // TODO: fix body
2009-12-16 18:58:36 +02:00
. AddMoney ( auction -> bid )
2010-04-14 19:06:37 +02:00
. SendMailTo ( MailReceiver ( bidder , auction -> bidder ), auction , MAIL_CHECK_MASK_COPIED );
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this void creates new auction and adds auction to some auctionhouse
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionSellItem ( WorldPacket & recv_data )
2008-10-02 16:23:55 -05:00
{
uint64 auctioneer , item ;
uint32 etime , bid , buyout ;
2009-12-19 10:29:12 +01:00
recv_data >> auctioneer ;
recv_data . read_skip < uint32 > (); // const 1?
recv_data >> item ;
recv_data . read_skip < uint32 > (); // unk 3.2.2, const 1?
recv_data >> bid ;
recv_data >> buyout ;
recv_data >> etime ;
2008-10-02 16:23:55 -05:00
Player * pl = GetPlayer ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( ! item || ! bid || ! etime )
return ; //check for cheaters
2009-10-17 15:51:44 -07:00
2009-04-19 18:23:10 -05:00
Creature * pCreature = GetPlayer () -> GetNPCIfCanInteractWith ( auctioneer , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! pCreature )
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( auctioneer )));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:50:20 -06:00
AuctionHouseEntry const * auctionHouseEntry = AuctionHouseMgr :: GetAuctionHouseEntry ( pCreature -> getFaction ());
2009-09-22 20:40:34 -04:00
if ( ! auctionHouseEntry )
2009-02-13 19:50:20 -06:00
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction." , uint32 ( GUID_LOPART ( auctioneer )));
2009-02-13 19:50:20 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionSellItem - ETIME: %u" , etime );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// client send time in minutes, convert to common used sec time
etime *= MINUTE ;
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionSellItem - ETIME: %u" , etime );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// 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 ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remove fake death
2009-09-22 20:40:34 -04:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
Item * it = pl -> GetItemByGuid ( item );
2008-10-02 16:23:55 -05:00
//do not allow to sell already auctioned items
2009-09-22 20:40:34 -04:00
if ( auctionmgr . GetAItem ( GUID_LOPART ( item )))
2008-10-02 16:23:55 -05:00
{
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 ;
}
2008-11-20 16:16:57 -06:00
// prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction)
2009-09-22 20:40:34 -04:00
if ( ! it )
2008-10-02 16:23:55 -05:00
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_ITEM_NOT_FOUND );
return ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! it -> CanBeTraded ())
2008-10-02 16:23:55 -05:00
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_INTERNAL_ERROR );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( it -> HasFlag ( ITEM_FIELD_FLAGS , ITEM_FLAGS_CONJURED ) || it -> GetUInt32Value ( ITEM_FIELD_DURATION ))
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_INTERNAL_ERROR );
return ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
AuctionHouseObject * auctionHouse = auctionmgr . GetAuctionsMap ( pCreature -> getFaction ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//we have to take deposit :
2009-09-22 20:40:34 -04:00
uint32 deposit = auctionmgr . GetAuctionDeposit ( auctionHouseEntry , etime , it );
if ( pl -> GetMoney () < deposit )
2008-10-02 16:23:55 -05:00
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_NOT_ENOUGHT_MONEY );
return ;
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( GetSecurity () > SEC_PLAYER && sWorld . getConfig ( CONFIG_GM_LOG_TRADE ))
2008-10-02 16:23:55 -05:00
{
2008-11-25 16:36:50 -06:00
sLog . outCommand ( GetAccountId (), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)" ,
2008-10-02 16:23:55 -05:00
GetPlayerName (), GetAccountId (), it -> GetProto () -> Name1 , it -> GetEntry (), it -> GetCount ());
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
pl -> ModifyMoney ( - int32 ( deposit ));
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 auction_time = uint32 ( etime * sWorld . getRate ( RATE_AUCTION_TIME ));
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
AuctionEntry * AH = new AuctionEntry ;
AH -> Id = objmgr . GenerateAuctionID ();
2009-09-22 20:40:34 -04:00
if ( sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION ))
2009-02-28 17:42:29 -05:00
AH -> auctioneer = 23442 ;
else
AH -> auctioneer = GUID_LOPART ( auctioneer );
2008-10-02 16:23:55 -05:00
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 ;
2009-12-24 10:20:15 +01:00
AH -> expire_time = time ( NULL ) + auction_time ;
2008-10-02 16:23:55 -05:00
AH -> deposit = deposit ;
2009-02-13 19:50:20 -06:00
AH -> auctionHouseEntry = auctionHouseEntry ;
2009-10-17 15:51:44 -07:00
2009-02-28 17:42:29 -05:00
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 ());
2009-09-22 20:40:34 -04:00
auctionmgr . AddAItem ( it );
2009-02-13 19:50:20 -06:00
auctionHouse -> AddAuction ( AH );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
pl -> MoveItemFromInventory ( it -> GetBagSlot (), it -> GetSlot (), true );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
CharacterDatabase . BeginTransaction ();
it -> DeleteFromInventoryDB ();
it -> SaveToDB (); // recursive and not have transaction guard into self, not in inventiory and can be save standalone
2009-02-13 19:50:20 -06:00
AH -> SaveToDB ();
2008-10-02 16:23:55 -05:00
pl -> SaveInventoryAndGoldToDB ();
CharacterDatabase . CommitTransaction ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
SendAuctionCommandResult ( AH -> Id , AUCTION_SELL_ITEM , AUCTION_OK );
2010-05-21 16:49:19 -03:00
GetPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION , 1 );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this function is called when client bids or buys out auction
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionPlaceBid ( WorldPacket & recv_data )
2008-10-02 16:23:55 -05:00
{
uint64 auctioneer ;
uint32 auctionId ;
2009-11-21 03:31:09 -08:00
uint32 price ;
2008-10-02 16:23:55 -05:00
recv_data >> auctioneer ;
recv_data >> auctionId >> price ;
2009-10-17 15:51:44 -07:00
2009-11-21 03:31:09 -08:00
if ( ! auctionId || ! price )
2008-10-02 16:23:55 -05:00
return ; //check for cheaters
2009-10-17 15:51:44 -07:00
2009-11-19 03:55:15 -08:00
Creature * pCreature = GetPlayer () -> GetNPCIfCanInteractWith ( auctioneer , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! pCreature )
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( auctioneer )));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remove fake death
2009-09-22 20:40:34 -04:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2009-11-19 03:55:15 -08:00
AuctionHouseObject * auctionHouse = auctionmgr . GetAuctionsMap ( pCreature -> getFaction ());
2009-10-17 15:51:44 -07:00
2009-02-13 19:50:20 -06:00
AuctionEntry * auction = auctionHouse -> GetAuction ( auctionId );
2008-10-02 16:23:55 -05:00
Player * pl = GetPlayer ();
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
if ( ! auction || auction -> owner == pl -> GetGUIDLow ())
2008-10-02 16:23:55 -05:00
{
//you cannot bid your own auction:
2009-09-22 20:40:34 -04:00
SendAuctionCommandResult ( 0 , AUCTION_PLACE_BID , CANNOT_BID_YOUR_AUCTION_ERROR );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// 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 ));
2009-09-22 20:40:34 -04:00
if ( ! auction_owner && objmgr . GetPlayerAccountIdByGUID ( MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER )) == pl -> GetSession () -> GetAccountId ())
2008-10-02 16:23:55 -05:00
{
//you cannot bid your another character auction:
2009-09-22 20:40:34 -04:00
SendAuctionCommandResult ( 0 , AUCTION_PLACE_BID , CANNOT_BID_YOUR_AUCTION_ERROR );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
// cheating
2009-11-20 15:06:21 -08:00
if ( price <= auction -> bid || price < auction -> startbid )
2008-12-22 10:59:38 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
// price too low for next bid if not buyout
2009-11-19 04:16:40 -08:00
if (( price < auction -> buyout || auction -> buyout == 0 ) &&
2009-02-13 19:50:20 -06:00
price < auction -> bid + auction -> GetAuctionOutBid ())
2008-10-02 16:23:55 -05:00
{
//auction has already higher bid, client tests it!
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( price > pl -> GetMoney ())
{
//you don't have enought money!, client tests!
//SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
return ;
}
2009-10-17 15:51:44 -07:00
2009-11-19 03:55:15 -08:00
if ( price < auction -> buyout || auction -> buyout == 0 )
2008-10-02 16:23:55 -05:00
{
if ( auction -> bidder > 0 )
{
2009-09-22 20:40:34 -04:00
if ( auction -> bidder == pl -> GetGUIDLow ())
pl -> ModifyMoney ( - int32 ( price - auction -> bid ));
2008-10-02 16:23:55 -05:00
else
{
// mail to last bidder and return money
2009-11-19 03:55:15 -08:00
SendAuctionOutbiddedMail ( auction , price );
2009-09-22 20:40:34 -04:00
pl -> ModifyMoney ( - int32 ( price ));
2008-10-02 16:23:55 -05:00
}
}
else
2009-09-22 20:40:34 -04:00
pl -> ModifyMoney ( - int32 ( price ));
2009-11-19 03:55:15 -08:00
2008-10-02 16:23:55 -05:00
auction -> bidder = pl -> GetGUIDLow ();
auction -> bid = price ;
2009-03-05 09:22:43 -06:00
GetPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID , price );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// after this update we should save player's money ...
2010-04-12 11:03:31 +02:00
CharacterDatabase . BeginTransaction ();
2008-10-02 16:23:55 -05:00
CharacterDatabase . PExecute ( "UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'" , auction -> bidder , auction -> bid , auction -> Id );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
SendAuctionCommandResult ( auction -> Id , AUCTION_PLACE_BID , AUCTION_OK , 0 );
2008-10-02 16:23:55 -05:00
}
else
{
//buyout:
2009-09-22 20:40:34 -04:00
if ( pl -> GetGUIDLow () == auction -> bidder )
2008-10-02 16:23:55 -05:00
pl -> ModifyMoney ( - int32 ( auction -> buyout - auction -> bid ));
else
{
pl -> ModifyMoney ( - int32 ( auction -> buyout ));
2009-09-22 20:40:34 -04:00
if ( auction -> bidder ) //buyout for bidded auction ..
SendAuctionOutbiddedMail ( auction , auction -> buyout );
2008-10-02 16:23:55 -05:00
}
auction -> bidder = pl -> GetGUIDLow ();
auction -> bid = auction -> buyout ;
2009-03-05 09:22:43 -06:00
GetPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID , auction -> buyout );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
auctionmgr . SendAuctionSalePendingMail ( auction );
auctionmgr . SendAuctionSuccessfulMail ( auction );
auctionmgr . SendAuctionWonMail ( auction );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
SendAuctionCommandResult ( auction -> Id , AUCTION_PLACE_BID , AUCTION_OK );
2010-04-12 11:03:31 +02:00
CharacterDatabase . BeginTransaction ();
2009-02-13 19:50:20 -06:00
auction -> DeleteFromDB ();
2009-09-22 20:40:34 -04:00
uint32 item_template = auction -> item_template ;
auctionmgr . RemoveAItem ( auction -> item_guidlow );
auctionHouse -> RemoveAuction ( auction , item_template );
2008-10-02 16:23:55 -05:00
}
pl -> SaveInventoryAndGoldToDB ();
CharacterDatabase . CommitTransaction ();
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this void is called when auction_owner cancels his auction
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionRemoveItem ( WorldPacket & recv_data )
2008-10-02 16:23:55 -05:00
{
uint64 auctioneer ;
uint32 auctionId ;
recv_data >> auctioneer ;
recv_data >> auctionId ;
2009-09-22 20:40:34 -04:00
//sLog.outDebug("Cancel AUCTION AuctionID: %u", auctionId);
2009-10-17 15:51:44 -07:00
2009-04-19 18:23:10 -05:00
Creature * pCreature = GetPlayer () -> GetNPCIfCanInteractWith ( auctioneer , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! pCreature )
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( auctioneer )));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remove fake death
2009-09-22 20:40:34 -04:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
AuctionHouseObject * auctionHouse = auctionmgr . GetAuctionsMap ( pCreature -> getFaction ());
2009-10-17 15:51:44 -07:00
2009-02-13 19:50:20 -06:00
AuctionEntry * auction = auctionHouse -> GetAuction ( auctionId );
2008-10-02 16:23:55 -05:00
Player * pl = GetPlayer ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( auction && auction -> owner == pl -> GetGUIDLow ())
{
2009-02-13 19:50:20 -06:00
Item * pItem = auctionmgr . GetAItem ( auction -> item_guidlow );
2008-10-02 16:23:55 -05:00
if ( pItem )
{
if ( auction -> bidder > 0 ) // If we have a bidder, we have to send him the money he paid
{
2009-02-13 19:50:20 -06:00
uint32 auctionCut = auction -> GetAuctionCut ();
2009-09-22 20:40:34 -04:00
if ( pl -> GetMoney () < auctionCut ) //player doesn't have enough money, maybe message needed
2008-10-02 16:23:55 -05:00
return ;
//some auctionBidderNotification would be needed, but don't know that parts..
2009-09-22 20:40:34 -04:00
SendAuctionCancelledToBidderMail ( auction );
pl -> ModifyMoney ( - int32 ( auctionCut ));
2008-10-02 16:23:55 -05:00
}
// Return the item by mail
std :: ostringstream msgAuctionCanceledOwner ;
2010-04-11 11:16:42 +04:00
msgAuctionCanceledOwner << auction -> item_template << ":0:" << AUCTION_CANCELED << ":0:0" ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// item will deleted or added to received mail list
2010-04-11 11:16:42 +04:00
MailDraft ( msgAuctionCanceledOwner . str (), "" ) // TODO: fix body
2009-12-16 18:58:36 +02:00
. AddItem ( pItem )
2010-04-14 19:06:37 +02:00
. SendMailTo ( pl , auction , MAIL_CHECK_MASK_COPIED );
2008-10-02 16:23:55 -05:00
}
else
{
sLog . outError ( "Auction id: %u has non-existed item (item guid : %u)!!!" , auction -> Id , auction -> item_guidlow );
2009-09-22 20:40:34 -04:00
SendAuctionCommandResult ( 0 , AUCTION_CANCEL , AUCTION_INTERNAL_ERROR );
2008-10-02 16:23:55 -05:00
return ;
}
}
else
{
2009-09-22 20:40:34 -04:00
SendAuctionCommandResult ( 0 , AUCTION_CANCEL , AUCTION_INTERNAL_ERROR );
2008-10-02 16:23:55 -05:00
//this code isn't possible ... maybe there should be assert
2009-09-22 20:40:34 -04:00
sLog . outError ( "CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL" , pl -> GetGUIDLow (), auctionId );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//inform player, that auction is removed
2009-09-22 20:40:34 -04:00
SendAuctionCommandResult ( auction -> Id , AUCTION_CANCEL , AUCTION_OK );
2010-04-12 11:03:31 +02:00
2008-10-02 16:23:55 -05:00
// Now remove the auction
CharacterDatabase . BeginTransaction ();
pl -> SaveInventoryAndGoldToDB ();
2009-09-22 20:40:34 -04:00
auction -> DeleteFromDB ();
uint32 item_template = auction -> item_template ;
auctionmgr . RemoveAItem ( auction -> item_guidlow );
auctionHouse -> RemoveAuction ( auction , item_template );
2010-04-12 11:03:31 +02:00
CharacterDatabase . CommitTransaction ();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//called when player lists his bids
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionListBidderItems ( WorldPacket & recv_data )
2008-10-02 16:23:55 -05:00
{
uint64 guid ; //NPC guid
uint32 listfrom ; //page of auctions
uint32 outbiddedCount ; //count of outbidded auctions
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> guid ;
recv_data >> listfrom ; // not used in fact (this list not have page control in client)
recv_data >> outbiddedCount ;
2009-09-22 20:40:34 -04:00
if ( recv_data . size () != ( 16 + outbiddedCount * 4 ))
2008-10-02 16:23:55 -05:00
{
2009-09-22 20:40:34 -04:00
sLog . outError ( "Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)" , outbiddedCount , ( unsigned long ) recv_data . size (),( 16 + outbiddedCount * 4 ));
2008-10-02 16:23:55 -05:00
outbiddedCount = 0 ;
}
2009-10-17 15:51:44 -07:00
2009-04-19 18:23:10 -05:00
Creature * pCreature = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! pCreature )
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( guid )));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remove fake death
2009-09-22 20:40:34 -04:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
AuctionHouseObject * auctionHouse = auctionmgr . GetAuctionsMap ( pCreature -> getFaction ());
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
WorldPacket data ( SMSG_AUCTION_BIDDER_LIST_RESULT , ( 4 + 4 + 4 ));
2008-10-02 16:23:55 -05:00
Player * pl = GetPlayer ();
data << ( uint32 ) 0 ; //add 0 as count
uint32 count = 0 ;
uint32 totalcount = 0 ;
2009-09-22 20:40:34 -04:00
while ( outbiddedCount > 0 ) //add all data, which client requires
2008-10-02 16:23:55 -05:00
{
-- outbiddedCount ;
uint32 outbiddedAuctionId ;
recv_data >> outbiddedAuctionId ;
2009-09-22 20:40:34 -04:00
AuctionEntry * auction = auctionHouse -> GetAuction ( outbiddedAuctionId );
if ( auction && auction -> BuildAuctionInfo ( data ))
2008-10-02 16:23:55 -05:00
{
++ totalcount ;
++ count ;
}
}
2009-10-17 15:51:44 -07:00
2009-02-13 19:50:20 -06:00
auctionHouse -> BuildListBidderItems ( data , pl , count , totalcount );
2009-09-22 20:40:34 -04:00
data . put < uint32 > ( 0 , count ); // add count to placeholder
2008-10-02 16:23:55 -05:00
data << totalcount ;
data << ( uint32 ) 300 ; //unk 2.3.0
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this void sends player info about his auctions
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionListOwnerItems ( WorldPacket & recv_data )
2008-10-02 16:23:55 -05:00
{
uint32 listfrom ;
uint64 guid ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> guid ;
recv_data >> listfrom ; // not used in fact (this list not have page control in client)
2009-10-17 15:51:44 -07:00
2009-04-19 18:23:10 -05:00
Creature * pCreature = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! pCreature )
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( guid )));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remove fake death
2009-09-22 20:40:34 -04:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
AuctionHouseObject * auctionHouse = auctionmgr . GetAuctionsMap ( pCreature -> getFaction ());
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
WorldPacket data ( SMSG_AUCTION_OWNER_LIST_RESULT , ( 4 + 4 + 4 ));
2008-10-02 16:23:55 -05:00
data << ( uint32 ) 0 ; // amount place holder
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 count = 0 ;
uint32 totalcount = 0 ;
2009-10-17 15:51:44 -07:00
2009-02-13 19:50:20 -06:00
auctionHouse -> BuildListOwnerItems ( data , _player , count , totalcount );
2008-10-02 16:23:55 -05:00
data . put < uint32 > ( 0 , count );
data << ( uint32 ) totalcount ;
data << ( uint32 ) 0 ;
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//this void is called when player clicks on search button
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionListItems ( WorldPacket & recv_data )
2008-10-02 16:23:55 -05:00
{
2009-02-09 22:08:06 -06:00
std :: string searchedname ;
uint8 levelmin , levelmax , usable ;
uint32 listfrom , auctionSlotID , auctionMainCategory , auctionSubCategory , quality ;
2008-10-02 16:23:55 -05:00
uint64 guid ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> guid ;
recv_data >> listfrom ; // start, used for page control listing by 50 elements
recv_data >> searchedname ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> levelmin >> levelmax ;
recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory ;
recv_data >> quality >> usable ;
2009-10-17 15:51:44 -07:00
2009-04-19 18:23:10 -05:00
Creature * pCreature = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! pCreature )
{
2009-09-22 20:40:34 -04:00
sLog . outDebug ( "WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( guid )));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remove fake death
2009-09-22 20:40:34 -04:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
AuctionHouseObject * auctionHouse = auctionmgr . GetAuctionsMap ( pCreature -> getFaction ());
2009-10-17 15:51:44 -07:00
2009-05-31 16:15:12 -05:00
//sLog.outDebug("Auctionhouse search (GUID: %u TypeId: %u)", , list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u",
// GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid)), listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable);
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
WorldPacket data ( SMSG_AUCTION_LIST_RESULT , ( 4 + 4 + 4 ));
2009-02-09 22:08:06 -06:00
uint32 count = 0 ;
uint32 totalcount = 0 ;
2008-10-02 16:23:55 -05:00
data << ( uint32 ) 0 ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// converting string that we try to find to lower case
std :: wstring wsearchedname ;
2009-09-22 20:40:34 -04:00
if ( ! Utf8toWStr ( searchedname , wsearchedname ))
2008-10-02 16:23:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
wstrToLower ( wsearchedname );
2009-10-17 15:51:44 -07:00
2009-02-13 19:50:20 -06:00
auctionHouse -> BuildListAuctionItems ( data , _player ,
wsearchedname , listfrom , levelmin , levelmax , usable ,
auctionSlotID , auctionMainCategory , auctionSubCategory , quality ,
count , totalcount );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
data . put < uint32 > ( 0 , count );
data << ( uint32 ) totalcount ;
data << ( uint32 ) 300 ; // unk 2.3.0 const?
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2009-09-22 20:40:34 -04:00
void WorldSession :: HandleAuctionListPendingSales ( WorldPacket & recv_data )
2008-12-24 09:58:26 -06:00
{
sLog . outDebug ( "CMSG_AUCTION_LIST_PENDING_SALES" );
recv_data . hexlike ();
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
WorldPacket data ( SMSG_AUCTION_LIST_PENDING_SALES , 4 );
data << uint32 ( count ); // count
2009-09-22 20:40:34 -04:00
/*for (uint32 i = 0; i < count; ++i)
2008-12-24 09:58:26 -06:00
{
data << ""; // string
data << ""; // string
data << uint32(0);
data << uint32(0);
data << float(0);
}*/
SendPacket ( & data );
}