From dffc4610d5d3f85db5407d234f2e4311d7ab758a Mon Sep 17 00:00:00 2001 From: Vayle Date: Sat, 31 Jan 2026 02:29:53 +0000 Subject: [PATCH] Reapply visual/state effects for pets and NPCs after suppression expires When buff suppression expires, only clients get ReapplyBuff() called to restore visual and state effects (illusions, procs, silence, etc.). Pets and NPCs had no equivalent handling, causing permanent loss of illusions, weapon procs, and other active effects after suppression. Add non-client effect restoration in the suppression expiry path of BuffFadeBySlot() that handles illusions, silence, amnesia, and weapon procs for pets, NPCs, and bots. Fixes #32 --- zone/spell_effects.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index bd03298e1..33090b07f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -4688,6 +4688,34 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses, bool suppress, uint32 su client->QueuePacket(action_packet); safe_delete(action_packet); client->ReapplyBuff(slot, true); + } else { + // Reapply visual/state effects for non-client mobs (pets, NPCs, bots) + const auto& spell = spells[buffs[slot].spellid]; + for (int i = 0; i < EFFECT_COUNT; i++) { + switch (spell.effect_id[i]) { + case SpellEffect::Illusion: + ApplySpellEffectIllusion(spell.id, entity_list.GetMobID(buffs[slot].casterid), slot, spell.base_value[i], spell.limit_value[i], spell.max_value[i]); + break; + case SpellEffect::Silence: + Silence(true); + break; + case SpellEffect::Amnesia: + Amnesia(true); + break; + case SpellEffect::AddMeleeProc: + case SpellEffect::WeaponProc: + AddProcToWeapon(GetProcID(buffs[slot].spellid, i), false, 100 + spell.limit_value[i], buffs[slot].spellid, buffs[slot].casterlevel, GetSpellProcLimitTimer(buffs[slot].spellid, ProcType::MELEE_PROC)); + break; + case SpellEffect::DefensiveProc: + AddDefensiveProc(GetProcID(buffs[slot].spellid, i), 100 + spell.limit_value[i], buffs[slot].spellid, GetSpellProcLimitTimer(buffs[slot].spellid, ProcType::DEFENSIVE_PROC)); + break; + case SpellEffect::RangedProc: + AddRangedProc(GetProcID(buffs[slot].spellid, i), 100 + spell.limit_value[i], buffs[slot].spellid, GetSpellProcLimitTimer(buffs[slot].spellid, ProcType::RANGED_PROC)); + break; + default: + break; + } + } } } else { buffs[slot].spellid = SPELL_UNKNOWN;