diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h index 12bd2a06e2..b8a9060faf 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h @@ -36,7 +36,6 @@ enum BWDDataTypes DATA_NEFARIANS_END = 5, /*Events*/ - DATA_DEAD_DWARF_SPIRITS, DATA_ANCIENT_BELL, DATA_COLUMN_OF_LIGHT, @@ -62,7 +61,11 @@ enum BWDDataTypes /*Chimaeron*/ DATA_BILE_O_TRON_800, DATA_FINKLE_EINHORN, - DATA_LORD_VICTOR_NEFARIUS_CHIMAERON + DATA_LORD_VICTOR_NEFARIUS_CHIMAERON, + + /*Maloriak*/ + DATA_CAULDRON_TRIGGER, + DATA_CAULDRON }; enum BWDCreatureIds @@ -115,6 +118,9 @@ enum BWDCreatureIds NPC_BILE_O_TRON_800 = 44418, NPC_LORD_VICTOR_NEFARIUS_CHIMAERON = 48964, + /*Maloriak*/ + NPC_CAULDRON_TRIGGER = 41505, + /*Events*/ NPC_SPIRIT_OF_MOLTENFIST = 43125, NPC_SPIRIT_OF_ANVILRAGE = 43128, @@ -129,9 +135,10 @@ enum BWDCreatureIds enum BWDGameObjectIds { - GO_INNER_CHAMBER_DOOR = 205830, - GO_ANCIENT_BELL = 204276, - GO_ATHENAEUM_DOOR = 208291, + GO_INNER_CHAMBER_DOOR = 205830, + GO_ANCIENT_BELL = 204276, + GO_ATHENAEUM_DOOR = 208291, + GO_DOODAD_BLACKROCKV2_LABROOM_CAULDRON_01 = 203306 }; enum BWDMisc diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_maloriak.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_maloriak.cpp new file mode 100644 index 0000000000..96d080e377 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_maloriak.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2008-2019 TrinityCore + * + * 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 "ObjectMgr.h" +#include "ScriptMgr.h" +#include "CommonPredicates.h" +#include "GridNotifiers.h" +#include "PassiveAI.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "SpellMgr.h" +#include "blackwing_descent.h" + +enum Spells +{ + // Maloriak + SPELL_ARCANE_STORM = 77896, + SPELL_REMEDY = 77912, + + SPELL_THROW_RED_BOTTLE = 77925, + SPELL_THROW_BLUE_BOTTLE = 77932, + SPELL_THROW_GREEN_BOTTLE = 77937, + SPELL_DRINK_RED_BOTTLE = 88699, + SPELL_DRINK_BLUE_BOTTLE = 88700, + SPELL_DRINK_BLACK_BOTTLE = 92828, + SPELL_FIRE_IMBUED = 78896, + SPELL_FROST_IMBUED = 78895, + SPELL_SHADOW_IMBUED = 92716, + SPELL_SLIME_IMBUED = 92917, + SPELL_THROW_RED_BOTTLE_TRIGGERED = 77928, + SPELL_THROW_BLUE_BOTTLE_TRIGGERED = 77934, + SPELL_THROW_GREEN_BOTTLE_TRIGGERED = 77938, + SPELL_THROW_BLACK_BOTTLE_TRIGGERED = 92837, + SPELL_RELEASE_ABERRATIONS = 77569, + + // Cauldron Trigger + SPELL_DEBILITATING_SLIME_CAST = 77602, + SPELL_DEBILITATING_SLIME_KNOCKBACK = 77948, + SPELL_DEBILITATING_SLIME_DEBUFF = 77615, + +}; + +enum Events +{ + // Maloriak + EVENT_ARCANE_STORM = 1, + EVENT_REMEDY, + EVENT_RELEASE_ABERRATIONS, + EVENT_FACE_TO_CAULDRON, + EVENT_THROW_VIAL, + EVENT_MOVE_TO_CAULDRON, + EVENT_DRINK_BOTTLE, + EVENT_IMBUED_BUFF, + EVENT_EXPLODE_CAULDRON, + EVENT_ATTACK_PLAYERS, +}; + +enum Actions +{ + ACTION_SCHEDULE_EVENTS_FOR_PHASE = 1 +}; + +enum MovePoints +{ + POINT_CAULDRON = 1 +}; + +enum Texts +{ + // Maloriak + SAY_AGGRO = 0, + SAY_RED_VIAL = 1, + SAY_ANNOUNCE_RED_VIAL = 2, + SAY_BLUE_VIAL = 3, + SAY_ANNOUNCE_BLUE_VIAL = 4, + SAY_GREEN_VIAL = 5, + SAY_ANNOUNCE_GREEN_VIAL = 6, + SAY_RELEASE_ABERRATIONS = 7, +}; + +enum Vials +{ + VIAL_RED = 0, + VIAL_BLUE = 1, + VIAL_GREEN = 2 +}; + +enum GameObjectCustomAnim +{ + CUSTOM_ANIM_RED_CAULDRON = 0, + CUSTOM_ANIM_BLUE_CAULDRON = 1, + CUSTOM_ANIM_GREEN_CAULDRON = 2, + CUSTOM_ANIM_BLACK_CAULDRON = 3 +}; + +Position const CauldronMovePosition = { -106.6782f, -475.4438f, 73.45684f }; + +struct VialData +{ + uint8 SayTextId; + uint8 AnnounceTextId; + uint32 ThrowSpellId; + uint32 DrinkSpellId; + uint32 ImbuedSpellId; +}; + +std::unordered_map vialData = +{ + { VIAL_RED, { SAY_RED_VIAL, SAY_ANNOUNCE_RED_VIAL, SPELL_THROW_RED_BOTTLE, SPELL_DRINK_RED_BOTTLE, SPELL_FIRE_IMBUED }}, + { VIAL_BLUE, { SAY_BLUE_VIAL, SAY_ANNOUNCE_BLUE_VIAL, SPELL_THROW_BLUE_BOTTLE, SPELL_DRINK_BLUE_BOTTLE, SPELL_FROST_IMBUED }}, + { VIAL_GREEN, { SAY_GREEN_VIAL, SAY_ANNOUNCE_GREEN_VIAL, SPELL_THROW_GREEN_BOTTLE, 0, SPELL_SLIME_IMBUED }}, +}; + +struct boss_maloriak : public BossAI +{ + boss_maloriak(Creature* creature) : BossAI(creature, DATA_MALORIAK), + _currentVial(urand(VIAL_RED, VIAL_BLUE)), _usedVialsCount(0) { } + + void Reset() override + { + _Reset(); + me->MakeInterruptable(false); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + Talk(SAY_AGGRO); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + events.ScheduleEvent(EVENT_FACE_TO_CAULDRON, 15s + 500ms); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + summons.DespawnAll(); + _DespawnAtEvade(); + } + + void OnSpellCastInterrupt(SpellInfo const* spell) override + { + switch (spell->Id) + { + case SPELL_ARCANE_STORM: + me->MakeInterruptable(false); + me->m_Events.KillAllEvents(true); + break; + case SPELL_RELEASE_ABERRATIONS: + me->MakeInterruptable(false); + break; + default: + break; + } + } + + void OnSuccessfulSpellCast(SpellInfo const* spell) override + { + switch (spell->Id) + { + case SPELL_RELEASE_ABERRATIONS: + Talk(SAY_RELEASE_ABERRATIONS); + me->MakeInterruptable(false); + break; + default: + break; + } + } + + void MovementInform(uint32 motionType, uint32 pointId) override + { + if (motionType != POINT_MOTION_TYPE && motionType != EFFECT_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_CAULDRON: + events.ScheduleEvent(EVENT_DRINK_BOTTLE, 1s + 500ms); + break; + default: + break; + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_SCHEDULE_EVENTS_FOR_PHASE: + events.ScheduleEvent(EVENT_ATTACK_PLAYERS, _currentVial != VIAL_GREEN ? 1ms : 4s); + + if (_currentVial == VIAL_RED || _currentVial == VIAL_BLUE) + { + events.ScheduleEvent(EVENT_ARCANE_STORM, 14s + 500ms); + events.ScheduleEvent(EVENT_REMEDY, 21s + 500ms); + events.ScheduleEvent(EVENT_RELEASE_ABERRATIONS, 11s); + } + else if (_currentVial == VIAL_GREEN) + { + if (Creature* cauldron = instance->GetCreature(DATA_CAULDRON_TRIGGER)) + cauldron->CastSpell(cauldron, SPELL_DEBILITATING_SLIME_DEBUFF); + + events.ScheduleEvent(EVENT_ARCANE_STORM, 8s); + events.ScheduleEvent(EVENT_REMEDY, 33s + 500ms); + events.ScheduleEvent(EVENT_RELEASE_ABERRATIONS, 15s); + } + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANE_STORM: + { + me->MakeInterruptable(true); + DoCastSelf(SPELL_ARCANE_STORM); + Creature* maloriak = me; + me->m_Events.AddEventAtOffset([maloriak]() { maloriak->MakeInterruptable(false); }, 6s + 500ms); + events.Repeat(13s + 500ms); + break; + } + case EVENT_REMEDY: + DoCastSelf(SPELL_REMEDY); + break; + case EVENT_RELEASE_ABERRATIONS: + me->MakeInterruptable(true); + DoCastAOE(SPELL_RELEASE_ABERRATIONS); + events.Repeat(24s + 500ms); + break; + case EVENT_FACE_TO_CAULDRON: + events.Reset(); + if (Creature* cauldron = instance->GetCreature(DATA_CAULDRON_TRIGGER)) + { + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->SetFacingToObject(cauldron); + + _currentVial = _usedVialsCount < 2 ? _currentVial == VIAL_BLUE ? VIAL_RED : VIAL_BLUE : VIAL_GREEN; + Talk(vialData[_currentVial].SayTextId); + _usedVialsCount = _usedVialsCount < 2 ? _usedVialsCount + 1 : 0; + + events.Repeat(50s); + events.ScheduleEvent(EVENT_THROW_VIAL, 1s + 300ms); + } + break; + case EVENT_THROW_VIAL: + DoCastSelf(vialData[_currentVial].ThrowSpellId); + Talk(vialData[_currentVial].AnnounceTextId); + events.ScheduleEvent(EVENT_MOVE_TO_CAULDRON, 1s); + break; + case EVENT_MOVE_TO_CAULDRON: + me->GetMotionMaster()->MovePoint(POINT_CAULDRON, CauldronMovePosition); + break; + case EVENT_DRINK_BOTTLE: + DoCastSelf(vialData[_currentVial].DrinkSpellId); + events.ScheduleEvent(EVENT_IMBUED_BUFF, 2s + 500ms); + + if (_currentVial == VIAL_GREEN) + events.ScheduleEvent(EVENT_EXPLODE_CAULDRON, 1s); + break; + case EVENT_IMBUED_BUFF: + DoCastSelf(vialData[_currentVial].ImbuedSpellId); + DoAction(ACTION_SCHEDULE_EVENTS_FOR_PHASE); + break; + case EVENT_EXPLODE_CAULDRON: + if (Creature* cauldron = instance->GetCreature(DATA_CAULDRON_TRIGGER)) + { + cauldron->CastSpell(cauldron, SPELL_DEBILITATING_SLIME_CAST); + cauldron->CastSpell(cauldron, SPELL_DEBILITATING_SLIME_KNOCKBACK); + } + break; + case EVENT_ATTACK_PLAYERS: + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } +private: + uint8 _currentVial; + uint8 _usedVialsCount; +}; + +class spell_maloriak_throw_bottle : public SpellScript +{ + PrepareSpellScript(spell_maloriak_throw_bottle); + + void HandleDummyEffect(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void Register() override + { + OnEffectLaunchTarget += SpellEffectFn(spell_maloriak_throw_bottle::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +class spell_maloriak_throw_bottle_triggered : public SpellScript +{ + PrepareSpellScript(spell_maloriak_throw_bottle_triggered); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_THROW_RED_BOTTLE_TRIGGERED, + SPELL_THROW_BLUE_BOTTLE_TRIGGERED, + SPELL_THROW_GREEN_BOTTLE_TRIGGERED, + SPELL_THROW_BLACK_BOTTLE_TRIGGERED + }); + } + + void HandleDummyEffect(SpellEffIndex /*effIndex*/) + { + InstanceScript* instance = GetHitUnit()->GetInstanceScript(); + if (!instance) + return; + + if (GameObject* cauldron = instance->GetGameObject(DATA_CAULDRON)) + { + switch (GetSpellInfo()->Id) + { + case SPELL_THROW_RED_BOTTLE_TRIGGERED: + cauldron->SendCustomAnim(CUSTOM_ANIM_RED_CAULDRON); + break; + case SPELL_THROW_BLUE_BOTTLE_TRIGGERED: + cauldron->SendCustomAnim(CUSTOM_ANIM_BLUE_CAULDRON); + break; + case SPELL_THROW_GREEN_BOTTLE_TRIGGERED: + cauldron->SendCustomAnim(CUSTOM_ANIM_GREEN_CAULDRON); + break; + case SPELL_THROW_BLACK_BOTTLE_TRIGGERED: + cauldron->SendCustomAnim(CUSTOM_ANIM_BLACK_CAULDRON); + break; + default: + break; + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_maloriak_throw_bottle_triggered::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +void AddSC_boss_maloriak() +{ + RegisterBlackwingDescentCreatureAI(boss_maloriak); + RegisterSpellScript(spell_maloriak_throw_bottle); + RegisterSpellScript(spell_maloriak_throw_bottle_triggered); +} diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/instance_blackwing_descent.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/instance_blackwing_descent.cpp index d8b9fe428e..07417d5ba1 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/instance_blackwing_descent.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/instance_blackwing_descent.cpp @@ -28,6 +28,7 @@ ObjectData const creatureData[] = { BOSS_OMNOTRON, DATA_OMNOTRON_DEFENSE_SYSTEM }, { BOSS_ATRAMEDES, DATA_ATRAMEDES }, { BOSS_CHIMAERON, DATA_CHIMAERON }, + { BOSS_MALORIAK, DATA_MALORIAK }, { NPC_ELECTRON, DATA_ELECTRON }, { NPC_MAGMATRON, DATA_MAGMATRON }, { NPC_TOXITRON, DATA_TOXITRON }, @@ -39,14 +40,16 @@ ObjectData const creatureData[] = { NPC_BILE_O_TRON_800, DATA_BILE_O_TRON_800 }, { NPC_FINKLE_EINHORN, DATA_FINKLE_EINHORN }, { NPC_LORD_VICTOR_NEFARIUS_CHIMAERON, DATA_LORD_VICTOR_NEFARIUS_CHIMAERON }, + { NPC_CAULDRON_TRIGGER, DATA_CAULDRON_TRIGGER }, { 0, 0 } // END }; ObjectData const gameobjectData[] = { - { GO_ANCIENT_BELL, DATA_ANCIENT_BELL }, - { GO_ATHENAEUM_DOOR, DATA_ATHENAEUM_DOOR }, - { 0, 0 } // END + { GO_ANCIENT_BELL, DATA_ANCIENT_BELL }, + { GO_ATHENAEUM_DOOR, DATA_ATHENAEUM_DOOR }, + { GO_DOODAD_BLACKROCKV2_LABROOM_CAULDRON_01, DATA_CAULDRON }, + { 0, 0 } // END }; DoorData const doorData[] = diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index 854c4b1d64..a4b952ab33 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -78,6 +78,7 @@ void AddSC_boss_magmaw(); void AddSC_boss_omnotron_defense_system(); void AddSC_boss_atramedes(); void AddSC_boss_chimaeron(); +void AddSC_boss_maloriak(); void AddSC_blackwing_descent(); void AddSC_instance_deadmines(); //Deadmines void AddSC_boss_glubtok(); @@ -307,6 +308,7 @@ void AddEasternKingdomsScripts() AddSC_boss_omnotron_defense_system(); AddSC_boss_atramedes(); AddSC_boss_chimaeron(); + AddSC_boss_maloriak(); AddSC_blackwing_descent(); AddSC_instance_deadmines(); //Deadmines AddSC_boss_glubtok();