[9529] Make Player::IsValidPos const
[getmangos.git] / src / game / NPCHandler.cpp
blobcfdf7fa81b0d2d27edf91ecf4affc9d83098d46a
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 // send spell for bind 3286 bind magic
429 npc->CastSpell(_player, 3286, true); // Bind
431 WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
432 data << uint64(npc->GetGUID());
433 data << uint32(3286); // Bind
434 SendPacket( &data );
436 _player->PlayerTalkClass->CloseGossip();
439 void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
441 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
442 uint64 npcGUID;
444 recv_data >> npcGUID;
446 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
447 if (!unit)
449 sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
450 return;
453 // remove fake death
454 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
455 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
457 SendStablePet(npcGUID);
460 void WorldSession::SendStablePet(uint64 guid )
462 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
464 WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
465 data << uint64 ( guid );
467 Pet *pet = _player->GetPet();
469 size_t wpos = data.wpos();
470 data << uint8(0); // place holder for slot show number
472 data << uint8(GetPlayer()->m_stableSlots);
474 uint8 num = 0; // counter for place holder
476 // not let move dead pet in slot
477 if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET)
479 data << uint32(pet->GetCharmInfo()->GetPetNumber());
480 data << uint32(pet->GetEntry());
481 data << uint32(pet->getLevel());
482 data << pet->GetName(); // petname
483 data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
484 ++num;
487 // 0 1 2 3 4
488 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",
489 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
491 if(result)
495 Field *fields = result->Fetch();
497 data << uint32(fields[1].GetUInt32()); // petnumber
498 data << uint32(fields[2].GetUInt32()); // creature entry
499 data << uint32(fields[3].GetUInt32()); // level
500 data << fields[4].GetString(); // name
501 data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
503 ++num;
504 }while( result->NextRow() );
506 delete result;
509 data.put<uint8>(wpos, num); // set real data to placeholder
510 SendPacket(&data);
513 void WorldSession::HandleStablePet( WorldPacket & recv_data )
515 sLog.outDebug("WORLD: Recv CMSG_STABLE_PET");
516 uint64 npcGUID;
518 recv_data >> npcGUID;
520 if(!GetPlayer()->isAlive())
521 return;
523 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
524 if (!unit)
526 sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
527 return;
530 // remove fake death
531 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
532 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
534 Pet *pet = _player->GetPet();
536 // can't place in stable dead pet
537 if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET)
539 WorldPacket data(SMSG_STABLE_RESULT, 1);
540 data << uint8(0x06);
541 SendPacket(&data);
542 return;
545 uint32 free_slot = 1;
547 QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
548 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
549 if(result)
553 Field *fields = result->Fetch();
555 uint32 slot = fields[1].GetUInt32();
557 // slots ordered in query, and if not equal then free
558 if(slot!=free_slot)
559 break;
561 // this slot not free, skip
562 ++free_slot;
563 }while( result->NextRow() );
565 delete result;
568 WorldPacket data(SMSG_STABLE_RESULT, 1);
569 if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
571 _player->RemovePet(pet,PetSaveMode(free_slot));
572 data << uint8(0x08);
574 else
575 data << uint8(0x06);
577 SendPacket(&data);
580 void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
582 sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
583 uint64 npcGUID;
584 uint32 petnumber;
586 recv_data >> npcGUID >> petnumber;
588 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
589 if (!unit)
591 sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
592 return;
595 // remove fake death
596 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
597 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
599 uint32 creature_id = 0;
602 QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
603 _player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
604 if(result)
606 Field *fields = result->Fetch();
607 creature_id = fields[0].GetUInt32();
608 delete result;
612 if(!creature_id)
614 WorldPacket data(SMSG_STABLE_RESULT, 1);
615 data << uint8(0x06);
616 SendPacket(&data);
617 return;
620 CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
621 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
623 WorldPacket data(SMSG_STABLE_RESULT, 1);
624 data << uint8(0x06);
625 SendPacket(&data);
626 return;
629 Pet* pet = _player->GetPet();
630 if(pet && pet->isAlive())
632 WorldPacket data(SMSG_STABLE_RESULT, 1);
633 data << uint8(0x06);
634 SendPacket(&data);
635 return;
638 // delete dead pet
639 if(pet)
640 _player->RemovePet(pet,PET_SAVE_AS_DELETED);
642 Pet *newpet = new Pet(HUNTER_PET);
643 if(!newpet->LoadPetFromDB(_player,creature_id,petnumber))
645 delete newpet;
646 newpet = NULL;
647 WorldPacket data(SMSG_STABLE_RESULT, 1);
648 data << uint8(0x06);
649 SendPacket(&data);
650 return;
653 WorldPacket data(SMSG_STABLE_RESULT, 1);
654 data << uint8(0x09);
655 SendPacket(&data);
658 void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
660 sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
661 uint64 npcGUID;
663 recv_data >> npcGUID;
665 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
666 if (!unit)
668 sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
669 return;
672 // remove fake death
673 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
674 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
676 WorldPacket data(SMSG_STABLE_RESULT, 200);
678 if(GetPlayer()->m_stableSlots < MAX_PET_STABLES)
680 StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
681 if(_player->GetMoney() >= SlotPrice->Price)
683 ++GetPlayer()->m_stableSlots;
684 _player->ModifyMoney(-int32(SlotPrice->Price));
685 data << uint8(0x0A); // success buy
687 else
688 data << uint8(0x06);
690 else
691 data << uint8(0x06);
693 SendPacket(&data);
696 void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */)
698 sLog.outDebug("HandleStableRevivePet: Not implemented");
701 void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
703 sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
704 uint64 npcGUID;
705 uint32 pet_number;
707 recv_data >> npcGUID >> pet_number;
709 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
710 if (!unit)
712 sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
713 return;
716 // remove fake death
717 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
718 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
721 Pet* pet = _player->GetPet();
723 if(!pet || pet->getPetType()!=HUNTER_PET)
724 return;
726 // find swapped pet slot in stable
727 QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
728 _player->GetGUIDLow(),pet_number);
729 if(!result)
730 return;
732 Field *fields = result->Fetch();
734 uint32 slot = fields[0].GetUInt32();
735 uint32 creature_id = fields[1].GetUInt32();
736 delete result;
738 if(!creature_id)
740 WorldPacket data(SMSG_STABLE_RESULT, 1);
741 data << uint8(0x06);
742 SendPacket(&data);
743 return;
746 CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
747 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
749 WorldPacket data(SMSG_STABLE_RESULT, 1);
750 data << uint8(0x06);
751 SendPacket(&data);
752 return;
755 // move alive pet to slot or delete dead pet
756 _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
758 WorldPacket data(SMSG_STABLE_RESULT, 1); // guess size
760 // summon unstabled pet
761 Pet *newpet = new Pet;
762 if(!newpet->LoadPetFromDB(_player,creature_id,pet_number))
764 delete newpet;
765 data << uint8(0x06);
767 else
768 data << uint8(0x09);
770 SendPacket(&data);
773 void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
775 sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
777 uint64 npcGUID, itemGUID;
778 uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
780 recv_data >> npcGUID >> itemGUID >> guildBank;
782 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR);
783 if (!unit)
785 sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
786 return;
789 // remove fake death
790 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
791 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
793 // reputation discount
794 float discountMod = _player->GetReputationPriceDiscount(unit);
796 uint32 TotalCost = 0;
797 if (itemGUID)
799 sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
801 Item* item = _player->GetItemByGuid(itemGUID);
803 if(item)
804 TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
806 else
808 sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
810 TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
812 if (guildBank)
814 uint32 GuildId = _player->GetGuildId();
815 if (!GuildId)
816 return;
817 Guild *pGuild = sObjectMgr.GetGuildById(GuildId);
818 if (!pGuild)
819 return;
820 pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
821 pGuild->SendMoneyInfo(this, _player->GetGUIDLow());