void AssistanceDistractMovementGenerator::Finalize(Unit& unit) { unit.ClearUnitState(UNIT_STATE_DISTRACTED); unit.ToCreature()->SetReactState(REACT_AGGRESSIVE); }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { sLog->outDetail("WORLD: CMSG_PET_CAST_SPELL"); uint64 guid; uint8 castCount; uint32 spellId; uint8 castFlags; recvPacket >> guid >> castCount >> spellId >> castFlags; sLog->outDebug("WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", castCount: %u, spellId %u, castFlags %u", guid, castCount, spellId, castFlags); // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, guid); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { sLog->outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); return; } SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) { sLog->outError("WORLD: unknown PET spell id %i", spellId); return; } if (spellInfo->GetStartRecoveryCategory() > 0) // Check if spell is affected by GCD if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) { caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY); return; } // do not cast not learned spells if (!caster->HasSpell(spellId) || IsPassiveSpell(spellId)) return; SpellCastTargets targets; targets.Read(recvPacket, caster); HandleClientCastFlags(recvPacket, castFlags, targets); caster->ClearUnitState(UNIT_STAT_FOLLOW); Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); spell->m_cast_count = castCount; // probably pending spell cast spell->m_targets = targets; // TODO: need to check victim? SpellCastResult result; if (caster->m_movedPlayer) result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); else result = spell->CheckPetCast(NULL); if (result == SPELL_CAST_OK) { if (caster->GetTypeId() == TYPEID_UNIT) { Creature* pet = caster->ToCreature(); pet->AddCreatureSpellCooldown(spellId); if (pet->isPet()) { Pet* p = (Pet*)pet; // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(guid); } } spell->prepare(&(spell->m_targets)); } else { caster->SendPetCastFail(spellId, result); if (caster->GetTypeId() == TYPEID_PLAYER) { if (!caster->ToPlayer()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } else { if (!caster->ToCreature()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } spell->finish(false); delete spell; } }
void RotateMovementGenerator::Finalize(Unit& unit) { unit.ClearUnitState(UNIT_STATE_ROTATING); if (unit.GetTypeId() == TYPEID_UNIT) unit.ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0); }
void DistractMovementGenerator::Finalize(Unit& owner) { owner.ClearUnitState(UNIT_STATE_DISTRACTED); }
void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& petCastSpell) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petCastSpell.Cast.SpellID); if (!spellInfo) { TC_LOG_ERROR("network", "WORLD: unknown PET spell id %i", petCastSpell.Cast.SpellID); return; } // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, petCastSpell.PetGUID); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { TC_LOG_ERROR("network", "HandlePetCastSpellOpcode: %s isn't pet of player %s (%s).", petCastSpell.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); return; } // do not cast not learned spells if (!caster->HasSpell(spellInfo->Id) || spellInfo->IsPassive()) return; SpellCastTargets targets(caster, petCastSpell.Cast); caster->ClearUnitState(UNIT_STATE_FOLLOW); Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); spell->m_cast_count = petCastSpell.Cast.CastID; spell->m_misc.Data = petCastSpell.Cast.Misc; spell->m_targets = targets; SpellCastResult result = spell->CheckPetCast(NULL); if (result == SPELL_CAST_OK) { if (Creature* creature = caster->ToCreature()) { if (Pet* pet = creature->ToPet()) { // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (pet->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk(PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(petCastSpell.PetGUID); } } spell->prepare(&targets); } else { spell->SendPetCastResult(result); if (!caster->GetSpellHistory()->HasCooldown(spellInfo->Id)) caster->GetSpellHistory()->ResetCooldown(spellInfo->Id, true); spell->finish(false); delete spell; } }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_CAST_SPELL"); ObjectGuid guid; uint8 castCount; uint32 spellId; uint8 castFlags; recvPacket >> guid >> castCount >> spellId >> castFlags; TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL, %s, castCount: %u, spellId %u, castFlags %u", guid.ToString().c_str(), castCount, spellId, castFlags); // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, guid); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { TC_LOG_ERROR("network", "HandlePetCastSpellOpcode: %s isn't pet of player %s (%s).", guid.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); return; } SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { TC_LOG_ERROR("network", "WORLD: unknown PET spell id %i", spellId); return; } // do not cast not learned spells if (!caster->HasSpell(spellId) || spellInfo->IsPassive()) return; SpellCastTargets targets; targets.Read(recvPacket, caster); HandleClientCastFlags(recvPacket, castFlags, targets); caster->ClearUnitState(UNIT_STATE_FOLLOW); Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); spell->m_cast_count = castCount; // probably pending spell cast spell->m_targets = targets; SpellCastResult result = spell->CheckPetCast(NULL); if (result == SPELL_CAST_OK) { if (Creature* creature = caster->ToCreature()) { if (Pet* pet = creature->ToPet()) { // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (pet->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk(PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(guid); } } spell->prepare(&(spell->m_targets)); } else { spell->SendPetCastResult(result); if (!caster->GetSpellHistory()->HasCooldown(spellId)) caster->GetSpellHistory()->ResetCooldown(spellId, true); spell->finish(false); delete spell; } }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_CAST_SPELL"); uint64 guid; uint8 castCount; uint32 spellId; uint8 castFlags; recvPacket >> guid >> castCount >> spellId >> castFlags; ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", castCount: %u, spellId %u, castFlags %u", guid, castCount, spellId, castFlags); // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, guid); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { sLog->outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName().c_str()); return; } SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { sLog->outError("WORLD: unknown PET spell id %i", spellId); return; } // do not cast not learned spells if (!caster->HasSpell(spellId) || spellInfo->IsPassive()) return; SpellCastTargets targets; targets.Read(recvPacket, caster); HandleClientCastFlags(recvPacket, castFlags, targets); bool SetFollow = caster->HasUnitState(UNIT_STATE_FOLLOW); caster->ClearUnitState(UNIT_STATE_FOLLOW); Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); spell->m_cast_count = castCount; // probably pending spell cast spell->m_targets = targets; spell->LoadScripts(); // Xinef: Send default target, fixes return on NeedExplicitUnitTarget Unit* target = targets.GetUnitTarget(); if (!target && spell->m_spellInfo->NeedsExplicitUnitTarget()) target = _player->GetSelectedUnit(); SpellCastResult result = spell->CheckPetCast(target); if (result == SPELL_CAST_OK) { if (Creature* creature = caster->ToCreature()) { creature->AddSpellCooldown(spellId, 0, 0); if (Pet* pet = creature->ToPet()) { // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (pet->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk(PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(guid); } } spell->prepare(&(spell->m_targets)); } else { if (!caster->GetCharmInfo() || !caster->GetCharmInfo()->GetForcedSpell()) spell->SendPetCastResult(result); if (caster->GetTypeId() == TYPEID_PLAYER) { if (!caster->ToPlayer()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } else { if (!caster->ToCreature()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); // reset specific flags in case of spell fail. AI will reset other flags if (caster->IsPet()) caster->PetSpellFail(spellInfo, targets.GetUnitTarget(), result); } spell->finish(false); delete spell; } if (SetFollow && !caster->IsInCombat()) caster->AddUnitState(UNIT_STATE_FOLLOW); }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL"); uint64 guid; uint32 spellId; recvPacket >> guid >> spellId; TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", spellId %u", guid, spellId); // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, guid); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { TC_LOG_ERROR("network", "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s (GUID: %u).", uint32(GUID_LOPART(guid)), GetPlayer()->GetName().c_str(), GUID_LOPART(GetPlayer()->GetGUID())); return; } SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { TC_LOG_ERROR("network", "WORLD: unknown PET spell id %i", spellId); return; } // do not cast not learned spells if (!caster->HasSpell(spellId) || spellInfo->IsPassive()) return; SpellCastTargets targets; targets.Read(recvPacket, caster); caster->ClearUnitState(UNIT_STATE_FOLLOW); Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); spell->m_targets = targets; SpellCastResult result = spell->CheckPetCast(NULL); if (result == SPELL_CAST_OK) { if (Creature* creature = caster->ToCreature()) { creature->AddCreatureSpellCooldown(spellId); if (Pet* pet = creature->ToPet()) { // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (pet->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk(PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(guid); } } spell->prepare(&(spell->m_targets)); } else { spell->SendPetCastResult(result); if (caster->GetTypeId() == TYPEID_PLAYER) { if (!caster->ToPlayer()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } else { if (!caster->ToCreature()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } spell->finish(false); delete spell; } }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); uint64 guid; uint32 spellid; recvPacket >> guid >> spellid; // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, guid); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { sLog.outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); return; } SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid); if (!spellInfo) { sLog.outError("WORLD: unknown PET spell id %i", spellid); return; } // do not cast not learned spells if (!caster->HasSpell(spellid) || IsPassiveSpell(spellid)) return; if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0) { caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY); return; } SpellCastTargets targets; recvPacket >> targets.ReadForCaster(caster); caster->ClearUnitState(UNIT_STATE_MOVING); Spell* spell = new Spell(caster, spellInfo, false); spell->m_targets = targets; SpellCastResult result = spell->CheckPetCast(NULL); if (result == SPELL_CAST_OK) { if (caster->GetTypeId() == TYPEID_UNIT) { Creature* pet = caster->ToCreature(); pet->AddCreatureSpellCooldown(spellid); if (pet->IsPet()) { Pet* p = (Pet*)pet; p->CheckLearning(spellid); // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(guid); } } spell->prepare(&(spell->m_targets)); } else { caster->SendPetCastFail(spellid, result); if (caster->GetTypeId() == TYPEID_PLAYER) { if (!caster->ToPlayer()->HasSpellCooldown(spellid)) caster->SendPetClearCooldown(spellid); } else { if (!caster->ToCreature()->HasSpellCooldown(spellid)) caster->SendPetClearCooldown(spellid); } spell->finish(false); delete spell; } }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_CAST_SPELL"); uint64 guid; uint8 castCount; uint32 spellId; uint8 castFlags; recvPacket >> guid >> castCount >> spellId >> castFlags; TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", castCount: %u, spellId %u, castFlags %u", guid, castCount, spellId, castFlags); // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, guid); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s (GUID: %u).", uint32(GUID_LOPART(guid)), GetPlayer()->GetName().c_str(), GUID_LOPART(GetPlayer()->GetGUID())); return; } SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "WORLD: unknown PET spell id %i", spellId); return; } if (spellInfo->StartRecoveryCategory > 0) // Check if spell is affected by GCD if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) { caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY); return; } // check spell focus object if (spellInfo->RequiresSpellFocus && caster->IsVehicle()) { CellCoord p(Trinity::ComputeCellCoord(caster->GetPositionX(), caster->GetPositionY())); Cell cell(p); GameObject* ok = NULL; Trinity::GameObjectFocusCheck goCheck(caster, spellInfo->RequiresSpellFocus); Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> checker(caster, ok, goCheck); TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > objectChecker(checker); Map& map = *caster->GetMap(); cell.Visit(p, objectChecker, map, *caster, caster->GetVisibilityRange()); if (!ok) { caster->SendPetCastFail(spellId, SPELL_FAILED_REQUIRES_SPELL_FOCUS); return; } } // do not cast not learned spells if (!caster->HasSpell(spellId) || spellInfo->IsPassive()) return; SpellCastTargets targets; targets.Read(recvPacket, caster); HandleClientCastFlags(recvPacket, castFlags, targets); caster->ClearUnitState(UNIT_STATE_FOLLOW); Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); spell->m_cast_count = castCount; // probably pending spell cast spell->m_targets = targets; /// @todo need to check victim? SpellCastResult result; if (caster->m_movedPlayer) result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); else result = spell->CheckPetCast(NULL); if (result == SPELL_CAST_OK) { if (caster->GetTypeId() == TYPEID_UNIT) { Creature* pet = caster->ToCreature(); pet->AddCreatureSpellCooldown(spellId); if (pet->IsPet()) { Pet* p = (Pet*)pet; // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(guid); } } spell->prepare(&(spell->m_targets)); } else { caster->SendPetCastFail(spellId, result); if (caster->GetTypeId() == TYPEID_PLAYER) { if (!caster->ToPlayer()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } else { if (!caster->ToCreature()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } spell->finish(false); delete spell; } }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL"); ObjectGuid casterGUID; ObjectGuid unkGUID1; ObjectGuid transportDstGUID; ObjectGuid transportSrcGUID; ObjectGuid targetGUID; ObjectGuid unkGUID2; bool hasDestPos; bool hasSrcPos; bool hasSpeed; bool hasSpell; bool hasGlyphIndex; bool hasTargetFlags; bool hasElevation; bool hasString; bool hasCastCount; bool hasUnk5bits; uint32 archeologyCounter = 0; WorldLocation dstLoc, srcLoc; float speed = 0.0f; float elevation = 0.0f; uint32 targetFlags = 0; uint32 spellID = 0; uint32 stringLenght = 0; uint8 castCount = 0; recvPacket.ReadBitSeq<3, 5>(casterGUID); hasDestPos = recvPacket.ReadBit(); recvPacket.ReadBit(); // unk bit hasSpeed = !recvPacket.ReadBit(); hasSrcPos = recvPacket.ReadBit(); hasSpell = !recvPacket.ReadBit(); recvPacket.ReadBitSeq<0>(casterGUID); hasGlyphIndex = !recvPacket.ReadBit(); recvPacket.ReadBitSeq<7>(casterGUID); hasTargetFlags = !recvPacket.ReadBit(); hasElevation = !recvPacket.ReadBit(); recvPacket.ReadBit(); // has movement info hasString = !recvPacket.ReadBit(); recvPacket.ReadBit(); // !inverse bit, unk hasCastCount = !recvPacket.ReadBit(); recvPacket.ReadBitSeq<2, 4>(casterGUID); archeologyCounter = recvPacket.ReadBits(2); recvPacket.ReadBitSeq<1>(casterGUID); hasUnk5bits = !recvPacket.ReadBit(); for (uint32 i = 0; i < archeologyCounter; i++) recvPacket.ReadBits(2); // archeology type recvPacket.ReadBitSeq<6>(casterGUID); if (hasDestPos) recvPacket.ReadBitSeq<2, 7, 4, 0, 1, 6, 5, 3>(transportDstGUID); // movement block (disabled by patch client-side) if (hasSrcPos) recvPacket.ReadBitSeq<6, 2, 3, 1, 5, 4, 0, 7>(transportSrcGUID); if (hasUnk5bits) recvPacket.ReadBits(5); // unk 5 bits // Target GUID recvPacket.ReadBitSeq<3, 5, 6, 2, 4, 1, 7, 0>(targetGUID); // unkGUID1 recvPacket.ReadBitSeq<3, 1, 5, 2, 4, 7, 0, 6>(unkGUID1); if (hasTargetFlags) targetFlags = recvPacket.ReadBits(20); if (hasString) stringLenght = recvPacket.ReadBits(7); recvPacket.ReadByteSeq<0, 4, 5, 1, 2, 3, 7>(casterGUID); for (uint32 i = 0; i < archeologyCounter; i++) { recvPacket.read_skip<uint32>(); // entry recvPacket.read_skip<uint32>(); // counter } recvPacket.ReadByteSeq<6>(casterGUID); recvPacket.ReadByteSeq<1, 5, 4, 2, 7, 3, 0>(unkGUID1); if (hasSrcPos) { recvPacket.ReadByteSeq<4>(transportSrcGUID); srcLoc.m_positionY = recvPacket.read<float>(); recvPacket.ReadByteSeq<2, 6>(transportSrcGUID); srcLoc.m_positionZ = recvPacket.read<float>(); srcLoc.m_positionX = recvPacket.read<float>(); recvPacket.ReadByteSeq<1, 3, 5, 7, 0>(transportSrcGUID); } // Target GUID recvPacket.ReadByteSeq<7, 4, 2, 6, 3, 0, 5, 1>(targetGUID); if (hasDestPos) { dstLoc.m_positionX = recvPacket.read<float>(); recvPacket.ReadByteSeq<5, 7, 2, 0, 1, 3, 6>(transportDstGUID); dstLoc.m_positionZ = recvPacket.read<float>(); dstLoc.m_positionY = recvPacket.read<float>(); recvPacket.ReadByteSeq<4>(transportDstGUID); } if (hasGlyphIndex) recvPacket.read_skip<uint32>(); // glyph index if (hasElevation) elevation = recvPacket.read<float>(); if (hasSpell) spellID = recvPacket.read<uint32>(); if (hasCastCount) castCount = recvPacket.read<uint8>(); if (hasString) recvPacket.ReadString(stringLenght); if (hasSpeed) speed = recvPacket.read<float>(); TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL, castCount: %u, spellId %u, targetFlags %u", castCount, spellID, targetFlags); // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, casterGUID); if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) { TC_LOG_ERROR("network", "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(casterGUID)), GetPlayer()->GetName().c_str()); return; } SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); if (!spellInfo) { TC_LOG_ERROR("network", "WORLD: unknown PET spell id %i", spellID); return; } if (spellInfo->StartRecoveryCategory > 0) // Check if spell is affected by GCD if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(caster, spellInfo)) { caster->SendPetCastFail(spellID, SPELL_FAILED_NOT_READY); return; } // do not cast not learned spells if (!caster->HasSpell(spellID) || spellInfo->IsPassive()) return; SpellCastTargets targets; targets.Initialize(targetFlags, targetGUID, unkGUID1, transportDstGUID, dstLoc, transportSrcGUID, srcLoc); targets.SetElevation(elevation); targets.SetSpeed(speed); targets.Update(caster); // Interrupt auto-cast if other spell is forced by player if (caster->IsNonMeleeSpellCasted(false, true, true, false, true)) caster->InterruptNonMeleeSpells(false, 0, false); caster->ClearUnitState(UNIT_STATE_FOLLOW); Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, 0, false, true); spell->m_cast_count = castCount; // probably pending spell cast spell->m_targets = targets; // TODO: need to check victim? SpellCastResult result; if (caster->m_movedPlayer) result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); else result = spell->CheckPetCast(NULL); if (result == SPELL_CAST_OK) { if (caster->GetTypeId() == TYPEID_UNIT) { Creature* pet = caster->ToCreature(); pet->AddCreatureSpellCooldown(spellID); if (pet->isPet()) { Pet* p = (Pet*)pet; // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else pet->SendPetAIReaction(spellID); } } spell->prepare(&(spell->m_targets)); } else { caster->SendPetCastFail(spellID, result); if (caster->GetTypeId() == TYPEID_PLAYER) { if (!caster->ToPlayer()->HasSpellCooldown(spellID)) GetPlayer()->SendClearCooldown(spellID, caster); } else { if (!caster->ToCreature()->HasSpellCooldown(spellID)) GetPlayer()->SendClearCooldown(spellID, caster); } spell->finish(false); delete spell; } }