server/src/game/NPCHandler.cpp
VladimirMangos cf685da47a [11139] Use for Creature/GameObject local per-map guids
* Creature/GameObject guid generators moved to Map
* For avoid wrong not converted cases generic function in ObjectMgr has been replaced by
  specilized guid generation function like sObjectMgr.GeneratePlayerLowGuid().
  This let catch all cases that need update in custom code or scripts.
* Drop many ObjectAcessor.h now dead code. This is also make mangos more thread safe.
* Restore one more time unix build broken in prev. commits.

Note: many cases when something not wotk in instance but work in continents
possible magicly start work after this commit. For example, some gm commands.
From large systems that need more chnages for start work in full power in instances
can be referecned pool/gamevent system. Last need just small hacks drop changes but
in will addded in independent commit.
2011-02-12 09:52:16 +03:00

880 lines
27 KiB
C++

/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Language.h"
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "GossipDef.h"
#include "UpdateMask.h"
#include "ScriptMgr.h"
#include "Creature.h"
#include "Pet.h"
#include "Guild.h"
#include "Chat.h"
enum StableResultCode
{
STABLE_ERR_MONEY = 0x01, // "you don't have enough money"
STABLE_ERR_STABLE = 0x06, // currently used in most fail cases
STABLE_SUCCESS_STABLE = 0x08, // stable success
STABLE_SUCCESS_UNSTABLE = 0x09, // unstable/swap success
STABLE_SUCCESS_BUY_SLOT = 0x0A, // buy slot success
STABLE_ERR_EXOTIC = 0x0C, // "you are unable to control exotic creatures"
};
void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data )
{
ObjectGuid guid;
recv_data >> guid;
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TABARDDESIGNER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleTabardVendorActivateOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendTabardVendorActivate(guid);
}
void WorldSession::SendTabardVendorActivate(ObjectGuid guid)
{
WorldPacket data( MSG_TABARDVENDOR_ACTIVATE, 8 );
data << ObjectGuid(guid);
SendPacket(&data);
}
void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data )
{
ObjectGuid guid;
DEBUG_LOG("WORLD: Received CMSG_BANKER_ACTIVATE");
recv_data >> guid;
if (!CheckBanker(guid))
return;
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendShowBank(guid);
}
void WorldSession::SendShowBank(ObjectGuid guid)
{
WorldPacket data(SMSG_SHOW_BANK, 8);
data << ObjectGuid(guid);
SendPacket(&data);
}
void WorldSession::HandleTrainerListOpcode( WorldPacket & recv_data )
{
ObjectGuid guid;
recv_data >> guid;
SendTrainerList(guid);
}
void WorldSession::SendTrainerList(ObjectGuid guid)
{
std::string str = GetMangosString(LANG_NPC_TAINER_HELLO);
SendTrainerList(guid, str);
}
static void SendTrainerSpellHelper(WorldPacket& data, TrainerSpell const* tSpell, TrainerSpellState state, float fDiscountMod, bool can_learn_primary_prof)
{
bool primary_prof_first_rank = sSpellMgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
SpellChainNode const* chain_node = sSpellMgr.GetSpellChainNode(tSpell->learnedSpell);
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
data << uint8(state==TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
data << uint32(floor(tSpell->spellCost * fDiscountMod));
data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
// primary prof. learn confirmation dialog
data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
data << uint8(tSpell->reqLevel);
data << uint32(tSpell->reqSkill);
data << uint32(tSpell->reqSkillValue);
data << uint32(!tSpell->IsCastable() && chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->req : 0);
data << uint32(0);
}
void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle)
{
DEBUG_LOG( "WORLD: SendTrainerList" );
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
DEBUG_LOG("WORLD: SendTrainerList - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
// trainer list loaded at check;
if (!unit->IsTrainerOf(_player,true))
return;
CreatureInfo const *ci = unit->GetCreatureInfo();
if (!ci)
return;
TrainerSpellData const* cSpells = unit->GetTrainerSpells();
TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells();
if (!cSpells && !tSpells)
{
DEBUG_LOG("WORLD: SendTrainerList - Training spells not found for %s", guid.GetString().c_str());
return;
}
uint32 maxcount = (cSpells ? cSpells->spellList.size() : 0) + (tSpells ? tSpells->spellList.size() : 0);
uint32 trainer_type = cSpells && cSpells->trainerType ? cSpells->trainerType : (tSpells ? tSpells->trainerType : 0);
WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+maxcount*38 + strTitle.size()+1);
data << ObjectGuid(guid);
data << uint32(trainer_type);
size_t count_pos = data.wpos();
data << uint32(maxcount);
// reputation discount
float fDiscountMod = _player->GetReputationPriceDiscount(unit);
bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0;
uint32 count = 0;
if (cSpells)
{
for(TrainerSpellMap::const_iterator itr = cSpells->spellList.begin(); itr != cSpells->spellList.end(); ++itr)
{
TrainerSpell const* tSpell = &itr->second;
if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
continue;
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
SendTrainerSpellHelper(data, tSpell, state, fDiscountMod, can_learn_primary_prof);
++count;
}
}
if (tSpells)
{
for(TrainerSpellMap::const_iterator itr = tSpells->spellList.begin(); itr != tSpells->spellList.end(); ++itr)
{
TrainerSpell const* tSpell = &itr->second;
if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
continue;
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
SendTrainerSpellHelper(data, tSpell, state, fDiscountMod, can_learn_primary_prof);
++count;
}
}
data << strTitle;
data.put<uint32>(count_pos,count);
SendPacket(&data);
}
void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
{
ObjectGuid guid;
uint32 spellId = 0;
recv_data >> guid >> spellId;
DEBUG_LOG("WORLD: Received CMSG_TRAINER_BUY_SPELL Trainer: %s, learn spell id is: %u", guid.GetString().c_str(), spellId);
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleTrainerBuySpellOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if (!unit->IsTrainerOf(_player, true))
return;
// check present spell in trainer spell list
TrainerSpellData const* cSpells = unit->GetTrainerSpells();
TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells();
if (!cSpells && !tSpells)
return;
// not found, cheat?
TrainerSpell const* trainer_spell = cSpells->Find(spellId);
if (!trainer_spell && tSpells)
trainer_spell = tSpells->Find(spellId);
if (!trainer_spell)
return;
// can't be learn, cheat? Or double learn with lags...
if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
return;
// apply reputation discount
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
// check money requirement
if(_player->GetMoney() < nSpellCost )
return;
_player->ModifyMoney( -int32(nSpellCost) );
WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
data << ObjectGuid(guid);
data << uint32(0xB3); // index from SpellVisualKit.dbc
SendPacket(&data);
data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player
data << _player->GetObjectGuid();
data << uint32(0x016A); // index from SpellVisualKit.dbc
SendPacket(&data);
// learn explicitly or cast explicitly
if(trainer_spell->IsCastable())
_player->CastSpell(_player, trainer_spell->spell, true);
else
_player->learnSpell(spellId, false);
data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
data << ObjectGuid(guid);
data << uint32(spellId); // should be same as in packet from client
SendPacket(&data);
}
void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data)
{
DEBUG_LOG("WORLD: Received CMSG_GOSSIP_HELLO");
ObjectGuid guid;
recv_data >> guid;
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!pCreature)
{
DEBUG_LOG("WORLD: HandleGossipHelloOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if (!pCreature->IsStopped())
pCreature->StopMoving();
if (pCreature->isSpiritGuide())
pCreature->SendAreaSpiritHealerQueryOpcode(_player);
if (!sScriptMgr.OnGossipHello(_player, pCreature))
{
_player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId);
_player->SendPreparedGossip(pCreature);
}
}
void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: CMSG_GOSSIP_SELECT_OPTION");
uint32 gossipListId;
uint32 menuId;
ObjectGuid guid;
std::string code;
recv_data >> guid >> menuId >> gossipListId;
if (_player->PlayerTalkClass->GossipOptionCoded(gossipListId))
{
recv_data >> code;
DEBUG_LOG("Gossip code: %s", code.c_str());
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
uint32 sender = _player->PlayerTalkClass->GossipOptionSender(gossipListId);
uint32 action = _player->PlayerTalkClass->GossipOptionAction(gossipListId);
if (guid.IsAnyTypeCreature())
{
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!pCreature)
{
DEBUG_LOG("WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
return;
}
if (!sScriptMgr.OnGossipSelect(_player, pCreature, sender, action, code.empty() ? NULL : code.c_str()))
_player->OnGossipSelect(pCreature, gossipListId, menuId);
}
else if (guid.IsGameObject())
{
GameObject *pGo = GetPlayer()->GetGameObjectIfCanInteractWith(guid);
if (!pGo)
{
DEBUG_LOG("WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
return;
}
if (!sScriptMgr.OnGossipSelect(_player, pGo, sender, action, code.empty() ? NULL : code.c_str()))
_player->OnGossipSelect(pGo, gossipListId, menuId);
}
}
void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
ObjectGuid guid;
recv_data >> guid;
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
if (!unit)
{
DEBUG_LOG( "WORLD: HandleSpiritHealerActivateOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendSpiritResurrect();
}
void WorldSession::SendSpiritResurrect()
{
_player->ResurrectPlayer(0.5f, true);
_player->DurabilityLossAll(0.25f,true);
// get corpse nearest graveyard
WorldSafeLocsEntry const *corpseGrave = NULL;
Corpse *corpse = _player->GetCorpse();
if(corpse)
corpseGrave = sObjectMgr.GetClosestGraveYard(
corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam());
// now can spawn bones
_player->SpawnCorpseBones();
// teleport to nearest from corpse graveyard, if different from nearest to player ghost
if(corpseGrave)
{
WorldSafeLocsEntry const *ghostGrave = sObjectMgr.GetClosestGraveYard(
_player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam());
if(corpseGrave != ghostGrave)
_player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
// or update at original position
else
{
_player->GetCamera().UpdateVisibilityForOwner();
_player->UpdateObjectVisibility();
}
}
// or update at original position
else
{
_player->GetCamera().UpdateVisibilityForOwner();
_player->UpdateObjectVisibility();
}
}
void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
{
ObjectGuid npcGuid;
recv_data >> npcGuid;
if(!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
return;
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGuid,UNIT_NPC_FLAG_INNKEEPER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleBinderActivateOpcode - %s not found or you can't interact with him.", npcGuid.GetString().c_str());
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendBindPoint(unit);
}
void WorldSession::SendBindPoint(Creature *npc)
{
// prevent set homebind to instances in any case
if(GetPlayer()->GetMap()->Instanceable())
return;
// send spell for bind 3286 bind magic
npc->CastSpell(_player, 3286, true); // Bind
WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
data << npc->GetObjectGuid();
data << uint32(3286); // Bind
SendPacket( &data );
_player->PlayerTalkClass->CloseGossip();
}
void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: Recv MSG_LIST_STABLED_PETS");
ObjectGuid npcGUID;
recv_data >> npcGUID;
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
if (!unit)
{
DEBUG_LOG( "WORLD: HandleListStabledPetsOpcode - %s not found or you can't interact with him.", npcGUID.GetString().c_str());
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendStablePet(npcGUID);
}
void WorldSession::SendStablePet( ObjectGuid guid )
{
DEBUG_LOG("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
data << guid;
Pet *pet = _player->GetPet();
size_t wpos = data.wpos();
data << uint8(0); // place holder for slot show number
data << uint8(GetPlayer()->m_stableSlots);
uint8 num = 0; // counter for place holder
// not let move dead pet in slot
if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET)
{
data << uint32(pet->GetCharmInfo()->GetPetNumber());
data << uint32(pet->GetEntry());
data << uint32(pet->getLevel());
data << pet->GetName(); // petname
data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
++num;
}
// 0 1 2 3 4
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",
_player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
if(result)
{
do
{
Field *fields = result->Fetch();
data << uint32(fields[1].GetUInt32()); // petnumber
data << uint32(fields[2].GetUInt32()); // creature entry
data << uint32(fields[3].GetUInt32()); // level
data << fields[4].GetString(); // name
data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
++num;
}while( result->NextRow() );
delete result;
}
data.put<uint8>(wpos, num); // set real data to placeholder
SendPacket(&data);
}
void WorldSession::SendStableResult(uint8 res)
{
WorldPacket data(SMSG_STABLE_RESULT, 1);
data << uint8(res);
SendPacket(&data);
}
bool WorldSession::CheckStableMaster(ObjectGuid guid)
{
// spell case or GM
if (guid == GetPlayer()->GetObjectGuid())
{
// command case will return only if player have real access to command
if (!GetPlayer()->HasAuraType(SPELL_AURA_OPEN_STABLE) && !ChatHandler(GetPlayer()).FindCommand("stable"))
{
DEBUG_LOG("%s attempt open stable in cheating way.", guid.GetString().c_str());
return false;
}
}
// stable master case
else
{
if (!GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_STABLEMASTER))
{
DEBUG_LOG("Stablemaster %s not found or you can't interact with him.", guid.GetString().c_str());
return false;
}
}
return true;
}
void WorldSession::HandleStablePet( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: Recv CMSG_STABLE_PET");
ObjectGuid npcGUID;
recv_data >> npcGUID;
if(!GetPlayer()->isAlive())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
Pet *pet = _player->GetPet();
// can't place in stable dead pet
if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
uint32 free_slot = 1;
QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
_player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
if(result)
{
do
{
Field *fields = result->Fetch();
uint32 slot = fields[1].GetUInt32();
// slots ordered in query, and if not equal then free
if(slot!=free_slot)
break;
// this slot not free, skip
++free_slot;
}while( result->NextRow() );
delete result;
}
if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
{
pet->Unsummon(PetSaveMode(free_slot), _player);
SendStableResult(STABLE_SUCCESS_STABLE);
}
else
SendStableResult(STABLE_ERR_STABLE);
}
void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: Recv CMSG_UNSTABLE_PET.");
ObjectGuid npcGUID;
uint32 petnumber;
recv_data >> npcGUID >> petnumber;
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
uint32 creature_id = 0;
{
QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
_player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT);
if(result)
{
Field *fields = result->Fetch();
creature_id = fields[0].GetUInt32();
delete result;
}
}
if(!creature_id)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
{
// if problem in exotic pet
if (creatureInfo && creatureInfo->isTameable(true))
SendStableResult(STABLE_ERR_EXOTIC);
else
SendStableResult(STABLE_ERR_STABLE);
return;
}
Pet* pet = _player->GetPet();
if(pet && pet->isAlive())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// delete dead pet
if(pet)
pet->Unsummon(PET_SAVE_AS_DELETED, _player);
Pet *newpet = new Pet(HUNTER_PET);
if(!newpet->LoadPetFromDB(_player,creature_id,petnumber))
{
delete newpet;
newpet = NULL;
SendStableResult(STABLE_ERR_STABLE);
return;
}
SendStableResult(STABLE_SUCCESS_UNSTABLE);
}
void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
ObjectGuid npcGUID;
recv_data >> npcGUID;
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if(GetPlayer()->m_stableSlots < MAX_PET_STABLES)
{
StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
if(_player->GetMoney() >= SlotPrice->Price)
{
++GetPlayer()->m_stableSlots;
_player->ModifyMoney(-int32(SlotPrice->Price));
SendStableResult(STABLE_SUCCESS_BUY_SLOT);
}
else
SendStableResult(STABLE_ERR_MONEY);
}
else
SendStableResult(STABLE_ERR_STABLE);
}
void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */)
{
DEBUG_LOG("HandleStableRevivePet: Not implemented");
}
void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: Recv CMSG_STABLE_SWAP_PET.");
ObjectGuid npcGUID;
uint32 pet_number;
recv_data >> npcGUID >> pet_number;
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
Pet* pet = _player->GetPet();
if(!pet || pet->getPetType()!=HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// find swapped pet slot in stable
QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
_player->GetGUIDLow(),pet_number);
if(!result)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
Field *fields = result->Fetch();
uint32 slot = fields[0].GetUInt32();
uint32 creature_id = fields[1].GetUInt32();
delete result;
if(!creature_id)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
if(!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
{
// if problem in exotic pet
if (creatureInfo && creatureInfo->isTameable(true))
SendStableResult(STABLE_ERR_EXOTIC);
else
SendStableResult(STABLE_ERR_STABLE);
return;
}
// move alive pet to slot or delete dead pet
pet->Unsummon(pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED, _player);
// summon unstabled pet
Pet *newpet = new Pet;
if(!newpet->LoadPetFromDB(_player,creature_id,pet_number))
{
delete newpet;
SendStableResult(STABLE_ERR_STABLE);
}
else
SendStableResult(STABLE_SUCCESS_UNSTABLE);
}
void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
{
DEBUG_LOG("WORLD: CMSG_REPAIR_ITEM");
ObjectGuid npcGuid;
ObjectGuid itemGuid;
uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
recv_data >> npcGuid >> itemGuid >> guildBank;
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_REPAIR);
if (!unit)
{
DEBUG_LOG( "WORLD: HandleRepairItemOpcode - %s not found or you can't interact with him.", npcGuid.GetString().c_str());
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
// reputation discount
float discountMod = _player->GetReputationPriceDiscount(unit);
uint32 TotalCost = 0;
if (!itemGuid.IsEmpty())
{
DEBUG_LOG("ITEM: %s repair of %s", npcGuid.GetString().c_str(), itemGuid.GetString().c_str());
Item* item = _player->GetItemByGuid(itemGuid);
if(item)
TotalCost= _player->DurabilityRepair(item->GetPos(), true, discountMod, (guildBank > 0));
}
else
{
DEBUG_LOG("ITEM: %s repair all items", npcGuid.GetString().c_str());
TotalCost = _player->DurabilityRepairAll(true, discountMod, (guildBank > 0));
}
if (guildBank)
{
uint32 GuildId = _player->GetGuildId();
if (!GuildId)
return;
Guild *pGuild = sObjectMgr.GetGuildById(GuildId);
if (!pGuild)
return;
pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
pGuild->SendMoneyInfo(this, _player->GetGUIDLow());
}
}