[9290] Some cleanups in realmd, no functional changes
[getmangos.git] / src / game / NPCHandler.cpp
blobbf3425dd5a011b8274d6a2018232ec070da310f9
1 /*
2 * Copyright (C) 2005-2010 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 "Guild.h"
37 void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data )
39 uint64 guid;
40 recv_data >> guid;
42 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TABARDDESIGNER);
43 if (!unit)
45 sLog.outDebug( "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
46 return;
49 // remove fake death
50 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
51 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
53 SendTabardVendorActivate(guid);
56 void WorldSession::SendTabardVendorActivate( uint64 guid )
58 WorldPacket data( MSG_TABARDVENDOR_ACTIVATE, 8 );
59 data << guid;
60 SendPacket( &data );
63 void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data )
65 uint64 guid;
67 sLog.outDebug( "WORLD: Received CMSG_BANKER_ACTIVATE" );
69 recv_data >> guid;
71 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_BANKER);
72 if (!unit)
74 sLog.outDebug( "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
75 return;
78 // remove fake death
79 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
80 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
82 SendShowBank(guid);
85 void WorldSession::SendShowBank( uint64 guid )
87 WorldPacket data( SMSG_SHOW_BANK, 8 );
88 data << guid;
89 SendPacket( &data );
92 void WorldSession::HandleTrainerListOpcode( WorldPacket & recv_data )
94 uint64 guid;
96 recv_data >> guid;
97 SendTrainerList( guid );
100 void WorldSession::SendTrainerList( uint64 guid )
102 std::string str = GetMangosString(LANG_NPC_TAINER_HELLO);
103 SendTrainerList( guid, str );
106 void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
108 sLog.outDebug( "WORLD: SendTrainerList" );
110 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER);
111 if (!unit)
113 sLog.outDebug( "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
114 return;
117 // remove fake death
118 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
119 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
121 // trainer list loaded at check;
122 if(!unit->isCanTrainingOf(_player,true))
123 return;
125 CreatureInfo const *ci = unit->GetCreatureInfo();
127 if (!ci)
129 sLog.outDebug( "WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!",GUID_LOPART(guid) );
130 return;
133 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
134 if(!trainer_spells)
136 sLog.outDebug( "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)",
137 GUID_LOPART(guid), unit->GetEntry());
138 return;
141 WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1);
142 data << guid;
143 data << uint32(trainer_spells->trainerType);
145 size_t count_pos = data.wpos();
146 data << uint32(trainer_spells->spellList.size());
148 // reputation discount
149 float fDiscountMod = _player->GetReputationPriceDiscount(unit);
150 bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0;
152 uint32 count = 0;
153 for(TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
155 TrainerSpell const* tSpell = &itr->second;
157 if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
158 continue;
160 bool primary_prof_first_rank = sSpellMgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
161 SpellChainNode const* chain_node = sSpellMgr.GetSpellChainNode(tSpell->learnedSpell);
162 TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
164 data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
165 data << uint8(state==TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
166 data << uint32(floor(tSpell->spellCost * fDiscountMod));
168 data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
169 // primary prof. learn confirmation dialog
170 data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
171 data << uint8(tSpell->reqLevel);
172 data << uint32(tSpell->reqSkill);
173 data << uint32(tSpell->reqSkillValue);
174 data << uint32(!tSpell->IsCastable() && chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
175 data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->req : 0);
176 data << uint32(0);
178 ++count;
181 data << strTitle;
183 data.put<uint32>(count_pos,count);
184 SendPacket( &data );
187 void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
189 uint64 guid;
190 uint32 spellId = 0;
192 recv_data >> guid >> spellId;
193 sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId );
195 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
196 if (!unit)
198 sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
199 return;
202 // remove fake death
203 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
204 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
206 if(!unit->isCanTrainingOf(_player,true))
207 return;
209 // check present spell in trainer spell list
210 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
211 if(!trainer_spells)
212 return;
214 // not found, cheat?
215 TrainerSpell const* trainer_spell = trainer_spells->Find(spellId);
216 if(!trainer_spell)
217 return;
219 // can't be learn, cheat? Or double learn with lags...
220 if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
221 return;
223 // apply reputation discount
224 uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
226 // check money requirement
227 if(_player->GetMoney() < nSpellCost )
228 return;
230 _player->ModifyMoney( -int32(nSpellCost) );
232 WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
233 data << uint64(guid) << uint32(0xB3);
234 SendPacket(&data);
236 data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player
237 data << uint64(_player->GetGUID()) << uint32(0x016A);
238 SendPacket(&data);
240 // learn explicitly or cast explicitly
241 if(trainer_spell->IsCastable ())
242 //FIXME: prof. spell entry in trainer list not marked gray until list re-open.
243 _player->CastSpell(_player,trainer_spell->spell,true);
244 else
245 _player->learnSpell(spellId,false);
247 data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
248 data << uint64(guid) << uint32(trainer_spell->spell);
249 SendPacket(&data);
252 void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data)
254 sLog.outDebug("WORLD: Received CMSG_GOSSIP_HELLO");
256 uint64 guid;
257 recv_data >> guid;
259 Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
261 if (!pCreature)
263 sLog.outDebug("WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
264 return;
267 // remove fake death
268 if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
269 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
271 if (!pCreature->IsStopped())
272 pCreature->StopMoving();
274 if (pCreature->isSpiritGuide())
275 pCreature->SendAreaSpiritHealerQueryOpcode(_player);
277 if (!Script->GossipHello(_player, pCreature))
279 _player->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID());
280 _player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId);
281 _player->SendPreparedGossip(pCreature);
285 void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
287 sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
289 uint32 gossipListId;
290 uint32 menuId;
291 uint64 guid;
292 std::string code = "";
294 recv_data >> guid >> menuId >> gossipListId;
296 if (_player->PlayerTalkClass->GossipOptionCoded(gossipListId))
298 sLog.outBasic("reading string");
299 recv_data >> code;
300 sLog.outBasic("string read: %s", code.c_str());
303 // remove fake death
304 if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
305 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
307 // TODO: determine if scriptCall is needed for GO and also if scriptCall can be same as current, with modified argument WorldObject*
309 // can vehicle have gossip? If so, need check for this also.
310 if (IS_CREATURE_OR_PET_GUID(guid))
312 Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
314 if (!pCreature)
316 sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Creature (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid)));
317 return;
320 if (!code.empty())
322 if (!Script->GossipSelectWithCode(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()))
323 _player->OnGossipSelect(pCreature, gossipListId, menuId);
325 else
327 if (!Script->GossipSelect(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)))
328 _player->OnGossipSelect(pCreature, gossipListId, menuId);
331 else if (IS_GAMEOBJECT_GUID(guid))
333 GameObject *pGo = GetPlayer()->GetGameObjectIfCanInteractWith(guid);
335 if (!pGo)
337 sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - GameObject (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid)));
338 return;
341 _player->OnGossipSelect(pGo, gossipListId, menuId);
345 void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
347 sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
349 uint64 guid;
351 recv_data >> guid;
353 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
354 if (!unit)
356 sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
357 return;
360 // remove fake death
361 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
362 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
364 SendSpiritResurrect();
367 void WorldSession::SendSpiritResurrect()
369 _player->ResurrectPlayer(0.5f, true);
371 _player->DurabilityLossAll(0.25f,true);
373 // get corpse nearest graveyard
374 WorldSafeLocsEntry const *corpseGrave = NULL;
375 Corpse *corpse = _player->GetCorpse();
376 if(corpse)
377 corpseGrave = sObjectMgr.GetClosestGraveYard(
378 corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam() );
380 // now can spawn bones
381 _player->SpawnCorpseBones();
383 // teleport to nearest from corpse graveyard, if different from nearest to player ghost
384 if(corpseGrave)
386 WorldSafeLocsEntry const *ghostGrave = sObjectMgr.GetClosestGraveYard(
387 _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam() );
389 if(corpseGrave != ghostGrave)
390 _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
391 // or update at original position
392 else
393 _player->UpdateVisibilityForPlayer();
395 // or update at original position
396 else
397 _player->UpdateVisibilityForPlayer();
400 void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
402 uint64 npcGUID;
403 recv_data >> npcGUID;
405 if(!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
406 return;
408 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
409 if (!unit)
411 sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
412 return;
415 // remove fake death
416 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
417 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
419 SendBindPoint(unit);
422 void WorldSession::SendBindPoint(Creature *npc)
424 // prevent set homebind to instances in any case
425 if(GetPlayer()->GetMap()->Instanceable())
426 return;
428 uint32 bindspell = 3286;
429 uint32 zone_id = _player->GetZoneId();
431 _player->SetHomebindToCurrentPos();
433 // send spell for bind 3286 bind magic
434 npc->CastSpell(_player, bindspell, true);
436 WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
437 data << npc->GetGUID();
438 data << bindspell;
439 SendPacket( &data );
441 // binding
442 data.Initialize( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) );
443 data << float(_player->GetPositionX());
444 data << float(_player->GetPositionY());
445 data << float(_player->GetPositionZ());
446 data << uint32(_player->GetMapId());
447 data << uint32(zone_id);
448 SendPacket( &data );
450 DEBUG_LOG("New Home Position X is %f",_player->GetPositionX());
451 DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY());
452 DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ());
453 DEBUG_LOG("New Home MapId is %u",_player->GetMapId());
454 DEBUG_LOG("New Home ZoneId is %u",zone_id);
456 // zone update
457 data.Initialize( SMSG_PLAYERBOUND, 8+4 );
458 data << uint64(_player->GetGUID());
459 data << uint32(zone_id);
460 SendPacket( &data );
462 _player->PlayerTalkClass->CloseGossip();
465 void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
467 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
468 uint64 npcGUID;
470 recv_data >> npcGUID;
472 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
473 if (!unit)
475 sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
476 return;
479 // remove fake death
480 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
481 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
483 SendStablePet(npcGUID);
486 void WorldSession::SendStablePet(uint64 guid )
488 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
490 WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
491 data << uint64 ( guid );
493 Pet *pet = _player->GetPet();
495 size_t wpos = data.wpos();
496 data << uint8(0); // place holder for slot show number
498 data << uint8(GetPlayer()->m_stableSlots);
500 uint8 num = 0; // counter for place holder
502 // not let move dead pet in slot
503 if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET)
505 data << uint32(pet->GetCharmInfo()->GetPetNumber());
506 data << uint32(pet->GetEntry());
507 data << uint32(pet->getLevel());
508 data << pet->GetName(); // petname
509 data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
510 ++num;
513 // 0 1 2 3 4
514 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",
515 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
517 if(result)
521 Field *fields = result->Fetch();
523 data << uint32(fields[1].GetUInt32()); // petnumber
524 data << uint32(fields[2].GetUInt32()); // creature entry
525 data << uint32(fields[3].GetUInt32()); // level
526 data << fields[4].GetString(); // name
527 data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
529 ++num;
530 }while( result->NextRow() );
532 delete result;
535 data.put<uint8>(wpos, num); // set real data to placeholder
536 SendPacket(&data);
539 void WorldSession::HandleStablePet( WorldPacket & recv_data )
541 sLog.outDebug("WORLD: Recv CMSG_STABLE_PET");
542 uint64 npcGUID;
544 recv_data >> npcGUID;
546 if(!GetPlayer()->isAlive())
547 return;
549 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
550 if (!unit)
552 sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
553 return;
556 // remove fake death
557 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
558 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
560 Pet *pet = _player->GetPet();
562 // can't place in stable dead pet
563 if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET)
565 WorldPacket data(SMSG_STABLE_RESULT, 1);
566 data << uint8(0x06);
567 SendPacket(&data);
568 return;
571 uint32 free_slot = 1;
573 QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
574 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
575 if(result)
579 Field *fields = result->Fetch();
581 uint32 slot = fields[1].GetUInt32();
583 // slots ordered in query, and if not equal then free
584 if(slot!=free_slot)
585 break;
587 // this slot not free, skip
588 ++free_slot;
589 }while( result->NextRow() );
591 delete result;
594 WorldPacket data(SMSG_STABLE_RESULT, 1);
595 if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
597 _player->RemovePet(pet,PetSaveMode(free_slot));
598 data << uint8(0x08);
600 else
601 data << uint8(0x06);
603 SendPacket(&data);
606 void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
608 sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
609 uint64 npcGUID;
610 uint32 petnumber;
612 recv_data >> npcGUID >> petnumber;
614 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
615 if (!unit)
617 sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
618 return;
621 // remove fake death
622 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
623 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
625 uint32 creature_id = 0;
628 QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
629 _player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
630 if(result)
632 Field *fields = result->Fetch();
633 creature_id = fields[0].GetUInt32();
634 delete result;
638 if(!creature_id)
640 WorldPacket data(SMSG_STABLE_RESULT, 1);
641 data << uint8(0x06);
642 SendPacket(&data);
643 return;
646 CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
647 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
649 WorldPacket data(SMSG_STABLE_RESULT, 1);
650 data << uint8(0x06);
651 SendPacket(&data);
652 return;
655 Pet* pet = _player->GetPet();
656 if(pet && pet->isAlive())
658 WorldPacket data(SMSG_STABLE_RESULT, 1);
659 data << uint8(0x06);
660 SendPacket(&data);
661 return;
664 // delete dead pet
665 if(pet)
666 _player->RemovePet(pet,PET_SAVE_AS_DELETED);
668 Pet *newpet = new Pet(HUNTER_PET);
669 if(!newpet->LoadPetFromDB(_player,creature_id,petnumber))
671 delete newpet;
672 newpet = NULL;
673 WorldPacket data(SMSG_STABLE_RESULT, 1);
674 data << uint8(0x06);
675 SendPacket(&data);
676 return;
679 WorldPacket data(SMSG_STABLE_RESULT, 1);
680 data << uint8(0x09);
681 SendPacket(&data);
684 void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
686 sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
687 uint64 npcGUID;
689 recv_data >> npcGUID;
691 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
692 if (!unit)
694 sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
695 return;
698 // remove fake death
699 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
700 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
702 WorldPacket data(SMSG_STABLE_RESULT, 200);
704 if(GetPlayer()->m_stableSlots < MAX_PET_STABLES)
706 StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
707 if(_player->GetMoney() >= SlotPrice->Price)
709 ++GetPlayer()->m_stableSlots;
710 _player->ModifyMoney(-int32(SlotPrice->Price));
711 data << uint8(0x0A); // success buy
713 else
714 data << uint8(0x06);
716 else
717 data << uint8(0x06);
719 SendPacket(&data);
722 void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */)
724 sLog.outDebug("HandleStableRevivePet: Not implemented");
727 void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
729 sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
730 uint64 npcGUID;
731 uint32 pet_number;
733 recv_data >> npcGUID >> pet_number;
735 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
736 if (!unit)
738 sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
739 return;
742 // remove fake death
743 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
744 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
746 WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
748 Pet* pet = _player->GetPet();
750 if(!pet || pet->getPetType()!=HUNTER_PET)
751 return;
753 // find swapped pet slot in stable
754 QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
755 _player->GetGUIDLow(),pet_number);
756 if(!result)
757 return;
759 Field *fields = result->Fetch();
761 uint32 slot = fields[0].GetUInt32();
762 uint32 creature_id = fields[1].GetUInt32();
763 delete result;
765 if(!creature_id)
767 WorldPacket data(SMSG_STABLE_RESULT, 1);
768 data << uint8(0x06);
769 SendPacket(&data);
770 return;
773 CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
774 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
776 WorldPacket data(SMSG_STABLE_RESULT, 1);
777 data << uint8(0x06);
778 SendPacket(&data);
779 return;
782 // move alive pet to slot or delete dead pet
783 _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
785 // summon unstabled pet
786 Pet *newpet = new Pet;
787 if(!newpet->LoadPetFromDB(_player,creature_id,pet_number))
789 delete newpet;
790 data << uint8(0x06);
792 else
793 data << uint8(0x09);
795 SendPacket(&data);
798 void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
800 sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
802 uint64 npcGUID, itemGUID;
803 uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
805 recv_data >> npcGUID >> itemGUID >> guildBank;
807 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR);
808 if (!unit)
810 sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
811 return;
814 // remove fake death
815 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
816 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
818 // reputation discount
819 float discountMod = _player->GetReputationPriceDiscount(unit);
821 uint32 TotalCost = 0;
822 if (itemGUID)
824 sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
826 Item* item = _player->GetItemByGuid(itemGUID);
828 if(item)
829 TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
831 else
833 sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
835 TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
837 if (guildBank)
839 uint32 GuildId = _player->GetGuildId();
840 if (!GuildId)
841 return;
842 Guild *pGuild = sObjectMgr.GetGuildById(GuildId);
843 if (!pGuild)
844 return;
845 pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
846 pGuild->SendMoneyInfo(this, _player->GetGUIDLow());