root/trunk/src/game/NPCHandler.cpp @ 168

Revision 168, 26.0 kB (checked in by yumileroy, 17 years ago)

[svn] *** Source Mangos ***
*Load npc_options at server startup, use cached data at creature gossip menu init.
* Also new .reload table command added
*Implement npc_option localization support, also store in DB BoxText/BoxMoney/Coded?
* Use characters.guid instead low guid value from characters.data in charcter enum data prepering for client.
* Fixed crash at .pinfo command use from console.
* Fixed windows ad.exe build
*Creature related code and DB cleanups.
* Rename 2 creature_template fields to more clean names and related code update also.
* Use enum values instead raw values for type_flags, use halper functions instead code repeating.
* Move tamed pet creating code to new function.

** Small code changes to make things compliant with above changes.
** Another rev with big changes so test away.

Original author: KingPin?
Date: 2008-11-05 09:22:56-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 "Common.h"
22#include "Language.h"
23#include "Database/DatabaseEnv.h"
24#include "WorldPacket.h"
25#include "WorldSession.h"
26#include "Opcodes.h"
27#include "Log.h"
28#include "World.h"
29#include "ObjectMgr.h"
30#include "SpellMgr.h"
31#include "Player.h"
32#include "GossipDef.h"
33#include "SpellAuras.h"
34#include "UpdateMask.h"
35#include "ScriptCalls.h"
36#include "ObjectAccessor.h"
37#include "Creature.h"
38#include "MapManager.h"
39#include "Pet.h"
40#include "BattleGroundMgr.h"
41#include "BattleGround.h"
42#include "Guild.h"
43
44void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data )
45{
46    CHECK_PACKET_SIZE(recv_data,8);
47
48    uint64 guid;
49    recv_data >> guid;
50
51    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TABARDDESIGNER);
52    if (!unit)
53    {
54        sLog.outDebug( "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
55        return;
56    }
57
58    // remove fake death
59    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
60        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
61
62    SendTabardVendorActivate(guid);
63}
64
65void WorldSession::SendTabardVendorActivate( uint64 guid )
66{
67    WorldPacket data( MSG_TABARDVENDOR_ACTIVATE, 8 );
68    data << guid;
69    SendPacket( &data );
70}
71
72void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data )
73{
74    CHECK_PACKET_SIZE(recv_data,8);
75
76    uint64 guid;
77
78    sLog.outDebug(  "WORLD: Received CMSG_BANKER_ACTIVATE" );
79
80    recv_data >> guid;
81
82    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_BANKER);
83    if (!unit)
84    {
85        sLog.outDebug( "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
86        return;
87    }
88
89    // remove fake death
90    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
91        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
92
93    SendShowBank(guid);
94}
95
96void WorldSession::SendShowBank( uint64 guid )
97{
98    WorldPacket data( SMSG_SHOW_BANK, 8 );
99    data << guid;
100    SendPacket( &data );
101}
102
103void WorldSession::HandleTrainerListOpcode( WorldPacket & recv_data )
104{
105    CHECK_PACKET_SIZE(recv_data,8);
106
107    uint64 guid;
108
109    recv_data >> guid;
110    SendTrainerList( guid );
111}
112
113void WorldSession::SendTrainerList( uint64 guid )
114{
115    std::string str = GetTrinityString(LANG_NPC_TAINER_HELLO);
116    SendTrainerList( guid, str );
117}
118
119void WorldSession::SendTrainerList( uint64 guid,std::string strTitle )
120{
121    sLog.outDebug( "WORLD: SendTrainerList" );
122
123    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TRAINER);
124    if (!unit)
125    {
126        sLog.outDebug( "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
127        return;
128    }
129
130    // remove fake death
131    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
132        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
133
134    // trainer list loaded at check;
135    if(!unit->isCanTrainingOf(_player,true))
136        return;
137
138    CreatureInfo const *ci = unit->GetCreatureInfo();
139
140    if (!ci)
141    {
142        sLog.outDebug( "WORLD: SendTrainerList - (%u) NO CREATUREINFO! (GUID: %u)", uint32(GUID_LOPART(guid)), guid );
143        return;
144    }
145
146    TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
147    if(!trainer_spells)
148    {
149        sLog.outDebug( "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)", guid, unit->GetEntry());
150        return;
151    }
152
153    WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1);
154    data << guid;
155    data << uint32(trainer_spells->trainerType);
156
157    size_t count_pos = data.wpos();
158    data << uint32(trainer_spells->spellList.size());
159
160    // reputation discount
161    float fDiscountMod = _player->GetReputationPriceDiscount(unit);
162
163    uint32 count = 0;
164    for(TrainerSpellList::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
165    {
166        TrainerSpell const* tSpell = *itr;
167
168        if(!_player->IsSpellFitByClassAndRace(tSpell->spell))
169            continue;
170
171        ++count;
172
173        bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->spell);
174
175        SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->spell);
176
177        data << uint32(tSpell->spell);
178        data << uint8(_player->GetTrainerSpellState(tSpell));
179        data << uint32(floor(tSpell->spellcost * fDiscountMod));
180
181        data << uint32(primary_prof_first_rank ? 1 : 0);    // primary prof. learn confirmation dialog
182        data << uint32(primary_prof_first_rank ? 1 : 0);    // must be equal prev. field to have learn button in enabled state
183        data << uint8(tSpell->reqlevel);
184        data << uint32(tSpell->reqskill);
185        data << uint32(tSpell->reqskillvalue);
186        data << uint32(chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
187        data << uint32(chain_node && chain_node->prev ? chain_node->req : 0);
188        data << uint32(0);
189    }
190
191    data << strTitle;
192
193    data.put<uint32>(count_pos,count);
194    SendPacket( &data );
195}
196
197void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
198{
199    CHECK_PACKET_SIZE(recv_data,8+4);
200
201    uint64 guid;
202    uint32 spellId = 0;
203
204    recv_data >> guid >> spellId;
205    sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId );
206
207    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_TRAINER);
208    if (!unit)
209    {
210        sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
211        return;
212    }
213
214    // remove fake death
215    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
216        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
217
218    if(!unit->isCanTrainingOf(_player,true))
219        return;
220
221    // check present spell in trainer spell list
222    TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
223    if(!trainer_spells)
224        return; 
225
226    // not found, cheat?
227    TrainerSpell const* trainer_spell = trainer_spells->Find(spellId);
228    if(!trainer_spell)
229        return;
230
231    // can't be learn, cheat? Or double learn with lags...
232    if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
233        return;
234
235    // apply reputation discount
236    uint32 nSpellCost = uint32(floor(trainer_spell->spellcost * _player->GetReputationPriceDiscount(unit)));
237
238    // check money requirement
239    if(_player->GetMoney() < nSpellCost )
240        return;
241
242    WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12);           // visual effect on trainer
243    data << uint64(guid) << uint32(0xB3);
244    SendPacket(&data);
245
246    data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12);            // visual effect on player
247    data << uint64(_player->GetGUID()) << uint32(0x016A);
248    SendPacket(&data);
249
250    _player->ModifyMoney( -int32(nSpellCost) );
251
252    // learn explicitly to prevent lost money at lags, learning spell will be only show spell animation
253    _player->learnSpell(trainer_spell->spell);
254
255    data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
256    data << uint64(guid) << uint32(spellId);
257    SendPacket(&data);
258}
259
260void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data )
261{
262    CHECK_PACKET_SIZE(recv_data,8);
263
264    sLog.outDebug(  "WORLD: Received CMSG_GOSSIP_HELLO" );
265
266    uint64 guid;
267    recv_data >> guid;
268
269    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE);
270    if (!unit)
271    {
272        sLog.outDebug( "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
273        return;
274    }
275
276    // remove fake death
277    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
278        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
279
280    if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider())
281    {
282        unit->StopMoving();
283    }
284
285    // If spiritguide, no need for gossip menu, just put player into resurrect queue
286    if (unit->isSpiritGuide())
287    {
288        BattleGround *bg = _player->GetBattleGround();
289        if(bg)
290        {
291            bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID());
292            sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID());
293            return;
294        }
295    }
296
297    if(!Script->GossipHello( _player, unit ))
298    {
299        _player->TalkedToCreature(unit->GetEntry(),unit->GetGUID());
300        unit->prepareGossipMenu(_player);
301        unit->sendPreparedGossip(_player);
302    }
303}
304
305void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
306{
307    CHECK_PACKET_SIZE(recv_data,8+4+4);
308
309    sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
310
311    uint32 option;
312    uint32 unk;
313    uint64 guid;
314    std::string code = "";
315
316    recv_data >> guid >> unk >> option;
317
318    if(_player->PlayerTalkClass->GossipOptionCoded( option ))
319    {
320        // recheck
321        CHECK_PACKET_SIZE(recv_data,8+4+1);
322        sLog.outBasic("reading string");
323        recv_data >> code;
324        sLog.outBasic("string read: %s", code.c_str());
325    }
326
327    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE);
328    if (!unit)
329    {
330        sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
331        return;
332    }
333
334    // remove fake death
335    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
336        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
337
338    if(!code.empty())
339    {
340
341        if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction( option ), code.c_str()))
342            unit->OnGossipSelect (_player, option);
343    }
344    else
345
346    {
347        if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option)))
348            unit->OnGossipSelect (_player, option);
349    }
350}
351
352void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
353{
354    CHECK_PACKET_SIZE(recv_data,8);
355
356    sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
357
358    uint64 guid;
359
360    recv_data >> guid;
361
362    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_SPIRITHEALER);
363    if (!unit)
364    {
365        sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
366        return;
367    }
368
369    // remove fake death
370    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
371        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
372
373    SendSpiritResurrect();
374}
375
376void WorldSession::SendSpiritResurrect()
377{
378    _player->ResurrectPlayer(0.5f,false, true);
379
380    _player->DurabilityLossAll(0.25f,true);
381
382    // get corpse nearest graveyard
383    WorldSafeLocsEntry const *corpseGrave = NULL;
384    Corpse *corpse = _player->GetCorpse();
385    if(corpse)
386        corpseGrave = objmgr.GetClosestGraveYard(
387            corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam() );
388
389    // now can spawn bones
390    _player->SpawnCorpseBones();
391
392    // teleport to nearest from corpse graveyard, if different from nearest to player ghost
393    if(corpseGrave)
394    {
395        WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard(
396            _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam() );
397
398        if(corpseGrave != ghostGrave)
399            _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
400        // or update at original position
401        else
402            ObjectAccessor::UpdateVisibilityForPlayer(_player);
403    }
404    // or update at original position
405    else
406        ObjectAccessor::UpdateVisibilityForPlayer(_player);
407
408    _player->SaveToDB();
409}
410
411void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
412{
413    CHECK_PACKET_SIZE(recv_data,8);
414
415    uint64 npcGUID;
416    recv_data >> npcGUID;
417
418    if(!GetPlayer()->isAlive())
419        return;
420
421    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID,UNIT_NPC_FLAG_INNKEEPER);
422    if (!unit)
423    {
424        sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
425        return;
426    }
427
428    // remove fake death
429    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
430        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
431
432    SendBindPoint(unit);
433}
434
435void WorldSession::SendBindPoint(Creature *npc)
436{
437    uint32 bindspell = 3286;
438
439    // update sql homebind
440    CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), _player->GetZoneId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
441    _player->m_homebindMapId = _player->GetMapId();
442    _player->m_homebindZoneId = _player->GetZoneId();
443    _player->m_homebindX = _player->GetPositionX();
444    _player->m_homebindY = _player->GetPositionY();
445    _player->m_homebindZ = _player->GetPositionZ();
446
447    // send spell for bind 3286 bind magic
448    npc->CastSpell(_player, bindspell, true);
449
450    WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
451    data << npc->GetGUID();
452    data << bindspell;
453    SendPacket( &data );
454
455    // binding
456    data.Initialize( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) );
457    data << float(_player->GetPositionX());
458    data << float(_player->GetPositionY());
459    data << float(_player->GetPositionZ());
460    data << uint32(_player->GetMapId());
461    data << uint32(_player->GetZoneId());
462    SendPacket( &data );
463
464    DEBUG_LOG("New Home Position X is %f",_player->GetPositionX());
465    DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY());
466    DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ());
467    DEBUG_LOG("New Home MapId is %u",_player->GetMapId());
468    DEBUG_LOG("New Home ZoneId is %u",_player->GetZoneId());
469
470    // zone update
471    data.Initialize( SMSG_PLAYERBOUND, 8+4 );
472    data << uint64(_player->GetGUID());
473    data << uint32(_player->GetZoneId());
474    SendPacket( &data );
475
476    _player->PlayerTalkClass->CloseGossip();
477}
478
479//Need fix
480void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
481{
482    CHECK_PACKET_SIZE(recv_data,8);
483
484    sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
485    uint64 npcGUID;
486
487    recv_data >> npcGUID;
488
489    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
490    if (!unit)
491    {
492        sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
493        return;
494    }
495
496    // remove fake death
497    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
498        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
499
500    SendStablePet(npcGUID);
501}
502
503void WorldSession::SendStablePet(uint64 guid )
504{
505    sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
506
507    WorldPacket data(MSG_LIST_STABLED_PETS, 200);           // guess size
508    data << uint64 ( guid );
509
510    Pet *pet = _player->GetPet();
511
512    data << uint8(0);                                       // place holder for slot show number
513    data << uint8(GetPlayer()->m_stableSlots);
514
515    uint8 num = 0;                                          // counter for place holder
516
517    // not let move dead pet in slot
518    if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET)
519    {
520        data << uint32(pet->GetCharmInfo()->GetPetNumber());
521        data << uint32(pet->GetEntry());
522        data << uint32(pet->getLevel());
523        data << pet->GetName();                             // petname
524        data << uint32(pet->GetLoyaltyLevel());             // loyalty
525        data << uint8(0x01);                                // client slot 1 == current pet (0)
526        ++num;
527    }
528
529    //                                                     0      1     2   3      4      5        6
530    QueryResult* result = CharacterDatabase.PQuery("SELECT owner, slot, id, entry, level, loyalty, name FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow());
531
532    if(result)
533    {
534        do
535        {
536            Field *fields = result->Fetch();
537
538            data << uint32(fields[2].GetUInt32());          // petnumber
539            data << uint32(fields[3].GetUInt32());          // creature entry
540            data << uint32(fields[4].GetUInt32());          // level
541            data << fields[6].GetString();                  // name
542            data << uint32(fields[5].GetUInt32());          // loyalty
543            data << uint8(fields[1].GetUInt32()+1);         // slot
544
545            ++num;
546        }while( result->NextRow() );
547
548        delete result;
549    }
550
551    data.put<uint8>(8, num);                                // set real data to placeholder
552    SendPacket(&data);
553}
554
555void WorldSession::HandleStablePet( WorldPacket & recv_data )
556{
557    CHECK_PACKET_SIZE(recv_data,8);
558
559    sLog.outDebug("WORLD: Recv CMSG_STABLE_PET not dispose.");
560    uint64 npcGUID;
561
562    recv_data >> npcGUID;
563
564    if(!GetPlayer()->isAlive())
565        return;
566
567    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
568    if (!unit)
569    {
570        sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
571        return;
572    }
573
574    // remove fake death
575    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
576        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
577
578    Pet *pet = _player->GetPet();
579
580    WorldPacket data(SMSG_STABLE_RESULT, 200);              // guess size
581
582    // can't place in stable dead pet
583    if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET)
584    {
585        data << uint8(0x06);
586        SendPacket(&data);
587        return;
588    }
589
590    uint32 free_slot = 1;
591
592    QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u'  AND slot > 0 AND slot < 3 ORDER BY slot ",_player->GetGUIDLow());
593    if(result)
594    {
595        do
596        {
597            Field *fields = result->Fetch();
598
599            uint32 slot = fields[1].GetUInt32();
600
601            if(slot==free_slot)                             // this slot not free
602                ++free_slot;
603        }while( result->NextRow() );
604    }
605    delete result;
606
607    if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
608    {
609        _player->RemovePet(pet,PetSaveMode(free_slot));
610        data << uint8(0x08);
611    }
612    else
613        data << uint8(0x06);
614
615    SendPacket(&data);
616}
617
618void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
619{
620    CHECK_PACKET_SIZE(recv_data,8+4);
621
622    sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
623    uint64 npcGUID;
624    uint32 petnumber;
625
626    recv_data >> npcGUID >> petnumber;
627
628    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
629    if (!unit)
630    {
631        sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
632        return;
633    }
634
635    // remove fake death
636    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
637        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
638
639    WorldPacket data(SMSG_STABLE_RESULT, 200);              // guess size
640
641    Pet* pet = _player->GetPet();
642    if(pet && pet->isAlive())
643    {
644        uint8 i = 0x06;
645        data << uint8(i);
646        SendPacket(&data);
647        return;
648    }
649
650    // delete dead pet
651    if(pet)
652        _player->RemovePet(pet,PET_SAVE_AS_DELETED);
653
654    Pet *newpet = NULL;
655
656    QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow(),petnumber);
657    if(result)
658    {
659        Field *fields = result->Fetch();
660        uint32 petentry = fields[0].GetUInt32();
661
662        newpet = new Pet(HUNTER_PET);
663        if(!newpet->LoadPetFromDB(_player,petentry,petnumber))
664        {
665            delete newpet;
666            newpet = NULL;
667        }
668        delete result;
669    }
670
671    if(newpet)
672        data << uint8(0x09);
673    else
674        data << uint8(0x06);
675    SendPacket(&data);
676}
677
678void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
679{
680    CHECK_PACKET_SIZE(recv_data,8);
681
682    sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
683    uint64 npcGUID;
684
685    recv_data >> npcGUID;
686
687    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
688    if (!unit)
689    {
690        sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
691        return;
692    }
693
694    // remove fake death
695    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
696        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
697
698    WorldPacket data(SMSG_STABLE_RESULT, 200);
699
700    if(GetPlayer()->m_stableSlots < 2)                      // max slots amount = 2
701    {
702        StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
703        if(_player->GetMoney() >= SlotPrice->Price)
704        {
705            ++GetPlayer()->m_stableSlots;
706            _player->ModifyMoney(-int32(SlotPrice->Price));
707            data << uint8(0x0A);                            // success buy
708        }
709        else
710            data << uint8(0x06);
711    }
712    else
713        data << uint8(0x06);
714
715    SendPacket(&data);
716}
717
718void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */)
719{
720    sLog.outDebug("HandleStableRevivePet: Not implemented");
721}
722
723void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
724{
725    CHECK_PACKET_SIZE(recv_data,8+4);
726
727    sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
728    uint64 npcGUID;
729    uint32 pet_number;
730
731    recv_data >> npcGUID >> pet_number;
732
733    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
734    if (!unit)
735    {
736        sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
737        return;
738    }
739
740    // remove fake death
741    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
742        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
743
744    WorldPacket data(SMSG_STABLE_RESULT, 200);              // guess size
745
746    Pet* pet = _player->GetPet();
747
748    if(!pet || pet->getPetType()!=HUNTER_PET)
749        return;
750
751    // find swapped pet slot in stable
752    QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",_player->GetGUIDLow(),pet_number);
753    if(!result)
754        return;
755
756    Field *fields = result->Fetch();
757
758    uint32 slot     = fields[0].GetUInt32();
759    uint32 petentry = fields[1].GetUInt32();
760    delete result;
761
762    // move alive pet to slot or delele dead pet
763    _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
764
765    // summon unstabled pet
766    Pet *newpet = new Pet;
767    if(!newpet->LoadPetFromDB(_player,petentry,pet_number))
768    {
769        delete newpet;
770        data << uint8(0x06);
771    }
772    else
773        data << uint8(0x09);
774
775    SendPacket(&data);
776}
777
778void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
779{
780    CHECK_PACKET_SIZE(recv_data,8+8+1);
781
782    sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
783
784    uint64 npcGUID, itemGUID;
785    uint8 guildBank;                                        // new in 2.3.2, bool that means from guild bank money
786
787    recv_data >> npcGUID >> itemGUID >> guildBank;
788
789    Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_REPAIR);
790    if (!unit)
791    {
792        sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
793        return;
794    }
795
796    // remove fake death
797    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
798        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
799
800    // reputation discount
801    float discountMod = _player->GetReputationPriceDiscount(unit);
802
803    uint32 TotalCost = 0;
804    if (itemGUID)
805    {
806        sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
807
808        Item* item = _player->GetItemByGuid(itemGUID);
809
810        if(item)
811            TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
812    }
813    else
814    {
815        sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
816
817        TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
818    }
819    if (guildBank)
820    {
821        uint32 GuildId = _player->GetGuildId();
822        if (!GuildId)
823            return;
824        Guild *pGuild = objmgr.GetGuildById(GuildId);
825        if (!pGuild)
826            return;
827        pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
828        pGuild->SendMoneyInfo(this, _player->GetGUIDLow());
829    }
830}
Note: See TracBrowser for help on using the browser.