diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index bacc58257..29ff343a8 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -30,6 +30,7 @@ enum VolkahnSpells //Molten Golem SPELL_BLAST_WAVE = 23113, + SPELL_COOL_DOWN = 52443, SPELL_IMMOLATION_STRIKE = 52433, SPELL_SHATTER = 52429, }; @@ -59,8 +60,8 @@ enum VolkhanEvents EVENT_MOVE_TO_ANVIL = 5, // Molten Golem - EVENT_BLAST = 11, - EVENT_IMMOLATION = 12, + EVENT_IMMOLATION_STRIKE = 12, + EVENT_CHANGE_TARGET = 13, }; enum Yells @@ -82,7 +83,7 @@ struct boss_volkhan : public BossAI { _Reset(); x = y = z = PointID = ShatteredCount = 0; - HealthCheck = 100; + shatteredStompCast = false; me->SetSpeed(MOVE_RUN, 1.2f, true); me->SetReactState(REACT_AGGRESSIVE); instance->SetData(DATA_VOLKHAN_ACHIEVEMENT, true); @@ -93,7 +94,10 @@ struct boss_volkhan : public BossAI _JustEngagedWith(); me->SetInCombatWithZone(); Talk(SAY_AGGRO); - ScheduleEvents(false); + events.ScheduleEvent(EVENT_MOVE_TO_ANVIL, randtime(9s, 14s)); + events.ScheduleEvent(EVENT_HEAT, randtime(18s, 38s)); + events.ScheduleEvent(EVENT_CHECK_HEALTH, 1s); + events.ScheduleEvent(EVENT_POSITION, 4s); } void JustDied(Unit*) override @@ -151,15 +155,6 @@ struct boss_volkhan : public BossAI Talk(SAY_SLAY); } - void ScheduleEvents(bool anvil) - { - events.SetPhase(1); - events.RescheduleEvent(EVENT_HEAT, 8s, 0, 1); - events.RescheduleEvent(EVENT_SHATTER, 10s, 0, 1); - events.RescheduleEvent(EVENT_CHECK_HEALTH, anvil ? 1s : 6s, 0, 1); - events.RescheduleEvent(EVENT_POSITION, 4s, 0, 1); - } - void JustSummoned(Creature* summon) override { summons.Summon(summon); @@ -182,6 +177,19 @@ struct boss_volkhan : public BossAI } } + bool HasActiveGolem() + { + for (ObjectGuid const& guid : summons) + { + if (Creature* golem = ObjectAccessor::GetCreature(*me, guid)) + { + if (golem->GetEntry() == NPC_MOLTEN_GOLEM && golem->IsAlive()) + return true; + } + } + return false; + } + void MovementInform(uint32 type, uint32 id) override { if (type != POINT_MOTION_TYPE) @@ -190,10 +198,8 @@ struct boss_volkhan : public BossAI if (id == POINT_ANVIL) { me->SetSpeed(MOVE_RUN, 1.2f, true); - me->SetReactState(REACT_AGGRESSIVE); - me->CastSpell(me, SPELL_TEMPER, false); + DoCastSelf(SPELL_TEMPER); PointID = 0; - ScheduleEvents(true); // update orientation at server me->SetOrientation(2.19f); @@ -205,24 +211,26 @@ struct boss_volkhan : public BossAI me->SetControlled(true, UNIT_STATE_ROOT); } else - events.ScheduleEvent(EVENT_MOVE_TO_ANVIL, 0ms, 0, 2); + me->GetMotionMaster()->MovePoint(PointID, x, y, z); } void SpellHitTarget(Unit* /*who*/, SpellInfo const* spellInfo) override { if (spellInfo->Id == SPELL_TEMPER) { - me->CastSpell(me, SPELL_SUMMON_MOLTEN_GOLEM, true); - me->CastSpell(me, SPELL_SUMMON_MOLTEN_GOLEM, true); - me->GetMotionMaster()->MoveChase(me->GetVictim()); + DoCastSelf(SPELL_SUMMON_MOLTEN_GOLEM, true); + DoCastSelf(SPELL_SUMMON_MOLTEN_GOLEM, true); me->SetControlled(false, UNIT_STATE_ROOT); + me->SetReactState(REACT_AGGRESSIVE); + if (me->GetVictim()) + me->GetMotionMaster()->MoveChase(me->GetVictim()); + + events.RescheduleEvent(EVENT_HEAT, randtime(9s, 24s)); } } void GoToAnvil() { - events.SetPhase(2); - HealthCheck -= 20; me->SetSpeed(MOVE_RUN, 4.0f, true); me->SetReactState(REACT_PASSIVE); @@ -231,12 +239,12 @@ struct boss_volkhan : public BossAI if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); - events.ScheduleEvent(EVENT_MOVE_TO_ANVIL, 0ms, 0, 2); + GetNextPos(); + me->GetMotionMaster()->MovePoint(PointID, x, y, z); } void UpdateAI(uint32 diff) override { - //Return since we have no target if (!UpdateVictim()) return; @@ -248,31 +256,31 @@ struct boss_volkhan : public BossAI switch (events.ExecuteEvent()) { case EVENT_HEAT: - me->CastSpell(me, SPELL_HEAT, true); - events.Repeat(8s); + if (HasActiveGolem()) + { + DoCastSelf(SPELL_HEAT); + events.Repeat(randtime(9s, 24s)); + } break; case EVENT_CHECK_HEALTH: - if (HealthBelowPct(HealthCheck)) - GoToAnvil(); - + if (!shatteredStompCast && HealthBelowPct(25)) + { + shatteredStompCast = true; + DoCastAOE(SPELL_SHATTERING_STOMP); + Talk(SAY_STOMP); + summons.DoAction(ACTION_SHATTER); + } events.Repeat(1s); return; - case EVENT_SHATTER: - { - events.Repeat(10s); - summons.DoAction(ACTION_SHATTER); - break; - } case EVENT_MOVE_TO_ANVIL: - GetNextPos(); - me->GetMotionMaster()->MovePoint(PointID, x, y, z); + GoToAnvil(); + events.Repeat(randtime(30s, 36s)); return; case EVENT_POSITION: if (me->GetDistance(1331.9f, -106, 56) > 95) EnterEvadeMode(); else events.Repeat(4s); - return; } @@ -282,10 +290,10 @@ struct boss_volkhan : public BossAI private: EventMap events; SummonList summons; - uint8 HealthCheck; float x, y, z; uint8 PointID; uint8 ShatteredCount; + bool shatteredStompCast; }; struct npc_molten_golem : public ScriptedAI @@ -298,8 +306,9 @@ struct npc_molten_golem : public ScriptedAI void Reset() override { events.Reset(); - events.ScheduleEvent(EVENT_BLAST, 7s); - events.ScheduleEvent(EVENT_IMMOLATION, 3s); + events.ScheduleEvent(EVENT_IMMOLATION_STRIKE, 3s); + events.ScheduleEvent(EVENT_CHANGE_TARGET, 5s); + DoCastSelf(SPELL_COOL_DOWN, true); } void DamageTaken(Unit*, uint32& uiDamage, DamageEffectType, SpellSchoolMask) override @@ -312,6 +321,9 @@ struct npc_molten_golem : public ScriptedAI if (uiDamage >= me->GetHealth()) { + if (me->GetMap()->IsHeroic()) + DoCastSelf(SPELL_BLAST_WAVE, true); + me->UpdateEntry(NPC_BRITTLE_GOLEM, 0, false); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE); me->SetHealth(me->GetMaxHealth()); @@ -351,14 +363,19 @@ struct npc_molten_golem : public ScriptedAI switch (events.ExecuteEvent()) { - case EVENT_BLAST: - me->CastSpell(me, SPELL_BLAST_WAVE, false); - events.Repeat(14s); - break; - case EVENT_IMMOLATION: - me->CastSpell(me->GetVictim(), SPELL_IMMOLATION_STRIKE, false); + case EVENT_IMMOLATION_STRIKE: + if (SelectTarget(SelectTargetMethod::MaxThreat, 0, 0.0f, true, true, -SPELL_IMMOLATION_STRIKE)) + DoCastVictim(SPELL_IMMOLATION_STRIKE); events.Repeat(5s); break; + case EVENT_CHANGE_TARGET: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + { + me->GetThreatMgr().ResetAllThreat(); + me->AddThreat(target, 30000.0f); + AttackStart(target); + } + break; } DoMeleeAttackIfReady();