From 5d0abdc4ac99f462babdc7e760c9cee36f6b2dd0 Mon Sep 17 00:00:00 2001 From: Vayle Date: Sat, 31 Jan 2026 02:27:36 +0000 Subject: [PATCH] Handle SPELL_SUPPRESSED slots in mass-fade functions BuffFadeNonPersistDeath(), BuffFadeBeneficial(), BuffFadeDetrimental(), and BuffFadeByEffect() all use IsValidSpell() which returns false for SPELL_SUPPRESSED (0xFFFD), causing suppressed buffs to survive death and mass-dispels. Worse, if BuffFadeBySlot() were called on a suppressed slot, it would restore the buff instead of clearing it. Add explicit handling for SPELL_SUPPRESSED slots in each function: check the suppressedid against the fade criteria and clear the slot directly (set to SPELL_UNKNOWN) rather than calling BuffFadeBySlot(). Fixes #31 --- zone/spells.cpp | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 845d4603e..b4ab546d0 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4843,7 +4843,20 @@ void Mob::BuffFadeNonPersistDeath() int buff_count = GetMaxTotalSlots(); for (int buff_slot = 0; buff_slot < buff_count; buff_slot++) { auto current_spell_id = buffs[buff_slot].spellid; - if ( + if (current_spell_id == SPELL_SUPPRESSED) { + auto suppressed_id = buffs[buff_slot].suppressedid; + if ( + IsValidSpell(suppressed_id) && + !IsPersistDeathSpell(suppressed_id) && + !HasPersistDeathIllusion(suppressed_id) + ) { + buffs[buff_slot].spellid = SPELL_UNKNOWN; + buffs[buff_slot].suppressedid = 0; + buffs[buff_slot].suppressedticsremaining = -1; + recalc_bonus = true; + } + } + else if ( IsValidSpell(current_spell_id) && !IsPersistDeathSpell(current_spell_id) && !HasPersistDeathIllusion(current_spell_id) @@ -4863,7 +4876,15 @@ void Mob::BuffFadeBeneficial() { int buff_count = GetMaxTotalSlots(); for (int buff_slot = 0; buff_slot < buff_count; buff_slot++) { auto current_spell_id = buffs[buff_slot].spellid; - if ( + if (current_spell_id == SPELL_SUPPRESSED) { + if (IsValidSpell(buffs[buff_slot].suppressedid) && IsBeneficialSpell(buffs[buff_slot].suppressedid)) { + buffs[buff_slot].spellid = SPELL_UNKNOWN; + buffs[buff_slot].suppressedid = 0; + buffs[buff_slot].suppressedticsremaining = -1; + recalc_bonus = true; + } + } + else if ( IsValidSpell(current_spell_id) && IsBeneficialSpell(current_spell_id) ) { @@ -4882,7 +4903,15 @@ void Mob::BuffFadeDetrimental() { int buff_count = GetMaxTotalSlots(); for (int buff_slot = 0; buff_slot < buff_count; buff_slot++) { auto current_spell_id = buffs[buff_slot].spellid; - if ( + if (current_spell_id == SPELL_SUPPRESSED) { + if (IsValidSpell(buffs[buff_slot].suppressedid) && IsDetrimentalSpell(buffs[buff_slot].suppressedid)) { + buffs[buff_slot].spellid = SPELL_UNKNOWN; + buffs[buff_slot].suppressedid = 0; + buffs[buff_slot].suppressedticsremaining = -1; + recalc_bonus = true; + } + } + else if ( IsValidSpell(current_spell_id) && IsDetrimentalSpell(current_spell_id) ) { @@ -4982,7 +5011,15 @@ void Mob::BuffFadeByEffect(int effect_id, int slot_to_skip) int buff_count = GetMaxTotalSlots(); for(int buff_slot = 0; buff_slot < buff_count; buff_slot++) { auto current_spell_id = buffs[buff_slot].spellid; - if ( + if (current_spell_id == SPELL_SUPPRESSED && buff_slot != slot_to_skip) { + if (IsValidSpell(buffs[buff_slot].suppressedid) && IsEffectInSpell(buffs[buff_slot].suppressedid, effect_id)) { + buffs[buff_slot].spellid = SPELL_UNKNOWN; + buffs[buff_slot].suppressedid = 0; + buffs[buff_slot].suppressedticsremaining = -1; + recalc_bonus = true; + } + } + else if ( IsValidSpell(current_spell_id) && IsEffectInSpell(current_spell_id, effect_id) && buff_slot != slot_to_skip