From 6db6d7dca91d75358c1906ea916d6f827f3b7dc3 Mon Sep 17 00:00:00 2001 From: Fryguy Date: Sun, 7 Jan 2024 16:44:15 -0500 Subject: [PATCH] [Bug Fix] Depop Charm Pet and Detach Debuffs on Evacuate (#3888) * [Bug Fix] depop charm pet and detach debuffs on evac. This will depop charm pets and deteach debuffs to prevent some social aggro issues and exploitable conditions with charming and pulling a mob across the zone with no aggro concerns. * Added Rules --- common/ruletypes.h | 1 + zone/entity.cpp | 8 +++++++- zone/entity.h | 2 +- zone/mob.h | 1 + zone/spell_effects.cpp | 30 ++++++++++++++++++++---------- zone/spells.cpp | 20 ++++++++++++++++++++ 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 776e1d752..318db63d7 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -474,6 +474,7 @@ RULE_BOOL(Spells, LegacyManaburn, false, "Enable to have the legacy manaburn sys RULE_BOOL(Spells, EvacClearAggroInSameZone, false, "Enable to clear aggro on clients when evacing in same zone.") RULE_BOOL(Spells, CharmAggroOverLevel, false, "Enabling this rule will cause Charm casts over level to show resisted and cause aggro. Early EQ style.") RULE_BOOL(Spells, RequireMnemonicRetention, true, "Enabling will require spell slots 9-12 to have the appropriate Mnemonic Retention AA learned.") +RULE_BOOL(Spells, EvacClearCharmPet, false, "Enable to have evac in zone clear charm from charm pets and detach buffs.") RULE_CATEGORY_END() RULE_CATEGORY(Combat) diff --git a/zone/entity.cpp b/zone/entity.cpp index 0689d6ac7..8f0e7d253 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3545,14 +3545,20 @@ void EntityList::HalveAggro(Mob *who) } //removes "targ" from all hate lists, including feigned, in the zone -void EntityList::ClearAggro(Mob* targ) +void EntityList::ClearAggro(Mob* targ, bool clear_caster_id) { Client *c = nullptr; + if (targ->IsClient()) { c = targ->CastToClient(); } + auto it = npc_list.begin(); while (it != npc_list.end()) { + if (clear_caster_id) { + it->second->BuffDetachCaster(targ); + } + if (it->second->CheckAggro(targ)) { if (c) { c->RemoveXTarget(it->second, false); diff --git a/zone/entity.h b/zone/entity.h index 1638dd40d..bd3b07f6a 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -463,7 +463,7 @@ public: void UpdateHoTT(Mob* target); void Process(); - void ClearAggro(Mob* targ); + void ClearAggro(Mob* targ, bool clear_caster_id = false); void ClearWaterAggro(Mob* targ); void ClearFeignAggro(Mob* targ); void ClearZoneFeignAggro(Mob* targ); diff --git a/zone/mob.h b/zone/mob.h index 2d160330f..c3833c555 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -445,6 +445,7 @@ public: void BuffFadeBySlot(int slot, bool iRecalcBonuses = true); void BuffFadeDetrimentalByCaster(Mob *caster); void BuffFadeBySitModifier(); + void BuffDetachCaster(Mob *caster); bool IsAffectedByBuffByGlobalGroup(GlobalGroup group); void BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration); int AddBuff(Mob *caster, const uint16 spell_id, int duration = 0, int32 level_override = -1, bool disable_buff_overwrite = false); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 2c45b5486..46b663d3d 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -568,19 +568,25 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove // Greater Decession = 3244 // Egress = 1566 - if(!target_zone) { + if (!target_zone) { #ifdef SPELL_EFFECT_SPAM LogDebug("Succor/Evacuation Spell In Same Zone"); #endif - if (IsClient()) { - CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), x, y, z, heading, 0, EvacToSafeCoords); - } else { - GMMove(x, y, z, heading); - } - - if (RuleB(Spells, EvacClearAggroInSameZone)) { - entity_list.ClearAggro(this); + if (IsClient()) { + if (HasPet()) { + if (RuleB(Spells, EvacClearCharmPet) && GetPet()->IsCharmed()) { + GetPet()->BuffFadeByEffect(SE_Charm); + } } + + CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), x, y, z, heading, 0, EvacToSafeCoords); + } else { + GMMove(x, y, z, heading); + } + + if (RuleB(Spells, EvacClearAggroInSameZone)) { + entity_list.ClearAggro(this); + } } else { #ifdef SPELL_EFFECT_SPAM LogDebug("Succor/Evacuation Spell To Another Zone"); @@ -2214,7 +2220,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove // clear aggro when summoned in zone and further than aggro clear distance rule. if (RuleR(Spells, CallOfTheHeroAggroClearDist) == 0 || caster->CalculateDistance(GetX(), GetY(), GetZ()) >= RuleR(Spells, CallOfTheHeroAggroClearDist)) { - entity_list.ClearAggro(this); + if (RuleB(Spells, EvacClearCharmPet)) { + entity_list.ClearAggro(this, true); + } else { + entity_list.ClearAggro(this); + } } } else if (!RuleB(Combat, SummonMeleeRange) && caster->GetZoneID() == GetZoneID() && caster->CombatRange(this)) { break; diff --git a/zone/spells.cpp b/zone/spells.cpp index 8939dface..73751db86 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4843,6 +4843,26 @@ bool Mob::IsAffectedByBuffByGlobalGroup(GlobalGroup group) return false; } +void Mob::BuffDetachCaster(Mob *caster) { + if (!caster) { + return; + } + + int buff_count = GetMaxTotalSlots(); + for (int j = 0; j < buff_count; j++) { + if (buffs[j].spellid != SPELL_UNKNOWN) { + if (IsDetrimentalSpell(buffs[j].spellid)) { + //this is a pretty terrible way to do this but + //there really isn't another way till I rewrite the basics + Mob* c = entity_list.GetMob(buffs[j].casterid); + if (c && c == caster) { + buffs[j].casterid = 0; + } + } + } + } +} + // checks if 'this' can be affected by spell_id from caster // returns true if the spell should fail, false otherwise bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)