/*
* Ascent MMORPG Server
* Copyright (C) 2005-2007 Ascent Team
*
* 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 3 of the License, or
* 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, see .
*
*/
#include "StdAfx.h"
void WorldSession::HandlePetAction(WorldPacket & recv_data)
{
if(!_player->IsInWorld()) return;
//WorldPacket data;
uint64 petGuid = 0;
uint16 misc = 0;
uint16 action = 0;
uint64 targetguid = 0;
recv_data >> petGuid >> misc >> action;
//recv_data.hexlike();
//printf("Pet_Action: 0x%.4X 0x%.4X\n", misc, action);
if(UINT32_LOPART(GUID_HIPART(petGuid)) == HIGHGUID_UNIT)
{
Creature *pCharm = GetPlayer()->GetMapMgr()->GetCreature(petGuid);
if(!pCharm)
return;
// must be a mind controled creature..
if(action == PET_ACTION_ACTION)
{
recv_data >> targetguid;
switch(misc)
{
case PET_ACTION_ATTACK:
{
if(!sEventMgr.HasEvent(_player, EVENT_PLAYER_CHARM_ATTACK))
{
uint32 timer = pCharm->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME);
if(!timer) timer = 2000;
sEventMgr.AddEvent(_player, &Player::_EventCharmAttack, EVENT_PLAYER_CHARM_ATTACK, timer, 0,0);
_player->_EventCharmAttack();
}
}break;
}
}
return;
}
Pet *pPet = _player->GetMapMgr()->GetPet(petGuid);
if(!pPet)
return;
Unit *pTarget = NULL;
if(action == PET_ACTION_SPELL || action == PET_ACTION_SPELL_1 || action == PET_ACTION_SPELL_2 || (action == PET_ACTION_ACTION && misc == PET_ACTION_ATTACK )) // >> target
{
recv_data >> targetguid;
pTarget = _player->GetMapMgr()->GetUnit(targetguid);
if(!pTarget) pTarget = pPet; // target self
}
if(action==PET_ACTION_ACTION && misc==PET_ACTION_STAY)//sit if STAY commanded
pPet->SetStandState(STANDSTATE_SIT);
else
pPet->SetStandState(STANDSTATE_STAND);
switch(action)
{
case PET_ACTION_ACTION:
{
pPet->SetPetAction(misc); // set current action
switch(misc)
{
case PET_ACTION_ATTACK:
{
// make sure the target is attackable
if(pTarget == pPet || !isAttackable(pPet, pTarget))
{
WorldPacket data(SMSG_SPELL_FAILURE, 20);
data << _player->GetNewGUID() << uint32(0) << uint8(SPELL_FAILED_BAD_TARGETS);
SendPacket(&data);
return;
}
// Clear the threat
pPet->GetAIInterface()->WipeTargetList();
pPet->GetAIInterface()->WipeHateList();
// Attack target with melee if the owner if we dont have spells - other wise cast. All done by AIInterface.
if(pPet->GetAIInterface()->getUnitToFollow() == NULL)
pPet->GetAIInterface()->SetUnitToFollow(_player);
// EVENT_PET_ATTACK
pPet->GetAIInterface()->SetAIState(STATE_ATTACKING);
pPet->GetAIInterface()->AttackReaction(pTarget, 1, 0);
}break;
case PET_ACTION_FOLLOW:
{
// Clear the threat
pPet->GetAIInterface()->WipeTargetList();
pPet->GetAIInterface()->WipeHateList();
// Follow the owner... run to him...
pPet->GetAIInterface()->SetUnitToFollow(_player);
pPet->GetAIInterface()->HandleEvent(EVENT_FOLLOWOWNER, pPet, 0);
}break;
case PET_ACTION_STAY:
{
// Clear the threat
pPet->GetAIInterface()->WipeTargetList();
pPet->GetAIInterface()->WipeHateList();
// Stop following the owner, and sit.
pPet->GetAIInterface()->SetUnitToFollow(NULL);
}break;
case PET_ACTION_DISMISS:
{
// Bye byte...
pPet->Dismiss();
}break;
}
}break;
case PET_ACTION_SPELL_2:
case PET_ACTION_SPELL_1:
case PET_ACTION_SPELL:
{
// misc == spellid
SpellEntry *entry = sSpellStore.LookupEntry(misc);
if(!entry)
return;
AI_Spell * sp = pPet->GetAISpellForSpellId(entry->Id);
if(sp)
{
// Check the cooldown
if(pPet->GetAIInterface()->GetSpellCooldown(sp->spell->Id) > 0)
{
//SendNotification("That spell is still cooling down.");
WorldPacket data(SMSG_SPELL_FAILURE, 20);
data << pPet->GetNewGUID();
data << sp->spell->Id;
data << uint8(SPELL_FAILED_NOT_READY);
SendPacket(&data);
}
else
{
if(sp->spellType != STYPE_BUFF)
{
// make sure the target is attackable
if(pTarget == pPet || !isAttackable(pPet, pTarget))
{
WorldPacket data(SMSG_SPELL_FAILURE, 20);
data << _player->GetNewGUID() << sp->spell->Id << uint8(SPELL_FAILED_BAD_TARGETS);
SendPacket(&data);
return;
}
}
// Clear the threat
pPet->GetAIInterface()->WipeTargetList();
pPet->GetAIInterface()->WipeHateList();
pPet->GetAIInterface()->AttackReaction(pTarget, 1, 0);
pPet->GetAIInterface()->SetNextSpell(sp);
}
}
/*// cast spell
SpellCastTargets targets;
//HACK HACK HACK
switch (misc)
{
case 7812:
case 19438:
case 19440:
case 19441:
case 19442:
case 19443:
targets.m_unitTarget = pPet->GetGUID(); // dono maybe it should be NULL;
break;
default:
targets.m_unitTarget = (pTarget ? pTarget->GetGUID() : pPet->GetGUID());
break;
}
targets.m_targetMask = 0x2; // unit
pPet->GetAIInterface()->CastSpell(pPet, entry, targets);*/
}break;
case PET_ACTION_STATE:
{
pPet->SetPetState(misc);
}break;
default:
{
printf("WARNING: Unknown pet action received. Action = %.4X, Misc = %.4X\n", action, misc);
}break;
}
/* Send pet action sound - WHEE THEY TALK */
WorldPacket actionp(SMSG_PET_ACTION_SOUND, 12);
actionp << pPet->GetGUID() << uint32(1);
SendPacket(&actionp);
}
void WorldSession::HandlePetInfo(WorldPacket & recv_data)
{
//nothing
sLog.outDebug("HandlePetInfo is called");
}
void WorldSession::HandlePetNameQuery(WorldPacket & recv_data)
{
if(!_player->IsInWorld()) return;
uint32 petNumber = 0;
uint64 petGuid = 0;
recv_data >> petNumber >> petGuid;
Pet *pPet = _player->GetMapMgr()->GetPet(petGuid);
if(!pPet) return;
WorldPacket data(8 + pPet->GetName().size());
data.SetOpcode(SMSG_PET_NAME_QUERY_RESPONSE);
data << (uint32)pPet->GetGUIDLow();
data << pPet->GetName();
data << pPet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP); // stops packet flood
SendPacket(&data);
}
void WorldSession::HandleStablePet(WorldPacket & recv_data)
{
if(!_player->IsInWorld()) return;
WorldPacket data(1);
data.SetOpcode(SMSG_STABLE_RESULT);
data << uint8(0x8); // success
SendPacket(&data);
// remove pet from world and association with player
Pet *pPet = _player->GetSummon();
if(!pPet || pPet->GetUInt32Value(UNIT_CREATED_BY_SPELL) != 0) return;
pPet->Remove(false, true, true); // no safedelete needed
}
void WorldSession::HandleUnstablePet(WorldPacket & recv_data)
{
if(!_player->IsInWorld()) return;
uint64 npcguid = 0;
uint32 petnumber = 0;
recv_data >> npcguid >> petnumber;
PlayerPet *pet = _player->GetPlayerPet(petnumber);
if(!pet)
{
sLog.outError("PET SYSTEM: Player "I64FMT" tried to unstable non-existant pet %d", _player->GetGUID(), petnumber);
return;
}
// much easier? :P
_player->SpawnPet(petnumber);
WorldPacket data(1);
data.SetOpcode(SMSG_STABLE_RESULT);
data << uint8(0x9); // success?
SendPacket(&data);
}
void WorldSession::HandleStabledPetList(WorldPacket & recv_data)
{
if(!_player->IsInWorld()) return;
WorldPacket data(10 + (_player->m_Pets.size() * 25));
data.SetOpcode(MSG_LIST_STABLED_PETS);
uint64 npcguid = 0;
recv_data >> npcguid;
data << npcguid;
data << uint8(_player->m_Pets.size());
data << uint8(_player->m_StableSlotCount);
for(std::map::iterator itr = _player->m_Pets.begin(); itr != _player->m_Pets.end(); ++itr)
{
data << uint32(itr->first); // pet no
data << uint32(itr->second->entry); // entryid
data << uint32(itr->second->level); // level
data << itr->second->name; // name
data << uint32(itr->second->loyaltylvl);
if(itr->second->active && _player->GetSummon() != NULL)
data << uint8(STABLE_STATE_ACTIVE);
else
data << uint8(STABLE_STATE_PASSIVE);
}
SendPacket(&data);
}
void WorldSession::HandleBuyStableSlot(WorldPacket &recv_data)
{
if(!_player->IsInWorld() || _player->GetStableSlotCount() == 2) return;
uint8 scount = _player->GetStableSlotCount();
int32 cost = (scount == 0) ? -500 : -50000;
if(cost > (int32)_player->GetUInt32Value(PLAYER_FIELD_COINAGE))
return;
_player->ModUInt32Value(PLAYER_FIELD_COINAGE, cost);
WorldPacket data(1);
data.SetOpcode(SMSG_STABLE_RESULT);
data << uint8(0x0A);
SendPacket(&data);
if(_player->GetStableSlotCount() > 2)
_player->m_StableSlotCount = 2;
else
_player->m_StableSlotCount++;
}
void WorldSession::HandlePetSetActionOpcode(WorldPacket& recv_data)
{
if(!_player->IsInWorld()) return;
uint32 unk1;
uint32 unk2;
uint32 slot;
uint16 spell;
uint16 state;
recv_data >> unk1 >> unk2 >> slot >> spell >> state;
if(!_player->GetSummon())
return;
Pet * pet = _player->GetSummon();
pet->ActionBar[slot] = spell;
pet->SetSpellState(spell, state);
AI_Spell * sp = pet->GetAISpellForSpellId(spell);
if(!sp) return;
if(state == 0x8100) //autocast OFF
sp->procChance = 0;
else if(state == 0xC100) //autocast ON
{
if(sp->spell->NameHash == 2858464432UL) /* Firebolt */
sp->procChance=100;
else
sp->procChance = PET_SPELL_AUTOCAST_CHANCE;
}
}
void WorldSession::HandlePetRename(WorldPacket & recv_data)
{
if(!_player->IsInWorld()) return;
uint64 guid;
string name;
recv_data >> guid >> name;
if(!_player->GetSummon() || _player->GetSummon()->GetGUID() != guid)
{
sChatHandler.SystemMessage(this, "That pet is not your current pet, or you do not have a pet.");
return;
}
Pet * pet = _player->GetSummon();
pet->Rename(name);
// Disable pet rename.
pet->SetUInt32Value(UNIT_FIELD_BYTES_2, 1 | (0x28 << 8) | (0x2 << 16));
}
void WorldSession::HandlePetAbandon(WorldPacket & recv_data)
{
if(!_player->IsInWorld()) return;
Pet * pet = _player->GetSummon();
if(!pet) return;
pet->Dismiss(false);
}