Merge commit 'mangos/master'
[auctionmangos.git] / src / game / NPCHandler.cpp
blob46a2b8ebd66b0aeb678ebce5364462494ff19b0f
1 /*
2 * Copyright (C) 2005-2008 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 "World.h"
27 #include "ObjectMgr.h"
28 #include "SpellMgr.h"
29 #include "Player.h"
30 #include "GossipDef.h"
31 #include "SpellAuras.h"
32 #include "UpdateMask.h"
33 #include "ScriptCalls.h"
34 #include "ObjectAccessor.h"
35 #include "Creature.h"
36 #include "MapManager.h"
37 #include "Pet.h"
38 #include "BattleGroundMgr.h"
39 #include "BattleGround.h"
40 #include "Guild.h"
42 void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data )
44 CHECK_PACKET_SIZE(recv_data,8);
46 uint64 guid;
47 recv_data >> guid;
49 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TABARDDESIGNER);
50 if (!unit)
52 sLog.outDebug( "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
53 return;
56 // remove fake death
57 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
58 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
60 SendTabardVendorActivate(guid);
63 void WorldSession::SendTabardVendorActivate( uint64 guid )
65 WorldPacket data( MSG_TABARDVENDOR_ACTIVATE, 8 );
66 data << guid;
67 SendPacket( &data );
70 void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data )
72 CHECK_PACKET_SIZE(recv_data,8);
74 uint64 guid;
76 sLog.outDebug( "WORLD: Received CMSG_BANKER_ACTIVATE" );
78 recv_data >> guid;
80 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_BANKER);
81 if (!unit)
83 sLog.outDebug( "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
84 return;
87 // remove fake death
88 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
89 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
91 SendShowBank(guid);
94 void WorldSession::SendShowBank( uint64 guid )
96 WorldPacket data( SMSG_SHOW_BANK, 8 );
97 data << guid;
98 SendPacket( &data );
101 void WorldSession::HandleTrainerListOpcode( WorldPacket & recv_data )
103 CHECK_PACKET_SIZE(recv_data,8);
105 uint64 guid;
107 recv_data >> guid;
108 SendTrainerList( guid );
111 void WorldSession::SendTrainerList( uint64 guid )
113 std::string str = GetMangosString(LANG_NPC_TAINER_HELLO);
114 SendTrainerList( guid, str );
117 void WorldSession::SendTrainerList( uint64 guid,std::string strTitle )
119 sLog.outDebug( "WORLD: SendTrainerList" );
121 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TRAINER);
122 if (!unit)
124 sLog.outDebug( "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
125 return;
128 // remove fake death
129 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
130 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
132 // trainer list loaded at check;
133 if(!unit->isCanTrainingOf(_player,true))
134 return;
136 CreatureInfo const *ci = unit->GetCreatureInfo();
138 if (!ci)
140 sLog.outDebug( "WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!",GUID_LOPART(guid) );
141 return;
144 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
145 if(!trainer_spells)
147 sLog.outDebug( "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)",
148 GUID_LOPART(guid), unit->GetEntry());
149 return;
152 WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1);
153 data << guid;
154 data << uint32(trainer_spells->trainerType);
156 size_t count_pos = data.wpos();
157 data << uint32(trainer_spells->spellList.size());
159 // reputation discount
160 float fDiscountMod = _player->GetReputationPriceDiscount(unit);
162 uint32 count = 0;
163 for(TrainerSpellList::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
165 TrainerSpell const* tSpell = *itr;
167 if(!_player->IsSpellFitByClassAndRace(tSpell->spell))
168 continue;
170 ++count;
172 bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->spell);
174 SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->spell);
176 data << uint32(tSpell->spell);
177 data << uint8(_player->GetTrainerSpellState(tSpell));
178 data << uint32(floor(tSpell->spellcost * fDiscountMod));
180 data << uint32(primary_prof_first_rank ? 1 : 0); // primary prof. learn confirmation dialog
181 data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
182 data << uint8(tSpell->reqlevel);
183 data << uint32(tSpell->reqskill);
184 data << uint32(tSpell->reqskillvalue);
185 data << uint32(chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
186 data << uint32(chain_node && chain_node->prev ? chain_node->req : 0);
187 data << uint32(0);
190 data << strTitle;
192 data.put<uint32>(count_pos,count);
193 SendPacket( &data );
196 void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
198 CHECK_PACKET_SIZE(recv_data,8+4);
200 uint64 guid;
201 uint32 spellId = 0;
203 recv_data >> guid >> spellId;
204 sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId );
206 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_TRAINER);
207 if (!unit)
209 sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
210 return;
213 // remove fake death
214 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
215 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
217 if(!unit->isCanTrainingOf(_player,true))
218 return;
220 // check present spell in trainer spell list
221 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
222 if(!trainer_spells)
223 return;
225 // not found, cheat?
226 TrainerSpell const* trainer_spell = trainer_spells->Find(spellId);
227 if(!trainer_spell)
228 return;
230 // can't be learn, cheat? Or double learn with lags...
231 if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
232 return;
234 // apply reputation discount
235 uint32 nSpellCost = uint32(floor(trainer_spell->spellcost * _player->GetReputationPriceDiscount(unit)));
237 // check money requirement
238 if(_player->GetMoney() < nSpellCost )
239 return;
241 WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
242 data << uint64(guid) << uint32(0xB3);
243 SendPacket(&data);
245 data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player
246 data << uint64(_player->GetGUID()) << uint32(0x016A);
247 SendPacket(&data);
249 _player->ModifyMoney( -int32(nSpellCost) );
251 // learn explicitly to prevent lost money at lags, learning spell will be only show spell animation
252 _player->learnSpell(trainer_spell->spell);
254 data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
255 data << uint64(guid) << uint32(spellId);
256 SendPacket(&data);
259 void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data )
261 CHECK_PACKET_SIZE(recv_data,8);
263 sLog.outDebug( "WORLD: Received CMSG_GOSSIP_HELLO" );
265 uint64 guid;
266 recv_data >> guid;
268 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE);
269 if (!unit)
271 sLog.outDebug( "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
272 return;
275 // remove fake death
276 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
277 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
279 if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider())
281 unit->StopMoving();
284 // If spiritguide, no need for gossip menu, just put player into resurrect queue
285 if (unit->isSpiritGuide())
287 BattleGround *bg = _player->GetBattleGround();
288 if(bg)
290 bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID());
291 sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID());
292 return;
296 if(!Script->GossipHello( _player, unit ))
298 _player->TalkedToCreature(unit->GetEntry(),unit->GetGUID());
299 unit->prepareGossipMenu(_player);
300 unit->sendPreparedGossip(_player);
304 void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
306 CHECK_PACKET_SIZE(recv_data,8+4+4);
308 sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
310 uint32 option;
311 uint32 unk;
312 uint64 guid;
313 std::string code = "";
315 recv_data >> guid >> unk >> option;
317 if(_player->PlayerTalkClass->GossipOptionCoded( option ))
319 // recheck
320 CHECK_PACKET_SIZE(recv_data,8+4+1);
321 sLog.outBasic("reading string");
322 recv_data >> code;
323 sLog.outBasic("string read: %s", code.c_str());
326 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE);
327 if (!unit)
329 sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
330 return;
333 // remove fake death
334 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
335 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
337 if(!code.empty())
339 if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction( option ), code.c_str()))
340 unit->OnGossipSelect (_player, option);
342 else
344 if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option)))
345 unit->OnGossipSelect (_player, option);
349 void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
351 CHECK_PACKET_SIZE(recv_data,8);
353 sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
355 uint64 guid;
357 recv_data >> guid;
359 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_SPIRITHEALER);
360 if (!unit)
362 sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
363 return;
366 // remove fake death
367 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
368 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
370 SendSpiritResurrect();
373 void WorldSession::SendSpiritResurrect()
375 _player->ResurrectPlayer(0.5f, true);
377 _player->DurabilityLossAll(0.25f,true);
379 // get corpse nearest graveyard
380 WorldSafeLocsEntry const *corpseGrave = NULL;
381 Corpse *corpse = _player->GetCorpse();
382 if(corpse)
383 corpseGrave = objmgr.GetClosestGraveYard(
384 corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam() );
386 // now can spawn bones
387 _player->SpawnCorpseBones();
389 // teleport to nearest from corpse graveyard, if different from nearest to player ghost
390 if(corpseGrave)
392 WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard(
393 _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam() );
395 if(corpseGrave != ghostGrave)
396 _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
397 // or update at original position
398 else
399 ObjectAccessor::UpdateVisibilityForPlayer(_player);
401 // or update at original position
402 else
403 ObjectAccessor::UpdateVisibilityForPlayer(_player);
405 _player->SaveToDB();
408 void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
410 CHECK_PACKET_SIZE(recv_data,8);
412 uint64 npcGUID;
413 recv_data >> npcGUID;
415 if(!GetPlayer()->isAlive())
416 return;
418 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID,UNIT_NPC_FLAG_INNKEEPER);
419 if (!unit)
421 sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
422 return;
425 // remove fake death
426 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
427 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
429 SendBindPoint(unit);
432 void WorldSession::SendBindPoint(Creature *npc)
434 uint32 bindspell = 3286;
436 // update sql homebind
437 CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), _player->GetZoneId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
438 _player->m_homebindMapId = _player->GetMapId();
439 _player->m_homebindZoneId = _player->GetZoneId();
440 _player->m_homebindX = _player->GetPositionX();
441 _player->m_homebindY = _player->GetPositionY();
442 _player->m_homebindZ = _player->GetPositionZ();
444 // send spell for bind 3286 bind magic
445 npc->CastSpell(_player, bindspell, true);
447 WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
448 data << npc->GetGUID();
449 data << bindspell;
450 SendPacket( &data );
452 // binding
453 data.Initialize( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) );
454 data << float(_player->GetPositionX());
455 data << float(_player->GetPositionY());
456 data << float(_player->GetPositionZ());
457 data << uint32(_player->GetMapId());
458 data << uint32(_player->GetZoneId());
459 SendPacket( &data );
461 DEBUG_LOG("New Home Position X is %f",_player->GetPositionX());
462 DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY());
463 DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ());
464 DEBUG_LOG("New Home MapId is %u",_player->GetMapId());
465 DEBUG_LOG("New Home ZoneId is %u",_player->GetZoneId());
467 // zone update
468 data.Initialize( SMSG_PLAYERBOUND, 8+4 );
469 data << uint64(_player->GetGUID());
470 data << uint32(_player->GetZoneId());
471 SendPacket( &data );
473 _player->PlayerTalkClass->CloseGossip();
476 //Need fix
477 void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
479 CHECK_PACKET_SIZE(recv_data,8);
481 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS");
482 uint64 npcGUID;
484 recv_data >> npcGUID;
486 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
487 if (!unit)
489 sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
490 return;
493 // remove fake death
494 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
495 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
497 SendStablePet(npcGUID);
500 void WorldSession::SendStablePet(uint64 guid )
502 sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
504 WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
505 data << uint64 ( guid );
507 Pet *pet = _player->GetPet();
509 data << uint8(0); // place holder for slot show number
510 data << uint8(GetPlayer()->m_stableSlots);
512 uint8 num = 0; // counter for place holder
514 // not let move dead pet in slot
515 if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET)
517 data << uint32(pet->GetCharmInfo()->GetPetNumber());
518 data << uint32(pet->GetEntry());
519 data << uint32(pet->getLevel());
520 data << pet->GetName(); // petname
521 data << uint32(pet->GetLoyaltyLevel()); // loyalty
522 data << uint8(0x01); // client slot 1 == current pet (0)
523 ++num;
526 // 0 1 2 3 4 5 6
527 QueryResult* result = CharacterDatabase.PQuery("SELECT owner, slot, id, entry, level, loyalty, name FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow());
529 if(result)
533 Field *fields = result->Fetch();
535 data << uint32(fields[2].GetUInt32()); // petnumber
536 data << uint32(fields[3].GetUInt32()); // creature entry
537 data << uint32(fields[4].GetUInt32()); // level
538 data << fields[6].GetString(); // name
539 data << uint32(fields[5].GetUInt32()); // loyalty
540 data << uint8(fields[1].GetUInt32()+1); // slot
542 ++num;
543 }while( result->NextRow() );
545 delete result;
548 data.put<uint8>(8, num); // set real data to placeholder
549 SendPacket(&data);
552 void WorldSession::HandleStablePet( WorldPacket & recv_data )
554 CHECK_PACKET_SIZE(recv_data,8);
556 sLog.outDebug("WORLD: Recv CMSG_STABLE_PET not dispose.");
557 uint64 npcGUID;
559 recv_data >> npcGUID;
561 if(!GetPlayer()->isAlive())
562 return;
564 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
565 if (!unit)
567 sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
568 return;
571 // remove fake death
572 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
573 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
575 Pet *pet = _player->GetPet();
577 WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
579 // can't place in stable dead pet
580 if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET)
582 data << uint8(0x06);
583 SendPacket(&data);
584 return;
587 uint32 free_slot = 1;
589 QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3 ORDER BY slot ",_player->GetGUIDLow());
590 if(result)
594 Field *fields = result->Fetch();
596 uint32 slot = fields[1].GetUInt32();
598 if(slot==free_slot) // this slot not free
599 ++free_slot;
600 }while( result->NextRow() );
602 delete result;
604 if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
606 _player->RemovePet(pet,PetSaveMode(free_slot));
607 data << uint8(0x08);
609 else
610 data << uint8(0x06);
612 SendPacket(&data);
615 void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
617 CHECK_PACKET_SIZE(recv_data,8+4);
619 sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET.");
620 uint64 npcGUID;
621 uint32 petnumber;
623 recv_data >> npcGUID >> petnumber;
625 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
626 if (!unit)
628 sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
629 return;
632 // remove fake death
633 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
634 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
636 WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
638 Pet* pet = _player->GetPet();
639 if(pet && pet->isAlive())
641 uint8 i = 0x06;
642 data << uint8(i);
643 SendPacket(&data);
644 return;
647 // delete dead pet
648 if(pet)
649 _player->RemovePet(pet,PET_SAVE_AS_DELETED);
651 Pet *newpet = NULL;
653 QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow(),petnumber);
654 if(result)
656 Field *fields = result->Fetch();
657 uint32 petentry = fields[0].GetUInt32();
659 newpet = new Pet(HUNTER_PET);
660 if(!newpet->LoadPetFromDB(_player,petentry,petnumber))
662 delete newpet;
663 newpet = NULL;
665 delete result;
668 if(newpet)
669 data << uint8(0x09);
670 else
671 data << uint8(0x06);
672 SendPacket(&data);
675 void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
677 CHECK_PACKET_SIZE(recv_data,8);
679 sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
680 uint64 npcGUID;
682 recv_data >> npcGUID;
684 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
685 if (!unit)
687 sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
688 return;
691 // remove fake death
692 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
693 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
695 WorldPacket data(SMSG_STABLE_RESULT, 200);
697 if(GetPlayer()->m_stableSlots < 2) // max slots amount = 2
699 StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
700 if(_player->GetMoney() >= SlotPrice->Price)
702 ++GetPlayer()->m_stableSlots;
703 _player->ModifyMoney(-int32(SlotPrice->Price));
704 data << uint8(0x0A); // success buy
706 else
707 data << uint8(0x06);
709 else
710 data << uint8(0x06);
712 SendPacket(&data);
715 void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */)
717 sLog.outDebug("HandleStableRevivePet: Not implemented");
720 void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
722 CHECK_PACKET_SIZE(recv_data,8+4);
724 sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET.");
725 uint64 npcGUID;
726 uint32 pet_number;
728 recv_data >> npcGUID >> pet_number;
730 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
731 if (!unit)
733 sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
734 return;
737 // remove fake death
738 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
739 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
741 WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
743 Pet* pet = _player->GetPet();
745 if(!pet || pet->getPetType()!=HUNTER_PET)
746 return;
748 // find swapped pet slot in stable
749 QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",_player->GetGUIDLow(),pet_number);
750 if(!result)
751 return;
753 Field *fields = result->Fetch();
755 uint32 slot = fields[0].GetUInt32();
756 uint32 petentry = fields[1].GetUInt32();
757 delete result;
759 // move alive pet to slot or delele dead pet
760 _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
762 // summon unstabled pet
763 Pet *newpet = new Pet;
764 if(!newpet->LoadPetFromDB(_player,petentry,pet_number))
766 delete newpet;
767 data << uint8(0x06);
769 else
770 data << uint8(0x09);
772 SendPacket(&data);
775 void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
777 CHECK_PACKET_SIZE(recv_data,8+8+1);
779 sLog.outDebug("WORLD: CMSG_REPAIR_ITEM");
781 uint64 npcGUID, itemGUID;
782 uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
784 recv_data >> npcGUID >> itemGUID >> guildBank;
786 Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_REPAIR);
787 if (!unit)
789 sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
790 return;
793 // remove fake death
794 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
795 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
797 // reputation discount
798 float discountMod = _player->GetReputationPriceDiscount(unit);
800 uint32 TotalCost = 0;
801 if (itemGUID)
803 sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID));
805 Item* item = _player->GetItemByGuid(itemGUID);
807 if(item)
808 TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false);
810 else
812 sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID));
814 TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false);
816 if (guildBank)
818 uint32 GuildId = _player->GetGuildId();
819 if (!GuildId)
820 return;
821 Guild *pGuild = objmgr.GetGuildById(GuildId);
822 if (!pGuild)
823 return;
824 pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
825 pGuild->SendMoneyInfo(this, _player->GetGUIDLow());