diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 1d2826409f..1a262241f9 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -3145,7 +3145,7 @@ void Creature::SetSpellFocus(Spell const* focusSpell, WorldObject const* target) ObjectGuid newTarget = [&]() { // Spells that do not allow turning or channeled spells that will track their channel target do not set a unit field target - if (turnDisabled || noTurnDuringCast || spellInfo->HasAttribute(SPELL_ATTR1_CHANNEL_TRACK_TARGET) || target == this) + if (turnDisabled || noTurnDuringCast || spellInfo->HasAttribute(SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL) || target == this) return ObjectGuid::Empty; return target->GetGUID(); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index a0d2f1a36c..008e2fd791 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3192,7 +3192,7 @@ bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const Unit* WorldObject::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo) { // Patch 1.2 notes: Spell Reflection no longer reflects abilities - if (spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REDIRECTED) || spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES)) + if (spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR1_NO_REDIRECTION) || spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES)) return victim; Unit::AuraEffectList const& magnetAuras = victim->GetAuraEffectsByType(SPELL_AURA_SPELL_MAGNET); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9a1da7499a..547ce8083c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5207,12 +5207,15 @@ inline int32 SkillGainChance(Player const* player, uint32 SkillValue, uint32 Gra return chance; } -bool Player::UpdateCraftSkill(uint32 spellid) +bool Player::UpdateCraftSkill(SpellInfo const* spellInfo) { - TC_LOG_DEBUG("entities.player.skills", "Player::UpdateCraftSkill: Player '%s' (%s), SpellID: %d", - GetName().c_str(), GetGUID().ToString().c_str(), spellid); + if (spellInfo->HasAttribute(SPELL_ATTR1_NO_SKILL_INCREASE)) + return false; - SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellid); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateCraftSkill: Player '%s' (%s), SpellID: %d", + GetName().c_str(), GetGUID().ToString().c_str(), spellInfo->Id); + + SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellInfo->Id); for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) { @@ -5221,10 +5224,9 @@ bool Player::UpdateCraftSkill(uint32 spellid) uint32 SkillValue = GetPureSkillValue(_spell_idx->second->SkillLine); // Alchemy Discoveries here - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spellid); - if (spellEntry && spellEntry->Mechanic == MECHANIC_DISCOVERY) + if (spellInfo && spellInfo->Mechanic == MECHANIC_DISCOVERY) { - if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->SkillLine, spellid, this)) + if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->SkillLine, spellInfo->Id, this)) LearnSpell(discoveredSpell, false); } @@ -5234,7 +5236,6 @@ bool Player::UpdateCraftSkill(uint32 spellid) if (craft_skill_points) { craft_skill_points *= craft_skill_gain; - TC_LOG_INFO("entities.player", "craft_skill_points is %u, spellID: %u, skillID: %u", craft_skill_points, spellid, _spell_idx->second->SkillLine); return UpdateSkillPro(_spell_idx->second->SkillLine, SkillGainChance(this, SkillValue, _spell_idx->second->TrivialSkillLineRankHigh, (_spell_idx->second->TrivialSkillLineRankHigh + _spell_idx->second->TrivialSkillLineRankLow) / 2, diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index b64f995555..325ab724c5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1754,7 +1754,7 @@ class TC_GAME_API Player : public Unit, public GridObject bool UpdateSkill(uint32 skill_id, uint32 step); bool UpdateSkillPro(uint16 skillId, int32 chance, uint32 step); - bool UpdateCraftSkill(uint32 spellid); + bool UpdateCraftSkill(SpellInfo const* spellInfo); bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1); bool UpdateFishingSkill(); void GiveXpForGather(uint32 const& skillId); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 266a1e79c3..c1a8bb2e68 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -443,7 +443,7 @@ void Unit::Update(uint32 p_time) { // Prioritize tracking channeled spells above unit targets if they should both be present at the same time. Spell const* channeledSpell = GetCurrentSpell(CURRENT_CHANNELED_SPELL); - if (channeledSpell && channeledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR1_CHANNEL_TRACK_TARGET)) + if (channeledSpell && channeledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL)) { ObjectGuid const channelGuid = GetChannelObjectGuid(); if (!channelGuid.IsEmpty() && channelGuid != GetGUID()) @@ -3651,7 +3651,7 @@ void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId } } -void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer) +void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer, int32 stolenCharges /*= 1*/) { AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId); for (AuraMap::iterator iter = range.first; iter != range.second;) @@ -3685,9 +3685,9 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, W if (Aura* oldAura = unitStealer->GetAura(aura->GetId(), aura->GetCasterGUID())) { if (stealCharge) - oldAura->ModCharges(1); + oldAura->ModCharges(stolenCharges); else - oldAura->ModStackAmount(1); + oldAura->ModStackAmount(stolenCharges); oldAura->SetDuration(int32(dur)); } else @@ -3712,16 +3712,16 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, W caster->GetLimitedCastAuras(aura->GetId()).push_back(aura); } // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate - newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, aura->GetCritChance(), aura->CanApplyResilience(), &damage[0]); + newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? stolenCharges : aura->GetCharges(), stolenCharges, recalculateMask, aura->GetCritChance(), aura->CanApplyResilience(), &damage[0]); newAura->ApplyForTargets(); } } } if (stealCharge) - aura->ModCharges(-1, AuraRemoveFlags::ByEnemySpell); + aura->ModCharges(-stolenCharges, AuraRemoveFlags::ByEnemySpell); else - aura->ModStackAmount(-1, AuraRemoveFlags::ByEnemySpell); + aura->ModStackAmount(-stolenCharges, AuraRemoveFlags::ByEnemySpell); return; } @@ -4033,7 +4033,27 @@ void Unit::RemoveAurasOnEvade() // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle // don't remove clone caster on evade (to be verified) - RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_CLONE_CASTER); + auto evadeAuraCheck = [](Aura const* aura) + { + if (aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE)) + return false; + + if (aura->HasEffectType(SPELL_AURA_CLONE_CASTER)) + return false; + + if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT)) + return false; + + return true; + }; + + auto evadeAuraApplicationCheck = [&evadeAuraCheck](AuraApplication const* aurApp) + { + return evadeAuraCheck(aurApp->GetBase()); + }; + + RemoveAppliedAuras(evadeAuraApplicationCheck); + RemoveOwnedAuras(evadeAuraCheck); } void Unit::RemoveAllAurasOnDeath() @@ -7303,7 +7323,7 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)) return false; - if (spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) + if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) return false; if (uint32 schoolMask = spellInfo->GetSchoolMask()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index b2a7a10147..f620732cc2 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -115,12 +115,12 @@ class DispelableAura uint8 GetDispelCharges() const { return _charges; } void IncrementCharges() { ++_charges; } - bool DecrementCharge() + bool DecrementCharge(uint8 charges) { if (!_charges) return false; - --_charges; + _charges -= charges; return _charges > 0; } @@ -1344,7 +1344,7 @@ class TC_GAME_API Unit : public WorldObject void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveFlags removeMode = AuraRemoveFlags::ByDefault); void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveFlags removeMode = AuraRemoveFlags::ByDefault); void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved = 1); - void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer); + void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer, int32 stolenCharges = 1); void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid); void RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID = ObjectGuid::Empty, Aura* except = nullptr, bool negative = true, bool positive = true); void RemoveNotOwnLimitedTargetAuras(bool onPhaseChange = false); diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 5dabf960a8..ef2778c780 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -387,40 +387,41 @@ enum SpellAttr0 : uint32 SPELL_ATTR0_NO_AURA_CANCEL = 0x80000000 // No Aura Cancel DESCRIPTION Prevents the player from voluntarily canceling a positive aura }; -enum SpellAttr1 +// EnumUtils: DESCRIBE THIS +enum SpellAttr1 : uint32 { - SPELL_ATTR1_DISMISS_PET = 0x00000001, // 0 for spells without this flag client doesn't allow to summon pet if caster has a pet - SPELL_ATTR1_DRAIN_ALL_POWER = 0x00000002, // 1 use all power (Only paladin Lay of Hands and Bunyanize) - SPELL_ATTR1_CHANNELED = 0x00000004, // 2 Is Channeled - SPELL_ATTR1_CANT_BE_REDIRECTED = 0x00000008, // 3 - SPELL_ATTR1_UNK4 = 0x00000010, // 4 stealth and whirlwind - SPELL_ATTR1_NOT_BREAK_STEALTH = 0x00000020, // 5 Not break stealth - SPELL_ATTR1_SELF_CHANNELED = 0x00000040, // 6 Is Self Channeled - SPELL_ATTR1_CANT_BE_REFLECTED = 0x00000080, // 7 - SPELL_ATTR1_CANT_TARGET_IN_COMBAT = 0x00000100, // 8 can target only out of combat units - SPELL_ATTR1_MELEE_COMBAT_START = 0x00000200, // 9 player starts melee combat after this spell is cast - SPELL_ATTR1_NO_THREAT = 0x00000400, // 10 no generates threat on cast 100% (old NO_INITIAL_AGGRO) - SPELL_ATTR1_DONT_REFRESH_DURATION_ON_RECAST = 0x00000800, // 11 aura will not refresh its duration when recast - SPELL_ATTR1_IS_PICKPOCKET = 0x00001000, // 12 Pickpocket - SPELL_ATTR1_FARSIGHT = 0x00002000, // 13 Client removes farsight on aura loss - SPELL_ATTR1_CHANNEL_TRACK_TARGET = 0x00004000, // 14 Client automatically forces player to face target when channeling - SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY = 0x00008000, // 15 remove auras on immunity - SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE = 0x00010000, // 16 on immuniy - SPELL_ATTR1_UNAUTOCASTABLE_BY_PET = 0x00020000, // 17 - SPELL_ATTR1_UNK18 = 0x00040000, // 18 stun, polymorph, daze, hex - SPELL_ATTR1_CANT_TARGET_SELF = 0x00080000, // 19 - SPELL_ATTR1_FINISHING_MOVE_DAMAGE = 0x00100000, // 20 Finishing Move - Damage - SPELL_ATTR1_UNK21 = 0x00200000, // 21 - SPELL_ATTR1_FINISHING_MOVE_DURATION = 0x00400000, // 22 Finishing Move - Duration - SPELL_ATTR1_UNK23 = 0x00800000, // 23 - SPELL_ATTR1_IS_FISHING = 0x01000000, // 24 only fishing spells - SPELL_ATTR1_UNK25 = 0x02000000, // 25 - SPELL_ATTR1_UNK26 = 0x04000000, // 26 works correctly with [target=focus] and [target=mouseover] macros? - SPELL_ATTR1_DISCOUNT_POWER_ON_MISS = 0x08000000, // 27 Discount Power On Miss - SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR = 0x10000000, // 28 client doesn't display these spells in aura bar - SPELL_ATTR1_CHANNEL_DISPLAY_SPELL_NAME = 0x20000000, // 29 spell name is displayed in cast bar instead of 'channeling' text - SPELL_ATTR1_ENABLE_AT_DODGE = 0x40000000, // 30 Overpower - SPELL_ATTR1_CAST_WHEN_LEARNED = 0x80000000 // 31 Cast When Learned + SPELL_ATTR1_DISMISS_PET_FIRST = 0x00000001, // Dismiss Pet First DESCRIPTION Without this attribute, summoning spells will fail if caster already has a pet + SPELL_ATTR1_USE_ALL_MANA = 0x00000002, // Use All Mana DESCRIPTION Ignores listed power cost and drains entire pool instead + SPELL_ATTR1_IS_CHANNELLED = 0x00000004, // Is Channelled DESCRIPTION Both "channeled" attributes have identical handling in server & client + SPELL_ATTR1_NO_REDIRECTION = 0x00000008, // No Redirection DESCRIPTION Spell will not be attracted by SPELL_MAGNET auras (Grounding Totem) + SPELL_ATTR1_NO_SKILL_INCREASE = 0x00000010, // No Skill Increase + SPELL_ATTR1_ALLOW_WHILE_STEALTHED = 0x00000020, // Allow While Stealthed + SPELL_ATTR1_IS_SELF_CHANNELLED = 0x00000040, // Is Self Channelled DESCRIPTION Both "channeled" attributes have identical handling in server & client + SPELL_ATTR1_NO_REFLECTION = 0x00000080, // No Reflection DESCRIPTION Spell will pierce through Spell Reflection and similar + SPELL_ATTR1_ONLY_PEACEFUL_TARGETS = 0x00000100, // Only Peaceful Targets DESCRIPTION Target cannot be in combat + SPELL_ATTR1_INITIATES_COMBAT_ENABLES_AUTO_ATTACK = 0x00000200, // Initiates Combat (Enables Auto-Attack) (client only) DESCRIPTION Caster will begin auto-attacking the target on cast + SPELL_ATTR1_NO_THREAT = 0x00000400, // Does not generate threat DESCRIPTION Also does not cause target to engage + SPELL_ATTR1_AURA_UNIQUE = 0x00000800, // Aura Unique DESCRIPTION Aura will not refresh its duration when recast + SPELL_ATTR1_FAILURE_BREAKS_STEALTH = 0x00001000, // Failure Breaks Stealth + SPELL_ATTR1_TOGGLE_FAR_SIGHT = 0x00002000, // Toggle Far Sight (client only) + SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL = 0x00004000, // Track Target in Channel DESCRIPTION While channeling, adjust facing to face target + SPELL_ATTR1_IMMUNITY_PURGES_EFFECT = 0x00008000, // Immunity Purges Effect DESCRIPTION For immunity spells, cancel all auras that this spell would make you immune to when the spell is applied + SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS = 0x00010000, /*WRONG IMPL*/ // Immunity to Hostile & Friendly Effects DESCRIPTION Will not pierce Divine Shield, Ice Block and other full invulnerabilities + SPELL_ATTR1_NO_AUTOCAST_AI = 0x00020000, // No AutoCast (AI) + SPELL_ATTR1_PREVENTS_ANIM = 0x00040000, /*NYI*/ // Prevents Anim DESCRIPTION Auras apply UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT + SPELL_ATTR1_EXCLUDE_CASTER = 0x00080000, // Exclude Caster + SPELL_ATTR1_FINISHING_MOVE_DAMAGE = 0x00100000, // Finishing Move - Damage + SPELL_ATTR1_THREAT_ONLY_ON_MISS = 0x00200000, /*NYI*/ // Threat only on Miss + SPELL_ATTR1_FINISHING_MOVE_DURATION = 0x00400000, // Finishing Move - Duration + SPELL_ATTR1_IGNORE_OWNERS_DEATH = 0x00800000, /*NYI*/ // Ignore Owner's Death + SPELL_ATTR1_SPECIAL_SKILLUP = 0x01000000, // Special Skillup + SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT = 0x02000000, // Aura Stays After Combat + SPELL_ATTR1_REQUIRE_ALL_TARGETS = 0x04000000, /*NYI, UNK*/ // Require All Targets + SPELL_ATTR1_DISCOUNT_POWER_ON_MISS = 0x08000000, // Discount Power On Miss + SPELL_ATTR1_NO_AURA_ICON = 0x10000000, // No Aura Icon (client only) + SPELL_ATTR1_NAME_IN_CHANNEL_BAR = 0x20000000, // Name in Channel Bar (client only) + SPELL_ATTR1_DISPEL_ALL_STACKS = 0x40000000, // Dispel All Stacks + SPELL_ATTR1_CAST_WHEN_LEARNED = 0x80000000 // Cast When Learned }; enum SpellAttr2 diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 91dbe5041f..8e875e4dc4 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -3325,7 +3325,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); // remove all flag auras (they are positive, but they must be removed when you are immune) - if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) + if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT) && GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD)) target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); } diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index ad248643fc..283970fda8 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1037,7 +1037,7 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveFlags removeMode /*= AuraRemoveFl EnumFlag removeFlags = removeMode; - bool refresh = stackAmount >= GetStackAmount() && (m_spellInfo->StackAmount || !m_spellInfo->HasAttribute(SPELL_ATTR1_DONT_REFRESH_DURATION_ON_RECAST)); + bool refresh = stackAmount >= GetStackAmount() && (m_spellInfo->StackAmount || !m_spellInfo->HasAttribute(SPELL_ATTR1_AURA_UNIQUE)); // Update stack amount SetStackAmount(stackAmount); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index b34f507c9c..9ce0fc772d 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -667,7 +667,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO // Determine if spell can be reflected back to the caster // Patch 1.2 notes: Spell Reflection no longer reflects abilities m_canReflect = caster->IsUnit() && m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) - && !m_spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REFLECTED) && !m_spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) + && !m_spellInfo->HasAttribute(SPELL_ATTR1_NO_REFLECTION) && !m_spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !m_spellInfo->IsPassive(); CleanupTargetList(); @@ -2673,7 +2673,7 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell) } // Failed Pickpocket, reveal rogue - if (MissCondition == SPELL_MISS_RESIST && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && spell->unitTarget->GetTypeId() == TYPEID_UNIT) + if (MissCondition == SPELL_MISS_RESIST && spell->m_spellInfo->HasAttribute(SPELL_ATTR1_FAILURE_BREAKS_STEALTH) && spell->unitTarget->GetTypeId() == TYPEID_UNIT) { Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit()); unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting); @@ -3566,7 +3566,7 @@ void Spell::_cast(bool skipCheck) } if (Unit* unitCaster = m_caster->ToUnit()) - if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET)) + if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET_FIRST)) if (Creature* pet = ObjectAccessor::GetCreature(*m_caster, unitCaster->GetPetGUID())) pet->DespawnOrUnsummon(); @@ -4941,27 +4941,10 @@ void Spell::SendChannelStart(uint32 duration) if (!unitCaster) return; - ObjectGuid channelTarget = m_targets.GetObjectTargetGUID(); - if (!channelTarget && !m_spellInfo->NeedsExplicitUnitTarget()) - { - // this is for TARGET_SELECT_CATEGORY_NEARBY - if (m_UniqueTargetInfo.size() + m_UniqueGOTargetInfo.size() == 1) - channelTarget = !m_UniqueTargetInfo.empty() ? m_UniqueTargetInfo.front().TargetGUID : m_UniqueGOTargetInfo.front().TargetGUID; - else - { - // We assume that when we have a channel spell with more than one unique unit target that there is a caster and a target. - // We don't want the caster but the target so we are looking for a non-caster entry within the target list - for (auto& itr : m_UniqueTargetInfo) - { - if (itr.TargetGUID != m_caster->GetGUID()) - channelTarget = itr.TargetGUID; - } - } - } - - // There must always be a channel target - if (!channelTarget) - channelTarget = m_caster->GetGUID(); + WorldPackets::Spells::ChannelStart packet; + packet.CasterGUID = m_caster->GetGUID(); + packet.SpellID = m_spellInfo->Id; + packet.ChannelDuration = duration; uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY; uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask(); @@ -4970,15 +4953,6 @@ void Spell::SendChannelStart(uint32 duration) if (schoolImmunityMask || mechanicImmunityMask) castFlags |= CAST_FLAG_IMMUNITY; - uint8 ticks = m_spellInfo->GetMaxTicks(); - if (m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY)) - ++ticks; - - WorldPackets::Spells::ChannelStart packet; - packet.CasterGUID = m_caster->GetGUID(); - packet.SpellID = m_spellInfo->Id; - packet.ChannelDuration = duration; - if (castFlags & CAST_FLAG_IMMUNITY) { packet.InterruptImmunities.emplace(); @@ -4986,26 +4960,62 @@ void Spell::SendChannelStart(uint32 duration) packet.InterruptImmunities->Immunities = mechanicImmunityMask; // CastImmunities } + if (!m_targets.HasDst()) + { + uint32 channelAuraMask = 0; + uint32 explicitTargetEffectMask = 0xFFFFFFFF; + // if there is an explicit target, only add channel objects from effects that also hit it + if (!m_targets.GetUnitTargetGUID().IsEmpty()) + { + auto explicitTargetItr = std::find_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo const& target) + { + return target.TargetGUID == m_targets.GetUnitTargetGUID(); + }); + if (explicitTargetItr != m_UniqueTargetInfo.end()) + explicitTargetEffectMask = explicitTargetItr->EffectMask; + } + + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + SpellEffectInfo const& spellEffectInfo = m_spellInfo->Effects[i]; + if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && (explicitTargetEffectMask & (1u << i))) + channelAuraMask |= 1 << i; + } + + for (TargetInfo const& target : m_UniqueTargetInfo) + { + if (!(target.EffectMask & channelAuraMask)) + continue; + + SpellAttr1 requiredAttribute = target.TargetGUID != unitCaster->GetGUID() ? SPELL_ATTR1_IS_CHANNELLED : SPELL_ATTR1_IS_SELF_CHANNELLED; + if (!m_spellInfo->HasAttribute(requiredAttribute)) + continue; + + unitCaster->SetChannelObjectGuid(target.TargetGUID); + } + + for (GOTargetInfo const& target : m_UniqueGOTargetInfo) + if (target.EffectMask & channelAuraMask) + unitCaster->SetChannelObjectGuid(target.TargetGUID); + } + else if (m_spellInfo->HasAttribute(SPELL_ATTR1_IS_SELF_CHANNELLED)) + unitCaster->SetChannelObjectGuid(unitCaster->GetGUID()); + + if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION)) { castFlags |= CAST_FLAG_HEAL_PREDICTION; WorldPackets::Spells::SpellHealPrediction predict; UpdateSpellHealPrediction(predict); - packet.HealPrediction.emplace(channelTarget, predict); + packet.HealPrediction.emplace(unitCaster->GetChannelObjectGuid(), predict); } m_caster->SendMessageToSet(packet.Write(), true); - m_timer = duration; - if (channelTarget) - { - unitCaster->SetChannelObjectGuid(channelTarget); - - if (Creature* creatureCaster = m_caster->ToCreature()) - if (!creatureCaster->HasSpellFocus(this)) - creatureCaster->SetSpellFocus(this, ObjectAccessor::GetWorldObject(*creatureCaster, channelTarget)); - } + if (Creature* creatureCaster = m_caster->ToCreature()) + if (!creatureCaster->HasSpellFocus(this)) + creatureCaster->SetSpellFocus(this, ObjectAccessor::GetWorldObject(*creatureCaster, unitCaster->GetChannelObjectGuid())); m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id); } @@ -5550,7 +5560,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint { if (m_spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) || m_spellInfo->IsNextMeleeSwingSpell() - || m_spellInfo->HasAttribute(SPELL_ATTR1_MELEE_COMBAT_START) + || m_spellInfo->HasAttribute(SPELL_ATTR1_INITIATES_COMBAT_ENABLES_AUTO_ATTACK) || m_spellInfo->HasAttribute(SPELL_ATTR2_INITIATE_COMBAT_POST_CAST) || m_spellInfo->HasEffect(SPELL_EFFECT_ATTACK) || m_spellInfo->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG) @@ -6157,7 +6167,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint switch (SummonProperties->Control) { case SUMMON_CATEGORY_PET: - if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && unitCaster->GetPetGUID()) + if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET_FIRST) && unitCaster->GetPetGUID()) return SPELL_FAILED_ALREADY_HAVE_SUMMON; [[fallthrough]]; // check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET*/ case SUMMON_CATEGORY_PUPPET: @@ -6173,7 +6183,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint { if (m_targets.GetUnitTarget()->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_BAD_TARGETS; - if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && m_targets.GetUnitTarget()->GetPetGUID()) + if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET_FIRST) && m_targets.GetUnitTarget()->GetPetGUID()) return SPELL_FAILED_ALREADY_HAVE_SUMMON; } break; @@ -6192,7 +6202,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (Pet* pet = unitCaster->ToPlayer()->GetPet()) pet->CastSpell(pet, 32752, pet->GetGUID()); } - else if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET)) + else if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET_FIRST)) return SPELL_FAILED_ALREADY_HAVE_SUMMON; } @@ -6325,7 +6335,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_CHARM || m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_POSSESS) { - if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && unitCaster->GetPetGUID()) + if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET_FIRST) && unitCaster->GetPetGUID()) return SPELL_FAILED_ALREADY_HAVE_SUMMON; if (unitCaster->GetCharmedGUID()) @@ -7712,7 +7722,7 @@ bool Spell::IsIgnoringCooldowns() const bool Spell::IsFocusDisabled() const { return ((_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING) != 0 - || (m_spellInfo->IsChanneled() && !m_spellInfo->HasAttribute(SpellAttr1(SPELL_ATTR1_CHANNEL_TRACK_TARGET | SPELL_ATTR1_SELF_CHANNELED)))); + || (m_spellInfo->IsChanneled() && !m_spellInfo->HasAttribute(SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL))); } bool Spell::IsProcDisabled() const diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index e34d955c07..23f7963a34 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1370,7 +1370,7 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype) // we succeeded in creating at least one item, so a levelup is possible if (bgType == 0) - player->UpdateCraftSkill(m_spellInfo->Id); + player->UpdateCraftSkill(m_spellInfo); } /* @@ -1406,7 +1406,7 @@ void Spell::EffectCreateItem2(SpellEffIndex effIndex) if (m_spellInfo->IsLootCrafting()) { player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell, false); - player->UpdateCraftSkill(m_spellInfo->Id); + player->UpdateCraftSkill(m_spellInfo); } else // If there's no random loot entries for this spell, pick the item associated with this spell { @@ -2069,12 +2069,17 @@ void Spell::EffectDispel(SpellEffIndex effIndex) return false; }); + uint8 dispelledCharges = 1; + if (itr->GetAura()->GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_ALL_STACKS)) + dispelledCharges = itr->GetDispelCharges(); + + if (successItr == successList.end()) - successList.emplace_back(itr->GetAura(), 0, 1); + successList.emplace_back(itr->GetAura(), 0, dispelledCharges); else successItr->IncrementCharges(); - if (!itr->DecrementCharge()) + if (!itr->DecrementCharge(dispelledCharges)) { --remaining; std::swap(*itr, dispelList[remaining]); @@ -2316,7 +2321,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) { // do not increase skill if vellum used if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST)) - player->UpdateCraftSkill(m_spellInfo->Id); + player->UpdateCraftSkill(m_spellInfo); uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue; if (!enchant_id) @@ -3976,7 +3981,7 @@ void Spell::EffectDisEnchant(SpellEffIndex /*effIndex*/) if (Player* caster = m_caster->ToPlayer()) { - caster->UpdateCraftSkill(m_spellInfo->Id); + caster->UpdateCraftSkill(m_spellInfo); caster->SendLoot(itemTarget->GetGUID(), LOOT_DISENCHANTING); } @@ -5135,7 +5140,7 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex) // Ok if exist some buffs for dispel try dispel it uint32 failCount = 0; - DispelList successList; + std::vector> successList; successList.reserve(damage); WorldPacket dataFail(SMSG_DISPEL_FAILED, 8 + 8 + 4 + 4 + damage * 4); @@ -5148,8 +5153,12 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex) if (itr->RollDispel()) { - successList.emplace_back(itr->GetAura()->GetId(), itr->GetAura()->GetCasterGUID()); - if (!itr->DecrementCharge()) + uint8 stolenCharges = 1; + if (itr->GetAura()->GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_ALL_STACKS)) + stolenCharges = itr->GetDispelCharges(); + + successList.emplace_back(itr->GetAura()->GetId(), itr->GetAura()->GetCasterGUID(), int32(stolenCharges)); + if (!itr->DecrementCharge(stolenCharges)) { --remaining; std::swap(*itr, stealList[remaining]); @@ -5182,11 +5191,11 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex) dataSuccess << uint32(m_spellInfo->Id); // dispel spell id dataSuccess << uint8(0); // not used dataSuccess << uint32(successList.size()); // count - for (auto itr = successList.begin(); itr != successList.end(); ++itr) + for (auto const& [spellId, auraCaster, stolenCharges] : successList) { - dataSuccess << uint32(itr->first); // Spell Id + dataSuccess << uint32(spellId); // Spell Id dataSuccess << uint8(0); // 0 - steals !=0 transfers - unitTarget->RemoveAurasDueToSpellBySteal(itr->first, itr->second, m_caster); + unitTarget->RemoveAurasDueToSpellBySteal(spellId, auraCaster, m_caster, stolenCharges); } m_caster->SendMessageToSet(&dataSuccess, true); } diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index d11b32890b..cd0ea2790a 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1319,7 +1319,7 @@ bool SpellInfo::IsAutocastable() const { if (IsPassive()) return false; - if (HasAttribute(SPELL_ATTR1_UNAUTOCASTABLE_BY_PET)) + if (HasAttribute(SPELL_ATTR1_NO_AUTOCAST_AI)) return false; return true; } @@ -1460,7 +1460,7 @@ bool SpellInfo::IsPositiveEffect(uint8 effIndex) const bool SpellInfo::IsChanneled() const { - return HasAttribute(SpellAttr1(SPELL_ATTR1_CHANNELED | SPELL_ATTR1_SELF_CHANNELED)); + return HasAttribute(SpellAttr1(SPELL_ATTR1_IS_CHANNELLED | SPELL_ATTR1_IS_SELF_CHANNELLED)); } bool SpellInfo::IsMoveAllowedChannel() const @@ -1480,7 +1480,7 @@ bool SpellInfo::IsNextMeleeSwingSpell() const bool SpellInfo::IsBreakingStealth() const { - return !HasAttribute(SPELL_ATTR1_NOT_BREAK_STEALTH); + return !HasAttribute(SPELL_ATTR1_ALLOW_WHILE_STEALTHED); } bool SpellInfo::IsRangedWeaponSpell() const @@ -1568,7 +1568,7 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const return true; // these spells (Cyclone for example) can pierce all... - if (HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) + if (HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) { // ...but not these (Divine shield, Ice block, Cyclone and Banish for example) if (auraSpellInfo->Mechanic != MECHANIC_IMMUNE_SHIELD && @@ -1578,7 +1578,7 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const } // Dispels other auras on immunity, check if this spell makes the unit immune to aura - if (HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) && CanSpellProvideImmunityAgainstAura(auraSpellInfo)) + if (HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT) && CanSpellProvideImmunityAgainstAura(auraSpellInfo)) return true; return false; @@ -1595,7 +1595,7 @@ bool SpellInfo::CanDispelAura(SpellInfo const* auraSpellInfo) const return true; // These auras (Cyclone for example) are not dispelable - if ((auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && auraSpellInfo->Mechanic != MECHANIC_NONE) + if ((auraSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && auraSpellInfo->Mechanic != MECHANIC_NONE) || auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) return false; @@ -1876,7 +1876,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject const* target, bool implicit /*= true*/) const { - if (HasAttribute(SPELL_ATTR1_CANT_TARGET_SELF) && caster == target) + if (HasAttribute(SPELL_ATTR1_EXCLUDE_CASTER) && caster == target) return SPELL_FAILED_BAD_TARGETS; // check visibility - ignore stealth for implicit (area) targets @@ -1889,7 +1889,7 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co if (unitTarget) { // spells cannot be cast if target has a pet in combat either - if (HasAttribute(SPELL_ATTR1_CANT_TARGET_IN_COMBAT) && (unitTarget->IsInCombat() || unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT))) + if (HasAttribute(SPELL_ATTR1_ONLY_PEACEFUL_TARGETS) && (unitTarget->IsInCombat() || unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT))) return SPELL_FAILED_TARGET_AFFECTING_COMBAT; // only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts @@ -3105,7 +3105,7 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app { target->ApplySpellImmune(Id, IMMUNITY_SCHOOL, schoolImmunity, apply); - if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) + if (apply && HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT)) { target->RemoveAppliedAuras([this, schoolImmunity](AuraApplication const* aurApp) -> bool { @@ -3127,7 +3127,7 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app if (mechanicImmunity & (1 << i)) target->ApplySpellImmune(Id, IMMUNITY_MECHANIC, i, apply); - if(apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) + if(apply && HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT)) target->RemoveAurasWithMechanic(mechanicImmunity, AuraRemoveFlags::ByDefault, Id); } @@ -3135,7 +3135,7 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app { target->ApplySpellImmune(Id, IMMUNITY_DISPEL, dispelImmunity, apply); - if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) + if (apply && HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT)) { target->RemoveAppliedAuras([dispelImmunity](AuraApplication const* aurApp) -> bool { @@ -3159,7 +3159,7 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app for (AuraType auraType : immuneInfo->AuraTypeImmune) { target->ApplySpellImmune(Id, IMMUNITY_STATE, auraType, apply); - if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) + if (apply && HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT)) target->RemoveAurasByType(auraType); } @@ -3176,7 +3176,7 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf { ImmunityInfo const* immuneInfo = _immunityInfo + i; - if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) + if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) { if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask) if ((auraSpellInfo->SchoolMask & schoolImmunity) != 0) @@ -3249,7 +3249,7 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf // based on client Spell_C::CancelsAuraEffect bool SpellInfo::SpellCancelsAuraEffect(SpellInfo const* auraSpellInfo, uint8 auraEffIndex) const { - if (!HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) + if (!HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT)) return false; if (auraSpellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES)) @@ -3534,7 +3534,7 @@ int32 SpellInfo::CalcPowerCost(WorldObject const* caster, SpellSchoolMask school return 0; // Spell drain all exist power on cast (Only paladin lay of Hands) - if (HasAttribute(SPELL_ATTR1_DRAIN_ALL_POWER)) + if (HasAttribute(SPELL_ATTR1_USE_ALL_MANA)) { // If power type - health drain all if (PowerType == POWER_HEALTH) @@ -3923,7 +3923,7 @@ bool _isPositiveEffectImpl(SpellInfo const* spellInfo, uint8 effIndex, std::unor } // Special case: effects which determine positivity of whole spell - if (spellInfo->HasAttribute(SPELL_ATTR1_DONT_REFRESH_DURATION_ON_RECAST)) // @todo: rename to and handle SPELL_ATTR1_AURA_UNIQUE + if (spellInfo->HasAttribute(SPELL_ATTR1_AURA_UNIQUE)) // @todo: rename to and handle SPELL_ATTR1_AURA_UNIQUE { // check for targets, there seems to be an assortment of dummy triggering spells that should be negative for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index a73b5faf18..01ba479967 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3705,7 +3705,7 @@ void SpellMgr::LoadSpellInfoCorrections() // spell should dispel area aura, but doesn't have the attribute // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity // that will be clear if we get more spells with problem like this - spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; + spellInfo->AttributesEx |= SPELL_ATTR1_IMMUNITY_PURGES_EFFECT; }); // Spinning Up (Mimiron) @@ -3925,7 +3925,7 @@ void SpellMgr::LoadSpellInfoCorrections() ApplySpellFix({ 69783, 69797, 69799, 69802 }, [](SpellInfo* spellInfo) { // Those spells are cast on creatures with same entry as caster while they have TARGET_UNIT_NEARBY_ENTRY. - spellInfo->AttributesEx |= SPELL_ATTR1_CANT_TARGET_SELF; + spellInfo->AttributesEx |= SPELL_ATTR1_EXCLUDE_CASTER; }); // Awaken Plagued Zombies @@ -4784,7 +4784,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Spore Cloud ApplySpellFix({ 75701 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED; + spellInfo->AttributesEx &= ~SPELL_ATTR1_IS_CHANNELLED; }); // Noxious Spores @@ -4857,7 +4857,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Gaze of Occu'thar ApplySpellFix({ 96942, 101009 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED; + spellInfo->AttributesEx &= ~SPELL_ATTR1_IS_CHANNELLED; }); // Meteor Slash @@ -4968,7 +4968,7 @@ void SpellMgr::LoadSpellInfoCorrections() 100190 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED; + spellInfo->AttributesEx &= ~SPELL_ATTR1_IS_CHANNELLED; }); // Fixate @@ -5202,7 +5202,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Nurture ApplySpellFix({ 85425 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx &= ~SPELL_ATTR1_SELF_CHANNELED; + spellInfo->AttributesEx &= ~SPELL_ATTR1_IS_CHANNELLED; }); // Soothing Breeze diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index 240c445ac4..56776603d3 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -1050,7 +1050,7 @@ struct npc_thorim_trashAI : public ScriptedAI static Unit* GetHealTarget(SpellInfo const* spellInfo, Unit* caster) { Unit* healTarget = nullptr; - if (!spellInfo->HasAttribute(SPELL_ATTR1_CANT_TARGET_SELF) && !roll_chance_f(caster->GetHealthPct()) && ((caster->GetHealth() + GetRemainingHealOn(caster) + GetTotalHeal(spellInfo, caster)) <= caster->GetMaxHealth())) + if (!spellInfo->HasAttribute(SPELL_ATTR1_EXCLUDE_CASTER) && !roll_chance_f(caster->GetHealthPct()) && ((caster->GetHealth() + GetRemainingHealOn(caster) + GetTotalHeal(spellInfo, caster)) <= caster->GetMaxHealth())) healTarget = caster; else healTarget = GetUnitWithMostMissingHp(spellInfo, caster); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 8d0d752031..5f027b1ebf 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -2729,7 +2729,7 @@ class spell_gen_profession_research : public SpellScriptLoader if (uint32 discoveredSpellId = GetExplicitDiscoverySpell(spellId, caster)) caster->LearnSpell(discoveredSpellId, false); - caster->UpdateCraftSkill(spellId); + caster->UpdateCraftSkill(GetSpellInfo()); } void Register() override