From af5cfb9bed7c4fdfbef3dcf42bb39b349cfb3888 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 16 Oct 2021 00:22:07 -0400 Subject: [PATCH] [Spells] Fix to prevent Charmed Pets from continuing fight target if owner is dead. (#1600) * Fix for charm break if pet owner dead * fix, can't check hatelist it is already wiped. * Update spell_effects.cpp --- zone/attack.cpp | 6 ++++ zone/spell_effects.cpp | 66 ++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 2d4278046..39c613cc6 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1684,11 +1684,17 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill // #2: figure out things that affect the player dying and mark them dead InterruptSpell(); + + Mob* m_pet = GetPet(); SetPet(0); SetHorseId(0); ShieldAbilityClearVariables(); dead = true; + if (m_pet && m_pet->IsCharmed()) { + m_pet->BuffFadeByEffect(SE_Charm); + } + if (GetMerc()) { GetMerc()->Suspend(); } diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f5ca54794..db2e78ecc 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -4291,7 +4291,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } SendAppearancePacket(AT_Pet, 0, true, true); - Mob* tempmob = GetOwner(); + Mob* owner = GetOwner(); SetOwnerID(0); SetPetType(petNone); SetHeld(false); @@ -4300,25 +4300,27 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) SetFocused(false); SetPetStop(false); SetPetRegroup(false); - if(tempmob) + if(owner) { - tempmob->SetPet(0); + owner->SetPet(0); } if (IsAIControlled()) { - // clear the hate list of the mobs + //Remove damage over time effects on charmed pet and those applied by charmed pet. if (RuleB(Spells, PreventFactionWarOnCharmBreak)) { for (auto mob : hate_list.GetHateList()) { auto tar = mob->entity_on_hatelist; - if (tar->IsCasting()) { - tar->InterruptSpell(tar->CastingSpellID()); - } - uint32 buff_count = tar->GetMaxTotalSlots(); - for (unsigned int j = 0; j < buff_count; j++) { - if (tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) { - auto spell = spells[tar->GetBuffs()[j].spellid]; - if (spell.goodEffect == 0 && IsEffectInSpell(spell.id, SE_CurrentHP) && tar->GetBuffs()[j].casterid == GetID()) { - tar->BuffFadeBySpellID(spell.id); + if (tar) { + if (tar->IsCasting()) { + tar->InterruptSpell(tar->CastingSpellID()); + } + uint32 buff_count = tar->GetMaxTotalSlots(); + for (unsigned int j = 0; j < buff_count; j++) { + if (IsValidSpell(tar->GetBuffs()[j].spellid)) { + auto spell = spells[tar->GetBuffs()[j].spellid]; + if (spell.goodEffect == 0 && IsEffectInSpell(spell.id, SE_CurrentHP) && tar->GetBuffs()[j].casterid == GetID()) { + tar->BuffFadeBySpellID(spell.id); + } } } } @@ -4328,7 +4330,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } uint32 buff_count = GetMaxTotalSlots(); for (unsigned int j = 0; j < buff_count; j++) { - if (GetBuffs()[j].spellid != SPELL_UNKNOWN) { + if (IsValidSpell(GetBuffs()[j].spellid )) { auto spell = spells[this->GetBuffs()[j].spellid]; if (spell.goodEffect == 0 && IsEffectInSpell(spell.id, SE_CurrentHP)) { BuffFadeBySpellID(spell.id); @@ -4336,17 +4338,43 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } } } - entity_list.ReplaceWithTarget(this, tempmob); + + // clear the hate list of the mobs + entity_list.ReplaceWithTarget(this, owner); WipeHateList(); - if(tempmob) - AddToHateList(tempmob, 1, 0); + if (owner) { + AddToHateList(owner, 1, 0); + } + //If owner dead, briefly setting Immmune Aggro while hatelists wipe for both pet and targets is needed to ensure no reaggroing. + else if (IsNPC()){ + bool immune_aggro = GetSpecialAbility(IMMUNE_AGGRO); //check if already immune aggro + SetSpecialAbility(IMMUNE_AGGRO, 1); + WipeHateList(); + if (IsCasting()) { + InterruptSpell(CastingSpellID()); + } + entity_list.RemoveFromHateLists(this); + //If NPC targeting charmed pet are in process of casting on it after it is removed from hatelist, stop the cast to prevent reaggroing. + Mob *current_npc = nullptr; + for (auto &it : entity_list.GetNPCList()) { + current_npc = it.second; + + if (current_npc && current_npc->IsCasting() && current_npc->GetTarget() == this) { + current_npc->InterruptSpell(current_npc->CastingSpellID()); + } + } + + if (!immune_aggro) { + SetSpecialAbility(IMMUNE_AGGRO, 0); + } + } SendAppearancePacket(AT_Anim, ANIM_STAND); } - if(tempmob && tempmob->IsClient()) + if(owner && owner->IsClient()) { auto app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); Charm_Struct *ps = (Charm_Struct*)app->pBuffer; - ps->owner_id = tempmob->GetID(); + ps->owner_id = owner->GetID(); ps->pet_id = GetID(); ps->command = 0; entity_list.QueueClients(this, app);