[8483] Implement glyph 43361.
[getmangos.git] / src / game / NPCHandler.cpp
blobfd15a1d4e506c71c2ee0bead8ef87483bc66925d
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Language.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "ObjectMgr.h"
27 #include "SpellMgr.h"
28 #include "Player.h"
29 #include "GossipDef.h"
30 #include "UpdateMask.h"
31 #include "ScriptCalls.h"
32 #include "ObjectAccessor.h"
33 #include "Creature.h"
34 #include "Pet.h"
35 #include "BattleGroundMgr.h"
36 #include "BattleGround.h"
37 #include "Guild.h"
39 void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data )
41 uint64 guid;
42 recv_data >> guid;
44 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TABARDDESIGNER);
45 if (!unit)
47 sLog.outDebug( "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
48 return;
51 // remove fake death
52 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
53 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
55 SendTabardVendorActivate(guid);
58 void WorldSession::SendTabardVendorActivate( uint64 guid )
60 WorldPacket data( MSG_TABARDVENDOR_ACTIVATE, 8 );
61 data << guid;
62 SendPacket( &data );
65 void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data )
67 uint64 guid;
69 sLog.outDebug( "WORLD: Received CMSG_BANKER_ACTIVATE" );
71 recv_data >> guid;
73 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_BANKER);
74 if (!unit)
76 sLog.outDebug( "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
77 return;
80 // remove fake death
81 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
82 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
84 SendShowBank(guid);
87 void WorldSession::SendShowBank( uint64 guid )
89 WorldPacket data( SMSG_SHOW_BANK, 8 );
90 data << guid;
91 SendPacket( &data );
94 void WorldSession::HandleTrainerListOpcode( WorldPacket & recv_data )
96 uint64 guid;
98 recv_data >> guid;
99 SendTrainerList( guid );
102 void WorldSession::SendTrainerList( uint64 guid )
104 std::string str = GetMangosString(LANG_NPC_TAINER_HELLO);
105 SendTrainerList( guid, str );
108 void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
110 sLog.outDebug( "WORLD: SendTrainerList" );
112 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER);
113 if (!unit)
115 sLog.outDebug( "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
116 return;
119 // remove fake death
120 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
121 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
123 // trainer list loaded at check;
124 if(!unit->isCanTrainingOf(_player,true))
125 return;
127 CreatureInfo const *ci = unit->GetCreatureInfo();
129 if (!ci)
131 sLog.outDebug( "WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!",GUID_LOPART(guid) );
132 return;
135 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
136 if(!trainer_spells)
138 sLog.outDebug( "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)",
139 GUID_LOPART(guid), unit->GetEntry());
140 return;
143 WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1);
144 data << guid;
145 data << uint32(trainer_spells->trainerType);
147 size_t count_pos = data.wpos();
148 data << uint32(trainer_spells->spellList.size());
150 // reputation discount
151 float fDiscountMod = _player->GetReputationPriceDiscount(unit);
152 bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0;
154 uint32 count = 0;
155 for(TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
157 TrainerSpell const* tSpell = &itr->second;
159 if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
160 continue;
162 bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
163 SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell);
164 TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
166 data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
167 data << uint8(state==TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
168 data << uint32(floor(tSpell->spellCost * fDiscountMod));
170 data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
171 // primary prof. learn confirmation dialog
172 data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
173 data << uint8(tSpell->reqLevel);
174 data << uint32(tSpell->reqSkill);
175 data << uint32(tSpell->reqSkillValue);
176 data << uint32(!tSpell->IsCastable() && chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
177 data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->req : 0);
178 data << uint32(0);
180 ++count;
183 data << strTitle;
185 data.put<uint32>(count_pos,count);
186 SendPacket( &data );
189 void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
191 uint64 guid;
192 uint32 spellId = 0;
194 recv_data >> guid >> spellId;
195 sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId );
197 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
198 if (!unit)
200 sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
201 return;
204 // remove fake death
205 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
206 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
208 if(!unit->isCanTrainingOf(_player,true))
209 return;
211 // check present spell in trainer spell list
212 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
213 if(!trainer_spells)
214 return;
216 // not found, cheat?
217 TrainerSpell const* trainer_spell = trainer_spells->Find(spellId);
218 if(!trainer_spell)
219 return;
221 // can't be learn, cheat? Or double learn with lags...
222 if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
223 return;
225 // apply reputation discount
226 uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
228 // check money requirement
229 if(_player->GetMoney() < nSpellCost )
230 return;
232 _player->ModifyMoney( -int32(nSpellCost) );
234 WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
235 data << uint64(guid) << uint32(0xB3);
236 SendPacket(&data);
238 data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player
239 data << uint64(_player->GetGUID()) << uint32(0x016A);
240 SendPacket(&data);
242 // learn explicitly or cast explicitly
243 if(trainer_spell->IsCastable ())
244 //FIXME: prof. spell entry in trainer list not marked gray until list re-open.
245 _player->CastSpell(_player,trainer_spell->spell,true);
246 else
247 _player->learnSpell(spellId,false);
249 data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
250 data << uint64(guid) << uint32(trainer_spell->spell);
251 SendPacket(&data);
254 void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data )
256 sLog.outDebug( "WORLD: Received CMSG_GOSSIP_HELLO" );
258 uint64 guid;
259 recv_data >> guid;
261 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
262 if (!unit)
264 sLog.outDebug( "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
265 return;
268 // remove fake death
269 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
270 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
272 if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider())
274 unit->StopMoving();
277 // If spiritguide, no need for gossip menu, just put player into resurrect queue
278 if (unit->isSpiritGuide())
280 BattleGround *bg = _player->GetBattleGround();
281 if(bg)
283 bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID());
284 sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID());
285 return;
289 if(!Script->GossipHello( _player, unit ))
291 _player->TalkedToCreature(unit->GetEntry(),unit->GetGUID());
292 unit->prepareGossipMenu(_player);
293 unit->sendPreparedGossip(_player);
297 void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
299 sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
301 uint32 option;
302 uint32 unk;
303 uint64 guid;
304 std::string code = "";
306 recv_data >> guid >> unk >> option;
308 if(_player->PlayerTalkClass->GossipOptionCoded( option ))
310 sLog.outBasic("reading string");
311 recv_data >> code;
312 sLog.outBasic("string read: %s", code.c_str());
315 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
316 if (!unit)
318 sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
319 return;
322 // remove fake death
323 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
324 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
326 if(!code.empty())
328 if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction( option ), code.c_str()))
329 unit->OnGossipSelect (_player, option);
331 else
333 if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option)))
334 unit->OnGossipSelect (_player, option);
338 void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
340 sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
342 uint64 guid;
344 recv_data >> guid;
346 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
347 if (!unit)
349 sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
350 return;
353 // remove fake death
354 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
355 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
357 SendSpiritResurrect();
360 void WorldSession::SendSpiritResurrect()
362 _player->ResurrectPlayer(0.5f, true);
364 _player->DurabilityLossAll(0.25f,true);
366 // get corpse nearest graveyard
367 WorldSafeLocsEntry const *corpseGrave = NULL;
368 Corpse *corpse = _player->GetCorpse();
369 if(corpse)
370 corpseGrave = objmgr.GetClosestGraveYard(
371 corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam() );
373 // now can spawn bones
374 _player->SpawnCorpseBones();
376 // teleport to nearest from corpse graveyard, if different from nearest to player ghost
377 if(corpseGrave)
379 WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard(
380 _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam() );
382 if(corpseGrave != ghostGrave)
383 _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
384 // or update at original position
385 else
386 ObjectAccessor::UpdateVisibilityForPlayer(_player);
388 // or update at original position
389 else
390 ObjectAccessor::UpdateVisibilityForPlayer(_player);
392 _player->SaveToDB();
395 void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
397 uint64 npcGUID;
398 recv_data >> npcGUID;
400 if(!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
401 return;
403 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
404 if (!unit)
406 sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
407 return;
410 // remove fake death
411 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
412 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
414 SendBindPoint(unit);
417 void WorldSession::SendBindPoint(Creature *npc)
419 // prevent set homebind to instances in any case
420 if(GetPlayer()->GetMap()->Instanceable())
421 return;
423 uint32 bindspell = 3286;
424 uint32 zone_id = _player->GetZoneId();
426 // update sql homebind
427 CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), zone_id, _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
428 _player->m_homebindMapId = _player->GetMapId();
429 _player->m_homebindZoneId = zone_id;
430 _player->m_homebindX = _player->GetPositionX();
431 _player->m_homebindY = _player->GetPositionY();
432 _player->m_homebindZ = _player->GetPositionZ();
434 // send spell for bind 3286 bind magic
435 npc->CastSpell(_player, bindspell, true);
437 WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
438 data << npc->GetGUID();
439 data << bindspell;
440 SendPacket( &data );
442 // binding
443 data.Initialize( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) );
444 data << float(_player->GetPositionX());
445 data << float(_player->GetPositionY());
446 data << float(_player->GetPositionZ());
447 data << uint32(_player->GetMapId());
448 data << uint32(zone_id);
449 SendPacket( &data );
451 DEBUG_LOG("New Home Position X is %f",_player->GetPositionX());
452 DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY());
453 DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ());
454 DEBUG_LOG("New Home MapId is %u",_player->GetMapId());
455 DEBUG_LOG("New Home ZoneId is %u",zone_id);
457 // zone update
458 data.Initialize( SMSG_PLAYERBOUND, 8+4 );
459 data << uint64(_player->GetGUID());
460 data << uint32(zone_id);
461 SendPacket( &data );
463 _player->PlayerTalkClass->CloseGossip();
466 void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
468 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
469 uint64 npcGUID;
471 recv_data >> npcGUID;
473 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
474 if (!unit)
476 sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
477 return;
480 // remove fake death
481 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
482 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
484 SendStablePet(npcGUID);
487 void WorldSession::SendStablePet(uint64 guid )
489 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
491 WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
492 data << uint64 ( guid );
494 Pet *pet = _player->GetPet();
496 size_t wpos = data.wpos();
497 data << uint8(0); // place holder for slot show number
499 data << uint8(GetPlayer()->m_stableSlots);
501 uint8 num = 0; // counter for place holder
503 // not let move dead pet in slot
504 if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET)
506 data << uint32(pet->GetCharmInfo()->GetPetNumber());
507 data << uint32(pet->GetEntry());
508 data << uint32(pet->getLevel());
509 data << pet->GetName(); // petname
510 data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
511 ++num;
514 // 0 1 2 3 4
515 QueryResult* result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot",
516 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
518 if(result)
522 Field *fields = result->Fetch();
524 data << uint32(fields[1].GetUInt32()); // petnumber
525 data << uint32(fields[2].GetUInt32()); // creature entry
526 data << uint32(fields[3].GetUInt32()); // level
527 data << fields[4].GetString(); // name
528 data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
530 ++num;
531 }while( result->NextRow() );
533 delete result;
536 data.put<uint8>(wpos, num); // set real data to placeholder
537 SendPacket(&data);
540 void WorldSession::HandleStablePet( WorldPacket & recv_data )
542 sLog.outDebug("WORLD: Recv CMSG_STABLE_PET");
543 uint64 npcGUID;
545 recv_data >> npcGUID;
547 if(!GetPlayer()->isAlive())
548 return;
550 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
551 if (!unit)
553 sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
554 return;
557 // remove fake death
558 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
559 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
561 Pet *pet = _player->GetPet();
563 // can't place in stable dead pet
564 if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET)
566 WorldPacket data(SMSG_STABLE_RESULT, 1);
567 data << uint8(0x06);
568 SendPacket(&data);
569 return;
572 uint32 free_slot = 1;
574 QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
575 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
576 if(result)
580 Field *fields = result->Fetch();
582 uint32 slot = fields[1].GetUInt32();
584 // slots ordered in query, and if not equal then free
585 if(slot!=free_slot)
586 break;
588 // this slot not free, skip
589 ++free_slot;
590 }while( result->NextRow() );
592 delete result;
595 WorldPacket data(SMSG_STABLE_RESULT, 1);
596 if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
598 _player->RemovePet(pet,PetSaveMode(free_slot));
599 data << uint8(0x08);
601 else
602 data << uint8(0x06);
604 SendPacket(&data);
607 void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
609 sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
610 uint64 npcGUID;
611 uint32 petnumber;
613 recv_data >> npcGUID >> petnumber;
615 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
616 if (!unit)
618 sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
619 return;
622 // remove fake death
623 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
624 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
626 uint32 creature_id = 0;
629 QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
630 _player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
631 if(result)
633 Field *fields = result->Fetch();
634 creature_id = fields[0].GetUInt32();
635 delete result;
639 if(!creature_id)
641 WorldPacket data(SMSG_STABLE_RESULT, 1);
642 data << uint8(0x06);
643 SendPacket(&data);
644 return;
647 CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id);
648 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
650 WorldPacket data(SMSG_STABLE_RESULT, 1);
651 data << uint8(0x06);
652 SendPacket(&data);
653 return;
656 Pet* pet = _player->GetPet();
657 if(pet && pet->isAlive())
659 WorldPacket data(SMSG_STABLE_RESULT, 1);
660 data << uint8(0x06);
661 SendPacket(&data);
662 return;
665 // delete dead pet
666 if(pet)
667 _player->RemovePet(pet,PET_SAVE_AS_DELETED);
669 Pet *newpet = new Pet(HUNTER_PET);
670 if(!newpet->LoadPetFromDB(_player,creature_id,petnumber))
672 delete newpet;
673 newpet = NULL;
674 WorldPacket data(SMSG_STABLE_RESULT, 1);
675 data << uint8(0x06);
676 SendPacket(&data);
677 return;
680 WorldPacket data(SMSG_STABLE_RESULT, 1);
681 data << uint8(0x09);
682 SendPacket(&data);
685 void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
687 sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
688 uint64 npcGUID;
690 recv_data >> npcGUID;
692 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
693 if (!unit)
695 sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
696 return;
699 // remove fake death
700 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
701 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
703 WorldPacket data(SMSG_STABLE_RESULT, 200);
705 if(GetPlayer()->m_stableSlots < MAX_PET_STABLES)
707 StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
708 if(_player->GetMoney() >= SlotPrice->Price)
710 ++GetPlayer()->m_stableSlots;
711 _player->ModifyMoney(-int32(SlotPrice->Price));
712 data << uint8(0x0A); // success buy
714 else
715 data << uint8(0x06);
717 else
718 data << uint8(0x06);
720 SendPacket(&data);
723 void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */)
725 sLog.outDebug("HandleStableRevivePet: Not implemented");
728 void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
730 sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
731 uint64 npcGUID;
732 uint32 pet_number;
734 recv_data >> npcGUID >> pet_number;
736 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
737 if (!unit)
739 sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
740 return;
743 // remove fake death
744 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
745 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
747 WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
749 Pet* pet = _player->GetPet();
751 if(!pet || pet->getPetType()!=HUNTER_PET)
752 return;
754 // find swapped pet slot in stable
755 QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
756 _player->GetGUIDLow(),pet_number);
757 if(!result)
758 return;
760 Field *fields = result->Fetch();
762 uint32 slot = fields[0].GetUInt32();
763 uint32 creature_id = fields[1].GetUInt32();
764 delete result;
766 if(!creature_id)
768 WorldPacket data(SMSG_STABLE_RESULT, 1);
769 data << uint8(0x06);
770 SendPacket(&data);
771 return;
774 CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id);
775 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
777 WorldPacket data(SMSG_STABLE_RESULT, 1);
778 data << uint8(0x06);
779 SendPacket(&data);
780 return;
783 // move alive pet to slot or delete dead pet
784 _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
786 // summon unstabled pet
787 Pet *newpet = new Pet;
788 if(!newpet->LoadPetFromDB(_player,creature_id,pet_number))
790 delete newpet;
791 data << uint8(0x06);
793 else
794 data << uint8(0x09);
796 SendPacket(&data);
799 void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
801 sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
803 uint64 npcGUID, itemGUID;
804 uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
806 recv_data >> npcGUID >> itemGUID >> guildBank;
808 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR);
809 if (!unit)
811 sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
812 return;
815 // remove fake death
816 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
817 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
819 // reputation discount
820 float discountMod = _player->GetReputationPriceDiscount(unit);
822 uint32 TotalCost = 0;
823 if (itemGUID)
825 sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
827 Item* item = _player->GetItemByGuid(itemGUID);
829 if(item)
830 TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
832 else
834 sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
836 TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
838 if (guildBank)
840 uint32 GuildId = _player->GetGuildId();
841 if (!GuildId)
842 return;
843 Guild *pGuild = objmgr.GetGuildById(GuildId);
844 if (!pGuild)
845 return;
846 pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
847 pGuild->SendMoneyInfo(this, _player->GetGUIDLow());