/* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "arcatraz.h" #include "CreatureScript.h" #include "Player.h" #include "ScriptedCreature.h" #include "SpellScript.h" #include "SpellScriptLoader.h" enum MillhouseSays { SAY_INTRO_1 = 0, SAY_INTRO_2 = 1, SAY_WATER = 2, SAY_BUFFS = 3, SAY_DRINK = 4, SAY_READY = 5, SAY_KILL = 6, SAY_PYRO = 7, SAY_ICEBLOCK = 8, SAY_LOWHP = 9, SAY_DEATH = 10, SAY_COMPLETE = 11, SAY_INTRO_3 = 12, SAY_INTRO_4 = 13, }; enum MillhouseSpells { SPELL_CONJURE_WATER = 36879, SPELL_ARCANE_INTELLECT = 36880, SPELL_ICE_ARMOR = 36881, SPELL_ARCANE_MISSILES = 33832, SPELL_CONE_OF_COLD = 12611, SPELL_FIRE_BLAST = 13341, SPELL_FIREBALL = 14034, SPELL_FROSTBOLT = 15497, SPELL_PYROBLAST = 33975, SPELL_ICEBLOCK = 36911, }; enum MillhouseEvents { EVENT_MILLHOUSE_INTRO1 = 1, EVENT_MILLHOUSE_INTRO2 = 2, EVENT_MILLHOUSE_INTRO3 = 3, EVENT_MILLHOUSE_INTRO4 = 4, EVENT_MILLHOUSE_INTRO5 = 5, EVENT_MILLHOUSE_INTRO6 = 6, EVENT_MILLHOUSE_INTRO7 = 7, EVENT_MILLHOUSE_INTRO8 = 8, EVENT_MILLHOUSE_INTRO9 = 9, EVENT_SEARCH_FIGHT = 10, EVENT_TELEPORT_VISUAL = 11, EVENT_MILL_CHECK_HEALTH = 20, EVENT_MILL_PYROBLAST = 21, EVENT_MILL_BASE_SPELL = 22 }; class npc_millhouse_manastorm : public CreatureScript { public: npc_millhouse_manastorm() : CreatureScript("npc_millhouse_manastorm") { } struct npc_millhouse_manastormAI : public ScriptedAI { npc_millhouse_manastormAI(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); _usedIceblock = false; } InstanceScript* instance; EventMap events; EventMap events2; void InitializeAI() override { ScriptedAI::InitializeAI(); me->SetReactState(REACT_PASSIVE); me->SetImmuneToAll(true); events2.Reset(); events2.ScheduleEvent(EVENT_TELEPORT_VISUAL, 0ms); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO1, 3s); } void Reset() override { events.Reset(); _usedIceblock = false; } void AttackStart(Unit* who) override { if (who && me->Attack(who, true)) me->GetMotionMaster()->MoveChase(who, 20.0f); } void KilledUnit(Unit* /*who*/) override { Talk(SAY_KILL); } void JustDied(Unit* /*killer*/) override { Talk(SAY_DEATH); } void JustEngagedWith(Unit*) override { events.ScheduleEvent(EVENT_MILL_CHECK_HEALTH, 1s); events.ScheduleEvent(EVENT_MILL_PYROBLAST, 30s); events.ScheduleEvent(EVENT_MILL_BASE_SPELL, 2s); } void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override { if (me->HealthBelowPctDamaged(50, damage) && !_usedIceblock) { _usedIceblock = true; Talk(SAY_ICEBLOCK); DoCastSelf(SPELL_ICEBLOCK, true); } } void UpdateAI(uint32 diff) override { events2.Update(diff); switch (events2.ExecuteEvent()) { case EVENT_TELEPORT_VISUAL: me->CastSpell(me, SPELL_TELEPORT_VISUAL, true); break; case EVENT_MILLHOUSE_INTRO1: Talk(SAY_INTRO_1); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO2, 18s); break; case EVENT_MILLHOUSE_INTRO2: Talk(SAY_INTRO_2); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO3, 8s); break; case EVENT_MILLHOUSE_INTRO3: Talk(SAY_INTRO_3); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO4, 6s); break; case EVENT_MILLHOUSE_INTRO4: Talk(SAY_INTRO_4); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO5, 8s); break; case EVENT_MILLHOUSE_INTRO5: Talk(SAY_WATER); me->CastSpell(me, SPELL_CONJURE_WATER, false); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO6, 7s); break; case EVENT_MILLHOUSE_INTRO6: Talk(SAY_BUFFS); me->CastSpell(me, SPELL_ICE_ARMOR, false); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO7, 7s); break; case EVENT_MILLHOUSE_INTRO7: Talk(SAY_DRINK); me->CastSpell(me, SPELL_ARCANE_INTELLECT, false); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO8, 7s); break; case EVENT_MILLHOUSE_INTRO8: Talk(SAY_READY); me->GetMotionMaster()->MovePoint(1, 445.82f, -158.38f, 43.067f); events2.ScheduleEvent(EVENT_MILLHOUSE_INTRO9, 5s); break; case EVENT_MILLHOUSE_INTRO9: me->SetFacingTo(M_PI * 1.5f); me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), M_PI * 1.5f); me->SetImmuneToAll(false); me->SetReactState(REACT_AGGRESSIVE); events2.ScheduleEvent(EVENT_SEARCH_FIGHT, 1s); break; case EVENT_SEARCH_FIGHT: if (!me->IsInCombat() && !me->IsInEvadeMode()) if (Unit* target = me->SelectNearbyTarget(nullptr, 30.0f)) AttackStart(target); events2.ScheduleEvent(EVENT_SEARCH_FIGHT, 1s); break; } if (!UpdateVictim()) return; events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; switch (events.ExecuteEvent()) { case EVENT_MILL_CHECK_HEALTH: if (HealthBelowPct(20)) { Talk(SAY_LOWHP); break; } events.ScheduleEvent(EVENT_MILL_CHECK_HEALTH, 1s); break; case EVENT_MILL_PYROBLAST: Talk(SAY_PYRO); me->CastSpell(me->GetVictim(), SPELL_PYROBLAST, false); events.ScheduleEvent(EVENT_MILL_PYROBLAST, 30s); break; case EVENT_MILL_BASE_SPELL: switch (RAND(SPELL_FIREBALL, SPELL_ARCANE_MISSILES, SPELL_FROSTBOLT)) { case SPELL_FIREBALL: me->CastSpell(me->GetVictim(), SPELL_FIREBALL, false); events.ScheduleEvent(EVENT_MILL_BASE_SPELL, 4s); break; case SPELL_ARCANE_MISSILES: me->CastSpell(me->GetVictim(), SPELL_ARCANE_MISSILES, false); events.ScheduleEvent(EVENT_MILL_BASE_SPELL, 9s); break; case SPELL_FROSTBOLT: me->CastSpell(me->GetVictim(), SPELL_FROSTBOLT, false); events.ScheduleEvent(EVENT_MILL_BASE_SPELL, 4s); break; default: break; } break; } DoMeleeAttackIfReady(); } private: bool _usedIceblock; }; CreatureAI* GetAI(Creature* creature) const override { return GetArcatrazAI(creature); } }; enum WardenSays { YELL_INTRO1 = 0, YELL_INTRO2 = 1, YELL_RELEASE1 = 2, YELL_RELEASE2A = 3, YELL_RELEASE2B = 4, YELL_RELEASE3 = 5, YELL_RELEASE4 = 6, YELL_WELCOME = 7, SAY_HARBINGER_INTRO = 0, }; enum WardenUnits { NPC_TRICKSTER = 20905, NPC_PH_HUNTER = 20906, NPC_MILLHOUSE = 20977, NPC_AKKIRIS = 20908, NPC_SULFURON = 20909, NPC_TW_DRAK = 20910, NPC_BL_DRAK = 20911, }; enum WardenSpells { SPELL_TARGET_ALPHA = 36858, SPELL_TARGET_BETA = 36854, SPELL_TARGET_DELTA = 36856, SPELL_TARGET_GAMMA = 36857, SPELL_TARGET_OMEGA = 36852, SPELL_BUBBLE_VISUAL = 36849, SPELL_MIND_REND = 36859, SPELL_QID10886 = 39564 // Trial of the Naaru: Tenacity }; enum WardenEvents { EVENT_WARDEN_CHECK_PLAYERS = 1, EVENT_WARDEN_INTRO1 = 2, EVENT_WARDEN_INTRO2, EVENT_WARDEN_INTRO3, EVENT_WARDEN_INTRO4, EVENT_WARDEN_INTRO5, EVENT_WARDEN_INTRO6, EVENT_WARDEN_INTRO7, EVENT_WARDEN_INTRO8, EVENT_WARDEN_INTRO9, EVENT_WARDEN_INTRO10, EVENT_WARDEN_INTRO11, EVENT_WARDEN_INTRO12, EVENT_WARDEN_INTRO13, EVENT_WARDEN_INTRO14, EVENT_WARDEN_INTRO15, EVENT_WARDEN_INTRO16, EVENT_WARDEN_INTRO17, EVENT_WARDEN_INTRO18, EVENT_WARDEN_INTRO19, EVENT_WARDEN_INTRO20, EVENT_WARDEN_INTRO21, EVENT_WARDEN_INTRO22, EVENT_WARDEN_INTRO23, EVENT_WARDEN_INTRO24, EVENT_WARDEN_INTRO25, EVENT_WARDEN_INTRO26, EVENT_WARDEN_INTRO27, EVENT_WARDEN_INTRO28, EVENT_WARDEN_INTRO29 }; class npc_warden_mellichar : public CreatureScript { public: npc_warden_mellichar() : CreatureScript("npc_warden_mellichar") { } struct npc_warden_mellicharAI : public BossAI { npc_warden_mellicharAI(Creature* creature) : BossAI(creature, DATA_WARDEN_MELLICHAR) { } void JustSummoned(Creature* summon) override { summons.Summon(summon); } void SummonedCreatureDies(Creature* summon, Unit*) override { if (summon->GetEntry() == NPC_HARBINGER_SKYRISS) { me->KillSelf(); me->setActive(false); instance->SetBossState(DATA_WARDEN_MELLICHAR, DONE); if (Creature* creature = summons.GetCreatureWithEntry(NPC_MILLHOUSE)) { if (IsHeroic()) { instance->DoCastSpellOnPlayers(SPELL_QID10886); } creature->AI()->Talk(SAY_COMPLETE); creature->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP); } } } void MoveInLineOfSight(Unit*) override { } void AttackStart(Unit*) override { } void JustEngagedWith(Unit*) override { } void JustDied(Unit*) override { me->setActive(false); } void Reset() override { _Reset(); me->setActive(false); me->SetImmuneToAll(false); me->RemoveDynamicFlag(UNIT_DYNFLAG_DEAD); me->RemoveUnitFlag2(UNIT_FLAG2_FEIGN_DEATH); me->CastSpell((Unit*)nullptr, SPELL_TARGET_OMEGA, false); instance->HandleGameObject(instance->GetGuidData(DATA_WARDENS_SHIELD), true); instance->SetBossState(DATA_WARDEN_MELLICHAR, NOT_STARTED); } void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override { if (attacker && attacker->GetCharmerOrOwnerOrOwnGUID().IsPlayer() && damage > 0 && !me->isActiveObject()) { me->setActive(true); me->InterruptNonMeleeSpells(false); me->SetImmuneToAll(true); events.ScheduleEvent(EVENT_WARDEN_INTRO1, 1500ms); events.ScheduleEvent(EVENT_WARDEN_CHECK_PLAYERS, 1s); instance->SetBossState(DATA_WARDEN_MELLICHAR, IN_PROGRESS); } damage = 0; } void SetData(uint32 type, uint32 data) override { if (data == FAIL) { CreatureAI::EnterEvadeMode(); return; } if (data != DONE) return; switch (type) { case DATA_WARDEN_1: events.ScheduleEvent(EVENT_WARDEN_INTRO8, 2s); break; case DATA_WARDEN_3: events.ScheduleEvent(EVENT_WARDEN_INTRO19, 2s); break; case DATA_WARDEN_4: events.ScheduleEvent(EVENT_WARDEN_INTRO24, 2s); break; } } void UpdateAI(uint32 diff) override { events.Update(diff); switch (events.ExecuteEvent()) { case EVENT_WARDEN_CHECK_PLAYERS: if (!SelectTargetFromPlayerList(100.0f)) { CreatureAI::EnterEvadeMode(); return; } events.ScheduleEvent(EVENT_WARDEN_CHECK_PLAYERS, 1s); break; case EVENT_WARDEN_INTRO1: Talk(YELL_INTRO1); me->SetFacingTo(M_PI / 2.0f); me->CastSpell(me, SPELL_BUBBLE_VISUAL, false); events.ScheduleEvent(EVENT_WARDEN_INTRO2, 1400ms); break; case EVENT_WARDEN_INTRO2: instance->HandleGameObject(instance->GetGuidData(DATA_WARDENS_SHIELD), false); events.ScheduleEvent(EVENT_WARDEN_INTRO3, 20s); break; case EVENT_WARDEN_INTRO3: Talk(YELL_INTRO2); events.ScheduleEvent(EVENT_WARDEN_INTRO4, 5s); break; case EVENT_WARDEN_INTRO4: me->SetFacingTo(0.5f); me->CastSpell((Unit*)nullptr, SPELL_TARGET_ALPHA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO5, 2s); break; case EVENT_WARDEN_INTRO5: instance->SetData(DATA_WARDEN_1, IN_PROGRESS); events.ScheduleEvent(EVENT_WARDEN_INTRO6, 3s); break; case EVENT_WARDEN_INTRO6: me->SetFacingTo(M_PI * 1.5f); me->CastSpell((Unit*)nullptr, SPELL_TARGET_OMEGA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO7, 5s); break; case EVENT_WARDEN_INTRO7: me->SummonCreature(RAND(NPC_TRICKSTER, NPC_PH_HUNTER), 478.326f, -148.505f, 42.56f, 3.19f, TEMPSUMMON_MANUAL_DESPAWN); // Wait for kill break; case EVENT_WARDEN_INTRO8: Talk(YELL_RELEASE1); me->InterruptNonMeleeSpells(false); me->SetFacingTo(2.6f); events.ScheduleEvent(EVENT_WARDEN_INTRO10, 4s); break; case EVENT_WARDEN_INTRO10: me->CastSpell((Unit*)nullptr, SPELL_TARGET_BETA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO11, 2s); break; case EVENT_WARDEN_INTRO11: Talk(YELL_RELEASE2A); instance->SetData(DATA_WARDEN_2, IN_PROGRESS); events.ScheduleEvent(EVENT_WARDEN_INTRO12, 2s); break; case EVENT_WARDEN_INTRO12: me->SetFacingTo(M_PI * 1.5f); me->CastSpell((Unit*)nullptr, SPELL_TARGET_OMEGA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO13, 6s); break; case EVENT_WARDEN_INTRO13: me->SummonCreature(NPC_MILLHOUSE, 413.292f, -148.378f, 42.56f, 6.27f, TEMPSUMMON_MANUAL_DESPAWN); events.ScheduleEvent(EVENT_WARDEN_INTRO14, 14s); break; case EVENT_WARDEN_INTRO14: Talk(YELL_RELEASE2B); me->InterruptNonMeleeSpells(false); me->SetFacingTo(3.3f); events.ScheduleEvent(EVENT_WARDEN_INTRO15, 5s); break; case EVENT_WARDEN_INTRO15: me->CastSpell((Unit*)nullptr, SPELL_TARGET_DELTA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO16, 2s); break; case EVENT_WARDEN_INTRO16: instance->SetData(DATA_WARDEN_3, IN_PROGRESS); events.ScheduleEvent(EVENT_WARDEN_INTRO17, 2s); break; case EVENT_WARDEN_INTRO17: me->SetFacingTo(M_PI * 1.5f); me->CastSpell((Unit*)nullptr, SPELL_TARGET_OMEGA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO18, 6s); break; case EVENT_WARDEN_INTRO18: me->SummonCreature(RAND(NPC_AKKIRIS, NPC_SULFURON), 420.179f, -174.396f, 42.58f, 0.02f, TEMPSUMMON_MANUAL_DESPAWN); // Wait for kill break; case EVENT_WARDEN_INTRO19: Talk(YELL_RELEASE3); me->InterruptNonMeleeSpells(false); me->SetFacingTo(6.05f); events.ScheduleEvent(EVENT_WARDEN_INTRO20, 4s); break; case EVENT_WARDEN_INTRO20: me->CastSpell((Unit*)nullptr, SPELL_TARGET_GAMMA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO21, 2s); break; case EVENT_WARDEN_INTRO21: instance->SetData(DATA_WARDEN_4, IN_PROGRESS); events.ScheduleEvent(EVENT_WARDEN_INTRO22, 2s); break; case EVENT_WARDEN_INTRO22: me->SetFacingTo(M_PI * 1.5f); me->CastSpell((Unit*)nullptr, SPELL_TARGET_OMEGA, false); events.ScheduleEvent(EVENT_WARDEN_INTRO23, 6s); break; case EVENT_WARDEN_INTRO23: me->SummonCreature(RAND(NPC_TW_DRAK, NPC_BL_DRAK), 471.795f, -174.58f, 42.58f, 3.06f, TEMPSUMMON_MANUAL_DESPAWN); // Wait for kill break; case EVENT_WARDEN_INTRO24: instance->SetData(DATA_WARDEN_5, IN_PROGRESS); Talk(YELL_RELEASE4); me->InterruptNonMeleeSpells(false); events.ScheduleEvent(EVENT_WARDEN_INTRO25, 8s); break; case EVENT_WARDEN_INTRO25: if (Creature* cr = me->SummonCreature(NPC_HARBINGER_SKYRISS, 445.763f, -191.639f, 44.64f, 1.60f, TEMPSUMMON_MANUAL_DESPAWN)) { cr->SetImmuneToAll(true); cr->CastSpell(cr, SPELL_TELEPORT_VISUAL, true); } events.ScheduleEvent(EVENT_WARDEN_INTRO26, 1s); break; case EVENT_WARDEN_INTRO26: if (Creature* creature = summons.GetCreatureWithEntry(NPC_HARBINGER_SKYRISS)) creature->AI()->Talk(SAY_HARBINGER_INTRO); events.ScheduleEvent(EVENT_WARDEN_INTRO27, 23s); break; case EVENT_WARDEN_INTRO27: Talk(YELL_WELCOME); events.ScheduleEvent(EVENT_WARDEN_INTRO28, 5s); break; case EVENT_WARDEN_INTRO28: instance->HandleGameObject(instance->GetGuidData(DATA_WARDENS_SHIELD), true); if (Creature* creature = summons.GetCreatureWithEntry(NPC_HARBINGER_SKYRISS)) creature->CastSpell((Unit*)nullptr, SPELL_MIND_REND, false); events.ScheduleEvent(EVENT_WARDEN_INTRO29, 4s); break; case EVENT_WARDEN_INTRO29: events.Reset(); me->SetDynamicFlag(UNIT_DYNFLAG_DEAD); me->SetUnitFlag2(UNIT_FLAG2_FEIGN_DEATH); if (Creature* creature = summons.GetCreatureWithEntry(NPC_HARBINGER_SKYRISS)) { creature->SetImmuneToAll(false); if (Player* player = SelectTargetFromPlayerList(50.0f)) AttackStart(player); } break; } } }; CreatureAI* GetAI(Creature* creature) const override { return GetArcatrazAI(creature); } }; class spell_arcatraz_soul_steal_aura : public AuraScript { PrepareAuraScript(spell_arcatraz_soul_steal_aura); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_SOUL_STEAL }); } void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* caster = GetCaster()) caster->CastSpell(caster, SPELL_SOUL_STEAL, true); } void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* caster = GetCaster()) caster->RemoveAurasDueToSpell(SPELL_SOUL_STEAL); } void Register() override { OnEffectApply += AuraEffectApplyFn(spell_arcatraz_soul_steal_aura::HandleEffectApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, AURA_EFFECT_HANDLE_REAL); OnEffectRemove += AuraEffectRemoveFn(spell_arcatraz_soul_steal_aura::HandleEffectRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, AURA_EFFECT_HANDLE_REAL); } }; void AddSC_arcatraz() { new npc_millhouse_manastorm(); new npc_warden_mellichar(); RegisterSpellScript(spell_arcatraz_soul_steal_aura); }