From 3c0cf32b43c11fa673abd77312fc5ca67d9b50ed Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 21 Oct 2023 20:32:32 +0200 Subject: [PATCH] Core/Spells: Named and implemented most of SpellAttr7 --- src/server/game/Entities/Object/Object.cpp | 6 +- src/server/game/Entities/Unit/Unit.cpp | 40 ++++--- src/server/game/Entities/Unit/Unit.h | 2 +- src/server/game/Miscellaneous/SharedDefines.h | 66 +++++------ .../game/Spells/Auras/SpellAuraEffects.cpp | 4 +- src/server/game/Spells/Auras/SpellAuras.cpp | 12 ++ src/server/game/Spells/Spell.cpp | 104 ++++++++---------- src/server/game/Spells/Spell.h | 1 + src/server/game/Spells/SpellEffects.cpp | 6 +- src/server/game/Spells/SpellInfo.cpp | 7 +- src/server/game/Spells/SpellMgr.cpp | 15 +-- .../icecrown_citadel_teleport.cpp | 2 +- 12 files changed, 135 insertions(+), 130 deletions(-) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 8de5ab7dfc..d09e8e5e9b 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2484,7 +2484,7 @@ int32 WorldObject::ModSpellDuration(SpellInfo const* spellInfo, WorldObject cons return duration; // some auras are not affected by duration modifiers - if (spellInfo->HasAttribute(SPELL_ATTR7_IGNORE_DURATION_MODS)) + if (spellInfo->HasAttribute(SPELL_ATTR7_NO_TARGET_DURATION_MOD)) return duration; // cut duration only of negative effects @@ -2583,7 +2583,7 @@ SpellMissInfo WorldObject::MagicSpellHitResult(Unit* victim, SpellInfo const* sp if (spellInfo->HasAttribute(SPELL_ATTR3_NO_AVOIDANCE)) return SPELL_MISS_NONE; - if (spellInfo->HasAttribute(SPELL_ATTR7_CANT_MISS)) + if (spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS)) return SPELL_MISS_NONE; SpellSchoolMask schoolMask = spellInfo->GetSchoolMask(); @@ -2700,7 +2700,7 @@ SpellMissInfo WorldObject::SpellHitResult(Unit* victim, SpellInfo const* spellIn reflectchance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_REFLECT_SPELLS_SCHOOL, spellInfo->GetSchoolMask()); if (reflectchance > 0 && roll_chance_i(reflectchance)) - return SPELL_MISS_REFLECT; + return spellInfo->HasAttribute(SPELL_ATTR7_REFLECTION_ONLY_DEFENDS) ? SPELL_MISS_DEFLECT : SPELL_MISS_REFLECT; } if (spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT)) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2b73b196c5..77085beb15 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -880,7 +880,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons if (Player* killer = attacker->ToPlayer()) { // in bg, count dmg if victim is also a player - if (victim->GetTypeId() == TYPEID_PLAYER) + if (victim->GetTypeId() == TYPEID_PLAYER && !(spellProto && spellProto->HasAttribute(SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD))) if (Battleground* bg = killer->GetBattleground()) bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); @@ -955,7 +955,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons if (damagetype != NODAMAGE && damagetype != DOT) { - if (victim != attacker && (!spellProto || !(spellProto->HasAttribute(SPELL_ATTR6_NO_PUSHBACK) || spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC)))) + if (victim != attacker && (!spellProto || !(spellProto->HasAttribute(SPELL_ATTR6_NO_PUSHBACK) || spellProto->HasAttribute(SPELL_ATTR7_DONT_CAUSE_SPELL_PUSHBACK) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC)))) { if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL]) { @@ -2303,8 +2303,8 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (spellInfo->HasAttribute(SPELL_ATTR0_NO_ACTIVE_DEFENSE)) return SPELL_MISS_NONE; - bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_CANT_DODGE); - bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_CANT_PARRY); + bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_DODGE); + bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_PARRY); bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_CANT_BLOCK); // if victim is casting or cc'd it can't avoid attacks @@ -3589,7 +3589,7 @@ void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId // Call OnDispel hook on AuraScript aura->CallScriptDispel(&dispelInfo); - if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES)) + if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES)) aura->ModCharges(-dispelInfo.GetRemovedCharges(), AuraRemoveFlags::ByEnemySpell); else aura->ModStackAmount(-dispelInfo.GetRemovedCharges(), AuraRemoveFlags::ByEnemySpell); @@ -3629,7 +3629,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, W } } - bool stealCharge = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES); + bool stealCharge = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES); // Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration())); @@ -4301,7 +4301,7 @@ void Unit::GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, // The charges / stack amounts don't count towards the total number of auras that can be dispelled. // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell // Polymorph instead of 1 / (5 + 1) -> 16%. - bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES); + bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES); uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount(); if (charges > 0) dispelList.emplace_back(aura, chance, charges); @@ -5056,10 +5056,21 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 spellID, uint32 damag /*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK; - if (typeMaskActor && actor) + SpellInfo const* spellInfo = [&]() -> SpellInfo const* + { + if (spell) + return spell->GetSpellInfo(); + if (damageInfo) + return damageInfo->GetSpellInfo(); + if (healInfo) + return healInfo->GetSpellInfo(); + return nullptr; + }(); + + if (typeMaskActor && actor && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS))) actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType); - if (typeMaskActionTarget && actionTarget) + if (typeMaskActionTarget && actionTarget && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS))) actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType); if (actor) @@ -5940,8 +5951,9 @@ void Unit::SetCharm(Unit* charm, bool apply) { if (Player* player = unit->ToPlayer()) { - if (Battleground* bg = player->GetBattleground()) - bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain); + if (!healInfo.GetSpellInfo() || !healInfo.GetSpellInfo()->HasAttribute(SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD)) + if (Battleground* bg = player->GetBattleground()) + bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain); // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) if (gain) @@ -12087,10 +12099,10 @@ bool Unit::CanApplyResilience() const *damage -= target->GetDamageReduction(*damage); } -int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const& casterGuid) const +int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const { damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask)); - if (casterGuid.IsAnyTypeCreature()) + if (npcCaster) damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, schoolMask)); return damage; @@ -12100,7 +12112,7 @@ int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid co // Crit or block - determined on damage calculation phase! (and can be both in some time) float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo /*= nullptr*/) const { - if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_CANT_MISS)) + if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS)) return 0.f; // Calculate miss chance diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 7592ae0bc8..4875d4c528 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1034,7 +1034,7 @@ class TC_GAME_API Unit : public WorldObject virtual bool CanApplyResilience() const; static void ApplyResilience(Unit const* victim, int32* damage); - int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const& casterGuid) const; + int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const; float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo = nullptr) const override; SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const override; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index cb457e1450..8f2eaa76a7 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -610,40 +610,40 @@ enum SpellAttr6 : uint32 SPELL_ATTR6_NO_CATEGORY_COOLDOWN_MODS = 0x80000000 // TITLE No Category Cooldown Mods }; -enum SpellAttr7 +enum SpellAttr7 : uint32 { - SPELL_ATTR7_UNK0 = 0x00000001, // 0 Shaman's new spells (Call of the ...), Feign Death. - SPELL_ATTR7_IGNORE_DURATION_MODS = 0x00000002, // 1 Duration is not affected by duration modifiers - SPELL_ATTR7_DISABLE_AURA_WHILE_DEAD = 0x00000004, // TITLE Disable Aura While Dead - SPELL_ATTR7_IS_CHEAT_SPELL = 0x00000008, // 3 Cannot cast if caster doesn't have UnitFlag2 & UNIT_FLAG2_ALLOW_CHEAT_SPELLS - SPELL_ATTR7_UNK4 = 0x00000010, // 4 Only 47883 (Soulstone Resurrection) and test spell. - SPELL_ATTR7_SUMMON_TOTEM = 0x00000020, // 5 Only Shaman totems. - SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE = 0x00000040, // 6 Does not cause spell pushback on damage - SPELL_ATTR7_UNK7 = 0x00000080, // 7 66218 (Launch) spell. - SPELL_ATTR7_HORDE_ONLY = 0x00000100, // 8 Teleports, mounts and other spells. - SPELL_ATTR7_ALLIANCE_ONLY = 0x00000200, // 9 Teleports, mounts and other spells. - SPELL_ATTR7_DISPEL_CHARGES = 0x00000400, // 10 Dispel and Spellsteal individual charges instead of whole aura. - SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER = 0x00000800, // 11 Only non-player casts interrupt, though Feral Charge - Bear has it. - SPELL_ATTR7_SILENCE_ONLY_NONPLAYER = 0x00001000, // 12 Not set in 3.2.2a. - SPELL_ATTR7_CAN_ALWAYS_BE_INTERRUPTED = 0x00002000, // 13 Can always be interrupted, even if caster is immune - SPELL_ATTR7_UNK14 = 0x00004000, // 14 Only 52150 (Raise Dead - Pet) spell. - SPELL_ATTR7_UNK15 = 0x00008000, // 15 Exorcism. Usable on players? 100% crit chance on undead and demons? - SPELL_ATTR7_HIDDEN_IN_SPELLBOOK_WHEN_LEARNED = 0x00010000, // 16 After learning these spells become hidden in spellbook (but are visible when not learned for low level characters) - SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell. - SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects. - SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones. - SPELL_ATTR7_UNK20 = 0x00100000, // 20 Blink, Divine Shield, Ice Block - SPELL_ATTR7_UNK21 = 0x00200000, // 21 Not set - SPELL_ATTR7_UNK22 = 0x00400000, // 22 - SPELL_ATTR7_CANT_DODGE = 0x00800000, // 23 No Attack Dodge - SPELL_ATTR7_CANT_PARRY = 0x01000000, // 24 No Attack Parry - SPELL_ATTR7_CANT_MISS = 0x02000000, // 25 No Attack Miss - SPELL_ATTR7_UNK26 = 0x04000000, // 26 - SPELL_ATTR7_UNK27 = 0x08000000, // 27 Not set - SPELL_ATTR7_CONSOLIDATED_RAID_BUFF = 0x10000000, // 28 May be collapsed in raid buff frame (clientside attribute) - SPELL_ATTR7_UNK29 = 0x20000000, // 29 only 69028, 71237 - SPELL_ATTR7_UNK30 = 0x40000000, // 30 Burning Determination, Divine Sacrifice, Earth Shield, Prayer of Mending - SPELL_ATTR7_CLIENT_INDICATOR = 0x80000000 + SPELL_ATTR7_ALLOW_SPELL_REFLECTION = 0x00000001, // TITLE Allow Spell Reflection + SPELL_ATTR7_NO_TARGET_DURATION_MOD = 0x00000002, // TITLE No Target Duration Mod + SPELL_ATTR7_DISABLE_AURA_WHILE_DEAD = 0x00000004, // TITLE Disable Aura While Dead + SPELL_ATTR7_DEBUG_SPELL = 0x00000008, // TITLE Debug Spell DESCRIPTION Cannot cast if caster doesn't have UnitFlag2 & UNIT_FLAG2_ALLOW_CHEAT_SPELLS + SPELL_ATTR7_TREAT_AS_RAID_BUFF = 0x00000010, /*NYI*/ // TITLE Treat as Raid Buff + SPELL_ATTR7_CAN_BE_MULTI_CAST = 0x00000020, // TITLE Can Be Multi Cast + SPELL_ATTR7_DONT_CAUSE_SPELL_PUSHBACK = 0x00000040, // TITLE Don't Cause Spell Pushback DESCRIPTION Damage dealt by this does not cause spell pushback + SPELL_ATTR7_PREPARE_FOR_VEHICLE_CONTROL_END = 0x00000080, /*NYI*/ // TITLE Prepare for Vehicle Control End + SPELL_ATTR7_HORDE_SPECIFIC_SPELL = 0x00000100, /*NYI*/ // TITLE Horde Specific Spell + SPELL_ATTR7_ALLIANCE_SPECIFIC_SPELL = 0x00000200, /*NYI*/ // TITLE Alliance Specific Spell + SPELL_ATTR7_DISPEL_REMOVES_CHARGES = 0x00000400, // TITLE Dispel Removes Charges DESCRIPTION Dispel/Spellsteal remove individual charges + SPELL_ATTR7_CAN_CAUSE_INTERRUPT = 0x00000800, // TITLE Can Cause Interrupt DESCRIPTION Only interrupt non-player casting + SPELL_ATTR7_CAN_CAUSE_SILENCE = 0x00001000, /*NYI*/ // TITLE Can Cause Silence + SPELL_ATTR7_NO_UI_NOT_INTERRUPTIBLE = 0x00002000, // TITLE No UI Not Interruptible DESCRIPTION Can always be interrupted, even if caster is immune + SPELL_ATTR7_RECAST_ON_RESUMMON = 0x00004000, /*NYI - deprecated attribute, there is no SPELL_GO sent anymore on pet resummon*/ // TITLE Recast On Resummon + SPELL_ATTR7_RESET_SWING_TIMER_AT_SPELL_START = 0x00008000, // TITLE Reset Swing Timer at spell start + SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED = 0x00010000, // TITLE Only In Spellbook Until Learned DESCRIPTION After learning these spells become hidden in spellbook (but are visible when not learned for low level characters) + SPELL_ATTR7_DO_NOT_LOG_PVP_KILL = 0x00020000, /*NYI, only used by 1 spell that is already filtered out in pvp credits because its self targeting*/ // TITLE Do Not Log PvP Kill + SPELL_ATTR7_ATTACK_ON_CHARGE_TO_UNIT = 0x00040000, // TITLE Attack on Charge to Unit + SPELL_ATTR7_REPORT_SPELL_FAILURE_TO_UNIT_TARGET = 0x00080000, // TITLE Report Spell failure to unit target + SPELL_ATTR7_NO_CLIENT_FAIL_WHILE_STUNNED_FLEEING_CONFUSED = 0x00100000, // TITLE No Client Fail While Stunned, Fleeing, Confused DESCRIPTION Clientside - skips stunned/fleeing/confused checks + SPELL_ATTR7_RETAIN_COOLDOWN_THROUGH_LOAD = 0x00200000, /*NYI*/ // TITLE Retain Cooldown Through Load + SPELL_ATTR7_IGNORES_COLD_WEATHER_FLYING_REQUIREMENT = 0x00400000, /*NYI - deprecated attribute*/ // TITLE Ignores Cold Weather Flying Requirement + SPELL_ATTR7_NO_ATTACK_DODGE = 0x00800000, // TITLE No Attack Dodge + SPELL_ATTR7_NO_ATTACK_PARRY = 0x01000000, // TITLE No Attack Parry + SPELL_ATTR7_NO_ATTACK_MISS = 0x02000000, // TITLE No Attack Miss + SPELL_ATTR7_TREAT_AS_NPC_AOE = 0x04000000, // TITLE Treat as NPC AoE + SPELL_ATTR7_BYPASS_NO_RESURRECT_AURA = 0x08000000, // TITLE Bypass No Resurrect Aura + SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD = 0x10000000, // TITLE Do Not Count For PvP Scoreboard + SPELL_ATTR7_REFLECTION_ONLY_DEFENDS = 0x20000000, // TITLE Reflection Only Defends + SPELL_ATTR7_CAN_PROC_FROM_SUPPRESSED_TARGET_PROCS = 0x40000000, // TITLE Can Proc From Suppressed Target Procs + SPELL_ATTR7_ALWAYS_CAST_LOG = 0x80000000 // TITLE Always Cast Log }; enum SpellAttr8 diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a131a1a124..68a101016d 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -5809,7 +5809,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS)) { if (GetSpellInfo()->Effects[GetEffIndex()].IsTargetingArea() || GetSpellInfo()->Effects[GetEffIndex()].IsAreaAuraEffect() || GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA || GetSpellInfo()->HasAttribute(SPELL_ATTR5_TREAT_AS_AREA_EFFECT)) - damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, GetBase()->GetCasterGUID()); + damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, (caster && !caster->IsControlledByPlayer()) || GetSpellInfo()->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)); } int32 dmg = damage; @@ -5899,7 +5899,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS)) { if (GetSpellInfo()->Effects[GetEffIndex()].IsTargetingArea() || GetSpellInfo()->Effects[GetEffIndex()].IsAreaAuraEffect() || GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA || GetSpellInfo()->HasAttribute(SPELL_ATTR5_TREAT_AS_AREA_EFFECT)) - damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, GetBase()->GetCasterGUID()); + damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, (caster && !caster->IsControlledByPlayer()) || GetSpellInfo()->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)); } int32 dmg = damage; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 79b50fea98..c918a401f5 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1826,6 +1826,18 @@ uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, if (spell->GetSpellInfo()->HasAttribute(SPELL_ATTR4_SUPPRESS_WEAPON_PROCS) && GetSpellInfo()->HasAttribute(SPELL_ATTR6_AURA_IS_WEAPON_PROC)) return 0; + + if (eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) + { + if (spell->GetSpellInfo()->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS) + && !GetSpellInfo()->HasAttribute(SPELL_ATTR7_CAN_PROC_FROM_SUPPRESSED_TARGET_PROCS)) + return 0; + } + else + { + if (spell->GetSpellInfo()->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)) + return 0; + } } // check don't break stealth attr present diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 534df9f50e..0bc42444a8 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -669,7 +669,8 @@ m_caster((info->HasAttribute(SPELL_ATTR6_ORIGINATE_FROM_CONTROLLER) && caster->G // 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_canReflect = caster->IsUnit() + && ((m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY)) || m_spellInfo->HasAttribute(SPELL_ATTR7_ALLOW_SPELL_REFLECTION)) && !m_spellInfo->HasAttribute(SPELL_ATTR1_NO_REFLECTION) && !m_spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !m_spellInfo->IsPassive(); @@ -2620,8 +2621,7 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell) uint32 hitMask = PROC_HIT_NONE; // Spells with this flag cannot trigger if effect is cast on self - bool const canEffectTrigger = (!spell->m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS) || !spell->m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS)) - && spell->unitTarget->CanProc(); + bool const canEffectTrigger = spell->unitTarget->CanProc(); // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now if (canEffectTrigger && !procAttacker && !procVictim) @@ -2777,12 +2777,6 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell) // Do triggers for unit if (canEffectTrigger) { - if (spell->m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)) - procAttacker = PROC_FLAG_NONE; - - if (spell->m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS)) - procVictim = PROC_FLAG_NONE; - Unit::ProcSkillsAndAuras(caster, spell->unitTarget, procAttacker, procVictim, procSpellType, PROC_SPELL_PHASE_HIT, hitMask, spell, spellDamageInfo.get(), healInfo.get()); // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit) @@ -2822,7 +2816,7 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell) } // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER - if (MissCondition == SPELL_MISS_NONE && spell->m_spellInfo->HasAttribute(SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER) && unit->GetTypeId() != TYPEID_PLAYER) + if (MissCondition == SPELL_MISS_NONE && spell->m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_CAUSE_INTERRUPT) && unit->GetTypeId() != TYPEID_PLAYER) caster->CastSpell(unit, SPELL_INTERRUPT_NONPLAYER, true); } @@ -3414,6 +3408,9 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const TC_LOG_DEBUG("spells", "Spell::prepare: spell id %u source %u caster %d customCastFlags %u mask %u", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, _triggeredCastFlags, m_targets.GetTargetMask()); + if (m_spellInfo->HasAttribute(SPELL_ATTR7_RESET_SWING_TIMER_AT_SPELL_START) && IsAutoActionResetSpell()) + ResetCombatTimers(); + //Containers for channeled spells have to be set /// @todoApply this to all cast spells if needed // Why check duration? 29350: channelled triggers channelled @@ -3698,6 +3695,9 @@ void Spell::_cast(bool skipCheck) HandleLaunchPhase(); + if (!m_spellInfo->HasAttribute(SPELL_ATTR7_RESET_SWING_TIMER_AT_SPELL_START) && IsAutoActionResetSpell()) + ResetCombatTimers(); + // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... SendSpellGo(); @@ -3783,8 +3783,7 @@ void Spell::_cast(bool skipCheck) if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_AN_ACTION)) m_originalCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ActionDelayed, m_spellInfo); - if (!m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)) - Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); + Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); // Call CreatureAI hook OnSuccessfulSpellCast if (Creature* caster = m_originalCaster->ToCreature()) @@ -4041,8 +4040,7 @@ void Spell::_handle_finish_phase() } } - if (!m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)) - Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, m_hitMask, this, nullptr, nullptr); + Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, m_hitMask, this, nullptr, nullptr); } void Spell::SendSpellCooldown() @@ -4201,28 +4199,6 @@ void Spell::finish(bool ok) } } - if (IsAutoActionResetSpell()) - { - bool found = false; - Unit::AuraEffectList const& vIgnoreReset = unitCaster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET); - for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i) - { - if ((*i)->IsAffectingSpell(m_spellInfo)) - { - found = true; - break; - } - } - - if (!found && !m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)) - { - unitCaster->resetAttackTimer(BASE_ATTACK); - if (unitCaster->haveOffhandWeapon()) - unitCaster->resetAttackTimer(OFF_ATTACK); - unitCaster->resetAttackTimer(RANGED_ATTACK); - } - } - // potions disabled by client, send event "not in combat" if need if (unitCaster->GetTypeId() == TYPEID_PLAYER) { @@ -4375,7 +4351,7 @@ void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo con uint32 itemid = spellInfo->Reagent[i]; uint32 itemcount = spellInfo->ReagentCount[i]; - if (!caster->HasItemCount(itemid, itemcount)) + if (caster && !caster->HasItemCount(itemid, itemcount)) { missingItem = itemid; break; @@ -4408,13 +4384,22 @@ void Spell::SendCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, if (result == SPELL_CAST_OK) return; - if (m_caster->GetTypeId() != TYPEID_PLAYER) + Player* receiver = m_caster->ToPlayer(); + if (m_spellInfo->HasAttribute(SPELL_ATTR7_REPORT_SPELL_FAILURE_TO_UNIT_TARGET)) + if (Unit* target = m_targets.GetUnitTarget()) + if (target->IsPlayer()) + receiver = target->ToPlayer(); + + if (!receiver) return; - if (m_caster->ToPlayer()->IsLoading()) // don't send cast results at loading time + if (receiver->IsLoading()) // don't send cast results at loading time return; - SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError, param1, param2); + if (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) + result = SPELL_FAILED_DONT_REPORT; + + SendCastResult(receiver, m_spellInfo, m_cast_count, result, m_customError, param1, param2); } void Spell::SendPetCastResult(SpellCastResult result) @@ -4430,6 +4415,9 @@ void Spell::SendPetCastResult(SpellCastResult result) if (!player) return; + if (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) + result = SPELL_FAILED_DONT_REPORT; + WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1); WriteCastResultInfo(data, player, m_spellInfo, m_cast_count, result, m_customError); @@ -5654,7 +5642,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint } } - if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && m_caster->ToUnit() && !m_caster->ToUnit()->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS)) + if (m_spellInfo->HasAttribute(SPELL_ATTR7_DEBUG_SPELL) && m_caster->ToUnit() && !m_caster->ToUnit()->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS)) { m_customError = SPELL_CUSTOM_ERROR_GM_ONLY; return SPELL_FAILED_CUSTOM_ERROR; @@ -7840,24 +7828,12 @@ bool Spell::IsChannelActive() const bool Spell::IsAutoActionResetSpell() const { - if (IsTriggered()) + if (IsTriggered() || m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)) return false; if (!m_casttime && m_spellInfo->HasAttribute(SPELL_ATTR6_DOESNT_RESET_SWING_TIMER_IF_INSTANT)) return false; - switch (m_spellInfo->DmgClass) - { - case SPELL_DAMAGE_CLASS_NONE: - case SPELL_DAMAGE_CLASS_RANGED: - // Spells with no or ranged damage class always reset swing timers - return true; - case SPELL_DAMAGE_CLASS_MAGIC: - case SPELL_DAMAGE_CLASS_MELEE: - // Spells with damage class magic or melee reset swing timers when any interrupt flag is given - return m_spellInfo->InterruptFlags.HasAnyFlag(); - } - return true; } @@ -7869,7 +7845,8 @@ bool Spell::IsPositive() const bool Spell::IsNeedSendToClient() const { return m_spellInfo->SpellVisual[0] || m_spellInfo->SpellVisual[1] || m_spellInfo->IsChanneled() || - m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT) || m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered()); + m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT) || m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered()) || + m_spellInfo->HasAttribute(SPELL_ATTR7_ALWAYS_CAST_LOG); } SpellEvent::SpellEvent(Spell* spell) : BasicEvent() @@ -8075,9 +8052,10 @@ void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, uin if (m_originalCaster&& m_damage > 0) { - if (m_spellInfo->Effects[effIndex].IsTargetingArea() || m_spellInfo->Effects[effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || m_spellInfo->HasAttribute(SPELL_ATTR5_TREAT_AS_AREA_EFFECT)) + bool isAoeTarget = m_spellInfo->Effects[effIndex].IsTargetingArea() || m_spellInfo->Effects[effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + if (isAoeTarget || m_spellInfo->HasAttribute(SPELL_ATTR5_TREAT_AS_AREA_EFFECT) || m_spellInfo->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)) { - m_damage = unit->CalculateAOEAvoidance(m_damage, m_spellInfo->SchoolMask, m_originalCaster->GetGUID()); + m_damage = unit->CalculateAOEAvoidance(m_damage, m_spellInfo->SchoolMask, !m_originalCaster->IsControlledByPlayer() || m_spellInfo->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)); if (m_originalCaster->GetTypeId() == TYPEID_PLAYER) { @@ -8111,6 +8089,18 @@ void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, uin targetInfo.IsCrit = roll_chance_f(critChance); } +void Spell::ResetCombatTimers() +{ + Unit* unitCaster = m_caster->ToUnit(); + if (!unitCaster) + return; + + unitCaster->resetAttackTimer(BASE_ATTACK); + if (unitCaster->haveOffhandWeapon()) + unitCaster->resetAttackTimer(OFF_ATTACK); + unitCaster->resetAttackTimer(RANGED_ATTACK); +} + SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue) { if (!lockId) // possible case for GO and maybe for items. diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 8ab0b132bd..8e6e2f9ae8 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -756,6 +756,7 @@ class TC_GAME_API Spell bool IsValidDeadOrAliveTarget(Unit const* target) const; void HandleLaunchPhase(); void DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, uint8 effIndex); + void ResetCombatTimers(); void PrepareTargetProcessing(); void FinishTargetProcessing(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 8fec5edec6..6dd46a0742 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4461,7 +4461,7 @@ void Spell::EffectCharge(SpellEffIndex effIndex) else if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) { // not all charge effects used in negative spells - if (!m_spellInfo->IsPositive() && unitCaster->GetTypeId() == TYPEID_PLAYER) + if (m_spellInfo->HasAttribute(SPELL_ATTR7_ATTACK_ON_CHARGE_TO_UNIT)) unitCaster->Attack(unitTarget, true); if (int32 spellId = GetSpellInfo()->Effects[effIndex].TriggerSpell) @@ -5149,7 +5149,7 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex) // The charges / stack amounts don't count towards the total number of auras that can be dispelled. // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell // Polymorph instead of 1 / (5 + 1) -> 16%. - bool dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES); + bool dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES); uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount(); if (charges > 0) stealList.emplace_back(aura, chance, charges); @@ -5583,7 +5583,7 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex) if (!player->HasSpell(spell_id) || player->GetSpellHistory()->HasCooldown(spell_id)) continue; - if (!spellInfo->HasAttribute(SPELL_ATTR9_SUMMON_PLAYER_TOTEM)) + if (!spellInfo->HasAttribute(SPELL_ATTR7_CAN_BE_MULTI_CAST)) continue; int32 cost = spellInfo->CalcPowerCost(player, spellInfo->GetSchoolMask()); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index c608a87157..b31229cce8 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1138,7 +1138,7 @@ bool SpellInfo::HasTargetType(::Targets target) const bool SpellInfo::CanBeInterrupted(Unit const* interruptTarget, bool ignoreImmunity /*= false*/) const { - return HasAttribute(SPELL_ATTR7_CAN_ALWAYS_BE_INTERRUPTED) + return HasAttribute(SPELL_ATTR7_NO_UI_NOT_INTERRUPTIBLE) || HasChannelInterruptFlag(SpellAuraInterruptFlags::Damage | SpellAuraInterruptFlags::EnteringCombat) || (interruptTarget->IsPlayer() && InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly)) || ((!(interruptTarget->GetMechanicImmunityMask() & (1 << MECHANIC_INTERRUPT)) || ignoreImmunity) @@ -1975,9 +1975,8 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co return SPELL_FAILED_BAD_TARGETS; // Do not allow pet or guardian targets if the spell is a raid buff or may not target pets at all - if ((HasAttribute(SPELL_ATTR7_CONSOLIDATED_RAID_BUFF) || HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC)) && (caster->IsCreature() && !caster->ToCreature()->IsPet() && !caster->ToCreature()->IsGuardian())) - if ((unitTarget->IsPet() || unitTarget->IsGuardian())) - return SPELL_FAILED_BAD_TARGETS; + if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && unitTarget->IsCreature() && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) + return SPELL_FAILED_BAD_TARGETS; // checked in Unit::IsValidAttack/AssistTarget, shouldn't be checked for ENTRY targets //if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 4aa6450ba5..336741ab44 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3503,15 +3503,6 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].Effect = 0; }); - ApplySpellFix({ - 15487, // Priest - Silence - 47476, // Deathknight - Strangulate - 69179 // Arcane Torrent (Rage) - }, [](SpellInfo* spellInfo) - { - spellInfo->AttributesEx7 |= SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER; - }); - ApplySpellFix({ 42490, // Energized! 42492, // Cast Energized @@ -4693,7 +4684,7 @@ void SpellMgr::LoadSpellInfoCorrections() 100258 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx7 |= SPELL_ATTR7_CANT_MISS; + spellInfo->AttributesEx7 |= SPELL_ATTR7_NO_ATTACK_MISS; }); // Entrapping Roots @@ -5311,13 +5302,13 @@ void SpellMgr::LoadSpellInfoCorrections() // Release Aberrations ApplySpellFix({ 77569 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx8 |= SPELL_ATTR7_CANT_MISS; + spellInfo->AttributesEx8 |= SPELL_ATTR7_NO_ATTACK_MISS; }); // Release All Minions ApplySpellFix({ 77991 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx8 |= SPELL_ATTR7_CANT_MISS; + spellInfo->AttributesEx8 |= SPELL_ATTR7_NO_ATTACK_MISS; }); // Debilitating Slime diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp index cc563b12f2..a03ca15eb7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp @@ -71,7 +71,7 @@ class icecrown_citadel_teleport : public GameObjectScript if (TransportBase* transport = player->GetTransport()) transport->RemovePassenger(player); - player->CastSpell(player, spell->Id, true); + me->CastSpell(player, spell->Id, true); return true; } };