2010-10-07 15:35:36 +02:00
/*
2012-01-01 00:32:13 +01:00
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02: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, see <http://www.gnu.org/licenses/>.
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 "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"
2011-09-08 15:11:55 +02:00
#include "AccountMgr.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
2011-06-12 01:47:45 +02:00
Creature * unit = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
2008-10-02 16:23:55 -05:00
if ( ! unit )
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-02-03 19:02:17 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_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-12-23 23:25:44 +01:00
if ( GetPlayer () -> getLevel () < sWorld -> getIntConfig ( CONFIG_AUCTION_LEVEL_REQ ))
2010-03-09 12:58:48 +01:00
{
2010-12-23 23:25:44 +01:00
SendNotification ( GetTrinityString ( LANG_AUCTION_REQ ), sWorld -> getIntConfig ( CONFIG_AUCTION_LEVEL_REQ ));
2010-03-09 12:58:48 +01:00
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
{
2012-01-14 19:40:13 -02:00
WorldPacket data ( SMSG_AUCTION_OWNER_NOTIFICATION , ( 8 * 4 ));
data << uint32 ( auction -> Id );
data << uint32 ( auction -> bid );
data << uint32 ( 0 ); //unk
data << uint64 ( 0 ); //unk (bidder guid?)
data << uint32 ( auction -> item_template );
data << uint32 ( 0 ); //unk
data << float ( 0 ); //unk (time?)
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 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
{
2012-02-14 20:12:23 -05:00
uint64 auctioneer ;
uint32 itemsCount , etime , bid , buyout ;
2009-12-19 10:29:12 +01:00
recv_data >> auctioneer ;
2012-02-14 20:12:23 -05:00
recv_data >> itemsCount ;
uint64 itemGUIDs [ MAX_AUCTION_ITEMS ]; // 160 slot = 4x 36 slot bag + backpack 16 slot
uint32 count [ MAX_AUCTION_ITEMS ];
for ( uint32 i = 0 ; i < itemsCount ; ++ i )
{
recv_data >> itemGUIDs [ i ];
recv_data >> count [ i ];
if ( ! itemGUIDs [ i ] || ! count [ i ] || count [ i ] > 1000 )
return ;
}
2009-12-19 10:29:12 +01:00
recv_data >> bid ;
recv_data >> buyout ;
recv_data >> etime ;
2012-02-14 20:12:23 -05:00
if ( ! bid || ! etime )
return ;
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( auctioneer , UNIT_NPC_FLAG_AUCTIONEER );
if ( ! creature )
2008-10-02 16:23:55 -05:00
{
2012-02-14 20:12:23 -05:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him." , GUID_LOPART ( auctioneer ));
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
AuctionHouseEntry const * auctionHouseEntry = AuctionHouseMgr :: GetAuctionHouseEntry ( creature -> getFaction ());
2009-09-22 20:40:34 -04:00
if ( ! auctionHouseEntry )
2009-02-13 19:50:20 -06:00
{
2012-02-14 20:12:23 -05:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction." , GUID_LOPART ( auctioneer ));
return ;
}
if ( itemsCount > MAX_AUCTION_ITEMS )
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_INTERNAL_ERROR );
2009-02-13 19:50:20 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
etime *= MINUTE ;
2009-10-17 15:51:44 -07:00
2012-02-14 20:12:23 -05:00
switch ( etime )
2008-10-02 16:23:55 -05:00
{
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
2012-02-14 20:12:23 -05: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
2012-02-14 20:12:23 -05:00
Item * items [ MAX_AUCTION_ITEMS ];
2009-10-17 15:51:44 -07:00
2012-02-14 20:12:23 -05:00
uint32 finalCount = 0 ;
2009-10-17 15:51:44 -07:00
2012-02-14 20:12:23 -05:00
for ( uint32 i = 0 ; i < itemsCount ; ++ i )
2008-10-02 16:23:55 -05:00
{
2012-02-14 20:12:23 -05:00
Item * item = _player -> GetItemByGuid ( itemGUIDs [ i ]);
if ( ! item )
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_ITEM_NOT_FOUND );
return ;
}
if ( sAuctionMgr -> GetAItem ( item -> GetGUIDLow ()) || ! item -> CanBeTraded () || item -> IsNotEmptyBag () ||
item -> GetTemplate () -> Flags & ITEM_PROTO_FLAG_CONJURED || item -> GetUInt32Value ( ITEM_FIELD_DURATION ) ||
item -> GetCount () < count [ i ])
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_INTERNAL_ERROR );
return ;
}
items [ i ] = item ;
finalCount += count [ i ];
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2012-02-14 20:12:23 -05:00
if ( ! finalCount )
2010-10-09 17:36:53 +02:00
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_INTERNAL_ERROR );
return ;
}
2012-02-14 20:12:23 -05:00
for ( uint32 i = 0 ; i < itemsCount ; ++ i )
2008-10-02 16:23:55 -05:00
{
2012-02-14 20:12:23 -05:00
Item * item = items [ i ];
if ( item -> GetMaxStackCount () < finalCount )
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_INTERNAL_ERROR );
return ;
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2012-02-14 20:12:23 -05:00
for ( uint32 i = 0 ; i < itemsCount ; ++ i )
2008-10-02 16:23:55 -05:00
{
2012-02-14 20:12:23 -05:00
Item * item = items [ i ];
2009-10-17 15:51:44 -07:00
2012-02-14 20:12:23 -05:00
uint32 auctionTime = uint32 ( etime * sWorld -> getRate ( RATE_AUCTION_TIME ));
AuctionHouseObject * auctionHouse = sAuctionMgr -> GetAuctionsMap ( creature -> getFaction ());
uint32 deposit = sAuctionMgr -> GetAuctionDeposit ( auctionHouseEntry , etime , item , finalCount );
if ( ! _player -> HasEnoughMoney ( deposit ))
{
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_NOT_ENOUGHT_MONEY );
return ;
}
_player -> ModifyMoney ( - int32 ( deposit ));
AuctionEntry * AH = new AuctionEntry ;
AH -> Id = sObjectMgr -> GenerateAuctionID ();
if ( sWorld -> getBoolConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION ))
AH -> auctioneer = 23442 ;
else
AH -> auctioneer = GUID_LOPART ( auctioneer );
if ( itemsCount == 1 && item -> GetCount () == count [ i ])
{
if ( GetSecurity () > SEC_PLAYER && sWorld -> getBoolConfig ( CONFIG_GM_LOG_TRADE ))
{
sLog -> outCommand ( GetAccountId (), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)" ,
GetPlayerName (), GetAccountId (), item -> GetTemplate () -> Name1 . c_str (), item -> GetEntry (), item -> GetCount ());
}
AH -> item_guidlow = item -> GetGUIDLow ();
AH -> item_template = item -> GetEntry ();
AH -> owner = _player -> GetGUIDLow ();
AH -> startbid = bid ;
AH -> bidder = 0 ;
AH -> bid = 0 ;
AH -> buyout = buyout ;
AH -> expire_time = time ( NULL ) + auctionTime ;
AH -> deposit = deposit ;
AH -> auctionHouseEntry = auctionHouseEntry ;
sLog -> outDetail ( "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u" , _player -> GetName (), _player -> GetGUIDLow (), item -> GetTemplate () -> Name1 . c_str (), item -> GetEntry (), item -> GetGUIDLow (), AH -> auctioneer , item -> GetCount (), bid , buyout , auctionTime , AH -> GetHouseId ());
sAuctionMgr -> AddAItem ( item );
auctionHouse -> AddAuction ( AH );
_player -> MoveItemFromInventory ( item -> GetBagSlot (), item -> GetSlot (), true );
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
item -> DeleteFromInventoryDB ( trans );
item -> SaveToDB ( trans );
AH -> SaveToDB ( trans );
_player -> SaveInventoryAndGoldToDB ( trans );
CharacterDatabase . CommitTransaction ( trans );
SendAuctionCommandResult ( AH -> Id , AUCTION_SELL_ITEM , AUCTION_OK );
GetPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION , 1 );
return ;
}
else
{
Item * newItem = item -> CloneItem ( finalCount , _player );
if ( ! newItem )
{
sLog -> outError ( "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u" , item -> GetEntry ());
SendAuctionCommandResult ( 0 , AUCTION_SELL_ITEM , AUCTION_INTERNAL_ERROR );
return ;
}
if ( GetSecurity () > SEC_PLAYER && sWorld -> getBoolConfig ( CONFIG_GM_LOG_TRADE ))
{
sLog -> outCommand ( GetAccountId (), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)" ,
GetPlayerName (), GetAccountId (), newItem -> GetTemplate () -> Name1 . c_str (), newItem -> GetEntry (), newItem -> GetCount ());
}
AH -> item_guidlow = newItem -> GetGUIDLow ();
AH -> item_template = newItem -> GetEntry ();
AH -> owner = _player -> GetGUIDLow ();
AH -> startbid = bid ;
AH -> bidder = 0 ;
AH -> bid = 0 ;
AH -> buyout = buyout ;
AH -> expire_time = time ( NULL ) + auctionTime ;
AH -> deposit = deposit ;
AH -> auctionHouseEntry = auctionHouseEntry ;
sLog -> outDetail ( "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u" , _player -> GetName (), _player -> GetGUIDLow (), newItem -> GetTemplate () -> Name1 . c_str (), newItem -> GetEntry (), newItem -> GetGUIDLow (), AH -> auctioneer , newItem -> GetCount (), bid , buyout , auctionTime , AH -> GetHouseId ());
sAuctionMgr -> AddAItem ( newItem );
auctionHouse -> AddAuction ( AH );
for ( uint32 i = 0 ; i < itemsCount ; ++ i )
{
Item * item = items [ i ];
if ( item -> GetCount () == count [ i ])
{
_player -> MoveItemFromInventory ( item -> GetBagSlot (), item -> GetSlot (), true );
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
item -> DeleteFromInventoryDB ( trans );
item -> SaveToDB ( trans );
CharacterDatabase . CommitTransaction ( trans );
}
else
{
item -> SetCount ( item -> GetCount () - count [ i ]);
item -> SetState ( ITEM_CHANGED , _player );
_player -> ItemRemovedQuestCheck ( item -> GetEntry (), count [ i ]);
item -> SendUpdateToPlayer ( _player );
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
item -> SaveToDB ( trans );
CharacterDatabase . CommitTransaction ( trans );
}
}
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
AH -> SaveToDB ( trans );
_player -> SaveInventoryAndGoldToDB ( trans );
CharacterDatabase . CommitTransaction ( trans );
SendAuctionCommandResult ( AH -> Id , AUCTION_SELL_ITEM , AUCTION_OK );
GetPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION , 1 );
return ;
}
}
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
{
2011-12-10 20:05:51 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_AUCTION_PLACE_BID" );
2011-12-10 16:26:04 +01:00
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
2011-10-07 11:08:09 -05:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( auctioneer , UNIT_NPC_FLAG_AUCTIONEER );
if ( ! creature )
2008-10-02 16:23:55 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-02-03 19:02:17 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
AuctionHouseObject * auctionHouse = sAuctionMgr -> GetAuctionsMap ( creature -> getFaction ());
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
AuctionEntry * auction = auctionHouse -> GetAuction ( auctionId );
2011-11-07 11:18:00 -06:00
Player * player = GetPlayer ();
2009-10-17 15:51:44 -07:00
2011-11-07 11:18:00 -06:00
if ( ! auction || auction -> owner == player -> 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)
2011-07-27 12:14:27 +02:00
Player * auction_owner = ObjectAccessor :: FindPlayer ( MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER ));
2011-11-07 11:18:00 -06:00
if ( ! auction_owner && sObjectMgr -> GetPlayerAccountIdByGUID ( MAKE_NEW_GUID ( auction -> owner , 0 , HIGHGUID_PLAYER )) == player -> 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
2011-11-07 11:18:00 -06:00
if ( ! player -> HasEnoughMoney ( price ))
2008-10-02 16:23:55 -05:00
{
//you don't have enought money!, client tests!
//SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
return ;
}
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
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 )
{
2011-11-07 11:18:00 -06:00
if ( auction -> bidder == player -> GetGUIDLow ())
player -> ModifyMoney ( - int32 ( price - auction -> bid ));
2008-10-02 16:23:55 -05:00
else
{
// mail to last bidder and return money
2010-12-22 21:25:23 +01:00
sAuctionMgr -> SendAuctionOutbiddedMail ( auction , price , GetPlayer (), trans );
2011-11-07 11:18:00 -06:00
player -> ModifyMoney ( - int32 ( price ));
2008-10-02 16:23:55 -05:00
}
}
else
2011-11-07 11:18:00 -06:00
player -> ModifyMoney ( - int32 ( price ));
2009-11-19 03:55:15 -08:00
2011-11-07 11:18:00 -06:00
auction -> bidder = player -> GetGUIDLow ();
2008-10-02 16:23:55 -05:00
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
2011-04-29 20:47:02 +02:00
trans -> PAppend ( "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:
2011-11-07 11:18:00 -06:00
if ( player -> GetGUIDLow () == auction -> bidder )
player -> ModifyMoney ( - int32 ( auction -> buyout - auction -> bid ));
2008-10-02 16:23:55 -05:00
else
{
2011-11-07 11:18:00 -06:00
player -> ModifyMoney ( - int32 ( auction -> buyout ));
2009-09-22 20:40:34 -04:00
if ( auction -> bidder ) //buyout for bidded auction ..
2010-12-22 21:25:23 +01:00
sAuctionMgr -> SendAuctionOutbiddedMail ( auction , auction -> buyout , GetPlayer (), trans );
2008-10-02 16:23:55 -05:00
}
2011-11-07 11:18:00 -06:00
auction -> bidder = player -> GetGUIDLow ();
2008-10-02 16:23:55 -05:00
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
2010-08-21 03:19:25 +02:00
//- Mails must be under transaction control too to prevent data loss
2010-12-22 21:25:23 +01:00
sAuctionMgr -> SendAuctionSalePendingMail ( auction , trans );
sAuctionMgr -> SendAuctionSuccessfulMail ( auction , trans );
sAuctionMgr -> SendAuctionWonMail ( auction , trans );
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
2010-08-21 03:19:25 +02:00
auction -> DeleteFromDB ( trans );
2010-09-12 01:40:27 +02:00
2009-09-22 20:40:34 -04:00
uint32 item_template = auction -> item_template ;
2010-12-22 21:25:23 +01:00
sAuctionMgr -> RemoveAItem ( auction -> item_guidlow );
2009-09-22 20:40:34 -04:00
auctionHouse -> RemoveAuction ( auction , item_template );
2008-10-02 16:23:55 -05:00
}
2011-11-07 11:18:00 -06:00
player -> SaveInventoryAndGoldToDB ( trans );
2010-08-21 03:19:25 +02:00
CharacterDatabase . CommitTransaction ( trans );
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 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
{
2011-12-10 20:05:51 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_AUCTION_REMOVE_ITEM" );
2011-12-10 16:26:04 +01:00
2008-10-02 16:23:55 -05:00
uint64 auctioneer ;
uint32 auctionId ;
recv_data >> auctioneer ;
recv_data >> auctionId ;
2010-12-23 23:25:44 +01:00
//sLog->outDebug("Cancel AUCTION AuctionID: %u", auctionId);
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( auctioneer , UNIT_NPC_FLAG_AUCTIONEER );
if ( ! creature )
2008-10-02 16:23:55 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-02-03 19:02:17 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
AuctionHouseObject * auctionHouse = sAuctionMgr -> GetAuctionsMap ( creature -> getFaction ());
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
AuctionEntry * auction = auctionHouse -> GetAuction ( auctionId );
2011-11-07 11:18:00 -06:00
Player * player = GetPlayer ();
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2011-11-07 11:18:00 -06:00
if ( auction && auction -> owner == player -> GetGUIDLow ())
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
Item * pItem = sAuctionMgr -> 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 ();
2011-11-07 11:18:00 -06:00
if ( ! player -> HasEnoughMoney ( 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..
2010-12-22 21:25:23 +01:00
sAuctionMgr -> SendAuctionCancelledToBidderMail ( auction , trans );
2011-11-07 11:18:00 -06:00
player -> 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 )
2011-11-07 11:18:00 -06:00
. SendMailTo ( trans , player , auction , MAIL_CHECK_MASK_COPIED );
2008-10-02 16:23:55 -05:00
}
else
{
2010-12-23 23:25:44 +01:00
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
2011-11-07 11:18:00 -06:00
sLog -> outError ( "CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL" , player -> 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
2010-09-12 01:40:27 +02:00
2011-11-07 11:18:00 -06:00
player -> SaveInventoryAndGoldToDB ( trans );
2010-08-21 03:19:25 +02:00
auction -> DeleteFromDB ( trans );
CharacterDatabase . CommitTransaction ( trans );
2009-09-22 20:40:34 -04:00
uint32 item_template = auction -> item_template ;
2010-12-22 21:25:23 +01:00
sAuctionMgr -> RemoveAItem ( auction -> item_guidlow );
2009-09-22 20:40:34 -04:00
auctionHouse -> RemoveAuction ( auction , item_template );
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
{
2011-12-10 20:05:51 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_AUCTION_LIST_BIDDER_ITEMS" );
2011-12-10 16:26:04 +01:00
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
{
2011-04-29 20:47:02 +02: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
2011-10-07 11:08:09 -05:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
if ( ! creature )
2008-10-02 16:23:55 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him." , uint32 ( GUID_LOPART ( guid )));
2011-12-10 13:42:22 +01:00
recv_data . rfinish ();
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
2012-02-03 19:02:17 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
AuctionHouseObject * auctionHouse = sAuctionMgr -> GetAuctionsMap ( creature -> 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 ));
2011-11-07 11:18:00 -06:00
Player * player = GetPlayer ();
2008-10-02 16:23:55 -05:00
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 ;
2011-09-15 14:08:17 +02:00
AuctionEntry * auction = auctionHouse -> GetAuction ( outbiddedAuctionId );
2009-09-22 20:40:34 -04:00
if ( auction && auction -> BuildAuctionInfo ( data ))
2008-10-02 16:23:55 -05:00
{
++ totalcount ;
++ count ;
}
}
2009-10-17 15:51:44 -07:00
2011-11-07 11:18:00 -06:00
auctionHouse -> BuildListBidderItems ( data , player , 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
{
2011-12-10 20:05:51 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_AUCTION_LIST_OWNER_ITEMS" );
2011-12-10 16:26:04 +01:00
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
2011-10-07 11:08:09 -05:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
if ( ! creature )
2008-10-02 16:23:55 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-02-03 19:02:17 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
AuctionHouseObject * auctionHouse = sAuctionMgr -> GetAuctionsMap ( creature -> 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
2011-04-29 20:47:02 +02: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
{
2011-12-10 20:05:51 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_AUCTION_LIST_ITEMS" );
2011-12-10 16:26:04 +01: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
2010-07-31 04:31:21 +02:00
recv_data . read_skip < uint8 > (); // unk
// this block looks like it uses some lame byte packing or similar...
uint8 unkCnt ;
recv_data >> unkCnt ;
for ( uint8 i = 0 ; i < unkCnt ; i ++ )
{
recv_data . read_skip < uint8 > ();
recv_data . read_skip < uint8 > ();
}
2010-05-25 16:15:22 +02:00
2011-10-07 11:08:09 -05:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( guid , UNIT_NPC_FLAG_AUCTIONEER );
if ( ! creature )
2008-10-02 16:23:55 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-02-03 19:02:17 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
AuctionHouseObject * auctionHouse = sAuctionMgr -> GetAuctionsMap ( creature -> getFaction ());
2009-10-17 15:51:44 -07:00
2011-09-29 12:43:05 +02: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",
2011-04-29 20:47:02 +02:00
// 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 ;
2011-04-29 20:47:02 +02: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
2011-04-29 20:47:02 +02:00
auctionHouse -> BuildListAuctionItems ( data , _player ,
2009-02-13 19:50:20 -06:00
wsearchedname , listfrom , levelmin , levelmax , usable ,
auctionSlotID , auctionMainCategory , auctionSubCategory , quality ,
2011-04-29 20:47:02 +02:00
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
{
2011-12-10 20:05:51 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_AUCTION_LIST_PENDING_SALES" );
2010-05-25 16:15:22 +02:00
recv_data . read_skip < uint64 > ();
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 );
}