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 000000000..6711c69c4 --- /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 f08e5eaf8..b03e25578 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 20b30a27a..f44638080 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 5a9bfcde5..87af1c4d4 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 b6622d8e1..5f87b094c 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 045ee219f..317f747db 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 8bb7eeea4..f40b8e533 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 736d9d950..985ead07c 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 6959632e2..018b64b64 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); }