diff --git a/data/sql/updates/pending_db_world/rev_1655583442917433100.sql b/data/sql/updates/pending_db_world/rev_1655583442917433100.sql new file mode 100644 index 000000000..def800063 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1655583442917433100.sql @@ -0,0 +1,4 @@ +-- +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_mandokir_charge'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(24408, 'spell_mandokir_charge'); diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index 9e85278f4..9039961d5 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -1369,6 +1369,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST; }); + // Frightening Shout + ApplySpellFix({ 19134 }, [](SpellInfo* spellInfo) + { + spellInfo->Effects[EFFECT_0].Effect = SPELL_EFFECT_DUMMY; + }); + // Isle of Conquest ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo) { diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index 4a262e2ad..6959632e2 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -47,6 +47,7 @@ enum Spells SPELL_LEVEL_UP = 24312, SPELL_EXECUTE = 7160, SPELL_MANDOKIR_CLEAVE = 20691, + SPELL_SUMMON_PLAYER = 25104, SPELL_REVIVE = 24341 // chained spirit }; @@ -63,8 +64,7 @@ enum Events EVENT_WATCH_PLAYER = 8, EVENT_CHARGE_PLAYER = 9, EVENT_EXECUTE = 10, - EVENT_FRIGHTENING_SHOUT = 11, - EVENT_CLEAVE = 12 + EVENT_CLEAVE = 11 }; enum Action @@ -113,6 +113,32 @@ Position const PosMandokir[2] = { -12197.86f, -1949.392f, 130.2745f, 0.0f } }; +void RevivePlayer(Unit* victim, ObjectGuid& reviveGUID) +{ + std::list chainedSpirits; + GetCreatureListWithEntryInGrid(chainedSpirits, victim, NPC_CHAINED_SPIRIT, 200.f); + if (chainedSpirits.empty()) + return; + + // Sort the list by distance to the victim. + chainedSpirits.sort([victim](Creature const* c1, Creature const* c2) + { + return c1->GetDistance2d(victim) < c2->GetDistance2d(victim); + }); + + // Now we have to check if the spirit is already reviving someone... + for (Creature* spirit : chainedSpirits) + { + if (!spirit->isMoving() && !spirit->HasUnitState(UNIT_STATE_CASTING)) + { + spirit->AI()->SetGUID(reviveGUID); + spirit->AI()->DoAction(ACTION_REVIVE); + reviveGUID.Clear(); + break; + } + } +} + class boss_mandokir : public CreatureScript { public: @@ -147,14 +173,11 @@ public: void JustDied(Unit* /*killer*/) override { - // Do not want to unsummon Ohgan - for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i) - { - if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpiritGUIDs[i])) - { - unsummon->DespawnOrUnsummon(); - } - } + std::list chainedSpirits; + GetCreatureListWithEntryInGrid(chainedSpirits, me, NPC_CHAINED_SPIRIT, 200.f); + for (Creature* spirit : chainedSpirits) + spirit->DespawnOrUnsummon(); + instance->SetBossState(DATA_MANDOKIR, DONE); instance->SaveToDB(); } @@ -176,8 +199,7 @@ public: me->SummonCreature(NPC_OHGAN, me->GetPositionX() - 3, me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i) { - Creature* chainedSpirit = me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN); - chainedSpiritGUIDs[i] = chainedSpirit->GetGUID(); + me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN); } DoZoneInCombat(); } @@ -188,7 +210,7 @@ public: return; reviveGUID = victim->GetGUID(); - DoAction(ACTION_START_REVIVE); + RevivePlayer(victim, reviveGUID); if (++killCount == 3) { Talk(SAY_DING_KILL); @@ -199,32 +221,11 @@ public: jindo->AI()->Talk(SAY_GRATS_JINDO); } } - DoCast(me, SPELL_LEVEL_UP, true); + DoCastSelf(SPELL_LEVEL_UP, true); killCount = 0; } } - void DoAction(int32 action) override - { - 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 = 0 */) override { reviveGUID = guid; @@ -297,7 +298,7 @@ public: return; } - if (me->HasUnitState(UNIT_STATE_CASTING)) + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING)) return; while (uint32 eventId = events.ExecuteEvent()) @@ -342,11 +343,21 @@ public: events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000)); break; case EVENT_CHARGE_PLAYER: - DoCast(SelectTarget(SelectTargetMethod::Random, 0, 40, true), SPELL_CHARGE); - events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 1500); - if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f)) + if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, [this](Unit const* target) + { + if (!me || !target) + return false; + if (target->GetTypeId() != TYPEID_PLAYER || !me->IsWithinLOSInMap(target)) + return false; + return true; + })) { - me->GetThreatMgr().modifyThreatPercent(mainTarget, -100); + DoCast(target, SPELL_CHARGE); + events.DelayEvents(1500); + if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f)) + { + me->GetThreatMgr().modifyThreatPercent(mainTarget, -100); + } } events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000)); break; @@ -354,9 +365,6 @@ public: DoCastVictim(SPELL_EXECUTE, true); events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000)); break; - case EVENT_FRIGHTENING_SHOUT: - DoCastAOE(SPELL_FRIGHTENING_SHOUT); - break; case EVENT_CLEAVE: { std::list meleeRangeTargets; @@ -384,12 +392,12 @@ public: break; } } + DoMeleeAttackIfReady(); } private: uint8 killCount; - ObjectGuid chainedSpiritGUIDs[CHAINED_SPIRIT_COUNT]; ObjectGuid reviveGUID; bool _useExecute; }; @@ -401,7 +409,6 @@ public: }; // Ohgan - enum OhganSpells { SPELL_SUNDERARMOR = 24317, @@ -422,9 +429,9 @@ public: me->AddAura(SPELL_THRASH, me); _scheduler.CancelAll(); _scheduler.SetValidator([this] - { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); reviveGUID.Clear(); } @@ -434,12 +441,10 @@ public: if (victim->GetTypeId() != TYPEID_PLAYER) return; - reviveGUID = victim->GetGUID(); - DoAction(ACTION_START_REVIVE); _scheduler.Schedule(6s, 12s, [this](TaskContext context) { - DoCastVictim(SPELL_SUNDERARMOR); - context.Repeat(6s, 12s); + DoCastVictim(SPELL_SUNDERARMOR); + context.Repeat(6s, 12s); }); } @@ -449,25 +454,7 @@ public: return; reviveGUID = victim->GetGUID(); - DoAction(ACTION_START_REVIVE); - } - - void DoAction(int32 action) override - { - if (action == ACTION_START_REVIVE) - { - std::list creatures; - GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f); - if (creatures.empty()) - return; - - for (Creature* chainedSpirit : creatures) - { - chainedSpirit->AI()->SetGUID(reviveGUID); - chainedSpirit->AI()->DoAction(ACTION_REVIVE); - reviveGUID.Clear(); - } - } + RevivePlayer(victim, reviveGUID); } void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override @@ -553,15 +540,6 @@ public: void JustDied(Unit* /*killer*/) override { - Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID); - if (!target || target->IsAlive()) - return; - - if (Creature* mandokir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MANDOKIR))) - { - mandokir->GetAI()->SetGUID(target->GetGUID()); - mandokir->GetAI()->DoAction(ACTION_START_REVIVE); - } me->DespawnOrUnsummon(); } @@ -579,61 +557,50 @@ enum VilebranchSpells SPELL_CLEAVE = 15284 }; -class npc_vilebranch_speaker : public CreatureScript +struct npc_vilebranch_speaker : public ScriptedAI { -public: - npc_vilebranch_speaker() : CreatureScript("npc_vilebranch_speaker") { } + npc_vilebranch_speaker(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { } - struct npc_vilebranch_speakerAI : public ScriptedAI + void Reset() override { - npc_vilebranch_speakerAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { } + _scheduler.CancelAll(); + } - void Reset() override - { - demoralizing_Shout_Timer = urand(2000, 4000); - cleave_Timer = urand(5000, 8000); - } - - void EnterCombat(Unit* /*who*/) override { } - - void JustDied(Unit* /*killer*/) override - { - instance->SetBossState(DATA_MANDOKIR, SPECIAL); - } - - void UpdateAI(uint32 diff) override - { - // Return since we have no target - if (!UpdateVictim()) - return; - - if (demoralizing_Shout_Timer <= diff) + void EnterCombat(Unit* /*who*/) override + { + _scheduler + .Schedule(2s, 4s, [this](TaskContext context) { - DoCast(me, SPELL_DEMORALIZING_SHOUT); - demoralizing_Shout_Timer = urand(22000, 30000); - } - else demoralizing_Shout_Timer -= diff; - - if (cleave_Timer <= diff) + DoCastAOE(SPELL_DEMORALIZING_SHOUT); + context.Repeat(22s, 30s); + }) + .Schedule(5s, 8s, [this](TaskContext context) { DoCastVictim(SPELL_CLEAVE, true); - cleave_Timer = urand(6000, 9000); - } - else cleave_Timer -= diff; - - DoMeleeAttackIfReady(); - } - - private: - uint32 demoralizing_Shout_Timer; - uint32 cleave_Timer; - InstanceScript* instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulGurubAI(creature); + context.Repeat(6s, 9s); + }); } + + void JustDied(Unit* /*killer*/) override + { + instance->SetBossState(DATA_MANDOKIR, SPECIAL); + } + + void UpdateAI(uint32 diff) override + { + // Return since we have no target + if (!UpdateVictim()) + return; + + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); + } + +private: + TaskScheduler _scheduler; + InstanceScript* instance; }; class spell_threatening_gaze : public SpellScriptLoader @@ -671,11 +638,30 @@ public: } }; +class spell_mandokir_charge : public SpellScript +{ + PrepareSpellScript(spell_mandokir_charge); + + void LaunchHit(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + if (caster && target) + caster->CastSpell(target, SPELL_FRIGHTENING_SHOUT, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mandokir_charge::LaunchHit, EFFECT_0, SPELL_EFFECT_CHARGE); + } +}; + void AddSC_boss_mandokir() { new boss_mandokir(); new npc_ohgan(); RegisterZulGurubCreatureAI(npc_chained_spirit); - new npc_vilebranch_speaker(); + RegisterZulGurubCreatureAI(npc_vilebranch_speaker); new spell_threatening_gaze(); + RegisterSpellScript(spell_mandokir_charge); }