root/trunk/src/game/AuctionHouse.cpp @ 229

Revision 229, 29.0 kB (checked in by yumileroy, 17 years ago)

[svn] *** Source: MaNGOS ***
* Fixed build extractor at Windows Vista. Author: Vladimir
* Fixed comment text and code indentifiers spelling. Author: Vladimir & Paradox.
* Access cached member lists in guild handlers instead of querying the DB. Author: Hunuza
* Small fixes in send/received packet and simple code cleanup also. Author: Vladimir
* Not output error at loading empty character_ticket table. Author: Vladimir
* Not reset display model at shapeshift aura remove if it not set at apply. Author: Arthorius
* Applied props to few files.

Original author: visagalis
Date: 2008-11-14 16:28:45-06:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "WorldPacket.h"
22#include "WorldSession.h"
23#include "Opcodes.h"
24#include "Log.h"
25#include "World.h"
26#include "ObjectMgr.h"
27#include "Player.h"
28#include "UpdateMask.h"
29#include "AuctionHouseObject.h"
30#include "Util.h"
31
32//please DO NOT use iterator++, because it is slower than ++iterator!!!
33//post-incrementation is always slower than pre-incrementation !
34
35//void called when player click on auctioneer npc
36void WorldSession::HandleAuctionHelloOpcode( WorldPacket & recv_data )
37{
38    CHECK_PACKET_SIZE(recv_data,8);
39
40    uint64 guid;                                            //NPC guid
41    recv_data >> guid;
42
43    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
44    if (!unit)
45    {
46        sLog.outDebug( "WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
47        return;
48    }
49
50    // remove fake death
51    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
52        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
53
54    SendAuctionHello(guid, unit);
55}
56
57static uint8 AuctioneerFactionToLocation(uint32 faction)
58{
59    if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
60        return 7;                                           // neutral
61
62    FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(faction);
63    if(!u_entry)
64        return 7;                                           // neutral
65
66    if(u_entry->ourMask & FACTION_MASK_ALLIANCE)
67        return 2;
68    else if(u_entry->ourMask & FACTION_MASK_HORDE)
69        return 6;
70    else
71        return 7;
72}
73
74//this void causes that auction window is opened
75void WorldSession::SendAuctionHello( uint64 guid, Creature* unit )
76{
77    WorldPacket data( MSG_AUCTION_HELLO, 12 );
78    data << (uint64) guid;
79    data << (uint32) AuctioneerFactionToLocation(unit->getFaction());
80    SendPacket( &data );
81}
82
83//this function inserts to WorldPacket auction's data
84bool WorldSession::SendAuctionInfo(WorldPacket & data, AuctionEntry* auction)
85{
86    Item *pItem = objmgr.GetAItem(auction->item_guidlow);
87    if (!pItem)
88    {
89        sLog.outError("auction to item, that doesn't exist !!!!");
90        return false;
91    }
92    data << auction->Id;
93    data << pItem->GetUInt32Value(OBJECT_FIELD_ENTRY);
94
95    for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; i++)
96    {
97        data << (uint32) pItem->GetEnchantmentId(EnchantmentSlot(i));
98        data << (uint32) pItem->GetEnchantmentDuration(EnchantmentSlot(i));
99        data << (uint32) pItem->GetEnchantmentCharges(EnchantmentSlot(i));
100    }
101
102    data << (uint32) pItem->GetItemRandomPropertyId();      //random item property id
103    data << (uint32) pItem->GetItemSuffixFactor();          //SuffixFactor
104    data << (uint32) pItem->GetCount();                     //item->count
105    data << (uint32) pItem->GetSpellCharges();              //item->charge FFFFFFF
106    data << (uint32) 0;                                     //Unknown
107    data << (uint64) auction->owner;                        //Auction->owner
108    data << (uint32) auction->startbid;                     //Auction->startbid (not sure if useful)
109    data << (uint32) ((auction->bid)? objmgr.GetAuctionOutBid(auction->bid) : 0);
110                                                            //minimal outbid
111    data << (uint32) auction->buyout;                       //auction->buyout
112    data << (uint32) (auction->time - time(NULL)) * 1000;   //time left
113    data << (uint64) auction->bidder;                       //auction->bidder current
114    data << (uint32) auction->bid;                          //current bid
115    return true;
116}
117
118//call this method when player bids, creates, or deletes auction
119void WorldSession::SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError )
120{
121    WorldPacket data( SMSG_AUCTION_COMMAND_RESULT, 16 );
122    data << auctionId;
123    data << Action;
124    data << ErrorCode;
125    if ( !ErrorCode && Action )
126        data << bidError;                                   //when bid, then send 0, once...
127    SendPacket(&data);
128}
129
130//this function sends notification, if bidder is online
131void WorldSession::SendAuctionBidderNotification( uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template)
132{
133    WorldPacket data(SMSG_AUCTION_BIDDER_NOTIFICATION, (8*4));
134    data << location;
135    data << auctionId;
136    data << (uint64) bidder;
137    data << bidSum;
138    data << (uint32) diff;
139    data << item_template;
140    data << (uint32) 0;
141    SendPacket(&data);
142}
143
144//this void causes on client to display: "Your auction sold"
145void WorldSession::SendAuctionOwnerNotification( AuctionEntry* auction)
146{
147    WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, (7*4));
148    data << auction->Id;
149    data << auction->bid;
150    data << (uint32) 0;                                     //unk
151    data << (uint32) 0;                                     //unk
152    data << (uint32) 0;                                     //unk
153    data << auction->item_template;
154    data << (uint32) 0;                                     //unk
155    SendPacket(&data);
156}
157
158//this function sends mail to old bidder
159void WorldSession::SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPrice)
160{
161    uint64 oldBidder_guid = MAKE_NEW_GUID(auction->bidder,0, HIGHGUID_PLAYER);
162    Player *oldBidder = objmgr.GetPlayer(oldBidder_guid);
163
164    uint32 oldBidder_accId = 0;
165    if(!oldBidder)
166        oldBidder_accId = objmgr.GetPlayerAccountIdByGUID(oldBidder_guid);
167
168    // old bidder exist
169    if(oldBidder || oldBidder_accId)
170    {
171        std::ostringstream msgAuctionOutbiddedSubject;
172        msgAuctionOutbiddedSubject << auction->item_template << ":0:" << AUCTION_OUTBIDDED;
173
174        if (oldBidder)
175            oldBidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, _player->GetGUID(), newPrice, objmgr.GetAuctionOutBid(auction->bid), auction->item_template);
176
177        WorldSession::SendMailTo(oldBidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionOutbiddedSubject.str(), 0, NULL, auction->bid, 0, MAIL_CHECK_MASK_NONE);
178    }
179}
180
181//this function sends mail, when auction is canceled to old bidder
182void WorldSession::SendAuctionCancelledToBidderMail( AuctionEntry* auction )
183{
184    uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
185    Player *bidder = objmgr.GetPlayer(bidder_guid);
186
187    uint32 bidder_accId = 0;
188    if(!bidder)
189        bidder_accId = objmgr.GetPlayerAccountIdByGUID(bidder_guid);
190
191    // bidder exist
192    if(bidder || bidder_accId)
193    {
194        std::ostringstream msgAuctionCancelledSubject;
195        msgAuctionCancelledSubject << auction->item_template << ":0:" << AUCTION_CANCELLED_TO_BIDDER;
196
197        WorldSession::SendMailTo(bidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionCancelledSubject.str(), 0, NULL, auction->bid, 0, MAIL_CHECK_MASK_NONE);
198    }
199}
200
201//this void creates new auction and adds auction to some auctionhouse
202void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data )
203{
204    CHECK_PACKET_SIZE(recv_data,8+8+4+4+4);
205
206    uint64 auctioneer, item;
207    uint32 etime, bid, buyout;
208    recv_data >> auctioneer >> item;
209    recv_data >> bid >> buyout >> etime;
210    Player *pl = GetPlayer();
211
212    if (!item || !bid || !etime)
213        return;                                             //check for cheaters
214
215    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
216    if (!pCreature)
217    {
218        sLog.outDebug( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
219        return;
220    }
221
222    // client send time in minutes, convert to common used sec time
223    etime *= MINUTE;
224
225    // client understand only 3 auction time
226    switch(etime)
227    {
228        case 1*MIN_AUCTION_TIME:
229        case 2*MIN_AUCTION_TIME:
230        case 4*MIN_AUCTION_TIME:
231            break;
232        default:
233            return;
234    }
235
236    // remove fake death
237    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
238        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
239
240    Item *it = pl->GetItemByGuid( item );
241    //do not allow to sell already auctioned items
242    if(objmgr.GetAItem(GUID_LOPART(item)))
243    {
244        sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item));
245        SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
246        return;
247    }
248    // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to auction)
249    if(!it)
250    {
251        SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND);
252        return;
253    }
254
255    if(!it->CanBeTraded())
256    {
257        SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
258        return;
259    }
260
261    if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION))
262    {
263        SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
264        return;
265    }
266
267    uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
268    AuctionHouseObject * mAuctions;
269    mAuctions = objmgr.GetAuctionsMap( location );
270
271    //we have to take deposit :
272    uint32 deposit = objmgr.GetAuctionDeposit( location, etime, it );
273    if ( pl->GetMoney() < deposit )
274    {
275        SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY);
276        return;
277    }
278
279    if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
280    {
281        sLog.outCommand("GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
282            GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount());
283    }
284
285    pl->ModifyMoney( -int32(deposit) );
286
287    uint32 auction_time = uint32(etime * sWorld.getRate(RATE_AUCTION_TIME));
288
289    AuctionEntry *AH = new AuctionEntry;
290    AH->Id = objmgr.GenerateAuctionID();
291    AH->auctioneer = GUID_LOPART(auctioneer);
292    AH->item_guidlow = GUID_LOPART(item);
293    AH->item_template = it->GetEntry();
294    AH->owner = pl->GetGUIDLow();
295    AH->startbid = bid;
296    AH->bidder = 0;
297    AH->bid = 0;
298    AH->buyout = buyout;
299    AH->time = time(NULL) + auction_time;
300    AH->deposit = deposit;
301    AH->location = location;
302
303    sLog.outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in location: %u", GUID_LOPART(item), GUID_LOPART(auctioneer), bid, buyout, auction_time, location);
304    mAuctions->AddAuction(AH);
305
306    objmgr.AddAItem(it);
307    pl->MoveItemFromInventory( it->GetBagSlot(), it->GetSlot(), true);
308
309    CharacterDatabase.BeginTransaction();
310    it->DeleteFromInventoryDB();
311    it->SaveToDB();                                         // recursive and not have transaction guard into self, not in inventiory and can be save standalone
312    CharacterDatabase.PExecute("INSERT INTO auctionhouse (id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location) "
313        "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u')",
314        AH->Id, AH->auctioneer, AH->item_guidlow, AH->item_template, AH->owner, AH->buyout, (uint64)AH->time, AH->bidder, AH->bid, AH->startbid, AH->deposit, AH->location);
315    pl->SaveInventoryAndGoldToDB();
316    CharacterDatabase.CommitTransaction();
317
318    SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK);
319}
320
321//this function is called when client bids or buys out auction
322void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
323{
324    CHECK_PACKET_SIZE(recv_data,8+4+4);
325
326    uint64 auctioneer;
327    uint32 auctionId;
328    uint32 price;
329    recv_data >> auctioneer;
330    recv_data >> auctionId >> price;
331
332    if (!auctionId || !price)
333        return;                                             //check for cheaters
334
335    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
336    if (!pCreature)
337    {
338        sLog.outDebug( "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
339        return;
340    }
341
342    // remove fake death
343    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
344        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
345
346    uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
347
348    AuctionHouseObject * mAuctions;
349    mAuctions = objmgr.GetAuctionsMap( location );
350
351    AuctionEntry *auction = mAuctions->GetAuction(auctionId);
352    Player *pl = GetPlayer();
353
354    if( !auction || auction->owner == pl->GetGUIDLow() )
355    {
356        //you cannot bid your own auction:
357        SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR );
358        return;
359    }
360
361    // impossible have online own another character (use this for speedup check in case online owner)
362    Player* auction_owner = objmgr.GetPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER));
363    if( !auction_owner && objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == pl->GetSession()->GetAccountId())
364    {
365        //you cannot bid your another character auction:
366        SendAuctionCommandResult( 0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR );
367        return;
368    }
369
370    if (price < (auction->bid + objmgr.GetAuctionOutBid(auction->bid)))
371    {
372        //auction has already higher bid, client tests it!
373        //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
374        return;
375    }
376
377    if (price > pl->GetMoney())
378    {
379        //you don't have enought money!, client tests!
380        //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
381        return;
382    }
383
384    if ((price < auction->buyout) || (auction->buyout == 0))
385    {
386        if (auction->bidder > 0)
387        {
388            if ( auction->bidder == pl->GetGUIDLow() )
389            {
390                pl->ModifyMoney( -int32(price - auction->bid));
391            }
392            else
393            {
394                // mail to last bidder and return money
395                SendAuctionOutbiddedMail( auction , price );
396                pl->ModifyMoney( -int32(price) );
397            }
398        }
399        else
400        {
401            pl->ModifyMoney( -int32(price) );
402        }
403        auction->bidder = pl->GetGUIDLow();
404        auction->bid = price;
405
406        // after this update we should save player's money ...
407        CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id);
408
409        SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0 );
410    }
411    else
412    {
413        //buyout:
414        if (pl->GetGUIDLow() == auction->bidder )
415        {
416            pl->ModifyMoney(-int32(auction->buyout - auction->bid));
417        }
418        else
419        {
420            pl->ModifyMoney(-int32(auction->buyout));
421            if ( auction->bidder )                          //buyout for bidded auction ..
422            {
423                SendAuctionOutbiddedMail( auction, auction->buyout );
424            }
425        }
426        auction->bidder = pl->GetGUIDLow();
427        auction->bid = auction->buyout;
428
429        objmgr.SendAuctionSalePendingMail( auction );
430        objmgr.SendAuctionSuccessfulMail( auction );
431        objmgr.SendAuctionWonMail( auction );
432
433        SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK);
434
435        objmgr.RemoveAItem(auction->item_guidlow);
436        mAuctions->RemoveAuction(auction->Id);
437        CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",auction->Id);
438
439        delete auction;
440    }
441    CharacterDatabase.BeginTransaction();
442    pl->SaveInventoryAndGoldToDB();
443    CharacterDatabase.CommitTransaction();
444}
445
446//this void is called when auction_owner cancels his auction
447void WorldSession::HandleAuctionRemoveItem( WorldPacket & recv_data )
448{
449    CHECK_PACKET_SIZE(recv_data,8+4);
450
451    uint64 auctioneer;
452    uint32 auctionId;
453    recv_data >> auctioneer;
454    recv_data >> auctionId;
455    //sLog.outDebug( "Cancel AUCTION AuctionID: %u", auctionId);
456
457    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
458    if (!pCreature)
459    {
460        sLog.outDebug( "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
461        return;
462    }
463
464    // remove fake death
465    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
466        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
467
468    uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
469
470    AuctionHouseObject * mAuctions;
471    mAuctions = objmgr.GetAuctionsMap( location );
472
473    AuctionEntry *auction = mAuctions->GetAuction(auctionId);
474    Player *pl = GetPlayer();
475
476    if (auction && auction->owner == pl->GetGUIDLow())
477    {
478        Item *pItem = objmgr.GetAItem(auction->item_guidlow);
479        if (pItem)
480        {
481            if (auction->bidder > 0)                        // If we have a bidder, we have to send him the money he paid
482            {
483                uint32 auctionCut = objmgr.GetAuctionCut( auction->location, auction->bid);
484                if ( pl->GetMoney() < auctionCut )          //player doesn't have enough money, maybe message needed
485                    return;
486                //some auctionBidderNotification would be needed, but don't know that parts..
487                SendAuctionCancelledToBidderMail( auction );
488                pl->ModifyMoney( -int32(auctionCut) );
489            }
490            // Return the item by mail
491            std::ostringstream msgAuctionCanceledOwner;
492            msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED;
493
494            MailItemsInfo mi;
495            mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
496
497            // item will deleted or added to received mail list
498            WorldSession::SendMailTo(pl, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, pl->GetGUIDLow(), msgAuctionCanceledOwner.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
499        }
500        else
501        {
502            sLog.outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->item_guidlow);
503            SendAuctionCommandResult( 0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR );
504            return;
505        }
506    }
507    else
508    {
509        SendAuctionCommandResult( 0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR );
510        //this code isn't possible ... maybe there should be assert
511        sLog.outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", pl->GetGUIDLow(), auctionId );
512        return;
513    }
514
515    //inform player, that auction is removed
516    SendAuctionCommandResult( auction->Id, AUCTION_CANCEL, AUCTION_OK );
517    // Now remove the auction
518    CharacterDatabase.BeginTransaction();
519    CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",auction->Id);
520    pl->SaveInventoryAndGoldToDB();
521    CharacterDatabase.CommitTransaction();
522    objmgr.RemoveAItem( auction->item_guidlow );
523    mAuctions->RemoveAuction( auction->Id );
524    delete auction;
525}
526
527//called when player lists his bids
528void WorldSession::HandleAuctionListBidderItems( WorldPacket & recv_data )
529{
530    CHECK_PACKET_SIZE(recv_data,8+4+4);
531
532    uint64 guid;                                            //NPC guid
533    uint32 listfrom;                                        //page of auctions
534    uint32 outbiddedCount;                                  //count of outbidded auctions
535
536    recv_data >> guid;
537    recv_data >> listfrom;                                  // not used in fact (this list not have page control in client)
538    recv_data >> outbiddedCount;
539    if (recv_data.size() != (16 + outbiddedCount * 4 ))
540    {
541        sLog.outError("Client sent bad opcode!!! with count: %u and size : %d (mustbe: %d", outbiddedCount, recv_data.size(),(16 + outbiddedCount * 4 ));
542        outbiddedCount = 0;
543    }
544
545    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
546    if (!pCreature)
547    {
548        sLog.outDebug( "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
549        return;
550    }
551
552    // remove fake death
553    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
554        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
555
556    uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
557    AuctionHouseObject* mAuctions = objmgr.GetAuctionsMap( location );
558
559    WorldPacket data( SMSG_AUCTION_BIDDER_LIST_RESULT, (4+4+4) );
560    Player *pl = GetPlayer();
561    data << (uint32) 0;                                     //add 0 as count
562    uint32 count = 0;
563    uint32 totalcount = 0;
564    while ( outbiddedCount > 0)                             //add all data, which client requires
565    {
566        --outbiddedCount;
567        uint32 outbiddedAuctionId;
568        recv_data >> outbiddedAuctionId;
569        AuctionEntry * auction = mAuctions->GetAuction( outbiddedAuctionId );
570        if ( auction && SendAuctionInfo(data, auction))
571        {
572            ++totalcount;
573            ++count;
574        }
575    }
576    for (AuctionHouseObject::AuctionEntryMap::iterator itr = mAuctions->GetAuctionsBegin();itr != mAuctions->GetAuctionsEnd();++itr)
577    {
578        AuctionEntry *Aentry = itr->second;
579        if( Aentry && Aentry->bidder == pl->GetGUIDLow() )
580        {
581            if (SendAuctionInfo(data, itr->second))
582                ++count;
583            ++totalcount;
584        }
585    }
586    data.put<uint32>( 0, count );                           // add count to placeholder
587    data << totalcount;
588    data << (uint32)300;                                    //unk 2.3.0
589    SendPacket(&data);
590}
591
592//this void sends player info about his auctions
593void WorldSession::HandleAuctionListOwnerItems( WorldPacket & recv_data )
594{
595    CHECK_PACKET_SIZE(recv_data,8+4);
596
597    uint32 listfrom;
598    uint64 guid;
599
600    recv_data >> guid;
601    recv_data >> listfrom;                                  // not used in fact (this list not have page control in client)
602
603    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
604    if (!pCreature)
605    {
606        sLog.outDebug( "WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
607        return;
608    }
609
610    // remove fake death
611    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
612        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
613
614    uint32 location = AuctioneerFactionToLocation(pCreature->getFaction());
615
616    AuctionHouseObject* mAuctions = objmgr.GetAuctionsMap( location );
617
618    WorldPacket data( SMSG_AUCTION_OWNER_LIST_RESULT, (4+4+4) );
619    data << (uint32) 0;                                     // amount place holder
620
621    uint32 count = 0;
622    uint32 totalcount = 0;
623    for (AuctionHouseObject::AuctionEntryMap::iterator itr = mAuctions->GetAuctionsBegin();itr != mAuctions->GetAuctionsEnd();++itr)
624    {
625        AuctionEntry *Aentry = itr->second;
626        if( Aentry && Aentry->owner == _player->GetGUIDLow() )
627        {
628            if(SendAuctionInfo(data, itr->second))
629                ++count;
630            ++totalcount;
631        }
632    }
633    data.put<uint32>(0, count);
634    data << (uint32) totalcount;
635    data << (uint32) 0;
636    SendPacket(&data);
637}
638
639//this void is called when player clicks on search button
640void WorldSession::HandleAuctionListItems( WorldPacket & recv_data )
641{
642    CHECK_PACKET_SIZE(recv_data,8+4+1+1+1+4+4+4+4+1);
643
644    std::string searchedname, name;
645    uint8 levelmin, levelmax, usable, location;
646    uint32 count, totalcount, listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality;
647    uint64 guid;
648
649    recv_data >> guid;
650    recv_data >> listfrom;                                  // start, used for page control listing by 50 elements
651    recv_data >> searchedname;
652
653    // recheck with known string size
654    CHECK_PACKET_SIZE(recv_data,8+4+(searchedname.size()+1)+1+1+4+4+4+4+1);
655
656    recv_data >> levelmin >> levelmax;
657    recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory;
658    recv_data >> quality >> usable;
659
660    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
661    if (!pCreature)
662    {
663        sLog.outDebug( "WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
664        return;
665    }
666
667    // remove fake death
668    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
669        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
670
671    location = AuctioneerFactionToLocation(pCreature->getFaction());
672    AuctionHouseObject * mAuctions;
673    mAuctions = objmgr.GetAuctionsMap( location );
674
675    //sLog.outDebug("Auctionhouse search guid: " I64FMTD ", list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", guid, listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable);
676
677    WorldPacket data( SMSG_AUCTION_LIST_RESULT, (4+4+4) );
678    count = 0;
679    totalcount = 0;
680    data << (uint32) 0;
681
682    // converting string that we try to find to lower case
683    std::wstring wsearchedname;
684    if(!Utf8toWStr(searchedname,wsearchedname))
685        return;
686
687    wstrToLower(wsearchedname);
688
689    for (AuctionHouseObject::AuctionEntryMap::iterator itr = mAuctions->GetAuctionsBegin();itr != mAuctions->GetAuctionsEnd();++itr)
690    {
691        AuctionEntry *Aentry = itr->second;
692        Item *item = objmgr.GetAItem(Aentry->item_guidlow);
693        if( item )
694        {
695            ItemPrototype const *proto = item->GetProto();
696            if( proto )
697            {
698                if( auctionMainCategory == (0xffffffff) || proto->Class == auctionMainCategory )
699                {
700                    if( auctionSubCategory == (0xffffffff) || proto->SubClass == auctionSubCategory )
701                    {
702                        if( auctionSlotID == (0xffffffff) || proto->InventoryType == auctionSlotID )
703                        {
704                            if( quality == (0xffffffff) || proto->Quality == quality )
705                            {
706                                if( usable == (0x00) || _player->CanUseItem( item ) == EQUIP_ERR_OK )
707                                {
708                                    if( ( levelmin == (0x00) || proto->RequiredLevel >= levelmin ) && ( levelmax == (0x00) || proto->RequiredLevel <= levelmax ) )
709                                    {
710                                        name = proto->Name1;
711
712                                        // local name
713                                        int loc_idx = GetSessionDbLocaleIndex();
714                                        if ( loc_idx >= 0 )
715                                        {
716                                            ItemLocale const *il = objmgr.GetItemLocale(proto->ItemId);
717                                            if (il)
718                                            {
719                                                if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
720                                                    name = il->Name[loc_idx];
721                                            }
722                                        }
723
724                                        if(name.empty())
725                                            continue;
726
727                                        if( wsearchedname.empty() || Utf8FitTo(name, wsearchedname) )
728                                        {
729                                            if ((count < 50) && (totalcount >= listfrom))
730                                            {
731                                                ++count;
732                                                SendAuctionInfo( data, Aentry);
733                                            }
734                                            ++totalcount;
735                                        }
736                                    }
737                                }
738                            }
739                        }
740                    }
741                }
742            }
743        }
744    }
745    data.put<uint32>(0, count);
746    data << (uint32) totalcount;
747    data << (uint32) 300;                                   // unk 2.3.0 const?
748    SendPacket(&data);
749}
Note: See TracBrowser for help on using the browser.