From ea24a7b231ae278a342808efb7101a3147c5d738 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Sun, 26 Jun 2022 09:50:50 +0200 Subject: [PATCH] fix(Scripts/ZulGurub): Mandokir's Threatening Gaze. (#12095) * fix(Scripts/ZulGurub: Mandokir's Threatening Gaze. Boss can melee attack while casting. Boss charges after the debuff run out. Guillotine is casted on hit rather than on launch. Properly coded Threatening Gaze Charge (with dot/hot exceptions) Whirlwind is removed during charge. Fixes #11748 * Update * missing * Update * Update. * Update. * Update. * Update. * Update. --- .../rev_1655562192338775600.sql | 4 + src/server/game/AI/CreatureAI.h | 3 + src/server/game/Combat/HostileRefMgr.cpp | 15 +- src/server/game/Combat/ThreatMgr.cpp | 17 ++- src/server/game/Combat/ThreatMgr.h | 2 +- src/server/game/Entities/Unit/Unit.cpp | 4 +- src/server/game/Entities/Unit/Unit.h | 2 +- .../game/Spells/SpellInfoCorrections.cpp | 6 - .../ZulGurub/boss_mandokir.cpp | 136 +++++++++++++++++- 9 files changed, 166 insertions(+), 23 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1655562192338775600.sql diff --git a/data/sql/updates/pending_db_world/rev_1655562192338775600.sql b/data/sql/updates/pending_db_world/rev_1655562192338775600.sql new file mode 100644 index 0000000000..6711c69c4a --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1655562192338775600.sql @@ -0,0 +1,4 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id`=24315; +INSERT INTO `spell_script_names` VALUES +(24315,'spell_threatening_gaze_charge'); diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index f08e5eaf85..b03e25578f 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -207,6 +207,9 @@ public: static bool IsInBounds(CreatureBoundary const& boundary, Position const* who); bool IsInBoundary(Position const* who = nullptr) const; + + virtual void CalculateThreat(Unit* /*hatedUnit*/, float& /*threat*/, SpellInfo const* /*threatSpell*/) { } + protected: virtual void MoveInLineOfSight(Unit* /*who*/); diff --git a/src/server/game/Combat/HostileRefMgr.cpp b/src/server/game/Combat/HostileRefMgr.cpp index 20b30a27ae..f44638080f 100644 --- a/src/server/game/Combat/HostileRefMgr.cpp +++ b/src/server/game/Combat/HostileRefMgr.cpp @@ -38,12 +38,23 @@ void HostileRefMgr::threatAssist(Unit* victim, float baseThreat, SpellInfo const return; HostileReference* ref = getFirst(); - float threat = ThreatCalcHelper::calcThreat(victim, iOwner, baseThreat, (threatSpell ? threatSpell->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL), threatSpell); + float threat = ThreatCalcHelper::calcThreat(victim, baseThreat, (threatSpell ? threatSpell->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL), threatSpell); threat /= getSize(); while (ref) { - if (ThreatCalcHelper::isValidProcess(victim, ref->GetSource()->GetOwner(), threatSpell)) + Unit* refOwner = ref->GetSource()->GetOwner(); + if (ThreatCalcHelper::isValidProcess(victim, refOwner, threatSpell)) + { + if (Creature* hatingCreature = refOwner->ToCreature()) + { + if (hatingCreature->IsAIEnabled) + { + hatingCreature->AI()->CalculateThreat(victim, threat, threatSpell); + } + } + ref->GetSource()->doAddThreat(victim, threat); + } ref = ref->next(); } diff --git a/src/server/game/Combat/ThreatMgr.cpp b/src/server/game/Combat/ThreatMgr.cpp index 5a9bfcde59..87af1c4d48 100644 --- a/src/server/game/Combat/ThreatMgr.cpp +++ b/src/server/game/Combat/ThreatMgr.cpp @@ -32,11 +32,11 @@ //============================================================== // The hatingUnit is not used yet -float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell) +float ThreatCalcHelper::calcThreat(Unit* hatedUnit, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell) { if (threatSpell) { - if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id)) + if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id)) if (threatEntry->pctMod != 1.0f) threat *= threatEntry->pctMod; @@ -427,10 +427,19 @@ void ThreatMgr::clearReferences() void ThreatMgr::addThreat(Unit* victim, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell) { - if (!ThreatCalcHelper::isValidProcess(victim, GetOwner(), threatSpell)) + if (!ThreatCalcHelper::isValidProcess(victim, iOwner, threatSpell)) return; - doAddThreat(victim, ThreatCalcHelper::calcThreat(victim, iOwner, threat, schoolMask, threatSpell)); + threat = ThreatCalcHelper::calcThreat(victim, threat, schoolMask, threatSpell); + if (Creature* hatingCreature = iOwner->ToCreature()) + { + if (hatingCreature->IsAIEnabled) + { + hatingCreature->AI()->CalculateThreat(victim, threat, threatSpell); + } + } + + doAddThreat(victim, threat); } void ThreatMgr::doAddThreat(Unit* victim, float threat) diff --git a/src/server/game/Combat/ThreatMgr.h b/src/server/game/Combat/ThreatMgr.h index b6622d8e11..5f87b094c0 100644 --- a/src/server/game/Combat/ThreatMgr.h +++ b/src/server/game/Combat/ThreatMgr.h @@ -39,7 +39,7 @@ class SpellInfo; struct ThreatCalcHelper { - static float calcThreat(Unit* hatedUnit, Unit* hatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr); + static float calcThreat(Unit* hatedUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr); static bool isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell = nullptr); }; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 045ee219fd..317f747dba 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -2329,14 +2329,14 @@ void Unit::CalcHealAbsorb(HealInfo& healInfo) healInfo.AbsorbHeal(absorbAmount); } -void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra) +void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_ATTACK*/, bool extra /*= false*/, bool ignoreCasting /*= false*/) { if (HasUnitFlag(UNIT_FLAG_PACIFIED)) { return; } - if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra) + if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra && !ignoreCasting) { return; } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8bb7eeea4c..f40b8e5336 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1533,7 +1533,7 @@ public: void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list& procAuras); void HandleEmoteCommand(uint32 emoteId); - void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false); + void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false); void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false); void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss); diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index 736d9d9506..985ead07ca 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -1363,12 +1363,6 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].Amplitude = 15000; }); - // Threatening Gaze - ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo) - { - spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST; - }); - // Frightening Shout ApplySpellFix({ 19134 }, [](SpellInfo* spellInfo) { diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index 6959632e2c..018b64b640 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -80,7 +80,8 @@ enum Misc MODEL_OHGAN_MOUNT = 15271, PATH_MANDOKIR = 492861, POINT_MANDOKIR_END = 24, - CHAINED_SPIRIT_COUNT = 20 + CHAINED_SPIRIT_COUNT = 20, + ACTION_CHARGE = 1 }; Position const PosSummonChainedSpirits[CHAINED_SPIRIT_COUNT] = @@ -169,6 +170,7 @@ public: me->Mount(MODEL_OHGAN_MOUNT); reviveGUID.Clear(); _useExecute = false; + _chargeTarget.first.Clear(); } void JustDied(Unit* /*killer*/) override @@ -226,9 +228,44 @@ public: } } - void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override + void DoAction(int32 action) override { - reviveGUID = guid; + if (action == ACTION_START_REVIVE) + { + std::list creatures; + GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f); + if (creatures.empty()) + return; + + for (std::list::iterator itr = creatures.begin(); itr != creatures.end(); ++itr) + { + if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, (*itr)->GetGUID())) + { + chainedSpirit->AI()->SetGUID(reviveGUID); + chainedSpirit->AI()->DoAction(ACTION_REVIVE); + reviveGUID.Clear(); + } + } + } + } + + void SetGUID(ObjectGuid const guid, int32 type) override + { + if (type == ACTION_CHARGE) + { + if (_chargeTarget.first == guid && _chargeTarget.second > 0.f) + { + if (Unit* target = ObjectAccessor::GetUnit(*me, _chargeTarget.first)) + { + me->RemoveAurasDueToSpell(SPELL_WHIRLWIND); + DoCast(target, SPELL_WATCH_CHARGE, true); + } + } + } + else + { + reviveGUID = guid; + } } void MovementInform(uint32 type, uint32 id) override @@ -244,6 +281,18 @@ public: } } + void CalculateThreat(Unit* hatedUnit, float& threat, SpellInfo const* threatSpell) override + { + if (_chargeTarget.first == hatedUnit->GetGUID()) + { + // Do not count DOTs/HOTs + if (!threatSpell || !threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT)) + { + _chargeTarget.second += threat; + } + } + } + void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/) override { if (doneTo && doneTo == me->GetVictim()) @@ -264,6 +313,43 @@ public: } } + void DoMeleeAttackIfReady(bool ignoreCasting) + { + if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING)) + { + return; + } + + Unit* victim = me->GetVictim(); + if (!victim || !victim->IsInWorld()) + return; + + if (!me->IsWithinMeleeRange(victim)) + return; + + //Make sure our attack is ready and we aren't currently casting before checking distance + if (me->isAttackReady()) + { + // xinef: prevent base and off attack in same time, delay attack at 0.2 sec + if (me->haveOffhandWeapon()) + if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) + me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); + + me->AttackerStateUpdate(victim, BASE_ATTACK, false, ignoreCasting); + me->resetAttackTimer(); + } + + if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK)) + { + // xinef: delay main hand attack if both will hit at the same time (players code) + if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY) + me->setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY); + + me->AttackerStateUpdate(victim, OFF_ATTACK, false, ignoreCasting); + me->resetAttackTimer(OFF_ATTACK); + } + } + void UpdateAI(uint32 diff) override { events.Update(diff); @@ -299,7 +385,14 @@ public: } if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING)) + { + if (me->GetCurrentSpellCastTime(SPELL_WATCH) >= 0) + { + DoMeleeAttackIfReady(true); + } + return; + } while (uint32 eventId = events.ExecuteEvent()) { @@ -339,6 +432,7 @@ public: { DoCast(player, SPELL_WATCH); Talk(SAY_WATCH, player); + _chargeTarget = std::make_pair(player->GetGUID(), 0.f); } events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000)); break; @@ -393,13 +487,14 @@ public: } } - DoMeleeAttackIfReady(); + DoMeleeAttackIfReady(false); } private: uint8 killCount; ObjectGuid reviveGUID; bool _useExecute; + std::pair _chargeTarget; }; CreatureAI* GetAI(Creature* creature) const override @@ -614,13 +709,16 @@ public: void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (Unit* caster = GetCaster()) + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) { if (Unit* target = GetTarget()) { - if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH) + if (Creature* caster = GetCaster()->ToCreature()) { - caster->CastSpell(target, SPELL_WATCH_CHARGE, true); + if (caster->IsAIEnabled) + { + caster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE); + } } } } @@ -656,6 +754,29 @@ class spell_mandokir_charge : public SpellScript } }; +class spell_threatening_gaze_charge : public SpellScript +{ + PrepareSpellScript(spell_threatening_gaze_charge) + + void PreventLaunchHit(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + } + + void LaunchHit(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + if (Unit* target = GetHitUnit()) + caster->CastSpell(target, GetSpellInfo()->Effects[effIndex].TriggerSpell, true); + } + + void Register() override + { + OnEffectLaunchTarget += SpellEffectFn(spell_threatening_gaze_charge::PreventLaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL); + OnEffectHitTarget += SpellEffectFn(spell_threatening_gaze_charge::LaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL); + } +}; + void AddSC_boss_mandokir() { new boss_mandokir(); @@ -664,4 +785,5 @@ void AddSC_boss_mandokir() RegisterZulGurubCreatureAI(npc_vilebranch_speaker); new spell_threatening_gaze(); RegisterSpellScript(spell_mandokir_charge); + RegisterSpellScript(spell_threatening_gaze_charge); }