From 187d6e9dc435c5113655bbabd3bd02782401a384 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 29 Jul 2021 19:20:21 -0400 Subject: [PATCH] [Spells] Bug fix for AOE Harmony/Lull (#1472) * Bug fix for AOE Harmony/Lull type spells. Fixed bug with SPA 30 SE_SE_ChangeFrenzyRad and SPA 86 SE_Harmony allowing those spells to affect NPC's above their level restrictions when cast as a 'Targeted AE' spell (ie. Harmony, Wake of Tranquility) when the targeted NPC was bellow level restricted range, but the NPC's next to them were above it. As coded now, the adjacent NPC's if over level limit will still get the buff applied to them BUT will not get any benefits from the buff. This bug was originally reported by: Isaaru * Live like behavior Implemented the live like behavior, if this case occurs on live, the buff is not applied to the targets over the level limit and "Your target looks unaffected" message is given. * code optimization code optimization --- zone/bonuses.cpp | 6 +++++- zone/mob.h | 1 + zone/spell_effects.cpp | 18 ++++++++++++++++++ zone/spells.cpp | 20 +++++++++----------- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index e52e61533..6ae0075bd 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1750,7 +1750,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne case SE_ChangeFrenzyRad: { - // redundant to have level check here + if (max != 0 && GetLevel() > max) + break; + if(new_bonus->AggroRange == -1 || effect_value < new_bonus->AggroRange) { new_bonus->AggroRange = static_cast(effect_value); @@ -1760,6 +1762,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne case SE_Harmony: { + if (max != 0 && GetLevel() > max) + break; // Harmony effect as buff - kinda tricky // harmony could stack with a lull spell, which has better aggro range // take the one with less range in any case diff --git a/zone/mob.h b/zone/mob.h index 4e051d76f..ee3801833 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -837,6 +837,7 @@ public: inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; }; inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; }; int32 GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot = 0); + bool HarmonySpellLevelCheck(int32 spell_id, Mob* target = nullptr); void CastSpellOnLand(Mob* caster, uint32 spell_id); void FocusProcLimitProcess(); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f39340876..18cd28117 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -7441,3 +7441,21 @@ void Client::BreakFeignDeathWhenCastOn(bool IsResisted) MessageString(Chat::SpellFailure,FD_CAST_ON); } } + +bool Mob::HarmonySpellLevelCheck(int32 spell_id, Mob *target) +{ + //'this' = caster of spell + if (!target) { + return false; + } + + for (int i = 0; i < EFFECT_COUNT; i++) { + // not important to check limit on SE_Lull as it doesnt have one and if the other components won't land, then SE_Lull wont either + if (spells[spell_id].effectid[i] == SE_ChangeFrenzyRad || spells[spell_id].effectid[i] == SE_Harmony) { + if ((spells[spell_id].max[i] != 0 && target->GetLevel() > spells[spell_id].max[i]) || target->GetSpecialAbility(IMMUNE_PACIFY)) { + return false; + } + } + } + return true; +} diff --git a/zone/spells.cpp b/zone/spells.cpp index c246c79a8..9a2d6f27c 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -224,17 +224,9 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot, if (spellbonuses.NegateIfCombat) BuffFadeByEffect(SE_NegateIfCombat); - if(IsClient() && GetTarget() && IsHarmonySpell(spell_id)) - { - for(int i = 0; i < EFFECT_COUNT; i++) { - // not important to check limit on SE_Lull as it doesnt have one and if the other components won't land, then SE_Lull wont either - if (spells[spell_id].effectid[i] == SE_ChangeFrenzyRad || spells[spell_id].effectid[i] == SE_Harmony) { - if((spells[spell_id].max[i] != 0 && GetTarget()->GetLevel() > spells[spell_id].max[i]) || GetTarget()->GetSpecialAbility(IMMUNE_PACIFY)) { - InterruptSpell(CANNOT_AFFECT_NPC, 0x121, spell_id); - return(false); - } - } - } + if (IsClient() && IsHarmonySpell(spell_id) && !HarmonySpellLevelCheck(spell_id, entity_list.GetMobID(target_id))) { + InterruptSpell(SPELL_NO_EFFECT, 0x121, spell_id); + return false; } if (HasActiveSong() && IsBardSong(spell_id)) { @@ -3789,6 +3781,12 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r return false; } } + //Need this to account for special AOE cases. + if (IsClient() && IsHarmonySpell(spell_id) && !HarmonySpellLevelCheck(spell_id, spelltar)) { + MessageString(Chat::SpellFailure, SPELL_NO_EFFECT); + return false; + } + // Block next spell effect should be used up first(since its blocking the next spell) if(CanBlockSpell()) { int buff_count = GetMaxTotalSlots();