[9581] Fixed apply damage reduction to melee/ranged damage.
[getmangos.git] / src / game / NPCHandler.cpp
blob5519f22b0a6ecd131bf2f7a41295865861e7acee
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 ObjectGuid 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 // can vehicle have gossip? If so, need check for this also.
308 if (guid.IsCreatureOrPet())
310 Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
312 if (!pCreature)
314 sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
315 return;
318 if (!code.empty())
320 if (!Script->GossipSelectWithCode(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()))
321 _player->OnGossipSelect(pCreature, gossipListId, menuId);
323 else
325 if (!Script->GossipSelect(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)))
326 _player->OnGossipSelect(pCreature, gossipListId, menuId);
329 else if (guid.IsGameobject())
331 GameObject *pGo = GetPlayer()->GetGameObjectIfCanInteractWith(guid);
333 if (!pGo)
335 sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
336 return;
339 if (!code.empty())
341 if (!Script->GOGossipSelectWithCode(_player, pGo, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()))
342 _player->OnGossipSelect(pGo, gossipListId, menuId);
344 else
346 if (!Script->GOGossipSelect(_player, pGo, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)))
347 _player->OnGossipSelect(pGo, gossipListId, menuId);
352 void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
354 sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
356 uint64 guid;
358 recv_data >> guid;
360 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
361 if (!unit)
363 sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
364 return;
367 // remove fake death
368 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
369 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
371 SendSpiritResurrect();
374 void WorldSession::SendSpiritResurrect()
376 _player->ResurrectPlayer(0.5f, true);
378 _player->DurabilityLossAll(0.25f,true);
380 // get corpse nearest graveyard
381 WorldSafeLocsEntry const *corpseGrave = NULL;
382 Corpse *corpse = _player->GetCorpse();
383 if(corpse)
384 corpseGrave = sObjectMgr.GetClosestGraveYard(
385 corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam() );
387 // now can spawn bones
388 _player->SpawnCorpseBones();
390 // teleport to nearest from corpse graveyard, if different from nearest to player ghost
391 if(corpseGrave)
393 WorldSafeLocsEntry const *ghostGrave = sObjectMgr.GetClosestGraveYard(
394 _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam() );
396 if(corpseGrave != ghostGrave)
397 _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
398 // or update at original position
399 else
400 _player->UpdateVisibilityForPlayer();
402 // or update at original position
403 else
404 _player->UpdateVisibilityForPlayer();
407 void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
409 uint64 npcGUID;
410 recv_data >> npcGUID;
412 if(!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
413 return;
415 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
416 if (!unit)
418 sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
419 return;
422 // remove fake death
423 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
424 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
426 SendBindPoint(unit);
429 void WorldSession::SendBindPoint(Creature *npc)
431 // prevent set homebind to instances in any case
432 if(GetPlayer()->GetMap()->Instanceable())
433 return;
435 // send spell for bind 3286 bind magic
436 npc->CastSpell(_player, 3286, true); // Bind
438 WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
439 data << uint64(npc->GetGUID());
440 data << uint32(3286); // Bind
441 SendPacket( &data );
443 _player->PlayerTalkClass->CloseGossip();
446 void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
448 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
449 uint64 npcGUID;
451 recv_data >> npcGUID;
453 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
454 if (!unit)
456 sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
457 return;
460 // remove fake death
461 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
462 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
464 SendStablePet(npcGUID);
467 void WorldSession::SendStablePet(uint64 guid )
469 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
471 WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
472 data << uint64 ( guid );
474 Pet *pet = _player->GetPet();
476 size_t wpos = data.wpos();
477 data << uint8(0); // place holder for slot show number
479 data << uint8(GetPlayer()->m_stableSlots);
481 uint8 num = 0; // counter for place holder
483 // not let move dead pet in slot
484 if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET)
486 data << uint32(pet->GetCharmInfo()->GetPetNumber());
487 data << uint32(pet->GetEntry());
488 data << uint32(pet->getLevel());
489 data << pet->GetName(); // petname
490 data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
491 ++num;
494 // 0 1 2 3 4
495 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",
496 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
498 if(result)
502 Field *fields = result->Fetch();
504 data << uint32(fields[1].GetUInt32()); // petnumber
505 data << uint32(fields[2].GetUInt32()); // creature entry
506 data << uint32(fields[3].GetUInt32()); // level
507 data << fields[4].GetString(); // name
508 data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
510 ++num;
511 }while( result->NextRow() );
513 delete result;
516 data.put<uint8>(wpos, num); // set real data to placeholder
517 SendPacket(&data);
520 void WorldSession::HandleStablePet( WorldPacket & recv_data )
522 sLog.outDebug("WORLD: Recv CMSG_STABLE_PET");
523 uint64 npcGUID;
525 recv_data >> npcGUID;
527 if(!GetPlayer()->isAlive())
528 return;
530 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
531 if (!unit)
533 sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
534 return;
537 // remove fake death
538 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
539 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
541 Pet *pet = _player->GetPet();
543 // can't place in stable dead pet
544 if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET)
546 WorldPacket data(SMSG_STABLE_RESULT, 1);
547 data << uint8(0x06);
548 SendPacket(&data);
549 return;
552 uint32 free_slot = 1;
554 QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
555 _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
556 if(result)
560 Field *fields = result->Fetch();
562 uint32 slot = fields[1].GetUInt32();
564 // slots ordered in query, and if not equal then free
565 if(slot!=free_slot)
566 break;
568 // this slot not free, skip
569 ++free_slot;
570 }while( result->NextRow() );
572 delete result;
575 WorldPacket data(SMSG_STABLE_RESULT, 1);
576 if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
578 _player->RemovePet(pet,PetSaveMode(free_slot));
579 data << uint8(0x08);
581 else
582 data << uint8(0x06);
584 SendPacket(&data);
587 void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
589 sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
590 uint64 npcGUID;
591 uint32 petnumber;
593 recv_data >> npcGUID >> petnumber;
595 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
596 if (!unit)
598 sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
599 return;
602 // remove fake death
603 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
604 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
606 uint32 creature_id = 0;
609 QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
610 _player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
611 if(result)
613 Field *fields = result->Fetch();
614 creature_id = fields[0].GetUInt32();
615 delete result;
619 if(!creature_id)
621 WorldPacket data(SMSG_STABLE_RESULT, 1);
622 data << uint8(0x06);
623 SendPacket(&data);
624 return;
627 CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
628 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
630 WorldPacket data(SMSG_STABLE_RESULT, 1);
631 data << uint8(0x06);
632 SendPacket(&data);
633 return;
636 Pet* pet = _player->GetPet();
637 if(pet && pet->isAlive())
639 WorldPacket data(SMSG_STABLE_RESULT, 1);
640 data << uint8(0x06);
641 SendPacket(&data);
642 return;
645 // delete dead pet
646 if(pet)
647 _player->RemovePet(pet,PET_SAVE_AS_DELETED);
649 Pet *newpet = new Pet(HUNTER_PET);
650 if(!newpet->LoadPetFromDB(_player,creature_id,petnumber))
652 delete newpet;
653 newpet = NULL;
654 WorldPacket data(SMSG_STABLE_RESULT, 1);
655 data << uint8(0x06);
656 SendPacket(&data);
657 return;
660 WorldPacket data(SMSG_STABLE_RESULT, 1);
661 data << uint8(0x09);
662 SendPacket(&data);
665 void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
667 sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
668 uint64 npcGUID;
670 recv_data >> npcGUID;
672 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
673 if (!unit)
675 sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
676 return;
679 // remove fake death
680 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
681 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
683 WorldPacket data(SMSG_STABLE_RESULT, 200);
685 if(GetPlayer()->m_stableSlots < MAX_PET_STABLES)
687 StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
688 if(_player->GetMoney() >= SlotPrice->Price)
690 ++GetPlayer()->m_stableSlots;
691 _player->ModifyMoney(-int32(SlotPrice->Price));
692 data << uint8(0x0A); // success buy
694 else
695 data << uint8(0x06);
697 else
698 data << uint8(0x06);
700 SendPacket(&data);
703 void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */)
705 sLog.outDebug("HandleStableRevivePet: Not implemented");
708 void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
710 sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
711 uint64 npcGUID;
712 uint32 pet_number;
714 recv_data >> npcGUID >> pet_number;
716 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
717 if (!unit)
719 sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
720 return;
723 // remove fake death
724 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
725 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
728 Pet* pet = _player->GetPet();
730 if(!pet || pet->getPetType()!=HUNTER_PET)
731 return;
733 // find swapped pet slot in stable
734 QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
735 _player->GetGUIDLow(),pet_number);
736 if(!result)
737 return;
739 Field *fields = result->Fetch();
741 uint32 slot = fields[0].GetUInt32();
742 uint32 creature_id = fields[1].GetUInt32();
743 delete result;
745 if(!creature_id)
747 WorldPacket data(SMSG_STABLE_RESULT, 1);
748 data << uint8(0x06);
749 SendPacket(&data);
750 return;
753 CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
754 if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
756 WorldPacket data(SMSG_STABLE_RESULT, 1);
757 data << uint8(0x06);
758 SendPacket(&data);
759 return;
762 // move alive pet to slot or delete dead pet
763 _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
765 WorldPacket data(SMSG_STABLE_RESULT, 1); // guess size
767 // summon unstabled pet
768 Pet *newpet = new Pet;
769 if(!newpet->LoadPetFromDB(_player,creature_id,pet_number))
771 delete newpet;
772 data << uint8(0x06);
774 else
775 data << uint8(0x09);
777 SendPacket(&data);
780 void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
782 sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
784 uint64 npcGUID, itemGUID;
785 uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
787 recv_data >> npcGUID >> itemGUID >> guildBank;
789 Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR);
790 if (!unit)
792 sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
793 return;
796 // remove fake death
797 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
798 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
800 // reputation discount
801 float discountMod = _player->GetReputationPriceDiscount(unit);
803 uint32 TotalCost = 0;
804 if (itemGUID)
806 sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
808 Item* item = _player->GetItemByGuid(itemGUID);
810 if(item)
811 TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
813 else
815 sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
817 TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
819 if (guildBank)
821 uint32 GuildId = _player->GetGuildId();
822 if (!GuildId)
823 return;
824 Guild *pGuild = sObjectMgr.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());