From 316da388d586eee5625d9b0a01d21b3befb2cc69 Mon Sep 17 00:00:00 2001 From: untaught Date: Sun, 3 Nov 2013 11:17:28 +0200 Subject: Fix quest Redeeming the Dead (9685) and remove the core script --- src/server/game/Scripting/ScriptLoader.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/server/game/Scripting/ScriptLoader.cpp') diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 31323a66ba9..ce3ad3cc0b9 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -272,7 +272,6 @@ void AddSC_ironforge(); void AddSC_isle_of_queldanas(); void AddSC_loch_modan(); void AddSC_redridge_mountains(); -void AddSC_silvermoon_city(); void AddSC_silverpine_forest(); void AddSC_stormwind_city(); void AddSC_stranglethorn_vale(); -- cgit v1.2.3 From b98cc11a4956ba887e6f45c63231885382bffe02 Mon Sep 17 00:00:00 2001 From: Discover- Date: Sun, 3 Nov 2013 10:36:02 +0100 Subject: Core/Misc: Fix compile after 316da388d586eee5625d9b0a01d21b3befb2cc69 --- src/server/game/Scripting/ScriptLoader.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/server/game/Scripting/ScriptLoader.cpp') diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index ce3ad3cc0b9..17fb3f33eca 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -962,7 +962,6 @@ void AddEasternKingdomsScripts() AddSC_isle_of_queldanas(); AddSC_loch_modan(); AddSC_redridge_mountains(); - AddSC_silvermoon_city(); AddSC_silverpine_forest(); AddSC_stormwind_city(); AddSC_stranglethorn_vale(); -- cgit v1.2.3 From e5b259fb4ad5f48d22f3e47443bb727698c1b5fd Mon Sep 17 00:00:00 2001 From: Malcrom Date: Sun, 10 Nov 2013 03:22:22 -0330 Subject: Scripting/Arcatraz: Move Zereketh the Unbound, Dalliah the Doomsayer, & Wrath-Scryer Soccothrates to cpp scripting and some cleanup. --- sql/updates/world/2013_11_10_00_world_misc.sql | 40 ++++ src/server/game/Scripting/ScriptLoader.cpp | 6 + src/server/scripts/Outland/CMakeLists.txt | 3 + .../Outland/TempestKeep/arcatraz/arcatraz.cpp | 34 +-- .../Outland/TempestKeep/arcatraz/arcatraz.h | 56 +++-- .../arcatraz/boss_dalliah_the_doomsayer.cpp | 165 +++++++++++++ .../arcatraz/boss_harbinger_skyriss.cpp | 19 +- .../arcatraz/boss_wrath_scryer_soccothrates.cpp | 254 +++++++++++++++++++++ .../arcatraz/boss_zereketh_the_unbound.cpp | 132 +++++++++++ .../TempestKeep/arcatraz/instance_arcatraz.cpp | 61 ++--- 10 files changed, 688 insertions(+), 82 deletions(-) create mode 100644 sql/updates/world/2013_11_10_00_world_misc.sql create mode 100644 src/server/scripts/Outland/TempestKeep/arcatraz/boss_dalliah_the_doomsayer.cpp create mode 100644 src/server/scripts/Outland/TempestKeep/arcatraz/boss_wrath_scryer_soccothrates.cpp create mode 100644 src/server/scripts/Outland/TempestKeep/arcatraz/boss_zereketh_the_unbound.cpp (limited to 'src/server/game/Scripting/ScriptLoader.cpp') diff --git a/sql/updates/world/2013_11_10_00_world_misc.sql b/sql/updates/world/2013_11_10_00_world_misc.sql new file mode 100644 index 00000000000..3898206978d --- /dev/null +++ b/sql/updates/world/2013_11_10_00_world_misc.sql @@ -0,0 +1,40 @@ +-- Creature text for Wrath-Scryer Soccothrates +SET @ENTRY = 20886; +DELETE FROM `creature_text` WHERE `entry`=@ENTRY AND `groupid` IN (7,8,9,10); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(@ENTRY, 7, 0, 'Did you call on me?', 14, 0, 100, 397, 0, 11236, 'Wrath-Scryer Soccothrates - Conversation with Dalliah part 1'), +(@ENTRY, 8, 0, 'To do your heavy lifting, most likely.', 14, 0, 100, 396, 0, 0, 'Wrath-Scryer Soccothrates - Conversation with Dalliah part 2'), +(@ENTRY, 9, 0, 'Then I''ll commit myself to ignoring you.', 14, 0, 100, 396, 0, 0, 'Wrath-Scryer Soccothrates - Conversation with Dalliah part 3'), +(@ENTRY, 10, 0, 'You''re the one who should be-- Wait, we have company...', 14, 0, 100, 396, 0, 0, 'Wrath-Scryer Soccothrates - Conversation with Dalliah part 4'); + +-- Creature text for Dalliah the Doomsayer +SET @ENTRY = 20885; +DELETE FROM `creature_text` WHERE `entry`=@ENTRY AND `groupid` IN (8,9,10); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(@ENTRY, 8, 0, 'Why would I call on you?', 14, 0, 100, 396, 0, 0, 'Dalliah the Doomsayer - Conversation with Soccothrates part 1'), +(@ENTRY, 9, 0, 'When I need someone to prance around like an overstuffed peacock, I''ll call on you.', 14, 0, 100, 396, 0, 0, 'Dalliah the Doomsayer - Conversation with Soccothrates part 2'), +(@ENTRY, 10, 0, 'What would you know about commitment, sheet-sah?', 14, 0, 100, 396, 0, 0, 'Dalliah the Doomsayer - Conversation with Soccothrates part 3'); + +-- Creature text updates +UPDATE `creature_text` SET `emote`=1 WHERE `entry`=20886 AND `groupid` IN (0,5); +UPDATE `creature_text` SET `emote`=1 WHERE `entry`=20885 AND `groupid` IN (0,6); +UPDATE `creature_text` SET `emote`=66 WHERE `entry`=20886 AND `groupid` IN (6); +UPDATE `creature_text` SET `emote`=66 WHERE `entry`=20885 AND `groupid` IN (7); +UPDATE `creature_text` SET `text`= 'As masters of blood, we are masters of life and death itself. Against us, even hope falls drained and lifeless.' WHERE `entry`=29196 AND `groupid`=8; +UPDATE `creature_text` SET `comment`= 'Wrath-Scryer Soccothrates - Knock Away' WHERE `entry`=20886 AND `groupid` IN (3); + +-- Add missing spelldifficulty_dbc values +DELETE FROM `spelldifficulty_dbc` WHERE `id` IN (36127,36123,36173,36144,35759,36051); +INSERT INTO `spelldifficulty_dbc` (`id`,`spellid0`,`spellid1`) VALUES +(36127,36127,39005),(36123,36123,39367), -- Zereketh the Unbound +(36173,36173,39009),(36144,36144,39013), -- Dalliah the Doomsayer +(35759,35759,39006),(36051,36051,39007); -- Wrath-Scryer Soccothrates + +UPDATE `creature_template` SET `AIName` = '', `ScriptName`= 'boss_zereketh_the_unbound' WHERE entry=20870; +UPDATE `creature_template` SET `AIName` = '', `ScriptName`= 'boss_dalliah_the_doomsayer' WHERE entry=20885; +UPDATE `creature_template` SET `AIName` = '', `ScriptName`= 'boss_wrath_scryer_soccothrates' WHERE entry=20886; +DELETE FROM creature_ai_scripts WHERE creature_id IN (20885,20886); +DELETE FROM smart_scripts WHERE entryorguid IN (20870); +DELETE FROM creature_ai_texts WHERE entry BETWEEN -28 AND -23; +DELETE FROM creature_ai_texts WHERE entry BETWEEN -80 AND -73; +UPDATE `creature` SET `spawndist`=5, `MovementType`=1 WHERE `id`=20870; diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 17fb3f33eca..779c9be6c0e 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -619,6 +619,9 @@ void AddSC_boss_omor_the_unscarred(); void AddSC_boss_vazruden_the_herald(); void AddSC_instance_ramparts(); void AddSC_arcatraz(); //TK Arcatraz +void AddSC_boss_zereketh_the_unbound(); +void AddSC_boss_dalliah_the_doomsayer(); +void AddSC_boss_wrath_scryer_soccothrates(); void AddSC_boss_harbinger_skyriss(); void AddSC_instance_arcatraz(); void AddSC_boss_high_botanist_freywinn(); //TK Botanica @@ -1140,6 +1143,9 @@ void AddOutlandScripts() AddSC_boss_vazruden_the_herald(); AddSC_instance_ramparts(); AddSC_arcatraz(); //TK Arcatraz + AddSC_boss_zereketh_the_unbound(); + AddSC_boss_dalliah_the_doomsayer(); + AddSC_boss_wrath_scryer_soccothrates(); AddSC_boss_harbinger_skyriss(); AddSC_instance_arcatraz(); AddSC_boss_high_botanist_freywinn(); //TK Botanica diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index 84cbbc3c30c..45db8a80a26 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -68,6 +68,9 @@ set(scripts_STAT_SRCS Outland/TempestKeep/botanica/boss_high_botanist_freywinn.cpp Outland/TempestKeep/botanica/boss_warp_splinter.cpp Outland/TempestKeep/botanica/boss_laj.cpp + Outland/TempestKeep/arcatraz/boss_zereketh_the_unbound.cpp + Outland/TempestKeep/arcatraz/boss_dalliah_the_doomsayer.cpp + Outland/TempestKeep/arcatraz/boss_wrath_scryer_soccothrates.cpp Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp Outland/TempestKeep/arcatraz/instance_arcatraz.cpp Outland/TempestKeep/arcatraz/arcatraz.h diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp index 9206636893c..8b3dc8f174c 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp @@ -103,10 +103,10 @@ class npc_millhouse_manastorm : public CreatureScript if (instance) { - if (instance->GetData(TYPE_WARDEN_2) == DONE) + if (instance->GetData(DATA_WARDEN_2) == DONE) Init = true; - if (instance->GetData(TYPE_HARBINGERSKYRISS) == DONE) + if (instance->GetData(DATA_HARBINGERSKYRISS) == DONE) Talk(SAY_COMPLETE); } } @@ -177,7 +177,7 @@ class npc_millhouse_manastorm : public CreatureScript break; case 7: if (instance) - instance->SetData(TYPE_WARDEN_2, DONE); + instance->SetData(DATA_WARDEN_2, DONE); Init = true; break; } @@ -305,7 +305,7 @@ class npc_warden_mellichar : public CreatureScript DoCast(me, SPELL_TARGET_OMEGA); if (instance) - instance->SetData(TYPE_HARBINGERSKYRISS, NOT_STARTED); + instance->SetData(DATA_HARBINGERSKYRISS, NOT_STARTED); } void AttackStart(Unit* /*who*/) OVERRIDE { } @@ -336,7 +336,7 @@ class npc_warden_mellichar : public CreatureScript if (instance) { - instance->SetData(TYPE_HARBINGERSKYRISS, IN_PROGRESS); + instance->SetData(DATA_HARBINGERSKYRISS, IN_PROGRESS); instance->HandleGameObject(instance->GetData64(DATA_SPHERE_SHIELD), false); IsRunning = true; } @@ -346,19 +346,19 @@ class npc_warden_mellichar : public CreatureScript { if (instance) { - if (Phase == 7 && instance->GetData(TYPE_WARDEN_4) == DONE) + if (Phase == 7 && instance->GetData(DATA_WARDEN_4) == DONE) return true; - if (Phase == 6 && instance->GetData(TYPE_WARDEN_3) == DONE) + if (Phase == 6 && instance->GetData(DATA_WARDEN_3) == DONE) return true; - if (Phase == 5 && instance->GetData(TYPE_WARDEN_2) == DONE) + if (Phase == 5 && instance->GetData(DATA_WARDEN_2) == DONE) return true; if (Phase == 4) return true; - if (Phase == 3 && instance->GetData(TYPE_WARDEN_1) == DONE) + if (Phase == 3 && instance->GetData(DATA_WARDEN_1) == DONE) return true; - if (Phase == 2 && instance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS) + if (Phase == 2 && instance->GetData(DATA_HARBINGERSKYRISS) == IN_PROGRESS) return true; - if (Phase == 1 && instance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS) + if (Phase == 1 && instance->GetData(DATA_HARBINGERSKYRISS) == IN_PROGRESS) return true; return false; } @@ -376,23 +376,23 @@ class npc_warden_mellichar : public CreatureScript { case 2: DoCast(me, SPELL_TARGET_ALPHA); - instance->SetData(TYPE_WARDEN_1, IN_PROGRESS); + instance->SetData(DATA_WARDEN_1, IN_PROGRESS); instance->HandleGameObject(instance->GetData64(DATA_SPHERE_SHIELD), false); break; case 3: DoCast(me, SPELL_TARGET_BETA); - instance->SetData(TYPE_WARDEN_2, IN_PROGRESS); + instance->SetData(DATA_WARDEN_2, IN_PROGRESS); break; case 5: DoCast(me, SPELL_TARGET_DELTA); - instance->SetData(TYPE_WARDEN_3, IN_PROGRESS); + instance->SetData(DATA_WARDEN_3, IN_PROGRESS); break; case 6: DoCast(me, SPELL_TARGET_GAMMA); - instance->SetData(TYPE_WARDEN_4, IN_PROGRESS); + instance->SetData(DATA_WARDEN_4, IN_PROGRESS); break; case 7: - instance->SetData(TYPE_WARDEN_5, IN_PROGRESS); + instance->SetData(DATA_WARDEN_5, IN_PROGRESS); break; } CanSpawn = true; @@ -408,7 +408,7 @@ class npc_warden_mellichar : public CreatureScript { if (instance) { - if (instance->GetData(TYPE_HARBINGERSKYRISS) == FAIL) + if (instance->GetData(DATA_HARBINGERSKYRISS) == FAIL) { Reset(); return; diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.h b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.h index 37839d4794d..038d94fc960 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.h +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.h @@ -16,23 +16,49 @@ * with this program. If not, see . */ -#ifndef ARCATRAZ_H_ -#define ARCATRAZ_H_ +#ifndef ARCATRAZ_H +#define ARCATRAZ_H + +uint32 const EncounterCount = 13; + +#define AScriptName "instance_arcatraz" enum DataTypes { - TYPE_ZEREKETH = 1, - TYPE_DALLIAH = 2, - TYPE_SOCCOTHRATES = 3, - TYPE_HARBINGERSKYRISS = 4, - TYPE_WARDEN_1 = 5, - TYPE_WARDEN_2 = 6, - TYPE_WARDEN_3 = 7, - TYPE_WARDEN_4 = 8, - TYPE_WARDEN_5 = 9, - DATA_MELLICHAR = 10, - TYPE_SHIELD_OPEN = 11, - DATA_SPHERE_SHIELD = 12 + DATA_ZEREKETH = 1, + DATA_DALLIAH = 2, + DATA_SOCCOTHRATES = 3, + DATA_HARBINGERSKYRISS = 4, + DATA_WARDEN_1 = 5, + DATA_WARDEN_2 = 6, + DATA_WARDEN_3 = 7, + DATA_WARDEN_4 = 8, + DATA_WARDEN_5 = 9, + DATA_MELLICHAR = 10, + DATA_SHIELD_OPEN = 11, + DATA_SPHERE_SHIELD = 12, + DATA_CONVERSATION = 13 +}; + +enum CreaturesIds +{ + NPC_MELLICHAR = 20904, //skyriss will kill this unit + NPC_ALPHA_POD_TARGET = 21436, + NPC_DALLIAH = 20885, + NPC_SOCCOTHRATES = 20886 +}; + +enum GameObjectsIds +{ + CONTAINMENT_CORE_SECURITY_FIELD_ALPHA = 184318, //door opened when Wrath-Scryer Soccothrates dies + CONTAINMENT_CORE_SECURITY_FIELD_BETA = 184319, //door opened when Dalliah the Doomsayer dies + POD_ALPHA = 183961, //pod first boss wave + POD_BETA = 183963, //pod second boss wave + POD_DELTA = 183964, //pod third boss wave + POD_GAMMA = 183962, //pod fourth boss wave + POD_OMEGA = 183965, //pod fifth boss wave + WARDENS_SHIELD = 184802, // warden shield + SEAL_SPHERE = 184802 //shield 'protecting' mellichar }; -#endif // ARCATRAZ_H_ +#endif // ARCATRAZ_H diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_dalliah_the_doomsayer.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_dalliah_the_doomsayer.cpp new file mode 100644 index 00000000000..20cfb2f07f8 --- /dev/null +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_dalliah_the_doomsayer.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2008-2013 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 . + */ + +/* ScriptData +SDName: boss_dalliah_the_doomsayer +SD%Complete: 95% +SDComment: soccothrates death left to script +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "arcatraz.h" + +enum Say +{ + SAY_AGGRO = 1, + SAY_SLAY = 2, + SAY_WHIRLWIND = 3, + SAY_HEAL = 4, + SAY_DEATH = 5, + SAY_SOCCOTHRATES_DEATH = 7, // To be scripted + + // boss_wrath_scryer_soccothrates + SAY_AGGRO_DALLIAH_FIRST = 0, + SAY_DALLIAH_25_PERCENT = 5 +}; + +enum Spells +{ + SPELL_GIFT_OF_THE_DOOMSAYER = 36173, + SPELL_WHIRLWIND = 36142, + SPELL_HEAL = 36144, + SPELL_SHADOW_WAVE = 39016 // Heroic only +}; + +enum Events +{ + EVENT_GIFT_OF_THE_DOOMSAYER = 1, + EVENT_WHIRLWIND = 2, + EVENT_HEAL = 3, + EVENT_SHADOW_WAVE = 4, // Heroic only + EVENT_ME_FIRST = 5 +}; + +class boss_dalliah_the_doomsayer : public CreatureScript +{ + public: + boss_dalliah_the_doomsayer() : CreatureScript("boss_dalliah_the_doomsayer") { } + + struct boss_dalliah_the_doomsayerAI : public BossAI + { + boss_dalliah_the_doomsayerAI(Creature* creature) : BossAI(creature, DATA_DALLIAH) { } + + void Reset() OVERRIDE + { + _Reset(); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + Talk(SAY_DEATH); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.ScheduleEvent(EVENT_GIFT_OF_THE_DOOMSAYER, urand(1000, 4000)); + events.ScheduleEvent(EVENT_WHIRLWIND, urand(7000, 9000)); + if (IsHeroic()) + events.ScheduleEvent(EVENT_SHADOW_WAVE, urand(11000, 16000)); + events.ScheduleEvent(EVENT_ME_FIRST, 6000); + Talk(SAY_AGGRO); + + if (Creature* soccothrates = me->FindNearestCreature(NPC_SOCCOTHRATES, 100.0f, true)) + soccothratesGUID = soccothrates->GetGUID(); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE + { + Talk(SAY_SLAY); + } + + 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_GIFT_OF_THE_DOOMSAYER: + DoCastVictim(SPELL_GIFT_OF_THE_DOOMSAYER, true); + events.ScheduleEvent(EVENT_GIFT_OF_THE_DOOMSAYER, urand(16000, 21000)); + break; + case EVENT_WHIRLWIND: + DoCast(me, SPELL_WHIRLWIND); + Talk(SAY_WHIRLWIND); + events.ScheduleEvent(EVENT_WHIRLWIND, urand(19000, 21000)); + events.ScheduleEvent(EVENT_HEAL, 6000); + break; + case EVENT_HEAL: + DoCast(me, SPELL_HEAL); + Talk(SAY_HEAL); + break; + case EVENT_SHADOW_WAVE: + DoCastVictim(SPELL_SHADOW_WAVE, true); + events.ScheduleEvent(EVENT_SHADOW_WAVE, urand(11000, 16000)); + break; + case EVENT_ME_FIRST: + if (Creature* soccothrates = me->GetCreature(*me, soccothratesGUID)) + if (soccothrates->IsAlive() && !soccothrates->IsInCombat()) + soccothrates->AI()->Talk(SAY_AGGRO_DALLIAH_FIRST); + break; + default: + break; + } + } + + if (HealthBelowPct(25) && !soccothratesTaunt) + { + if (Creature* soccothrates = me->GetCreature(*me, soccothratesGUID)) + soccothrates->AI()->Talk(SAY_DALLIAH_25_PERCENT); + soccothratesTaunt = true; + } + + DoMeleeAttackIfReady(); + } + + private: + bool soccothratesTaunt; + uint64 soccothratesGUID; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_dalliah_the_doomsayerAI(creature); + } +}; + +void AddSC_boss_dalliah_the_doomsayer() +{ + new boss_dalliah_the_doomsayer(); +} diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp index eda90d3b734..3748b704e0a 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp @@ -61,21 +61,15 @@ enum Spells class boss_harbinger_skyriss : public CreatureScript { public: + boss_harbinger_skyriss() : CreatureScript("boss_harbinger_skyriss") { } - boss_harbinger_skyriss() - : CreatureScript("boss_harbinger_skyriss") + struct boss_harbinger_skyrissAI : public BossAI { - } - struct boss_harbinger_skyrissAI : public ScriptedAI - { - boss_harbinger_skyrissAI(Creature* creature) : ScriptedAI(creature) + boss_harbinger_skyrissAI(Creature* creature) : BossAI(creature, DATA_HARBINGERSKYRISS) { - instance = creature->GetInstanceScript(); Intro = false; } - InstanceScript* instance; - bool Intro; bool IsImage33; bool IsImage66; @@ -117,8 +111,7 @@ class boss_harbinger_skyriss : public CreatureScript void JustDied(Unit* /*killer*/) OVERRIDE { Talk(SAY_DEATH); - if (instance) - instance->SetData(TYPE_HARBINGERSKYRISS, DONE); + _JustDied(); } void JustSummoned(Creature* summon) OVERRIDE @@ -137,7 +130,7 @@ class boss_harbinger_skyriss : public CreatureScript void KilledUnit(Unit* victim) OVERRIDE { //won't yell killing pet/other unit - if (victim->GetEntry() == 21436) + if (victim->GetEntry() == NPC_ALPHA_POD_TARGET) return; Talk(SAY_KILL); @@ -180,7 +173,7 @@ class boss_harbinger_skyriss : public CreatureScript //should have a better way to do this. possibly spell exist. mellic->setDeathState(JUST_DIED); mellic->SetHealth(0); - instance->SetData(TYPE_SHIELD_OPEN, IN_PROGRESS); + instance->SetData(DATA_SHIELD_OPEN, IN_PROGRESS); } ++Intro_Phase; Intro_Timer = 3000; diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_wrath_scryer_soccothrates.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_wrath_scryer_soccothrates.cpp new file mode 100644 index 00000000000..cef8a8b8e2d --- /dev/null +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_wrath_scryer_soccothrates.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2008-2013 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 . + */ + +/* ScriptData +SDName: boss_wrath_scryer_soccothrates +SD%Complete: 85% +SDComment: charge and dalliah death left to script +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "arcatraz.h" + +enum Say +{ + // boss_wrath_scryer_soccothrates + SAY_AGGRO = 1, + SAY_SLAY = 2, + SAY_KNOCK_AWAY = 3, + SAY_DEATH = 4, + SAY_DALLIAH_DEATH = 6, // To be scripted + SAY_SOCCOTHRATES_CONVO_1 = 7, + SAY_SOCCOTHRATES_CONVO_2 = 8, + SAY_SOCCOTHRATES_CONVO_3 = 9, + SAY_SOCCOTHRATES_CONVO_4 = 10, + + // boss_dalliah_the_doomsayer + SAY_AGGRO_SOCCOTHRATES_FIRST = 0, + SAY_SOCCOTHRATES_25_PERCENT = 6, + SAY_DALLIAH_CONVO_1 = 8, + SAY_DALLIAH_CONVO_2 = 9, + SAY_DALLIAH_CONVO_3 = 10 +}; + +enum Spells +{ + SPELL_FEL_IMMOLATION = 36051, + SPELL_FELFIRE_SHOCK = 35759, + SPELL_KNOCK_AWAY = 36512, + SPELL_FELFIRE_LINE_UP = 35770, + SPELL_CHARGE_TARGETING = 36038, + SPELL_CHARGE = 35754 +}; + +enum Events +{ + EVENT_FELFIRE_SHOCK = 1, + EVENT_KNOCK_AWAY = 2, + + EVENT_PREFIGHT_1 = 3, + EVENT_PREFIGHT_2 = 4, + EVENT_PREFIGHT_3 = 5, + EVENT_PREFIGHT_4 = 6, + EVENT_PREFIGHT_5 = 7, + EVENT_PREFIGHT_6 = 8, + EVENT_PREFIGHT_7 = 9, + EVENT_PREFIGHT_8 = 10, + EVENT_PREFIGHT_9 = 11, + EVENT_ME_FIRST = 12, +}; + +class boss_wrath_scryer_soccothrates : public CreatureScript +{ + public: + boss_wrath_scryer_soccothrates() : CreatureScript("boss_wrath_scryer_soccothrates") { } + + struct boss_wrath_scryer_soccothratesAI : public BossAI + { + boss_wrath_scryer_soccothratesAI(Creature* creature) : BossAI(creature, DATA_SOCCOTHRATES) { } + + void Reset() OVERRIDE + { + _Reset(); + preFight = false; + dalliahTaunt = false; + DoCast(me, SPELL_FEL_IMMOLATION); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + Talk(SAY_DEATH); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.ScheduleEvent(EVENT_FELFIRE_SHOCK, urand(12000, 14000)); + events.ScheduleEvent(EVENT_KNOCK_AWAY, urand(11000, 12000)); + events.ScheduleEvent(EVENT_ME_FIRST, 6000); + Talk(SAY_AGGRO); + preFight = false; + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE + { + Talk(SAY_SLAY); + } + + void MoveInLineOfSight(Unit* who) OVERRIDE + { + if (instance) + { + if (instance->GetData(DATA_CONVERSATION) == NOT_STARTED && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 70.0f)) + { + Talk(SAY_SOCCOTHRATES_CONVO_1); + instance->SetData(DATA_CONVERSATION, DONE); + + if (Creature* dalliah = me->FindNearestCreature(NPC_DALLIAH, 50.0f, true)) + { + dalliahGUID = dalliah->GetGUID(); + preFight = true; + events.ScheduleEvent(EVENT_PREFIGHT_1, 2000); + } + } + } + } + + void UpdateAI(uint32 diff) OVERRIDE + { + if (!UpdateVictim()) + { + if (preFight) + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_PREFIGHT_1: + if (Creature* dalliah = me->GetCreature(*me, dalliahGUID)) + dalliah->AI()->Talk(SAY_DALLIAH_CONVO_1); + events.ScheduleEvent(EVENT_PREFIGHT_2, 3000); + break; + case EVENT_PREFIGHT_2: + Talk(SAY_SOCCOTHRATES_CONVO_2); + events.ScheduleEvent(EVENT_PREFIGHT_3, 3000); + break; + case EVENT_PREFIGHT_3: + if (Creature* dalliah = me->GetCreature(*me, dalliahGUID)) + dalliah->AI()->Talk(SAY_DALLIAH_CONVO_2); + events.ScheduleEvent(EVENT_PREFIGHT_4, 6000); + break; + case EVENT_PREFIGHT_4: + Talk(SAY_SOCCOTHRATES_CONVO_3); + events.ScheduleEvent(EVENT_PREFIGHT_5, 2000); + break; + case EVENT_PREFIGHT_5: + if (Creature* dalliah = me->GetCreature(*me, dalliahGUID)) + dalliah->AI()->Talk(SAY_DALLIAH_CONVO_3); + events.ScheduleEvent(EVENT_PREFIGHT_6, 3000); + break; + case EVENT_PREFIGHT_6: + Talk(SAY_SOCCOTHRATES_CONVO_4); + events.ScheduleEvent(EVENT_PREFIGHT_7, 2000); + break; + case EVENT_PREFIGHT_7: + if (Creature* dalliah = me->GetCreature(*me, dalliahGUID)) + dalliah->GetMotionMaster()->MovePoint(0, 118.6048f, 96.84852f, 22.44115f); + events.ScheduleEvent(EVENT_PREFIGHT_8, 4000); + break; + case EVENT_PREFIGHT_8: + me->GetMotionMaster()->MovePoint(0, 122.1035f, 192.7203f, 22.44115f); + events.ScheduleEvent(EVENT_PREFIGHT_9, 4000); + break; + case EVENT_PREFIGHT_9: + if (Creature* dalliah = me->GetCreature(*me, dalliahGUID)) + { + dalliah->SetFacingToObject(me); + me->SetFacingToObject(dalliah); + dalliah->SetHomePosition(dalliah->GetPositionX(), dalliah->GetPositionY(), dalliah->GetPositionZ(), 1.51737f); + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 4.725722f); + preFight = false; + } + break; + default: + break; + } + } + } + + return; + } + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FELFIRE_SHOCK: + DoCastVictim(SPELL_FELFIRE_SHOCK, true); + events.ScheduleEvent(EVENT_FELFIRE_SHOCK, urand(12000, 14000)); + break; + case EVENT_KNOCK_AWAY: + DoCast(me, SPELL_KNOCK_AWAY); + Talk(SAY_KNOCK_AWAY); + events.ScheduleEvent(EVENT_KNOCK_AWAY, urand(11000, 12000)); + break; + case EVENT_ME_FIRST: + if (Creature* dalliah = me->GetCreature(*me, dalliahGUID)) + if (dalliah->IsAlive() && !dalliah->IsInCombat()) + dalliah->AI()->Talk(SAY_AGGRO_SOCCOTHRATES_FIRST); + break; + default: + break; + } + } + + if (HealthBelowPct(25) && !dalliahTaunt) + { + if (Creature* dalliah = me->GetCreature(*me, dalliahGUID)) + dalliah->AI()->Talk(SAY_SOCCOTHRATES_25_PERCENT); + dalliahTaunt = true; + } + + DoMeleeAttackIfReady(); + } + + private: + bool preFight; + bool dalliahTaunt; + uint64 dalliahGUID; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_wrath_scryer_soccothratesAI(creature); + } +}; + +void AddSC_boss_wrath_scryer_soccothrates() +{ + new boss_wrath_scryer_soccothrates(); +} diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_zereketh_the_unbound.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_zereketh_the_unbound.cpp new file mode 100644 index 00000000000..062c88bb666 --- /dev/null +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_zereketh_the_unbound.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2008-2013 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 . + */ + +/* ScriptData +SDName: boss_zereketh_the_unbound +SD%Complete: 100% +SDComment: +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "arcatraz.h" + +enum Say +{ + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_SHADOW_NOVA = 2, + SAY_DEATH = 3 +}; + +enum Spells +{ + SPELL_VOID_ZONE = 36119, + SPELL_SHADOW_NOVA = 36127, + SPELL_SEED_OF_CORRUPTION = 36123 +}; + +enum Events +{ + EVENT_VOID_ZONE = 1, + EVENT_SHADOW_NOVA = 2, + EVENT_SEED_OF_CORRUPTION = 3 +}; + +class boss_zereketh_the_unbound : public CreatureScript +{ + public: + boss_zereketh_the_unbound() : CreatureScript("boss_zereketh_the_unbound") { } + + struct boss_zereketh_the_unboundAI : public BossAI + { + boss_zereketh_the_unboundAI(Creature* creature) : BossAI(creature, DATA_ZEREKETH) { } + + void Reset() OVERRIDE + { + _Reset(); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + Talk(SAY_DEATH); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.ScheduleEvent(EVENT_VOID_ZONE, urand (6000, 10000)); + events.ScheduleEvent(EVENT_SHADOW_NOVA, urand (6000, 10000)); + events.ScheduleEvent(EVENT_SEED_OF_CORRUPTION, urand(12000, 20000)); + Talk(SAY_AGGRO); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE + { + Talk(SAY_SLAY); + } + + 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_VOID_ZONE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true)) + DoCast(target, SPELL_VOID_ZONE); + events.ScheduleEvent(EVENT_VOID_ZONE, urand (6000, 10000)); + break; + case EVENT_SHADOW_NOVA: + DoCastVictim(SPELL_SHADOW_NOVA, true); + Talk(SAY_SHADOW_NOVA); + events.ScheduleEvent(EVENT_SHADOW_NOVA, urand (6000, 10000)); + break; + case EVENT_SEED_OF_CORRUPTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true)) + DoCast(target, SPELL_SEED_OF_CORRUPTION); + events.ScheduleEvent(EVENT_SEED_OF_CORRUPTION, urand(12000, 20000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_zereketh_the_unboundAI(creature); + } +}; + +void AddSC_boss_zereketh_the_unbound() +{ + new boss_zereketh_the_unbound(); +} diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/instance_arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/instance_arcatraz.cpp index e836c5c4bf9..43f4a98c8cf 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/instance_arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/instance_arcatraz.cpp @@ -27,23 +27,6 @@ EndScriptData */ #include "InstanceScript.h" #include "arcatraz.h" -#define MAX_ENCOUNTER 9 - -enum Units -{ - CONTAINMENT_CORE_SECURITY_FIELD_ALPHA = 184318, //door opened when Wrath-Scryer Soccothrates dies - CONTAINMENT_CORE_SECURITY_FIELD_BETA = 184319, //door opened when Dalliah the Doomsayer dies - POD_ALPHA = 183961, //pod first boss wave - POD_BETA = 183963, //pod second boss wave - POD_DELTA = 183964, //pod third boss wave - POD_GAMMA = 183962, //pod fourth boss wave - POD_OMEGA = 183965, //pod fifth boss wave - WARDENS_SHIELD = 184802, // warden shield - SEAL_SPHERE = 184802, //shield 'protecting' mellichar - - MELLICHAR = 20904, //skyriss will kill this unit -}; - /* Arcatraz encounters: 1 - Zereketh the Unbound event 2 - Dalliah the Doomsayer event @@ -55,14 +38,14 @@ class instance_arcatraz : public InstanceMapScript { public: instance_arcatraz() - : InstanceMapScript("instance_arcatraz", 552) + : InstanceMapScript(AScriptName, 552) { } struct instance_arcatraz_InstanceMapScript : public InstanceScript { instance_arcatraz_InstanceMapScript(Map* map) : InstanceScript(map) { } - uint32 m_auiEncounter[MAX_ENCOUNTER]; + uint32 m_auiEncounter[EncounterCount]; uint64 Containment_Core_Security_Field_AlphaGUID; uint64 Containment_Core_Security_Field_BetaGUID; @@ -93,7 +76,7 @@ class instance_arcatraz : public InstanceMapScript bool IsEncounterInProgress() const OVERRIDE { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < EncounterCount; ++i) if (m_auiEncounter[i] == IN_PROGRESS) return true; @@ -144,7 +127,7 @@ class instance_arcatraz : public InstanceMapScript void OnCreatureCreate(Creature* creature) OVERRIDE { - if (creature->GetEntry() == MELLICHAR) + if (creature->GetEntry() == NPC_MELLICHAR) MellicharGUID = creature->GetGUID(); } @@ -152,10 +135,10 @@ class instance_arcatraz : public InstanceMapScript { switch (type) { - case TYPE_ZEREKETH: + case DATA_ZEREKETH: m_auiEncounter[0] = data; break; - case TYPE_DALLIAH: + case DATA_DALLIAH: if (data == DONE) { if (GameObject* go = instance->GetGameObject(Containment_Core_Security_Field_BetaGUID)) @@ -163,7 +146,7 @@ class instance_arcatraz : public InstanceMapScript } m_auiEncounter[1] = data; break; - case TYPE_SOCCOTHRATES: + case DATA_SOCCOTHRATES: if (data == DONE) { if (GameObject* go = instance->GetGameObject(Containment_Core_Security_Field_AlphaGUID)) @@ -171,7 +154,7 @@ class instance_arcatraz : public InstanceMapScript } m_auiEncounter[2] = data; break; - case TYPE_HARBINGERSKYRISS: + case DATA_HARBINGERSKYRISS: if (data == NOT_STARTED || data == FAIL) { m_auiEncounter[4] = NOT_STARTED; @@ -182,13 +165,13 @@ class instance_arcatraz : public InstanceMapScript } m_auiEncounter[3] = data; break; - case TYPE_WARDEN_1: + case DATA_WARDEN_1: if (data == IN_PROGRESS) if (GameObject* go = instance->GetGameObject(Pod_AlphaGUID)) go->UseDoorOrButton(); m_auiEncounter[4] = data; break; - case TYPE_WARDEN_2: + case DATA_WARDEN_2: if (data == IN_PROGRESS) { if (GameObject* go = instance->GetGameObject(Pod_BetaGUID)) @@ -196,7 +179,7 @@ class instance_arcatraz : public InstanceMapScript } m_auiEncounter[5] = data; break; - case TYPE_WARDEN_3: + case DATA_WARDEN_3: if (data == IN_PROGRESS) { if (GameObject* go = instance->GetGameObject(Pod_DeltaGUID)) @@ -204,7 +187,7 @@ class instance_arcatraz : public InstanceMapScript } m_auiEncounter[6] = data; break; - case TYPE_WARDEN_4: + case DATA_WARDEN_4: if (data == IN_PROGRESS) { if (GameObject* go = instance->GetGameObject(Pod_GammaGUID)) @@ -212,7 +195,7 @@ class instance_arcatraz : public InstanceMapScript } m_auiEncounter[7] = data; break; - case TYPE_WARDEN_5: + case DATA_WARDEN_5: if (data == IN_PROGRESS) { if (GameObject* go = instance->GetGameObject(Pod_OmegaGUID)) @@ -220,13 +203,16 @@ class instance_arcatraz : public InstanceMapScript } m_auiEncounter[8] = data; break; - case TYPE_SHIELD_OPEN: + case DATA_SHIELD_OPEN: if (data == IN_PROGRESS) { if (GameObject* go = instance->GetGameObject(Wardens_ShieldGUID)) go->UseDoorOrButton(); } break; + case DATA_CONVERSATION: + m_auiEncounter[12] = data; + break; } } @@ -234,12 +220,13 @@ class instance_arcatraz : public InstanceMapScript { switch (type) { - case TYPE_HARBINGERSKYRISS: return m_auiEncounter[3]; - case TYPE_WARDEN_1: return m_auiEncounter[4]; - case TYPE_WARDEN_2: return m_auiEncounter[5]; - case TYPE_WARDEN_3: return m_auiEncounter[6]; - case TYPE_WARDEN_4: return m_auiEncounter[7]; - case TYPE_WARDEN_5: return m_auiEncounter[8]; + case DATA_HARBINGERSKYRISS: return m_auiEncounter[3]; + case DATA_WARDEN_1: return m_auiEncounter[4]; + case DATA_WARDEN_2: return m_auiEncounter[5]; + case DATA_WARDEN_3: return m_auiEncounter[6]; + case DATA_WARDEN_4: return m_auiEncounter[7]; + case DATA_WARDEN_5: return m_auiEncounter[8]; + case DATA_CONVERSATION: return m_auiEncounter[12]; } return 0; } -- cgit v1.2.3 From 8332cee0522b9166bd73903b85a3220a84b57a5f Mon Sep 17 00:00:00 2001 From: Malcrom Date: Sun, 10 Nov 2013 10:53:43 -0330 Subject: Scripting/The Slave Pens: Moved boss_mennu_the_betrayer from EAI to CPP. --- sql/updates/world/2013_11_10_01_world_misc.sql | 3 + src/server/game/Scripting/ScriptLoader.cpp | 27 +++- src/server/scripts/Outland/CMakeLists.txt | 4 +- .../TheSlavePens/boss_mennu_the_betrayer.cpp | 143 +++++++++++++++++++++ .../TheSlavePens/instance_the_slave_pens.cpp | 3 +- .../TheSlavePens/the_slave_pens.h | 32 +++++ 6 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 sql/updates/world/2013_11_10_01_world_misc.sql create mode 100644 src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp create mode 100644 src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h (limited to 'src/server/game/Scripting/ScriptLoader.cpp') diff --git a/sql/updates/world/2013_11_10_01_world_misc.sql b/sql/updates/world/2013_11_10_01_world_misc.sql new file mode 100644 index 00000000000..72881a96924 --- /dev/null +++ b/sql/updates/world/2013_11_10_01_world_misc.sql @@ -0,0 +1,3 @@ +UPDATE `creature_template` SET `AIName` = '', `ScriptName`= 'boss_mennu_the_betrayer' WHERE entry=17991; +DELETE FROM creature_ai_scripts WHERE creature_id=17991; +DELETE FROM creature_ai_texts WHERE entry BETWEEN -98 AND -93; diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 779c9be6c0e..bc29d96d1b8 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -575,7 +575,8 @@ void AddSC_boss_grandmaster_vorpil(); void AddSC_boss_murmur(); void AddSC_instance_shadow_labyrinth(); -void AddSC_black_temple(); //Black Temple +//Black Temple +void AddSC_black_temple(); void AddSC_boss_illidan(); void AddSC_boss_shade_of_akama(); void AddSC_boss_supremus(); @@ -586,22 +587,33 @@ void AddSC_boss_teron_gorefiend(); void AddSC_boss_najentus(); void AddSC_boss_illidari_council(); void AddSC_instance_black_temple(); -void AddSC_boss_fathomlord_karathress(); //CR Serpent Shrine Cavern + +//Coilfang Reservoir - Serpent Shrine Cavern +void AddSC_boss_fathomlord_karathress(); void AddSC_boss_hydross_the_unstable(); void AddSC_boss_lady_vashj(); void AddSC_boss_leotheras_the_blind(); void AddSC_boss_morogrim_tidewalker(); void AddSC_instance_serpentshrine_cavern(); void AddSC_boss_the_lurker_below(); -void AddSC_boss_hydromancer_thespia(); //CR Steam Vault + +//Coilfang Reservoir - The Steam Vault +void AddSC_boss_hydromancer_thespia(); void AddSC_boss_mekgineer_steamrigger(); void AddSC_boss_warlord_kalithresh(); void AddSC_instance_steam_vault(); -void AddSC_instance_the_slave_pens(); //The Slave Pens -void AddSC_boss_hungarfen(); //CR Underbog -void AddSC_boss_the_black_stalker(); + +//Coilfang Reservoir - The Slave Pens +void AddSC_instance_the_slave_pens(); +void AddSC_boss_mennu_the_betrayer(); + +//Coilfang Reservoir - The Underbog void AddSC_instance_the_underbog(); -void AddSC_boss_gruul(); //Gruul's Lair +void AddSC_boss_hungarfen(); +void AddSC_boss_the_black_stalker(); + +//Gruul's Lair +void AddSC_boss_gruul(); void AddSC_boss_high_king_maulgar(); void AddSC_instance_gruuls_lair(); void AddSC_boss_broggok(); //HC Blood Furnace @@ -1122,6 +1134,7 @@ void AddOutlandScripts() AddSC_boss_warlord_kalithresh(); AddSC_instance_steam_vault(); AddSC_instance_the_slave_pens(); //The Slave Pens + AddSC_boss_mennu_the_betrayer(); AddSC_boss_hungarfen(); //CR Underbog AddSC_boss_the_black_stalker(); AddSC_instance_the_underbog(); diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index 45db8a80a26..e07424a77d2 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -43,9 +43,11 @@ set(scripts_STAT_SRCS Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp + Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h + Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp + Outland/CoilfangReservoir/TheUnderbog/instance_the_underbog.cpp Outland/CoilfangReservoir/TheUnderbog/boss_hungarfen.cpp Outland/CoilfangReservoir/TheUnderbog/boss_the_black_stalker.cpp - Outland/CoilfangReservoir/TheUnderbog/instance_the_underbog.cpp Outland/zone_shattrath_city.cpp Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp new file mode 100644 index 00000000000..d015919d978 --- /dev/null +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2008-2013 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 . + */ + +/* ScriptData +SDName: boss_mennu_the_betrayer +SD%Complete: 100% +SDComment: +SDCategory: Coilfang Reservoir, The Slave Pens +EndScriptData */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "the_slave_pens.h" + +enum Say +{ + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_DEATH = 2 +}; + +enum Spells +{ + SPELL_TAINTED_STONESKIN_TOTEM = 31985, + SPELL_TAINTED_EARTHGRAB_TOTEM = 31981, + SPELL_CORRUPTED_NOVA_TOTEM = 31991, + SPELL_MENNUS_HEALING_WARD = 34980, + SPELL_LIGHTNING_BOLT = 35010 +}; + +enum Events +{ + EVENT_TAINTED_STONESKIN_TOTEM = 1, + EVENT_TAINTED_EARTHGRAB_TOTEM = 2, + EVENT_CORRUPTED_NOVA_TOTEM = 3, + EVENT_LIGHTNING_BOLT = 4 +}; + +class boss_mennu_the_betrayer : public CreatureScript +{ + public: + boss_mennu_the_betrayer() : CreatureScript("boss_mennu_the_betrayer") { } + + struct boss_mennu_the_betrayerAI : public BossAI + { + boss_mennu_the_betrayerAI(Creature* creature) : BossAI(creature, DATA_MENNU_THE_BETRAYER) { } + + void Reset() OVERRIDE + { + _Reset(); + healingWardDropped = false; + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + Talk(SAY_DEATH); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.ScheduleEvent(EVENT_TAINTED_STONESKIN_TOTEM, 18000); + events.ScheduleEvent(EVENT_TAINTED_EARTHGRAB_TOTEM, 19000); + events.ScheduleEvent(EVENT_CORRUPTED_NOVA_TOTEM, 20000); + events.ScheduleEvent(EVENT_LIGHTNING_BOLT, urand(5000, 8000)); + Talk(SAY_AGGRO); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE + { + Talk(SAY_SLAY); + } + + 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_TAINTED_STONESKIN_TOTEM: + DoCast(me, SPELL_TAINTED_STONESKIN_TOTEM); + break; + case EVENT_TAINTED_EARTHGRAB_TOTEM: + DoCast(me, SPELL_TAINTED_EARTHGRAB_TOTEM); + break; + case EVENT_CORRUPTED_NOVA_TOTEM: + DoCast(me, SPELL_CORRUPTED_NOVA_TOTEM); + break; + case EVENT_LIGHTNING_BOLT: + DoCastVictim(SPELL_LIGHTNING_BOLT, true); + events.ScheduleEvent(EVENT_LIGHTNING_BOLT, urand(7000, 11000)); + break; + default: + break; + } + } + + if (HealthBelowPct(60) && !healingWardDropped) + { + DoCast(me, SPELL_MENNUS_HEALING_WARD); + healingWardDropped = true; + } + + DoMeleeAttackIfReady(); + } + + private: + bool healingWardDropped; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_mennu_the_betrayerAI(creature); + } +}; + +void AddSC_boss_mennu_the_betrayer() +{ + new boss_mennu_the_betrayer(); +} diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp index cd11e2e1bf1..1c31bee7d4f 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp @@ -24,11 +24,12 @@ gets instead the deserter debuff. #include "ScriptMgr.h" #include "InstanceScript.h" +#include "the_slave_pens.h" class instance_the_slave_pens : public InstanceMapScript { public: - instance_the_slave_pens() : InstanceMapScript("instance_the_slave_pens", 547) { } + instance_the_slave_pens() : InstanceMapScript(SPScriptName, 547) { } InstanceScript* GetInstanceScript(InstanceMap* map) const OVERRIDE { diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h new file mode 100644 index 00000000000..624ead7ef08 --- /dev/null +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008-2013 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 . + */ + +#ifndef SLAVE_PENS_H +#define SLAVE_PENS_H + +uint32 const EncounterCount = 3; + +#define SPScriptName "instance_the_slave_pens" + +enum DataTypes +{ + DATA_MENNU_THE_BETRAYER = 1, + DATA_ROKMAR_THE_CRACKLER = 2, + DATA_QUAGMIRRAN = 3 +}; + +#endif // SLAVE_PENS_H -- cgit v1.2.3 From 113735690a06217a9648ddd6c8de2aa932c89db8 Mon Sep 17 00:00:00 2001 From: Malcrom Date: Sun, 10 Nov 2013 18:00:15 -0330 Subject: Scripts/The Slave Pens: Fix up Mennu the Betrayer and add Rokmar the Cracker & Quagmirran. --- sql/updates/world/2013_11_10_02_world_misc.sql | 13 +++ src/server/game/Scripting/ScriptLoader.cpp | 43 ++++--- src/server/scripts/Outland/CMakeLists.txt | 2 + .../TheSlavePens/boss_mennu_the_betrayer.cpp | 44 ++++--- .../TheSlavePens/boss_quagmirran.cpp | 124 ++++++++++++++++++++ .../TheSlavePens/boss_rokmar_the_crackler.cpp | 127 +++++++++++++++++++++ 6 files changed, 316 insertions(+), 37 deletions(-) create mode 100644 sql/updates/world/2013_11_10_02_world_misc.sql create mode 100644 src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_quagmirran.cpp create mode 100644 src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_rokmar_the_crackler.cpp (limited to 'src/server/game/Scripting/ScriptLoader.cpp') diff --git a/sql/updates/world/2013_11_10_02_world_misc.sql b/sql/updates/world/2013_11_10_02_world_misc.sql new file mode 100644 index 00000000000..6049724f6d3 --- /dev/null +++ b/sql/updates/world/2013_11_10_02_world_misc.sql @@ -0,0 +1,13 @@ +UPDATE `creature_template` SET `AIName` = '', `ScriptName`= 'boss_rokmar_the_crackler' WHERE entry=17991; +DELETE FROM creature_ai_scripts WHERE creature_id=17991; +UPDATE `creature_template` SET `AIName` = '', `ScriptName`= 'boss_mennu_the_betrayer' WHERE entry=17941; +DELETE FROM creature_ai_scripts WHERE creature_id=17941; +DELETE FROM creature_ai_texts WHERE entry BETWEEN -98 AND -93; +UPDATE `creature_template` SET `AIName` = '', `ScriptName`= 'boss_quagmirran' WHERE entry=17942; +DELETE FROM creature_ai_scripts WHERE creature_id=17942; + +-- Add missing spelldifficulty_dbc values +DELETE FROM `spelldifficulty_dbc` WHERE `id` IN (31956,34780); +INSERT INTO `spelldifficulty_dbc` (`id`,`spellid0`,`spellid1`) VALUES +(31956,31956,39005), -- Rokmar the Crackler +(34780,34780,39340); -- Quagmirran diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index bc29d96d1b8..28fe883feb9 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -575,7 +575,7 @@ void AddSC_boss_grandmaster_vorpil(); void AddSC_boss_murmur(); void AddSC_instance_shadow_labyrinth(); -//Black Temple +// Black Temple void AddSC_black_temple(); void AddSC_boss_illidan(); void AddSC_boss_shade_of_akama(); @@ -588,7 +588,7 @@ void AddSC_boss_najentus(); void AddSC_boss_illidari_council(); void AddSC_instance_black_temple(); -//Coilfang Reservoir - Serpent Shrine Cavern +// Coilfang Reservoir - Serpent Shrine Cavern void AddSC_boss_fathomlord_karathress(); void AddSC_boss_hydross_the_unstable(); void AddSC_boss_lady_vashj(); @@ -597,22 +597,24 @@ void AddSC_boss_morogrim_tidewalker(); void AddSC_instance_serpentshrine_cavern(); void AddSC_boss_the_lurker_below(); -//Coilfang Reservoir - The Steam Vault +// Coilfang Reservoir - The Steam Vault void AddSC_boss_hydromancer_thespia(); void AddSC_boss_mekgineer_steamrigger(); void AddSC_boss_warlord_kalithresh(); void AddSC_instance_steam_vault(); -//Coilfang Reservoir - The Slave Pens +// Coilfang Reservoir - The Slave Pens void AddSC_instance_the_slave_pens(); void AddSC_boss_mennu_the_betrayer(); +void AddSC_boss_rokmar_the_crackler(); +void AddSC_boss_quagmirran(); -//Coilfang Reservoir - The Underbog +// Coilfang Reservoir - The Underbog void AddSC_instance_the_underbog(); void AddSC_boss_hungarfen(); void AddSC_boss_the_black_stalker(); -//Gruul's Lair +// Gruul's Lair void AddSC_boss_gruul(); void AddSC_boss_high_king_maulgar(); void AddSC_instance_gruuls_lair(); @@ -1111,7 +1113,8 @@ void AddOutlandScripts() AddSC_boss_murmur(); AddSC_instance_shadow_labyrinth(); - AddSC_black_temple(); //Black Temple + // Black Temple + AddSC_black_temple(); AddSC_boss_illidan(); AddSC_boss_shade_of_akama(); AddSC_boss_supremus(); @@ -1122,23 +1125,35 @@ void AddOutlandScripts() AddSC_boss_najentus(); AddSC_boss_illidari_council(); AddSC_instance_black_temple(); - AddSC_boss_fathomlord_karathress(); //CR Serpent Shrine Cavern + + // Coilfang Reservoir - Serpent Shrine Cavern + AddSC_boss_fathomlord_karathress(); AddSC_boss_hydross_the_unstable(); AddSC_boss_lady_vashj(); AddSC_boss_leotheras_the_blind(); AddSC_boss_morogrim_tidewalker(); AddSC_instance_serpentshrine_cavern(); AddSC_boss_the_lurker_below(); - AddSC_boss_hydromancer_thespia(); //CR Steam Vault + + // Coilfang Reservoir - The Steam Vault + AddSC_instance_steam_vault(); + AddSC_boss_hydromancer_thespia(); AddSC_boss_mekgineer_steamrigger(); AddSC_boss_warlord_kalithresh(); - AddSC_instance_steam_vault(); - AddSC_instance_the_slave_pens(); //The Slave Pens + + // Coilfang Reservoir - The Slave Pens + AddSC_instance_the_slave_pens(); AddSC_boss_mennu_the_betrayer(); - AddSC_boss_hungarfen(); //CR Underbog - AddSC_boss_the_black_stalker(); + AddSC_boss_rokmar_the_crackler(); + AddSC_boss_quagmirran(); + + // Coilfang Reservoir - The Underbog AddSC_instance_the_underbog(); - AddSC_boss_gruul(); //Gruul's Lair + AddSC_boss_hungarfen(); + AddSC_boss_the_black_stalker(); + + // Gruul's Lair + AddSC_boss_gruul(); AddSC_boss_high_king_maulgar(); AddSC_instance_gruuls_lair(); AddSC_boss_broggok(); //HC Blood Furnace diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index e07424a77d2..ab10ee2dfe4 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -45,6 +45,8 @@ set(scripts_STAT_SRCS Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp + Outland/CoilfangReservoir/TheSlavePens/boss_rokmar_the_crackler.cpp + Outland/CoilfangReservoir/TheSlavePens/boss_quagmirran.cpp Outland/CoilfangReservoir/TheUnderbog/instance_the_underbog.cpp Outland/CoilfangReservoir/TheUnderbog/boss_hungarfen.cpp Outland/CoilfangReservoir/TheUnderbog/boss_the_black_stalker.cpp diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp index d015919d978..ba59aa3b463 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp @@ -17,7 +17,7 @@ /* ScriptData SDName: boss_mennu_the_betrayer -SD%Complete: 100% +SD%Complete: 95% SDComment: SDCategory: Coilfang Reservoir, The Slave Pens EndScriptData */ @@ -35,11 +35,11 @@ enum Say enum Spells { - SPELL_TAINTED_STONESKIN_TOTEM = 31985, - SPELL_TAINTED_EARTHGRAB_TOTEM = 31981, - SPELL_CORRUPTED_NOVA_TOTEM = 31991, - SPELL_MENNUS_HEALING_WARD = 34980, - SPELL_LIGHTNING_BOLT = 35010 + SPELL_TAINTED_STONESKIN_TOTEM = 31985, // every 30 sec if health below 100% + SPELL_TAINTED_EARTHGRAB_TOTEM = 31981, // ? + SPELL_CORRUPTED_NOVA_TOTEM = 31991, // ? + SPELL_MENNUS_HEALING_WARD = 34980, // every 14 - 25 sec + SPELL_LIGHTNING_BOLT = 35010 // every 14 - 19 sec }; enum Events @@ -47,7 +47,8 @@ enum Events EVENT_TAINTED_STONESKIN_TOTEM = 1, EVENT_TAINTED_EARTHGRAB_TOTEM = 2, EVENT_CORRUPTED_NOVA_TOTEM = 3, - EVENT_LIGHTNING_BOLT = 4 + EVENT_MENNUS_HEALING_WARD = 4, + EVENT_LIGHTNING_BOLT = 5 }; class boss_mennu_the_betrayer : public CreatureScript @@ -62,7 +63,6 @@ class boss_mennu_the_betrayer : public CreatureScript void Reset() OVERRIDE { _Reset(); - healingWardDropped = false; } void JustDied(Unit* /*killer*/) OVERRIDE @@ -74,10 +74,11 @@ class boss_mennu_the_betrayer : public CreatureScript void EnterCombat(Unit* /*who*/) OVERRIDE { _EnterCombat(); - events.ScheduleEvent(EVENT_TAINTED_STONESKIN_TOTEM, 18000); - events.ScheduleEvent(EVENT_TAINTED_EARTHGRAB_TOTEM, 19000); - events.ScheduleEvent(EVENT_CORRUPTED_NOVA_TOTEM, 20000); - events.ScheduleEvent(EVENT_LIGHTNING_BOLT, urand(5000, 8000)); + events.ScheduleEvent(EVENT_TAINTED_STONESKIN_TOTEM, 30000); + events.ScheduleEvent(EVENT_TAINTED_EARTHGRAB_TOTEM, 20000); + events.ScheduleEvent(EVENT_CORRUPTED_NOVA_TOTEM, 60000); + events.ScheduleEvent(EVENT_MENNUS_HEALING_WARD, urand(14000, 25000)); + events.ScheduleEvent(EVENT_LIGHTNING_BOLT, urand(14000, 19000)); Talk(SAY_AGGRO); } @@ -101,7 +102,9 @@ class boss_mennu_the_betrayer : public CreatureScript switch (eventId) { case EVENT_TAINTED_STONESKIN_TOTEM: - DoCast(me, SPELL_TAINTED_STONESKIN_TOTEM); + if (HealthBelowPct(100)) + DoCast(me, SPELL_TAINTED_STONESKIN_TOTEM); + events.ScheduleEvent(EVENT_TAINTED_STONESKIN_TOTEM, 30000); break; case EVENT_TAINTED_EARTHGRAB_TOTEM: DoCast(me, SPELL_TAINTED_EARTHGRAB_TOTEM); @@ -109,26 +112,21 @@ class boss_mennu_the_betrayer : public CreatureScript case EVENT_CORRUPTED_NOVA_TOTEM: DoCast(me, SPELL_CORRUPTED_NOVA_TOTEM); break; + case EVENT_MENNUS_HEALING_WARD: + DoCast(me, SPELL_MENNUS_HEALING_WARD); + events.ScheduleEvent(EVENT_MENNUS_HEALING_WARD, urand(14000, 25000)); + break; case EVENT_LIGHTNING_BOLT: DoCastVictim(SPELL_LIGHTNING_BOLT, true); - events.ScheduleEvent(EVENT_LIGHTNING_BOLT, urand(7000, 11000)); + events.ScheduleEvent(EVENT_LIGHTNING_BOLT, urand(14000, 25000)); break; default: break; } } - if (HealthBelowPct(60) && !healingWardDropped) - { - DoCast(me, SPELL_MENNUS_HEALING_WARD); - healingWardDropped = true; - } - DoMeleeAttackIfReady(); } - - private: - bool healingWardDropped; }; CreatureAI* GetAI(Creature* creature) const OVERRIDE diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_quagmirran.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_quagmirran.cpp new file mode 100644 index 00000000000..6cef7291542 --- /dev/null +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_quagmirran.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008-2013 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 . + */ + +/* ScriptData +SDName: boss_quagmirran +SD%Complete: 100% +SDComment: +SDCategory: Coilfang Reservoir, The Slave Pens +EndScriptData */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "the_slave_pens.h" + +enum Spells +{ + SPELL_ACID_SPRAY = 38153, + SPELL_CLEAVE = 40504, + SPELL_UPPERCUT = 32055, + SPELL_POISON_BOLT_VOLLEY = 34780 // 39340 +}; + +enum Events +{ + EVENT_ACID_SPRAY = 1, + EVENT_CLEAVE = 2, + EVENT_UPPERCUT = 3, + EVENT_POISON_BOLT_VOLLEY = 4 +}; + +class boss_quagmirran : public CreatureScript +{ + public: + boss_quagmirran() : CreatureScript("boss_quagmirran") { } + + struct boss_quagmirranAI : public BossAI + { + boss_quagmirranAI(Creature* creature) : BossAI(creature, DATA_QUAGMIRRAN) { } + + void Reset() OVERRIDE + { + _Reset(); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.ScheduleEvent(EVENT_ACID_SPRAY, 25000); + events.ScheduleEvent(EVENT_CLEAVE, 9000); + events.ScheduleEvent(EVENT_UPPERCUT, 20000); + events.ScheduleEvent(EVENT_POISON_BOLT_VOLLEY, 31000); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE { } + + 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_ACID_SPRAY: + DoCastAOE(SPELL_ACID_SPRAY); + events.ScheduleEvent(EVENT_ACID_SPRAY, urand(20000, 25000)); + break; + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE, true); + events.ScheduleEvent(EVENT_CLEAVE, urand(18000, 34000)); + break; + case EVENT_UPPERCUT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 10.0f, true)) + DoCast(target, SPELL_UPPERCUT); + events.ScheduleEvent(EVENT_UPPERCUT, 22000); + break; + case EVENT_POISON_BOLT_VOLLEY: + DoCast(me, SPELL_POISON_BOLT_VOLLEY); + events.ScheduleEvent(EVENT_POISON_BOLT_VOLLEY, 24000); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_quagmirranAI(creature); + } +}; + +void AddSC_boss_quagmirran() +{ + new boss_quagmirran(); +} diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_rokmar_the_crackler.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_rokmar_the_crackler.cpp new file mode 100644 index 00000000000..a025df5c3ae --- /dev/null +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_rokmar_the_crackler.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2008-2013 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 . + */ + +/* ScriptData +SDName: boss_rokmar_the_crackler +SD%Complete: 100% +SDComment: +SDCategory: Coilfang Reservoir, The Slave Pens +EndScriptData */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "the_slave_pens.h" + +enum Spells +{ + SPELL_GRIEVOUS_WOUND = 31956, + SPELL_ENSNARING_MOSS = 31948, + SPELL_WATER_SPIT = 35008, + SPELL_FRENZY = 34970 +}; + +enum Events +{ + EVENT_GRIEVOUS_WOUND = 1, + EVENT_ENSNARING_MOSS = 2, + EVENT_WATER_SPIT = 3 +}; + +class boss_rokmar_the_crackler : public CreatureScript +{ + public: + boss_rokmar_the_crackler() : CreatureScript("boss_rokmar_the_crackler") { } + + struct boss_rokmar_the_cracklerAI : public BossAI + { + boss_rokmar_the_cracklerAI(Creature* creature) : BossAI(creature, DATA_MENNU_THE_BETRAYER) { } + + void Reset() OVERRIDE + { + _Reset(); + rokmarFrenzy = false; + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.ScheduleEvent(EVENT_GRIEVOUS_WOUND, 10000); + events.ScheduleEvent(EVENT_ENSNARING_MOSS, 20000); + events.ScheduleEvent(EVENT_WATER_SPIT, 14000); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE { } + + 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_GRIEVOUS_WOUND: + DoCastVictim(SPELL_GRIEVOUS_WOUND, true); + events.ScheduleEvent(EVENT_GRIEVOUS_WOUND, urand(20000, 30000)); + break; + case EVENT_ENSNARING_MOSS: + DoCastAOE(SPELL_ENSNARING_MOSS); + events.ScheduleEvent(EVENT_ENSNARING_MOSS, urand(20000, 30000)); + break; + case EVENT_WATER_SPIT: + DoCastAOE(SPELL_WATER_SPIT); + events.ScheduleEvent(EVENT_WATER_SPIT, urand(14000, 18000)); + break; + default: + break; + } + } + + if (HealthBelowPct(10) && !rokmarFrenzy) + { + DoCast(me, SPELL_FRENZY); + rokmarFrenzy = true; + } + + DoMeleeAttackIfReady(); + } + + private: + bool rokmarFrenzy; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_rokmar_the_cracklerAI(creature); + } +}; + +void AddSC_boss_rokmar_the_crackler() +{ + new boss_rokmar_the_crackler(); +} -- cgit v1.2.3 From 89de7e74198e517dc7105f73af0f1d74c3629c64 Mon Sep 17 00:00:00 2001 From: Malcrom Date: Sat, 7 Dec 2013 21:19:46 -0330 Subject: Scripting/Razorfen Downs: Additions and fixes for instance. Moved bosses Glutton, Mordresh Fire Eye, Tuten Kash to cpp. Cleaned up code for boss Amnennar The Coldbringer. Fixed up gong event for gong to have sound and proper spawning. Scripted quest 3525 "Extinguishing the Idol" so you can now fight Plagmaw the Rotting. --- sql/updates/world/2013_12_07_00_world_misc.sql | 77 +++++ src/server/game/Scripting/ScriptLoader.cpp | 10 +- src/server/scripts/Kalimdor/CMakeLists.txt | 5 +- .../boss_amnennar_the_coldbringer.cpp | 115 +++---- .../Kalimdor/RazorfenDowns/boss_glutton.cpp | 95 ++++++ .../RazorfenDowns/boss_mordresh_fire_eye.cpp | 136 ++++++++ .../Kalimdor/RazorfenDowns/boss_tuten_kash.cpp | 107 +++++++ .../RazorfenDowns/instance_razorfen_downs.cpp | 270 ++++++++-------- .../Kalimdor/RazorfenDowns/razorfen_downs.cpp | 345 +++++++++++++++++++-- .../Kalimdor/RazorfenDowns/razorfen_downs.h | 51 ++- 10 files changed, 988 insertions(+), 223 deletions(-) create mode 100644 sql/updates/world/2013_12_07_00_world_misc.sql create mode 100644 src/server/scripts/Kalimdor/RazorfenDowns/boss_glutton.cpp create mode 100644 src/server/scripts/Kalimdor/RazorfenDowns/boss_mordresh_fire_eye.cpp create mode 100644 src/server/scripts/Kalimdor/RazorfenDowns/boss_tuten_kash.cpp (limited to 'src/server/game/Scripting/ScriptLoader.cpp') diff --git a/sql/updates/world/2013_12_07_00_world_misc.sql b/sql/updates/world/2013_12_07_00_world_misc.sql new file mode 100644 index 00000000000..42063be2e3a --- /dev/null +++ b/sql/updates/world/2013_12_07_00_world_misc.sql @@ -0,0 +1,77 @@ +-- Talk text for Mordresh Fire Eye from sniff +SET @ENTRY := 7357; +DELETE FROM `creature_text` WHERE `entry`=@ENTRY; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(@ENTRY,0,0,'We will enslave the quilboar!',12,0,100,1,0,5819, 'Mordresh Fire Eye - SAY_OOC_1'), +(@ENTRY,1,0,'We will spread across this barren land!',12,0,100,1,0,5820, 'Mordresh Fire Eye - SAY_OOC_2'), +(@ENTRY,2,0,'Soon, the Scourge will rule the world!',12,0,100,22,0,5821, 'Mordresh Fire Eye - SAY_OOC_3'), +(@ENTRY,3,0,'Slay them, my brethren! For the Scourge!',14,0,100,0,0,5822, 'Mordresh Fire Eye - SAY_AGGRO'); + +-- Talk text for Belnistrasz from sniff +SET @ENTRY := 8516; +DELETE FROM `creature_text` WHERE `entry`=@ENTRY; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(@ENTRY,0,0,'All right, stay close. These fiends will jump right out of the shadows at you if you let your guard down.',12,0,100,0,0,0,'Belnistrasz SAY_QUEST_ACCEPTED'), +(@ENTRY,1,0,'Okay, here we go. It's going to take about five minutes to shut this thing down through the ritual. Once I start, keep the vermin off of me or it will be the end of us all!',12,0,100,0,0,0,'Belnistrasz SAY_EVENT_START'), +(@ENTRY,2,0,'Three minutes left -- I can feel the energy starting to build! Keep up the solid defense!',14,0,100,0,0,0,'Belnistrasz SAY_EVENT_THREE_MIN_LEFT'), +(@ENTRY,3,0,'Just two minutes to go! We're half way there, but don't let your guard down!',14,0,100,0,0,0,'Belnistrasz SAY_EVENT_TWO_MIN_LEFT'), +(@ENTRY,4,0,'One more minute! Hold on now, the ritual is about to take hold!',14,0,100,0,0,0,'Belnistrasz SAY_EVENT_ONE_MIN_LEFT'), +(@ENTRY,5,0,'That's it -- we made it! The ritual is set in motion, and idol fires are about to go out for good! You truly are the heroes I thought you would be!',14,0,100,4,0,0,'Belnistrasz SAY_EVENT_END'), +(@ENTRY,6,0,'You'll rue the day you crossed me, $N',12,0,100,0,0,0,'Belnistrasz SAY_AGGRO'); +(@ENTRY,7,0,'Watch out for the $N!',12,0,100,0,0,0,'Belnistrasz SAY_WATCH_OUT'); + +-- Fix trigger location +UPDATE `creature_template` SET `InhabitType`=4, `flags_extra`=`flags_extra`|128 WHERE `entry`=8662; + +-- Condition for spell Belnistrasz Idol Shutdown Visual +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=12774; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 1, 12774, 0, 0, 31, 0, 3, 8662, 0, 0, 0, 0, '', 'Belnistrasz Idol Shutdown Visual targets Idol Oven Fire Target'); + +-- Add cpp scripts +UPDATE creature_template SET `AIName`= '',ScriptName = 'boss_tuten_kash' WHERE entry=7355; +UPDATE creature_template SET `AIName`= '',ScriptName = 'boss_mordresh_fire_eye' WHERE entry=7357; +UPDATE creature_template SET `AIName`= '',ScriptName = 'boss_glutton' WHERE entry=8567; +UPDATE creature_template SET `AIName`= '',ScriptName = 'npc_belnistrasz' WHERE entry=8516; +UPDATE creature_template SET `AIName`= '',ScriptName = 'npc_idol_room_spawner' WHERE entry=8611; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (7355,7357,8567,8516) AND `source_type`=0; + +-- Pathing for Belnistrasz Entry: 8516 +SET @NPC := 87171; +SET @PATH := @NPC * 10; +DELETE FROM `creature_template_addon` WHERE `entry`=8516; +INSERT INTO `creature_template_addon` (`entry`,`path_id`,`bytes2`,`mount`,`auras`) VALUES (8516,@PATH,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,2603.313,724.335,54.608,0,0,1,0,100,0), +(@PATH,2,2593.379,726.272,55.112,0,0,1,0,100,0), +(@PATH,3,2588.499,733.1947,55.3959,0,0,1,0,100,0), +(@PATH,4,2572.573,752.5162,54.71815,0,0,1,0,100,0), +(@PATH,5,2558.068,748.3008,54.3559,0,0,1,0,100,0), +(@PATH,6,2539.677,777.1356,46.95155,0,0,1,0,100,0), +(@PATH,7,2527.828,800.8403,44.74713,0,0,1,0,100,0), +(@PATH,8,2495.996,785.7536,39.51203,0,0,1,0,100,0), +(@PATH,9,2484.358,814.8914,43.57789,0,0,1,0,100,0), +(@PATH,10,2501.128,847.9614,47.5574,0,0,1,0,100,0), +(@PATH,11,2537.36,874.4713,47.67798,0,0,1,0,100,0), +(@PATH,12,2548.493,894.6515,47.69307,0,0,1,0,100,0), +(@PATH,13,2541.478,910.5101,46.17223,0,0,1,0,100,0), +(@PATH,14,2519.403,925.6332,46.51501,0,0,1,0,100,0), +(@PATH,15,2527.237,951.4606,49.2807,0,0,1,0,100,0), +(@PATH,16,2541.675,976.5887,50.41221,0,0,1,0,100,0), +(@PATH,17,2554.084,973.8665,50.36161,0,0,1,0,100,0), +(@PATH,18,2575.601,950.1381,52.84592,0,0,1,0,100,0); + +DELETE FROM `creature_questender` WHERE `id`=8516 AND `quest`=3525; +DELETE FROM `gameobject_questender` WHERE `id`=152097 AND `quest`=3525; +INSERT INTO `gameobject_questender` (`id`,`quest`) VALUES (152097,3525); + +-- Death's Head Geomancer SAI +SET @ENTRY := 7335; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,0,0,100,2,0,0,3000,4000,11,9053,64,0,0,0,0,2,0,0,0,0,0,0,0,"Death's Head Geomancer - Combat - Cast Fireball (Normal Dungeon)"), +(@ENTRY,0,1,0,0,0,100,2,8000,10000,6000,15000,11,6725,0,0,0,0,0,5,0,0,0,0,0,0,0,"Death's Head Geomancer - Combat - Cast Flame Spike (Normal Dungeon)"), +(@ENTRY,0,2,0,0,0,100,2,12000,16000,8000,20000,11,11436,1,0,0,0,0,5,0,0,0,0,0,0,0,"Death's Head Geomancer - Combat - Cast Slow (Normal Dungeon)"), +(@ENTRY,0,3,0,2,0,100,3,0,15,0,0,25,1,0,0,0,0,0,0,0,0,0,0,0,0,0,"Death's Head Geomancer - 0-15% Health - Flee For Assist (Normal Dungeon)"); diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 28fe883feb9..b486eb45915 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -321,7 +321,10 @@ void AddSC_boss_ptheradras(); void AddSC_instance_maraudon(); void AddSC_boss_onyxia(); //Onyxia's Lair void AddSC_instance_onyxias_lair(); -void AddSC_boss_amnennar_the_coldbringer(); //Razorfen Downs +void AddSC_boss_tuten_kash(); //Razorfen Downs +void AddSC_boss_mordresh_fire_eye(); +void AddSC_boss_glutton(); +void AddSC_boss_amnennar_the_coldbringer(); void AddSC_razorfen_downs(); void AddSC_instance_razorfen_downs(); void AddSC_razorfen_kraul(); //Razorfen Kraul @@ -1032,7 +1035,10 @@ void AddKalimdorScripts() AddSC_instance_maraudon(); AddSC_boss_onyxia(); //Onyxia's Lair AddSC_instance_onyxias_lair(); - AddSC_boss_amnennar_the_coldbringer(); //Razorfen Downs + AddSC_boss_tuten_kash(); //Razorfen Downs + AddSC_boss_mordresh_fire_eye(); + AddSC_boss_glutton(); + AddSC_boss_amnennar_the_coldbringer(); AddSC_razorfen_downs(); AddSC_instance_razorfen_downs(); AddSC_razorfen_kraul(); //Razorfen Kraul diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt index 17c360a54b2..c02e896a87d 100644 --- a/src/server/scripts/Kalimdor/CMakeLists.txt +++ b/src/server/scripts/Kalimdor/CMakeLists.txt @@ -15,12 +15,15 @@ set(scripts_STAT_SRCS Kalimdor/zone_moonglade.cpp Kalimdor/RazorfenDowns/razorfen_downs.cpp Kalimdor/RazorfenDowns/instance_razorfen_downs.cpp + Kalimdor/RazorfenDowns/boss_tuten_kash.cpp + Kalimdor/RazorfenDowns/boss_mordresh_fire_eye.cpp + Kalimdor/RazorfenDowns/boss_glutton.cpp Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp Kalimdor/RazorfenDowns/razorfen_downs.h - Kalimdor/ZulFarrak/zulfarrak.h Kalimdor/ZulFarrak/zulfarrak.cpp Kalimdor/ZulFarrak/instance_zulfarrak.cpp Kalimdor/ZulFarrak/boss_zum_rah.cpp + Kalimdor/ZulFarrak/zulfarrak.h Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_epoch_hunter.cpp Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.h Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_leutenant_drake.cpp diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp index 4a4d7fe4b07..323fd92a8f6 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp +++ b/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 * * 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 @@ -16,63 +15,57 @@ * with this program. If not, see . */ -/* ScriptData -SDName: Boss_Amnennar_the_coldbringer -SD%Complete: 100 -SDComment: -SDCategory: Razorfen Downs -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "razorfen_downs.h" -enum AmnennarTheColdbringer +enum Say { SAY_AGGRO = 0, SAY_SUMMON60 = 1, SAY_SUMMON30 = 2, SAY_HP = 3, - SAY_KILL = 4, + SAY_KILL = 4 +}; +enum Spells +{ SPELL_AMNENNARSWRATH = 13009, SPELL_FROSTBOLT = 15530, SPELL_FROST_NOVA = 15531, SPELL_FROST_SPECTRES = 12642 }; +enum Events +{ + EVENT_AMNENNARSWRATH = 1, + EVENT_FROSTBOLT = 2, + EVENT_FROST_NOVA = 3 +}; + class boss_amnennar_the_coldbringer : public CreatureScript { public: boss_amnennar_the_coldbringer() : CreatureScript("boss_amnennar_the_coldbringer") { } - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new boss_amnennar_the_coldbringerAI(creature); - } - - struct boss_amnennar_the_coldbringerAI : public ScriptedAI + struct boss_amnennar_the_coldbringerAI : public BossAI { - boss_amnennar_the_coldbringerAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 AmnenarsWrath_Timer; - uint32 FrostBolt_Timer; - uint32 FrostNova_Timer; - bool Spectrals60; - bool Spectrals30; - bool Hp; + boss_amnennar_the_coldbringerAI(Creature* creature) : BossAI(creature, DATA_AMNENNAR_THE_COLD_BRINGER) { } void Reset() OVERRIDE { - AmnenarsWrath_Timer = 8000; - FrostBolt_Timer = 1000; - FrostNova_Timer = urand(10000, 15000); - Spectrals30 = false; - Spectrals60 = false; - Hp = false; + _Reset(); + hp60Spectrals = false; + hp30Spectrals = false; + hp50 = false; } void EnterCombat(Unit* /*who*/) OVERRIDE { + _EnterCombat(); + events.ScheduleEvent(EVENT_AMNENNARSWRATH, 8000); + events.ScheduleEvent(EVENT_FROSTBOLT, 1000); + events.ScheduleEvent(EVENT_FROST_NOVA, urand(10000, 15000)); Talk(SAY_AGGRO); } @@ -81,55 +74,73 @@ public: Talk(SAY_KILL); } + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + } + void UpdateAI(uint32 diff) OVERRIDE { if (!UpdateVictim()) return; - //AmnenarsWrath_Timer - if (AmnenarsWrath_Timer <= diff) - { - DoCastVictim(SPELL_AMNENNARSWRATH); - AmnenarsWrath_Timer = 12000; - } else AmnenarsWrath_Timer -= diff; + events.Update(diff); - //FrostBolt_Timer - if (FrostBolt_Timer <= diff) - { - DoCastVictim(SPELL_FROSTBOLT); - FrostBolt_Timer = 8000; - } else FrostBolt_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (FrostNova_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCast(me, SPELL_FROST_NOVA); - FrostNova_Timer = 15000; - } else FrostNova_Timer -= diff; + switch (eventId) + { + case EVENT_AMNENNARSWRATH: + DoCastVictim(SPELL_AMNENNARSWRATH); + events.ScheduleEvent(EVENT_AMNENNARSWRATH, 12000); + break; + case EVENT_FROSTBOLT: + DoCastVictim(SPELL_FROSTBOLT); + events.ScheduleEvent(EVENT_FROSTBOLT, 8000); + break; + case EVENT_FROST_NOVA: + DoCast(me, SPELL_FROST_NOVA); + events.ScheduleEvent(EVENT_FROST_NOVA, 15000); + break; + } + } - if (!Spectrals60 && HealthBelowPct(60)) + if (!hp60Spectrals && HealthBelowPct(60)) { Talk(SAY_SUMMON60); DoCastVictim(SPELL_FROST_SPECTRES); - Spectrals60 = true; + hp60Spectrals = true; } - if (!Hp && HealthBelowPct(50)) + if (!hp50 && HealthBelowPct(50)) { Talk(SAY_HP); - Hp = true; + hp50 = true; } - if (!Spectrals30 && HealthBelowPct(30)) + if (!hp30Spectrals && HealthBelowPct(30)) { Talk(SAY_SUMMON30); DoCastVictim(SPELL_FROST_SPECTRES); - Spectrals30 = true; + hp30Spectrals = true; } DoMeleeAttackIfReady(); } + + private: + bool hp60Spectrals; + bool hp30Spectrals; + bool hp50; }; + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_amnennar_the_coldbringerAI(creature); + } }; void AddSC_boss_amnennar_the_coldbringer() diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/boss_glutton.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/boss_glutton.cpp new file mode 100644 index 00000000000..a249013bd6a --- /dev/null +++ b/src/server/scripts/Kalimdor/RazorfenDowns/boss_glutton.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2008-2013 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "razorfen_downs.h" + +enum Say +{ + SAY_HP50 = 0, + SAY_HP15 = 1 +}; + +enum Spells +{ + SPELL_DISEASE_CLOUD = 12627, + SPELL_FRENZY = 12795 +}; + +class boss_glutton : public CreatureScript +{ +public: + boss_glutton() : CreatureScript("boss_glutton") { } + + struct boss_gluttonAI : public BossAI + { + boss_gluttonAI(Creature* creature) : BossAI(creature, DATA_GLUTTON) { } + + void Reset() OVERRIDE + { + _Reset(); + hp50 = false; + hp15 = false; + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + } + + void UpdateAI(uint32 /*diff*/) OVERRIDE + { + if (!UpdateVictim()) + return; + + if (!hp50 && HealthBelowPct(50)) + { + Talk(SAY_HP50); + hp50 = true; + } + + if (!hp15 && HealthBelowPct(15)) + { + Talk(SAY_HP15); + DoCast(me, SPELL_FRENZY); + hp15 = true; + } + + DoMeleeAttackIfReady(); + } + + private: + bool hp50; + bool hp15; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_gluttonAI(creature); + } +}; + +void AddSC_boss_glutton() +{ + new boss_glutton(); +} diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/boss_mordresh_fire_eye.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/boss_mordresh_fire_eye.cpp new file mode 100644 index 00000000000..1f45de3c4c6 --- /dev/null +++ b/src/server/scripts/Kalimdor/RazorfenDowns/boss_mordresh_fire_eye.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2008-2013 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "razorfen_downs.h" + +enum Say +{ + SAY_OOC_1 = 0, + SAY_OOC_2 = 1, + SAY_OOC_3 = 2, + SAY_AGGRO = 3 +}; + +enum Spells +{ + SPELL_FIREBALL = 12466, + SPELL_FIRE_NOVA = 12470 +}; + +enum Events +{ + EVENT_OOC_1 = 1, + EVENT_OOC_2 = 2, + EVENT_OOC_3 = 3, + EVENT_OOC_4 = 4, + EVENT_FIREBALL = 5, + EVENT_FIRE_NOVA = 6 +}; + +class boss_mordresh_fire_eye : public CreatureScript +{ +public: + boss_mordresh_fire_eye() : CreatureScript("boss_mordresh_fire_eye") { } + + struct boss_mordresh_fire_eyeAI : public BossAI + { + boss_mordresh_fire_eyeAI(Creature* creature) : BossAI(creature, DATA_MORDRESH_FIRE_EYE) { } + + void Reset() OVERRIDE + { + _Reset(); + events.ScheduleEvent(EVENT_OOC_1, 10000); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.Reset(); + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_FIREBALL, 100); + events.ScheduleEvent(EVENT_FIRE_NOVA, urand(8000, 12000)); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + events.Update(diff); + + if (!UpdateVictim()) + { + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_OOC_1: + Talk(SAY_OOC_1); + events.ScheduleEvent(EVENT_OOC_2, 8000); + break; + case EVENT_OOC_2: + Talk(SAY_OOC_2); + events.ScheduleEvent(EVENT_OOC_3, 3000); + break; + case EVENT_OOC_3: + me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + events.ScheduleEvent(EVENT_OOC_4, 6000); + break; + case EVENT_OOC_4: + Talk(SAY_OOC_3); + events.ScheduleEvent(EVENT_OOC_1, 14000); + break; + } + } + return; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FIREBALL: + DoCastVictim(SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, urand(2400, 3800)); + break; + case EVENT_FIRE_NOVA: + DoCast(me, SPELL_FIRE_NOVA); + events.ScheduleEvent(EVENT_FIRE_NOVA, urand(11000, 16000)); + break; + } + } + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_mordresh_fire_eyeAI(creature); + } +}; + +void AddSC_boss_mordresh_fire_eye() +{ + new boss_mordresh_fire_eye(); +} diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/boss_tuten_kash.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/boss_tuten_kash.cpp new file mode 100644 index 00000000000..5cf8a2992a3 --- /dev/null +++ b/src/server/scripts/Kalimdor/RazorfenDowns/boss_tuten_kash.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008-2013 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "razorfen_downs.h" + +enum Spells +{ + SPELL_THRASH = 8876, + SPELL_WEB_SPRAY = 12252, + SPELL_VIRULENT_POISON = 12254, + SPELL_CURSE_OF_TUTENKASH = 12255 +}; + +enum Events +{ + EVENT_WEB_SPRAY = 1, + EVENT_CURSE_OF_TUTENKASH = 2 +}; + +class boss_tuten_kash : public CreatureScript +{ +public: + boss_tuten_kash() : CreatureScript("boss_tuten_kash") { } + + struct boss_tuten_kashAI : public BossAI + { + boss_tuten_kashAI(Creature* creature) : BossAI(creature, DATA_TUTEN_KASH) { } + + void Reset() OVERRIDE + { + _Reset(); + if (!me->HasAura(SPELL_THRASH)) + DoCast(me, SPELL_THRASH); + if (!me->HasAura(SPELL_VIRULENT_POISON)) + DoCast(me, SPELL_VIRULENT_POISON); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + _EnterCombat(); + events.ScheduleEvent(EVENT_WEB_SPRAY, urand(3000, 5000)); + events.ScheduleEvent(EVENT_CURSE_OF_TUTENKASH, urand(9000, 14000)); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + _JustDied(); + } + + 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_WEB_SPRAY: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, false)) + { + if (!target->HasAura(SPELL_WEB_SPRAY)) + DoCast(target, SPELL_WEB_SPRAY); + } + events.ScheduleEvent(EVENT_WEB_SPRAY, urand(6000, 8000)); + break; + case EVENT_CURSE_OF_TUTENKASH: + DoCast(me, SPELL_CURSE_OF_TUTENKASH); + events.ScheduleEvent(EVENT_CURSE_OF_TUTENKASH, urand(15000, 25000)); + break; + } + } + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new boss_tuten_kashAI(creature); + } +}; + +void AddSC_boss_tuten_kash() +{ + new boss_tuten_kash(); +} diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/instance_razorfen_downs.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/instance_razorfen_downs.cpp index 091c7e46585..097f340891a 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/instance_razorfen_downs.cpp +++ b/src/server/scripts/Kalimdor/RazorfenDowns/instance_razorfen_downs.cpp @@ -16,199 +16,219 @@ */ #include "ScriptMgr.h" +#include "ObjectMgr.h" #include "InstanceScript.h" #include "razorfen_downs.h" #include "Player.h" #include "TemporarySummon.h" -#define MAX_ENCOUNTER 1 +Position const PosSummonTutenkash[15] = +{ + // 7349 Tomb Fiend + { 2487.339f, 805.9111f, 43.08361f, 2.844887f }, + { 2485.405f, 804.1145f, 43.68511f, 3.054326f }, + { 2488.431f, 801.2809f, 42.70374f, 4.29351f }, + { 2489.914f, 804.7949f, 43.25175f, 1.658063f }, + { 2541.246f, 907.0941f, 46.64201f, 2.024582f }, + { 2544.701f, 907.6331f, 46.38007f, 1.605703f }, + { 2541.49f, 911.1756f, 46.26493f, 4.817109f }, + { 2544.693f, 912.8887f, 46.39912f, 2.129302f }, + { 2524.036f, 834.4852f, 48.37031f, 0.8028514f }, + { 2527.017f, 829.9793f, 48.06498f, 0.6981317f }, + // 7351 Tomb Reaver + { 2542.818f, 904.9359f, 46.80911f, 4.642576f }, + { 2543.287f, 911.2448f, 46.32785f, 0.6806784f }, + { 2489.083f, 806.5914f, 43.21102f, 3.682645f }, + { 2486.828f, 802.8737f, 43.19883f, 2.9147f }, + // 7355 Tuten'kash + { 2487.939f, 804.2224f, 43.10735f, 1.692969f } +}; class instance_razorfen_downs : public InstanceMapScript { public: - instance_razorfen_downs() : InstanceMapScript("instance_razorfen_downs", 129) { } - - InstanceScript* GetInstanceScript(InstanceMap* map) const OVERRIDE - { - return new instance_razorfen_downs_InstanceMapScript(map); - } + instance_razorfen_downs() : InstanceMapScript(RFDScriptName, 129) { } struct instance_razorfen_downs_InstanceMapScript : public InstanceScript { instance_razorfen_downs_InstanceMapScript(Map* map) : InstanceScript(map) { + SetBossNumber(EncounterCount); } - uint64 uiGongGUID; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint16 uiGongWaves; - - std::string str_data; - void Initialize() OVERRIDE { - uiGongGUID = 0; - - uiGongWaves = 0; - - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - } - - std::string GetSaveData() OVERRIDE - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - - saveStream << "T C " << m_auiEncounter[0] - << ' ' << uiGongWaves; - - str_data = saveStream.str(); - - OUT_SAVE_INST_DATA_COMPLETE; - return str_data; + goGongGUID = 0; + gongWave = 0; + fiendsKilled = 0; + reaversKilled = 0; + summonLowRange = 0; + summonHighRange = 0; + summonCreature = 0; } - void Load(const char* in) OVERRIDE + void OnGameObjectCreate(GameObject* gameObject) OVERRIDE { - if (!in) + switch (gameObject->GetEntry()) { - OUT_LOAD_INST_DATA_FAIL; - return; + case GO_GONG: + goGongGUID = gameObject->GetGUID(); + if (GetBossState(DATA_TUTEN_KASH) == DONE) + gameObject->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + break; + case GO_IDOL_OVEN_FIRE: + case GO_IDOL_CUP_FIRE: + case GO_IDOL_MOUTH_FIRE: + if (GetBossState(DATA_EXTINGUISHING_THE_IDOL) == DONE) + gameObject->Delete(); + break; + default: + break; } - - OUT_LOAD_INST_DATA(in); - - char dataHead1, dataHead2; - uint16 data0, data1; - - std::istringstream loadStream(in); - loadStream >> dataHead1 >> dataHead2 >> data0 >> data1; - - if (dataHead1 == 'T' && dataHead2 == 'C') - { - m_auiEncounter[0] = data0; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - - uiGongWaves = data1; - } else OUT_LOAD_INST_DATA_FAIL; - - OUT_LOAD_INST_DATA_COMPLETE; } - void OnGameObjectCreate(GameObject* go) OVERRIDE + bool SetBossState(uint32 type, EncounterState state) OVERRIDE { - switch (go->GetEntry()) + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) { - case GO_GONG: - uiGongGUID = go->GetGUID(); - if (m_auiEncounter[0] == DONE) - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + case DATA_TUTEN_KASH: + case DATA_MORDRESH_FIRE_EYE: + case DATA_GLUTTON: + case DATA_AMNENNAR_THE_COLD_BRINGER: + case DATA_GONG: + case DATA_WAVE: + case DATA_EXTINGUISHING_THE_IDOL: break; default: break; } + return true; } - void SetData(uint32 uiType, uint32 uiData) OVERRIDE + void SetData(uint32 type, uint32 data) OVERRIDE { - if (uiType == DATA_GONG_WAVES) + if (type == DATA_WAVE) { - uiGongWaves = uiData; - - switch (uiGongWaves) + switch (data) { - case 9: - case 14: - if (GameObject* go = instance->GetGameObject(uiGongGUID)) - go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - break; - case 1: - case 10: - case 16: + case IN_PROGRESS: { - GameObject* go = instance->GetGameObject(uiGongGUID); - - if (!go) - return; - - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - - uint32 uiCreature = 0; - uint8 uiSummonTimes = 0; + if (GameObject* go = instance->GetGameObject(goGongGUID)) + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - switch (uiGongWaves) + switch (gongWave) { - case 1: - uiCreature = NPC_TOMB_FIEND; - uiSummonTimes = 7; - break; - case 10: - uiCreature = NPC_TOMB_REAVER; - uiSummonTimes = 3; + case 0: + summonLowRange = 0; + summonHighRange = 10; + summonCreature = NPC_TOMB_FIEND; break; - case 16: - uiCreature = NPC_TUTEN_KASH; + case 1: + summonLowRange = 10; + summonHighRange = 14; + summonCreature = NPC_TOMB_REAVER; break; - default: + case 2: + summonLowRange = 14; + summonHighRange = 15; + summonCreature = NPC_TUTEN_KASH; break; } - if (Creature* creature = go->SummonCreature(uiCreature, 2502.635f, 844.140f, 46.896f, 0.633f)) + if (GameObject* go = instance->GetGameObject(goGongGUID)) { - if (uiGongWaves == 10 || uiGongWaves == 1) + for (uint8 i = summonLowRange; i < summonHighRange; ++i) { - for (uint8 i = 0; i < uiSummonTimes; ++i) - { - if (Creature* summon = go->SummonCreature(uiCreature, 2502.635f + float(irand(-5, 5)), 844.140f + float(irand(-5, 5)), 46.896f, 0.633f)) - summon->GetMotionMaster()->MovePoint(0, 2533.479f + float(irand(-5, 5)), 870.020f + float(irand(-5, 5)), 47.678f); - } + Creature* creature = go->SummonCreature(summonCreature, PosSummonTutenkash[i]); + creature->GetMotionMaster()->MovePoint(0, 2533.479f + float(irand(-5, 5)), 870.020f + float(irand(-5, 5)), 47.678f); } - creature->GetMotionMaster()->MovePoint(0, 2533.479f + float(irand(-5, 5)), 870.020f + float(irand(-5, 5)), 47.678f); } + + ++gongWave; break; } - default: + case NPC_TOMB_FIEND: + if (++fiendsKilled == 10) + { + fiendsKilled = 0; + if (GameObject* go = instance->GetGameObject(goGongGUID)) + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } + break; + case NPC_TOMB_REAVER: + if (++reaversKilled == 4) + { + reaversKilled = 0; + if (GameObject* go = instance->GetGameObject(goGongGUID)) + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } break; } + } - if (uiType == BOSS_TUTEN_KASH) - { - m_auiEncounter[0] = uiData; + } - if (uiData == DONE) - SaveToDB(); - } + std::string GetSaveData() OVERRIDE + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "R D " << GetBossSaveData(); + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); } - uint32 GetData(uint32 uiType) const OVERRIDE + void Load(const char* str) OVERRIDE { - switch (uiType) + if (!str) { - case DATA_GONG_WAVES: - return uiGongWaves; + OUT_LOAD_INST_DATA_FAIL; + return; } - return 0; - } + OUT_LOAD_INST_DATA(str); - uint64 GetData64(uint32 uiType) const OVERRIDE - { - switch (uiType) + char dataHead1, dataHead2; + + std::istringstream loadStream(str); + loadStream >> dataHead1 >> dataHead2; + + if (dataHead1 == 'R' && dataHead2 == 'D') { - case DATA_GONG: return uiGongGUID; + for (uint32 i = 0; i < EncounterCount; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + SetBossState(i, EncounterState(tmpState)); + } } + else + OUT_LOAD_INST_DATA_FAIL; - return 0; + OUT_LOAD_INST_DATA_COMPLETE; } + + protected: + uint64 goGongGUID; + uint16 gongWave; + uint8 fiendsKilled; + uint8 reaversKilled; + uint8 summonLowRange; + uint8 summonHighRange; + uint32 summonCreature; }; + InstanceScript* GetInstanceScript(InstanceMap* map) const OVERRIDE + { + return new instance_razorfen_downs_InstanceMapScript(map); + } }; void AddSC_instance_razorfen_downs() diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp index 320c9970077..f81d634e019 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp +++ b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp @@ -32,6 +32,11 @@ EndContentData */ #include "ScriptedGossip.h" #include "razorfen_downs.h" #include "Player.h" +#include "GridDefines.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "ObjectDefines.h" +#include "ObjectMgr.h" /*### # npc_henry_stern @@ -101,32 +106,272 @@ public: }; /*###### -## go_gong +## npc_belnistrasz for Quest 3525 "Extinguishing the Idol" ######*/ -class go_gong : public GameObjectScript +Position const PosSummonSpawner[3] = +{ + { 2582.789f, 954.3925f, 52.48214f, 3.787364f }, + { 2569.42f, 956.3801f, 52.27323f, 5.427974f }, + { 2570.62f, 942.3934f, 53.7433f, 0.715585f } +}; + +enum Belnistrasz +{ + EVENT_CHANNEL = 1, + EVENT_IDOL_ROOM_SPAWNER = 2, + EVENT_PROGRESS = 3, + EVENT_COMPLETE = 4, + EVENT_FIREBALL = 5, + EVENT_FROST_NOVA = 6, + + FACTION_ESCORT = 250, + + PATH_ESCORT = 871710, + POINT_REACH_IDOL = 17, + + QUEST_EXTINGUISHING_THE_IDOL = 3525, + + SAY_QUEST_ACCEPTED = 0, + SAY_EVENT_START = 1, + SAY_EVENT_THREE_MIN_LEFT = 2, + SAY_EVENT_TWO_MIN_LEFT = 3, + SAY_EVENT_ONE_MIN_LEFT = 4, + SAY_EVENT_END = 5, + SAY_AGGRO = 6, // Combat + SAY_WATCH_OUT = 7, // 25% chance to target random creature and say on wave spawn + + SPELL_ARCANE_INTELLECT = 13326, + SPELL_FIREBALL = 9053, + SPELL_FROST_NOVA = 11831, + SPELL_IDOL_SHUTDOWN_VISUAL = 12774, // Hits Unit Entry: 8662 + SPELL_IDOM_ROOM_CAMERA_SHAKE = 12816 // Dummy needs scripting +}; + +class npc_belnistrasz : public CreatureScript { public: - go_gong() : GameObjectScript("go_gong") { } + npc_belnistrasz() : CreatureScript("npc_belnistrasz") { } - bool OnGossipHello(Player* /*player*/, GameObject* go) OVERRIDE + struct npc_belnistraszAI : public ScriptedAI { - //basic support, not blizzlike data is missing... - InstanceScript* instance = go->GetInstanceScript(); + npc_belnistraszAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + eventInProgress = false; + } - if (instance) + void Reset() OVERRIDE { - instance->SetData(DATA_GONG_WAVES, instance->GetData(DATA_GONG_WAVES)+1); - return true; + if (!eventInProgress) + { + if (!me->HasAura(SPELL_ARCANE_INTELLECT)) + DoCast(me, SPELL_ARCANE_INTELLECT); + + channeling = false; + eventProgress = 0; + spawnerCount = 0; + me->SetFlag(UNIT_NPC_FLAGS, GOSSIP_OPTION_QUESTGIVER); + } } - return false; + void EnterCombat(Unit* who) OVERRIDE + { + if (channeling) + { + Talk(SAY_WATCH_OUT, who->GetGUID()); + } + else + { + events.ScheduleEvent(EVENT_FIREBALL, 1000); + events.ScheduleEvent(EVENT_FROST_NOVA, urand(8000, 12000)); + if (urand(0, 100) > 40) + Talk(SAY_AGGRO, who->GetGUID()); + } + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + instance->SetBossState(DATA_EXTINGUISHING_THE_IDOL, DONE); + me->DespawnOrUnsummon(5000); + } + + void sQuestAccept(Player* /*player*/, Quest const* quest) OVERRIDE + { + if (quest->GetQuestId() == QUEST_EXTINGUISHING_THE_IDOL) + { + eventInProgress = true; + Talk(SAY_QUEST_ACCEPTED); + me->RemoveFlag(UNIT_NPC_FLAGS, GOSSIP_OPTION_QUESTGIVER); + me->setFaction(FACTION_ESCORT); + me->GetMotionMaster()->MovePath(PATH_ESCORT, false); + } + } + + void MovementInform(uint32 type, uint32 id) OVERRIDE + { + if (type == WAYPOINT_MOTION_TYPE && id == POINT_REACH_IDOL) + { + channeling = true; + events.ScheduleEvent(EVENT_CHANNEL, 2000); + } + } + + void UpdateAI(uint32 diff) OVERRIDE + { + if (!eventInProgress) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CHANNEL: + Talk(SAY_EVENT_START); + DoCast(me, SPELL_IDOL_SHUTDOWN_VISUAL); + events.ScheduleEvent(EVENT_IDOL_ROOM_SPAWNER, 100); + events.ScheduleEvent(EVENT_PROGRESS, 120000); + break; + case EVENT_IDOL_ROOM_SPAWNER: + if (Creature* creature = me->SummonCreature(NPC_IDOL_ROOM_SPAWNER, PosSummonSpawner[urand(0,2)], TEMPSUMMON_TIMED_DESPAWN, 4000)) + creature->AI()->SetData(0,spawnerCount); + if (++spawnerCount < 8) + events.ScheduleEvent(EVENT_IDOL_ROOM_SPAWNER, 35000); + break; + case EVENT_PROGRESS: + { + switch (eventProgress) + { + case 0: + Talk(SAY_EVENT_THREE_MIN_LEFT); + ++eventProgress; + events.ScheduleEvent(EVENT_PROGRESS, 60000); + break; + case 1: + Talk(SAY_EVENT_TWO_MIN_LEFT); + ++eventProgress; + events.ScheduleEvent(EVENT_PROGRESS, 60000); + break; + case 2: + Talk(SAY_EVENT_ONE_MIN_LEFT); + ++eventProgress; + events.ScheduleEvent(EVENT_PROGRESS, 60000); + break; + case 3: + events.CancelEvent(EVENT_IDOL_ROOM_SPAWNER); + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + Talk(SAY_EVENT_END); + events.ScheduleEvent(EVENT_COMPLETE, 3000); + break; + } + break; + } + case EVENT_COMPLETE: + { + DoCast(me, SPELL_IDOM_ROOM_CAMERA_SHAKE); + me->SummonGameObject(GO_BELNISTRASZS_BRAZIER, 2577.196f, 947.0781f, 53.16757f, 2.356195f, 0, 0, 0.9238796f, 0.3826832f, 3600000); + std::list ClusterList; + Trinity::AllWorldObjectsInRange objects(me, 50.0f); + Trinity::WorldObjectListSearcher searcher(me, ClusterList, objects); + me->VisitNearbyObject(50.0f, searcher); + for (std::list::const_iterator itr = ClusterList.begin(); itr != ClusterList.end(); ++itr) + { + if (Player* player = (*itr)->ToPlayer()) + { + if (player->GetQuestStatus(QUEST_EXTINGUISHING_THE_IDOL) == QUEST_STATUS_INCOMPLETE) + player->CompleteQuest(QUEST_EXTINGUISHING_THE_IDOL); + } + else if (GameObject* go = (*itr)->ToGameObject()) + { + if (go->GetEntry() == GO_IDOL_OVEN_FIRE || go->GetEntry() == GO_IDOL_CUP_FIRE || go->GetEntry() == GO_IDOL_MOUTH_FIRE) + go->Delete(); + } + } + instance->SetBossState(DATA_EXTINGUISHING_THE_IDOL, DONE); + me->DespawnOrUnsummon(); + break; + } + case EVENT_FIREBALL: + if (me->HasUnitState(UNIT_STATE_CASTING) || !UpdateVictim()) + return; + DoCastVictim(SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, 8000); + break; + case EVENT_FROST_NOVA: + if (me->HasUnitState(UNIT_STATE_CASTING) || !UpdateVictim()) + return; + DoCast(me, SPELL_FROST_NOVA); + events.ScheduleEvent(EVENT_FROST_NOVA, 15000); + break; + } + } + if (!channeling) + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* instance; + EventMap events; + bool eventInProgress; + bool channeling; + uint8 eventProgress; + uint8 spawnerCount; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_belnistraszAI(creature); } +}; + +class npc_idol_room_spawner : public CreatureScript +{ +public: + npc_idol_room_spawner() : CreatureScript("npc_idol_room_spawner") { } + + struct npc_idol_room_spawnerAI : public ScriptedAI + { + npc_idol_room_spawnerAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() OVERRIDE { } + void SetData(uint32 /*type*/, uint32 data) OVERRIDE + { + if(!instance) + return; + + if (data < 7) + { + me->SummonCreature(NPC_WITHERED_BATTLE_BOAR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + if (data > 0 && me->GetOrientation() < 4.0f) + me->SummonCreature(NPC_WITHERED_BATTLE_BOAR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + me->SummonCreature(NPC_DEATHS_HEAD_GEOMANCER, me->GetPositionX() + (cos(me->GetOrientation() - (M_PI/2)) * 2), me->GetPositionY() + (sin(me->GetOrientation() - (M_PI/2)) * 2), me->GetPositionZ(), me->GetOrientation()); + me->SummonCreature(NPC_WITHERED_QUILGUARD, me->GetPositionX() + (cos(me->GetOrientation() + (M_PI/2)) * 2), me->GetPositionY() + (sin(me->GetOrientation() + (M_PI/2)) * 2), me->GetPositionZ(), me->GetOrientation()); + } + else if (data =7) + me->SummonCreature(NPC_PLAGUEMAW_THE_ROTTING, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + } + + private: + InstanceScript* instance; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_idol_room_spawnerAI(creature); + } }; enum TombCreature { + EVENT_WEB = 7, + SPELL_POISON_PROC = 3616, + SPELL_VIRULENT_POISON_PROC = 12254, SPELL_WEB = 745 }; @@ -135,11 +380,6 @@ class npc_tomb_creature : public CreatureScript public: npc_tomb_creature() : CreatureScript("npc_tomb_creature") { } - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_tomb_creatureAI(creature); - } - struct npc_tomb_creatureAI : public ScriptedAI { npc_tomb_creatureAI(Creature* creature) : ScriptedAI(creature) @@ -147,45 +387,86 @@ public: instance = creature->GetInstanceScript(); } - InstanceScript* instance; + void Reset() OVERRIDE + { + if (!me->HasAura(SPELL_POISON_PROC) && me->GetEntry() == NPC_TOMB_FIEND) + DoCast(me, SPELL_POISON_PROC); - uint32 uiWebTimer; + if (!me->HasAura(SPELL_VIRULENT_POISON_PROC) && me->GetEntry() == NPC_TOMB_REAVER) + DoCast(me, SPELL_VIRULENT_POISON_PROC); + } - void Reset() OVERRIDE + void JustDied(Unit* /*killer*/) OVERRIDE + { + if (instance) + instance->SetData(DATA_WAVE, me->GetEntry()); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE { - uiWebTimer = urand(5000, 8000); + events.ScheduleEvent(EVENT_WEB, urand(5000, 8000)); } - void UpdateAI(uint32 uiDiff) OVERRIDE + void UpdateAI(uint32 diff) OVERRIDE { if (!UpdateVictim()) return; - //from acid - if (me->GetEntry() == NPC_TOMB_REAVER) + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - if (uiWebTimer <= uiDiff) + switch (eventId) { - DoCastVictim(SPELL_WEB); - uiWebTimer = urand(7000, 16000); - } else uiWebTimer -= uiDiff; + case EVENT_WEB: + DoCastVictim(SPELL_WEB); + events.ScheduleEvent(EVENT_WEB, urand(7000, 16000)); + break; + } } - DoMeleeAttackIfReady(); } - void JustDied(Unit* /*killer*/) OVERRIDE + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_tomb_creatureAI(creature); + } +}; + +/*###### +## go_gong +######*/ + +class go_gong : public GameObjectScript +{ +public: + go_gong() : GameObjectScript("go_gong") { } + + bool OnGossipHello(Player* /*player*/, GameObject* go) OVERRIDE + { + InstanceScript* instance = go->GetInstanceScript(); + + if (instance) { - if (instance) - instance->SetData(DATA_GONG_WAVES, instance->GetData(DATA_GONG_WAVES)+1); + go->SendCustomAnim(0); + instance->SetData(DATA_WAVE, IN_PROGRESS); + return true; } - }; + return false; + } }; void AddSC_razorfen_downs() { new npc_henry_stern(); - new go_gong(); + new npc_belnistrasz(); + new npc_idol_room_spawner(); new npc_tomb_creature(); + new go_gong(); } diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.h b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.h index c0f63474f23..9fe5314fda0 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.h +++ b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.h @@ -18,27 +18,56 @@ #ifndef DEF_RAZORFEN_DOWNS_H #define DEF_RAZORFEN_DOWNS_H -enum Data +#define RFDScriptName "instance_razorfen_downs" + +uint32 const EncounterCount = 5; + +enum DataTypes { - BOSS_TUTEN_KASH, - DATA_GONG_WAVES + // Main Bosses + DATA_TUTEN_KASH = 0, + DATA_MORDRESH_FIRE_EYE = 1, + DATA_GLUTTON = 2, + DATA_AMNENNAR_THE_COLD_BRINGER = 3, + // Events + DATA_GONG = 4, + DATA_WAVE = 5, + DATA_EXTINGUISHING_THE_IDOL = 6 }; -enum Data64 +enum CreatureIds { - DATA_GONG + // Used in Tuten Kash summon event + NPC_TOMB_FIEND = 7349, + NPC_TOMB_REAVER = 7351, + NPC_TUTEN_KASH = 7355, + // Used for quest 3525 "Extinguishing the Idol" + NPC_IDOL_ROOM_SPAWNER = 8611, + NPC_WITHERED_BATTLE_BOAR = 7333, + NPC_DEATHS_HEAD_GEOMANCER = 7335, + NPC_WITHERED_QUILGUARD = 7329, + NPC_PLAGUEMAW_THE_ROTTING = 7356 }; enum GameObjectIds { - GO_GONG = 148917 + // Used for Tuten Kash summon event + GO_GONG = 148917, + // Used for quest 3525 "Extinguishing the Idol" + GO_IDOL_OVEN_FIRE = 151951, + GO_IDOL_CUP_FIRE = 151952, + GO_IDOL_MOUTH_FIRE = 151973, + GO_BELNISTRASZS_BRAZIER = 152097 }; -enum CreatureId +template +CreatureAI* GetRazorfenDownsAI(Creature* creature) { - NPC_TOMB_FIEND = 7349, - NPC_TOMB_REAVER = 7351, - NPC_TUTEN_KASH = 7355 -}; + if (InstanceMap* instance = creature->GetMap()->ToInstanceMap()) + if (instance->GetInstanceScript()) + if (instance->GetScriptId() == sObjectMgr->GetScriptId(RFDScriptName)) + return new AI(creature); + return NULL; +} #endif -- cgit v1.2.3 From fc7e335d3bee0b86f5cfb1a4b46d73577cd6494b Mon Sep 17 00:00:00 2001 From: Malcrom Date: Wed, 11 Dec 2013 01:13:23 -0330 Subject: Scripting/Obsidian Sanctum: Updated scripts to use Events. --- src/server/game/Scripting/ScriptLoader.cpp | 2 + src/server/scripts/Northrend/CMakeLists.txt | 1 + .../ObsidianSanctum/boss_sartharion.cpp | 1738 +++----------------- .../ObsidianSanctum/instance_obsidian_sanctum.cpp | 155 +- .../ObsidianSanctum/obsidian_sanctum.cpp | 1183 +++++++++++++ .../ObsidianSanctum/obsidian_sanctum.h | 19 +- 6 files changed, 1543 insertions(+), 1555 deletions(-) create mode 100644 src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp (limited to 'src/server/game/Scripting/ScriptLoader.cpp') diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index b486eb45915..3b340f8d147 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -449,6 +449,7 @@ void AddSC_oculus(); void AddSC_boss_malygos(); // The Nexus: Eye of Eternity void AddSC_instance_eye_of_eternity(); void AddSC_boss_sartharion(); //Obsidian Sanctum +void AddSC_obsidian_sanctum(); void AddSC_instance_obsidian_sanctum(); void AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning void AddSC_boss_loken(); @@ -1287,6 +1288,7 @@ void AddNorthrendScripts() AddSC_boss_malygos(); // The Nexus: Eye of Eternity AddSC_instance_eye_of_eternity(); AddSC_boss_sartharion(); //Obsidian Sanctum + AddSC_obsidian_sanctum(); AddSC_instance_obsidian_sanctum(); AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning AddSC_boss_loken(); diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index 3c56361d096..285f8f866cb 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -45,6 +45,7 @@ set(scripts_STAT_SRCS Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp + Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp index 2088ef2fa2e..a212a74df86 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp @@ -37,9 +37,6 @@ enum Enums SAY_SARTHARION_SLAY = 8, WHISPER_LAVA_CHURN = 9, - WHISPER_HATCH_EGGS = 6, - WHISPER_OPEN_PORTAL = 6, // whisper, shared by two dragons - WHISPER_SHADRON_DICIPLE = 7, WHISPER_VESPERON_DICIPLE = 7, @@ -58,70 +55,25 @@ enum Enums SPELL_PYROBUFFET = 56916, // currently used for hard enrage after 15 minutes SPELL_PYROBUFFET_RANGE = 58907, // possibly used when player get too far away from dummy creatures (2x Creature entry 30494) - SPELL_TWILIGHT_SHIFT_ENTER = 57620, // enter phase. Player get this when click GO - SPELL_TWILIGHT_SHIFT = 57874, // Twilight Shift Aura - SPELL_TWILIGHT_SHIFT_REMOVAL = 61187, // leave phase - SPELL_TWILIGHT_SHIFT_REMOVAL_ALL = 61190, // leave phase (probably version to make all leave) - - //Mini bosses common spells - SPELL_TWILIGHT_RESIDUE = 61885, // makes immune to shadow damage, applied when leave phase - - //Miniboses (Vesperon, Shadron, Tenebron) - SPELL_SHADOW_BREATH_H = 59126, // Inflicts 8788 to 10212 Fire damage to enemies in a cone in front of the caster. - SPELL_SHADOW_BREATH = 57570, // Inflicts 6938 to 8062 Fire damage to enemies in a cone in front of the caster. - - SPELL_SHADOW_FISSURE_H = 59127, // Deals 9488 to 13512 Shadow damage to any enemy within the Shadow fissure after 5 sec. - SPELL_SHADOW_FISSURE = 57579, // Deals 6188 to 8812 Shadow damage to any enemy within the Shadow fissure after 5 sec. - //Vesperon //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times NPC_ACOLYTE_OF_VESPERON = 31219, // Acolyte of Vesperon SPELL_POWER_OF_VESPERON = 61251, // Vesperon's presence decreases the maximum health of all enemies by 25%. - SPELL_TWILIGHT_TORMENT_VESP = 57948, // (Shadow only) trigger 57935 then 57988 - SPELL_TWILIGHT_TORMENT_VESP_ACO = 58853, // (Fire and Shadow) trigger 58835 then 57988 //Shadron //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times NPC_ACOLYTE_OF_SHADRON = 31218, // Acolyte of Shadron SPELL_POWER_OF_SHADRON = 58105, // Shadron's presence increases Fire damage taken by all enemies by 100%. - SPELL_GIFT_OF_TWILIGTH_SHA = 57835, // TARGET_SCRIPT shadron - SPELL_GIFT_OF_TWILIGTH_SAR = 58766, // TARGET_SCRIPT sartharion - SPELL_VOID_BLAST = 57581, // Twilight Fissure - SPELL_VOID_BLAST_H = 59128, //Tenebron //in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 SPELL_POWER_OF_TENEBRON = 61248, // Tenebron's presence increases Shadow damage taken by all enemies by 100%. - //Tenebron, dummy spell - SPELL_SUMMON_TWILIGHT_WHELP = 58035, // doesn't work, will spawn NPC_TWILIGHT_WHELP - SPELL_SUMMON_SARTHARION_TWILIGHT_WHELP = 58826, // doesn't work, will spawn NPC_SHARTHARION_TWILIGHT_WHELP - - SPELL_HATCH_EGGS_H = 59189, - SPELL_HATCH_EGGS = 58542, - SPELL_HATCH_EGGS_EFFECT_H = 59190, - SPELL_HATCH_EGGS_EFFECT = 58685, - NPC_TWILIHT_WHELP = 31214, - NPC_TWILIGHT_EGG = 30882, - NPC_SARTHARION_TWILIGHT_EGG = 31204, - - //Whelps - NPC_TWILIGHT_WHELP = 30890, - NPC_SHARTHARION_TWILIGHT_WHELP = 31214, - SPELL_FADE_ARMOR = 60708, // Reduces the armor of an enemy by 1500 for 15s - - //flame tsunami - SPELL_FLAME_TSUNAMI = 57494, // the visual dummy - SPELL_FLAME_TSUNAMI_LEAP = 60241, // SPELL_EFFECT_138 some leap effect, causing caster to move in direction - - SPELL_FLAME_TSUNAMI_DMG_AURA = 57491, // periodic damage, npc has this aura - SPELL_FLAME_TSUNAMI_BUFF = 60430, NPC_FLAME_TSUNAMI = 30616, // for the flame waves - NPC_LAVA_BLAZE = 30643, // adds spawning from flame strike //using these custom points for dragons start and end POINT_ID_INIT = 100, - POINT_ID_LAND = 200, + POINT_ID_LAND = 200 }; enum Misc @@ -129,25 +81,32 @@ enum Misc DATA_CAN_LOOT = 0 }; -struct Waypoint -{ - float m_fX, m_fY, m_fZ; -}; - struct Location { float x, y, z; }; -struct Locations + +static Location FlameRight1Spawn = { 3200.00f, 573.211f, 57.1551f }; +static Location FlameRight1Direction = { 3289.28f, 573.211f, 57.1551f }; +static Location FlameRight2Spawn = { 3200.00f, 532.211f, 57.1551f }; +static Location FlameRight2Direction = { 3289.28f, 532.211f, 57.1551f }; +static Location FlameRight3Spawn = { 3200.00f, 491.211f, 57.1551f }; +static Location FlameRight3Direction = { 3289.28f, 491.211f, 57.1551f }; +static Location FlameLeft1Spawn = { 3289.28f, 511.711f, 57.1551f }; +static Location FlameLeft1Direction = { 3200.00f, 511.711f, 57.1551f }; +static Location FlameLeft2Spawn = { 3289.28f, 552.711f, 57.1551f }; +static Location FlameLeft2Direction = { 3200.00f, 552.711f, 57.1551f }; + +struct Waypoint { - float x, y, z; + float m_fX, m_fY, m_fZ; }; //each dragons special points. First where fly to before connect to connon, second where land point is. Waypoint m_aTene[]= { - {3212.854f, 575.597f, 109.856f}, //init - {3246.425f, 565.367f, 61.249f} //end + {3212.854f, 575.597f, 109.856f}, // init + {3246.425f, 565.367f, 61.249f} // end }; Waypoint m_aShad[]= @@ -162,54 +121,19 @@ Waypoint m_aVesp[]= {3227.268f, 533.238f, 59.995f} }; -#define MAX_WAYPOINT 6 -//points around raid "isle", counter clockwise. should probably be adjusted to be more alike -Waypoint m_aDragonCommon[MAX_WAYPOINT]= -{ - {3214.012f, 468.932f, 98.652f}, - {3244.950f, 468.427f, 98.652f}, - {3283.520f, 496.869f, 98.652f}, - {3287.316f, 555.875f, 98.652f}, - {3250.479f, 585.827f, 98.652f}, - {3209.969f, 566.523f, 98.652f} -}; - -static Location FlameRight1Spawn = { 3200.00f, 573.211f, 57.1551f }; -static Location FlameRight1Direction = { 3289.28f, 573.211f, 57.1551f }; -static Location FlameRight2Spawn = { 3200.00f, 532.211f, 57.1551f }; -static Location FlameRight2Direction = { 3289.28f, 532.211f, 57.1551f }; -static Location FlameRight3Spawn = { 3200.00f, 491.211f, 57.1551f }; -static Location FlameRight3Direction = { 3289.28f, 491.211f, 57.1551f }; -static Location FlameLeft1Spawn = { 3289.28f, 511.711f, 57.1551f }; -static Location FlameLeft1Direction = { 3200.00f, 511.711f, 57.1551f }; -static Location FlameLeft2Spawn = { 3289.28f, 552.711f, 57.1551f }; -static Location FlameLeft2Direction = { 3200.00f, 552.711f, 57.1551f }; - -static Location AcolyteofShadron = { 3363.92f, 534.703f, 97.2683f }; -static Location AcolyteofShadron2 = { 3246.57f, 551.263f, 58.6164f }; -static Location AcolyteofVesperon = { 3145.68f, 520.71f, 89.7f }; -static Location AcolyteofVesperon2 = { 3246.57f, 551.263f, 58.6164f }; -Locations TwilightEggs[] = -{ - {3219.28f, 669.121f, 88.5549f}, - {3221.55f, 682.852f, 90.5361f}, - {3239.77f, 685.94f, 90.3168f}, - {3250.33f, 669.749f, 88.7637f}, - {3246.6f, 642.365f, 84.8752f}, - {3233.68f, 653.117f, 85.7051f} -}; -Locations TwilightEggsSarth[] = +enum SartharionEvents { - {3252.73f, 515.762f, 58.5501f}, - {3256.56f, 521.119f, 58.6061f}, - {3255.63f, 527.513f, 58.7568f}, - {3264.90f, 525.865f, 58.6436f}, - {3264.26f, 516.364f, 58.8011f}, - {3257.54f, 502.285f, 58.2077f} + EVENT_HARD_ENRAGE = 1, + EVENT_FLAME_TSUNAMI = 2, + EVENT_FLAME_BREATH = 3, + EVENT_TAIL_SWEEP = 4, + EVENT_CLEAVE_ATTACK = 5, + EVENT_LAVA_STRIKE = 6, + EVENT_CALL_TENEBRON = 7, + EVENT_CALL_SHADRON = 8, + EVENT_CALL_VESPERON = 9 }; -#define TWILIGHT_ACHIEVEMENTS 1 - /*###### ## Boss Sartharion ######*/ @@ -219,169 +143,71 @@ class boss_sartharion : public CreatureScript public: boss_sartharion() : CreatureScript("boss_sartharion") { } - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new boss_sartharionAI(creature); - } - - struct boss_sartharionAI : public ScriptedAI + struct boss_sartharionAI : public BossAI { - boss_sartharionAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - bool m_bIsBerserk; - bool m_bIsSoftEnraged; - - uint32 m_uiEnrageTimer; - bool m_bIsHardEnraged; - - uint32 m_uiTenebronTimer; - uint32 m_uiShadronTimer; - uint32 m_uiVesperonTimer; - - uint32 m_uiFlameTsunamiTimer; - uint32 m_uiFlameBreathTimer; - uint32 m_uiTailSweepTimer; - uint32 m_uiCleaveTimer; - uint32 m_uiLavaStrikeTimer; - - bool m_bHasCalledTenebron; - bool m_bHasCalledShadron; - bool m_bHasCalledVesperon; - - uint8 drakeCount; + boss_sartharionAI(Creature* creature) : BossAI(creature, DATA_SARTHARION) { } void Reset() OVERRIDE { - m_bIsBerserk = false; - m_bIsSoftEnraged = false; - - m_uiEnrageTimer = 15*MINUTE*IN_MILLISECONDS; - m_bIsHardEnraged = false; - - m_uiTenebronTimer = 30000; - m_uiShadronTimer = 75000; - m_uiVesperonTimer = 120000; - - m_uiFlameTsunamiTimer = 30000; - m_uiFlameBreathTimer = 20000; - m_uiTailSweepTimer = 20000; - m_uiCleaveTimer = 7000; - m_uiLavaStrikeTimer = 5000; - - m_bHasCalledTenebron = false; - m_bHasCalledShadron = false; - m_bHasCalledVesperon = false; + _isBerserk = false; + _isSoftEnraged = false; + _isHardEnraged = false; + drakeCount = 0; if (me->HasAura(SPELL_TWILIGHT_REVENGE)) me->RemoveAurasDueToSpell(SPELL_TWILIGHT_REVENGE); me->SetHomePosition(3246.57f, 551.263f, 58.6164f, 4.66003f); - drakeCount = 0; - - // Drakes respawning system if (instance) { - Creature* pTenebron = Unit::GetCreature(*me, instance->GetData64(DATA_TENEBRON)); - Creature* pShadron = Unit::GetCreature(*me, instance->GetData64(DATA_SHADRON)); - Creature* pVesperon = Unit::GetCreature(*me, instance->GetData64(DATA_VESPERON)); - if (pTenebron) - { - pTenebron->SetHomePosition(3239.07f, 657.235f, 86.8775f, 4.74729f); - if (pTenebron->IsAlive()) - { - if (pTenebron->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - pTenebron->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pTenebron->GetMotionMaster()->MoveTargetedHome(); - }else - { - if (instance->GetData(TYPE_TENEBRON_PREKILLED) == false) - { - pTenebron->Respawn(); - pTenebron->GetMotionMaster()->MoveTargetedHome(); - pTenebron->AI()->SetData(DATA_CAN_LOOT, 0); - } - } - } - if (pShadron) - { - pShadron->SetHomePosition(3363.06f, 525.28f, 98.362f, 4.76475f); - if (pShadron->IsAlive()) - { - if (pShadron->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - pShadron->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pShadron->GetMotionMaster()->MoveTargetedHome(); - }else - { - if (instance->GetData(TYPE_SHADRON_PREKILLED) == false) - { - pShadron->Respawn(); - pShadron->GetMotionMaster()->MoveTargetedHome(); - pShadron->AI()->SetData(DATA_CAN_LOOT, 0); - } - } - } - if (pVesperon) - { - pVesperon->SetHomePosition(3145.68f, 520.71f, 89.7f, 4.64258f); - if (pVesperon->IsAlive()) - { - if (pVesperon->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - pVesperon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pVesperon->GetMotionMaster()->MoveTargetedHome(); - }else - { - if (instance->GetData(TYPE_VESPERON_PREKILLED) == false) - { - pVesperon->Respawn(); - pVesperon->GetMotionMaster()->MoveTargetedHome(); - pVesperon->AI()->SetData(DATA_CAN_LOOT, 0); - } - } - } + DrakeRespawn(); + instance->SetBossState(DATA_PORTAL_OPEN, NOT_STARTED); } } void JustReachedHome() OVERRIDE { - if (instance) - instance->SetData(TYPE_SARTHARION_EVENT, NOT_STARTED); + _Reset(); } void EnterCombat(Unit* /*who*/) OVERRIDE { Talk(SAY_SARTHARION_AGGRO); + _EnterCombat(); DoZoneInCombat(); if (instance) - { - instance->SetData(TYPE_SARTHARION_EVENT, IN_PROGRESS); FetchDragons(); - } + + events.ScheduleEvent(EVENT_LAVA_STRIKE, 5000); + events.ScheduleEvent(EVENT_CLEAVE_ATTACK, 7000); + events.ScheduleEvent(EVENT_FLAME_BREATH, 20000); + events.ScheduleEvent(EVENT_TAIL_SWEEP, 20000); + events.ScheduleEvent(EVENT_FLAME_TSUNAMI, 30000); + events.ScheduleEvent(EVENT_CALL_TENEBRON, 30000); + events.ScheduleEvent(EVENT_CALL_SHADRON, 75000); + events.ScheduleEvent(EVENT_CALL_VESPERON, 120000); } void JustDied(Unit* /*killer*/) OVERRIDE { Talk(SAY_SARTHARION_DEATH); + _JustDied(); if (instance) { - Creature* pTenebron = Unit::GetCreature(*me, instance->GetData64(DATA_TENEBRON)); - Creature* pShadron = Unit::GetCreature(*me, instance->GetData64(DATA_SHADRON)); - Creature* pVesperon = Unit::GetCreature(*me, instance->GetData64(DATA_VESPERON)); - if (pTenebron && pTenebron->IsAlive()) - pTenebron->DisappearAndDie(); - if (pShadron && pShadron->IsAlive()) - pShadron->DisappearAndDie(); - if (pVesperon && pVesperon->IsAlive()) - pVesperon->DisappearAndDie(); - - instance->SetData(TYPE_SARTHARION_EVENT, DONE); + if (Creature* tenebron = Unit::GetCreature(*me, instance->GetData64(DATA_TENEBRON))) + if (tenebron->IsAlive()) + tenebron->DisappearAndDie(); + + if (Creature* shadron = Unit::GetCreature(*me, instance->GetData64(DATA_SHADRON))) + if (shadron->IsAlive()) + shadron->DisappearAndDie(); + + if (Creature* vesperon = Unit::GetCreature(*me, instance->GetData64(DATA_VESPERON))) + if (vesperon->IsAlive()) + vesperon->DisappearAndDie(); } } @@ -402,83 +228,140 @@ public: me->AddLootMode(LOOT_MODE_HARD_MODE_1); // Add 1st Drake loot mode } - uint32 GetData(uint32 type) const OVERRIDE + void DrakeRespawn() // Drakes respawning system { - if (type == TWILIGHT_ACHIEVEMENTS) - return drakeCount; + if (Creature* tenebron = Unit::GetCreature(*me, instance->GetData64(DATA_TENEBRON))) + { + tenebron->SetHomePosition(3239.07f, 657.235f, 86.8775f, 4.74729f); + if (tenebron->IsAlive()) + { + if (tenebron->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + tenebron->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + tenebron->GetMotionMaster()->MoveTargetedHome(); + } + else + { + if (instance->GetBossState(DATA_TENEBRON) != DONE) + { + tenebron->Respawn(); + tenebron->GetMotionMaster()->MoveTargetedHome(); + tenebron->AI()->SetData(DATA_CAN_LOOT, 0); + } + } + } - return 0; + if (Creature* shadron = Unit::GetCreature(*me, instance->GetData64(DATA_SHADRON))) + { + shadron->SetHomePosition(3363.06f, 525.28f, 98.362f, 4.76475f); + if (shadron->IsAlive()) + { + if (shadron->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + shadron->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + shadron->GetMotionMaster()->MoveTargetedHome(); + } + else + { + if (instance->GetBossState(DATA_SHADRON) != DONE) + { + shadron->Respawn(); + shadron->GetMotionMaster()->MoveTargetedHome(); + shadron->AI()->SetData(DATA_CAN_LOOT, 0); + } + } + } + + if (Creature* vesperon = Unit::GetCreature(*me, instance->GetData64(DATA_VESPERON))) + { + vesperon->SetHomePosition(3145.68f, 520.71f, 89.7f, 4.64258f); + if (vesperon->IsAlive()) + { + if (vesperon->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + vesperon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + vesperon->GetMotionMaster()->MoveTargetedHome(); + } + else + { + if (instance->GetBossState(DATA_VESPERON) != DONE) + { + vesperon->Respawn(); + vesperon->GetMotionMaster()->MoveTargetedHome(); + vesperon->AI()->SetData(DATA_CAN_LOOT, 0); + } + } + } } void FetchDragons() { - if (!instance) - return; - me->ResetLootMode(); drakeCount = 0; - Creature* pFetchTene = Unit::GetCreature(*me, instance->GetData64(DATA_TENEBRON)); - Creature* pFetchShad = Unit::GetCreature(*me, instance->GetData64(DATA_SHADRON)); - Creature* pFetchVesp = Unit::GetCreature(*me, instance->GetData64(DATA_VESPERON)); - //if at least one of the dragons are alive and are being called - bool bCanUseWill = false; + bool _canUseWill = false; - if (pFetchTene && pFetchTene->IsAlive() && !pFetchTene->GetVictim()) + if (Creature* fetchTene = Unit::GetCreature(*me, instance->GetData64(DATA_TENEBRON))) { - bCanUseWill = true; - if (!pFetchTene->IsInCombat()) + if (fetchTene->IsAlive() && !fetchTene->GetVictim()) { - DoCast(me, SPELL_POWER_OF_TENEBRON); - AddDrakeLootMode(); - ++drakeCount; - } - pFetchTene->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aTene[0].m_fX, m_aTene[0].m_fY, m_aTene[0].m_fZ); + _canUseWill = true; + if (!fetchTene->IsInCombat()) + { + DoCast(me, SPELL_POWER_OF_TENEBRON); + AddDrakeLootMode(); + ++drakeCount; + } + fetchTene->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aTene[0].m_fX, m_aTene[0].m_fY, m_aTene[0].m_fZ); - if (!pFetchTene->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - pFetchTene->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (!fetchTene->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + fetchTene->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } } - if (pFetchShad && pFetchShad->IsAlive() && !pFetchShad->GetVictim()) + if (Creature* fetchShad = Unit::GetCreature(*me, instance->GetData64(DATA_SHADRON))) { - bCanUseWill = true; - if (!pFetchShad->IsInCombat()) + if (fetchShad->IsAlive() && !fetchShad->GetVictim()) { - DoCast(me, SPELL_POWER_OF_SHADRON); - AddDrakeLootMode(); - ++drakeCount; - } - pFetchShad->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aShad[0].m_fX, m_aShad[0].m_fY, m_aShad[0].m_fZ); + _canUseWill = true; + if (!fetchShad->IsInCombat()) + { + DoCast(me, SPELL_POWER_OF_SHADRON); + AddDrakeLootMode(); + ++drakeCount; + } + fetchShad->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aShad[0].m_fX, m_aShad[0].m_fY, m_aShad[0].m_fZ); - if (!pFetchShad->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - pFetchShad->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (!fetchShad->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + fetchShad->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } } - if (pFetchVesp && pFetchVesp->IsAlive() && !pFetchVesp->GetVictim()) + if (Creature* fetchVesp = Unit::GetCreature(*me, instance->GetData64(DATA_VESPERON))) { - bCanUseWill = true; - if (!pFetchVesp->IsInCombat()) + if (fetchVesp && fetchVesp->IsAlive() && !fetchVesp->GetVictim()) { - DoCast(me, SPELL_POWER_OF_VESPERON); - AddDrakeLootMode(); - ++drakeCount; - } - pFetchVesp->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aVesp[0].m_fX, m_aVesp[0].m_fY, m_aVesp[0].m_fZ); + _canUseWill = true; + if (!fetchVesp->IsInCombat()) + { + DoCast(me, SPELL_POWER_OF_VESPERON); + AddDrakeLootMode(); + ++drakeCount; + } + fetchVesp->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aVesp[0].m_fX, m_aVesp[0].m_fY, m_aVesp[0].m_fZ); - if (!pFetchVesp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - pFetchVesp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (!fetchVesp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + fetchVesp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } } - if (bCanUseWill) + if (_canUseWill) DoCast(me, SPELL_WILL_OF_SARTHARION); } - void CallDragon(uint32 uiDataId) + void CallDragon(uint32 dataId) { if (instance) { - if (Creature* temp = Unit::GetCreature(*me, instance->GetData64(uiDataId))) + if (Creature* temp = Unit::GetCreature(*me, instance->GetData64(dataId))) { if (temp->IsAlive() && !temp->GetVictim()) { @@ -487,33 +370,41 @@ public: if (temp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - int32 iTextId = 0; + int32 textId = 0; switch (temp->GetEntry()) { case NPC_TENEBRON: - iTextId = SAY_SARTHARION_CALL_TENEBRON; + textId = SAY_SARTHARION_CALL_TENEBRON; temp->AddAura(SPELL_POWER_OF_TENEBRON, temp); temp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aTene[1].m_fX, m_aTene[1].m_fY, m_aTene[1].m_fZ); break; case NPC_SHADRON: - iTextId = SAY_SARTHARION_CALL_SHADRON; + textId = SAY_SARTHARION_CALL_SHADRON; temp->AddAura(SPELL_POWER_OF_SHADRON, temp); temp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aShad[1].m_fX, m_aShad[1].m_fY, m_aShad[1].m_fZ); break; case NPC_VESPERON: - iTextId = SAY_SARTHARION_CALL_VESPERON; + textId = SAY_SARTHARION_CALL_VESPERON; temp->AddAura(SPELL_POWER_OF_VESPERON, temp); temp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aVesp[1].m_fX, m_aVesp[1].m_fY, m_aVesp[1].m_fZ); break; } - Talk(iTextId); + Talk(textId); } } } } + uint32 GetData(uint32 type) const OVERRIDE + { + if (type == TWILIGHT_ACHIEVEMENTS) + return drakeCount; + + return 0; + } + void SendFlameTsunami() { if (Map* map = me->GetMap()) @@ -532,16 +423,16 @@ public: // FIXME: Frequency of the casts reduced to compensate 100% chance of spawning a Lava Blaze add void CastLavaStrikeOnTarget(Unit* target) { - std::list pFireCyclonesList; + std::list fireCyclonesList; Trinity::AllCreaturesOfEntryInRange checker(me, NPC_FIRE_CYCLONE, 200.0f); - Trinity::CreatureListSearcher searcher(me, pFireCyclonesList, checker); + Trinity::CreatureListSearcher searcher(me, fireCyclonesList, checker); me->VisitNearbyObject(200.0f, searcher); - if (pFireCyclonesList.empty()) + if (fireCyclonesList.empty()) return; - std::list::iterator itr = pFireCyclonesList.begin(); - uint32 rnd = rand()%pFireCyclonesList.size(); + std::list::iterator itr = fireCyclonesList.begin(); + uint32 rnd = rand()%fireCyclonesList.size(); for (uint32 i = 0; i < rnd; ++i) ++itr; @@ -549,1224 +440,121 @@ public: (*itr)->CastSpell(target, SPELL_LAVA_STRIKE, true); } - void UpdateAI(uint32 uiDiff) OVERRIDE + void UpdateAI(uint32 diff) OVERRIDE { - //Return since we have no target if (!UpdateVictim()) return; - Unit* pTene = Unit::GetUnit(*me, instance ? instance->GetData64(DATA_TENEBRON) : 0); - Unit* pShad = Unit::GetUnit(*me, instance ? instance->GetData64(DATA_SHADRON) : 0); - Unit* pVesp = Unit::GetUnit(*me, instance ? instance->GetData64(DATA_VESPERON) : 0); - - //spell will target dragons, if they are still alive at 35% - if (!m_bIsBerserk && !HealthAbovePct(35) - && ((pTene && pTene->IsAlive()) || (pShad && pShad->IsAlive()) || (pVesp && pVesp->IsAlive()))) - { - Talk(SAY_SARTHARION_BERSERK); - DoCast(me, SPELL_BERSERK); - m_bIsBerserk = true; - } - - //soft enrage - if (!m_bIsSoftEnraged && HealthBelowPct(10)) - { - // m_bIsSoftEnraged is used while determining Lava Strike cooldown. - m_bIsSoftEnraged = true; - } - - // hard enrage - if (!m_bIsHardEnraged) - { - if (m_uiEnrageTimer <= uiDiff) - { - DoCast(me, SPELL_PYROBUFFET, true); - m_bIsHardEnraged = true; - } - else - m_uiEnrageTimer -= uiDiff; - } + events.Update(diff); - // flame tsunami - if (m_uiFlameTsunamiTimer <= uiDiff) + while (uint32 eventId = events.ExecuteEvent()) { - SendFlameTsunami(); - switch (urand(0, 1)) + switch (eventId) { - case 0: - { - Creature* Right1 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameRight1Spawn.x, FlameRight1Spawn.y, FlameRight1Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000); - Creature* Right2 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameRight2Spawn.x, FlameRight2Spawn.y, FlameRight2Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000); - Creature* Right3 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameRight3Spawn.x, FlameRight3Spawn.y, FlameRight3Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000); - Right1->GetMotionMaster()->MovePoint(0, FlameRight1Direction.x, FlameRight1Direction.y, FlameRight1Direction.z); - Right2->GetMotionMaster()->MovePoint(0, FlameRight2Direction.x, FlameRight2Direction.y, FlameRight2Direction.z); - Right3->GetMotionMaster()->MovePoint(0, FlameRight3Direction.x, FlameRight3Direction.y, FlameRight3Direction.z); + case EVENT_HARD_ENRAGE: + if (!_isHardEnraged) + { + DoCast(me, SPELL_PYROBUFFET, true); + _isHardEnraged = true; + } break; - } - case 1: - { - Creature* Left1 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameLeft1Spawn.x, FlameLeft1Spawn.y, FlameLeft1Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000); - Creature* Left2 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameLeft2Spawn.x, FlameLeft2Spawn.y, FlameLeft2Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000); - Left1->GetMotionMaster()->MovePoint(0, FlameLeft1Direction.x, FlameLeft1Direction.y, FlameLeft1Direction.z); - Left2->GetMotionMaster()->MovePoint(0, FlameLeft2Direction.x, FlameLeft2Direction.y, FlameLeft2Direction.z); + case EVENT_FLAME_TSUNAMI: + SendFlameTsunami(); + switch (urand(0, 1)) + { + case 0: + { + if (Creature* right1 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameRight1Spawn.x, FlameRight1Spawn.y, FlameRight1Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000)) + right1->GetMotionMaster()->MovePoint(0, FlameRight1Direction.x, FlameRight1Direction.y, FlameRight1Direction.z); + if (Creature* right2 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameRight2Spawn.x, FlameRight2Spawn.y, FlameRight2Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000)) + right2->GetMotionMaster()->MovePoint(0, FlameRight2Direction.x, FlameRight2Direction.y, FlameRight2Direction.z); + if (Creature* right3 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameRight3Spawn.x, FlameRight3Spawn.y, FlameRight3Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000)) + right3->GetMotionMaster()->MovePoint(0, FlameRight3Direction.x, FlameRight3Direction.y, FlameRight3Direction.z); + break; + } + case 1: + { + if (Creature* left1 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameLeft1Spawn.x, FlameLeft1Spawn.y, FlameLeft1Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000)) + left1->GetMotionMaster()->MovePoint(0, FlameLeft1Direction.x, FlameLeft1Direction.y, FlameLeft1Direction.z); + if (Creature* left2 = me->SummonCreature(NPC_FLAME_TSUNAMI, FlameLeft2Spawn.x, FlameLeft2Spawn.y, FlameLeft2Spawn.z, 0, TEMPSUMMON_TIMED_DESPAWN, 12000)) + left2->GetMotionMaster()->MovePoint(0, FlameLeft2Direction.x, FlameLeft2Direction.y, FlameLeft2Direction.z); + break; + } + } + events.ScheduleEvent(EVENT_FLAME_TSUNAMI, 30000); + break; + case EVENT_FLAME_BREATH: + Talk(SAY_SARTHARION_BREATH); + DoCastVictim(RAID_MODE(SPELL_FLAME_BREATH, SPELL_FLAME_BREATH_H)); + events.ScheduleEvent(EVENT_FLAME_BREATH, urand(25000, 35000)); + break; + case EVENT_TAIL_SWEEP: + DoCastVictim(RAID_MODE(SPELL_TAIL_LASH, SPELL_TAIL_LASH_H)); + events.ScheduleEvent(EVENT_TAIL_SWEEP, urand(15000, 20000)); + break; + case EVENT_CLEAVE_ATTACK: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE_ATTACK, urand(7000, 10000)); + break; + case EVENT_LAVA_STRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + CastLavaStrikeOnTarget(target); + if (urand(0, 5) == 0) + Talk(SAY_SARTHARION_SPECIAL); + } + events.ScheduleEvent(EVENT_LAVA_STRIKE, (_isSoftEnraged ? urand(1400, 2000) : urand(5000, 20000))); + break; + case EVENT_CALL_TENEBRON: + CallDragon(DATA_TENEBRON); + break; + case EVENT_CALL_SHADRON: + CallDragon(DATA_SHADRON); + break; + case EVENT_CALL_VESPERON: + CallDragon(DATA_VESPERON); + break; + default: break; - } } - - m_uiFlameTsunamiTimer = 30000; - } - else - m_uiFlameTsunamiTimer -= uiDiff; - - // flame breath - if (m_uiFlameBreathTimer <= uiDiff) - { - Talk(SAY_SARTHARION_BREATH); - DoCastVictim(RAID_MODE(SPELL_FLAME_BREATH, SPELL_FLAME_BREATH_H)); - m_uiFlameBreathTimer = urand(25000, 35000); - } - else - m_uiFlameBreathTimer -= uiDiff; - - // Tail Sweep - if (m_uiTailSweepTimer <= uiDiff) - { - DoCastVictim(RAID_MODE(SPELL_TAIL_LASH, SPELL_TAIL_LASH_H)); - m_uiTailSweepTimer = urand(15000, 20000); - } - else - m_uiTailSweepTimer -= uiDiff; - - // Cleave - if (m_uiCleaveTimer <= uiDiff) - { - DoCastVictim(SPELL_CLEAVE); - m_uiCleaveTimer = urand(7000, 10000); } - else - m_uiCleaveTimer -= uiDiff; - // Lavas Strike - if (m_uiLavaStrikeTimer <= uiDiff) + // At 35% spell will target dragons, if they are still alive. + if (!_isBerserk && !HealthAbovePct(35)) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (instance->GetBossState(DATA_TENEBRON) != DONE || instance->GetBossState(DATA_SHADRON) != DONE || instance->GetBossState(DATA_VESPERON) != DONE) { - CastLavaStrikeOnTarget(target); - - if (urand(0, 5) == 0) - Talk(SAY_SARTHARION_SPECIAL); + Talk(SAY_SARTHARION_BERSERK); + DoCast(me, SPELL_BERSERK); + _isBerserk = true; } - m_uiLavaStrikeTimer = (m_bIsSoftEnraged ? urand(1400, 2000) : urand(5000, 20000)); - } - else - m_uiLavaStrikeTimer -= uiDiff; - - // call tenebron - if (!m_bHasCalledTenebron && m_uiTenebronTimer <= uiDiff) - { - CallDragon(DATA_TENEBRON); - m_bHasCalledTenebron = true; } - else - m_uiTenebronTimer -= uiDiff; - // call shadron - if (!m_bHasCalledShadron && m_uiShadronTimer <= uiDiff) + // Soft Enrage used while determining Lava Strike cooldown. + if (!_isSoftEnraged && HealthBelowPct(10)) { - CallDragon(DATA_SHADRON); - m_bHasCalledShadron = true; + _isSoftEnraged = true; } - else - m_uiShadronTimer -= uiDiff; - - // call vesperon - if (!m_bHasCalledVesperon && m_uiVesperonTimer <= uiDiff) - { - CallDragon(DATA_VESPERON); - m_bHasCalledVesperon = true; - } - else - m_uiVesperonTimer -= uiDiff; DoMeleeAttackIfReady(); - EnterEvadeIfOutOfCombatArea(uiDiff); - } - }; - -}; - -enum TeneText -{ - SAY_TENEBRON_AGGRO = 0, - SAY_TENEBRON_SLAY = 1, - SAY_TENEBRON_DEATH = 2, - SAY_TENEBRON_BREATH = 3, - SAY_TENEBRON_RESPOND = 4, - SAY_TENEBRON_SPECIAL = 5 -}; - -enum ShadText -{ - SAY_SHADRON_AGGRO = 0, - SAY_SHADRON_SLAY = 1, - SAY_SHADRON_DEATH = 2, - SAY_SHADRON_BREATH = 3, - SAY_SHADRON_RESPOND = 4, - SAY_SHADRON_SPECIAL = 5 -}; - -enum VespText -{ - SAY_VESPERON_AGGRO = 0, - SAY_VESPERON_SLAY = 1, - SAY_VESPERON_DEATH = 2, - SAY_VESPERON_BREATH = 3, - SAY_VESPERON_RESPOND = 4, - SAY_VESPERON_SPECIAL = 5, -}; - -//to control each dragons common abilities -struct dummy_dragonAI : public ScriptedAI -{ - dummy_dragonAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 m_uiWaypointId; - uint32 m_uiMoveNextTimer; - int32 m_iPortalRespawnTime; - bool m_bCanMoveFree; - bool m_bCanLoot; - - void Reset() OVERRIDE - { - if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - m_uiWaypointId = 0; - m_uiMoveNextTimer = 500; - m_iPortalRespawnTime = 30000; - m_bCanMoveFree = false; - m_bCanLoot = true; - } - - void SetData(uint32 type, uint32 value) OVERRIDE - { - if (type == DATA_CAN_LOOT) - m_bCanLoot = value; - } - - void MovementInform(uint32 uiType, uint32 uiPointId) OVERRIDE - { - if (!instance || uiType != POINT_MOTION_TYPE) - return; - -// debug_log("dummy_dragonAI: %s reached point %u", me->GetName(), uiPointId); - - //if healers messed up the raid and we was already initialized - if (instance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) - { - EnterEvadeMode(); - return; - } - - //this is end, if we reach this, don't do much - if (uiPointId == POINT_ID_LAND) - { - me->GetMotionMaster()->Clear(); - me->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) - { - me->AddThreat(target, 1.0f); - me->Attack(target, true); - me->GetMotionMaster()->MoveChase(target); - } - - m_bCanMoveFree = false; - return; - } - - //get amount of common points - uint32 uiCommonWPCount = sizeof(m_aDragonCommon)/sizeof(Waypoint); - - //increase - m_uiWaypointId = uiPointId+1; - - //if we have reached a point bigger or equal to count, it mean we must reset to point 0 - if (m_uiWaypointId >= uiCommonWPCount) - { - if (!m_bCanMoveFree) - m_bCanMoveFree = true; - - m_uiWaypointId = 0; + EnterEvadeIfOutOfCombatArea(diff); } - m_uiMoveNextTimer = 500; - } + private: + bool _isBerserk; + bool _isSoftEnraged; + bool _isHardEnraged; + uint8 drakeCount; + }; - //used when open portal and spawn mobs in phase - void DoRaidWhisper(int32 iTextId) + CreatureAI* GetAI(Creature* creature) const OVERRIDE { - Map* map = me->GetMap(); - - if (map && map->IsDungeon()) - { - Map::PlayerList const &PlayerList = map->GetPlayers(); - - if (!PlayerList.isEmpty()) - { - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - Talk(iTextId, i->GetSource()->GetGUID()); - } - } + return new boss_sartharionAI(creature); } - - //"opens" the portal and does the "opening" whisper - void OpenPortal() - { - int32 iTextId = 0; - - //there are 4 portal spawn locations, each are expected to be spawned with negative spawntimesecs in database - - //using a grid search here seem to be more efficient than caching all four guids - //in instance script and calculate range to each. - GameObject* pPortal = me->FindNearestGameObject(GO_TWILIGHT_PORTAL, 50.0f); - - switch (me->GetEntry()) - { - case NPC_TENEBRON: - { - iTextId = WHISPER_HATCH_EGGS; - if (instance && !instance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) - { - for (uint32 i = 0; i < 6; ++i) - me->SummonCreature(NPC_TWILIGHT_EGG, TwilightEggs[i].x, TwilightEggs[i].y, TwilightEggs[i].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000); - } - else - { - for (uint32 i = 0; i < 6; ++i) - me->SummonCreature(NPC_SARTHARION_TWILIGHT_EGG, TwilightEggsSarth[i].x, TwilightEggsSarth[i].y, TwilightEggsSarth[i].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000); - } - break; - } - case NPC_SHADRON: - { - iTextId = WHISPER_OPEN_PORTAL; - if (instance && !instance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) - me->SummonCreature(NPC_ACOLYTE_OF_SHADRON, AcolyteofShadron.x, AcolyteofShadron.y, AcolyteofShadron.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 28000); - else - me->SummonCreature(NPC_ACOLYTE_OF_SHADRON, AcolyteofShadron2.x, AcolyteofShadron2.y, AcolyteofShadron2.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 28000); - - break; - } - case NPC_VESPERON: - { - iTextId = WHISPER_OPEN_PORTAL; - if (instance && !instance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) - { - if (Creature* Acolyte = me->SummonCreature(NPC_ACOLYTE_OF_VESPERON, AcolyteofVesperon.x, AcolyteofVesperon.y, AcolyteofVesperon.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000)) - { - me->InterruptNonMeleeSpells(true); - Acolyte->InterruptNonMeleeSpells(true); - me->CastSpell(me, 32747, false); - } - } - else - { - if (Creature* Acolyte = me->SummonCreature(NPC_ACOLYTE_OF_VESPERON, AcolyteofVesperon2.x, AcolyteofVesperon2.y, AcolyteofVesperon2.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000)) - { - me->InterruptNonMeleeSpells(true); - Acolyte->InterruptNonMeleeSpells(true); - me->CastSpell(me, 32747, false); - } - } - - break; - } - } - - DoRaidWhisper(iTextId); - - //By using SetRespawnTime() we will actually "spawn" the object with our defined time. - //Once time is up, portal will disappear again. - if (pPortal && !pPortal->isSpawned()) - pPortal->SetRespawnTime(m_iPortalRespawnTime); - - //Unclear what are expected to happen if one drake has a portal open already - //Refresh respawnTime so time again are set to 30secs? - } - - void JustDied(Unit* /*killer*/) OVERRIDE - { - if (!m_bCanLoot) - me->SetLootRecipient(NULL); - - int32 iTextId = 0; - uint32 uiSpellId = 0; - - switch (me->GetEntry()) - { - case NPC_TENEBRON: - iTextId = SAY_TENEBRON_DEATH; - uiSpellId = SPELL_POWER_OF_TENEBRON; - if (instance && instance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) - instance->SetData(TYPE_TENEBRON_PREKILLED, 1); - break; - case NPC_SHADRON: - iTextId = SAY_SHADRON_DEATH; - uiSpellId = SPELL_POWER_OF_SHADRON; - if (instance && instance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) - instance->SetData(TYPE_SHADRON_PREKILLED, 1); - if (Creature* pAcolyte = me->FindNearestCreature(NPC_ACOLYTE_OF_SHADRON, 100.0f)) - pAcolyte->Kill(pAcolyte); - break; - case NPC_VESPERON: - iTextId = SAY_VESPERON_DEATH; - uiSpellId = SPELL_POWER_OF_VESPERON; - if (instance && instance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) - instance->SetData(TYPE_VESPERON_PREKILLED, 1); - if (Creature* pAcolyte = me->FindNearestCreature(NPC_ACOLYTE_OF_VESPERON, 100.0f)) - pAcolyte->Kill(pAcolyte); - break; - } - - Talk(iTextId); - - me->RemoveAurasDueToSpell(uiSpellId); - - if (instance) - { - instance->DoRemoveAurasDueToSpellOnPlayers(uiSpellId); - - // not if solo mini-boss fight - if (instance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) - return; - - // Twilight Revenge to main boss - if (Unit* pSartharion = Unit::GetUnit(*me, instance->GetData64(DATA_SARTHARION))) - if (pSartharion->IsAlive()) - { - pSartharion->RemoveAurasDueToSpell(uiSpellId); - DoCast(pSartharion, SPELL_TWILIGHT_REVENGE, true); - } - } - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - if (m_bCanMoveFree && m_uiMoveNextTimer) - { - if (m_uiMoveNextTimer <= uiDiff) - { - if (m_uiWaypointId < MAX_WAYPOINT) - me->GetMotionMaster()->MovePoint(m_uiWaypointId, - m_aDragonCommon[m_uiWaypointId].m_fX, m_aDragonCommon[m_uiWaypointId].m_fY, m_aDragonCommon[m_uiWaypointId].m_fZ); - -// debug_log("dummy_dragonAI: %s moving to point %u", me->GetName(), m_uiWaypointId); - m_uiMoveNextTimer = 0; - } - else - m_uiMoveNextTimer -= uiDiff; - } - } -}; - -/*###### -## Mob Tenebron -######*/ - -class npc_tenebron : public CreatureScript -{ -public: - npc_tenebron() : CreatureScript("npc_tenebron") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_tenebronAI(creature); - } - - struct npc_tenebronAI : public dummy_dragonAI - { - npc_tenebronAI(Creature* creature) : dummy_dragonAI(creature) { } - - uint32 m_uiShadowBreathTimer; - uint32 m_uiShadowFissureTimer; - uint32 m_uiHatchEggTimer; - - bool m_bHasPortalOpen; - - void Reset() OVERRIDE - { - dummy_dragonAI::Reset(); - - m_uiShadowBreathTimer = 20000; - m_uiShadowFissureTimer = 5000; - m_uiHatchEggTimer = 30000; - - m_bHasPortalOpen = false; - } - - void EnterCombat(Unit* /*who*/) OVERRIDE - { - Talk(SAY_TENEBRON_AGGRO); - DoZoneInCombat(); - } - - void KilledUnit(Unit* /*victim*/) OVERRIDE - { - Talk(SAY_TENEBRON_SLAY); - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - //if no target, update dummy and return - if (!UpdateVictim()) - { - dummy_dragonAI::UpdateAI(uiDiff); - return; - } - - // shadow fissure - if (m_uiShadowFissureTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE)); - - m_uiShadowFissureTimer = urand(15000, 20000); - } - else - m_uiShadowFissureTimer -= uiDiff; - - // Hatch Egg - if (m_uiHatchEggTimer <= uiDiff) - { - OpenPortal(); - m_uiHatchEggTimer = 30000; - } - else - m_uiHatchEggTimer -= uiDiff; - - // shadow breath - if (m_uiShadowBreathTimer <= uiDiff) - { - Talk(SAY_TENEBRON_BREATH); - DoCastVictim(RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); - m_uiShadowBreathTimer = urand(20000, 25000); - } - else - m_uiShadowBreathTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } - }; - -}; - -/*###### -## Mob Shadron -######*/ - -class npc_shadron : public CreatureScript -{ -public: - npc_shadron() : CreatureScript("npc_shadron") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_shadronAI(creature); - } - - struct npc_shadronAI : public dummy_dragonAI - { - npc_shadronAI(Creature* creature) : dummy_dragonAI(creature) { } - - uint32 m_uiShadowBreathTimer; - uint32 m_uiShadowFissureTimer; - uint32 m_uiAcolyteShadronTimer; - - bool m_bHasPortalOpen; - - void Reset() OVERRIDE - { - dummy_dragonAI::Reset(); - - m_uiShadowBreathTimer = 20000; - m_uiShadowFissureTimer = 5000; - m_uiAcolyteShadronTimer = 60000; - - if (me->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) - me->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); - - if (me->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) - me->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); - - m_bHasPortalOpen = false; - } - - void EnterCombat(Unit* /*who*/) OVERRIDE - { - Talk(SAY_SHADRON_AGGRO); - DoZoneInCombat(); - } - - void KilledUnit(Unit* /*victim*/) OVERRIDE - { - Talk(SAY_SHADRON_SLAY); - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - //if no target, update dummy and return - if (!UpdateVictim()) - { - dummy_dragonAI::UpdateAI(uiDiff); - return; - } - - // shadow fissure - if (m_uiShadowFissureTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE_H)); - - m_uiShadowFissureTimer = urand(15000, 20000); - } - else - m_uiShadowFissureTimer -= uiDiff; - - // Portal Event - if (m_uiAcolyteShadronTimer <= uiDiff) - { - if (m_bHasPortalOpen) - m_uiAcolyteShadronTimer = 10000; - else - { - if (me->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) - return; - - OpenPortal(); - m_bHasPortalOpen = true; - m_uiAcolyteShadronTimer = urand(60000, 65000); - } - } - else - m_uiAcolyteShadronTimer -= uiDiff; - - // shadow breath - if (m_uiShadowBreathTimer <= uiDiff) - { - Talk(SAY_SHADRON_BREATH); - DoCastVictim(RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); - m_uiShadowBreathTimer = urand(20000, 25000); - } - else - m_uiShadowBreathTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } - }; - -}; - -/*###### -## Mob Vesperon -######*/ - -class npc_vesperon : public CreatureScript -{ -public: - npc_vesperon() : CreatureScript("npc_vesperon") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_vesperonAI(creature); - } - - struct npc_vesperonAI : public dummy_dragonAI - { - npc_vesperonAI(Creature* creature) : dummy_dragonAI(creature) { } - - uint32 m_uiShadowBreathTimer; - uint32 m_uiShadowFissureTimer; - uint32 m_uiAcolyteVesperonTimer; - - bool m_bHasPortalOpen; - - void Reset() OVERRIDE - { - dummy_dragonAI::Reset(); - - m_uiShadowBreathTimer = 20000; - m_uiShadowFissureTimer = 5000; - m_uiAcolyteVesperonTimer = 60000; - - m_bHasPortalOpen = false; - } - - void EnterCombat(Unit* /*who*/) OVERRIDE - { - Talk(SAY_VESPERON_AGGRO); - DoZoneInCombat(); - } - - void KilledUnit(Unit* /*victim*/) OVERRIDE - { - Talk(SAY_VESPERON_SLAY); - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - //if no target, update dummy and return - if (!UpdateVictim()) - { - dummy_dragonAI::UpdateAI(uiDiff); - return; - } - - // shadow fissure - if (m_uiShadowFissureTimer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE_H)); - - m_uiShadowFissureTimer = urand(15000, 20000); - } - else - m_uiShadowFissureTimer -= uiDiff; - - // Portal Event - if (m_uiAcolyteVesperonTimer <= uiDiff) - { - if (m_bHasPortalOpen) - m_uiAcolyteVesperonTimer = 10000; - else - { - OpenPortal(); - DoCastVictim(SPELL_TWILIGHT_TORMENT_VESP); - m_uiAcolyteVesperonTimer = urand(60000, 70000); - } - } - else - m_uiAcolyteVesperonTimer -= uiDiff; - - // shadow breath - if (m_uiShadowBreathTimer <= uiDiff) - { - Talk(SAY_VESPERON_BREATH); - DoCastVictim(RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); - m_uiShadowBreathTimer = urand(20000, 25000); - } - else - m_uiShadowBreathTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } - }; - -}; - -/*###### -## Mob Acolyte of Shadron -######*/ - -class npc_acolyte_of_shadron : public CreatureScript -{ -public: - npc_acolyte_of_shadron() : CreatureScript("npc_acolyte_of_shadron") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_acolyte_of_shadronAI(creature); - } - - struct npc_acolyte_of_shadronAI : public ScriptedAI - { - npc_acolyte_of_shadronAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 uiDespawnTimer; - - void Reset() OVERRIDE - { - uiDespawnTimer = 28000; - if (instance) - { - Creature* target = NULL; - //if not solo figth, buff main boss, else place debuff on mini-boss. both spells TARGET_SCRIPT - if (instance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) - { - target = Unit::GetCreature((*me), instance->GetData64(DATA_SARTHARION)); - if (target) - target->AddAura(SPELL_GIFT_OF_TWILIGTH_SAR, target); - } - else - { - target = Unit::GetCreature((*me), instance->GetData64(DATA_SHADRON)); - if (target) - target->AddAura(SPELL_GIFT_OF_TWILIGTH_SHA, target); - } - } - - me->AddAura(SPELL_TWILIGHT_SHIFT_ENTER, me); - } - - void JustDied(Unit* /*killer*/) OVERRIDE - { - if (instance) - { - Creature* Shadron = instance->instance->GetCreature(instance->GetData64(DATA_SHADRON)); - if (Shadron) - { - (CAST_AI(npc_shadron::npc_shadronAI, Shadron->AI()))->m_bHasPortalOpen = false; - } - - Creature* pDebuffTarget = NULL; - Map* map = me->GetMap(); - if (map->IsDungeon()) - { - Map::PlayerList const &PlayerList = map->GetPlayers(); - - if (PlayerList.isEmpty()) - return; - - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (i->GetSource()->IsAlive() && i->GetSource()->HasAura(SPELL_TWILIGHT_SHIFT, 0) && !i->GetSource()->GetVictim()) - { - i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_SHIFT_REMOVAL_ALL, true); - i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_RESIDUE, true); - i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT); - i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT_ENTER); - } - } - } - - //not solo fight, so main boss has deduff - pDebuffTarget = instance->instance->GetCreature(instance->GetData64(DATA_SARTHARION)); - if (pDebuffTarget && pDebuffTarget->IsAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SAR)) - pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SAR); - - //event not in progress, then solo fight and must remove debuff mini-boss - pDebuffTarget = instance->instance->GetCreature(instance->GetData64(DATA_SHADRON)); - if (pDebuffTarget && pDebuffTarget->IsAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) - pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); - } - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - if (uiDespawnTimer < uiDiff) - { - me->SetVisible(false); - me->Kill(me); - uiDespawnTimer = 28000; - return; - }else uiDespawnTimer -= uiDiff; - - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - }; - -}; - -/*###### -## Mob Acolyte of Vesperon -######*/ - -class npc_acolyte_of_vesperon : public CreatureScript -{ -public: - npc_acolyte_of_vesperon() : CreatureScript("npc_acolyte_of_vesperon") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_acolyte_of_vesperonAI(creature); - } - - struct npc_acolyte_of_vesperonAI : public ScriptedAI - { - npc_acolyte_of_vesperonAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 uiDespawnTimer; - - void Reset() OVERRIDE - { - uiDespawnTimer = 28000; - if (instance) - me->AddAura(SPELL_TWILIGHT_SHIFT_ENTER, me); - DoCast(me, SPELL_TWILIGHT_TORMENT_VESP_ACO); - } - - void JustDied(Unit* /*killer*/) OVERRIDE - { - me->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP_ACO); - - // remove twilight torment on Vesperon - if (instance) - { - Creature* pVesperon = instance->instance->GetCreature(instance->GetData64(DATA_VESPERON)); - if (pVesperon) - (CAST_AI(npc_vesperon::npc_vesperonAI, pVesperon->AI()))->m_bHasPortalOpen = false; - - if (pVesperon && pVesperon->IsAlive() && pVesperon->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) - pVesperon->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); - - Map* map = me->GetMap(); - if (map->IsDungeon()) - { - Map::PlayerList const &PlayerList = map->GetPlayers(); - - if (PlayerList.isEmpty()) - return; - - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (i->GetSource()->IsAlive() && i->GetSource()->HasAura(SPELL_TWILIGHT_SHIFT, 0) && !i->GetSource()->GetVictim()) - { - i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_SHIFT_REMOVAL_ALL, true); - i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_RESIDUE, true); - i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT); - i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT_ENTER); - } - if (i->GetSource()->IsAlive() && i->GetSource()->HasAura(SPELL_TWILIGHT_TORMENT_VESP, 0) && !i->GetSource()->GetVictim()) - i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); - } - } - - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_VESP_ACO); - instance->DoRemoveAurasDueToSpellOnPlayers(57935); - instance->DoRemoveAurasDueToSpellOnPlayers(58835); // Components of spell Twilight Torment - } - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - if (uiDespawnTimer < uiDiff) - { - me->SetVisible(false); - me->Kill(me); - uiDespawnTimer = 28000; - return; - }else uiDespawnTimer -= uiDiff; - - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - }; - -}; - -/*###### -## Mob Twilight Eggs -######*/ - -class npc_twilight_eggs : public CreatureScript -{ -public: - npc_twilight_eggs() : CreatureScript("npc_twilight_eggs") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_twilight_eggsAI(creature); - } - - struct npc_twilight_eggsAI : public ScriptedAI - { - npc_twilight_eggsAI(Creature* creature) : ScriptedAI(creature) - { - SetCombatMovement(false); - instance = creature->GetInstanceScript(); - } - - uint32 m_uiFadeArmorTimer; - uint32 m_uiHatchEggTimer; - - InstanceScript* instance; - - void Reset() OVERRIDE - { - if (instance) - me->AddAura(SPELL_TWILIGHT_SHIFT_ENTER, me); - m_uiFadeArmorTimer = 1000; - m_uiHatchEggTimer = 20000; - } - - void SpawnWhelps() - { - me->RemoveAllAuras(); - - if (!instance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) - me->SummonCreature(NPC_TWILIGHT_WHELP, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - else - me->SummonCreature(NPC_SHARTHARION_TWILIGHT_WHELP, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - me->DealDamage(me, me->GetHealth()); - } - - void JustSummoned(Creature* who) OVERRIDE - { - who->SetInCombatWithZone(); - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - if (m_uiHatchEggTimer <= uiDiff) - { - Creature* Tenebron = instance->instance->GetCreature(instance->GetData64(DATA_TENEBRON)); - if (Tenebron) - (CAST_AI(npc_tenebron::npc_tenebronAI, Tenebron->AI()))->m_bHasPortalOpen = false; - SpawnWhelps(); - } - else - m_uiHatchEggTimer -= uiDiff; - } - - void AttackStart(Unit* /*who*/) OVERRIDE { } - void MoveInLineOfSight(Unit* /*who*/) OVERRIDE { } - - }; - -}; - -/*###### -## Mob Flame Tsunami -######*/ -class npc_flame_tsunami : public CreatureScript -{ -public: - npc_flame_tsunami() : CreatureScript("npc_flame_tsunami") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_flame_tsunamiAI(creature); - } - - struct npc_flame_tsunamiAI : public ScriptedAI - { - npc_flame_tsunamiAI(Creature* creature) : ScriptedAI(creature) - { - me->SetDisplayId(11686); - me->AddAura(SPELL_FLAME_TSUNAMI, me); - } - - uint32 Tsunami_Timer; - uint32 TsunamiBuff_timer; - uint32 entry; - - void Reset() OVERRIDE - { - me->SetReactState(REACT_PASSIVE); - Tsunami_Timer = 100; - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - TsunamiBuff_timer = 1000; - entry = 0; - } - - void UpdateAI(uint32 diff) OVERRIDE - { - if (Tsunami_Timer <= diff) - { - DoCast(me, SPELL_FLAME_TSUNAMI_DMG_AURA); - Tsunami_Timer = 500; - }else Tsunami_Timer -= diff; - - if (TsunamiBuff_timer <= diff) - { - if (Unit* LavaBlaze = GetClosestCreatureWithEntry(me, NPC_LAVA_BLAZE, 10.0f, true)) - LavaBlaze->CastSpell(LavaBlaze, SPELL_FLAME_TSUNAMI_BUFF, true); - TsunamiBuff_timer = 1000; - }else TsunamiBuff_timer -= diff; - } - }; - -}; - -// Twilight Fissure -class npc_twilight_fissure : public CreatureScript -{ -public: - npc_twilight_fissure() : CreatureScript("npc_twilight_fissure") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_twilight_fissureAI(creature); - } - - struct npc_twilight_fissureAI : public ScriptedAI - { - npc_twilight_fissureAI(Creature* creature) : ScriptedAI(creature) - { - SetCombatMovement(false); - } - - uint32 VoidBlast_Timer; - - void Reset() OVERRIDE - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->AddAura( 46265, me ); // Wrong, can't find proper visual - me->AddAura( 69422, me ); - VoidBlast_Timer = 5000; - } - - void UpdateAI(uint32 diff) OVERRIDE - { - if (VoidBlast_Timer <= diff) - { - DoCastAOE(RAID_MODE(SPELL_VOID_BLAST, SPELL_VOID_BLAST_H)); - ////twilight realm - //DoCastVictim(57620, true); - //DoCastVictim(57874, true); - VoidBlast_Timer = 9000; - me->RemoveAllAuras(); - me->Kill(me); - } else VoidBlast_Timer -= diff; - } - }; - -}; - -/*###### -## Mob Twilight Whelps -######*/ - -class npc_twilight_whelp : public CreatureScript -{ -public: - npc_twilight_whelp() : CreatureScript("npc_twilight_whelp") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_twilight_whelpAI(creature); - } - - struct npc_twilight_whelpAI : public ScriptedAI - { - npc_twilight_whelpAI(Creature* creature) : ScriptedAI(creature) - { - Reset(); - } - - uint32 m_uiFadeArmorTimer; - - void Reset() OVERRIDE - { - me->RemoveAllAuras(); - me->SetInCombatWithZone(); - m_uiFadeArmorTimer = 1000; - } - - void UpdateAI(uint32 uiDiff) OVERRIDE - { - //Return since we have no target - if (!UpdateVictim()) - return; - - // twilight torment - if (m_uiFadeArmorTimer <= uiDiff) - { - DoCastVictim(SPELL_FADE_ARMOR); - m_uiFadeArmorTimer = urand(5000, 10000); - } - else - m_uiFadeArmorTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } - }; - -}; - -class achievement_twilight_assist : public AchievementCriteriaScript -{ - public: - achievement_twilight_assist() : AchievementCriteriaScript("achievement_twilight_assist") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) OVERRIDE - { - if (!target) - return false; - - if (Creature* Sartharion = target->ToCreature()) - if (Sartharion->AI()->GetData(TWILIGHT_ACHIEVEMENTS) >= 1) - return true; - - return false; - } -}; - -class achievement_twilight_duo : public AchievementCriteriaScript -{ - public: - achievement_twilight_duo() : AchievementCriteriaScript("achievement_twilight_duo") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) OVERRIDE - { - if (!target) - return false; - - if (Creature* Sartharion = target->ToCreature()) - if (Sartharion->AI()->GetData(TWILIGHT_ACHIEVEMENTS) >= 2) - return true; - - return false; - } -}; - -class achievement_twilight_zone : public AchievementCriteriaScript -{ - public: - achievement_twilight_zone() : AchievementCriteriaScript("achievement_twilight_zone") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) OVERRIDE - { - if (!target) - return false; - - if (Creature* Sartharion = target->ToCreature()) - if (Sartharion->AI()->GetData(TWILIGHT_ACHIEVEMENTS) == 3) - return true; - - return false; - } }; void AddSC_boss_sartharion() { new boss_sartharion(); - new npc_vesperon(); - new npc_shadron(); - new npc_tenebron(); - new npc_acolyte_of_shadron(); - new npc_acolyte_of_vesperon(); - new npc_twilight_eggs(); - new npc_flame_tsunami(); - new npc_twilight_fissure(); - new npc_twilight_whelp(); - new achievement_twilight_assist(); - new achievement_twilight_duo(); - new achievement_twilight_zone(); } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp index ace2258ac9f..ad1346e7f37 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp @@ -19,8 +19,6 @@ #include "InstanceScript.h" #include "obsidian_sanctum.h" -#define MAX_ENCOUNTER 1 - /* Obsidian Sanctum encounters: 0 - Sartharion */ @@ -28,48 +26,18 @@ class instance_obsidian_sanctum : public InstanceMapScript { public: - instance_obsidian_sanctum() : InstanceMapScript("instance_obsidian_sanctum", 615) { } - - InstanceScript* GetInstanceScript(InstanceMap* map) const OVERRIDE - { - return new instance_obsidian_sanctum_InstanceMapScript(map); - } + instance_obsidian_sanctum() : InstanceMapScript(OSScriptName, 615) { } struct instance_obsidian_sanctum_InstanceMapScript : public InstanceScript { instance_obsidian_sanctum_InstanceMapScript(Map* map) : InstanceScript(map) { } - uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint64 m_uiSartharionGUID; - uint64 m_uiTenebronGUID; - uint64 m_uiShadronGUID; - uint64 m_uiVesperonGUID; - - bool m_bTenebronKilled; - bool m_bShadronKilled; - bool m_bVesperonKilled; - void Initialize() OVERRIDE { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiSartharionGUID = 0; - m_uiTenebronGUID = 0; - m_uiShadronGUID = 0; - m_uiVesperonGUID = 0; - - m_bTenebronKilled = false; - m_bShadronKilled = false; - m_bVesperonKilled = false; - } - - bool IsEncounterInProgress() const OVERRIDE - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; + sartharionGUID = 0; + tenebronGUID = 0; + shadronGUID = 0; + vesperonGUID = 0; } void OnCreatureCreate(Creature* creature) OVERRIDE @@ -77,68 +45,113 @@ public: switch (creature->GetEntry()) { case NPC_SARTHARION: - m_uiSartharionGUID = creature->GetGUID(); + sartharionGUID = creature->GetGUID(); break; - //three dragons below set to active state once created. - //we must expect bigger raid to encounter main boss, and then three dragons must be active due to grid differences + // Three dragons below set to active state once created. + // We must expect bigger raid to encounter main boss, and then three dragons must be active due to grid differences case NPC_TENEBRON: - m_uiTenebronGUID = creature->GetGUID(); + tenebronGUID = creature->GetGUID(); creature->setActive(true); break; case NPC_SHADRON: - m_uiShadronGUID = creature->GetGUID(); + shadronGUID = creature->GetGUID(); creature->setActive(true); break; case NPC_VESPERON: - m_uiVesperonGUID = creature->GetGUID(); + vesperonGUID = creature->GetGUID(); creature->setActive(true); break; } } - void SetData(uint32 uiType, uint32 uiData) OVERRIDE - { - if (uiType == TYPE_SARTHARION_EVENT) - m_auiEncounter[0] = uiData; - else if (uiType == TYPE_TENEBRON_PREKILLED) - m_bTenebronKilled = true; - else if (uiType == TYPE_SHADRON_PREKILLED) - m_bShadronKilled = true; - else if (uiType == TYPE_VESPERON_PREKILLED) - m_bVesperonKilled = true; - } - - uint32 GetData(uint32 uiType) const OVERRIDE + bool SetBossState(uint32 type, EncounterState state) OVERRIDE { - if (uiType == TYPE_SARTHARION_EVENT) - return m_auiEncounter[0]; - else if (uiType == TYPE_TENEBRON_PREKILLED) - return m_bTenebronKilled; - else if (uiType == TYPE_SHADRON_PREKILLED) - return m_bShadronKilled; - else if (uiType == TYPE_VESPERON_PREKILLED) - return m_bVesperonKilled; + if (!InstanceScript::SetBossState(type, state)) + return false; - return 0; + switch (type) + { + case DATA_SARTHARION: + case DATA_TENEBRON: + case DATA_SHADRON: + case DATA_VESPERON: + break; + default: + break; + } + return true; } - uint64 GetData64(uint32 uiData) const OVERRIDE + uint64 GetData64(uint32 Data) const OVERRIDE { - switch (uiData) + switch (Data) { case DATA_SARTHARION: - return m_uiSartharionGUID; + return sartharionGUID; case DATA_TENEBRON: - return m_uiTenebronGUID; + return tenebronGUID; case DATA_SHADRON: - return m_uiShadronGUID; + return shadronGUID; case DATA_VESPERON: - return m_uiVesperonGUID; + return vesperonGUID; } return 0; } + + std::string GetSaveData() OVERRIDE + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "O S " << GetBossSaveData(); + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); + } + + void Load(const char* str) OVERRIDE + { + if (!str) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(str); + + char dataHead1, dataHead2; + + std::istringstream loadStream(str); + loadStream >> dataHead1 >> dataHead2; + + if (dataHead1 == 'O' && dataHead2 == 'S') + { + for (uint32 i = 0; i < EncounterCount; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + SetBossState(i, EncounterState(tmpState)); + } + } + else + OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } + + protected: + uint64 sartharionGUID; + uint64 tenebronGUID; + uint64 shadronGUID; + uint64 vesperonGUID; }; + InstanceScript* GetInstanceScript(InstanceMap* map) const OVERRIDE + { + return new instance_obsidian_sanctum_InstanceMapScript(map); + } }; void AddSC_instance_obsidian_sanctum() diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp new file mode 100644 index 00000000000..f8d8b0106c5 --- /dev/null +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp @@ -0,0 +1,1183 @@ +/* + * Copyright (C) 2008-2013 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "Cell.h" +#include "CellImpl.h" +#include "obsidian_sanctum.h" + +enum Enums +{ + WHISPER_HATCH_EGGS = 6, + WHISPER_OPEN_PORTAL = 6, // whisper, shared by two dragons + + //Mini bosses common spells + SPELL_TWILIGHT_RESIDUE = 61885, // makes immune to shadow damage, applied when leave phase + + //Miniboses (Vesperon, Shadron, Tenebron) + SPELL_SHADOW_BREATH_H = 59126, // Inflicts 8788 to 10212 Fire damage to enemies in a cone in front of the caster. + SPELL_SHADOW_BREATH = 57570, // Inflicts 6938 to 8062 Fire damage to enemies in a cone in front of the caster. + + SPELL_SHADOW_FISSURE_H = 59127, // Deals 9488 to 13512 Shadow damage to any enemy within the Shadow fissure after 5 sec. + SPELL_SHADOW_FISSURE = 57579, // Deals 6188 to 8812 Shadow damage to any enemy within the Shadow fissure after 5 sec. + + //Vesperon + //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times + NPC_ACOLYTE_OF_VESPERON = 31219, // Acolyte of Vesperon + SPELL_POWER_OF_VESPERON = 61251, // Vesperon's presence decreases the maximum health of all enemies by 25%. + SPELL_TWILIGHT_TORMENT_VESP = 57948, // (Shadow only) trigger 57935 then 57988 + SPELL_TWILIGHT_TORMENT_VESP_ACO = 58853, // (Fire and Shadow) trigger 58835 then 57988 + + //Shadron + //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times + NPC_ACOLYTE_OF_SHADRON = 31218, // Acolyte of Shadron + SPELL_POWER_OF_SHADRON = 58105, // Shadron's presence increases Fire damage taken by all enemies by 100%. + SPELL_GIFT_OF_TWILIGTH_SHA = 57835, // TARGET_SCRIPT shadron + SPELL_GIFT_OF_TWILIGTH_SAR = 58766, // TARGET_SCRIPT sartharion + SPELL_VOID_BLAST = 57581, // Twilight Fissure + SPELL_VOID_BLAST_H = 59128, + + //Tenebron + //in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 + SPELL_POWER_OF_TENEBRON = 61248, // Tenebron's presence increases Shadow damage taken by all enemies by 100%. + //Tenebron, dummy spell + SPELL_SUMMON_TWILIGHT_WHELP = 58035, // doesn't work, will spawn NPC_TWILIGHT_WHELP + SPELL_SUMMON_SARTHARION_TWILIGHT_WHELP = 58826, // doesn't work, will spawn NPC_SHARTHARION_TWILIGHT_WHELP + SPELL_TWILIGHT_REVENGE = 60639, + SPELL_HATCH_EGGS_H = 59189, + SPELL_HATCH_EGGS = 58542, + SPELL_HATCH_EGGS_EFFECT_H = 59190, + SPELL_HATCH_EGGS_EFFECT = 58685, + NPC_TWILIHT_WHELP = 31214, + NPC_TWILIGHT_EGG = 30882, + NPC_SARTHARION_TWILIGHT_EGG = 31204, + + SPELL_TWILIGHT_SHIFT_ENTER = 57620, // enter phase. Player get this when click GO + SPELL_TWILIGHT_SHIFT = 57874, // Twilight Shift Aura + SPELL_TWILIGHT_SHIFT_REMOVAL = 61187, // leave phase + SPELL_TWILIGHT_SHIFT_REMOVAL_ALL = 61190, // leave phase (probably version to make all leave) + + //Whelps + NPC_TWILIGHT_WHELP = 30890, + NPC_SHARTHARION_TWILIGHT_WHELP = 31214, + SPELL_FADE_ARMOR = 60708, // Reduces the armor of an enemy by 1500 for 15s + + //flame tsunami + SPELL_FLAME_TSUNAMI = 57494, // the visual dummy + SPELL_FLAME_TSUNAMI_LEAP = 60241, // SPELL_EFFECT_138 some leap effect, causing caster to move in direction + + SPELL_FLAME_TSUNAMI_DMG_AURA = 57491, // periodic damage, npc has this aura + SPELL_FLAME_TSUNAMI_BUFF = 60430, + NPC_LAVA_BLAZE = 30643, // adds spawning from flame strike + + //using these custom points for dragons start and end + POINT_ID_INIT = 100, + POINT_ID_LAND = 200 +}; + +enum Misc +{ + DATA_CAN_LOOT = 0 +}; + +struct Location +{ + float x, y, z; +}; + +struct Locations +{ + float x, y, z; +}; + +struct Waypoint +{ + float m_fX, m_fY, m_fZ; +}; + +#define MAX_WAYPOINT 6 +//points around raid "isle", counter clockwise. should probably be adjusted to be more alike +Waypoint dragonCommon[MAX_WAYPOINT]= +{ + {3214.012f, 468.932f, 98.652f}, + {3244.950f, 468.427f, 98.652f}, + {3283.520f, 496.869f, 98.652f}, + {3287.316f, 555.875f, 98.652f}, + {3250.479f, 585.827f, 98.652f}, + {3209.969f, 566.523f, 98.652f} +}; + +static Location AcolyteofShadron = { 3363.92f, 534.703f, 97.2683f }; +static Location AcolyteofShadron2 = { 3246.57f, 551.263f, 58.6164f }; +static Location AcolyteofVesperon = { 3145.68f, 520.71f, 89.7f }; +static Location AcolyteofVesperon2 = { 3246.57f, 551.263f, 58.6164f }; + +Locations TwilightEggs[] = +{ + {3219.28f, 669.121f, 88.5549f}, + {3221.55f, 682.852f, 90.5361f}, + {3239.77f, 685.94f, 90.3168f}, + {3250.33f, 669.749f, 88.7637f}, + {3246.6f, 642.365f, 84.8752f}, + {3233.68f, 653.117f, 85.7051f} +}; +Locations TwilightEggsSarth[] = +{ + {3252.73f, 515.762f, 58.5501f}, + {3256.56f, 521.119f, 58.6061f}, + {3255.63f, 527.513f, 58.7568f}, + {3264.90f, 525.865f, 58.6436f}, + {3264.26f, 516.364f, 58.8011f}, + {3257.54f, 502.285f, 58.2077f} +}; + +enum SharedTextIDs +{ + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_DEATH = 2, + SAY_BREATH = 3, + SAY_RESPOND = 4, + SAY_SPECIAL = 5 +}; + +enum DummyDragonEvents +{ + EVENT_FREE_MOVEMENT = 1 +}; + +//to control each dragons common abilities +struct dummy_dragonAI : public ScriptedAI +{ + dummy_dragonAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() OVERRIDE + { + if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + waypointId = 0; + portalRespawnTime = 30000; + _canMoveFree = false; + _canLoot = true; + } + + void SetData(uint32 type, uint32 value) OVERRIDE + { + if (type == DATA_CAN_LOOT) + _canLoot = value; + } + + void MovementInform(uint32 type, uint32 pointId) OVERRIDE + { + if (!instance || type != POINT_MOTION_TYPE) + return; + + // debug_log("dummy_dragonAI: %s reached point %u", me->GetName(), uiPointId); + + // if healers messed up the raid and we was already initialized + if (instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS) + { + EnterEvadeMode(); + return; + } + + // this is end, if we reach this, don't do much + if (pointId == POINT_ID_LAND) + { + me->GetMotionMaster()->Clear(); + me->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) + { + me->AddThreat(target, 1.0f); + me->Attack(target, true); + me->GetMotionMaster()->MoveChase(target); + } + + _canMoveFree = false; + return; + } + + // get amount of common points + uint32 commonWPCount = sizeof(dragonCommon)/sizeof(Waypoint); + + // increase + waypointId = pointId+1; + + // if we have reached a point bigger or equal to count, it mean we must reset to point 0 + if (waypointId >= commonWPCount) + { + if (!_canMoveFree) + _canMoveFree = true; + + waypointId = 0; + } + + events.ScheduleEvent(EVENT_FREE_MOVEMENT, 500); + } + + // used when open portal and spawn mobs in phase + void DoRaidWhisper(int32 iTextId) + { + Map* map = me->GetMap(); + + if (map && map->IsDungeon()) + { + Map::PlayerList const &PlayerList = map->GetPlayers(); + + if (!PlayerList.isEmpty()) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + Talk(iTextId, i->GetSource()->GetGUID()); + } + } + } + + // "opens" the portal and does the "opening" whisper + void OpenPortal() + { + int32 textId = 0; + + // there are 4 portal spawn locations, each are expected to be spawned with negative spawntimesecs in database + + // using a grid search here seem to be more efficient than caching all four guids + // in instance script and calculate range to each. + GameObject* portal = me->FindNearestGameObject(GO_TWILIGHT_PORTAL, 50.0f); + + switch (me->GetEntry()) + { + case NPC_TENEBRON: + { + textId = WHISPER_HATCH_EGGS; + if (instance && !instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS) + { + for (uint32 i = 0; i < 6; ++i) + me->SummonCreature(NPC_TWILIGHT_EGG, TwilightEggs[i].x, TwilightEggs[i].y, TwilightEggs[i].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000); + } + else + { + for (uint32 i = 0; i < 6; ++i) + me->SummonCreature(NPC_SARTHARION_TWILIGHT_EGG, TwilightEggsSarth[i].x, TwilightEggsSarth[i].y, TwilightEggsSarth[i].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000); + } + break; + } + case NPC_SHADRON: + { + textId = WHISPER_OPEN_PORTAL; + if (instance && !instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS) + me->SummonCreature(NPC_ACOLYTE_OF_SHADRON, AcolyteofShadron.x, AcolyteofShadron.y, AcolyteofShadron.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 28000); + else + me->SummonCreature(NPC_ACOLYTE_OF_SHADRON, AcolyteofShadron2.x, AcolyteofShadron2.y, AcolyteofShadron2.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 28000); + + break; + } + case NPC_VESPERON: + { + textId = WHISPER_OPEN_PORTAL; + if (instance && !instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS) + { + if (Creature* acolyte = me->SummonCreature(NPC_ACOLYTE_OF_VESPERON, AcolyteofVesperon.x, AcolyteofVesperon.y, AcolyteofVesperon.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000)) + { + me->InterruptNonMeleeSpells(true); + acolyte->InterruptNonMeleeSpells(true); + me->CastSpell(me, 32747, false); + } + } + else + { + if (Creature* acolyte = me->SummonCreature(NPC_ACOLYTE_OF_VESPERON, AcolyteofVesperon2.x, AcolyteofVesperon2.y, AcolyteofVesperon2.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000)) + { + me->InterruptNonMeleeSpells(true); + acolyte->InterruptNonMeleeSpells(true); + me->CastSpell(me, 32747, false); + } + } + + break; + } + } + + DoRaidWhisper(textId); + + // By using SetRespawnTime() we will actually "spawn" the object with our defined time. + // Once time is up, portal will disappear again. + if (portal && !portal->isSpawned()) + portal->SetRespawnTime(portalRespawnTime); + + // Unclear what are expected to happen if one drake has a portal open already + // Refresh respawnTime so time again are set to 30secs? + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + if (!_canLoot) + me->SetLootRecipient(NULL); + + uint32 spellId = 0; + + switch (me->GetEntry()) + { + case NPC_TENEBRON: + spellId = SPELL_POWER_OF_TENEBRON; + if (instance && instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS) + instance->SetBossState(DATA_TENEBRON, DONE); + break; + case NPC_SHADRON: + spellId = SPELL_POWER_OF_SHADRON; + if (instance && instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS) + instance->SetBossState(DATA_SHADRON, DONE); + if (Creature* acolyte = me->FindNearestCreature(NPC_ACOLYTE_OF_SHADRON, 100.0f)) + acolyte->Kill(acolyte); + break; + case NPC_VESPERON: + spellId = SPELL_POWER_OF_VESPERON; + if (instance && instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS) + instance->SetBossState(DATA_VESPERON, DONE); + if (Creature* acolyte = me->FindNearestCreature(NPC_ACOLYTE_OF_VESPERON, 100.0f)) + acolyte->Kill(acolyte); + break; + } + + Talk(SAY_DEATH); + me->RemoveAurasDueToSpell(spellId); + + if (instance) + { + instance->DoRemoveAurasDueToSpellOnPlayers(spellId); + + // not if solo mini-boss fight + if (instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS) + return; + + // Twilight Revenge to main boss + if (Unit* sartharion = Unit::GetUnit(*me, instance->GetData64(DATA_SARTHARION))) + if (sartharion->IsAlive()) + { + sartharion->RemoveAurasDueToSpell(spellId); + DoCast(sartharion, SPELL_TWILIGHT_REVENGE, true); + } + } + } + + void UpdateAI(uint32 diff) OVERRIDE + { + events.Update(diff); + + if (events.ExecuteEvent() == EVENT_FREE_MOVEMENT) + { + if (_canMoveFree && waypointId < MAX_WAYPOINT) + me->GetMotionMaster()->MovePoint(waypointId, dragonCommon[waypointId].m_fX, dragonCommon[waypointId].m_fY, dragonCommon[waypointId].m_fZ); + } + } + + private: + InstanceScript* instance; + EventMap events; + uint32 waypointId; + int32 portalRespawnTime; + bool _canMoveFree; + bool _canLoot; +}; + +/*###### +## Tenebron +######*/ + +enum TenebronEvents +{ + EVENT_SHADOW_FISSURE_TENEBRON = 2, + EVENT_HATCH_EGGS = 3, + EVENT_SHADOW_BREATH_TENEBRON = 4 +}; + +class npc_tenebron : public CreatureScript +{ +public: + npc_tenebron() : CreatureScript("npc_tenebron") { } + + struct npc_tenebronAI : public dummy_dragonAI + { + npc_tenebronAI(Creature* creature) : dummy_dragonAI(creature) { } + + void Reset() OVERRIDE + { + dummy_dragonAI::Reset(); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + Talk(SAY_AGGRO); + DoZoneInCombat(); + events.ScheduleEvent(EVENT_SHADOW_FISSURE_TENEBRON, 5000); + events.ScheduleEvent(EVENT_HATCH_EGGS, 30000); + events.ScheduleEvent(EVENT_SHADOW_BREATH_TENEBRON, 20000); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE + { + Talk(SAY_SLAY); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(diff); + return; + } + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHADOW_FISSURE_TENEBRON: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE)); + events.ScheduleEvent(EVENT_SHADOW_FISSURE_TENEBRON, urand(15000, 20000)); + break; + case EVENT_HATCH_EGGS: + OpenPortal(); + events.ScheduleEvent(EVENT_HATCH_EGGS, 30000); + break; + case EVENT_SHADOW_BREATH_TENEBRON: + Talk(SAY_BREATH); + DoCastVictim(RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); + events.ScheduleEvent(EVENT_SHADOW_BREATH_TENEBRON, urand(20000, 25000)); + break; + } + } + DoMeleeAttackIfReady(); + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_tenebronAI(creature); + } +}; + +/*###### +## Shadron +######*/ + +enum ShadronEvents +{ + EVENT_SHADOW_FISSURE_SHADRON = 5, + EVENT_ACOLYTE_SHADRON = 6, + EVENT_SHADOW_BREATH_SHADRON = 7 +}; + +class npc_shadron : public CreatureScript +{ +public: + npc_shadron() : CreatureScript("npc_shadron") { } + + struct npc_shadronAI : public dummy_dragonAI + { + npc_shadronAI(Creature* creature) : dummy_dragonAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() OVERRIDE + { + dummy_dragonAI::Reset(); + + if (me->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) + me->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + + if (me->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) + me->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); + + if (instance) + instance->SetBossState(DATA_PORTAL_OPEN, NOT_STARTED); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + Talk(SAY_AGGRO); + DoZoneInCombat(); + events.ScheduleEvent(EVENT_SHADOW_FISSURE_SHADRON, 5000); + events.ScheduleEvent(EVENT_ACOLYTE_SHADRON, 60000); + events.ScheduleEvent(EVENT_SHADOW_BREATH_SHADRON, 20000); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE + { + Talk(SAY_SLAY); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(diff); + return; + } + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHADOW_FISSURE_SHADRON: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE_H)); + events.ScheduleEvent(EVENT_SHADOW_FISSURE_SHADRON, urand(15000, 20000)); + break; + case EVENT_ACOLYTE_SHADRON: + if (instance->GetBossState(DATA_PORTAL_OPEN) == NOT_STARTED) + events.ScheduleEvent(EVENT_ACOLYTE_SHADRON, 10000); + else + { + if (me->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) + return; + + OpenPortal(); + + if (instance) + instance->SetBossState(DATA_PORTAL_OPEN, IN_PROGRESS); + + events.ScheduleEvent(EVENT_ACOLYTE_SHADRON, urand(60000, 65000)); + } + break; + case EVENT_SHADOW_BREATH_SHADRON: + Talk(SAY_BREATH); + DoCastVictim(RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); + events.ScheduleEvent(EVENT_SHADOW_BREATH_SHADRON, urand(20000, 25000)); + break; + } + } + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_shadronAI(creature); + } +}; + +/*###### +## Vesperon +######*/ + +enum VesperonEvents +{ + EVENT_SHADOW_FISSURE_VESPERON = 8, + EVENT_ACOLYTE_VESPERON = 9, + EVENT_SHADOW_BREATH_VESPERON = 10 +}; + +class npc_vesperon : public CreatureScript +{ +public: + npc_vesperon() : CreatureScript("npc_vesperon") { } + + struct npc_vesperonAI : public dummy_dragonAI + { + npc_vesperonAI(Creature* creature) : dummy_dragonAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() OVERRIDE + { + dummy_dragonAI::Reset(); + } + + void EnterCombat(Unit* /*who*/) OVERRIDE + { + Talk(SAY_AGGRO); + DoZoneInCombat(); + events.ScheduleEvent(EVENT_SHADOW_FISSURE_VESPERON, 5000); + events.ScheduleEvent(EVENT_ACOLYTE_VESPERON, 60000); + events.ScheduleEvent(EVENT_SHADOW_BREATH_VESPERON, 20000); + } + + void KilledUnit(Unit* /*victim*/) OVERRIDE + { + Talk(SAY_SLAY); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(diff); + return; + } + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHADOW_FISSURE_VESPERON: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE_H)); + events.ScheduleEvent(EVENT_SHADOW_FISSURE_VESPERON, urand(15000, 20000)); + break; + case EVENT_ACOLYTE_VESPERON: + if (instance->GetBossState(DATA_PORTAL_OPEN) == IN_PROGRESS) + events.ScheduleEvent(EVENT_ACOLYTE_VESPERON, 10000); + else + { + OpenPortal(); + DoCastVictim(SPELL_TWILIGHT_TORMENT_VESP); + events.ScheduleEvent(EVENT_ACOLYTE_VESPERON, urand(60000, 70000)); + } + break; + case EVENT_SHADOW_BREATH_VESPERON: + Talk(SAY_BREATH); + DoCastVictim(RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); + events.ScheduleEvent(EVENT_SHADOW_BREATH_VESPERON, urand(20000, 25000)); + break; + } + } + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_vesperonAI(creature); + } +}; + +/*###### +## Acolyte of Shadron +######*/ + +class npc_acolyte_of_shadron : public CreatureScript +{ +public: + npc_acolyte_of_shadron() : CreatureScript("npc_acolyte_of_shadron") { } + + struct npc_acolyte_of_shadronAI : public ScriptedAI + { + npc_acolyte_of_shadronAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() OVERRIDE + { + // Despawn the NPC automatically after 28 seconds + me->DespawnOrUnsummon(28000); + + if (instance) + { + Creature* target = NULL; + //if not solo figth, buff main boss, else place debuff on mini-boss. both spells TARGET_SCRIPT + if (instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS) + { + if (target = Unit::GetCreature((*me), instance->GetData64(DATA_SARTHARION))) + target->AddAura(SPELL_GIFT_OF_TWILIGTH_SAR, target); + } + else + { + if (target = Unit::GetCreature((*me), instance->GetData64(DATA_SHADRON))) + target->AddAura(SPELL_GIFT_OF_TWILIGTH_SHA, target); + } + } + + me->AddAura(SPELL_TWILIGHT_SHIFT_ENTER, me); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + if (instance) + { + if (Creature* shadron = instance->instance->GetCreature(instance->GetData64(DATA_SHADRON))) + instance->SetBossState(DATA_PORTAL_OPEN, NOT_STARTED); + + Map* map = me->GetMap(); + if (map->IsDungeon()) + { + Map::PlayerList const &PlayerList = map->GetPlayers(); + + if (PlayerList.isEmpty()) + return; + + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (i->GetSource()->IsAlive() && i->GetSource()->HasAura(SPELL_TWILIGHT_SHIFT, 0) && !i->GetSource()->GetVictim()) + { + i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_SHIFT_REMOVAL_ALL, true); + i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_RESIDUE, true); + i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT); + i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT_ENTER); + } + } + } + + //not solo fight, so main boss has deduff + if (Creature* debuffTarget = instance->instance->GetCreature(instance->GetData64(DATA_SARTHARION))) + if (debuffTarget->IsAlive() && debuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SAR)) + debuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SAR); + + //event not in progress, then solo fight and must remove debuff mini-boss + if (Creature* debuffTarget = instance->instance->GetCreature(instance->GetData64(DATA_SHADRON))) + if (debuffTarget->IsAlive() && debuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) + debuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); + } + } + + void UpdateAI(uint32 diff) OVERRIDE + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* instance; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_acolyte_of_shadronAI(creature); + } +}; + +/*###### +## Acolyte of Vesperon +######*/ + +class npc_acolyte_of_vesperon : public CreatureScript +{ +public: + npc_acolyte_of_vesperon() : CreatureScript("npc_acolyte_of_vesperon") { } + + struct npc_acolyte_of_vesperonAI : public ScriptedAI + { + npc_acolyte_of_vesperonAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() OVERRIDE + { + // Despawn the NPC automatically after 28 seconds + me->DespawnOrUnsummon(28000); + + if (instance) + me->AddAura(SPELL_TWILIGHT_SHIFT_ENTER, me); + + DoCast(me, SPELL_TWILIGHT_TORMENT_VESP_ACO); + } + + void JustDied(Unit* /*killer*/) OVERRIDE + { + me->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP_ACO); + + // remove twilight torment on Vesperon + if (instance) + { + if (Creature* vesperon = instance->instance->GetCreature(instance->GetData64(DATA_VESPERON))) + { + instance->SetBossState(DATA_PORTAL_OPEN, NOT_STARTED); + + if (vesperon->IsAlive() && vesperon->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) + vesperon->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + } + + Map* map = me->GetMap(); + if (map->IsDungeon()) + { + Map::PlayerList const &PlayerList = map->GetPlayers(); + + if (PlayerList.isEmpty()) + return; + + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (i->GetSource()->IsAlive() && i->GetSource()->HasAura(SPELL_TWILIGHT_SHIFT, 0) && !i->GetSource()->GetVictim()) + { + i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_SHIFT_REMOVAL_ALL, true); + i->GetSource()->CastSpell(i->GetSource(), SPELL_TWILIGHT_RESIDUE, true); + i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT); + i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_SHIFT_ENTER); + } + if (i->GetSource()->IsAlive() && i->GetSource()->HasAura(SPELL_TWILIGHT_TORMENT_VESP, 0) && !i->GetSource()->GetVictim()) + i->GetSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + } + } + + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_VESP_ACO); + instance->DoRemoveAurasDueToSpellOnPlayers(57935); + instance->DoRemoveAurasDueToSpellOnPlayers(58835); // Components of spell Twilight Torment + } + } + + void UpdateAI(uint32 diff) OVERRIDE + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* instance; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_acolyte_of_vesperonAI(creature); + } +}; + +/*###### +## Twilight Eggs +######*/ + +enum TwilightEggs +{ + EVENT_TWILIGHT_EGGS = 11 +}; + +class npc_twilight_eggs : public CreatureScript +{ +public: + npc_twilight_eggs() : CreatureScript("npc_twilight_eggs") { } + + struct npc_twilight_eggsAI : public ScriptedAI + { + npc_twilight_eggsAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + instance = creature->GetInstanceScript(); + } + + void Reset() OVERRIDE + { + if (instance) + me->AddAura(SPELL_TWILIGHT_SHIFT_ENTER, me); + + events.ScheduleEvent(EVENT_TWILIGHT_EGGS, 20000); + } + + void SpawnWhelps() + { + me->RemoveAllAuras(); + + if (!instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS) + me->SummonCreature(NPC_TWILIGHT_WHELP, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + else + me->SummonCreature(NPC_SHARTHARION_TWILIGHT_WHELP, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + me->DealDamage(me, me->GetHealth()); + } + + void JustSummoned(Creature* who) OVERRIDE + { + who->SetInCombatWithZone(); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + events.Update(diff); + + if (events.ExecuteEvent() == EVENT_TWILIGHT_EGGS) + { + if (Creature* tenebron = instance->instance->GetCreature(instance->GetData64(DATA_TENEBRON))) + instance->SetBossState(DATA_PORTAL_OPEN, NOT_STARTED); + + SpawnWhelps(); + } + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_twilight_eggsAI(creature); + } +}; + +/*###### +## Flame Tsunami +######*/ + +enum FlameTsunami +{ + EVENT_TSUNAMI_TIMER = 12, + EVENT_TSUNAMI_BUFF = 13 +}; + +class npc_flame_tsunami : public CreatureScript +{ +public: + npc_flame_tsunami() : CreatureScript("npc_flame_tsunami") { } + + struct npc_flame_tsunamiAI : public ScriptedAI + { + npc_flame_tsunamiAI(Creature* creature) : ScriptedAI(creature) + { + me->SetDisplayId(11686); + me->AddAura(SPELL_FLAME_TSUNAMI, me); + } + + void Reset() OVERRIDE + { + me->SetReactState(REACT_PASSIVE); + events.ScheduleEvent(EVENT_TSUNAMI_TIMER, 100); + events.ScheduleEvent(EVENT_TSUNAMI_BUFF, 1000); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_TSUNAMI_TIMER: + DoCast(me, SPELL_FLAME_TSUNAMI_DMG_AURA); + events.ScheduleEvent(EVENT_TSUNAMI_TIMER, 500); + break; + case EVENT_TSUNAMI_BUFF: + if (Unit* lavaBlaze = GetClosestCreatureWithEntry(me, NPC_LAVA_BLAZE, 10.0f, true)) + lavaBlaze->CastSpell(lavaBlaze, SPELL_FLAME_TSUNAMI_BUFF, true); + events.ScheduleEvent(EVENT_TSUNAMI_BUFF, 1000); + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_flame_tsunamiAI(creature); + } +}; + +/*###### +## Twilight Fissure +######*/ + +enum TwilightFissure +{ + EVENT_VOID_BLAST = 14 +}; + +class npc_twilight_fissure : public CreatureScript +{ +public: + npc_twilight_fissure() : CreatureScript("npc_twilight_fissure") { } + + struct npc_twilight_fissureAI : public ScriptedAI + { + npc_twilight_fissureAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } + + void Reset() OVERRIDE + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->AddAura( 46265, me ); // Wrong, can't find proper visual + me->AddAura( 69422, me ); + events.ScheduleEvent(EVENT_VOID_BLAST, 5000); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + events.Update(diff); + + if (events.ExecuteEvent() == EVENT_VOID_BLAST) + { + DoCastAOE(RAID_MODE(SPELL_VOID_BLAST, SPELL_VOID_BLAST_H)); + ////twilight realm + //DoCastVictim(57620, true); + //DoCastVictim(57874, true); + me->RemoveAllAuras(); + me->Kill(me); + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_twilight_fissureAI(creature); + } +}; + +/*###### +## Twilight Whelps +######*/ + +enum TwilightWhelps +{ + EVENT_FADE_ARMOR = 15 +}; + +class npc_twilight_whelp : public CreatureScript +{ +public: + npc_twilight_whelp() : CreatureScript("npc_twilight_whelp") { } + + struct npc_twilight_whelpAI : public ScriptedAI + { + npc_twilight_whelpAI(Creature* creature) : ScriptedAI(creature) + { + Reset(); + } + + void Reset() OVERRIDE + { + me->RemoveAllAuras(); + me->SetInCombatWithZone(); + events.ScheduleEvent(EVENT_FADE_ARMOR, 1000); + } + + void UpdateAI(uint32 diff) OVERRIDE + { + if (!UpdateVictim()) + return; + + // twilight torment + events.Update(diff); + + if (events.ExecuteEvent() == EVENT_FADE_ARMOR) + { + DoCastVictim(SPELL_FADE_ARMOR); + events.ScheduleEvent(EVENT_FADE_ARMOR, urand(5000, 10000)); + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const OVERRIDE + { + return new npc_twilight_whelpAI(creature); + } +}; + +class achievement_twilight_assist : public AchievementCriteriaScript +{ + public: + achievement_twilight_assist() : AchievementCriteriaScript("achievement_twilight_assist") { } + + bool OnCheck(Player* /*player*/, Unit* target) OVERRIDE + { + if (!target) + return false; + + if (Creature* sartharion = target->ToCreature()) + if (sartharion->AI()->GetData(TWILIGHT_ACHIEVEMENTS) >= 1) + return true; + + return false; + } +}; + +class achievement_twilight_duo : public AchievementCriteriaScript +{ + public: + achievement_twilight_duo() : AchievementCriteriaScript("achievement_twilight_duo") { } + + bool OnCheck(Player* /*player*/, Unit* target) OVERRIDE + { + if (!target) + return false; + + if (Creature* sartharion = target->ToCreature()) + if (sartharion->AI()->GetData(TWILIGHT_ACHIEVEMENTS) >= 2) + return true; + + return false; + } +}; + +class achievement_twilight_zone : public AchievementCriteriaScript +{ + public: + achievement_twilight_zone() : AchievementCriteriaScript("achievement_twilight_zone") { } + + bool OnCheck(Player* /*player*/, Unit* target) OVERRIDE + { + if (!target) + return false; + + if (Creature* sartharion = target->ToCreature()) + if (sartharion->AI()->GetData(TWILIGHT_ACHIEVEMENTS) == 3) + return true; + + return false; + } +}; + +void AddSC_obsidian_sanctum() +{ + new npc_vesperon(); + new npc_shadron(); + new npc_tenebron(); + new npc_acolyte_of_shadron(); + new npc_acolyte_of_vesperon(); + new npc_twilight_eggs(); + new npc_flame_tsunami(); + new npc_twilight_fissure(); + new npc_twilight_whelp(); + new achievement_twilight_assist(); + new achievement_twilight_duo(); + new achievement_twilight_zone(); +} + diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h index 7d2403be469..8cfb3931372 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h @@ -18,17 +18,18 @@ #ifndef DEF_OBSIDIAN_SANCTUM_H #define DEF_OBSIDIAN_SANCTUM_H +#define OSScriptName "instance_obsidian_sanctum" + +uint32 const EncounterCount = 5; + enum DataTypes { - TYPE_SARTHARION_EVENT = 1, - TYPE_TENEBRON_PREKILLED = 2, - TYPE_SHADRON_PREKILLED = 3, - TYPE_VESPERON_PREKILLED = 4, - - DATA_SARTHARION = 10, - DATA_TENEBRON = 11, - DATA_SHADRON = 12, - DATA_VESPERON = 13 + DATA_SARTHARION = 0, + DATA_TENEBRON = 1, + DATA_SHADRON = 2, + DATA_VESPERON = 3, + DATA_PORTAL_OPEN = 4, + TWILIGHT_ACHIEVEMENTS = 5 }; enum CreaturesIds -- cgit v1.2.3