void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) { uint32 spellId; recvPacket >> spellId; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) return; // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)) return; // channeled spell case (it currently casted then) if (IsChanneledSpell(spellInfo)) { if (Spell* curSpell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) if (curSpell->m_spellInfo->Id==spellId) _player->InterruptSpell(CURRENT_CHANNELED_SPELL); return; } // non channeled case _player->RemoveAurasDueToSpellByCancel(spellId); }
void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,4); uint32 spellId; recvPacket >> spellId; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) return; // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)) return; // channeled spell case (it currently casted then) if(IsChanneledSpell(spellInfo)) { if(Spell* spell = _player->m_currentSpells[CURRENT_CHANNELED_SPELL]) { if(spell->m_spellInfo->Id==spellId) { spell->cancel(); spell->SetReferencedFromCurrent(false); _player->m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; } } return; } // non channeled case _player->RemoveAurasDueToSpellByCancel(spellId); }
void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,4); // ignore for remote control state if(_player->m_mover != _player) return; uint32 spellId; recvPacket >> spellId; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) return; // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)) return; // channeled spell case (it currently casted then) if (IsChanneledSpell(spellInfo)) { if (_player->m_currentSpells[CURRENT_CHANNELED_SPELL] && _player->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id==spellId) _player->InterruptSpell(CURRENT_CHANNELED_SPELL); return; } // non channeled case _player->RemoveAurasDueToSpellByCancel(spellId); }
void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) { uint32 spellId; recvPacket >> spellId; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) return; if (spellInfo->HasAttribute(SPELL_ATTR_CANT_CANCEL)) return; if (IsPassiveSpell(spellInfo)) return; if (!IsPositiveSpell(spellId)) { // ignore for remote control state if (!_player->IsSelfMover()) { // except own aura spells bool allow = false; for (int k = 0; k < MAX_EFFECT_INDEX; ++k) { SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(SpellEffectIndex(k)); if (spellEffect && (spellEffect->EffectApplyAuraName == SPELL_AURA_MOD_POSSESS || spellEffect->EffectApplyAuraName == SPELL_AURA_MOD_POSSESS_PET)) { allow = true; break; } } // this also include case when aura not found if (!allow) return; } else return; } // channeled spell case (it currently casted then) if (IsChanneledSpell(spellInfo)) { if (Spell* curSpell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) if (curSpell->m_spellInfo->Id == spellId) _player->InterruptSpell(CURRENT_CHANNELED_SPELL); return; } SpellAuraHolder* holder = _player->GetSpellAuraHolder(spellId); // not own area auras can't be cancelled (note: maybe need to check for aura on holder and not general on spell) if (holder && holder->GetCasterGuid() != _player->GetObjectGuid() && HasAreaAuraEffect(holder->GetSpellProto())) return; // non channeled case _player->RemoveAurasDueToSpellByCancel(spellId); }
void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) { uint32 spellId; recvPacket >> spellId; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) return; if (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL) return; if (IsPassiveSpell(spellInfo)) return; if (!IsPositiveSpell(spellId)) { // ignore for remote control state if (!_player->IsSelfMover()) { // except own aura spells bool allow = false; for(int k = 0; k < MAX_EFFECT_INDEX; ++k) { if (spellInfo->EffectApplyAuraName[k] == SPELL_AURA_MOD_POSSESS || spellInfo->EffectApplyAuraName[k] == SPELL_AURA_MOD_POSSESS_PET) { allow = true; break; } } // this also include case when aura not found if(!allow) return; } else return; } // channeled spell case (it currently casted then) if (IsChanneledSpell(spellInfo)) { if (Spell* curSpell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) if (curSpell->m_spellInfo->Id==spellId) _player->InterruptSpell(CURRENT_CHANNELED_SPELL); return; } // non channeled case _player->RemoveAurasDueToSpellByCancel(spellId); }
void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) { uint32 spellId; recvPacket >> spellId; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) return; // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL if (spellInfo->Attributes & SPELL_ATTR0_CANT_CANCEL) return; // channeled spell case (it currently casted then) if (IsChanneledSpell(spellInfo)) { if (Spell* spell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) { if (spell->m_spellInfo->Id == spellId) spell->cancel(); } return; } // non channeled case: // don't allow remove non positive spells // don't allow cancelling passive auras (some of them are visible) if (!IsPositiveSpell(spellId) || IsPassiveSpell(spellId)) return; // non channeled case if (!IsPositiveSpell(spellId)) return; _player->RemoveAurasDueToSpellByCancel(spellId); }
void PetAI::Reset() { m_primaryTargetGuid.Clear(); m_savedTargetGuid.Clear(); m_attackDistanceRecheckTimer.SetInterval(TIME_INTERVAL_LOOK); m_attackDistanceRecheckTimer.Reset(); m_updateAlliesTimer.SetInterval(ALLIES_UPDATE_TIME); m_updateAlliesTimer.Reset(); UpdateAllies(); for (uint8 i = PET_SPELL_PASSIVE; i < PET_SPELL_MAX; ++i) m_spellType[i].clear(); m_AIType = PET_AI_PASSIVE; m_attackDistance = 0.0f; float f_range = 0.0f; if (!m_creature->GetCharmInfo()) return; uint32 spellsSize = m_creature->IsPet() ? ((Pet*)m_creature)->GetPetAutoSpellSize() : m_creature->GetPetAutoSpellSize(); uint8 rangedDamageSpells = 0; uint8 meleeDamageSpells = 0; // classification for pet spells for (uint32 i = 0; i < spellsSize; ++i) { uint32 spellID = m_creature->IsPet() ? ((Pet*)m_creature)->GetPetAutoSpellOnPos(i) : m_creature->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (IsPassiveSpell(spellInfo)) { m_spellType[PET_SPELL_PASSIVE].insert(spellID); continue; } if (IsNonCombatSpell(spellInfo)) { // Voidwalker Consume Shadows if (IsChanneledSpell(spellInfo)) m_spellType[PET_SPELL_HEAL].insert(spellID); else m_spellType[PET_SPELL_NONCOMBAT].insert(spellID); continue; } // need more correct define this type if (IsSpellReduceThreat(spellInfo) || IsChanneledSpell(spellInfo)) { m_spellType[PET_SPELL_DEFENCE].insert(spellID); continue; } // Voracious Appetite && Cannibalize && Carrion Feeder if (spellInfo->HasAttribute(SPELL_ATTR_ABILITY) && spellInfo->HasAttribute(SPELL_ATTR_EX2_ALLOW_DEAD_TARGET)) { m_spellType[PET_SPELL_HEAL].insert(spellID); continue; } if (IsPositiveSpell(spellInfo) && IsSpellAppliesAura(spellInfo)) { m_spellType[PET_SPELL_BUFF].insert(spellID); continue; } if (spellInfo->HasAttribute(SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)) { m_spellType[PET_SPELL_FREEACTION].insert(spellID); continue; } // don't have SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY ! if (spellInfo->HasAttribute(SPELL_ATTR_EX_CANT_REFLECTED) || spellInfo->HasAttribute(SPELL_ATTR_EX7_HAS_CHARGE_EFFECT)) { m_spellType[PET_SPELL_ATTACKSTART].insert(spellID); continue; } if (IsSpellIncreaseThreat(spellInfo)) { m_spellType[PET_SPELL_THREAT].insert(spellID); continue; } // all non-combat spells classified. switch (spellInfo->rangeIndex) { case SPELL_RANGE_IDX_COMBAT: { if (IsSpellCauseDamage(spellInfo)) { m_spellType[PET_SPELL_MELEE].insert(spellID); ++meleeDamageSpells; } else { m_spellType[PET_SPELL_SPECIAL].insert(spellID); } break; } // possible debuffs or auras? case SPELL_RANGE_IDX_SELF_ONLY: case SPELL_RANGE_IDX_ANYWHERE: { m_spellType[PET_SPELL_SPECIAL].insert(spellID); break; } default: { float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellInfo->rangeIndex), false); if (f_range < M_NULL_F || (range > M_NULL_F && range < f_range)) f_range = range; if (IsSpellCauseDamage(spellInfo)) { m_spellType[PET_SPELL_RANGED].insert(spellID); ++rangedDamageSpells; } else { m_spellType[PET_SPELL_SPECIAL].insert(spellID); } break; } } } // define initial AI type if (m_creature->IsVehicle()) m_AIType = PET_AI_PASSIVE; if (m_spellType[PET_SPELL_RANGED].size() > 0 && (m_spellType[PET_SPELL_MELEE].size() < m_spellType[PET_SPELL_RANGED].size())) { m_AIType = PET_AI_RANGED; m_attackDistance = f_range - m_creature->GetObjectBoundingRadius() - 2.0f; if (m_attackDistance < 20.0f) m_attackDistance = 18.0f; } else { m_AIType = PET_AI_MELEE; m_attackDistance = 0.0f; } m_savedAIType = m_AIType; m_creature->GetMotionMaster()->MoveTargetedHome(); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"PetAI::Reset %s, AI %u dist %f, spells: "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD" "SIZEFMTD , m_creature->GetObjectGuid().GetString().c_str(), m_AIType, m_attackDistance, m_spellType[PET_SPELL_PASSIVE].size(), m_spellType[PET_SPELL_NONCOMBAT].size(), m_spellType[PET_SPELL_BUFF].size(), m_spellType[PET_SPELL_DEBUFF].size(), m_spellType[PET_SPELL_FREEACTION].size(), m_spellType[PET_SPELL_ATTACKSTART].size(), m_spellType[PET_SPELL_THREAT].size(), m_spellType[PET_SPELL_MELEE].size(), m_spellType[PET_SPELL_RANGED].size(), m_spellType[PET_SPELL_DEFENCE].size(), m_spellType[PET_SPELL_SPECIAL].size(), m_spellType[PET_SPELL_HEAL].size() ); }
CanCastResult UnitAI::DoCastSpellIfCan(Unit* target, uint32 spellId, uint32 castFlags, ObjectGuid originalCasterGUID) const { Unit* caster = m_unit; if (target) { if (castFlags & CAST_SWITCH_CASTER_TARGET) std::swap(caster, target); if (castFlags & CAST_FORCE_TARGET_SELF) caster = target; } else if (castFlags & (CAST_FORCE_TARGET_SELF | CAST_SWITCH_CASTER_TARGET)) return CAST_FAIL_OTHER; // Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered if (!caster->IsNonMeleeSpellCasted(false) || (castFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS))) { if (const SpellEntry* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spellId)) { // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them if (castFlags & CAST_AURA_NOT_PRESENT) { if (!target) { if (caster->HasAura(spellId)) return CAST_FAIL_TARGET_AURA; } else if (target->HasAura(spellId)) return CAST_FAIL_TARGET_AURA; } // Check if cannot cast spell if (!(castFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST))) { CanCastResult castResult = CanCastSpell(target, spellInfo, (castFlags & CAST_TRIGGERED) != 0); if (castResult != CAST_OK) return castResult; } // Interrupt any previous spell if (castFlags & CAST_INTERRUPT_PREVIOUS && caster->IsNonMeleeSpellCasted(false)) caster->InterruptNonMeleeSpells(false); // Creature should always stop before it will cast a non-instant spell if (GetSpellCastTime(spellInfo) || (IsChanneledSpell(spellInfo) && spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_MOVEMENT)) caster->StopMoving(); // Creature should interrupt any current melee spell caster->InterruptSpell(CURRENT_MELEE_SPELL); // Creature should stop wielding weapon while casting // caster->SetSheath(SHEATH_STATE_UNARMED); uint32 flags = (castFlags & CAST_TRIGGERED ? TRIGGERED_OLD_TRIGGERED : TRIGGERED_NONE) | (castFlags & CAST_IGNORE_UNSELECTABLE_TARGET ? TRIGGERED_IGNORE_UNSELECTABLE_FLAG : TRIGGERED_NONE); if (flags == TRIGGERED_NONE) flags |= TRIGGERED_NORMAL_COMBAT_CAST; caster->CastSpell(target, spellInfo, flags, nullptr, nullptr, originalCasterGUID); return CAST_OK; } sLog.outErrorDb("DoCastSpellIfCan by %s attempt to cast spell %u but spell does not exist.", m_unit->GetObjectGuid().GetString().c_str(), spellId); return CAST_FAIL_OTHER; } return CAST_FAIL_IS_CASTING; }
bool SpellEvent::Execute(uint64 e_time, uint32 p_time) { // update spell if it is not finished if (m_Spell->getState() != SPELL_STATE_FINISHED) m_Spell->update(p_time); // check spell state to process switch (m_Spell->getState()) { case SPELL_STATE_FINISHED: { // spell was finished, check deletable state if (m_Spell->IsDeletable()) { // check, if we do have unfinished triggered spells return true; // spell is deletable, finish event } // event will be re-added automatically at the end of routine) } break; case SPELL_STATE_CASTING: { // this spell is in channeled state, process it on the next update // event will be re-added automatically at the end of routine) } break; case SPELL_STATE_DELAYED: { // first, check, if we have just started if (m_Spell->GetDelayStart() != 0) { // no, we aren't, do the typical update // check, if we have channeled spell on our hands if (IsChanneledSpell(m_Spell->m_spellInfo)) { // evented channeled spell is processed separately, casted once after delay, and not destroyed till finish // check, if we have casting anything else except this channeled spell and autorepeat if (m_Spell->GetCaster()->IsNonMeleeSpellCasted(false, true, true)) { // another non-melee non-delayed spell is casted now, abort m_Spell->cancel(); } else { // do the action (pass spell to channeling state) m_Spell->handle_immediate(); } // event will be re-added automatically at the end of routine) } else { // run the spell handler and think about what we can do next uint64 t_offset = e_time - m_Spell->GetDelayStart(); uint64 n_offset = m_Spell->handle_delayed(t_offset); if (n_offset) { // re-add us to the queue m_Spell->GetCaster()->AddEvent(this, m_Spell->GetDelayStart() + n_offset, false); return false; // event not complete } // event complete // finish update event will be re-added automatically at the end of routine) } } else { // delaying had just started, record the moment m_Spell->SetDelayStart(e_time); // re-plan the event for the delay moment m_Spell->GetCaster()->AddEvent(this, e_time + m_Spell->GetDelayMoment(), false); return false; // event not complete } } break; default: { // all other states // event will be re-added automatically at the end of routine) } break; } // spell processing not complete, plan event on the next update interval m_Spell->GetCaster()->AddEvent(this, e_time + 1, false); return false; // event not complete }