From 46b56ac036ca539c745944e48820ac1a99b362ac Mon Sep 17 00:00:00 2001 From: Aokromes Date: Mon, 7 Nov 2011 14:23:14 +0100 Subject: Scripts/Misc Capitalize lowercase directories --- .../Northrend/AzjolNerub/Ahnkahet/ahnkahet.h | 50 + .../AzjolNerub/Ahnkahet/boss_amanitar.cpp | 228 +++ .../AzjolNerub/Ahnkahet/boss_elder_nadox.cpp | 325 ++++ .../AzjolNerub/Ahnkahet/boss_herald_volazj.cpp | 326 ++++ .../Ahnkahet/boss_jedoga_shadowseeker.cpp | 626 +++++++ .../AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp | 417 +++++ .../AzjolNerub/Ahnkahet/instance_ahnkahet.cpp | 308 ++++ .../Northrend/AzjolNerub/ahnkahet/ahnkahet.h | 50 - .../AzjolNerub/ahnkahet/boss_amanitar.cpp | 228 --- .../AzjolNerub/ahnkahet/boss_elder_nadox.cpp | 325 ---- .../AzjolNerub/ahnkahet/boss_herald_volazj.cpp | 326 ---- .../ahnkahet/boss_jedoga_shadowseeker.cpp | 626 ------- .../AzjolNerub/ahnkahet/boss_prince_taldaram.cpp | 417 ----- .../AzjolNerub/ahnkahet/instance_ahnkahet.cpp | 308 ---- .../Northrend/Ulduar/Ulduar/boss_algalon.cpp | 376 +++++ .../Ulduar/Ulduar/boss_assembly_of_iron.cpp | 812 +++++++++ .../Northrend/Ulduar/Ulduar/boss_auriaya.cpp | 588 +++++++ .../Ulduar/Ulduar/boss_flame_leviathan.cpp | 1755 ++++++++++++++++++++ .../scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp | 1717 +++++++++++++++++++ .../Northrend/Ulduar/Ulduar/boss_general_vezax.cpp | 514 ++++++ .../scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp | 1013 +++++++++++ .../scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp | 495 ++++++ .../Northrend/Ulduar/Ulduar/boss_kologarn.cpp | 658 ++++++++ .../Northrend/Ulduar/Ulduar/boss_mimiron.cpp | 120 ++ .../Northrend/Ulduar/Ulduar/boss_razorscale.cpp | 1103 ++++++++++++ .../Northrend/Ulduar/Ulduar/boss_thorim.cpp | 106 ++ .../scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp | 1091 ++++++++++++ .../Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp | 58 + .../Northrend/Ulduar/Ulduar/instance_ulduar.cpp | 647 ++++++++ .../scripts/Northrend/Ulduar/Ulduar/ulduar.h | 215 +++ .../Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp | 123 ++ .../Northrend/Ulduar/ulduar/boss_algalon.cpp | 376 ----- .../Ulduar/ulduar/boss_assembly_of_iron.cpp | 812 --------- .../Northrend/Ulduar/ulduar/boss_auriaya.cpp | 588 ------- .../Ulduar/ulduar/boss_flame_leviathan.cpp | 1755 -------------------- .../scripts/Northrend/Ulduar/ulduar/boss_freya.cpp | 1717 ------------------- .../Northrend/Ulduar/ulduar/boss_general_vezax.cpp | 514 ------ .../scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp | 1013 ----------- .../scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp | 495 ------ .../Northrend/Ulduar/ulduar/boss_kologarn.cpp | 658 -------- .../Northrend/Ulduar/ulduar/boss_mimiron.cpp | 120 -- .../Northrend/Ulduar/ulduar/boss_razorscale.cpp | 1103 ------------ .../Northrend/Ulduar/ulduar/boss_thorim.cpp | 106 -- .../scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp | 1091 ------------ .../Northrend/Ulduar/ulduar/boss_yoggsaron.cpp | 58 - .../Northrend/Ulduar/ulduar/instance_ulduar.cpp | 647 -------- .../scripts/Northrend/Ulduar/ulduar/ulduar.h | 215 --- .../Northrend/Ulduar/ulduar/ulduar_teleporter.cpp | 123 -- 48 files changed, 13671 insertions(+), 13671 deletions(-) create mode 100644 src/server/scripts/Northrend/AzjolNerub/Ahnkahet/ahnkahet.h create mode 100644 src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp create mode 100644 src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp create mode 100644 src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp create mode 100644 src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp create mode 100644 src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp create mode 100644 src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp delete mode 100644 src/server/scripts/Northrend/AzjolNerub/ahnkahet/ahnkahet.h delete mode 100644 src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_amanitar.cpp delete mode 100644 src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_elder_nadox.cpp delete mode 100644 src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_herald_volazj.cpp delete mode 100644 src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp delete mode 100644 src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_prince_taldaram.cpp delete mode 100644 src/server/scripts/Northrend/AzjolNerub/ahnkahet/instance_ahnkahet.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_algalon.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_auriaya.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_mimiron.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_thorim.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/boss_yoggsaron.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h delete mode 100644 src/server/scripts/Northrend/Ulduar/ulduar/ulduar_teleporter.cpp (limited to 'src') diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/ahnkahet.h b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/ahnkahet.h new file mode 100644 index 00000000000..e19054d2f46 --- /dev/null +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/ahnkahet.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008-2011 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 DEF_AHNKAHET_H +#define DEF_AHNKAHET_H + +enum Data64 +{ + DATA_ELDER_NADOX, + DATA_PRINCE_TALDARAM, + DATA_JEDOGA_SHADOWSEEKER, + DATA_HERALD_VOLAZJ, + DATA_AMANITAR, + DATA_SPHERE1, + DATA_SPHERE2, + DATA_PRINCE_TALDARAM_PLATFORM, + DATA_PL_JEDOGA_TARGET, + DATA_ADD_JEDOGA_OPFER, + DATA_ADD_JEDOGA_INITIAND +}; + +enum Data +{ + DATA_ELDER_NADOX_EVENT, + DATA_PRINCE_TALDARAM_EVENT, + DATA_JEDOGA_SHADOWSEEKER_EVENT, + DATA_HERALD_VOLAZJ_EVENT, + DATA_AMANITAR_EVENT, + DATA_SPHERE1_EVENT, + DATA_SPHERE2_EVENT, + DATA_JEDOGA_TRIGGER_SWITCH, + DATA_JEDOGA_RESET_INITIANDS, + DATA_ALL_INITIAND_DEAD +}; + +#endif diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp new file mode 100644 index 00000000000..cde97f8d37b --- /dev/null +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2008-2011 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 . + */ + +/* + * Comment: Find correct mushrooms spell to make them visible - buffs of the mushrooms not ever applied to the users... + */ + +#include "ScriptPCH.h" +#include "ahnkahet.h" + +enum Spells +{ + SPELL_BASH = 57094, // Victim + SPELL_ENTANGLING_ROOTS = 57095, // Random Victim 100Y + SPELL_MINI = 57055, // Self + SPELL_VENOM_BOLT_VOLLEY = 57088, // Random Victim 100Y + SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS = 56648, // Killer 3Y + SPELL_POISONOUS_MUSHROOM_POISON_CLOUD = 57061, // Self - Duration 8 Sec + SPELL_POISONOUS_MUSHROOM_VISUAL_AREA = 61566, // Self + SPELL_POISONOUS_MUSHROOM_VISUAL_AURA = 56741, // Self + SPELL_PUTRID_MUSHROOM = 31690, // To make the mushrooms visible +}; + +enum Creatures +{ + NPC_HEALTHY_MUSHROOM = 30391, + NPC_POISONOUS_MUSHROOM = 30435 +}; + +class boss_amanitar : public CreatureScript +{ +public: + boss_amanitar() : CreatureScript("boss_amanitar") { } + + struct boss_amanitarAI : public ScriptedAI + { + boss_amanitarAI(Creature* c) : ScriptedAI(c) + { + instance = c->GetInstanceScript(); + bFirstTime = true; + } + + InstanceScript* instance; + + uint32 uiRootTimer; + uint32 uiBashTimer; + uint32 uiBoltTimer; + uint32 uiSpawnTimer; + + bool bFirstTime; + + void Reset() + { + uiRootTimer = urand(5*IN_MILLISECONDS, 9*IN_MILLISECONDS); + uiBashTimer = urand(10*IN_MILLISECONDS, 14*IN_MILLISECONDS); + uiBoltTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + uiSpawnTimer = 0; + + me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + + if (instance) + { + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI); + if (!bFirstTime) + instance->SetData(DATA_AMANITAR_EVENT, FAIL); + else + bFirstTime = false; + } + } + + void JustDied(Unit* /*Killer*/) + { + if (instance) + { + instance->SetData(DATA_AMANITAR_EVENT, DONE); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI); + } + } + + void EnterCombat(Unit* /*who*/) + { + if (instance) + instance->SetData(DATA_AMANITAR_EVENT, IN_PROGRESS); + + DoCast(me, SPELL_MINI, false); + } + + void SpawnAdds() + { + for (uint8 i = 0; i < 30; ++i) + { + Unit* victim = SelectTarget(SELECT_TARGET_RANDOM, 0); + + if (victim) + { + Position pos; + victim->GetPosition(&pos); + me->GetRandomNearPosition(pos, float(urand(5, 80))); + me->SummonCreature(NPC_POISONOUS_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30*IN_MILLISECONDS); + me->GetRandomNearPosition(pos, float(urand(5, 80))); + me->SummonCreature(NPC_HEALTHY_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30*IN_MILLISECONDS); + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiSpawnTimer <= diff) + { + SpawnAdds(); + uiSpawnTimer = urand(35*IN_MILLISECONDS, 40*IN_MILLISECONDS); + } else uiSpawnTimer -= diff; + + if (uiRootTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(target, SPELL_ENTANGLING_ROOTS); + uiRootTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } else uiRootTimer -= diff; + + if (uiBashTimer <= diff) + { + DoCastVictim(SPELL_BASH); + uiBashTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } else uiBashTimer -= diff; + + if (uiBoltTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(target, SPELL_VENOM_BOLT_VOLLEY); + uiBoltTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } else uiBoltTimer -= diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_amanitarAI(creature); + } +}; + +class mob_amanitar_mushrooms : public CreatureScript +{ +public: + mob_amanitar_mushrooms() : CreatureScript("mob_amanitar_mushrooms") { } + + struct mob_amanitar_mushroomsAI : public Scripted_NoMovementAI + { + mob_amanitar_mushroomsAI(Creature* c) : Scripted_NoMovementAI(c) {} + + uint32 uiAuraTimer; + uint32 uiDeathTimer; + + void Reset() + { + DoCast(me, SPELL_PUTRID_MUSHROOM, true); // Hack, to make the mushrooms visible, can't find orig. spell... + + if (me->GetEntry() == NPC_POISONOUS_MUSHROOM) + DoCast(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AURA, true); + + uiAuraTimer = 0; + uiDeathTimer = 30*IN_MILLISECONDS; + } + + void JustDied(Unit* killer) + { + if (!killer) + return; + + if (me->GetEntry() == NPC_HEALTHY_MUSHROOM && killer->GetTypeId() == TYPEID_PLAYER) + { + me->InterruptNonMeleeSpells(false); + DoCast(killer, SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS, false); + } + } + + void EnterCombat(Unit* /*who*/) {} + void AttackStart(Unit* /*victim*/) {} + + void UpdateAI(const uint32 diff) + { + if (me->GetEntry() == NPC_POISONOUS_MUSHROOM) + { + if (uiAuraTimer <= diff) + { + DoCast(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AREA, true); + DoCast(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false); + uiAuraTimer = 7*IN_MILLISECONDS; + } else uiAuraTimer -= diff; + } + if (uiDeathTimer <= diff) + me->DisappearAndDie(); + else uiDeathTimer -= diff; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_amanitar_mushroomsAI(creature); + } +}; + +void AddSC_boss_amanitar() +{ + new boss_amanitar; + new mob_amanitar_mushrooms; +} diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp new file mode 100644 index 00000000000..a2371fa0121 --- /dev/null +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2008-2011 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 "ScriptPCH.h" +#include "ahnkahet.h" + +//not in db +enum Yells +{ + SAY_AGGRO = -1619014, + SAY_SLAY_1 = -1619015, + SAY_SLAY_2 = -1619016, + SAY_SLAY_3 = -1619017, + SAY_DEATH = -1619018, + SAY_EGG_SAC_1 = -1619019, + SAY_EGG_SAC_2 = -1619020 +}; + +enum Spells +{ + SPELL_BROOD_PLAGUE = 56130, + H_SPELL_BROOD_PLAGUE = 59467, + H_SPELL_BROOD_RAGE = 59465, + SPELL_ENRAGE = 26662, // Enraged if too far away from home + SPELL_SUMMON_SWARMERS = 56119, //2x 30178 -- 2x every 10secs + SPELL_SUMMON_SWARM_GUARD = 56120, //1x 30176 -- every 25secs +}; + +enum Creatures +{ + MOB_AHNKAHAR_SWARMER = 30178, + MOB_AHNKAHAR_GUARDIAN_ENTRY = 30176 +}; + +#define ACTION_AHNKAHAR_GUARDIAN_DEAD 1 +#define DATA_RESPECT_YOUR_ELDERS 2 + +#define EMOTE_HATCHES "An Ahn'kahar Guardian hatches!" + +class boss_elder_nadox : public CreatureScript +{ + public: + boss_elder_nadox() : CreatureScript("boss_elder_nadox") { } + + struct boss_elder_nadoxAI : public ScriptedAI + { + boss_elder_nadoxAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + uint32 uiPlagueTimer; + uint32 uiRagueTimer; + + uint32 uiSwarmerSpawnTimer; + uint32 uiGuardSpawnTimer; + uint32 uiEnrageTimer; + + bool bGuardSpawned; + bool respectYourElders; + + InstanceScript* instance; + + void Reset() + { + uiPlagueTimer = 13000; + uiRagueTimer = 20000; + + uiSwarmerSpawnTimer = 10000; + uiGuardSpawnTimer = 25000; + + uiEnrageTimer = 5000; + + bGuardSpawned = false; + respectYourElders = true; + + if (instance) + instance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* /*who*/) + { + DoScriptText(SAY_DEATH, me); + + if (instance) + instance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS); + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2, SAY_SLAY_3), me); + } + + void JustDied(Unit* /*who*/) + { + DoScriptText(SAY_SLAY_3, me); //SAY_SLAY_3 on death? + + if (instance) + instance->SetData(DATA_ELDER_NADOX_EVENT, DONE); + } + + void DoAction(int32 const action) + { + if (action == ACTION_AHNKAHAR_GUARDIAN_DEAD) + respectYourElders = false; + } + + uint32 GetData(uint32 type) + { + if (type == DATA_RESPECT_YOUR_ELDERS) + return respectYourElders ? 1 : 0; + + return 0; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (uiPlagueTimer <= diff) + { + DoCast(me->getVictim(), SPELL_BROOD_PLAGUE); + uiPlagueTimer = 15000; + } + else + uiPlagueTimer -= diff; + + if (IsHeroic()) + { + if (uiRagueTimer <= diff) + { + if (Creature* Swarmer = me->FindNearestCreature(MOB_AHNKAHAR_SWARMER, 35.0f)) + { + DoCast(Swarmer, H_SPELL_BROOD_RAGE, true); + uiRagueTimer = 15000; + } + } + else + uiRagueTimer -= diff; + } + + if (uiSwarmerSpawnTimer <= diff) + { + DoCast(me, SPELL_SUMMON_SWARMERS, true); + DoCast(me, SPELL_SUMMON_SWARMERS); + if (urand(1, 3) == 3) // 33% chance of dialog + DoScriptText(RAND(SAY_EGG_SAC_1, SAY_EGG_SAC_2), me); + + uiSwarmerSpawnTimer = 10000; + } + else + uiSwarmerSpawnTimer -= diff; + + if (!bGuardSpawned && uiGuardSpawnTimer <= diff) + { + me->MonsterTextEmote(EMOTE_HATCHES, me->GetGUID(), true); + DoCast(me, SPELL_SUMMON_SWARM_GUARD); + bGuardSpawned = true; + } + else + uiGuardSpawnTimer -= diff; + + if (uiEnrageTimer <= diff) + { + if (me->HasAura(SPELL_ENRAGE, 0)) + return; + + float x, y, z, o; + me->GetHomePosition(x, y, z, o); + if (z < 24) + if (!me->IsNonMeleeSpellCasted(false)) + DoCast(me, SPELL_ENRAGE, true); + + uiEnrageTimer = 5000; + } + else + uiEnrageTimer -= diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_elder_nadoxAI(creature); + } +}; + +enum AddSpells +{ + SPELL_SPRINT = 56354, + SPELL_GUARDIAN_AURA = 56151 +}; + +class mob_ahnkahar_nerubian : public CreatureScript +{ + public: + mob_ahnkahar_nerubian() : CreatureScript("mob_ahnkahar_nerubian") { } + + struct mob_ahnkahar_nerubianAI : public ScriptedAI + { + mob_ahnkahar_nerubianAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + InstanceScript* instance; + uint32 uiSprintTimer; + + void Reset() + { + if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) + DoCast(me, SPELL_GUARDIAN_AURA, true); + uiSprintTimer = 10000; + } + + void JustDied(Unit* /*who*/) + { + if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) + if (Creature* Nadox = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ELDER_NADOX))) + Nadox->AI()->DoAction(ACTION_AHNKAHAR_GUARDIAN_DEAD); + } + + void EnterCombat(Unit* /*who*/) + { + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) + me->RemoveAurasDueToSpell(SPELL_GUARDIAN_AURA); + + if (instance) + if (instance->GetData(DATA_ELDER_NADOX_EVENT) != IN_PROGRESS) + me->DespawnOrUnsummon(); + + if (uiSprintTimer <= diff) + { + DoCast(me, SPELL_SPRINT); + uiSprintTimer = 25000; + } + else + uiSprintTimer -= diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_ahnkahar_nerubianAI(creature); + } +}; + +//HACK: No, AI. Replace with proper db content? +class mob_nadox_eggs : public CreatureScript +{ +public: + mob_nadox_eggs() : CreatureScript("mob_nadox_eggs") { } + + struct mob_nadox_eggsAI : public Scripted_NoMovementAI + { + mob_nadox_eggsAI(Creature* c) : Scripted_NoMovementAI(c) + { + c->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + c->UpdateAllStats(); + } + void Reset() {} + void EnterCombat(Unit* /*who*/) {} + void AttackStart(Unit* /*victim*/) {} + void MoveInLineOfSight(Unit* /*who*/) {} + void UpdateAI(const uint32 /*diff*/) {} + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_nadox_eggsAI(creature); + } +}; + +class achievement_respect_your_elders : public AchievementCriteriaScript +{ + public: + achievement_respect_your_elders() : AchievementCriteriaScript("achievement_respect_your_elders") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Nadox = target->ToCreature()) + if (Nadox->AI()->GetData(DATA_RESPECT_YOUR_ELDERS)) + return true; + + return false; + } +}; + +void AddSC_boss_elder_nadox() +{ + new boss_elder_nadox; + new mob_ahnkahar_nerubian; + new mob_nadox_eggs; + new achievement_respect_your_elders(); +} diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp new file mode 100644 index 00000000000..bc4d4ba5eea --- /dev/null +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2008-2011 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 . + */ + +/* + * Comment: Missing AI for Twisted Visages + */ + +#include "ScriptPCH.h" +#include "ahnkahet.h" + +enum Spells +{ + SPELL_INSANITY = 57496, //Dummy + INSANITY_VISUAL = 57561, + SPELL_INSANITY_TARGET = 57508, + SPELL_MIND_FLAY = 57941, + SPELL_SHADOW_BOLT_VOLLEY = 57942, + SPELL_SHIVER = 57949, + SPELL_CLONE_PLAYER = 57507, //casted on player during insanity + SPELL_INSANITY_PHASING_1 = 57508, + SPELL_INSANITY_PHASING_2 = 57509, + SPELL_INSANITY_PHASING_3 = 57510, + SPELL_INSANITY_PHASING_4 = 57511, + SPELL_INSANITY_PHASING_5 = 57512 +}; + +enum Creatures +{ + MOB_TWISTED_VISAGE = 30625 +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1619030, + SAY_SLAY_1 = -1619031, + SAY_SLAY_2 = -1619032, + SAY_SLAY_3 = -1619033, + SAY_DEATH_1 = -1619034, + SAY_DEATH_2 = -1619035, + SAY_PHASE = -1619036 +}; + +enum Achievements +{ + ACHIEV_QUICK_DEMISE_START_EVENT = 20382, +}; + +class boss_volazj : public CreatureScript +{ +public: + boss_volazj() : CreatureScript("boss_volazj") { } + + struct boss_volazjAI : public ScriptedAI + { + boss_volazjAI(Creature* creature) : ScriptedAI(creature), Summons(me) + { + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + + uint32 uiMindFlayTimer; + uint32 uiShadowBoltVolleyTimer; + uint32 uiShiverTimer; + uint32 insanityHandled; + SummonList Summons; + + // returns the percentage of health after taking the given damage. + uint32 GetHealthPct(uint32 damage) + { + if (damage > me->GetHealth()) + return 0; + return 100*(me->GetHealth()-damage)/me->GetMaxHealth(); + } + + void DamageTaken(Unit* /*pAttacker*/, uint32 &damage) + { + if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + damage = 0; + + if ((GetHealthPct(0) >= 66 && GetHealthPct(damage) < 66)|| + (GetHealthPct(0) >= 33 && GetHealthPct(damage) < 33)) + { + me->InterruptNonMeleeSpells(false); + DoCast(me, SPELL_INSANITY, false); + } + } + + void SpellHitTarget(Unit* target, const SpellInfo* spell) + { + if (spell->Id == SPELL_INSANITY) + { + // Not good target or too many players + if (target->GetTypeId() != TYPEID_PLAYER || insanityHandled > 4) + return; + // First target - start channel visual and set self as unnattackable + if (!insanityHandled) + { + // Channel visual + DoCast(me, INSANITY_VISUAL, true); + // Unattackable + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(true, UNIT_STAT_STUNNED); + } + // phase mask + target->CastSpell(target, SPELL_INSANITY_TARGET+insanityHandled, true); + // summon twisted party members for this target + Map::PlayerList const &players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + { + Player* player = i->getSource(); + if (!player || !player->isAlive()) + continue; + // Summon clone + if (Unit* summon = me->SummonCreature(MOB_TWISTED_VISAGE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + // clone + player->CastSpell(summon, SPELL_CLONE_PLAYER, true); + // set phase + summon->SetPhaseMask((1<<(4+insanityHandled)), true); + } + } + ++insanityHandled; + } + } + + void ResetPlayersPhaseMask() + { + Map::PlayerList const &players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + { + Player* player = i->getSource(); + player->RemoveAurasDueToSpell(GetSpellForPhaseMask(player->GetPhaseMask())); + } + } + + void Reset() + { + uiMindFlayTimer = 8*IN_MILLISECONDS; + uiShadowBoltVolleyTimer = 5*IN_MILLISECONDS; + uiShiverTimer = 15*IN_MILLISECONDS; + + if (instance) + { + instance->SetData(DATA_HERALD_VOLAZJ, NOT_STARTED); + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); + } + + // Visible for all players in insanity + me->SetPhaseMask((1|16|32|64|128|256), true); + // Used for Insanity handling + insanityHandled = 0; + + ResetPlayersPhaseMask(); + + // Cleanup + Summons.DespawnAll(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STAT_STUNNED); + } + + void EnterCombat(Unit* /*who*/) + { + DoScriptText(SAY_AGGRO, me); + + if (instance) + { + instance->SetData(DATA_HERALD_VOLAZJ, IN_PROGRESS); + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); + } + } + + void JustSummoned(Creature* summon) + { + Summons.Summon(summon); + } + + uint32 GetSpellForPhaseMask(uint32 phase) + { + uint32 spell = 0; + switch (phase) + { + case 16: + spell = SPELL_INSANITY_PHASING_1; + break; + case 32: + spell = SPELL_INSANITY_PHASING_2; + break; + case 64: + spell = SPELL_INSANITY_PHASING_3; + break; + case 128: + spell = SPELL_INSANITY_PHASING_4; + break; + case 256: + spell = SPELL_INSANITY_PHASING_5; + break; + } + return spell; + } + + void SummonedCreatureDespawn(Creature* summon) + { + uint32 phase= summon->GetPhaseMask(); + uint32 nextPhase = 0; + Summons.Despawn(summon); + + // Check if all summons in this phase killed + for (SummonList::const_iterator iter = Summons.begin(); iter != Summons.end(); ++iter) + { + if (Creature* visage = Unit::GetCreature(*me, *iter)) + { + // Not all are dead + if (phase == visage->GetPhaseMask()) + return; + else + nextPhase = visage->GetPhaseMask(); + } + } + + // Roll Insanity + uint32 spell = GetSpellForPhaseMask(phase); + uint32 spell2 = GetSpellForPhaseMask(nextPhase); + Map* map = me->GetMap(); + if (!map) + return; + + Map::PlayerList const &PlayerList = map->GetPlayers(); + if (!PlayerList.isEmpty()) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (Player* player = i->getSource()) + { + if (player->HasAura(spell)) + { + player->RemoveAurasDueToSpell(spell); + if (spell2) // if there is still some different mask cast spell for it + player->CastSpell(player, spell2, true); + } + } + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (insanityHandled) + { + if (!Summons.empty()) + return; + + insanityHandled = 0; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STAT_STUNNED); + me->RemoveAurasDueToSpell(INSANITY_VISUAL); + } + + if (uiMindFlayTimer <= diff) + { + DoCast(me->getVictim(), SPELL_MIND_FLAY); + uiMindFlayTimer = 20*IN_MILLISECONDS; + } else uiMindFlayTimer -= diff; + + if (uiShadowBoltVolleyTimer <= diff) + { + DoCast(me->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); + uiShadowBoltVolleyTimer = 5*IN_MILLISECONDS; + } else uiShadowBoltVolleyTimer -= diff; + + if (uiShiverTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_SHIVER); + uiShiverTimer = 15*IN_MILLISECONDS; + } else uiShiverTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) + { + DoScriptText(SAY_DEATH_1, me); + + if (instance) + instance->SetData(DATA_HERALD_VOLAZJ, DONE); + + Summons.DespawnAll(); + ResetPlayersPhaseMask(); + } + + void KilledUnit(Unit* /*victim*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2, SAY_SLAY_3), me); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_volazjAI(creature); + } +}; + +void AddSC_boss_volazj() +{ + new boss_volazj; +} diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp new file mode 100644 index 00000000000..b2975797a02 --- /dev/null +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2008-2011 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 . + */ + +/* + * Comment: Complete - BUT THE TRIGGER NEEDS DATA WHETHER THE PRISON OF TALDARAM IS OFFLINE ! + */ + +#include "ScriptPCH.h" +#include "ahnkahet.h" + +enum Yells +{ + TEXT_AGGRO = -1619000, + TEXT_SACRIFICE_1_1 = -1619001, + TEXT_SACRIFICE_1_2 = -1619002, + TEXT_SACRIFICE_2_1 = -1619003, + TEXT_SACRIFICE_2_2 = -1619004, + TEXT_SLAY_1 = -1619005, + TEXT_SLAY_2 = -1619006, + TEXT_SLAY_3 = -1619007, + TEXT_DEATH = -1619008, + TEXT_PREACHING_1 = -1619009, + TEXT_PREACHING_2 = -1619010, + TEXT_PREACHING_3 = -1619011, + TEXT_PREACHING_4 = -1619012, + TEXT_PREACHING_5 = -1619013 +}; + +enum Spells +{ + SPELL_SPHERE_VISUAL = 56075, + SPELL_GIFT_OF_THE_HERALD = 56219, + SPELL_CYCLONE_STRIKE = 56855, // Self + SPELL_CYCLONE_STRIKE_H = 60030, + SPELL_LIGHTNING_BOLT = 56891, // 40Y + SPELL_LIGHTNING_BOLT_H = 60032, // 40Y + SPELL_THUNDERSHOCK = 56926, // 30Y + SPELL_THUNDERSHOCK_H = 60029 // 30Y +}; + +enum Creatures +{ + NPC_JEDOGA_CONTROLLER = 30181 +}; + +const Position JedogaPosition[2] = +{ + {372.330994f, -705.278015f, -0.624178f, 5.427970f}, + {372.330994f, -705.278015f, -16.179716f, 5.427970f} +}; + +#define ACTION_INITIAND_KILLED 1 +#define DATA_VOLUNTEER_WORK 2 + +class boss_jedoga_shadowseeker : public CreatureScript +{ +public: + boss_jedoga_shadowseeker() : CreatureScript("boss_jedoga_shadowseeker") { } + + struct boss_jedoga_shadowseekerAI : public ScriptedAI + { + boss_jedoga_shadowseekerAI(Creature* c) : ScriptedAI(c) + { + instance = c->GetInstanceScript(); + bFirstTime = true; + bPreDone = false; + } + + InstanceScript* instance; + + uint32 uiOpFerTimer; + uint32 uiCycloneTimer; + uint32 uiBoltTimer; + uint32 uiThunderTimer; + + bool bPreDone; + bool bOpFerok; + bool bOnGround; + bool bOpFerokFail; + bool bCanDown; + bool volunteerWork; + bool bFirstTime; + + void Reset() + { + uiOpFerTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); + + uiCycloneTimer = 3*IN_MILLISECONDS; + uiBoltTimer = 7*IN_MILLISECONDS; + uiThunderTimer = 12*IN_MILLISECONDS; + + bOpFerok = false; + bOpFerokFail = false; + bOnGround = false; + bCanDown = false; + volunteerWork = true; + + if (instance) + { + if (!bFirstTime) + instance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, FAIL); + + instance->SetData64(DATA_PL_JEDOGA_TARGET, 0); + instance->SetData64(DATA_ADD_JEDOGA_OPFER, 0); + instance->SetData(DATA_JEDOGA_RESET_INITIANDS, 0); + } + MoveUp(); + + bFirstTime = false; + } + + void EnterCombat(Unit* who) + { + if (!instance || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_JEDOGA_CONTROLLER)) + return; + + DoScriptText(TEXT_AGGRO, me); + me->SetInCombatWithZone(); + instance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, IN_PROGRESS); + } + + void AttackStart(Unit* who) + { + if (!who || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_JEDOGA_CONTROLLER)) + return; + + ScriptedAI::AttackStart(who); + } + + void KilledUnit(Unit* Victim) + { + if (!Victim || Victim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(RAND(TEXT_SLAY_1, TEXT_SLAY_2, TEXT_SLAY_3), me); + } + + void JustDied(Unit* /*Killer*/) + { + DoScriptText(TEXT_DEATH, me); + if (instance) + instance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, DONE); + } + + void DoAction(int32 const action) + { + if (action == ACTION_INITIAND_KILLED) + volunteerWork = false; + } + + uint32 GetData(uint32 type) + { + if (type == DATA_VOLUNTEER_WORK) + return volunteerWork ? 1 : 0; + + return 0; + } + + void MoveInLineOfSight(Unit* who) + { + if (!instance || !who || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_JEDOGA_CONTROLLER)) + return; + + if (!bPreDone && who->GetTypeId() == TYPEID_PLAYER && me->GetDistance(who) < 100.0f) + { + DoScriptText(RAND(TEXT_PREACHING_1, TEXT_PREACHING_2, TEXT_PREACHING_3, TEXT_PREACHING_4, TEXT_PREACHING_5), me); + bPreDone = true; + } + + if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS || !bOnGround) + return; + + if (!me->getVictim() && me->canCreatureAttack(who)) + { + float attackRadius = me->GetAttackDistance(who); + if (me->IsWithinDistInMap(who, attackRadius) && me->IsWithinLOSInMap(who)) + { + if (!me->getVictim()) + { + who->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); + AttackStart(who); + } + else if (me->GetMap()->IsDungeon()) + { + who->SetInCombatWith(me); + me->AddThreat(who, 0.0f); + } + } + } + } + + void MoveDown() + { + if (!instance) + return; + + bOpFerokFail = false; + + instance->SetData(DATA_JEDOGA_TRIGGER_SWITCH, 0); + me->GetMotionMaster()->MovePoint(1, JedogaPosition[1]); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + + me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + + bOnGround = true; + + if (UpdateVictim()) + { + AttackStart(me->getVictim()); + me->GetMotionMaster()->MoveChase(me->getVictim()); + } + else + { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_PL_JEDOGA_TARGET))) + { + AttackStart(target); + instance->SetData(DATA_JEDOGA_RESET_INITIANDS, 0); + if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS) + EnterCombat(target); + } + else if (!me->isInCombat()) + EnterEvadeMode(); + } + } + + void MoveUp() + { + if (!instance) + return; + + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + + me->AttackStop(); + me->RemoveAllAuras(); + me->LoadCreaturesAddon(); + me->GetMotionMaster()->MovePoint(0, JedogaPosition[0]); + + instance->SetData(DATA_JEDOGA_TRIGGER_SWITCH, 1); + if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) OpferRufen(); + + bOnGround = false; + uiOpFerTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } + + void OpferRufen() + { + if (!instance) + return; + + uint64 opfer = instance->GetData64(DATA_ADD_JEDOGA_INITIAND); + + if (opfer) + { + DoScriptText(RAND(TEXT_SACRIFICE_1_1, TEXT_SACRIFICE_1_2), me); + instance->SetData64(DATA_ADD_JEDOGA_OPFER, opfer); + } else + bCanDown = true; + } + + void Opfern() + { + DoScriptText(RAND(TEXT_SACRIFICE_2_1, TEXT_SACRIFICE_2_2), me); + + me->InterruptNonMeleeSpells(false); + DoCast(me, SPELL_GIFT_OF_THE_HERALD, false); + + bOpFerok = false; + bCanDown = true; + } + + void UpdateAI(const uint32 diff) + { + if (!instance) + return; + + if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS && instance->GetData(DATA_ALL_INITIAND_DEAD)) + MoveDown(); + + if (bOpFerok && !bOnGround && !bCanDown) Opfern(); + + if (bOpFerokFail && !bOnGround && !bCanDown) + bCanDown = true; + + if (bCanDown) + { + MoveDown(); + bCanDown = false; + } + + if (bOnGround) + { + if (!UpdateVictim()) + return; + + if (uiCycloneTimer <= diff) + { + DoCast(me, SPELL_CYCLONE_STRIKE, false); + uiCycloneTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } else uiCycloneTimer -= diff; + + if (uiBoltTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + me->CastSpell(target, DUNGEON_MODE(SPELL_LIGHTNING_BOLT, SPELL_LIGHTNING_BOLT_H), false); + + uiBoltTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } else uiBoltTimer -= diff; + + if (uiThunderTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + me->CastSpell(target, DUNGEON_MODE(SPELL_THUNDERSHOCK, SPELL_THUNDERSHOCK_H), false); + + uiThunderTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } else uiThunderTimer -= diff; + + if (uiOpFerTimer <= diff) + MoveUp(); + else + uiOpFerTimer -= diff; + + DoMeleeAttackIfReady(); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_jedoga_shadowseekerAI(creature); + } +}; + +class mob_jedoga_initiand : public CreatureScript +{ +public: + mob_jedoga_initiand() : CreatureScript("mob_jedoga_initiand") { } + + struct mob_jedoga_initiandAI : public ScriptedAI + { + mob_jedoga_initiandAI(Creature* c) : ScriptedAI(c) + { + instance = c->GetInstanceScript(); + } + + InstanceScript* instance; + + uint32 bCheckTimer; + + bool bWalking; + + void Reset() + { + if (!instance) + return; + + bWalking = false; + bCheckTimer = 2*IN_MILLISECONDS; + + if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS) + { + me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + else + { + DoCast(me, SPELL_SPHERE_VISUAL, false); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + } + + void JustDied(Unit* Killer) + { + if (!Killer || !instance) + return; + + if (bWalking) + { + if (Creature* boss = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_JEDOGA_SHADOWSEEKER))) + { + if (!CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerok) + CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerokFail = true; + + boss->AI()->DoAction(ACTION_INITIAND_KILLED); + } + + instance->SetData64(DATA_ADD_JEDOGA_OPFER, 0); + + bWalking = false; + } + if (Killer->GetTypeId() == TYPEID_PLAYER) + instance->SetData64(DATA_PL_JEDOGA_TARGET, Killer->GetGUID()); + } + + void EnterCombat(Unit* who) + { + if ((instance && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !who) + return; + } + + void AttackStart(Unit* victim) + { + if ((instance && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !victim) + return; + + ScriptedAI::AttackStart(victim); + } + + void MoveInLineOfSight(Unit* who) + { + if ((instance && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !who) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) + { + if (uiType != POINT_MOTION_TYPE || !instance) + return; + + switch (uiPointId) + { + case 1: + { + Creature* boss = me->GetMap()->GetCreature(instance->GetData64(DATA_JEDOGA_SHADOWSEEKER)); + if (boss) + { + CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerok = true; + CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerokFail = false; + me->Kill(me); + } + } + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (instance && bCheckTimer <= diff) + { + if (me->GetGUID() == instance->GetData64(DATA_ADD_JEDOGA_OPFER) && !bWalking) + { + me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + + float distance = me->GetDistance(JedogaPosition[1]); + + if (distance < 9.0f) + me->SetSpeed(MOVE_WALK, 0.5f, true); + else if (distance < 15.0f) + me->SetSpeed(MOVE_WALK, 0.75f, true); + else if (distance < 20.0f) + me->SetSpeed(MOVE_WALK, 1.0f, true); + + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MovePoint(1, JedogaPosition[1]); + bWalking = true; + } + if (!bWalking) + { + if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS && me->HasAura(SPELL_SPHERE_VISUAL)) + { + me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS && !me->HasAura(SPELL_SPHERE_VISUAL)) + { + DoCast(me, SPELL_SPHERE_VISUAL, false); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + } + bCheckTimer = 2*IN_MILLISECONDS; + } else bCheckTimer -= diff; + + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_jedoga_initiandAI(creature); + } +}; + +// ------------------------------------------------------------------------------------------------------------ +// Jedogas Aufseher - Entry: 30181 +// ------------------------------------------------------------------------------------------------------------ +enum AufseherSpell +{ + SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_1 = 60342, + SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_2 = 56312 +}; + +class npc_jedogas_aufseher_trigger : public CreatureScript +{ +public: + npc_jedogas_aufseher_trigger() : CreatureScript("npc_jedogas_aufseher_trigger") { } + + struct npc_jedogas_aufseher_triggerAI : public Scripted_NoMovementAI + { + npc_jedogas_aufseher_triggerAI(Creature* c) : Scripted_NoMovementAI(c) + { + instance = c->GetInstanceScript(); + bRemoved = false; + bRemoved2 = false; + bCasted = false; + bCasted2 = false; + } + + InstanceScript* instance; + + bool bRemoved; + bool bRemoved2; + bool bCasted; + bool bCasted2; + + void Reset() {} + void EnterCombat(Unit* /*who*/) {} + void AttackStart(Unit* /*victim*/) {} + void MoveInLineOfSight(Unit* /*who*/) {} + + void UpdateAI(const uint32 /*diff*/) + { + if (!instance) + return; + + if (!bRemoved && me->GetPositionX() > 440.0f) + { + if (instance->GetData(DATA_PRINCE_TALDARAM_EVENT) == DONE) + { + me->InterruptNonMeleeSpells(true); + bRemoved = true; + return; + } + if (!bCasted) + { + DoCast(me, SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_1, false); + bCasted = true; + } + } + if (!bRemoved2 && me->GetPositionX() < 440.0f) + { + if (!bCasted2 && instance->GetData(DATA_JEDOGA_TRIGGER_SWITCH)) + { + DoCast(me, SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_2, false); + bCasted2 = true; + } + if (bCasted2 && !instance->GetData(DATA_JEDOGA_TRIGGER_SWITCH)) + { + me->InterruptNonMeleeSpells(true); + bCasted2 = false; + } + if (!bRemoved2 && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == DONE) + { + me->InterruptNonMeleeSpells(true); + bRemoved2 = true; + } + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_jedogas_aufseher_triggerAI(creature); + } +}; + +class achievement_volunteer_work : public AchievementCriteriaScript +{ + public: + achievement_volunteer_work() : AchievementCriteriaScript("achievement_volunteer_work") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Jedoga = target->ToCreature()) + if (Jedoga->AI()->GetData(DATA_VOLUNTEER_WORK)) + return true; + + return false; + } +}; + +void AddSC_boss_jedoga_shadowseeker() +{ + new boss_jedoga_shadowseeker(); + new mob_jedoga_initiand(); + new npc_jedogas_aufseher_trigger(); + new achievement_volunteer_work(); +} diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp new file mode 100644 index 00000000000..9a7dc2f2cc9 --- /dev/null +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2008-2011 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 "ScriptPCH.h" +#include "ahnkahet.h" + +enum Spells +{ + SPELL_BLOODTHIRST = 55968, //Trigger Spell + add aura + SPELL_CONJURE_FLAME_SPHERE = 55931, + SPELL_FLAME_SPHERE_SUMMON_1 = 55895, // 1x 30106 + H_SPELL_FLAME_SPHERE_SUMMON_1 = 59511, // 1x 31686 + H_SPELL_FLAME_SPHERE_SUMMON_2 = 59512, // 1x 31687 + SPELL_FLAME_SPHERE_SPAWN_EFFECT = 55891, + SPELL_FLAME_SPHERE_VISUAL = 55928, + SPELL_FLAME_SPHERE_PERIODIC = 55926, + H_SPELL_FLAME_SPHERE_PERIODIC = 59508, + SPELL_FLAME_SPHERE_DEATH_EFFECT = 55947, + SPELL_BEAM_VISUAL = 60342, + SPELL_EMBRACE_OF_THE_VAMPYR = 55959, + H_SPELL_EMBRACE_OF_THE_VAMPYR = 59513, + SPELL_VANISH = 55964, + CREATURE_FLAME_SPHERE = 30106, + H_CREATURE_FLAME_SPHERE_1 = 31686, + H_CREATURE_FLAME_SPHERE_2 = 31687 +}; +enum Misc +{ + DATA_EMBRACE_DMG = 20000, + H_DATA_EMBRACE_DMG = 40000, + DATA_SPHERE_DISTANCE = 15 +}; +#define DATA_SPHERE_ANGLE_OFFSET 0.7f +#define DATA_GROUND_POSITION_Z 11.4f + +enum Yells +{ + SAY_AGGRO = -1619021, + SAY_SLAY_1 = -1619022, + SAY_SLAY_2 = -1619023, + SAY_DEATH = -1619024, + SAY_FEED_1 = -1619025, + SAY_FEED_2 = -1619026, + SAY_VANISH_1 = -1619027, + SAY_VANISH_2 = -1619028 +}; +enum CombatPhase +{ + NORMAL, + CASTING_FLAME_SPHERES, + JUST_VANISHED, + VANISHED, + FEEDING +}; +enum GameObjects +{ + GO_SPHERE1 = 193093, + GO_SPHERE2 = 193094 +}; + +class boss_taldaram : public CreatureScript +{ +public: + boss_taldaram() : CreatureScript("boss_taldaram") { } + + struct boss_taldaramAI : public ScriptedAI + { + boss_taldaramAI(Creature* c) : ScriptedAI(c) + { + instance = c->GetInstanceScript(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + uint32 uiBloodthirstTimer; + uint32 uiVanishTimer; + uint32 uiWaitTimer; + uint32 uiEmbraceTimer; + uint32 uiEmbraceTakenDamage; + uint32 uiFlamesphereTimer; + uint32 uiPhaseTimer; + + uint64 uiEmbraceTarget; + + CombatPhase Phase; + + InstanceScript* instance; + + void Reset() + { + uiBloodthirstTimer = 10*IN_MILLISECONDS; + uiVanishTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS); + uiEmbraceTimer = 20*IN_MILLISECONDS; + uiFlamesphereTimer = 5*IN_MILLISECONDS; + uiEmbraceTakenDamage = 0; + Phase = NORMAL; + uiPhaseTimer = 0; + uiEmbraceTarget = 0; + if (instance) + instance->SetData(DATA_PRINCE_TALDARAM_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* /*who*/) + { + if (instance) + instance->SetData(DATA_PRINCE_TALDARAM_EVENT, IN_PROGRESS); + DoScriptText(SAY_AGGRO, me); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + if (uiPhaseTimer <= diff) + { + switch (Phase) + { + case CASTING_FLAME_SPHERES: + { + Creature* pSpheres[3]; + + //DoCast(me, SPELL_FLAME_SPHERE_SUMMON_1); + pSpheres[0] = DoSpawnCreature(CREATURE_FLAME_SPHERE, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS); + Unit* pSphereTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); + if (pSphereTarget && pSpheres[0]) + { + float angle, x, y; + angle = pSpheres[0]->GetAngle(pSphereTarget); + x = pSpheres[0]->GetPositionX() + DATA_SPHERE_DISTANCE * cos(angle); + y = pSpheres[0]->GetPositionY() + DATA_SPHERE_DISTANCE * sin(angle); + pSpheres[0]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[0]->GetPositionZ()); + } + if (IsHeroic()) + { + //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_1); + pSpheres[1] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_1, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS); + //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_2); + pSpheres[2] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_2, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS); + if (pSphereTarget && pSpheres[1] && pSpheres[2]) + { + float angle, x, y; + angle = pSpheres[1]->GetAngle(pSphereTarget) + DATA_SPHERE_ANGLE_OFFSET; + x = pSpheres[1]->GetPositionX() + DATA_SPHERE_DISTANCE/2 * cos(angle); + y = pSpheres[1]->GetPositionY() + DATA_SPHERE_DISTANCE/2 * sin(angle); + pSpheres[1]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[1]->GetPositionZ()); + angle = pSpheres[2]->GetAngle(pSphereTarget) - DATA_SPHERE_ANGLE_OFFSET; + x = pSpheres[2]->GetPositionX() + DATA_SPHERE_DISTANCE/2 * cos(angle); + y = pSpheres[2]->GetPositionY() + DATA_SPHERE_DISTANCE/2 * sin(angle); + pSpheres[2]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[2]->GetPositionZ()); + } + } + + Phase = NORMAL; + uiPhaseTimer = 0; + break; + } + case JUST_VANISHED: + if (Unit* pEmbraceTarget = GetEmbraceTarget()) + { + me->GetMotionMaster()->Clear(); + me->SetSpeed(MOVE_WALK, 2.0f, true); + me->GetMotionMaster()->MoveChase(pEmbraceTarget); + } + Phase = VANISHED; + uiPhaseTimer = 1300; + break; + case VANISHED: + if (Unit* pEmbraceTarget = GetEmbraceTarget()) + DoCast(pEmbraceTarget, SPELL_EMBRACE_OF_THE_VAMPYR); + me->GetMotionMaster()->Clear(); + me->SetSpeed(MOVE_WALK, 1.0f, true); + me->GetMotionMaster()->MoveChase(me->getVictim()); + Phase = FEEDING; + uiPhaseTimer = 20*IN_MILLISECONDS; + break; + case FEEDING: + Phase = NORMAL; + uiPhaseTimer = 0; + uiEmbraceTarget = 0; + break; + case NORMAL: + if (uiBloodthirstTimer <= diff) + { + DoCast(me, SPELL_BLOODTHIRST); + uiBloodthirstTimer = 10*IN_MILLISECONDS; + } else uiBloodthirstTimer -= diff; + + if (uiFlamesphereTimer <= diff) + { + DoCast(me, SPELL_CONJURE_FLAME_SPHERE); + Phase = CASTING_FLAME_SPHERES; + uiPhaseTimer = 3*IN_MILLISECONDS + diff; + uiFlamesphereTimer = 15*IN_MILLISECONDS; + } else uiFlamesphereTimer -= diff; + + if (uiVanishTimer <= diff) + { + //Count alive players + Unit* target = NULL; + std::list t_list = me->getThreatManager().getThreatList(); + std::vector target_list; + for (std::list::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + target = Unit::GetUnit(*me, (*itr)->getUnitGuid()); + // exclude pets & totems + if (target && target->GetTypeId() == TYPEID_PLAYER && target->isAlive()) + target_list.push_back(target); + target = NULL; + } + //He only vanishes if there are 3 or more alive players + if (target_list.size() > 2) + { + DoScriptText(RAND(SAY_VANISH_1, SAY_VANISH_2), me); + DoCast(me, SPELL_VANISH); + Phase = JUST_VANISHED; + uiPhaseTimer = 500; + if (Unit* pEmbraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + uiEmbraceTarget = pEmbraceTarget->GetGUID(); + + } + uiVanishTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS); + } else uiVanishTimer -= diff; + + DoMeleeAttackIfReady(); + break; + } + } else uiPhaseTimer -= diff; + } + + void DamageTaken(Unit* /*done_by*/, uint32 &damage) + { + Unit* pEmbraceTarget = GetEmbraceTarget(); + + if (Phase == FEEDING && pEmbraceTarget && pEmbraceTarget->isAlive()) + { + uiEmbraceTakenDamage += damage; + if (uiEmbraceTakenDamage > (uint32) DUNGEON_MODE(DATA_EMBRACE_DMG, H_DATA_EMBRACE_DMG)) + { + Phase = NORMAL; + uiPhaseTimer = 0; + uiEmbraceTarget = 0; + me->CastStop(); + } + } + } + + void JustDied(Unit* /*killer*/) + { + DoScriptText(SAY_DEATH, me); + + if (instance) + instance->SetData(DATA_PRINCE_TALDARAM_EVENT, DONE); + } + + void KilledUnit(Unit* victim) + { + if (victim == me) + return; + + Unit* pEmbraceTarget = GetEmbraceTarget(); + if (Phase == FEEDING && pEmbraceTarget && victim == pEmbraceTarget) + { + Phase = NORMAL; + uiPhaseTimer = 0; + uiEmbraceTarget = 0; + } + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + bool CheckSpheres() + { + if (!instance) + return false; + + uint64 uiSphereGuids[2]; + uiSphereGuids[0] = instance->GetData64(DATA_SPHERE1); + uiSphereGuids[1] = instance->GetData64(DATA_SPHERE2); + + for (uint8 i=0; i < 2; ++i) + { + GameObject* pSpheres = instance->instance->GetGameObject(uiSphereGuids[i]); + if (!pSpheres) + return false; + if (pSpheres->GetGoState() != GO_STATE_ACTIVE) + return false; + } + RemovePrison(); + return true; + } + + Unit* GetEmbraceTarget() + { + if (!uiEmbraceTarget) + return NULL; + + return Unit::GetUnit(*me, uiEmbraceTarget); + } + + void RemovePrison() + { + if (!instance) + return; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAurasDueToSpell(SPELL_BEAM_VISUAL); + me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation()); + uint64 prison_GUID = instance->GetData64(DATA_PRINCE_TALDARAM_PLATFORM); + instance->HandleGameObject(prison_GUID, true); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_taldaramAI(creature); + } +}; + +class mob_taldaram_flamesphere : public CreatureScript +{ +public: + mob_taldaram_flamesphere() : CreatureScript("mob_taldaram_flamesphere") { } + + struct mob_taldaram_flamesphereAI : public ScriptedAI + { + mob_taldaram_flamesphereAI(Creature* c) : ScriptedAI(c) + { + instance = c->GetInstanceScript(); + } + + uint32 uiDespawnTimer; + InstanceScript* instance; + + void Reset() + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); + me->setFaction(16); + me->SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); + DoCast(me, SPELL_FLAME_SPHERE_VISUAL); + DoCast(me, SPELL_FLAME_SPHERE_SPAWN_EFFECT); + DoCast(me, SPELL_FLAME_SPHERE_PERIODIC); + uiDespawnTimer = 10*IN_MILLISECONDS; + } + + void EnterCombat(Unit* /*who*/) {} + void MoveInLineOfSight(Unit* /*who*/) {} + + void JustDied(Unit* /*who*/) + { + DoCast(me, SPELL_FLAME_SPHERE_DEATH_EFFECT); + } + + void UpdateAI(const uint32 diff) + { + if (uiDespawnTimer <= diff) + me->DisappearAndDie(); + else + uiDespawnTimer -= diff; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_taldaram_flamesphereAI(creature); + } +}; + +class prince_taldaram_sphere : public GameObjectScript +{ +public: + prince_taldaram_sphere() : GameObjectScript("prince_taldaram_sphere") { } + + bool OnGossipHello(Player* /*player*/, GameObject* pGO) + { + InstanceScript* instance = pGO->GetInstanceScript(); + + Creature* pPrinceTaldaram = Unit::GetCreature(*pGO, instance ? instance->GetData64(DATA_PRINCE_TALDARAM) : 0); + if (pPrinceTaldaram && pPrinceTaldaram->isAlive()) + { + // maybe these are hacks :( + pGO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + pGO->SetGoState(GO_STATE_ACTIVE); + + switch (pGO->GetEntry()) + { + case GO_SPHERE1: instance->SetData(DATA_SPHERE1_EVENT, IN_PROGRESS); break; + case GO_SPHERE2: instance->SetData(DATA_SPHERE2_EVENT, IN_PROGRESS); break; + } + + CAST_AI(boss_taldaram::boss_taldaramAI, pPrinceTaldaram->AI())->CheckSpheres(); + } + return true; + } +}; + +void AddSC_boss_taldaram() +{ + new boss_taldaram; + new mob_taldaram_flamesphere; + new prince_taldaram_sphere; +} diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp new file mode 100644 index 00000000000..5ba11dd5353 --- /dev/null +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2008-2011 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 "ScriptPCH.h" +#include "ahnkahet.h" + +/* Ahn'kahet encounters: +0 - Elder Nadox +1 - Prince Taldaram +2 - Jedoga Shadowseeker +3 - Herald Volazj +4 - Amanitar (Heroic only) +*/ + +#define MAX_ENCOUNTER 5 + +enum Achievements +{ + ACHIEV_VOLUNTEER_WORK = 2056 +}; + +class instance_ahnkahet : public InstanceMapScript +{ +public: + instance_ahnkahet() : InstanceMapScript("instance_ahnkahet", 619) { } + + struct instance_ahnkahet_InstanceScript : public InstanceScript + { + instance_ahnkahet_InstanceScript(Map* map) : InstanceScript(map) {} + + uint64 Elder_Nadox; + uint64 Prince_Taldaram; + uint64 Jedoga_Shadowseeker; + uint64 Herald_Volazj; + uint64 Amanitar; + + uint64 Prince_TaldaramSpheres[2]; + uint64 Prince_TaldaramPlatform; + uint64 Prince_TaldaramGate; + + std::set InitiandGUIDs; + uint64 JedogaSacrifices; + uint64 JedogaTarget; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + uint32 spheres[2]; + + uint8 InitiandCnt; + uint8 switchtrigger; + + std::string str_data; + + void Initialize() + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + InitiandGUIDs.clear(); + + Elder_Nadox =0; + Prince_Taldaram =0; + Jedoga_Shadowseeker =0; + Herald_Volazj =0; + Amanitar =0; + + spheres[0] = NOT_STARTED; + spheres[1] = NOT_STARTED; + + InitiandCnt = 0; + switchtrigger = 0; + JedogaSacrifices = 0; + JedogaTarget = 0; + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature* creature) + { + switch (creature->GetEntry()) + { + case 29309: Elder_Nadox = creature->GetGUID(); break; + case 29308: Prince_Taldaram = creature->GetGUID(); break; + case 29310: Jedoga_Shadowseeker = creature->GetGUID(); break; + case 29311: Herald_Volazj = creature->GetGUID(); break; + case 30258: Amanitar = creature->GetGUID(); break; + case 30114: InitiandGUIDs.insert(creature->GetGUID()); break; + } + } + + void OnGameObjectCreate(GameObject* go) + { + switch (go->GetEntry()) + { + case 193564: Prince_TaldaramPlatform = go->GetGUID(); + if (m_auiEncounter[1] == DONE) HandleGameObject(0, true, go); break; + case 193093: Prince_TaldaramSpheres[0] = go->GetGUID(); + if (spheres[0] == IN_PROGRESS) + { + go->SetGoState(GO_STATE_ACTIVE); + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } + else go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + break; + case 193094: Prince_TaldaramSpheres[1] = go->GetGUID(); + if (spheres[1] == IN_PROGRESS) + { + go->SetGoState(GO_STATE_ACTIVE); + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } + else go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + break; + case 192236: Prince_TaldaramGate = go->GetGUID(); // Web gate past Prince Taldaram + if (m_auiEncounter[1] == DONE)HandleGameObject(0, true, go);break; + } + } + + void SetData64(uint32 idx, uint64 guid) + { + switch (idx) + { + case DATA_ADD_JEDOGA_OPFER: JedogaSacrifices = guid; break; + case DATA_PL_JEDOGA_TARGET: JedogaTarget = guid; break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch (identifier) + { + case DATA_ELDER_NADOX: return Elder_Nadox; + case DATA_PRINCE_TALDARAM: return Prince_Taldaram; + case DATA_JEDOGA_SHADOWSEEKER: return Jedoga_Shadowseeker; + case DATA_HERALD_VOLAZJ: return Herald_Volazj; + case DATA_AMANITAR: return Amanitar; + case DATA_SPHERE1: return Prince_TaldaramSpheres[0]; + case DATA_SPHERE2: return Prince_TaldaramSpheres[1]; + case DATA_PRINCE_TALDARAM_PLATFORM: return Prince_TaldaramPlatform; + case DATA_ADD_JEDOGA_INITIAND: + { + std::vector vInitiands; + vInitiands.clear(); + for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + { + Creature* cr = instance->GetCreature(*itr); + if (cr && cr->isAlive()) + vInitiands.push_back(*itr); + } + if (vInitiands.empty()) + return 0; + uint8 j = urand(0, vInitiands.size() -1); + return vInitiands[j]; + } + case DATA_ADD_JEDOGA_OPFER: return JedogaSacrifices; + case DATA_PL_JEDOGA_TARGET: return JedogaTarget; + } + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch (type) + { + case DATA_ELDER_NADOX_EVENT: m_auiEncounter[0] = data; break; + case DATA_PRINCE_TALDARAM_EVENT: + if (data == DONE) + HandleGameObject(Prince_TaldaramGate, true); + m_auiEncounter[1] = data; + break; + case DATA_JEDOGA_SHADOWSEEKER_EVENT: + m_auiEncounter[2] = data; + if (data == DONE) + { + for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + { + Creature* cr = instance->GetCreature(*itr); + if (cr && cr->isAlive()) + { + cr->SetVisible(false); + cr->setDeathState(JUST_DIED); + cr->RemoveCorpse(); + } + } + } + break; + case DATA_HERALD_VOLAZJ_EVENT: m_auiEncounter[3] = data; break; + case DATA_AMANITAR_EVENT: m_auiEncounter[4] = data; break; + case DATA_SPHERE1_EVENT: spheres[0] = data; break; + case DATA_SPHERE2_EVENT: spheres[1] = data; break; + case DATA_JEDOGA_TRIGGER_SWITCH: switchtrigger = data; break; + case DATA_JEDOGA_RESET_INITIANDS: + for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + { + Creature* cr = instance->GetCreature(*itr); + if (cr) + { + cr->Respawn(); + if (!cr->IsInEvadeMode()) cr->AI()->EnterEvadeMode(); + } + } + break; + } + if (data == DONE) + SaveToDB(); + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_ELDER_NADOX_EVENT: return m_auiEncounter[0]; + case DATA_PRINCE_TALDARAM_EVENT: return m_auiEncounter[1]; + case DATA_JEDOGA_SHADOWSEEKER_EVENT: return m_auiEncounter[2]; + case DATA_HERALD_VOLAZJ: return m_auiEncounter[3]; + case DATA_AMANITAR_EVENT: return m_auiEncounter[4]; + case DATA_SPHERE1_EVENT: return spheres[0]; + case DATA_SPHERE2_EVENT: return spheres[1]; + case DATA_ALL_INITIAND_DEAD: + for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + { + Creature* cr = instance->GetCreature(*itr); + if (!cr || (cr && cr->isAlive())) return 0; + } + return 1; + case DATA_JEDOGA_TRIGGER_SWITCH: return switchtrigger; + } + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "A K " << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' + << m_auiEncounter[2] << ' ' << m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' ' + << spheres[0] << ' ' << spheres[1]; + + str_data = saveStream.str(); + + OUT_SAVE_INST_DATA_COMPLETE; + return str_data; + } + + void Load(const char* in) + { + if (!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(in); + + char dataHead1, dataHead2; + uint16 data0, data1, data2, data3, data4, data5, data6; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4 >> data5 >> data6; + + if (dataHead1 == 'A' && dataHead2 == 'K') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + m_auiEncounter[3] = data3; + m_auiEncounter[4] = data4; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + spheres[0] = data5; + spheres[1] = data6; + + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const + { + return new instance_ahnkahet_InstanceScript(map); + } +}; + +void AddSC_instance_ahnkahet() +{ + new instance_ahnkahet; +} diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/ahnkahet.h b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/ahnkahet.h deleted file mode 100644 index e19054d2f46..00000000000 --- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/ahnkahet.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 DEF_AHNKAHET_H -#define DEF_AHNKAHET_H - -enum Data64 -{ - DATA_ELDER_NADOX, - DATA_PRINCE_TALDARAM, - DATA_JEDOGA_SHADOWSEEKER, - DATA_HERALD_VOLAZJ, - DATA_AMANITAR, - DATA_SPHERE1, - DATA_SPHERE2, - DATA_PRINCE_TALDARAM_PLATFORM, - DATA_PL_JEDOGA_TARGET, - DATA_ADD_JEDOGA_OPFER, - DATA_ADD_JEDOGA_INITIAND -}; - -enum Data -{ - DATA_ELDER_NADOX_EVENT, - DATA_PRINCE_TALDARAM_EVENT, - DATA_JEDOGA_SHADOWSEEKER_EVENT, - DATA_HERALD_VOLAZJ_EVENT, - DATA_AMANITAR_EVENT, - DATA_SPHERE1_EVENT, - DATA_SPHERE2_EVENT, - DATA_JEDOGA_TRIGGER_SWITCH, - DATA_JEDOGA_RESET_INITIANDS, - DATA_ALL_INITIAND_DEAD -}; - -#endif diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_amanitar.cpp b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_amanitar.cpp deleted file mode 100644 index cde97f8d37b..00000000000 --- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_amanitar.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 . - */ - -/* - * Comment: Find correct mushrooms spell to make them visible - buffs of the mushrooms not ever applied to the users... - */ - -#include "ScriptPCH.h" -#include "ahnkahet.h" - -enum Spells -{ - SPELL_BASH = 57094, // Victim - SPELL_ENTANGLING_ROOTS = 57095, // Random Victim 100Y - SPELL_MINI = 57055, // Self - SPELL_VENOM_BOLT_VOLLEY = 57088, // Random Victim 100Y - SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS = 56648, // Killer 3Y - SPELL_POISONOUS_MUSHROOM_POISON_CLOUD = 57061, // Self - Duration 8 Sec - SPELL_POISONOUS_MUSHROOM_VISUAL_AREA = 61566, // Self - SPELL_POISONOUS_MUSHROOM_VISUAL_AURA = 56741, // Self - SPELL_PUTRID_MUSHROOM = 31690, // To make the mushrooms visible -}; - -enum Creatures -{ - NPC_HEALTHY_MUSHROOM = 30391, - NPC_POISONOUS_MUSHROOM = 30435 -}; - -class boss_amanitar : public CreatureScript -{ -public: - boss_amanitar() : CreatureScript("boss_amanitar") { } - - struct boss_amanitarAI : public ScriptedAI - { - boss_amanitarAI(Creature* c) : ScriptedAI(c) - { - instance = c->GetInstanceScript(); - bFirstTime = true; - } - - InstanceScript* instance; - - uint32 uiRootTimer; - uint32 uiBashTimer; - uint32 uiBoltTimer; - uint32 uiSpawnTimer; - - bool bFirstTime; - - void Reset() - { - uiRootTimer = urand(5*IN_MILLISECONDS, 9*IN_MILLISECONDS); - uiBashTimer = urand(10*IN_MILLISECONDS, 14*IN_MILLISECONDS); - uiBoltTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - uiSpawnTimer = 0; - - me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); - me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); - - if (instance) - { - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI); - if (!bFirstTime) - instance->SetData(DATA_AMANITAR_EVENT, FAIL); - else - bFirstTime = false; - } - } - - void JustDied(Unit* /*Killer*/) - { - if (instance) - { - instance->SetData(DATA_AMANITAR_EVENT, DONE); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI); - } - } - - void EnterCombat(Unit* /*who*/) - { - if (instance) - instance->SetData(DATA_AMANITAR_EVENT, IN_PROGRESS); - - DoCast(me, SPELL_MINI, false); - } - - void SpawnAdds() - { - for (uint8 i = 0; i < 30; ++i) - { - Unit* victim = SelectTarget(SELECT_TARGET_RANDOM, 0); - - if (victim) - { - Position pos; - victim->GetPosition(&pos); - me->GetRandomNearPosition(pos, float(urand(5, 80))); - me->SummonCreature(NPC_POISONOUS_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30*IN_MILLISECONDS); - me->GetRandomNearPosition(pos, float(urand(5, 80))); - me->SummonCreature(NPC_HEALTHY_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30*IN_MILLISECONDS); - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (uiSpawnTimer <= diff) - { - SpawnAdds(); - uiSpawnTimer = urand(35*IN_MILLISECONDS, 40*IN_MILLISECONDS); - } else uiSpawnTimer -= diff; - - if (uiRootTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - DoCast(target, SPELL_ENTANGLING_ROOTS); - uiRootTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else uiRootTimer -= diff; - - if (uiBashTimer <= diff) - { - DoCastVictim(SPELL_BASH); - uiBashTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else uiBashTimer -= diff; - - if (uiBoltTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - DoCast(target, SPELL_VENOM_BOLT_VOLLEY); - uiBoltTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else uiBoltTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_amanitarAI(creature); - } -}; - -class mob_amanitar_mushrooms : public CreatureScript -{ -public: - mob_amanitar_mushrooms() : CreatureScript("mob_amanitar_mushrooms") { } - - struct mob_amanitar_mushroomsAI : public Scripted_NoMovementAI - { - mob_amanitar_mushroomsAI(Creature* c) : Scripted_NoMovementAI(c) {} - - uint32 uiAuraTimer; - uint32 uiDeathTimer; - - void Reset() - { - DoCast(me, SPELL_PUTRID_MUSHROOM, true); // Hack, to make the mushrooms visible, can't find orig. spell... - - if (me->GetEntry() == NPC_POISONOUS_MUSHROOM) - DoCast(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AURA, true); - - uiAuraTimer = 0; - uiDeathTimer = 30*IN_MILLISECONDS; - } - - void JustDied(Unit* killer) - { - if (!killer) - return; - - if (me->GetEntry() == NPC_HEALTHY_MUSHROOM && killer->GetTypeId() == TYPEID_PLAYER) - { - me->InterruptNonMeleeSpells(false); - DoCast(killer, SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS, false); - } - } - - void EnterCombat(Unit* /*who*/) {} - void AttackStart(Unit* /*victim*/) {} - - void UpdateAI(const uint32 diff) - { - if (me->GetEntry() == NPC_POISONOUS_MUSHROOM) - { - if (uiAuraTimer <= diff) - { - DoCast(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AREA, true); - DoCast(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false); - uiAuraTimer = 7*IN_MILLISECONDS; - } else uiAuraTimer -= diff; - } - if (uiDeathTimer <= diff) - me->DisappearAndDie(); - else uiDeathTimer -= diff; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_amanitar_mushroomsAI(creature); - } -}; - -void AddSC_boss_amanitar() -{ - new boss_amanitar; - new mob_amanitar_mushrooms; -} diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_elder_nadox.cpp b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_elder_nadox.cpp deleted file mode 100644 index a2371fa0121..00000000000 --- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_elder_nadox.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "ScriptPCH.h" -#include "ahnkahet.h" - -//not in db -enum Yells -{ - SAY_AGGRO = -1619014, - SAY_SLAY_1 = -1619015, - SAY_SLAY_2 = -1619016, - SAY_SLAY_3 = -1619017, - SAY_DEATH = -1619018, - SAY_EGG_SAC_1 = -1619019, - SAY_EGG_SAC_2 = -1619020 -}; - -enum Spells -{ - SPELL_BROOD_PLAGUE = 56130, - H_SPELL_BROOD_PLAGUE = 59467, - H_SPELL_BROOD_RAGE = 59465, - SPELL_ENRAGE = 26662, // Enraged if too far away from home - SPELL_SUMMON_SWARMERS = 56119, //2x 30178 -- 2x every 10secs - SPELL_SUMMON_SWARM_GUARD = 56120, //1x 30176 -- every 25secs -}; - -enum Creatures -{ - MOB_AHNKAHAR_SWARMER = 30178, - MOB_AHNKAHAR_GUARDIAN_ENTRY = 30176 -}; - -#define ACTION_AHNKAHAR_GUARDIAN_DEAD 1 -#define DATA_RESPECT_YOUR_ELDERS 2 - -#define EMOTE_HATCHES "An Ahn'kahar Guardian hatches!" - -class boss_elder_nadox : public CreatureScript -{ - public: - boss_elder_nadox() : CreatureScript("boss_elder_nadox") { } - - struct boss_elder_nadoxAI : public ScriptedAI - { - boss_elder_nadoxAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - uint32 uiPlagueTimer; - uint32 uiRagueTimer; - - uint32 uiSwarmerSpawnTimer; - uint32 uiGuardSpawnTimer; - uint32 uiEnrageTimer; - - bool bGuardSpawned; - bool respectYourElders; - - InstanceScript* instance; - - void Reset() - { - uiPlagueTimer = 13000; - uiRagueTimer = 20000; - - uiSwarmerSpawnTimer = 10000; - uiGuardSpawnTimer = 25000; - - uiEnrageTimer = 5000; - - bGuardSpawned = false; - respectYourElders = true; - - if (instance) - instance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED); - } - - void EnterCombat(Unit* /*who*/) - { - DoScriptText(SAY_DEATH, me); - - if (instance) - instance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS); - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2, SAY_SLAY_3), me); - } - - void JustDied(Unit* /*who*/) - { - DoScriptText(SAY_SLAY_3, me); //SAY_SLAY_3 on death? - - if (instance) - instance->SetData(DATA_ELDER_NADOX_EVENT, DONE); - } - - void DoAction(int32 const action) - { - if (action == ACTION_AHNKAHAR_GUARDIAN_DEAD) - respectYourElders = false; - } - - uint32 GetData(uint32 type) - { - if (type == DATA_RESPECT_YOUR_ELDERS) - return respectYourElders ? 1 : 0; - - return 0; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (uiPlagueTimer <= diff) - { - DoCast(me->getVictim(), SPELL_BROOD_PLAGUE); - uiPlagueTimer = 15000; - } - else - uiPlagueTimer -= diff; - - if (IsHeroic()) - { - if (uiRagueTimer <= diff) - { - if (Creature* Swarmer = me->FindNearestCreature(MOB_AHNKAHAR_SWARMER, 35.0f)) - { - DoCast(Swarmer, H_SPELL_BROOD_RAGE, true); - uiRagueTimer = 15000; - } - } - else - uiRagueTimer -= diff; - } - - if (uiSwarmerSpawnTimer <= diff) - { - DoCast(me, SPELL_SUMMON_SWARMERS, true); - DoCast(me, SPELL_SUMMON_SWARMERS); - if (urand(1, 3) == 3) // 33% chance of dialog - DoScriptText(RAND(SAY_EGG_SAC_1, SAY_EGG_SAC_2), me); - - uiSwarmerSpawnTimer = 10000; - } - else - uiSwarmerSpawnTimer -= diff; - - if (!bGuardSpawned && uiGuardSpawnTimer <= diff) - { - me->MonsterTextEmote(EMOTE_HATCHES, me->GetGUID(), true); - DoCast(me, SPELL_SUMMON_SWARM_GUARD); - bGuardSpawned = true; - } - else - uiGuardSpawnTimer -= diff; - - if (uiEnrageTimer <= diff) - { - if (me->HasAura(SPELL_ENRAGE, 0)) - return; - - float x, y, z, o; - me->GetHomePosition(x, y, z, o); - if (z < 24) - if (!me->IsNonMeleeSpellCasted(false)) - DoCast(me, SPELL_ENRAGE, true); - - uiEnrageTimer = 5000; - } - else - uiEnrageTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_elder_nadoxAI(creature); - } -}; - -enum AddSpells -{ - SPELL_SPRINT = 56354, - SPELL_GUARDIAN_AURA = 56151 -}; - -class mob_ahnkahar_nerubian : public CreatureScript -{ - public: - mob_ahnkahar_nerubian() : CreatureScript("mob_ahnkahar_nerubian") { } - - struct mob_ahnkahar_nerubianAI : public ScriptedAI - { - mob_ahnkahar_nerubianAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 uiSprintTimer; - - void Reset() - { - if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) - DoCast(me, SPELL_GUARDIAN_AURA, true); - uiSprintTimer = 10000; - } - - void JustDied(Unit* /*who*/) - { - if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) - if (Creature* Nadox = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ELDER_NADOX))) - Nadox->AI()->DoAction(ACTION_AHNKAHAR_GUARDIAN_DEAD); - } - - void EnterCombat(Unit* /*who*/) - { - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) - me->RemoveAurasDueToSpell(SPELL_GUARDIAN_AURA); - - if (instance) - if (instance->GetData(DATA_ELDER_NADOX_EVENT) != IN_PROGRESS) - me->DespawnOrUnsummon(); - - if (uiSprintTimer <= diff) - { - DoCast(me, SPELL_SPRINT); - uiSprintTimer = 25000; - } - else - uiSprintTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_ahnkahar_nerubianAI(creature); - } -}; - -//HACK: No, AI. Replace with proper db content? -class mob_nadox_eggs : public CreatureScript -{ -public: - mob_nadox_eggs() : CreatureScript("mob_nadox_eggs") { } - - struct mob_nadox_eggsAI : public Scripted_NoMovementAI - { - mob_nadox_eggsAI(Creature* c) : Scripted_NoMovementAI(c) - { - c->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - c->UpdateAllStats(); - } - void Reset() {} - void EnterCombat(Unit* /*who*/) {} - void AttackStart(Unit* /*victim*/) {} - void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_nadox_eggsAI(creature); - } -}; - -class achievement_respect_your_elders : public AchievementCriteriaScript -{ - public: - achievement_respect_your_elders() : AchievementCriteriaScript("achievement_respect_your_elders") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Nadox = target->ToCreature()) - if (Nadox->AI()->GetData(DATA_RESPECT_YOUR_ELDERS)) - return true; - - return false; - } -}; - -void AddSC_boss_elder_nadox() -{ - new boss_elder_nadox; - new mob_ahnkahar_nerubian; - new mob_nadox_eggs; - new achievement_respect_your_elders(); -} diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_herald_volazj.cpp b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_herald_volazj.cpp deleted file mode 100644 index bc4d4ba5eea..00000000000 --- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_herald_volazj.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 . - */ - -/* - * Comment: Missing AI for Twisted Visages - */ - -#include "ScriptPCH.h" -#include "ahnkahet.h" - -enum Spells -{ - SPELL_INSANITY = 57496, //Dummy - INSANITY_VISUAL = 57561, - SPELL_INSANITY_TARGET = 57508, - SPELL_MIND_FLAY = 57941, - SPELL_SHADOW_BOLT_VOLLEY = 57942, - SPELL_SHIVER = 57949, - SPELL_CLONE_PLAYER = 57507, //casted on player during insanity - SPELL_INSANITY_PHASING_1 = 57508, - SPELL_INSANITY_PHASING_2 = 57509, - SPELL_INSANITY_PHASING_3 = 57510, - SPELL_INSANITY_PHASING_4 = 57511, - SPELL_INSANITY_PHASING_5 = 57512 -}; - -enum Creatures -{ - MOB_TWISTED_VISAGE = 30625 -}; - -//not in db -enum Yells -{ - SAY_AGGRO = -1619030, - SAY_SLAY_1 = -1619031, - SAY_SLAY_2 = -1619032, - SAY_SLAY_3 = -1619033, - SAY_DEATH_1 = -1619034, - SAY_DEATH_2 = -1619035, - SAY_PHASE = -1619036 -}; - -enum Achievements -{ - ACHIEV_QUICK_DEMISE_START_EVENT = 20382, -}; - -class boss_volazj : public CreatureScript -{ -public: - boss_volazj() : CreatureScript("boss_volazj") { } - - struct boss_volazjAI : public ScriptedAI - { - boss_volazjAI(Creature* creature) : ScriptedAI(creature), Summons(me) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 uiMindFlayTimer; - uint32 uiShadowBoltVolleyTimer; - uint32 uiShiverTimer; - uint32 insanityHandled; - SummonList Summons; - - // returns the percentage of health after taking the given damage. - uint32 GetHealthPct(uint32 damage) - { - if (damage > me->GetHealth()) - return 0; - return 100*(me->GetHealth()-damage)/me->GetMaxHealth(); - } - - void DamageTaken(Unit* /*pAttacker*/, uint32 &damage) - { - if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) - damage = 0; - - if ((GetHealthPct(0) >= 66 && GetHealthPct(damage) < 66)|| - (GetHealthPct(0) >= 33 && GetHealthPct(damage) < 33)) - { - me->InterruptNonMeleeSpells(false); - DoCast(me, SPELL_INSANITY, false); - } - } - - void SpellHitTarget(Unit* target, const SpellInfo* spell) - { - if (spell->Id == SPELL_INSANITY) - { - // Not good target or too many players - if (target->GetTypeId() != TYPEID_PLAYER || insanityHandled > 4) - return; - // First target - start channel visual and set self as unnattackable - if (!insanityHandled) - { - // Channel visual - DoCast(me, INSANITY_VISUAL, true); - // Unattackable - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetControlled(true, UNIT_STAT_STUNNED); - } - // phase mask - target->CastSpell(target, SPELL_INSANITY_TARGET+insanityHandled, true); - // summon twisted party members for this target - Map::PlayerList const &players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - { - Player* player = i->getSource(); - if (!player || !player->isAlive()) - continue; - // Summon clone - if (Unit* summon = me->SummonCreature(MOB_TWISTED_VISAGE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0)) - { - // clone - player->CastSpell(summon, SPELL_CLONE_PLAYER, true); - // set phase - summon->SetPhaseMask((1<<(4+insanityHandled)), true); - } - } - ++insanityHandled; - } - } - - void ResetPlayersPhaseMask() - { - Map::PlayerList const &players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - { - Player* player = i->getSource(); - player->RemoveAurasDueToSpell(GetSpellForPhaseMask(player->GetPhaseMask())); - } - } - - void Reset() - { - uiMindFlayTimer = 8*IN_MILLISECONDS; - uiShadowBoltVolleyTimer = 5*IN_MILLISECONDS; - uiShiverTimer = 15*IN_MILLISECONDS; - - if (instance) - { - instance->SetData(DATA_HERALD_VOLAZJ, NOT_STARTED); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); - } - - // Visible for all players in insanity - me->SetPhaseMask((1|16|32|64|128|256), true); - // Used for Insanity handling - insanityHandled = 0; - - ResetPlayersPhaseMask(); - - // Cleanup - Summons.DespawnAll(); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetControlled(false, UNIT_STAT_STUNNED); - } - - void EnterCombat(Unit* /*who*/) - { - DoScriptText(SAY_AGGRO, me); - - if (instance) - { - instance->SetData(DATA_HERALD_VOLAZJ, IN_PROGRESS); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); - } - } - - void JustSummoned(Creature* summon) - { - Summons.Summon(summon); - } - - uint32 GetSpellForPhaseMask(uint32 phase) - { - uint32 spell = 0; - switch (phase) - { - case 16: - spell = SPELL_INSANITY_PHASING_1; - break; - case 32: - spell = SPELL_INSANITY_PHASING_2; - break; - case 64: - spell = SPELL_INSANITY_PHASING_3; - break; - case 128: - spell = SPELL_INSANITY_PHASING_4; - break; - case 256: - spell = SPELL_INSANITY_PHASING_5; - break; - } - return spell; - } - - void SummonedCreatureDespawn(Creature* summon) - { - uint32 phase= summon->GetPhaseMask(); - uint32 nextPhase = 0; - Summons.Despawn(summon); - - // Check if all summons in this phase killed - for (SummonList::const_iterator iter = Summons.begin(); iter != Summons.end(); ++iter) - { - if (Creature* visage = Unit::GetCreature(*me, *iter)) - { - // Not all are dead - if (phase == visage->GetPhaseMask()) - return; - else - nextPhase = visage->GetPhaseMask(); - } - } - - // Roll Insanity - uint32 spell = GetSpellForPhaseMask(phase); - uint32 spell2 = GetSpellForPhaseMask(nextPhase); - Map* map = me->GetMap(); - if (!map) - return; - - Map::PlayerList const &PlayerList = map->GetPlayers(); - if (!PlayerList.isEmpty()) - { - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (Player* player = i->getSource()) - { - if (player->HasAura(spell)) - { - player->RemoveAurasDueToSpell(spell); - if (spell2) // if there is still some different mask cast spell for it - player->CastSpell(player, spell2, true); - } - } - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (insanityHandled) - { - if (!Summons.empty()) - return; - - insanityHandled = 0; - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetControlled(false, UNIT_STAT_STUNNED); - me->RemoveAurasDueToSpell(INSANITY_VISUAL); - } - - if (uiMindFlayTimer <= diff) - { - DoCast(me->getVictim(), SPELL_MIND_FLAY); - uiMindFlayTimer = 20*IN_MILLISECONDS; - } else uiMindFlayTimer -= diff; - - if (uiShadowBoltVolleyTimer <= diff) - { - DoCast(me->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); - uiShadowBoltVolleyTimer = 5*IN_MILLISECONDS; - } else uiShadowBoltVolleyTimer -= diff; - - if (uiShiverTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_SHIVER); - uiShiverTimer = 15*IN_MILLISECONDS; - } else uiShiverTimer -= diff; - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) - { - DoScriptText(SAY_DEATH_1, me); - - if (instance) - instance->SetData(DATA_HERALD_VOLAZJ, DONE); - - Summons.DespawnAll(); - ResetPlayersPhaseMask(); - } - - void KilledUnit(Unit* /*victim*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2, SAY_SLAY_3), me); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_volazjAI(creature); - } -}; - -void AddSC_boss_volazj() -{ - new boss_volazj; -} diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp deleted file mode 100644 index b2975797a02..00000000000 --- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 . - */ - -/* - * Comment: Complete - BUT THE TRIGGER NEEDS DATA WHETHER THE PRISON OF TALDARAM IS OFFLINE ! - */ - -#include "ScriptPCH.h" -#include "ahnkahet.h" - -enum Yells -{ - TEXT_AGGRO = -1619000, - TEXT_SACRIFICE_1_1 = -1619001, - TEXT_SACRIFICE_1_2 = -1619002, - TEXT_SACRIFICE_2_1 = -1619003, - TEXT_SACRIFICE_2_2 = -1619004, - TEXT_SLAY_1 = -1619005, - TEXT_SLAY_2 = -1619006, - TEXT_SLAY_3 = -1619007, - TEXT_DEATH = -1619008, - TEXT_PREACHING_1 = -1619009, - TEXT_PREACHING_2 = -1619010, - TEXT_PREACHING_3 = -1619011, - TEXT_PREACHING_4 = -1619012, - TEXT_PREACHING_5 = -1619013 -}; - -enum Spells -{ - SPELL_SPHERE_VISUAL = 56075, - SPELL_GIFT_OF_THE_HERALD = 56219, - SPELL_CYCLONE_STRIKE = 56855, // Self - SPELL_CYCLONE_STRIKE_H = 60030, - SPELL_LIGHTNING_BOLT = 56891, // 40Y - SPELL_LIGHTNING_BOLT_H = 60032, // 40Y - SPELL_THUNDERSHOCK = 56926, // 30Y - SPELL_THUNDERSHOCK_H = 60029 // 30Y -}; - -enum Creatures -{ - NPC_JEDOGA_CONTROLLER = 30181 -}; - -const Position JedogaPosition[2] = -{ - {372.330994f, -705.278015f, -0.624178f, 5.427970f}, - {372.330994f, -705.278015f, -16.179716f, 5.427970f} -}; - -#define ACTION_INITIAND_KILLED 1 -#define DATA_VOLUNTEER_WORK 2 - -class boss_jedoga_shadowseeker : public CreatureScript -{ -public: - boss_jedoga_shadowseeker() : CreatureScript("boss_jedoga_shadowseeker") { } - - struct boss_jedoga_shadowseekerAI : public ScriptedAI - { - boss_jedoga_shadowseekerAI(Creature* c) : ScriptedAI(c) - { - instance = c->GetInstanceScript(); - bFirstTime = true; - bPreDone = false; - } - - InstanceScript* instance; - - uint32 uiOpFerTimer; - uint32 uiCycloneTimer; - uint32 uiBoltTimer; - uint32 uiThunderTimer; - - bool bPreDone; - bool bOpFerok; - bool bOnGround; - bool bOpFerokFail; - bool bCanDown; - bool volunteerWork; - bool bFirstTime; - - void Reset() - { - uiOpFerTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); - - uiCycloneTimer = 3*IN_MILLISECONDS; - uiBoltTimer = 7*IN_MILLISECONDS; - uiThunderTimer = 12*IN_MILLISECONDS; - - bOpFerok = false; - bOpFerokFail = false; - bOnGround = false; - bCanDown = false; - volunteerWork = true; - - if (instance) - { - if (!bFirstTime) - instance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, FAIL); - - instance->SetData64(DATA_PL_JEDOGA_TARGET, 0); - instance->SetData64(DATA_ADD_JEDOGA_OPFER, 0); - instance->SetData(DATA_JEDOGA_RESET_INITIANDS, 0); - } - MoveUp(); - - bFirstTime = false; - } - - void EnterCombat(Unit* who) - { - if (!instance || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_JEDOGA_CONTROLLER)) - return; - - DoScriptText(TEXT_AGGRO, me); - me->SetInCombatWithZone(); - instance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, IN_PROGRESS); - } - - void AttackStart(Unit* who) - { - if (!who || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_JEDOGA_CONTROLLER)) - return; - - ScriptedAI::AttackStart(who); - } - - void KilledUnit(Unit* Victim) - { - if (!Victim || Victim->GetTypeId() != TYPEID_PLAYER) - return; - - DoScriptText(RAND(TEXT_SLAY_1, TEXT_SLAY_2, TEXT_SLAY_3), me); - } - - void JustDied(Unit* /*Killer*/) - { - DoScriptText(TEXT_DEATH, me); - if (instance) - instance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, DONE); - } - - void DoAction(int32 const action) - { - if (action == ACTION_INITIAND_KILLED) - volunteerWork = false; - } - - uint32 GetData(uint32 type) - { - if (type == DATA_VOLUNTEER_WORK) - return volunteerWork ? 1 : 0; - - return 0; - } - - void MoveInLineOfSight(Unit* who) - { - if (!instance || !who || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_JEDOGA_CONTROLLER)) - return; - - if (!bPreDone && who->GetTypeId() == TYPEID_PLAYER && me->GetDistance(who) < 100.0f) - { - DoScriptText(RAND(TEXT_PREACHING_1, TEXT_PREACHING_2, TEXT_PREACHING_3, TEXT_PREACHING_4, TEXT_PREACHING_5), me); - bPreDone = true; - } - - if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS || !bOnGround) - return; - - if (!me->getVictim() && me->canCreatureAttack(who)) - { - float attackRadius = me->GetAttackDistance(who); - if (me->IsWithinDistInMap(who, attackRadius) && me->IsWithinLOSInMap(who)) - { - if (!me->getVictim()) - { - who->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } - else if (me->GetMap()->IsDungeon()) - { - who->SetInCombatWith(me); - me->AddThreat(who, 0.0f); - } - } - } - } - - void MoveDown() - { - if (!instance) - return; - - bOpFerokFail = false; - - instance->SetData(DATA_JEDOGA_TRIGGER_SWITCH, 0); - me->GetMotionMaster()->MovePoint(1, JedogaPosition[1]); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - - me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); - - bOnGround = true; - - if (UpdateVictim()) - { - AttackStart(me->getVictim()); - me->GetMotionMaster()->MoveChase(me->getVictim()); - } - else - { - if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_PL_JEDOGA_TARGET))) - { - AttackStart(target); - instance->SetData(DATA_JEDOGA_RESET_INITIANDS, 0); - if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS) - EnterCombat(target); - } - else if (!me->isInCombat()) - EnterEvadeMode(); - } - } - - void MoveUp() - { - if (!instance) - return; - - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - - me->AttackStop(); - me->RemoveAllAuras(); - me->LoadCreaturesAddon(); - me->GetMotionMaster()->MovePoint(0, JedogaPosition[0]); - - instance->SetData(DATA_JEDOGA_TRIGGER_SWITCH, 1); - if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) OpferRufen(); - - bOnGround = false; - uiOpFerTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } - - void OpferRufen() - { - if (!instance) - return; - - uint64 opfer = instance->GetData64(DATA_ADD_JEDOGA_INITIAND); - - if (opfer) - { - DoScriptText(RAND(TEXT_SACRIFICE_1_1, TEXT_SACRIFICE_1_2), me); - instance->SetData64(DATA_ADD_JEDOGA_OPFER, opfer); - } else - bCanDown = true; - } - - void Opfern() - { - DoScriptText(RAND(TEXT_SACRIFICE_2_1, TEXT_SACRIFICE_2_2), me); - - me->InterruptNonMeleeSpells(false); - DoCast(me, SPELL_GIFT_OF_THE_HERALD, false); - - bOpFerok = false; - bCanDown = true; - } - - void UpdateAI(const uint32 diff) - { - if (!instance) - return; - - if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS && instance->GetData(DATA_ALL_INITIAND_DEAD)) - MoveDown(); - - if (bOpFerok && !bOnGround && !bCanDown) Opfern(); - - if (bOpFerokFail && !bOnGround && !bCanDown) - bCanDown = true; - - if (bCanDown) - { - MoveDown(); - bCanDown = false; - } - - if (bOnGround) - { - if (!UpdateVictim()) - return; - - if (uiCycloneTimer <= diff) - { - DoCast(me, SPELL_CYCLONE_STRIKE, false); - uiCycloneTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else uiCycloneTimer -= diff; - - if (uiBoltTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - me->CastSpell(target, DUNGEON_MODE(SPELL_LIGHTNING_BOLT, SPELL_LIGHTNING_BOLT_H), false); - - uiBoltTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else uiBoltTimer -= diff; - - if (uiThunderTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - me->CastSpell(target, DUNGEON_MODE(SPELL_THUNDERSHOCK, SPELL_THUNDERSHOCK_H), false); - - uiThunderTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); - } else uiThunderTimer -= diff; - - if (uiOpFerTimer <= diff) - MoveUp(); - else - uiOpFerTimer -= diff; - - DoMeleeAttackIfReady(); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_jedoga_shadowseekerAI(creature); - } -}; - -class mob_jedoga_initiand : public CreatureScript -{ -public: - mob_jedoga_initiand() : CreatureScript("mob_jedoga_initiand") { } - - struct mob_jedoga_initiandAI : public ScriptedAI - { - mob_jedoga_initiandAI(Creature* c) : ScriptedAI(c) - { - instance = c->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 bCheckTimer; - - bool bWalking; - - void Reset() - { - if (!instance) - return; - - bWalking = false; - bCheckTimer = 2*IN_MILLISECONDS; - - if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS) - { - me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - } - else - { - DoCast(me, SPELL_SPHERE_VISUAL, false); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - } - } - - void JustDied(Unit* Killer) - { - if (!Killer || !instance) - return; - - if (bWalking) - { - if (Creature* boss = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_JEDOGA_SHADOWSEEKER))) - { - if (!CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerok) - CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerokFail = true; - - boss->AI()->DoAction(ACTION_INITIAND_KILLED); - } - - instance->SetData64(DATA_ADD_JEDOGA_OPFER, 0); - - bWalking = false; - } - if (Killer->GetTypeId() == TYPEID_PLAYER) - instance->SetData64(DATA_PL_JEDOGA_TARGET, Killer->GetGUID()); - } - - void EnterCombat(Unit* who) - { - if ((instance && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !who) - return; - } - - void AttackStart(Unit* victim) - { - if ((instance && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !victim) - return; - - ScriptedAI::AttackStart(victim); - } - - void MoveInLineOfSight(Unit* who) - { - if ((instance && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !who) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void MovementInform(uint32 uiType, uint32 uiPointId) - { - if (uiType != POINT_MOTION_TYPE || !instance) - return; - - switch (uiPointId) - { - case 1: - { - Creature* boss = me->GetMap()->GetCreature(instance->GetData64(DATA_JEDOGA_SHADOWSEEKER)); - if (boss) - { - CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerok = true; - CAST_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerokFail = false; - me->Kill(me); - } - } - break; - } - } - - void UpdateAI(const uint32 diff) - { - if (instance && bCheckTimer <= diff) - { - if (me->GetGUID() == instance->GetData64(DATA_ADD_JEDOGA_OPFER) && !bWalking) - { - me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - - float distance = me->GetDistance(JedogaPosition[1]); - - if (distance < 9.0f) - me->SetSpeed(MOVE_WALK, 0.5f, true); - else if (distance < 15.0f) - me->SetSpeed(MOVE_WALK, 0.75f, true); - else if (distance < 20.0f) - me->SetSpeed(MOVE_WALK, 1.0f, true); - - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MovePoint(1, JedogaPosition[1]); - bWalking = true; - } - if (!bWalking) - { - if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS && me->HasAura(SPELL_SPHERE_VISUAL)) - { - me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - } - if (instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS && !me->HasAura(SPELL_SPHERE_VISUAL)) - { - DoCast(me, SPELL_SPHERE_VISUAL, false); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - } - } - bCheckTimer = 2*IN_MILLISECONDS; - } else bCheckTimer -= diff; - - //Return since we have no target - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_jedoga_initiandAI(creature); - } -}; - -// ------------------------------------------------------------------------------------------------------------ -// Jedogas Aufseher - Entry: 30181 -// ------------------------------------------------------------------------------------------------------------ -enum AufseherSpell -{ - SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_1 = 60342, - SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_2 = 56312 -}; - -class npc_jedogas_aufseher_trigger : public CreatureScript -{ -public: - npc_jedogas_aufseher_trigger() : CreatureScript("npc_jedogas_aufseher_trigger") { } - - struct npc_jedogas_aufseher_triggerAI : public Scripted_NoMovementAI - { - npc_jedogas_aufseher_triggerAI(Creature* c) : Scripted_NoMovementAI(c) - { - instance = c->GetInstanceScript(); - bRemoved = false; - bRemoved2 = false; - bCasted = false; - bCasted2 = false; - } - - InstanceScript* instance; - - bool bRemoved; - bool bRemoved2; - bool bCasted; - bool bCasted2; - - void Reset() {} - void EnterCombat(Unit* /*who*/) {} - void AttackStart(Unit* /*victim*/) {} - void MoveInLineOfSight(Unit* /*who*/) {} - - void UpdateAI(const uint32 /*diff*/) - { - if (!instance) - return; - - if (!bRemoved && me->GetPositionX() > 440.0f) - { - if (instance->GetData(DATA_PRINCE_TALDARAM_EVENT) == DONE) - { - me->InterruptNonMeleeSpells(true); - bRemoved = true; - return; - } - if (!bCasted) - { - DoCast(me, SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_1, false); - bCasted = true; - } - } - if (!bRemoved2 && me->GetPositionX() < 440.0f) - { - if (!bCasted2 && instance->GetData(DATA_JEDOGA_TRIGGER_SWITCH)) - { - DoCast(me, SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_2, false); - bCasted2 = true; - } - if (bCasted2 && !instance->GetData(DATA_JEDOGA_TRIGGER_SWITCH)) - { - me->InterruptNonMeleeSpells(true); - bCasted2 = false; - } - if (!bRemoved2 && instance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == DONE) - { - me->InterruptNonMeleeSpells(true); - bRemoved2 = true; - } - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_jedogas_aufseher_triggerAI(creature); - } -}; - -class achievement_volunteer_work : public AchievementCriteriaScript -{ - public: - achievement_volunteer_work() : AchievementCriteriaScript("achievement_volunteer_work") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Jedoga = target->ToCreature()) - if (Jedoga->AI()->GetData(DATA_VOLUNTEER_WORK)) - return true; - - return false; - } -}; - -void AddSC_boss_jedoga_shadowseeker() -{ - new boss_jedoga_shadowseeker(); - new mob_jedoga_initiand(); - new npc_jedogas_aufseher_trigger(); - new achievement_volunteer_work(); -} diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_prince_taldaram.cpp deleted file mode 100644 index 9a7dc2f2cc9..00000000000 --- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_prince_taldaram.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "ScriptPCH.h" -#include "ahnkahet.h" - -enum Spells -{ - SPELL_BLOODTHIRST = 55968, //Trigger Spell + add aura - SPELL_CONJURE_FLAME_SPHERE = 55931, - SPELL_FLAME_SPHERE_SUMMON_1 = 55895, // 1x 30106 - H_SPELL_FLAME_SPHERE_SUMMON_1 = 59511, // 1x 31686 - H_SPELL_FLAME_SPHERE_SUMMON_2 = 59512, // 1x 31687 - SPELL_FLAME_SPHERE_SPAWN_EFFECT = 55891, - SPELL_FLAME_SPHERE_VISUAL = 55928, - SPELL_FLAME_SPHERE_PERIODIC = 55926, - H_SPELL_FLAME_SPHERE_PERIODIC = 59508, - SPELL_FLAME_SPHERE_DEATH_EFFECT = 55947, - SPELL_BEAM_VISUAL = 60342, - SPELL_EMBRACE_OF_THE_VAMPYR = 55959, - H_SPELL_EMBRACE_OF_THE_VAMPYR = 59513, - SPELL_VANISH = 55964, - CREATURE_FLAME_SPHERE = 30106, - H_CREATURE_FLAME_SPHERE_1 = 31686, - H_CREATURE_FLAME_SPHERE_2 = 31687 -}; -enum Misc -{ - DATA_EMBRACE_DMG = 20000, - H_DATA_EMBRACE_DMG = 40000, - DATA_SPHERE_DISTANCE = 15 -}; -#define DATA_SPHERE_ANGLE_OFFSET 0.7f -#define DATA_GROUND_POSITION_Z 11.4f - -enum Yells -{ - SAY_AGGRO = -1619021, - SAY_SLAY_1 = -1619022, - SAY_SLAY_2 = -1619023, - SAY_DEATH = -1619024, - SAY_FEED_1 = -1619025, - SAY_FEED_2 = -1619026, - SAY_VANISH_1 = -1619027, - SAY_VANISH_2 = -1619028 -}; -enum CombatPhase -{ - NORMAL, - CASTING_FLAME_SPHERES, - JUST_VANISHED, - VANISHED, - FEEDING -}; -enum GameObjects -{ - GO_SPHERE1 = 193093, - GO_SPHERE2 = 193094 -}; - -class boss_taldaram : public CreatureScript -{ -public: - boss_taldaram() : CreatureScript("boss_taldaram") { } - - struct boss_taldaramAI : public ScriptedAI - { - boss_taldaramAI(Creature* c) : ScriptedAI(c) - { - instance = c->GetInstanceScript(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - uint32 uiBloodthirstTimer; - uint32 uiVanishTimer; - uint32 uiWaitTimer; - uint32 uiEmbraceTimer; - uint32 uiEmbraceTakenDamage; - uint32 uiFlamesphereTimer; - uint32 uiPhaseTimer; - - uint64 uiEmbraceTarget; - - CombatPhase Phase; - - InstanceScript* instance; - - void Reset() - { - uiBloodthirstTimer = 10*IN_MILLISECONDS; - uiVanishTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS); - uiEmbraceTimer = 20*IN_MILLISECONDS; - uiFlamesphereTimer = 5*IN_MILLISECONDS; - uiEmbraceTakenDamage = 0; - Phase = NORMAL; - uiPhaseTimer = 0; - uiEmbraceTarget = 0; - if (instance) - instance->SetData(DATA_PRINCE_TALDARAM_EVENT, NOT_STARTED); - } - - void EnterCombat(Unit* /*who*/) - { - if (instance) - instance->SetData(DATA_PRINCE_TALDARAM_EVENT, IN_PROGRESS); - DoScriptText(SAY_AGGRO, me); - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; - if (uiPhaseTimer <= diff) - { - switch (Phase) - { - case CASTING_FLAME_SPHERES: - { - Creature* pSpheres[3]; - - //DoCast(me, SPELL_FLAME_SPHERE_SUMMON_1); - pSpheres[0] = DoSpawnCreature(CREATURE_FLAME_SPHERE, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS); - Unit* pSphereTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (pSphereTarget && pSpheres[0]) - { - float angle, x, y; - angle = pSpheres[0]->GetAngle(pSphereTarget); - x = pSpheres[0]->GetPositionX() + DATA_SPHERE_DISTANCE * cos(angle); - y = pSpheres[0]->GetPositionY() + DATA_SPHERE_DISTANCE * sin(angle); - pSpheres[0]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[0]->GetPositionZ()); - } - if (IsHeroic()) - { - //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_1); - pSpheres[1] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_1, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS); - //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_2); - pSpheres[2] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_2, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS); - if (pSphereTarget && pSpheres[1] && pSpheres[2]) - { - float angle, x, y; - angle = pSpheres[1]->GetAngle(pSphereTarget) + DATA_SPHERE_ANGLE_OFFSET; - x = pSpheres[1]->GetPositionX() + DATA_SPHERE_DISTANCE/2 * cos(angle); - y = pSpheres[1]->GetPositionY() + DATA_SPHERE_DISTANCE/2 * sin(angle); - pSpheres[1]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[1]->GetPositionZ()); - angle = pSpheres[2]->GetAngle(pSphereTarget) - DATA_SPHERE_ANGLE_OFFSET; - x = pSpheres[2]->GetPositionX() + DATA_SPHERE_DISTANCE/2 * cos(angle); - y = pSpheres[2]->GetPositionY() + DATA_SPHERE_DISTANCE/2 * sin(angle); - pSpheres[2]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[2]->GetPositionZ()); - } - } - - Phase = NORMAL; - uiPhaseTimer = 0; - break; - } - case JUST_VANISHED: - if (Unit* pEmbraceTarget = GetEmbraceTarget()) - { - me->GetMotionMaster()->Clear(); - me->SetSpeed(MOVE_WALK, 2.0f, true); - me->GetMotionMaster()->MoveChase(pEmbraceTarget); - } - Phase = VANISHED; - uiPhaseTimer = 1300; - break; - case VANISHED: - if (Unit* pEmbraceTarget = GetEmbraceTarget()) - DoCast(pEmbraceTarget, SPELL_EMBRACE_OF_THE_VAMPYR); - me->GetMotionMaster()->Clear(); - me->SetSpeed(MOVE_WALK, 1.0f, true); - me->GetMotionMaster()->MoveChase(me->getVictim()); - Phase = FEEDING; - uiPhaseTimer = 20*IN_MILLISECONDS; - break; - case FEEDING: - Phase = NORMAL; - uiPhaseTimer = 0; - uiEmbraceTarget = 0; - break; - case NORMAL: - if (uiBloodthirstTimer <= diff) - { - DoCast(me, SPELL_BLOODTHIRST); - uiBloodthirstTimer = 10*IN_MILLISECONDS; - } else uiBloodthirstTimer -= diff; - - if (uiFlamesphereTimer <= diff) - { - DoCast(me, SPELL_CONJURE_FLAME_SPHERE); - Phase = CASTING_FLAME_SPHERES; - uiPhaseTimer = 3*IN_MILLISECONDS + diff; - uiFlamesphereTimer = 15*IN_MILLISECONDS; - } else uiFlamesphereTimer -= diff; - - if (uiVanishTimer <= diff) - { - //Count alive players - Unit* target = NULL; - std::list t_list = me->getThreatManager().getThreatList(); - std::vector target_list; - for (std::list::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = Unit::GetUnit(*me, (*itr)->getUnitGuid()); - // exclude pets & totems - if (target && target->GetTypeId() == TYPEID_PLAYER && target->isAlive()) - target_list.push_back(target); - target = NULL; - } - //He only vanishes if there are 3 or more alive players - if (target_list.size() > 2) - { - DoScriptText(RAND(SAY_VANISH_1, SAY_VANISH_2), me); - DoCast(me, SPELL_VANISH); - Phase = JUST_VANISHED; - uiPhaseTimer = 500; - if (Unit* pEmbraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - uiEmbraceTarget = pEmbraceTarget->GetGUID(); - - } - uiVanishTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS); - } else uiVanishTimer -= diff; - - DoMeleeAttackIfReady(); - break; - } - } else uiPhaseTimer -= diff; - } - - void DamageTaken(Unit* /*done_by*/, uint32 &damage) - { - Unit* pEmbraceTarget = GetEmbraceTarget(); - - if (Phase == FEEDING && pEmbraceTarget && pEmbraceTarget->isAlive()) - { - uiEmbraceTakenDamage += damage; - if (uiEmbraceTakenDamage > (uint32) DUNGEON_MODE(DATA_EMBRACE_DMG, H_DATA_EMBRACE_DMG)) - { - Phase = NORMAL; - uiPhaseTimer = 0; - uiEmbraceTarget = 0; - me->CastStop(); - } - } - } - - void JustDied(Unit* /*killer*/) - { - DoScriptText(SAY_DEATH, me); - - if (instance) - instance->SetData(DATA_PRINCE_TALDARAM_EVENT, DONE); - } - - void KilledUnit(Unit* victim) - { - if (victim == me) - return; - - Unit* pEmbraceTarget = GetEmbraceTarget(); - if (Phase == FEEDING && pEmbraceTarget && victim == pEmbraceTarget) - { - Phase = NORMAL; - uiPhaseTimer = 0; - uiEmbraceTarget = 0; - } - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - bool CheckSpheres() - { - if (!instance) - return false; - - uint64 uiSphereGuids[2]; - uiSphereGuids[0] = instance->GetData64(DATA_SPHERE1); - uiSphereGuids[1] = instance->GetData64(DATA_SPHERE2); - - for (uint8 i=0; i < 2; ++i) - { - GameObject* pSpheres = instance->instance->GetGameObject(uiSphereGuids[i]); - if (!pSpheres) - return false; - if (pSpheres->GetGoState() != GO_STATE_ACTIVE) - return false; - } - RemovePrison(); - return true; - } - - Unit* GetEmbraceTarget() - { - if (!uiEmbraceTarget) - return NULL; - - return Unit::GetUnit(*me, uiEmbraceTarget); - } - - void RemovePrison() - { - if (!instance) - return; - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->RemoveAurasDueToSpell(SPELL_BEAM_VISUAL); - me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation()); - uint64 prison_GUID = instance->GetData64(DATA_PRINCE_TALDARAM_PLATFORM); - instance->HandleGameObject(prison_GUID, true); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_taldaramAI(creature); - } -}; - -class mob_taldaram_flamesphere : public CreatureScript -{ -public: - mob_taldaram_flamesphere() : CreatureScript("mob_taldaram_flamesphere") { } - - struct mob_taldaram_flamesphereAI : public ScriptedAI - { - mob_taldaram_flamesphereAI(Creature* c) : ScriptedAI(c) - { - instance = c->GetInstanceScript(); - } - - uint32 uiDespawnTimer; - InstanceScript* instance; - - void Reset() - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); - me->setFaction(16); - me->SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); - DoCast(me, SPELL_FLAME_SPHERE_VISUAL); - DoCast(me, SPELL_FLAME_SPHERE_SPAWN_EFFECT); - DoCast(me, SPELL_FLAME_SPHERE_PERIODIC); - uiDespawnTimer = 10*IN_MILLISECONDS; - } - - void EnterCombat(Unit* /*who*/) {} - void MoveInLineOfSight(Unit* /*who*/) {} - - void JustDied(Unit* /*who*/) - { - DoCast(me, SPELL_FLAME_SPHERE_DEATH_EFFECT); - } - - void UpdateAI(const uint32 diff) - { - if (uiDespawnTimer <= diff) - me->DisappearAndDie(); - else - uiDespawnTimer -= diff; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_taldaram_flamesphereAI(creature); - } -}; - -class prince_taldaram_sphere : public GameObjectScript -{ -public: - prince_taldaram_sphere() : GameObjectScript("prince_taldaram_sphere") { } - - bool OnGossipHello(Player* /*player*/, GameObject* pGO) - { - InstanceScript* instance = pGO->GetInstanceScript(); - - Creature* pPrinceTaldaram = Unit::GetCreature(*pGO, instance ? instance->GetData64(DATA_PRINCE_TALDARAM) : 0); - if (pPrinceTaldaram && pPrinceTaldaram->isAlive()) - { - // maybe these are hacks :( - pGO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - pGO->SetGoState(GO_STATE_ACTIVE); - - switch (pGO->GetEntry()) - { - case GO_SPHERE1: instance->SetData(DATA_SPHERE1_EVENT, IN_PROGRESS); break; - case GO_SPHERE2: instance->SetData(DATA_SPHERE2_EVENT, IN_PROGRESS); break; - } - - CAST_AI(boss_taldaram::boss_taldaramAI, pPrinceTaldaram->AI())->CheckSpheres(); - } - return true; - } -}; - -void AddSC_boss_taldaram() -{ - new boss_taldaram; - new mob_taldaram_flamesphere; - new prince_taldaram_sphere; -} diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/instance_ahnkahet.cpp b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/instance_ahnkahet.cpp deleted file mode 100644 index 5ba11dd5353..00000000000 --- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/instance_ahnkahet.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "ScriptPCH.h" -#include "ahnkahet.h" - -/* Ahn'kahet encounters: -0 - Elder Nadox -1 - Prince Taldaram -2 - Jedoga Shadowseeker -3 - Herald Volazj -4 - Amanitar (Heroic only) -*/ - -#define MAX_ENCOUNTER 5 - -enum Achievements -{ - ACHIEV_VOLUNTEER_WORK = 2056 -}; - -class instance_ahnkahet : public InstanceMapScript -{ -public: - instance_ahnkahet() : InstanceMapScript("instance_ahnkahet", 619) { } - - struct instance_ahnkahet_InstanceScript : public InstanceScript - { - instance_ahnkahet_InstanceScript(Map* map) : InstanceScript(map) {} - - uint64 Elder_Nadox; - uint64 Prince_Taldaram; - uint64 Jedoga_Shadowseeker; - uint64 Herald_Volazj; - uint64 Amanitar; - - uint64 Prince_TaldaramSpheres[2]; - uint64 Prince_TaldaramPlatform; - uint64 Prince_TaldaramGate; - - std::set InitiandGUIDs; - uint64 JedogaSacrifices; - uint64 JedogaTarget; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint32 spheres[2]; - - uint8 InitiandCnt; - uint8 switchtrigger; - - std::string str_data; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - InitiandGUIDs.clear(); - - Elder_Nadox =0; - Prince_Taldaram =0; - Jedoga_Shadowseeker =0; - Herald_Volazj =0; - Amanitar =0; - - spheres[0] = NOT_STARTED; - spheres[1] = NOT_STARTED; - - InitiandCnt = 0; - switchtrigger = 0; - JedogaSacrifices = 0; - JedogaTarget = 0; - } - - bool IsEncounterInProgress() const - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; - - return false; - } - - void OnCreatureCreate(Creature* creature) - { - switch (creature->GetEntry()) - { - case 29309: Elder_Nadox = creature->GetGUID(); break; - case 29308: Prince_Taldaram = creature->GetGUID(); break; - case 29310: Jedoga_Shadowseeker = creature->GetGUID(); break; - case 29311: Herald_Volazj = creature->GetGUID(); break; - case 30258: Amanitar = creature->GetGUID(); break; - case 30114: InitiandGUIDs.insert(creature->GetGUID()); break; - } - } - - void OnGameObjectCreate(GameObject* go) - { - switch (go->GetEntry()) - { - case 193564: Prince_TaldaramPlatform = go->GetGUID(); - if (m_auiEncounter[1] == DONE) HandleGameObject(0, true, go); break; - case 193093: Prince_TaldaramSpheres[0] = go->GetGUID(); - if (spheres[0] == IN_PROGRESS) - { - go->SetGoState(GO_STATE_ACTIVE); - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - } - else go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - break; - case 193094: Prince_TaldaramSpheres[1] = go->GetGUID(); - if (spheres[1] == IN_PROGRESS) - { - go->SetGoState(GO_STATE_ACTIVE); - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - } - else go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - break; - case 192236: Prince_TaldaramGate = go->GetGUID(); // Web gate past Prince Taldaram - if (m_auiEncounter[1] == DONE)HandleGameObject(0, true, go);break; - } - } - - void SetData64(uint32 idx, uint64 guid) - { - switch (idx) - { - case DATA_ADD_JEDOGA_OPFER: JedogaSacrifices = guid; break; - case DATA_PL_JEDOGA_TARGET: JedogaTarget = guid; break; - } - } - - uint64 GetData64(uint32 identifier) - { - switch (identifier) - { - case DATA_ELDER_NADOX: return Elder_Nadox; - case DATA_PRINCE_TALDARAM: return Prince_Taldaram; - case DATA_JEDOGA_SHADOWSEEKER: return Jedoga_Shadowseeker; - case DATA_HERALD_VOLAZJ: return Herald_Volazj; - case DATA_AMANITAR: return Amanitar; - case DATA_SPHERE1: return Prince_TaldaramSpheres[0]; - case DATA_SPHERE2: return Prince_TaldaramSpheres[1]; - case DATA_PRINCE_TALDARAM_PLATFORM: return Prince_TaldaramPlatform; - case DATA_ADD_JEDOGA_INITIAND: - { - std::vector vInitiands; - vInitiands.clear(); - for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) - { - Creature* cr = instance->GetCreature(*itr); - if (cr && cr->isAlive()) - vInitiands.push_back(*itr); - } - if (vInitiands.empty()) - return 0; - uint8 j = urand(0, vInitiands.size() -1); - return vInitiands[j]; - } - case DATA_ADD_JEDOGA_OPFER: return JedogaSacrifices; - case DATA_PL_JEDOGA_TARGET: return JedogaTarget; - } - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch (type) - { - case DATA_ELDER_NADOX_EVENT: m_auiEncounter[0] = data; break; - case DATA_PRINCE_TALDARAM_EVENT: - if (data == DONE) - HandleGameObject(Prince_TaldaramGate, true); - m_auiEncounter[1] = data; - break; - case DATA_JEDOGA_SHADOWSEEKER_EVENT: - m_auiEncounter[2] = data; - if (data == DONE) - { - for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) - { - Creature* cr = instance->GetCreature(*itr); - if (cr && cr->isAlive()) - { - cr->SetVisible(false); - cr->setDeathState(JUST_DIED); - cr->RemoveCorpse(); - } - } - } - break; - case DATA_HERALD_VOLAZJ_EVENT: m_auiEncounter[3] = data; break; - case DATA_AMANITAR_EVENT: m_auiEncounter[4] = data; break; - case DATA_SPHERE1_EVENT: spheres[0] = data; break; - case DATA_SPHERE2_EVENT: spheres[1] = data; break; - case DATA_JEDOGA_TRIGGER_SWITCH: switchtrigger = data; break; - case DATA_JEDOGA_RESET_INITIANDS: - for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) - { - Creature* cr = instance->GetCreature(*itr); - if (cr) - { - cr->Respawn(); - if (!cr->IsInEvadeMode()) cr->AI()->EnterEvadeMode(); - } - } - break; - } - if (data == DONE) - SaveToDB(); - } - - uint32 GetData(uint32 type) - { - switch (type) - { - case DATA_ELDER_NADOX_EVENT: return m_auiEncounter[0]; - case DATA_PRINCE_TALDARAM_EVENT: return m_auiEncounter[1]; - case DATA_JEDOGA_SHADOWSEEKER_EVENT: return m_auiEncounter[2]; - case DATA_HERALD_VOLAZJ: return m_auiEncounter[3]; - case DATA_AMANITAR_EVENT: return m_auiEncounter[4]; - case DATA_SPHERE1_EVENT: return spheres[0]; - case DATA_SPHERE2_EVENT: return spheres[1]; - case DATA_ALL_INITIAND_DEAD: - for (std::set::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) - { - Creature* cr = instance->GetCreature(*itr); - if (!cr || (cr && cr->isAlive())) return 0; - } - return 1; - case DATA_JEDOGA_TRIGGER_SWITCH: return switchtrigger; - } - return 0; - } - - std::string GetSaveData() - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << "A K " << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' - << m_auiEncounter[2] << ' ' << m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' ' - << spheres[0] << ' ' << spheres[1]; - - str_data = saveStream.str(); - - OUT_SAVE_INST_DATA_COMPLETE; - return str_data; - } - - void Load(const char* in) - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - - char dataHead1, dataHead2; - uint16 data0, data1, data2, data3, data4, data5, data6; - - std::istringstream loadStream(in); - loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4 >> data5 >> data6; - - if (dataHead1 == 'A' && dataHead2 == 'K') - { - m_auiEncounter[0] = data0; - m_auiEncounter[1] = data1; - m_auiEncounter[2] = data2; - m_auiEncounter[3] = data3; - m_auiEncounter[4] = data4; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - - spheres[0] = data5; - spheres[1] = data6; - - } else OUT_LOAD_INST_DATA_FAIL; - - OUT_LOAD_INST_DATA_COMPLETE; - } - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const - { - return new instance_ahnkahet_InstanceScript(map); - } -}; - -void AddSC_instance_ahnkahet() -{ - new instance_ahnkahet; -} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon.cpp new file mode 100644 index 00000000000..3888cc43bc9 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2008-2011 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 "ulduar.h" + +#define GAMEOBJECT_GIVE_OF_THE_OBSERVER 194821 + +enum Spells +{ + SPELL_ASCEND = 64487, + SPELL_BERSERK = 47008, + SPELL_BIG_BANG = 64443, + H_SPELL_BIG_BANG = 64584, + SPELL_COSMIC_SMASH = 62301, + H_SPELL_COSMIC_SMASH = 64598, + SPELL_PHASE_PUNCH = 64412, + SPELL_QUANTUM_STRIKE = 64395, + H_SPELL_QUANTUM_STRIKE = 64592, + SPELL_BLACK_HOLE_EXPLOSION = 64122, + SPELL_ARCANE_BARAGE = 64599, + H_SPELL_ARCANE_BARAGE = 64607 +}; + +enum Creatures +{ + CREATURE_COLLAPSING_STAR = 32955, + CREATURE_BLACK_HOLE = 32953, + CREATURE_LIVING_CONSTELLATION = 33052, + CREATURE_DARK_MATTER = 33089 +}; + +enum Yells +{ + SAY_AGGRO = -1603000, + SAY_SLAY_1 = -1603001, + SAY_SLAY_2 = -1603002, + SAY_ENGADED_FOR_FIRTS_TIME = -1603003, + SAY_PHASE_2 = -1603004, + SAY_SUMMON_COLLAPSING_STAR = -1603005, + SAY_DEATH_1 = -1603006, + SAY_DEATH_2 = -1603007, + SAY_DEATH_3 = -1603008, + SAY_DEATH_4 = -1603009, + SAY_DEATH_5 = -1603010, + SAY_BERSERK = -1603011, + SAY_BIG_BANG_1 = -1603012, + SAY_BIG_BANG_2 = -1603013, + SAY_TIMER_1 = -1603014, + SAY_TIMER_2 = -1603015, + SAY_TIMER_3 = -1603016, + SAY_SUMMON_1 = -1603017, + SAY_SUMMON_2 = -1603018, + SAY_SUMMON_3 = -1603019, +}; + +class boss_algalon : public CreatureScript +{ +public: + boss_algalon() : CreatureScript("boss_algalon") { } + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } + + struct boss_algalonAI : public ScriptedAI + { + boss_algalonAI(Creature* c) : ScriptedAI(c) + { + instance = c->GetInstanceScript(); + Summon = false; // not in reset. intro speech done only once. + } + + InstanceScript* instance; + + std::list m_lCollapsingStarGUIDList; + + uint32 Phase; + uint32 Ascend_Timer; + uint32 Berserk_Timer; + uint32 BigBang_Timer; + uint32 CosmicSmash_Timer; + uint32 PhasePunch_Timer; + uint32 QuantumStrike_Timer; + uint32 CollapsingStar_Timer; + uint32 uiPhase_timer; + uint32 uiStep; + + uint64 BlackHoleGUID; + + bool Enrage; + bool Summon; + + void EnterCombat(Unit* who) + { + if (Summon) + { + DoScriptText(SAY_AGGRO, me); + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + DoZoneInCombat(who->ToCreature()); + } + else + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + uiStep = 1; + } + + if (instance) + instance->SetData(BOSS_ALGALON, IN_PROGRESS); + } + + void KilledUnit(Unit* /*victim*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void Reset() + { + Phase = 1; + + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (instance) + instance->SetData(BOSS_ALGALON, NOT_STARTED); + + BlackHoleGUID = 0; + + uiPhase_timer = 0; + Ascend_Timer = 480000; //8 minutes + QuantumStrike_Timer = 4000 + rand()%10000; + Berserk_Timer = 360000; //6 minutes + CollapsingStar_Timer = urand(15000, 20000); //Spawns between 15 to 20 seconds + BigBang_Timer = 90000; + PhasePunch_Timer = 8000; + CosmicSmash_Timer = urand(30000, 60000); + Enrage = false; + } + + void JumpToNextStep(uint32 uiTimer) + { + uiPhase_timer = uiTimer; + ++uiStep; + } + + void DespawnCollapsingStar() + { + if (m_lCollapsingStarGUIDList.empty()) + return; + + for (std::list::const_iterator itr = m_lCollapsingStarGUIDList.begin(); itr != m_lCollapsingStarGUIDList.end(); ++itr) + { + if (Creature* temp = Unit::GetCreature(*me, *itr)) + { + if (temp->isAlive()) + temp->DespawnOrUnsummon(); + } + } + m_lCollapsingStarGUIDList.clear(); + } + + void JustSummoned(Creature* summoned) + { + if (summoned->GetEntry() == CREATURE_COLLAPSING_STAR) + { + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); + if (me->getVictim()) + summoned->AI()->AttackStart(target ? target : me->getVictim()); + m_lCollapsingStarGUIDList.push_back(summoned->GetGUID()); + } + } + + void SummonCollapsingStar(Unit* target) + { + DoScriptText(SAY_SUMMON_COLLAPSING_STAR, me); + me->SummonCreature(CREATURE_COLLAPSING_STAR, target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 100000); + me->SummonCreature(CREATURE_BLACK_HOLE, target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 27000); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (Phase == 1 && HealthBelowPct(20)) + { + Phase = 2; + DoScriptText(SAY_PHASE_2, me); + } + + if (HealthBelowPct(2)) + { + me->SummonGameObject(GAMEOBJECT_GIVE_OF_THE_OBSERVER, 1634.258667f, -295.101166f, 417.321381f, 0, 0, 0, 0, 0, 0); + + // All of them. or random? + DoScriptText(SAY_DEATH_1, me); + DoScriptText(SAY_DEATH_2, me); + DoScriptText(SAY_DEATH_3, me); + DoScriptText(SAY_DEATH_4, me); + DoScriptText(SAY_DEATH_5, me); + + me->DisappearAndDie(); + + if (instance) + instance->SetData(BOSS_ALGALON, DONE); + + return; + } + + if (Phase == 1) + { + if (!Summon) + { + if (uiPhase_timer <= diff) + { + switch (uiStep) + { + case 1: + DoScriptText(SAY_SUMMON_1, me); + JumpToNextStep(3000); + break; + case 2: + DoScriptText(SAY_SUMMON_2, me); + JumpToNextStep(3000); + break; + case 3: + DoScriptText(SAY_SUMMON_3, me); + JumpToNextStep(3000); + break; + case 4: + DoScriptText(SAY_ENGADED_FOR_FIRTS_TIME, me); + JumpToNextStep(3000); + break; + case 5: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + Summon = true; + break; + } + } else uiPhase_timer -= diff; + + return; + } + + if (QuantumStrike_Timer <= diff) + { + DoCast(me->getVictim(), RAID_MODE(SPELL_QUANTUM_STRIKE, H_SPELL_QUANTUM_STRIKE), true); + + QuantumStrike_Timer = urand(4000, 14000); + } else QuantumStrike_Timer -= diff; + + if (BigBang_Timer <= diff) + { + DoScriptText(RAND(SAY_BIG_BANG_1, SAY_BIG_BANG_2), me); + DoCast(me->getVictim(), RAID_MODE(SPELL_BIG_BANG, H_SPELL_BIG_BANG), true); + + BigBang_Timer = 90000; + } else BigBang_Timer -= diff; + + if (Ascend_Timer <= diff) + { + DoCast(me->getVictim(), SPELL_ASCEND, true); + + Ascend_Timer = 480000; + } else Ascend_Timer -= diff; + + if (PhasePunch_Timer <= diff) + { + DoCast(me->getVictim(), SPELL_PHASE_PUNCH, true); + + PhasePunch_Timer = 8000; + } else PhasePunch_Timer -= diff; + + if (CosmicSmash_Timer <= diff) + { + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), RAID_MODE(SPELL_COSMIC_SMASH, H_SPELL_COSMIC_SMASH), true); + + CosmicSmash_Timer = urand(30000, 60000); + } else CosmicSmash_Timer -= diff; + + if (Berserk_Timer <= diff) + { + DoScriptText(SAY_BERSERK, me); + DoCast(me->getVictim(), SPELL_BERSERK, true); + + Berserk_Timer = 360000; + } else Berserk_Timer -= diff; + + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(diff); + } + + if (Phase == 2) + { + if (Enrage) + { + if (Ascend_Timer <= diff) + { + DoCast(me, SPELL_ASCEND); + DoScriptText(SAY_BERSERK, me); + Ascend_Timer = urand(360000, 365000); + Enrage = false; + } else Ascend_Timer -= diff; + } + } + + DoMeleeAttackIfReady(); + } + }; + +}; + +//Collapsing Star +class mob_collapsing_star : public CreatureScript +{ +public: + mob_collapsing_star() : CreatureScript("mob_collapsing_star") { } + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_collapsing_starAI(creature); + } + + struct mob_collapsing_starAI : public ScriptedAI + { + mob_collapsing_starAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + + uint32 BlackHoleExplosion_Timer; + + void Reset() + { + BlackHoleExplosion_Timer = 0; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (BlackHoleExplosion_Timer <= diff) + { + me->CastSpell(me, SPELL_BLACK_HOLE_EXPLOSION, false); + BlackHoleExplosion_Timer = 0; + } else BlackHoleExplosion_Timer -= diff; + } + }; + +}; + +void AddSC_boss_Algalon() +{ + new boss_algalon(); + new mob_collapsing_star(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp new file mode 100644 index 00000000000..a8a4fad5e4e --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp @@ -0,0 +1,812 @@ +/* + * Copyright (C) 2008-2011 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: Assembly of Iron encounter +SD%Complete: 60% +SDComment: Runes need DB support, chain lightning won't cast, supercharge won't cast (target error?) - it worked before during debugging. +SDCategory: Ulduar - Ulduar +EndScriptData */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "ulduar.h" + +enum AssemblySpells +{ + // General + SPELL_SUPERCHARGE = 61920, + SPELL_BERSERK = 47008, // Hard enrage, don't know the correct ID. + + // Steelbreaker + SPELL_HIGH_VOLTAGE = 61890, + SPELL_FUSION_PUNCH = 61903, + SPELL_STATIC_DISRUPTION = 44008, + SPELL_OVERWHELMING_POWER = 64637, + SPELL_ELECTRICAL_CHARGE = 61902, + + // Runemaster Molgeim + SPELL_SHIELD_OF_RUNES = 62274, + SPELL_SHIELD_OF_RUNES_BUFF = 62277, + SPELL_SUMMON_RUNE_OF_POWER = 63513, + SPELL_RUNE_OF_POWER = 61974, + SPELL_RUNE_OF_DEATH = 62269, + SPELL_RUNE_OF_SUMMONING = 62273, // This is the spell that summons the rune + SPELL_RUNE_OF_SUMMONING_VIS = 62019, // Visual + SPELL_RUNE_OF_SUMMONING_SUMMON = 62020, // Spell that summons + SPELL_LIGHTNING_ELEMENTAL_PASSIVE = 62052, + + // Stormcaller Brundir + SPELL_CHAIN_LIGHTNING = 61879, + SPELL_OVERLOAD = 61869, + SPELL_LIGHTNING_WHIRL = 61915, + SPELL_LIGHTNING_TENDRILS_10M = 61887, + SPELL_LIGHTNING_TENDRILS_25M = 63486, + SPELL_LIGHTNING_TENDRILS_VISUAL = 61883, + SPELL_STORMSHIELD = 64187, +}; + +enum AssemblyEvents +{ + // General + EVENT_BERSERK = 1, + + // Steelbreaker + EVENT_FUSION_PUNCH = 2, + EVENT_STATIC_DISRUPTION = 3, + EVENT_OVERWHELMING_POWER = 4, + + // Molgeim + EVENT_RUNE_OF_POWER = 5, + EVENT_SHIELD_OF_RUNES = 6, + EVENT_RUNE_OF_DEATH = 7, + EVENT_RUNE_OF_SUMMONING = 8, + EVENT_LIGHTNING_BLAST = 9, + + // Brundir + EVENT_CHAIN_LIGHTNING = 10, + EVENT_OVERLOAD = 11, + EVENT_LIGHTNING_WHIRL = 12, + EVENT_LIGHTNING_TENDRILS = 13, + EVENT_FLIGHT = 14, + EVENT_ENDFLIGHT = 15, + EVENT_GROUND = 16, + EVENT_LAND = 17, + EVENT_MOVE_POSITION = 18, +}; + +enum AssemblyActions +{ + ACTION_STEELBREAKER = 0, + ACTION_MOLGEIM = 1, + ACTION_BRUNDIR = 2, + ACTION_ADD_CHARGE = 3, +}; + +enum AssemblyYells +{ + SAY_STEELBREAKER_AGGRO = -1603020, + SAY_STEELBREAKER_SLAY_1 = -1603021, + SAY_STEELBREAKER_SLAY_2 = -1603022, + SAY_STEELBREAKER_POWER = -1603023, + SAY_STEELBREAKER_DEATH_1 = -1603024, + SAY_STEELBREAKER_DEATH_2 = -1603025, + SAY_STEELBREAKER_BERSERK = -1603026, + + SAY_MOLGEIM_AGGRO = -1603030, + SAY_MOLGEIM_SLAY_1 = -1603031, + SAY_MOLGEIM_SLAY_2 = -1603032, + SAY_MOLGEIM_RUNE_DEATH = -1603033, + SAY_MOLGEIM_SUMMON = -1603034, + SAY_MOLGEIM_DEATH_1 = -1603035, + SAY_MOLGEIM_DEATH_2 = -1603036, + SAY_MOLGEIM_BERSERK = -1603037, + + SAY_BRUNDIR_AGGRO = -1603040, + SAY_BRUNDIR_SLAY_1 = -1603041, + SAY_BRUNDIR_SLAY_2 = -1603042, + SAY_BRUNDIR_SPECIAL = -1603043, + SAY_BRUNDIR_FLIGHT = -1603044, + SAY_BRUNDIR_DEATH_1 = -1603045, + SAY_BRUNDIR_DEATH_2 = -1603046, + SAY_BRUNDIR_BERSERK = -1603047, +}; + +enum AssemblyNPCs +{ + NPC_WORLD_TRIGGER = 22515, +}; + +#define EMOTE_OVERLOAD "Stormcaller Brundir begins to Overload!" // Move it to DB +#define FLOOR_Z 427.28f +#define FINAL_FLIGHT_Z 435.0f + +bool IsEncounterComplete(InstanceScript* instance, Creature* me) +{ + if (!instance || !me) + return false; + + for (uint8 i = 0; i < 3; ++i) + { + uint64 guid = instance->GetData64(BOSS_STEELBREAKER + i); + if (!guid) + return false; + + if (Creature* boss = ObjectAccessor::GetCreature(*me, guid)) + { + if (boss->isAlive()) + return false; + } + else + return false; + } + + return true; +} + +void RespawnEncounter(InstanceScript* instance, Creature* me) +{ + for (uint8 i = 0; i < 3; ++i) + { + uint64 guid = instance->GetData64(BOSS_STEELBREAKER + i); + if (!guid) + continue; + + if (Creature* boss = ObjectAccessor::GetCreature(*me, guid)) + { + if (!boss->isAlive()) + { + boss->Respawn(); + boss->GetMotionMaster()->MoveTargetedHome(); + } + } + } +} + +void StartEncounter(InstanceScript* instance, Creature* me, Unit* /*target*/) +{ + if (instance->GetBossState(BOSS_ASSEMBLY_OF_IRON) == IN_PROGRESS) + return; // Prevent recursive calls + + instance->SetBossState(BOSS_ASSEMBLY_OF_IRON, IN_PROGRESS); + + for (uint8 i = 0; i < 3; ++i) + { + uint64 guid = instance->GetData64(BOSS_STEELBREAKER + i); + if (!guid) + continue; + + if (Creature* boss = ObjectAccessor::GetCreature(*me, guid)) + boss->SetInCombatWithZone(); + } +} + +class boss_steelbreaker : public CreatureScript +{ + public: + boss_steelbreaker() : CreatureScript("boss_steelbreaker") { } + + struct boss_steelbreakerAI : public BossAI + { + boss_steelbreakerAI(Creature* creature) : BossAI(creature, BOSS_ASSEMBLY_OF_IRON) + { + instance = me->GetInstanceScript(); + } + + InstanceScript* instance; + uint32 phase; + + void Reset() + { + _Reset(); + phase = 0; + me->RemoveAllAuras(); + RespawnEncounter(instance, me); + } + + void EnterCombat(Unit* who) + { + StartEncounter(instance, me, who); + DoScriptText(SAY_STEELBREAKER_AGGRO, me); + DoZoneInCombat(); + DoCast(me, SPELL_HIGH_VOLTAGE); + events.SetPhase(++phase); + events.ScheduleEvent(EVENT_BERSERK, 900000); + events.ScheduleEvent(EVENT_FUSION_PUNCH, 15000); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_STEELBREAKER: + me->SetHealth(me->GetMaxHealth()); + me->AddAura(SPELL_SUPERCHARGE, me); + events.SetPhase(++phase); + events.RescheduleEvent(EVENT_FUSION_PUNCH, 15000); + if (phase >= 2) + events.RescheduleEvent(EVENT_STATIC_DISRUPTION, 30000); + if (phase >= 3) + events.RescheduleEvent(EVENT_OVERWHELMING_POWER, urand(2000, 5000)); + break; + case ACTION_ADD_CHARGE: + DoCast(me, SPELL_ELECTRICAL_CHARGE, true); + break; + } + } + + void JustDied(Unit* /*who*/) + { + DoScriptText(RAND(SAY_STEELBREAKER_DEATH_1, SAY_STEELBREAKER_DEATH_2), me); + if (IsEncounterComplete(instance, me)) + instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE); + else + me->SetLootRecipient(NULL); + + if (Creature* Brundir = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRUNDIR))) + if (Brundir->isAlive()) + Brundir->AI()->DoAction(ACTION_BRUNDIR); + + if (Creature* Molgeim = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MOLGEIM))) + if (Molgeim->isAlive()) + Molgeim->AI()->DoAction(ACTION_MOLGEIM); + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_STEELBREAKER_SLAY_1, SAY_STEELBREAKER_SLAY_2), me); + + if (phase == 3) + DoCast(me, SPELL_ELECTRICAL_CHARGE); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BERSERK: + DoScriptText(SAY_STEELBREAKER_BERSERK, me); + DoCast(SPELL_BERSERK); + events.CancelEvent(EVENT_BERSERK); + break; + case EVENT_FUSION_PUNCH: + if (me->IsWithinMeleeRange(me->getVictim())) + DoCastVictim(SPELL_FUSION_PUNCH); + events.ScheduleEvent(EVENT_FUSION_PUNCH, urand(13000, 22000)); + break; + case EVENT_STATIC_DISRUPTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_STATIC_DISRUPTION); + events.ScheduleEvent(EVENT_STATIC_DISRUPTION, urand(20000, 40000)); + break; + case EVENT_OVERWHELMING_POWER: + DoScriptText(SAY_STEELBREAKER_POWER, me); + DoCastVictim(SPELL_OVERWHELMING_POWER); + events.ScheduleEvent(EVENT_OVERWHELMING_POWER, RAID_MODE(60000, 35000)); + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class boss_runemaster_molgeim : public CreatureScript +{ + public: + boss_runemaster_molgeim() : CreatureScript("boss_runemaster_molgeim") { } + + struct boss_runemaster_molgeimAI : public BossAI + { + boss_runemaster_molgeimAI(Creature* creature) : BossAI(creature, BOSS_ASSEMBLY_OF_IRON) + { + instance = me->GetInstanceScript(); + } + + InstanceScript* instance; + uint32 phase; + + void Reset() + { + _Reset(); + phase = 0; + me->RemoveAllAuras(); + RespawnEncounter(instance, me); + } + + void EnterCombat(Unit* who) + { + StartEncounter(instance, me, who); + DoScriptText(SAY_MOLGEIM_AGGRO, me); + DoZoneInCombat(); + events.SetPhase(++phase); + events.ScheduleEvent(EVENT_BERSERK, 900000); + events.ScheduleEvent(EVENT_SHIELD_OF_RUNES, 30000); + events.ScheduleEvent(EVENT_RUNE_OF_POWER, 20000); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_MOLGEIM: + me->SetHealth(me->GetMaxHealth()); + me->AddAura(SPELL_SUPERCHARGE, me); + events.SetPhase(++phase); + events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 27000); + events.RescheduleEvent(EVENT_RUNE_OF_POWER, 25000); + if (phase >= 2) + events.RescheduleEvent(EVENT_RUNE_OF_DEATH, 30000); + if (phase >= 3) + events.RescheduleEvent(EVENT_RUNE_OF_SUMMONING, urand(20000, 30000)); + break; + } + } + + void JustDied(Unit* /*who*/) + { + DoScriptText(RAND(SAY_MOLGEIM_DEATH_1, SAY_MOLGEIM_DEATH_2), me); + if (IsEncounterComplete(instance, me)) + instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE); + else + me->SetLootRecipient(NULL); + + if (Creature* Brundir = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRUNDIR))) + if (Brundir->isAlive()) + Brundir->AI()->DoAction(ACTION_BRUNDIR); + + if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) + if (Steelbreaker->isAlive()) + Steelbreaker->AI()->DoAction(ACTION_STEELBREAKER); + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_MOLGEIM_SLAY_1, SAY_MOLGEIM_SLAY_2), me); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BERSERK: + DoScriptText(SAY_MOLGEIM_BERSERK, me); + DoCast(SPELL_BERSERK); + events.CancelEvent(EVENT_BERSERK); + break; + case EVENT_RUNE_OF_POWER: + { + Unit* target = NULL; + switch (urand(0, 2)) + { + case 0: + target = me; + break; + case 1: + if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) + if (Steelbreaker->isAlive()) + target = Steelbreaker; + break; + case 2: + if (Creature* Brundir = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) + if (Brundir->isAlive()) + target = Brundir; + break; + } + DoCast(target, SPELL_SUMMON_RUNE_OF_POWER); + events.ScheduleEvent(EVENT_RUNE_OF_POWER, 60000); + break; + } + case EVENT_SHIELD_OF_RUNES: + DoCast(me, SPELL_SHIELD_OF_RUNES); + events.ScheduleEvent(EVENT_SHIELD_OF_RUNES, urand(27000, 34000)); + break; + case EVENT_RUNE_OF_DEATH: + DoScriptText(SAY_MOLGEIM_RUNE_DEATH, me); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_RUNE_OF_DEATH); + events.ScheduleEvent(EVENT_RUNE_OF_DEATH, urand(30000, 40000)); + break; + case EVENT_RUNE_OF_SUMMONING: + DoScriptText(SAY_MOLGEIM_SUMMON, me); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_RUNE_OF_SUMMONING); + events.ScheduleEvent(EVENT_RUNE_OF_SUMMONING, urand(30000, 45000)); + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class mob_rune_of_power : public CreatureScript +{ + public: + mob_rune_of_power() : CreatureScript("mob_rune_of_power") { } + + struct mob_rune_of_powerAI : public ScriptedAI + { + mob_rune_of_powerAI(Creature* creature) : ScriptedAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->setFaction(16); // Same faction as bosses + DoCast(SPELL_RUNE_OF_POWER); + + me->DespawnOrUnsummon(60000); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_rune_of_powerAI(creature); + } +}; + +class mob_lightning_elemental : public CreatureScript +{ + public: + mob_lightning_elemental() : CreatureScript("mob_lightning_elemental") { } + + struct mob_lightning_elementalAI : public ScriptedAI + { + mob_lightning_elementalAI(Creature* creature) : ScriptedAI(creature) + { + me->SetInCombatWithZone(); + me->AddAura(SPELL_LIGHTNING_ELEMENTAL_PASSIVE, me); + } + + // Nothing to do here, just let the creature chase players and procflags == 2 on the applied aura will trigger explosion + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_lightning_elementalAI(creature); + } +}; + +class mob_rune_of_summoning : public CreatureScript +{ + public: + mob_rune_of_summoning() : CreatureScript("mob_rune_of_summoning") { } + + struct mob_rune_of_summoningAI : public ScriptedAI + { + mob_rune_of_summoningAI(Creature* creature) : ScriptedAI(creature) + { + me->AddAura(SPELL_RUNE_OF_SUMMONING_VIS, me); + summonCount = 0; + summonTimer = 2000; + } + + uint32 summonCount; + uint32 summonTimer; + + void UpdateAI(uint32 const diff) + { + if (summonTimer <= diff) + SummonLightningElemental(); + else + summonTimer -= diff; + } + + void SummonLightningElemental() + { + me->CastSpell(me, SPELL_RUNE_OF_SUMMONING_SUMMON, false); + if (++summonCount == 10) // TODO: Find out if this amount is right + me->DespawnOrUnsummon(); + else + summonTimer = 2000; // TODO: Find out of timer is right + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_rune_of_summoningAI(creature); + } +}; + +class boss_stormcaller_brundir : public CreatureScript +{ + public: + boss_stormcaller_brundir() : CreatureScript("boss_stormcaller_brundir") { } + + struct boss_stormcaller_brundirAI : public BossAI + { + boss_stormcaller_brundirAI(Creature* creature) : BossAI(creature, BOSS_ASSEMBLY_OF_IRON) + { + instance = me->GetInstanceScript(); + } + + InstanceScript* instance; + uint32 phase; + + void Reset() + { + _Reset(); + phase = 0; + me->RemoveAllAuras(); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, false); // Should be interruptable unless overridden by spell (Overload) + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, false); // Reset immumity, Brundir should be stunnable by default + RespawnEncounter(instance, me); + } + + void EnterCombat(Unit* who) + { + StartEncounter(instance, me, who); + DoScriptText(SAY_BRUNDIR_AGGRO, me); + DoZoneInCombat(); + events.SetPhase(++phase); + events.ScheduleEvent(EVENT_MOVE_POSITION, 1000); + events.ScheduleEvent(EVENT_BERSERK, 900000); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 4000); + events.ScheduleEvent(EVENT_OVERLOAD, urand(60000, 120000)); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_BRUNDIR: + me->SetHealth(me->GetMaxHealth()); + me->AddAura(SPELL_SUPERCHARGE, me); + events.SetPhase(++phase); + events.RescheduleEvent(EVENT_CHAIN_LIGHTNING, urand(7000, 12000)); + events.RescheduleEvent(EVENT_OVERLOAD, urand(40000, 50000)); + if (phase >= 2) + events.RescheduleEvent(EVENT_LIGHTNING_WHIRL, urand(15000, 250000)); + if (phase >= 3) + { + DoCast(me, SPELL_STORMSHIELD); + events.RescheduleEvent(EVENT_LIGHTNING_TENDRILS, urand(50000, 60000)); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); // Apply immumity to stuns + } + break; + + } + } + + void JustDied(Unit* /*who*/) + { + DoScriptText(RAND(SAY_BRUNDIR_DEATH_1, SAY_BRUNDIR_DEATH_2), me); + if (IsEncounterComplete(instance, me)) + instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE); + else + me->SetLootRecipient(NULL); + + if (Creature* Molgeim = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MOLGEIM))) + if (Molgeim->isAlive()) + Molgeim->AI()->DoAction(ACTION_MOLGEIM); + + if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) + if (Steelbreaker->isAlive()) + Steelbreaker->AI()->DoAction(ACTION_STEELBREAKER); + + // Prevent to have Brundir somewhere in the air when he die in Air phase + if (me->GetPositionZ() > FLOOR_Z) + me->GetMotionMaster()->MoveFall(FLOOR_Z); + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_BRUNDIR_SLAY_1, SAY_BRUNDIR_SLAY_2), me); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BERSERK: + DoScriptText(SAY_BRUNDIR_BERSERK, me); + DoCast(SPELL_BERSERK); + events.CancelEvent(EVENT_BERSERK); + break; + case EVENT_CHAIN_LIGHTNING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_CHAIN_LIGHTNING); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, urand(7000, 10000)); + break; + case EVENT_OVERLOAD: + me->MonsterTextEmote(EMOTE_OVERLOAD, 0, true); + DoScriptText(SAY_BRUNDIR_SPECIAL, me); + DoCast(SPELL_OVERLOAD); + events.ScheduleEvent(EVENT_OVERLOAD, urand(60000, 120000)); + break; + case EVENT_LIGHTNING_WHIRL: + DoCast(SPELL_LIGHTNING_WHIRL); + events.ScheduleEvent(EVENT_LIGHTNING_WHIRL, urand(15000, 20000)); + break; + case EVENT_LIGHTNING_TENDRILS: + DoScriptText(SAY_BRUNDIR_FLIGHT, me); + DoCast(RAID_MODE(SPELL_LIGHTNING_TENDRILS_10M, SPELL_LIGHTNING_TENDRILS_25M)); + DoCast(SPELL_LIGHTNING_TENDRILS_VISUAL); + me->AttackStop(); + //me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->GetMotionMaster()->Initialize(); + me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), FINAL_FLIGHT_Z); + events.DelayEvents(35000); + events.ScheduleEvent(EVENT_FLIGHT, 2500); + events.ScheduleEvent(EVENT_ENDFLIGHT, 32500); + events.ScheduleEvent(EVENT_LIGHTNING_TENDRILS, 90000); + break; + case EVENT_FLIGHT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + me->GetMotionMaster()->MovePoint(0, target->GetPositionX(), target->GetPositionY(), FINAL_FLIGHT_Z); + events.ScheduleEvent(EVENT_FLIGHT, 6000); + break; + case EVENT_ENDFLIGHT: + me->GetMotionMaster()->Initialize(); + me->GetMotionMaster()->MovePoint(0, 1586.920166f, 119.848984f, FINAL_FLIGHT_Z); + events.CancelEvent(EVENT_FLIGHT); + events.CancelEvent(EVENT_ENDFLIGHT); + events.ScheduleEvent(EVENT_LAND, 4000); + break; + case EVENT_LAND: + me->GetMotionMaster()->Initialize(); + me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), FLOOR_Z); + events.CancelEvent(EVENT_LAND); + events.ScheduleEvent(EVENT_GROUND, 2500); + break; + case EVENT_GROUND: + //me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->RemoveAurasDueToSpell(RAID_MODE(SPELL_LIGHTNING_TENDRILS_10M, SPELL_LIGHTNING_TENDRILS_25M)); + me->RemoveAurasDueToSpell(SPELL_LIGHTNING_TENDRILS_VISUAL); + DoStartMovement(me->getVictim()); + events.CancelEvent(EVENT_GROUND); + me->getThreatManager().resetAllAggro(); + break; + case EVENT_MOVE_POSITION: + if (me->IsWithinMeleeRange(me->getVictim())) + { + float x = float(irand(-25, 25)); + float y = float(irand(-25, 25)); + me->GetMotionMaster()->MovePoint(0, me->GetPositionX() + x, me->GetPositionY() + y, FLOOR_Z); + // Prevention to go outside the room or into the walls + if (Creature* trigger = me->FindNearestCreature(NPC_WORLD_TRIGGER, 100.0f, true)) + if (me->GetDistance(trigger) >= 50.0f) + me->GetMotionMaster()->MovePoint(0, trigger->GetPositionX(), trigger->GetPositionY(), FLOOR_Z); + } + events.ScheduleEvent(EVENT_MOVE_POSITION, urand(7500, 10000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class spell_shield_of_runes : public SpellScriptLoader +{ + public: + spell_shield_of_runes() : SpellScriptLoader("spell_shield_of_runes") { } + + class spell_shield_of_runes_AuraScript : public AuraScript + { + PrepareAuraScript(spell_shield_of_runes_AuraScript); + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) + caster->CastSpell(caster, SPELL_SHIELD_OF_RUNES_BUFF, false); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_shield_of_runes_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_shield_of_runes_AuraScript(); + } +}; + +class spell_assembly_meltdown : public SpellScriptLoader +{ + public: + spell_assembly_meltdown() : SpellScriptLoader("spell_assembly_meltdown") { } + + class spell_assembly_meltdown_SpellScript : public SpellScript + { + PrepareSpellScript(spell_assembly_meltdown_SpellScript); + + void HandleInstaKill(SpellEffIndex /*effIndex*/) + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(BOSS_STEELBREAKER))) + Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_assembly_meltdown_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_assembly_meltdown_SpellScript(); + } +}; + +void AddSC_boss_assembly_of_iron() +{ + new boss_steelbreaker(); + new boss_runemaster_molgeim(); + new boss_stormcaller_brundir(); + new mob_lightning_elemental(); + new mob_rune_of_summoning(); + new mob_rune_of_power(); + new spell_shield_of_runes(); + new spell_assembly_meltdown(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp new file mode 100644 index 00000000000..bcc417c50cd --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -0,0 +1,588 @@ +/* + * Copyright (C) 2008-2011 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 "SpellScript.h" +#include "ulduar.h" + +enum AuriayaSpells +{ + // Auriaya + SPELL_SENTINEL_BLAST = 64389, + SPELL_SONIC_SCREECH = 64422, + SPELL_TERRIFYING_SCREECH = 64386, + SPELL_SUMMON_SWARMING_GUARDIAN = 64396, + SPELL_ACTIVATE_DEFENDER = 64449, + SPELL_DEFENDER_TRIGGER = 64448, + SPELL_SUMMON_DEFENDER = 64447, + SPELL_BERSERK = 47008, + + // Feral Defender + SPELL_FERAL_RUSH = 64496, + SPELL_FERAL_POUNCE = 64478, + SPELL_SEEPING_ESSENCE = 64458, + SPELL_SUMMON_ESSENCE = 64457, + SPELL_FERAL_ESSENCE = 64455, + + // Sanctum Sentry + SPELL_SAVAGE_POUNCE = 64666, + SPELL_RIP_FLESH = 64375, + SPELL_STRENGHT_PACK = 64369, +}; + +enum AuriayaNPCs +{ + NPC_SANCTUM_SENTRY = 34014, + NPC_FERAL_DEFENDER = 34035, + NPC_FERAL_DEFENDER_TRIGGER = 34096, + NPC_SEEPING_TRIGGER = 34098, +}; + +enum AuriayaEvents +{ + // Auriaya + EVENT_SCREECH = 1, + EVENT_BLAST = 2, + EVENT_TERRIFYING = 3, + EVENT_SUMMON = 4, + EVENT_DEFENDER = 5, + EVENT_ACTIVATE_DEFENDER = 6, + EVENT_RESPAWN_DEFENDER = 7, + EVENT_BERSERK = 8, + + // Sanctum Sentry + EVENT_RIP = 9, + EVENT_POUNCE = 10, + + // Feral Defender + EVENT_FERAL_POUNCE = 11, + EVENT_RUSH = 12, +}; + +enum AuriayaYells +{ + // Yells + SAY_AGGRO = -1603050, + SAY_SLAY_1 = -1603051, + SAY_SLAY_2 = -1603052, + SAY_DEATH = -1603053, + SAY_BERSERK = -1603054, + + // Emotes + EMOTE_FEAR = -1603055, + EMOTE_DEFENDER = -1603056, +}; + +enum AuriayaActions +{ + ACTION_CRAZY_CAT_LADY = 0, + ACTION_RESPAWN_DEFENDER +}; + +#define SENTRY_NUMBER RAID_MODE(2, 4) +#define DATA_NINE_LIVES 30763077 +#define DATA_CRAZY_CAT_LADY 30063007 + +class boss_auriaya : public CreatureScript +{ + public: + boss_auriaya() : CreatureScript("boss_auriaya") { } + + struct boss_auriayaAI : public BossAI + { + boss_auriayaAI(Creature* creature) : BossAI(creature, BOSS_AURIAYA) + { + } + + void Reset() + { + _Reset(); + DefenderGUID = 0; + defenderLives = 8; + crazyCatLady = true; + nineLives = false; + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + DoScriptText(SAY_AGGRO, me); + + events.ScheduleEvent(EVENT_SCREECH, urand(45000, 65000)); + events.ScheduleEvent(EVENT_BLAST, urand(20000, 25000)); + events.ScheduleEvent(EVENT_TERRIFYING, urand(20000, 30000)); + events.ScheduleEvent(EVENT_DEFENDER, urand(40000, 55000)); + events.ScheduleEvent(EVENT_SUMMON, urand(45000, 55000)); + events.ScheduleEvent(EVENT_BERSERK, 600000); + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void JustSummoned(Creature* summoned) + { + summons.Summon(summoned); + + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + summoned->AI()->AttackStart(target); + summoned->AddThreat(target, 250.0f); + DoZoneInCombat(summoned); + } + + if (summoned->GetEntry() == NPC_FERAL_DEFENDER) + { + if (!summoned->isInCombat() && me->getVictim()) + summoned->AI()->AttackStart(me->getVictim()); + summoned->SetAuraStack(SPELL_FERAL_ESSENCE, summoned, 9); + DefenderGUID = summoned->GetGUID(); + DoZoneInCombat(summoned); + } + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_CRAZY_CAT_LADY: + SetData(DATA_CRAZY_CAT_LADY, 0); + break; + case ACTION_RESPAWN_DEFENDER: + --defenderLives; + if (!defenderLives) + { + SetData(DATA_NINE_LIVES, 1); + break; + } + events.ScheduleEvent(EVENT_RESPAWN_DEFENDER, 30000); + break; + default: + break; + } + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_NINE_LIVES: + return nineLives ? 1 : 0; + case DATA_CRAZY_CAT_LADY: + return crazyCatLady ? 1 : 0; + } + + return 0; + } + + void SetData(uint32 id, uint32 data) + { + switch (id) + { + case DATA_NINE_LIVES: + nineLives = data ? true : false; + break; + case DATA_CRAZY_CAT_LADY: + crazyCatLady = data ? true : false; + break; + } + } + + void JustDied(Unit* /*who*/) + { + DoScriptText(SAY_DEATH, me); + _JustDied(); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SCREECH: + DoCast(SPELL_SONIC_SCREECH); + events.ScheduleEvent(EVENT_SCREECH, urand(40000, 60000)); + break; + case EVENT_TERRIFYING: + DoScriptText(EMOTE_FEAR, me); + DoCast(SPELL_TERRIFYING_SCREECH); + events.ScheduleEvent(EVENT_TERRIFYING, urand(20000, 30000)); + break; + case EVENT_BLAST: + DoCastAOE(SPELL_SENTINEL_BLAST); + events.ScheduleEvent(EVENT_BLAST, urand(25000, 35000)); + break; + case EVENT_DEFENDER: + DoScriptText(EMOTE_DEFENDER, me); + DoCast(SPELL_DEFENDER_TRIGGER); + if (Creature* trigger = me->FindNearestCreature(NPC_FERAL_DEFENDER_TRIGGER, 15.0f, true)) + DoCast(trigger, SPELL_ACTIVATE_DEFENDER, true); + break; + case EVENT_RESPAWN_DEFENDER: + if (Creature* Defender = ObjectAccessor::GetCreature(*me, DefenderGUID)) + { + Defender->Respawn(); + if (defenderLives) + Defender->SetAuraStack(SPELL_FERAL_ESSENCE, Defender, defenderLives); + Defender->SetInCombatWithZone(); + if (!Defender->isInCombat()) + Defender->AI()->AttackStart(me->getVictim()); + events.CancelEvent(EVENT_RESPAWN_DEFENDER); + } + break; + case EVENT_SUMMON: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_SUMMON_SWARMING_GUARDIAN); + events.ScheduleEvent(EVENT_SUMMON, urand(30000, 45000)); + break; + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK, true); + DoScriptText(SAY_BERSERK, me); + events.CancelEvent(EVENT_BERSERK); + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + uint64 DefenderGUID; + uint8 defenderLives; + bool crazyCatLady; + bool nineLives; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class npc_auriaya_seeping_trigger : public CreatureScript +{ + public: + npc_auriaya_seeping_trigger() : CreatureScript("npc_auriaya_seeping_trigger") { } + + struct npc_auriaya_seeping_triggerAI : public ScriptedAI + { + npc_auriaya_seeping_triggerAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void Reset() + { + me->ForcedDespawn(600000); + DoCast(me, SPELL_SEEPING_ESSENCE); + } + + void UpdateAI(uint32 const /*diff*/) + { + if (instance->GetBossState(BOSS_AURIAYA) != IN_PROGRESS) + me->ForcedDespawn(); + } + + private: + InstanceScript* instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_auriaya_seeping_triggerAI(creature); + } +}; + +class npc_sanctum_sentry : public CreatureScript +{ + public: + npc_sanctum_sentry() : CreatureScript("npc_sanctum_sentry") { } + + struct npc_sanctum_sentryAI : public ScriptedAI + { + npc_sanctum_sentryAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void Reset() + { + events.ScheduleEvent(EVENT_RIP, urand(4000, 8000)); + events.ScheduleEvent(EVENT_POUNCE, urand(12000, 15000)); + } + + void EnterCombat(Unit* /*who*/) + { + DoCast(me, SPELL_STRENGHT_PACK, true); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RIP: + DoCastVictim(SPELL_RIP_FLESH); + events.ScheduleEvent(EVENT_RIP, urand(12000, 15000)); + break; + case EVENT_POUNCE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + me->AddThreat(target, 100.0f); + me->AI()->AttackStart(target); + DoCast(target, SPELL_SAVAGE_POUNCE); + } + events.ScheduleEvent(EVENT_POUNCE, urand(12000, 17000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Auriaya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_AURIAYA))) + Auriaya->AI()->DoAction(ACTION_CRAZY_CAT_LADY); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_sanctum_sentryAI(creature); + } +}; + +class npc_feral_defender : public CreatureScript +{ + public: + npc_feral_defender() : CreatureScript("npc_feral_defender") { } + + struct npc_feral_defenderAI : public ScriptedAI + { + npc_feral_defenderAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void Reset() + { + events.ScheduleEvent(EVENT_FERAL_POUNCE, 5000); + events.ScheduleEvent(EVENT_RUSH, 10000); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FERAL_POUNCE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + me->AddThreat(target, 100.0f); + me->AI()->AttackStart(target); + DoCast(target, SPELL_FERAL_POUNCE); + } + events.ScheduleEvent(EVENT_FERAL_POUNCE, urand(10000, 12000)); + break; + case EVENT_RUSH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + me->AddThreat(target, 100.0f); + me->AI()->AttackStart(target); + DoCast(target, SPELL_FERAL_RUSH); + } + events.ScheduleEvent(EVENT_RUSH, urand(10000, 12000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*who*/) + { + DoCast(me, SPELL_SUMMON_ESSENCE); + if (Creature* Auriaya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_AURIAYA))) + Auriaya->AI()->DoAction(ACTION_RESPAWN_DEFENDER); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_feral_defenderAI(creature); + } +}; + +class SanctumSentryCheck +{ + public: + bool operator() (Unit* unit) + { + if (unit->GetEntry() == NPC_SANCTUM_SENTRY) + return false; + + return true; + } +}; + +class spell_auriaya_strenght_of_the_pack : public SpellScriptLoader +{ + public: + spell_auriaya_strenght_of_the_pack() : SpellScriptLoader("spell_auriaya_strenght_of_the_pack") { } + + class spell_auriaya_strenght_of_the_pack_SpellScript : public SpellScript + { + PrepareSpellScript(spell_auriaya_strenght_of_the_pack_SpellScript); + + void FilterTargets(std::list& unitList) + { + unitList.remove_if (SanctumSentryCheck()); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_auriaya_strenght_of_the_pack_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_auriaya_strenght_of_the_pack_SpellScript(); + } +}; + +class spell_auriaya_sentinel_blast : public SpellScriptLoader +{ + public: + spell_auriaya_sentinel_blast() : SpellScriptLoader("spell_auriaya_sentinel_blast") { } + + class spell_auriaya_sentinel_blast_SpellScript : public SpellScript + { + PrepareSpellScript(spell_auriaya_sentinel_blast_SpellScript); + + void FilterTargets(std::list& unitList) + { + unitList.remove_if (PlayerOrPetCheck()); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnUnitTargetSelect += SpellUnitTargetFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_auriaya_sentinel_blast_SpellScript(); + } +}; + + +class achievement_nine_lives : public AchievementCriteriaScript +{ + public: + achievement_nine_lives() : AchievementCriteriaScript("achievement_nine_lives") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Auriaya = target->ToCreature()) + if (Auriaya->AI()->GetData(DATA_NINE_LIVES)) + return true; + + return false; + } +}; + +class achievement_crazy_cat_lady : public AchievementCriteriaScript +{ + public: + achievement_crazy_cat_lady() : AchievementCriteriaScript("achievement_crazy_cat_lady") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Auriaya = target->ToCreature()) + if (Auriaya->AI()->GetData(DATA_CRAZY_CAT_LADY)) + return true; + + return false; + } +}; + +void AddSC_boss_auriaya() +{ + new boss_auriaya(); + new npc_auriaya_seeping_trigger(); + new npc_feral_defender(); + new npc_sanctum_sentry(); + new spell_auriaya_strenght_of_the_pack(); + new spell_auriaya_sentinel_blast(); + new achievement_nine_lives(); + new achievement_crazy_cat_lady(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp new file mode 100644 index 00000000000..ad79d1b56cc --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -0,0 +1,1755 @@ +/* + * Copyright (C) 2008-2011 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 . + */ + +/* + * Comment: there is missing code on triggers, + * brann bronzebeard needs correct gossip info. + * requires more work involving area triggers. + * if reached brann speaks through his radio.. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "ScriptedGossip.h" +#include "ScriptedEscortAI.h" +#include "CombatAI.h" +#include "PassiveAI.h" +#include "ObjectMgr.h" +#include "SpellInfo.h" +#include "SpellScript.h" +#include "Vehicle.h" +#include "VehicleDefines.h" +#include "ulduar.h" + +enum Spells +{ + SPELL_PURSUED = 62374, + SPELL_GATHERING_SPEED = 62375, + SPELL_BATTERING_RAM = 62376, + SPELL_FLAME_VENTS = 62396, + SPELL_MISSILE_BARRAGE = 62400, + SPELL_SYSTEMS_SHUTDOWN = 62475, + SPELL_OVERLOAD_CIRCUIT = 62399, + SPELL_START_THE_ENGINE = 62472, + SPELL_SEARING_FLAME = 62402, + SPELL_BLAZE = 62292, + SPELL_TAR_PASSIVE = 62288, + SPELL_SMOKE_TRAIL = 63575, + SPELL_ELECTROSHOCK = 62522, + SPELL_NAPALM = 63666, + SPELL_INVIS_AND_STEALTH_DETECT = 18950, // Passive + //TOWER Additional SPELLS + SPELL_THORIM_S_HAMMER = 62911, // Tower of Storms + SPELL_MIMIRON_S_INFERNO = 62909, // Tower of Flames + SPELL_HODIR_S_FURY = 62533, // Tower of Frost + SPELL_FREYA_S_WARD = 62906, // Tower of Nature + SPELL_FREYA_SUMMONS = 62947, // Tower of Nature + //TOWER ap & health spells + SPELL_BUFF_TOWER_OF_STORMS = 65076, + SPELL_BUFF_TOWER_OF_FLAMES = 65075, + SPELL_BUFF_TOWER_OF_FR0ST = 65077, + SPELL_BUFF_TOWER_OF_LIFE = 64482, + //Additional Spells + SPELL_LASH = 65062, + SPELL_FREYA_S_WARD_EFFECT_1 = 62947, + SPELL_FREYA_S_WARD_EFFECT_2 = 62907, + SPELL_AUTO_REPAIR = 62705, + AURA_DUMMY_BLUE = 63294, + AURA_DUMMY_GREEN = 63295, + AURA_DUMMY_YELLOW = 63292, + SPELL_LIQUID_PYRITE = 62494, + SPELL_DUSTY_EXPLOSION = 63360, + SPELL_DUST_CLOUD_IMPACT = 54740, + AURA_STEALTH_DETECTION = 18950, + SPELL_RIDE_VEHICLE = 46598, +}; + +enum Creatures +{ + NPC_SEAT = 33114, + NPC_MECHANOLIFT = 33214, + NPC_LIQUID = 33189, + NPC_CONTAINER = 33218, + NPC_THORIM_BEACON = 33365, + NPC_MIMIRON_BEACON = 33370, + NPC_HODIR_BEACON = 33212, + NPC_FREYA_BEACON = 33367, + NPC_THORIM_TARGET_BEACON = 33364, + NPC_MIMIRON_TARGET_BEACON = 33369, + NPC_HODIR_TARGET_BEACON = 33108, + NPC_FREYA_TARGET_BEACON = 33366, + NPC_LOREKEEPER = 33686, // Hard mode starter + NPC_BRANZ_BRONZBEARD = 33579, + NPC_DELORAH = 33701, + NPC_ULDUAR_GAUNTLET_GENERATOR = 33571, // Trigger tied to towers +}; + +enum Towers +{ + GO_TOWER_OF_STORMS = 194377, + GO_TOWER_OF_FLAMES = 194371, + GO_TOWER_OF_FROST = 194370, + GO_TOWER_OF_LIFE = 194375, +}; + +enum Events +{ + EVENT_PURSUE = 1, + EVENT_MISSILE = 2, + EVENT_VENT = 3, + EVENT_SPEED = 4, + EVENT_SUMMON = 5, + EVENT_SHUTDOWN = 6, + EVENT_REPAIR = 7, + EVENT_THORIM_S_HAMMER = 8, // Tower of Storms + EVENT_MIMIRON_S_INFERNO = 9, // Tower of Flames + EVENT_HODIR_S_FURY = 10, // Tower of Frost + EVENT_FREYA_S_WARD = 11, // Tower of Nature +}; + +enum Seats +{ + SEAT_PLAYER = 0, + SEAT_TURRET = 1, + SEAT_DEVICE = 2, + SEAT_CANNON = 7, +}; + +enum Vehicles +{ + VEHICLE_SIEGE = 33060, + VEHICLE_CHOPPER = 33062, + VEHICLE_DEMOLISHER = 33109, +}; + +#define EMOTE_PURSUE "Flame Leviathan pursues $N." +#define EMOTE_OVERLOAD "Flame Leviathan's circuits overloaded." +#define EMOTE_REPAIR "Automatic repair sequence initiated." +#define DATA_SHUTOUT 29112912 // 2911, 2912 are achievement IDs +#define DATA_ORBIT_ACHIEVEMENTS 1 +#define VEHICLE_SPAWNS 5 +#define FREYA_SPAWNS 4 + +enum Yells +{ + SAY_AGGRO = -1603060, + SAY_SLAY = -1603061, + SAY_DEATH = -1603062, + SAY_TARGET_1 = -1603063, + SAY_TARGET_2 = -1603064, + SAY_TARGET_3 = -1603065, + SAY_HARDMODE = -1603066, + SAY_TOWER_NONE = -1603067, + SAY_TOWER_FROST = -1603068, + SAY_TOWER_FLAME = -1603069, + SAY_TOWER_NATURE = -1603070, + SAY_TOWER_STORM = -1603071, + SAY_PLAYER_RIDING = -1603072, + SAY_OVERLOAD_1 = -1603073, + SAY_OVERLOAD_2 = -1603074, + SAY_OVERLOAD_3 = -1603075, +}; + +enum MiscellanousData +{ + // Other actions are in Ulduar.h + ACTION_START_HARD_MODE = 5, + ACTION_SPAWN_VEHICLES = 6, + // Amount of seats depending on Raid mode + TWO_SEATS = 2, + FOUR_SEATS = 4, +}; + +Position const Center[]= +{ + {354.8771f, -12.90240f, 409.803650f, 0.0f}, +}; + +Position const InfernoStart[]= +{ + {390.93f, -13.91f, 409.81f, 0.0f}, +}; + +Position const PosSiege[VEHICLE_SPAWNS] = +{ + {-814.59f, -64.54f, 429.92f, 5.969f}, + {-784.37f, -33.31f, 429.92f, 5.096f}, + {-808.99f, -52.10f, 429.92f, 5.668f}, + {-798.59f, -44.00f, 429.92f, 5.663f}, + {-812.83f, -77.71f, 429.92f, 0.046f}, +}; + +Position const PosChopper[VEHICLE_SPAWNS] = +{ + {-717.83f, -106.56f, 430.02f, 0.122f}, + {-717.83f, -114.23f, 430.44f, 0.122f}, + {-717.83f, -109.70f, 430.22f, 0.122f}, + {-718.45f, -118.24f, 430.26f, 0.052f}, + {-718.45f, -123.58f, 430.41f, 0.085f}, +}; + +Position const PosDemolisher[VEHICLE_SPAWNS] = +{ + {-724.12f, -176.64f, 430.03f, 2.543f}, + {-766.70f, -225.03f, 430.50f, 1.710f}, + {-729.54f, -186.26f, 430.12f, 1.902f}, + {-756.01f, -219.23f, 430.50f, 2.369f}, + {-798.01f, -227.24f, 429.84f, 1.446f}, +}; + +Position const FreyaBeacons[FREYA_SPAWNS] = +{ + {377.02f, -119.10f, 409.81f, 0.0f}, + {185.62f, -119.10f, 409.81f, 0.0f}, + {377.02f, 54.78f, 409.81f, 0.0f}, + {185.62f, 54.78f, 409.81f, 0.0f}, +}; + +class boss_flame_leviathan : public CreatureScript +{ + public: + boss_flame_leviathan() : CreatureScript("boss_flame_leviathan") { } + + struct boss_flame_leviathanAI : public BossAI + { + boss_flame_leviathanAI(Creature* creature) : BossAI(creature, BOSS_LEVIATHAN), vehicle(creature->GetVehicleKit()) + { + } + + void InitializeAI() + { + ASSERT(vehicle); + if (!me->isDead()) + Reset(); + + ActiveTowersCount = 4; + Shutdown = 0; + ActiveTowers = false; + towerOfStorms = false; + towerOfLife = false; + towerOfFlames = false; + towerOfFrost = false; + Shutout = true; + Unbroken = true; + + DoCast(SPELL_INVIS_AND_STEALTH_DETECT); + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); + me->SetReactState(REACT_PASSIVE); + } + + Vehicle* vehicle; + uint8 ActiveTowersCount; + uint8 Shutdown; + bool ActiveTowers; + bool towerOfStorms; + bool towerOfLife; + bool towerOfFlames; + bool towerOfFrost; + bool Shutout; + bool Unbroken; + + void Reset() + { + _Reset(); + //resets shutdown counter to 0. 2 or 4 depending on raid mode + Shutdown = 0; + _pursueTarget = 0; + + me->SetReactState(REACT_DEFENSIVE); + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + me->SetReactState(REACT_PASSIVE); + events.ScheduleEvent(EVENT_PURSUE, 1); + events.ScheduleEvent(EVENT_MISSILE, urand(1500, 4*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_VENT, 20*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SHUTDOWN, 150*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SPEED, 15*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMON, 1*IN_MILLISECONDS); + ActiveTower(); //void ActiveTower + } + + void ActiveTower() + { + if (ActiveTowers) + { + if (towerOfStorms) + { + me->AddAura(SPELL_BUFF_TOWER_OF_STORMS, me); + events.ScheduleEvent(EVENT_THORIM_S_HAMMER, 35*IN_MILLISECONDS); + } + + if (towerOfFlames) + { + me->AddAura(SPELL_BUFF_TOWER_OF_FLAMES, me); + events.ScheduleEvent(EVENT_MIMIRON_S_INFERNO, 70*IN_MILLISECONDS); + } + + if (towerOfFrost) + { + me->AddAura(SPELL_BUFF_TOWER_OF_FR0ST, me); + events.ScheduleEvent(EVENT_HODIR_S_FURY, 105*IN_MILLISECONDS); + } + + if (towerOfLife) + { + me->AddAura(SPELL_BUFF_TOWER_OF_LIFE, me); + events.ScheduleEvent(EVENT_FREYA_S_WARD, 140*IN_MILLISECONDS); + } + + if (!towerOfLife && !towerOfFrost && !towerOfFlames && !towerOfStorms) + DoScriptText(SAY_TOWER_NONE, me); + else + DoScriptText(SAY_HARDMODE, me); + } + else + DoScriptText(SAY_AGGRO, me); + } + + void JustDied(Unit* /*victim*/) + { + _JustDied(); + // Set Field Flags 67108928 = 64 | 67108864 = UNIT_FLAG_UNK_6 | UNIT_FLAG_SKINNABLE + // Set DynFlags 12 + // Set NPCFlags 0 + DoScriptText(SAY_DEATH, me); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_START_THE_ENGINE) + vehicle->InstallAllAccessories(false); + + if (spell->Id == SPELL_ELECTROSHOCK) + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + + if (spell->Id == SPELL_OVERLOAD_CIRCUIT) + ++Shutdown; + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_SHUTOUT: + return Shutout ? 1 : 0; + case DATA_UNBROKEN: + return Unbroken ? 1 : 0; + case DATA_ORBIT_ACHIEVEMENTS: + if (ActiveTowers) // Only on HardMode + return ActiveTowersCount; + default: + break; + } + + return 0; + } + + void SetData(uint32 id, uint32 data) + { + if (id == DATA_UNBROKEN) + Unbroken = data ? true : false; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + if (Shutdown == RAID_MODE(TWO_SEATS, FOUR_SEATS)) + { + Shutdown = 0; + events.ScheduleEvent(EVENT_SHUTDOWN, 4000); + me->RemoveAurasDueToSpell(SPELL_OVERLOAD_CIRCUIT); + me->InterruptNonMeleeSpells(true); + return; + } + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_PURSUE: + DoScriptText(RAND(SAY_TARGET_1, SAY_TARGET_2, SAY_TARGET_3), me); + DoCast(SPELL_PURSUED); // Will select target in spellscript + events.ScheduleEvent(EVENT_PURSUE, 35*IN_MILLISECONDS); + break; + case EVENT_MISSILE: + DoCast(me, SPELL_MISSILE_BARRAGE, true); + events.ScheduleEvent(EVENT_MISSILE, 2*IN_MILLISECONDS); + break; + case EVENT_VENT: + DoCastAOE(SPELL_FLAME_VENTS); + events.ScheduleEvent(EVENT_VENT, 20*IN_MILLISECONDS); + break; + case EVENT_SPEED: + DoCastAOE(SPELL_GATHERING_SPEED); + events.ScheduleEvent(EVENT_SPEED, 15*IN_MILLISECONDS); + break; + case EVENT_SUMMON: + if (summons.size() < 15) + if (Creature* lift = DoSummonFlyer(NPC_MECHANOLIFT, me, 30.0f, 50.0f, 0)) + lift->GetMotionMaster()->MoveRandom(100); + events.ScheduleEvent(EVENT_SUMMON, 2*IN_MILLISECONDS); + break; + case EVENT_SHUTDOWN: + DoScriptText(RAND(SAY_OVERLOAD_1, SAY_OVERLOAD_2, SAY_OVERLOAD_3), me); + me->MonsterTextEmote(EMOTE_OVERLOAD, 0, true); + me->CastSpell(me, SPELL_SYSTEMS_SHUTDOWN, true); + if (Shutout) + Shutout = false; + events.ScheduleEvent(EVENT_REPAIR, 4000); + events.DelayEvents(20 * IN_MILLISECONDS, 0); + break; + case EVENT_REPAIR: + me->MonsterTextEmote(EMOTE_REPAIR, 0, true); + me->ClearUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT); + events.ScheduleEvent(EVENT_SHUTDOWN, 150*IN_MILLISECONDS); + events.CancelEvent(EVENT_REPAIR); + break; + case EVENT_THORIM_S_HAMMER: // Tower of Storms + for (uint8 i = 0; i < 7; ++i) + { + if (Creature* thorim = DoSummon(NPC_THORIM_BEACON, me, float(urand(20, 60)), 20000, TEMPSUMMON_TIMED_DESPAWN)) + thorim->GetMotionMaster()->MoveRandom(100); + } + DoScriptText(SAY_TOWER_STORM, me); + events.CancelEvent(EVENT_THORIM_S_HAMMER); + break; + case EVENT_MIMIRON_S_INFERNO: // Tower of Flames + me->SummonCreature(NPC_MIMIRON_BEACON, InfernoStart->GetPositionX(), InfernoStart->GetPositionY(), InfernoStart->GetPositionZ()); + DoScriptText(SAY_TOWER_FLAME, me); + events.CancelEvent(EVENT_MIMIRON_S_INFERNO); + break; + case EVENT_HODIR_S_FURY: // Tower of Frost + for (uint8 i = 0; i < 7; ++i) + { + if (Creature* hodir = DoSummon(NPC_HODIR_BEACON, me, 50, 0)) + hodir->GetMotionMaster()->MoveRandom(100); + } + DoScriptText(SAY_TOWER_FROST, me); + events.CancelEvent(EVENT_HODIR_S_FURY); + break; + case EVENT_FREYA_S_WARD: // Tower of Nature + DoScriptText(SAY_TOWER_NATURE, me); + for (int32 i = 0; i < 4; ++i) + me->SummonCreature(NPC_FREYA_BEACON, FreyaBeacons[i]); + + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_FREYA_S_WARD); + events.CancelEvent(EVENT_FREYA_S_WARD); + break; + } + } + + DoBatteringRamIfReady(); + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) + { + if (spell->Id == SPELL_PURSUED) + _pursueTarget = target->GetGUID(); + } + + void DoAction(int32 const action) + { + if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count + { + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4) && ActiveTowersCount == 4) + { + me->RemoveLootMode(LOOT_MODE_HARD_MODE_4); + --ActiveTowersCount; + } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3) && ActiveTowersCount == 3) + { + me->RemoveLootMode(LOOT_MODE_HARD_MODE_3); + --ActiveTowersCount; + } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2) && ActiveTowersCount == 2) + { + me->RemoveLootMode(LOOT_MODE_HARD_MODE_2); + --ActiveTowersCount; + } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1) && ActiveTowersCount == 1) + { + me->RemoveLootMode(LOOT_MODE_HARD_MODE_1); + --ActiveTowersCount; + } + } + + switch (action) + { + case ACTION_TOWER_OF_STORM_DESTROYED: + towerOfStorms = false; + break; + case ACTION_TOWER_OF_FROST_DESTROYED: + towerOfFrost = false; + break; + case ACTION_TOWER_OF_FLAMES_DESTROYED: + towerOfFlames = false; + break; + case ACTION_TOWER_OF_LIFE_DESTROYED: + towerOfLife = false; + break; + case ACTION_START_HARD_MODE: // Activate hard-mode enable all towers, apply buffs on leviathan + ActiveTowers = true; + towerOfStorms = true; + towerOfLife = true; + towerOfFlames = true; + towerOfFrost = true; + me->SetLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4); + break; + case ACTION_MOVE_TO_CENTER_POSITION: // Triggered by 2 Collossus near door + if (!me->isDead()) + { + me->SetHomePosition(Center->GetPositionX(), Center->GetPositionY(), Center->GetPositionZ(), 0); + me->GetMotionMaster()->MoveCharge(Center->GetPositionX(), Center->GetPositionY(), Center->GetPositionZ()); //position center + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); + return; + } + break; + default: + break; + } + } + + private: + //! Copypasta from DoSpellAttackIfReady, only difference is the target - it cannot be selected trough getVictim this way - + //! I also removed the spellInfo check + void DoBatteringRamIfReady() + { + if (me->isAttackReady()) + { + Unit* target = ObjectAccessor::GetUnit(*me, _pursueTarget); + if (me->IsWithinCombatRange(target, 30.0f)) + { + DoCast(target, SPELL_BATTERING_RAM); + me->resetAttackTimer(); + } + } + } + + uint64 _pursueTarget; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class boss_flame_leviathan_seat : public CreatureScript +{ + public: + boss_flame_leviathan_seat() : CreatureScript("boss_flame_leviathan_seat") { } + + struct boss_flame_leviathan_seatAI : public ScriptedAI + { + boss_flame_leviathan_seatAI(Creature* creature) : ScriptedAI(creature), vehicle(creature->GetVehicleKit()) + { + ASSERT(vehicle); + me->SetReactState(REACT_PASSIVE); + me->SetDisplayId(me->GetCreatureInfo()->Modelid2); + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + Vehicle* vehicle; + + void PassengerBoarded(Unit* who, int8 seatId, bool apply) + { + if (!me->GetVehicle()) + return; + + if (seatId == SEAT_PLAYER) + { + if (!apply) + return; + else + DoScriptText(SAY_PLAYER_RIDING, me); + + if (Creature* turret = me->GetVehicleKit()->GetPassenger(SEAT_TURRET)->ToCreature()) + { + turret->setFaction(me->GetVehicleBase()->getFaction()); + turret->SetUInt32Value(UNIT_FIELD_FLAGS, 0); // unselectable + turret->AI()->AttackStart(who); + } + if (Creature* device = me->GetVehicleKit()->GetPassenger(SEAT_DEVICE)->ToCreature()) + { + device->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + device->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + else if (seatId == SEAT_TURRET) + { + if (apply) + return; + + if (Unit* device = vehicle->GetPassenger(SEAT_DEVICE)) + { + device->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + device->SetUInt32Value(UNIT_FIELD_FLAGS, 0); // unselectable + } + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_flame_leviathan_seatAI(creature); + } +}; + +class boss_flame_leviathan_defense_cannon : public CreatureScript +{ + public: + boss_flame_leviathan_defense_cannon() : CreatureScript("boss_flame_leviathan_defense_cannon") { } + + struct boss_flame_leviathan_defense_cannonAI : public ScriptedAI + { + boss_flame_leviathan_defense_cannonAI(Creature* creature) : ScriptedAI(creature) + { + } + + uint32 NapalmTimer; + + void Reset () + { + NapalmTimer = 5*IN_MILLISECONDS; + DoCast(me, AURA_STEALTH_DETECTION); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (NapalmTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (CanAIAttack(target)) + DoCast(target, SPELL_NAPALM, true); + + NapalmTimer = 5000; + } + else + NapalmTimer -= diff; + } + + bool CanAIAttack(Unit const* who) const + { + if (who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() == NPC_SEAT) + return false; + return true; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_flame_leviathan_defense_cannonAI(creature); + } +}; + +class boss_flame_leviathan_defense_turret : public CreatureScript +{ + public: + boss_flame_leviathan_defense_turret() : CreatureScript("boss_flame_leviathan_defense_turret") { } + + struct boss_flame_leviathan_defense_turretAI : public TurretAI + { + boss_flame_leviathan_defense_turretAI(Creature* creature) : TurretAI(creature) {} + + void DamageTaken(Unit* who, uint32 &damage) + { + if (!CanAIAttack(who)) + damage = 0; + } + + bool CanAIAttack(Unit const* who) const + { + if (who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() != NPC_SEAT) + return false; + return true; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_flame_leviathan_defense_turretAI(creature); + } +}; + +class boss_flame_leviathan_overload_device : public CreatureScript +{ + public: + boss_flame_leviathan_overload_device() : CreatureScript("boss_flame_leviathan_overload_device") { } + + struct boss_flame_leviathan_overload_deviceAI : public PassiveAI + { + boss_flame_leviathan_overload_deviceAI(Creature* creature) : PassiveAI(creature) + { + } + + void DoAction(const int32 param) + { + if (param == EVENT_SPELLCLICK) + { + if (me->GetVehicle()) + { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if (Unit* player = me->GetVehicle()->GetPassenger(SEAT_PLAYER)) + { + me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true); + player->GetMotionMaster()->MoveKnockbackFrom(me->GetVehicleBase()->GetPositionX(), me->GetVehicleBase()->GetPositionY(), 30, 30); + player->ExitVehicle(); + } + } + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_flame_leviathan_overload_deviceAI(creature); + } +}; + +class boss_flame_leviathan_safety_container : public CreatureScript +{ + public: + boss_flame_leviathan_safety_container() : CreatureScript("boss_flame_leviathan_safety_container") { } + + struct boss_flame_leviathan_safety_containerAI : public PassiveAI + { + boss_flame_leviathan_safety_containerAI(Creature* creature) : PassiveAI(creature) + { + } + + void JustDied(Unit* /*killer*/) + { + float x, y, z; + me->GetPosition(x, y, z); + z = me->GetMap()->GetHeight(x, y, z); + me->GetMotionMaster()->MovePoint(0, x, y, z); + me->SetPosition(x, y, z, 0); + } + + void UpdateAI(uint32 const /*diff*/) + { + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_flame_leviathan_safety_containerAI(creature); + } +}; + +class npc_mechanolift : public CreatureScript +{ + public: + npc_mechanolift() : CreatureScript("npc_mechanolift") { } + + struct npc_mechanoliftAI : public PassiveAI + { + npc_mechanoliftAI(Creature* creature) : PassiveAI(creature) + { + ASSERT(me->GetVehicleKit()); + } + + uint32 MoveTimer; + + void Reset() + { + MoveTimer = 0; + me->GetMotionMaster()->MoveRandom(50); + } + + void JustDied(Unit* /*killer*/) + { + me->GetMotionMaster()->MoveTargetedHome(); + DoCast(SPELL_DUSTY_EXPLOSION); + Creature* liquid = DoSummon(NPC_LIQUID, me, 0); + if (liquid) + { + liquid->CastSpell(liquid, SPELL_LIQUID_PYRITE, true); + liquid->CastSpell(liquid, SPELL_DUST_CLOUD_IMPACT, true); + } + } + + void MovementInform(uint32 type, uint32 id) + { + if (type == POINT_MOTION_TYPE && id == 1) + if (Creature* container = me->FindNearestCreature(NPC_CONTAINER, 5, true)) + container->EnterVehicle(me); + } + + void UpdateAI(const uint32 diff) + { + if (MoveTimer <= diff) + { + if (me->GetVehicleKit()->HasEmptySeat(-1)) + { + Creature* container = me->FindNearestCreature(NPC_CONTAINER, 50, true); + if (container && !container->GetVehicle()) + me->GetMotionMaster()->MovePoint(1, container->GetPositionX(), container->GetPositionY(), container->GetPositionZ()); + } + + MoveTimer = 30000; //check next 30 seconds + } + else + MoveTimer -= diff; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_mechanoliftAI(creature); + } +}; + +class npc_pool_of_tar : public CreatureScript +{ + public: + npc_pool_of_tar() : CreatureScript("npc_pool_of_tar") { } + + struct npc_pool_of_tarAI : public ScriptedAI + { + npc_pool_of_tarAI(Creature* creature) : ScriptedAI(creature) + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); + me->CastSpell(me, SPELL_TAR_PASSIVE, true); + } + + void DamageTaken(Unit* /*who*/, uint32& damage) + { + damage = 0; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->SchoolMask & SPELL_SCHOOL_MASK_FIRE && !me->HasAura(SPELL_BLAZE)) + me->CastSpell(me, SPELL_BLAZE, true); + } + + void UpdateAI(uint32 const /*diff*/) {} + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_pool_of_tarAI(creature); + } +}; + +class npc_colossus : public CreatureScript +{ + public: + npc_colossus() : CreatureScript("npc_colossus") { } + + struct npc_colossusAI : public ScriptedAI + { + npc_colossusAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + + void JustDied(Unit* /*Who*/) + { + if (me->GetHomePosition().IsInDist(Center, 50.f)) + instance->SetData(DATA_COLOSSUS, instance->GetData(DATA_COLOSSUS)+1); + } + + void UpdateAI(uint32 const /*diff*/) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_colossusAI(creature); + } +}; + +class npc_thorims_hammer : public CreatureScript +{ + public: + npc_thorims_hammer() : CreatureScript("npc_thorims_hammer") { } + + struct npc_thorims_hammerAI : public ScriptedAI + { + npc_thorims_hammerAI(Creature* creature) : ScriptedAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->CastSpell(me, AURA_DUMMY_BLUE, true); + } + + void MoveInLineOfSight(Unit* who) + { + if (who->GetTypeId() == TYPEID_PLAYER && who->IsVehicle() && me->IsInRange(who, 0, 10, false)) + { + if (Creature* trigger = DoSummonFlyer(NPC_THORIM_TARGET_BEACON, me, 20, 0, 1000, TEMPSUMMON_TIMED_DESPAWN)) + trigger->CastSpell(who, SPELL_THORIM_S_HAMMER, true); + } + } + + void UpdateAI(uint32 const /*diff*/) + { + if (!me->HasAura(AURA_DUMMY_BLUE)) + me->CastSpell(me, AURA_DUMMY_BLUE, true); + + UpdateVictim(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_thorims_hammerAI(creature); + } +}; + +class npc_mimirons_inferno : public CreatureScript +{ +public: + npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { } + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_mimirons_infernoAI(creature); + } + + struct npc_mimirons_infernoAI : public npc_escortAI + { + npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->CastSpell(me, AURA_DUMMY_YELLOW, true); + me->SetReactState(REACT_PASSIVE); + } + + void WaypointReached(uint32 /*i*/) + { + } + + void Reset() + { + infernoTimer = 2000; + } + + uint32 infernoTimer; + + void UpdateAI(uint32 const diff) + { + npc_escortAI::UpdateAI(diff); + + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + Start(false, true, 0, NULL, false, true); + else + { + if (infernoTimer <= diff) + { + if (Creature* trigger = DoSummonFlyer(NPC_MIMIRON_TARGET_BEACON, me, 20, 0, 1000, TEMPSUMMON_TIMED_DESPAWN)) + { + trigger->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), SPELL_MIMIRON_S_INFERNO, true); + infernoTimer = 2000; + } + } + else + infernoTimer -= diff; + + if (!me->HasAura(AURA_DUMMY_YELLOW)) + me->CastSpell(me, AURA_DUMMY_YELLOW, true); + } + } + }; + +}; + +class npc_hodirs_fury : public CreatureScript +{ + public: + npc_hodirs_fury() : CreatureScript("npc_hodirs_fury") { } + + struct npc_hodirs_furyAI : public ScriptedAI + { + npc_hodirs_furyAI(Creature* creature) : ScriptedAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->CastSpell(me, AURA_DUMMY_GREEN, true); + } + + void MoveInLineOfSight(Unit* who) + { + if (who->GetTypeId() == TYPEID_PLAYER && who->IsVehicle() && me->IsInRange(who, 0, 5, false)) + { + if (Creature* trigger = DoSummonFlyer(NPC_HODIR_TARGET_BEACON, me, 20, 0, 1000, TEMPSUMMON_TIMED_DESPAWN)) + trigger->CastSpell(who, SPELL_HODIR_S_FURY, true); + } + } + + void UpdateAI(uint32 const /*diff*/) + { + if (!me->HasAura(AURA_DUMMY_GREEN)) + me->CastSpell(me, AURA_DUMMY_GREEN, true); + + UpdateVictim(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_hodirs_furyAI(creature); + } +}; + +class npc_freyas_ward : public CreatureScript +{ + public: + npc_freyas_ward() : CreatureScript("npc_freyas_ward") { } + + struct npc_freyas_wardAI : public ScriptedAI + { + npc_freyas_wardAI(Creature* creature) : ScriptedAI(creature) + { + me->CastSpell(me, AURA_DUMMY_GREEN, true); + } + + uint32 summonTimer; + + void Reset() + { + summonTimer = 5000; + } + + void UpdateAI(uint32 const diff) + { + if (summonTimer <= diff) + { + DoCast(SPELL_FREYA_S_WARD_EFFECT_1); + DoCast(SPELL_FREYA_S_WARD_EFFECT_2); + summonTimer = 20000; + } + else + summonTimer -= diff; + + if (!me->HasAura(AURA_DUMMY_GREEN)) + me->CastSpell(me, AURA_DUMMY_GREEN, true); + + UpdateVictim(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_freyas_wardAI(creature); + } +}; + +class npc_freya_ward_summon : public CreatureScript +{ + public: + npc_freya_ward_summon() : CreatureScript("npc_freya_ward_summon") { } + + struct npc_freya_ward_summonAI : public ScriptedAI + { + npc_freya_ward_summonAI(Creature* creature) : ScriptedAI(creature) + { + creature->GetMotionMaster()->MoveRandom(100); + } + + uint32 lashTimer; + + void Reset() + { + lashTimer = 5000; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (lashTimer <= diff) + { + DoCast(SPELL_LASH); + lashTimer = 20000; + } + else + lashTimer -= diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_freya_ward_summonAI(creature); + } +}; + +//npc lore keeper +#define GOSSIP_ITEM_1 "Activate secondary defensive systems" +#define GOSSIP_ITEM_2 "Confirmed" + +class npc_lorekeeper : public CreatureScript +{ + public: + npc_lorekeeper() : CreatureScript("npc_lorekeeper") { } + + struct npc_lorekeeperAI : public ScriptedAI + { + npc_lorekeeperAI(Creature* creature) : ScriptedAI(creature) + { + } + + void DoAction(int32 const action) + { + // Start encounter + if (action == ACTION_SPAWN_VEHICLES) + { + for (int32 i = 0; i < RAID_MODE(2, 5); ++i) + DoSummon(VEHICLE_SIEGE, PosSiege[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); + for (int32 i = 0; i < RAID_MODE(2, 5); ++i) + DoSummon(VEHICLE_CHOPPER, PosChopper[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); + for (int32 i = 0; i < RAID_MODE(2, 5); ++i) + DoSummon(VEHICLE_DEMOLISHER, PosDemolisher[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); + return; + } + } + }; + + bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 action) + { + player->PlayerTalkClass->ClearMenus(); + InstanceScript* instance = creature->GetInstanceScript(); + if (!instance) + return true; + + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + if (player) + { + player->PrepareGossipMenu(creature); + instance->instance->LoadGrid(364, -16); //make sure leviathan is loaded + + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); + } + break; + case GOSSIP_ACTION_INFO_DEF+2: + if (player) + player->CLOSE_GOSSIP_MENU(); + + if (Creature* leviathan = instance->instance->GetCreature(instance->GetData64(BOSS_LEVIATHAN))) + { + leviathan->AI()->DoAction(ACTION_START_HARD_MODE); + creature->SetVisible(false); + creature->AI()->DoAction(ACTION_SPAWN_VEHICLES); // spawn the vehicles + if (Creature* Delorah = creature->FindNearestCreature(NPC_DELORAH, 1000, true)) + { + if (Creature* Branz = creature->FindNearestCreature(NPC_BRANZ_BRONZBEARD, 1000, true)) + { + Delorah->GetMotionMaster()->MovePoint(0, Branz->GetPositionX()-4, Branz->GetPositionY(), Branz->GetPositionZ()); + //TODO DoScriptText(xxxx, Delorah, Branz); when reached at branz + } + } + } + break; + } + + return true; + } + + bool OnGossipHello(Player* player, Creature* creature) + { + InstanceScript* instance = creature->GetInstanceScript(); + if (instance && instance->GetData(BOSS_LEVIATHAN) !=DONE && player) + { + player->PrepareGossipMenu(creature); + + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); + } + return true; + } + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_lorekeeperAI(creature); + } +}; + +//enable hardmode +////npc_brann_bronzebeard this requires more work involving area triggers. if reached this guy speaks through his radio.. +//#define GOSSIP_ITEM_1 "xxxxx" +//#define GOSSIP_ITEM_2 "xxxxx" +// +/* +class npc_brann_bronzebeard : public CreatureScript +{ +public: + npc_brann_bronzebeard() : CreatureScript("npc_brann_bronzebeard") { } + + //bool OnGossipSelect(Player* player, Creature* creature, uint32 uiSender, uint32 uiAction) + //{ + // player->PlayerTalkClass->ClearMenus(); + // switch(uiAction) + // { + // case GOSSIP_ACTION_INFO_DEF+1: + // if (player) + // { + // player->PrepareGossipMenu(creature); + // + // player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + // player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); + // } + // break; + // case GOSSIP_ACTION_INFO_DEF+2: + // if (player) + // player->CLOSE_GOSSIP_MENU(); + // if (Creature* Lorekeeper = creature->FindNearestCreature(NPC_LOREKEEPER, 1000, true)) //lore keeper of lorgannon + // Lorekeeper->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + // break; + // } + // return true; + //} + //bool OnGossipHello(Player* player, Creature* creature) + //{ + // InstanceScript* instance = creature->GetInstanceScript(); + // if (instance && instance->GetData(BOSS_LEVIATHAN) !=DONE) + // { + // player->PrepareGossipMenu(creature); + // + // player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + // player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); + // } + // return true; + //} + // +} +*/ + +class go_ulduar_tower : public GameObjectScript +{ + public: + go_ulduar_tower() : GameObjectScript("go_ulduar_tower") { } + + void OnDestroyed(GameObject* go, Player* /*player*/, uint32 /*value*/) + { + InstanceScript* instance = go->GetInstanceScript(); + if (!instance) + return; + + switch (go->GetEntry()) + { + case GO_TOWER_OF_STORMS: + instance->ProcessEvent(go, EVENT_TOWER_OF_STORM_DESTROYED); + break; + case GO_TOWER_OF_FLAMES: + instance->ProcessEvent(go, EVENT_TOWER_OF_FLAMES_DESTROYED); + break; + case GO_TOWER_OF_FROST: + instance->ProcessEvent(go, EVENT_TOWER_OF_FROST_DESTROYED); + break; + case GO_TOWER_OF_LIFE: + instance->ProcessEvent(go, EVENT_TOWER_OF_LIFE_DESTROYED); + break; + } + + Creature* trigger = go->FindNearestCreature(NPC_ULDUAR_GAUNTLET_GENERATOR, 15.0f, true); + if (trigger) + trigger->DisappearAndDie(); + } +}; + +class achievement_three_car_garage_demolisher : public AchievementCriteriaScript +{ + public: + achievement_three_car_garage_demolisher() : AchievementCriteriaScript("achievement_three_car_garage_demolisher") { } + + bool OnCheck(Player* source, Unit* /*target*/) + { + if (Creature* vehicle = source->GetVehicleCreatureBase()) + { + if (vehicle->GetEntry() == VEHICLE_DEMOLISHER) + return true; + } + + return false; + } +}; + +class achievement_three_car_garage_chopper : public AchievementCriteriaScript +{ + public: + achievement_three_car_garage_chopper() : AchievementCriteriaScript("achievement_three_car_garage_chopper") { } + + bool OnCheck(Player* source, Unit* /*target*/) + { + if (Creature* vehicle = source->GetVehicleCreatureBase()) + { + if (vehicle->GetEntry() == VEHICLE_CHOPPER) + return true; + } + + return false; + } +}; + +class achievement_three_car_garage_siege : public AchievementCriteriaScript +{ + public: + achievement_three_car_garage_siege() : AchievementCriteriaScript("achievement_three_car_garage_siege") { } + + bool OnCheck(Player* source, Unit* /*target*/) + { + if (Creature* vehicle = source->GetVehicleCreatureBase()) + { + if (vehicle->GetEntry() == VEHICLE_SIEGE) + return true; + } + + return false; + } +}; + +class achievement_shutout : public AchievementCriteriaScript +{ + public: + achievement_shutout() : AchievementCriteriaScript("achievement_shutout") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (target) + if (Creature* leviathan = target->ToCreature()) + if (leviathan->AI()->GetData(DATA_SHUTOUT)) + return true; + + return false; + } +}; + +class achievement_unbroken : public AchievementCriteriaScript +{ + public: + achievement_unbroken() : AchievementCriteriaScript("achievement_unbroken") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + return instance->GetData(DATA_UNBROKEN); + + return false; + } +}; + +class achievement_orbital_bombardment : public AchievementCriteriaScript +{ + public: + achievement_orbital_bombardment() : AchievementCriteriaScript("achievement_orbital_bombardment") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Leviathan = target->ToCreature()) + if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) >= 1) + return true; + + return false; + } +}; + +class achievement_orbital_devastation : public AchievementCriteriaScript +{ + public: + achievement_orbital_devastation() : AchievementCriteriaScript("achievement_orbital_devastation") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Leviathan = target->ToCreature()) + if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) >= 2) + return true; + + return false; + } +}; + +class achievement_nuked_from_orbit : public AchievementCriteriaScript +{ + public: + achievement_nuked_from_orbit() : AchievementCriteriaScript("achievement_nuked_from_orbit") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Leviathan = target->ToCreature()) + if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) >= 3) + return true; + + return false; + } +}; + +class achievement_orbit_uary : public AchievementCriteriaScript +{ + public: + achievement_orbit_uary() : AchievementCriteriaScript("achievement_orbit_uary") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Leviathan = target->ToCreature()) + if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) == 4) + return true; + + return false; + } +}; + +class spell_load_into_catapult : public SpellScriptLoader +{ + enum Spells + { + SPELL_PASSENGER_LOADED = 62340, + }; + + public: + spell_load_into_catapult() : SpellScriptLoader("spell_load_into_catapult") { } + + class spell_load_into_catapult_AuraScript : public AuraScript + { + PrepareAuraScript(spell_load_into_catapult_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* owner = GetOwner()->ToUnit(); + if (!owner) + return; + + owner->CastSpell(owner, SPELL_PASSENGER_LOADED, true); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* owner = GetOwner()->ToUnit(); + if (!owner) + return; + + owner->RemoveAurasDueToSpell(SPELL_PASSENGER_LOADED); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_load_into_catapult_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_load_into_catapult_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_load_into_catapult_AuraScript(); + } +}; + +class spell_auto_repair : public SpellScriptLoader +{ + enum Spells + { + SPELL_AUTO_REPAIR = 62705, + }; + + public: + spell_auto_repair() : SpellScriptLoader("spell_auto_repair") {} + + class spell_auto_repair_SpellScript : public SpellScript + { + PrepareSpellScript(spell_auto_repair_SpellScript); + + void CheckCooldownForTarget() + { + if (GetHitUnit()->HasAuraEffect(SPELL_AUTO_REPAIR, EFFECT_2)) // Check presence of dummy aura indicating cooldown + { + PreventHitEffect(EFFECT_0); + PreventHitDefaultEffect(EFFECT_1); + PreventHitDefaultEffect(EFFECT_2); + //! Currently this doesn't work: if we call PreventHitAura(), the existing aura will be removed + //! because of recent aura refreshing changes. Since removing the existing aura negates the idea + //! of a cooldown marker, we just let the dummy aura refresh itself without executing the other spelleffects. + //! The spelleffects can be executed by letting the dummy aura expire naturally. + //! This is a temporary solution only. + //PreventHitAura(); + } + } + + void HandleScript(SpellEffIndex /*eff*/) + { + Vehicle* vehicle = GetHitUnit()->GetVehicleKit(); + if (!vehicle) + return; + + Player* driver = vehicle->GetPassenger(0) ? vehicle->GetPassenger(0)->ToPlayer() : NULL; + if (!driver) + return; + + driver->MonsterTextEmote(EMOTE_REPAIR, driver->GetGUID(), true); + + InstanceScript* instance = driver->GetInstanceScript(); + if (!instance) + return; + + // Actually should/could use basepoints (100) for this spell effect as percentage of health, but oh well. + vehicle->GetBase()->SetFullHealth(); + + // For achievement + instance->SetData(DATA_UNBROKEN, 0); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_auto_repair_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + BeforeHit += SpellHitFn(spell_auto_repair_SpellScript::CheckCooldownForTarget); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_auto_repair_SpellScript(); + } +}; + +class spell_systems_shutdown : public SpellScriptLoader +{ + public: + spell_systems_shutdown() : SpellScriptLoader("spell_systems_shutdown") { } + + class spell_systems_shutdown_AuraScript : public AuraScript + { + PrepareAuraScript(spell_systems_shutdown_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Creature* owner = GetOwner()->ToCreature(); + if (!owner) + return; + + //! This could probably in the SPELL_EFFECT_SEND_EVENT handler too: + owner->AddUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT); + owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + owner->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Creature* owner = GetOwner()->ToCreature(); + if (!owner) + return; + + owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_systems_shutdown_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_systems_shutdown_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_systems_shutdown_AuraScript(); + } +}; + +class FlameLeviathanPursuedTargetSelector +{ + enum Area + { + AREA_FORMATION_GROUNDS = 4652, + }; + + public: + explicit FlameLeviathanPursuedTargetSelector(Unit* unit) : _me(unit) {}; + + bool operator()(Unit* target) const + { + //! No players, only vehicles (todo: check if blizzlike) + Creature* creatureTarget = target->ToCreature(); + if (!creatureTarget) + return true; + + //! NPC entries must match + if (creatureTarget->GetEntry() != NPC_SALVAGED_DEMOLISHER && creatureTarget->GetEntry() != NPC_SALVAGED_SIEGE_ENGINE) + return true; + + //! NPC must be a valid vehicle installation + Vehicle* vehicle = creatureTarget->GetVehicleKit(); + if (!vehicle) + return true; + + //! Entity needs to be in appropriate area + if (target->GetAreaId() != AREA_FORMATION_GROUNDS) + return true; + + //! Vehicle must be in use by player + bool playerFound = false; + for (SeatMap::const_iterator itr = vehicle->Seats.begin(); itr != vehicle->Seats.end() && !playerFound; ++itr) + if (IS_PLAYER_GUID(itr->second.Passenger)) + playerFound = true; + + return !playerFound; + } + + private: + Unit const* _me; +}; + +class spell_pursue : public SpellScriptLoader +{ + public: + spell_pursue() : SpellScriptLoader("spell_pursue") {} + + class spell_pursue_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pursue_SpellScript); + + bool Load() + { + _target = NULL; + return true; + } + + void FilterTargets(std::list& targets) + { + targets.remove_if(FlameLeviathanPursuedTargetSelector(GetCaster())); + if (targets.empty()) + { + if (Creature* caster = GetCaster()->ToCreature()) + caster->AI()->EnterEvadeMode(); + } + else + { + //! In the end, only one target should be selected + _target = SelectRandomContainerElement(targets); + FilterTargetsSubsequently(targets); + } + } + + void FilterTargetsSubsequently(std::list& targets) + { + targets.clear(); + if(_target) + targets.push_back(_target); + } + + void HandleScript(SpellEffIndex /*eff*/) + { + Creature* caster = GetCaster()->ToCreature(); + if (!caster) + return; + + caster->AI()->AttackStart(GetHitUnit()); // Chase target + + for (SeatMap::const_iterator itr = caster->GetVehicleKit()->Seats.begin(); itr != caster->GetVehicleKit()->Seats.end(); ++itr) + { + if (IS_PLAYER_GUID(itr->second.Passenger)) + { + caster->MonsterTextEmote(EMOTE_PURSUE, itr->second.Passenger, true); + return; + } + } + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_pursue_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnUnitTargetSelect += SpellUnitTargetFn(spell_pursue_SpellScript::FilterTargetsSubsequently, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_pursue_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + + Unit* _target; + }; + + SpellScript* GetSpellScript() const + { + return new spell_pursue_SpellScript(); + } +}; + +void AddSC_boss_flame_leviathan() +{ + new boss_flame_leviathan(); + new boss_flame_leviathan_seat(); + new boss_flame_leviathan_defense_turret(); + new boss_flame_leviathan_defense_cannon(); + new boss_flame_leviathan_overload_device(); + new boss_flame_leviathan_safety_container(); + new npc_mechanolift(); + new npc_pool_of_tar(); + new npc_colossus(); + new npc_thorims_hammer(); + new npc_mimirons_inferno(); + new npc_hodirs_fury(); + new npc_freyas_ward(); + new npc_freya_ward_summon(); + new npc_lorekeeper(); + // new npc_brann_bronzebeard(); + new go_ulduar_tower(); + + new achievement_three_car_garage_demolisher(); + new achievement_three_car_garage_chopper(); + new achievement_three_car_garage_siege(); + new achievement_shutout(); + new achievement_unbroken(); + new achievement_orbital_bombardment(); + new achievement_orbital_devastation(); + new achievement_nuked_from_orbit(); + new achievement_orbit_uary(); + + new spell_load_into_catapult(); + new spell_auto_repair(); + new spell_systems_shutdown(); + new spell_pursue(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp new file mode 100644 index 00000000000..f59ef8afe10 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -0,0 +1,1717 @@ +/* + * Copyright (C) 2008-2011 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 "SpellScript.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "ulduar.h" + +enum FreyaYells +{ + // Freya + SAY_AGGRO = -1603180, + SAY_AGGRO_WITH_ELDER = -1603181, + SAY_SLAY_1 = -1603182, + SAY_SLAY_2 = -1603183, + SAY_DEATH = -1603184, + SAY_BERSERK = -1603185, + SAY_SUMMON_CONSERVATOR = -1603186, + SAY_SUMMON_TRIO = -1603187, + SAY_SUMMON_LASHERS = -1603188, + SAY_YS_HELP = -1603189, + + // Elder Brightleaf + SAY_BRIGHTLEAF_AGGRO = -1603190, + SAY_BRIGHTLEAF_SLAY_1 = -1603191, + SAY_BRIGHTLEAF_SLAY_2 = -1603192, + SAY_BRIGHTLEAF_DEATH = -1603193, + + // Elder Ironbranch + SAY_IRONBRANCH_AGGRO = -1603194, + SAY_IRONBRANCH_SLAY_1 = -1603195, + SAY_IRONBRANCH_SLAY_2 = -1603196, + SAY_IRONBRANCH_DEATH = -1603197, + + // Elder Stonebark + SAY_STONEBARK_AGGRO = -1603198, + SAY_STONEBARK_SLAY_1 = -1603199, + SAY_STONEBARK_SLAY_2 = -1603200, + SAY_STONEBARK_DEATH = -1603201, +}; + +enum FreyaSpells +{ + // Freya + SPELL_ATTUNED_TO_NATURE = 62519, + SPELL_TOUCH_OF_EONAR = 62528, + SPELL_SUNBEAM = 62623, + SPELL_ENRAGE = 47008, + SPELL_FREYA_GROUND_TREMOR = 62437, + SPELL_ROOTS_FREYA = 62283, + SPELL_STONEBARK_ESSENCE = 62483, + SPELL_IRONBRANCH_ESSENCE = 62484, + SPELL_BRIGHTLEAF_ESSENCE = 62485, + SPELL_DRAINED_OF_POWER = 62467, + SPELL_SUMMON_EONAR_GIFT = 62572, + + // Stonebark + SPELL_FISTS_OF_STONE = 62344, + SPELL_GROUND_TREMOR = 62325, + SPELL_PETRIFIED_BARK = 62337, + SPELL_PETRIFIED_BARK_DMG = 62379, + + // Ironbranch + SPELL_IMPALE = 62310, + SPELL_ROOTS_IRONBRANCH = 62438, + SPELL_THORN_SWARM = 62285, + + // Brightleaf + SPELL_FLUX_AURA = 62239, + SPELL_FLUX = 62262, + SPELL_FLUX_PLUS = 62251, + SPELL_FLUX_MINUS = 62252, + SPELL_SOLAR_FLARE = 62240, + SPELL_UNSTABLE_SUN_BEAM_SUMMON = 62207, // Trigger 62221 + + // Stack Removing of Attuned to Nature + SPELL_REMOVE_25STACK = 62521, + SPELL_REMOVE_10STACK = 62525, + SPELL_REMOVE_2STACK = 62524, + + // Achievement spells + SPELL_DEFORESTATION_CREDIT = 65015, + SPELL_KNOCK_ON_WOOD_CREDIT = 65074, + + // Wave summoning spells + SPELL_SUMMON_LASHERS = 62687, + SPELL_SUMMON_TRIO = 62686, + SPELL_SUMMON_ANCIENT_CONSERVATOR = 62685, + + // Detonating Lasher + SPELL_DETONATE = 62598, + SPELL_FLAME_LASH = 62608, + + // Ancient Water Spirit + SPELL_TIDAL_WAVE = 62653, + SPELL_TIDAL_WAVE_EFFECT = 62654, + + // Storm Lasher + SPELL_LIGHTNING_LASH = 62648, + SPELL_STORMBOLT = 62649, + + // Snaplasher + SPELL_HARDENED_BARK = 62664, + SPELL_BARK_AURA = 62663, + + // Ancient Conservator + SPELL_CONSERVATOR_GRIP = 62532, + SPELL_NATURE_FURY = 62589, + SPELL_SUMMON_PERIODIC = 62566, + SPELL_SPORE_SUMMON_NW = 62582, // Not used, triggered by SPELL_SUMMON_PERIODIC + SPELL_SPORE_SUMMON_NE = 62591, + SPELL_SPORE_SUMMON_SE = 62592, + SPELL_SPORE_SUMMON_SW = 62593, + + // Healthly Spore + SPELL_HEALTHY_SPORE_VISUAL = 62538, + SPELL_GROW = 62559, + SPELL_POTENT_PHEROMONES = 62541, + + // Eonar's Gift + SPELL_LIFEBINDERS_GIFT = 62584, + SPELL_PHEROMONES = 62619, + SPELL_EONAR_VISUAL = 62579, + + // Nature Bomb + SPELL_NATURE_BOMB = 64587, + SPELL_OBJECT_BOMB = 64600, + SPELL_SUMMON_NATURE_BOMB = 64606, + + // Unstable Sun Beam + SPELL_UNSTABLE_SUN_BEAM = 62211, + SPELL_UNSTABLE_ENERGY = 62217, + SPELL_PHOTOSYNTHESIS = 62209, + SPELL_UNSTABLE_SUN_BEAM_TRIGGERED = 62243, + SPELL_FREYA_UNSTABLE_SUNBEAM = 62450, // Or maybe 62866? + + // Sun Beam + SPELL_FREYA_UNSTABLE_ENERGY = 62451, + SPELL_FREYA_UNSTABLE_ENERGY_VISUAL = 62216, + + // Attuned To Nature spells + SPELL_ATTUNED_TO_NATURE_2_DOSE_REDUCTION = 62524, + SPELL_ATTUNED_TO_NATURE_10_DOSE_REDUCTION = 62525, + SPELL_ATTUNED_TO_NATURE_25_DOSE_REDUCTION = 62521, +}; + +enum FreyaNpcs +{ + NPC_SUN_BEAM = 33170, + NPC_DETONATING_LASHER = 32918, + NPC_ANCIENT_CONSERVATOR = 33203, + NPC_ANCIENT_WATER_SPIRIT = 33202, + NPC_STORM_LASHER = 32919, + NPC_SNAPLASHER = 32916, + NPC_NATURE_BOMB = 34129, + NPC_EONARS_GIFT = 33228, + NPC_HEALTHY_SPORE = 33215, + NPC_UNSTABLE_SUN_BEAM = 33050, + NPC_IRON_ROOTS = 33088, + NPC_STRENGTHENED_IRON_ROOTS = 33168, + + OBJECT_NATURE_BOMB = 194902, +}; + +enum FreyaActions +{ + ACTION_ELDER_DEATH = 1, + ACTION_ELDER_FREYA_KILLED = 2, +}; + +enum FreyaEvents +{ + // Freya + EVENT_WAVE = 1, + EVENT_EONAR_GIFT = 2, + EVENT_NATURE_BOMB = 3, + EVENT_UNSTABLE_ENERGY = 4, + EVENT_STRENGTHENED_IRON_ROOTS = 5, + EVENT_GROUND_TREMOR = 6, + EVENT_SUNBEAM = 7, + EVENT_ENRAGE = 8, + + // Elder Stonebark + EVENT_TREMOR = 9, + EVENT_BARK = 10, + EVENT_FISTS = 11, + + // Elder Ironbranch + EVENT_IMPALE = 12, + EVENT_IRON_ROOTS = 13, + EVENT_THORN_SWARM = 14, + + // Elder Brightleaf + EVENT_SOLAR_FLARE = 15, + EVENT_UNSTABLE_SUN_BEAM = 16, + EVENT_FLUX = 17, +}; + +#define WAVE_TIME 60000 // Normal wave is one minute +#define TIME_DIFFERENCE 10000 // If difference between waveTime and WAVE_TIME is bigger then TIME_DIFFERENCE, schedule EVENT_WAVE in 10 seconds +#define DATA_GETTING_BACK_TO_NATURE 1 +#define DATA_KNOCK_ON_WOOD 2 + +class npc_iron_roots : public CreatureScript +{ + public: + npc_iron_roots() : CreatureScript("npc_iron_roots") { } + + struct npc_iron_rootsAI : public Scripted_NoMovementAI + { + npc_iron_rootsAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); + me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip + me->setFaction(14); + me->SetReactState(REACT_PASSIVE); + summonerGUID = 0; + } + + void IsSummonedBy(Unit* summoner) + { + if (summoner->GetTypeId() != TYPEID_PLAYER) + return; + // Summoner is a player, who should have root aura on self + summonerGUID = summoner->GetGUID(); + me->SetFacingToObject(summoner); + me->SetInCombatWith(summoner); + } + + void JustDied(Unit* /*who*/) + { + if (Player* target = ObjectAccessor::GetPlayer(*me, summonerGUID)) + { + target->RemoveAurasDueToSpell(SPELL_ROOTS_IRONBRANCH); + target->RemoveAurasDueToSpell(SPELL_ROOTS_FREYA); + } + + me->RemoveCorpse(false); + } + + private: + uint64 summonerGUID; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_iron_rootsAI(creature); + } +}; + +class boss_freya : public CreatureScript +{ + public: + boss_freya() : CreatureScript("boss_freya") { } + + struct boss_freyaAI : public BossAI + { + boss_freyaAI(Creature* creature) : BossAI(creature, BOSS_FREYA) + { + } + + uint64 ElementalGUID[3][2]; + + uint32 deforestation[6][2]; + uint32 elementalTimer[2]; + uint32 diffTimer; + uint8 trioWaveCount; + uint8 trioWaveController; + uint8 waveCount; + uint8 elderCount; + uint8 attunedToNature; + + bool checkElementalAlive[2]; + bool trioDefeated[2]; + bool random[3]; + + void Reset() + { + _Reset(); + summons.clear(); + trioWaveCount = 0; + trioWaveController = 0; + waveCount = 0; + elderCount = 0; + + for (uint8 i = 0; i < 3; ++i) + for (uint8 n = 0; n < 2; ++n) + ElementalGUID[i][n] = 0; + for (uint8 i = 0; i < 6; ++i) + for (uint8 n = 0; n < 2; ++n) + deforestation[i][n] = 0; + for (uint8 n = 0; n < 2; ++n) + { + checkElementalAlive[n] = true; + trioDefeated[n] = false; + } + for (uint8 n = 0; n < 3; ++n) + random[n] = false; + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void DamageTaken(Unit* /*who*/, uint32& damage) + { + if (damage >= me->GetHealth()) + { + damage = 0; + DoScriptText(SAY_DEATH, me); + me->SetReactState(REACT_PASSIVE); + _JustDied(); + me->RemoveAllAuras(); + me->AttackStop(); + me->setFaction(35); + me->DeleteThreatList(); + me->CombatStop(true); + me->DespawnOrUnsummon(7500); + me->CastSpell(me, SPELL_KNOCK_ON_WOOD_CREDIT, true); + + Creature* Elder[3]; + for (uint8 n = 0; n < 3; ++n) + { + Elder[n] = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF + n)); + if (Elder[n] && Elder[n]->isAlive()) + { + Elder[n]->RemoveAllAuras(); + Elder[n]->AttackStop(); + Elder[n]->CombatStop(true); + Elder[n]->DeleteThreatList(); + Elder[n]->GetAI()->DoAction(ACTION_ELDER_FREYA_KILLED); + } + } + } + } + + void EnterCombat(Unit* who) + { + _EnterCombat(); + DoZoneInCombat(); + Creature* Elder[3]; + for (uint8 n = 0; n < 3; ++n) + { + Elder[n] = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF + n)); + if (Elder[n] && Elder[n]->isAlive()) + { + me->AddAura(SPELL_DRAINED_OF_POWER, Elder[n]); + Elder[n]->CastSpell(me, SPELL_IRONBRANCH_ESSENCE, true); + Elder[n]->RemoveLootMode(LOOT_MODE_DEFAULT); //! Why? + Elder[n]->AI()->AttackStart(who); + Elder[n]->AddThreat(who, 250.0f); + Elder[n]->SetInCombatWith(who); + ++elderCount; + } + } + + if (Elder[0] && Elder[0]->isAlive()) + { + Elder[0]->CastSpell(me, SPELL_BRIGHTLEAF_ESSENCE, true); + events.ScheduleEvent(EVENT_UNSTABLE_ENERGY, urand(10000, 20000)); + } + + if (Elder[1] && Elder[1]->isAlive()) + { + Elder[1]->CastSpell(me, SPELL_STONEBARK_ESSENCE, true); + events.ScheduleEvent(EVENT_GROUND_TREMOR, urand(10000, 20000)); + } + + if (Elder[2] && Elder[2]->isAlive()) + { + Elder[2]->CastSpell(me, SPELL_IRONBRANCH_ESSENCE, true); + events.ScheduleEvent(EVENT_STRENGTHENED_IRON_ROOTS, urand(10000, 20000)); + } + + if (elderCount == 0) + DoScriptText(SAY_AGGRO, me); + else + DoScriptText(SAY_AGGRO_WITH_ELDER, me); + + me->CastCustomSpell(SPELL_ATTUNED_TO_NATURE, SPELLVALUE_AURA_STACK, 150, me, true); + + events.ScheduleEvent(EVENT_WAVE, 10000); + events.ScheduleEvent(EVENT_EONAR_GIFT, 25000); + events.ScheduleEvent(EVENT_ENRAGE, 600000); + events.ScheduleEvent(EVENT_SUNBEAM, urand(5000, 15000)); + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_GETTING_BACK_TO_NATURE: + return attunedToNature; + case DATA_KNOCK_ON_WOOD: + return elderCount; + } + + return 0; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ENRAGE: + DoScriptText(SAY_BERSERK, me); + DoCast(me, SPELL_ENRAGE); + break; + case EVENT_SUNBEAM: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_SUNBEAM); + events.ScheduleEvent(EVENT_SUNBEAM, urand(10000, 15000)); + break; + case EVENT_NATURE_BOMB: + { + // On every player + std::list PlayerList; + Trinity::AnyPlayerInObjectRangeCheck checker(me, 50.0f); + Trinity::PlayerListSearcher searcher(me, PlayerList, checker); + me->VisitNearbyWorldObject(50.0f, searcher); + for (std::list::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + (*itr)->CastSpell(*itr, SPELL_SUMMON_NATURE_BOMB, true); + events.ScheduleEvent(EVENT_NATURE_BOMB, urand(10000, 12000)); + break; + } + case EVENT_UNSTABLE_ENERGY: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_FREYA_UNSTABLE_SUNBEAM, true); + events.ScheduleEvent(EVENT_UNSTABLE_ENERGY, urand(15000, 20000)); + break; + case EVENT_WAVE: + SpawnWave(); + if (waveCount < 6) + events.ScheduleEvent(EVENT_WAVE, WAVE_TIME); + else + events.ScheduleEvent(EVENT_NATURE_BOMB, urand(10000, 20000)); + break; + case EVENT_EONAR_GIFT: + DoCast(me, SPELL_SUMMON_EONAR_GIFT); + events.ScheduleEvent(EVENT_EONAR_GIFT, urand(40000, 50000)); + break; + case EVENT_STRENGTHENED_IRON_ROOTS: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_ROOTS_FREYA)) + target->CastSpell(target, SPELL_ROOTS_FREYA, true); // This must be casted by Target self + events.ScheduleEvent(EVENT_STRENGTHENED_IRON_ROOTS, urand(12000, 20000)); + break; + case EVENT_GROUND_TREMOR: + DoCastAOE(SPELL_FREYA_GROUND_TREMOR); + events.ScheduleEvent(EVENT_GROUND_TREMOR, urand(25000, 28000)); + break; + } + } + + if (!me->HasAura(SPELL_TOUCH_OF_EONAR)) + me->CastSpell(me, SPELL_TOUCH_OF_EONAR, true); + + // For achievement check + if (Aura* aura = me->GetAura(SPELL_ATTUNED_TO_NATURE)) + attunedToNature = aura->GetStackAmount(); + else + attunedToNature = 0; + + diffTimer += diff; // For getting time difference for Deforestation achievement + + // Elementals must be killed within 12 seconds of each other, or they will all revive and heal + Creature* Elemental[3][2]; + for (uint8 i = 0; i < 2; ++i) + { + if (checkElementalAlive[i]) + elementalTimer[i] = 0; + else + { + elementalTimer[i] += diff; + for (uint8 k = 0; k < 3; ++k) + Elemental[k][i] = ObjectAccessor::GetCreature(*me, ElementalGUID[k][i]); + if (elementalTimer[i] > 12000) + { + if (!trioDefeated[i]) // Do *NOT* merge this bool with bool few lines below! + { + if (Elemental[0][i] && Elemental[1][i] && Elemental[2][i]) + { + for (uint8 n = 0; n < 3; ++n) + { + if (Elemental[n][i]->isAlive()) + Elemental[n][i]->SetHealth(Elemental[n][i]->GetMaxHealth()); + else + Elemental[n][i]->Respawn(); + } + } + } + checkElementalAlive[i] = true; + } + else + { + if (!trioDefeated[i]) + { + if (Elemental[0][i] && Elemental[1][i] && Elemental[2][i]) + { + if (Elemental[0][i]->isDead() && Elemental[1][i]->isDead() && Elemental[2][i]->isDead()) + { + for (uint8 n = 0; n < 3; ++n) + { + summons.remove(Elemental[n][i]->GetGUID()); + Elemental[n][i]->ForcedDespawn(5000); + trioDefeated[i] = true; + Elemental[n][i]->CastSpell(me, SPELL_REMOVE_10STACK, true); + } + } + } + } + } + } + } + + DoMeleeAttackIfReady(); + } + + // Check if all Trio NPCs are dead - achievement check + void LasherDead(uint32 type) // Type must be in format of a binary mask + { + uint8 n = 0; + + // Handling recieved data + for (uint8 i = 0; i < 5; ++i) // We have created "instances" for keeping informations about last 6 death lashers - needed because of respawning + { + deforestation[i][0] = deforestation[(i + 1)][0]; // Time + deforestation[i][1] = deforestation[(i + 1)][1]; // Type + } + deforestation[5][0] = diffTimer; + deforestation[5][1] = type; + + // Check for achievement completion + if (deforestation[0][1]) // Check for proper functionality of binary masks (overflow would not be problem) + { + for (uint8 i = 0; i < 6; ++i) // Count binary mask + { + n += deforestation[i][1]; + } + if ((deforestation[5][0] - deforestation[0][0]) < 10000) // Time check + { + if (n == 14 && instance) // Binary mask check - verification of lasher types + { + instance->DoCastSpellOnPlayers(SPELL_DEFORESTATION_CREDIT); + } + } + } + } + + // Random order of spawning waves + int GetWaveId() + { + if (random[0] && random[1] && random[2]) + for (uint8 n = 0; n < 3; ++n) + random[n] = false; + + uint8 randomId = urand(0, 2); + + while (random[randomId]) + randomId = urand(0, 2); + + random[randomId] = true; + return randomId; + } + + void SpawnWave() + { + switch (GetWaveId()) + { + case 0: + DoScriptText(SAY_SUMMON_LASHERS, me); + for (uint8 n = 0; n < 10; ++n) + DoCast(SPELL_SUMMON_LASHERS); + break; + case 1: + DoScriptText(SAY_SUMMON_TRIO, me); + DoCast(SPELL_SUMMON_TRIO); + trioWaveCount++; + break; + case 2: + DoScriptText(SAY_SUMMON_CONSERVATOR, me); + DoCast(SPELL_SUMMON_ANCIENT_CONSERVATOR); + break; + } + waveCount++; + } + + void JustDied(Unit* who) + { + //! Freya's chest is dynamically spawned on death by different spells. + const uint32 summonSpell[2][4] = + { + /* 0Elder, 1Elder, 2Elder, 3Elder */ + /* 10N */ {62950, 62953, 62955, 62957}, + /* 25N */ {62952, 62954, 62956, 62958} + }; + + me->CastSpell((Unit*)NULL, summonSpell[me->GetMap()->GetDifficulty()][elderCount], true); + + _JustDied(); + } + + void JustSummoned(Creature* summoned) + { + switch (summoned->GetEntry()) + { + case NPC_SNAPLASHER: + case NPC_ANCIENT_WATER_SPIRIT: + case NPC_STORM_LASHER: + ElementalGUID[trioWaveController][trioWaveCount] = summoned->GetGUID(); + summons.push_back(summoned->GetGUID()); + ++trioWaveController; + if (trioWaveController > 2) + trioWaveController = 0; + break; + case NPC_DETONATING_LASHER: + case NPC_ANCIENT_CONSERVATOR: + default: + summons.push_back(summoned->GetGUID()); + break; + } + + // Need to have it there, or summoned units would do nothing untill attacked + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 250.0f, true)) + { + summoned->AI()->AttackStart(target); + summoned->AddThreat(target, 250.0f); + DoZoneInCombat(summoned); + } + } + + void SummonedCreatureDies(Creature* summoned, Unit* who) + { + switch (summoned->GetEntry()) + { + case NPC_DETONATING_LASHER: + summoned->CastSpell(me, SPELL_REMOVE_2STACK, true); + summoned->CastSpell(who, SPELL_DETONATE, true); + summoned->ForcedDespawn(5000); + summons.remove(summoned->GetGUID()); + break; + case NPC_ANCIENT_CONSERVATOR: + summoned->CastSpell(me, SPELL_REMOVE_25STACK, true); + summoned->ForcedDespawn(5000); + summons.remove(summoned->GetGUID()); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class boss_elder_brightleaf : public CreatureScript +{ + public: + boss_elder_brightleaf() : CreatureScript("boss_elder_brightleaf") { } + + struct boss_elder_brightleafAI : public BossAI + { + boss_elder_brightleafAI(Creature* creature) : BossAI(creature, BOSS_BRIGHTLEAF) + { + } + + void Reset() + { + _Reset(); + if (me->HasAura(SPELL_DRAINED_OF_POWER)) + me->RemoveAurasDueToSpell(SPELL_DRAINED_OF_POWER); + events.ScheduleEvent(EVENT_SOLAR_FLARE, urand(5000, 7000)); + events.ScheduleEvent(EVENT_UNSTABLE_SUN_BEAM, urand(7000, 12000)); + events.ScheduleEvent(EVENT_FLUX, 5000); + elderCount = 0; + lumberjack = false; + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_BRIGHTLEAF_SLAY_1, SAY_BRIGHTLEAF_SLAY_2), me); + } + + void JustDied(Unit* who) + { + _JustDied(); + DoScriptText(SAY_BRIGHTLEAF_DEATH, me); + + if (who && who->GetTypeId() == TYPEID_PLAYER) + { + if (Creature* Ironbranch = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_IRONBRANCH))) + Ironbranch->AI()->DoAction(ACTION_ELDER_DEATH); + + if (Creature* Stonebark = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STONEBARK))) + Stonebark->AI()->DoAction(ACTION_ELDER_DEATH); + } + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + if (!me->HasAura(SPELL_DRAINED_OF_POWER)) + DoScriptText(SAY_BRIGHTLEAF_AGGRO, me); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_UNSTABLE_SUN_BEAM: + me->CastSpell(me, SPELL_UNSTABLE_SUN_BEAM_SUMMON, true); + events.ScheduleEvent(EVENT_UNSTABLE_SUN_BEAM, urand(10000, 15000)); + break; + case EVENT_SOLAR_FLARE: + { + uint8 stackAmount = 0; + if (me->GetAura(SPELL_FLUX_AURA)) + stackAmount = me->GetAura(SPELL_FLUX_AURA)->GetStackAmount(); + me->CastCustomSpell(SPELL_SOLAR_FLARE, SPELLVALUE_MAX_TARGETS, stackAmount, me, false); + events.ScheduleEvent(EVENT_SOLAR_FLARE, urand(5000, 10000)); + break; + } + case EVENT_FLUX: + me->RemoveAurasDueToSpell(SPELL_FLUX_AURA); + me->AddAura(SPELL_FLUX_AURA, me); + if (Aura* Flux = me->GetAura(SPELL_FLUX_AURA)) + Flux->SetStackAmount(urand(1, 8)); + events.ScheduleEvent(EVENT_FLUX, 7500); + break; + } + } + + if (lumberjack) + lumberjackTimer += diff; + + DoMeleeAttackIfReady(); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_ELDER_DEATH: + ++elderCount; + lumberjack = true; + break; + case ACTION_ELDER_FREYA_KILLED: + me->DespawnOrUnsummon(10000); + _JustDied(); + break; + } + } + + private: + uint32 lumberjackTimer; + uint8 elderCount; + bool lumberjack; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class boss_elder_stonebark : public CreatureScript +{ + public: + boss_elder_stonebark() : CreatureScript("boss_elder_stonebark") { } + + struct boss_elder_stonebarkAI : public BossAI + { + boss_elder_stonebarkAI(Creature* creature) : BossAI(creature, BOSS_STONEBARK) + { + } + + void Reset() + { + _Reset(); + if (me->HasAura(SPELL_DRAINED_OF_POWER)) + me->RemoveAurasDueToSpell(SPELL_DRAINED_OF_POWER); + events.ScheduleEvent(EVENT_TREMOR, urand(10000, 12000)); + events.ScheduleEvent(EVENT_FISTS, urand(25000, 35000)); + events.ScheduleEvent(EVENT_BARK, urand(37500, 40000)); + elderCount = 0; + lumberjack = false; + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_STONEBARK_SLAY_1, SAY_STONEBARK_SLAY_2), me); + } + + void JustDied(Unit* who) + { + _JustDied(); + DoScriptText(SAY_STONEBARK_DEATH, me); + + if (who && who->GetTypeId() == TYPEID_PLAYER) + { + if (Creature* Ironbranch = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_IRONBRANCH))) + Ironbranch->AI()->DoAction(ACTION_ELDER_DEATH); + + if (Creature* Brightleaf = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF))) + Brightleaf->AI()->DoAction(ACTION_ELDER_DEATH); + } + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + if (!me->HasAura(SPELL_DRAINED_OF_POWER)) + DoScriptText(SAY_STONEBARK_AGGRO, me); + } + + void DamageTaken(Unit* who, uint32& damage) + { + if (who == me) + return; + + if (me->HasAura(SPELL_PETRIFIED_BARK)) + { + int32 reflect = damage; + who->CastCustomSpell(who, SPELL_PETRIFIED_BARK_DMG, &reflect, NULL, NULL, true); + damage = 0; + } + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BARK: + DoCast(me, SPELL_PETRIFIED_BARK); + events.ScheduleEvent(EVENT_BARK, urand(30000, 50000)); + break; + case EVENT_FISTS: + DoCastVictim(SPELL_FISTS_OF_STONE); + events.ScheduleEvent(EVENT_FISTS, urand(20000, 30000)); + break; + case EVENT_TREMOR: + if (!me->HasAura(SPELL_FISTS_OF_STONE)) + DoCastVictim(SPELL_GROUND_TREMOR); + events.ScheduleEvent(EVENT_TREMOR, urand(10000, 20000)); + break; + } + } + + if (lumberjack) + lumberjackTimer += diff; + + DoMeleeAttackIfReady(); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_ELDER_DEATH: + ++elderCount; + lumberjack = true; + break; + case ACTION_ELDER_FREYA_KILLED: + me->DespawnOrUnsummon(10000); + _JustDied(); + break; + } + } + + private: + uint32 lumberjackTimer; + uint8 elderCount; + bool lumberjack; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class boss_elder_ironbranch : public CreatureScript +{ + public: + boss_elder_ironbranch() : CreatureScript("boss_elder_ironbranch") { } + + struct boss_elder_ironbranchAI : public BossAI + { + boss_elder_ironbranchAI(Creature* creature) : BossAI(creature, BOSS_IRONBRANCH) + { + } + + void Reset() + { + _Reset(); + if (me->HasAura(SPELL_DRAINED_OF_POWER)) + me->RemoveAurasDueToSpell(SPELL_DRAINED_OF_POWER); + events.ScheduleEvent(EVENT_IMPALE, urand(18000, 22000)); + events.ScheduleEvent(EVENT_IRON_ROOTS, urand(12000, 17000)); + events.ScheduleEvent(EVENT_THORN_SWARM, urand(7500, 12500)); + elderCount = 0; + lumberjack = false; + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_IRONBRANCH_SLAY_1, SAY_IRONBRANCH_SLAY_2), me); + } + + void JustDied(Unit* who) + { + _JustDied(); + DoScriptText(SAY_IRONBRANCH_DEATH, me); + + if (who && who->GetTypeId() == TYPEID_PLAYER) + { + if (Creature* Brightleaf = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF))) + Brightleaf->AI()->DoAction(ACTION_ELDER_DEATH); + + if (Creature* Stonebark = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STONEBARK))) + Stonebark->AI()->DoAction(ACTION_ELDER_DEATH); + } + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + if (!me->HasAura(SPELL_DRAINED_OF_POWER)) + DoScriptText(SAY_IRONBRANCH_AGGRO, me); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_IMPALE: + DoCastVictim(SPELL_IMPALE); + events.ScheduleEvent(EVENT_IMPALE, urand(15000, 25000)); + break; + case EVENT_IRON_ROOTS: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_ROOTS_IRONBRANCH)) + target->CastSpell(target, SPELL_ROOTS_IRONBRANCH, true); + events.ScheduleEvent(EVENT_IRON_ROOTS, urand(10000, 20000)); + break; + case EVENT_THORN_SWARM: + DoCastVictim(SPELL_THORN_SWARM); + events.ScheduleEvent(EVENT_THORN_SWARM, urand(8000, 13000)); + break; + } + } + + if (lumberjack) + lumberjackTimer += diff; + + DoMeleeAttackIfReady(); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_ELDER_DEATH: + ++elderCount; + lumberjack = true; + break; + case ACTION_ELDER_FREYA_KILLED: + me->DespawnOrUnsummon(10000); + _JustDied(); + break; + } + } + + private: + uint32 lumberjackTimer; + uint8 elderCount; + bool lumberjack; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class npc_detonating_lasher : public CreatureScript +{ + public: + npc_detonating_lasher() : CreatureScript("npc_detonating_lasher") { } + + struct npc_detonating_lasherAI : public ScriptedAI + { + npc_detonating_lasherAI(Creature* creature) : ScriptedAI(creature) + { + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + } + + void Reset() + { + lashTimer = 5000; + changeTargetTimer = 7500; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (lashTimer <= diff) + { + DoCast(SPELL_FLAME_LASH); + lashTimer = urand(5000, 10000); + } + else + lashTimer -= diff; + + if (changeTargetTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + { + // Switching to other target - modify aggro of new target by 20% from current target's aggro + me->AddThreat(target, me->getThreatManager().getThreat(me->getVictim(), false) * 1.2f); + me->AI()->AttackStart(target); + } + changeTargetTimer = urand(5000, 10000); + } + else + changeTargetTimer -= diff; + + DoMeleeAttackIfReady(); + } + + private: + uint32 lashTimer; + uint32 changeTargetTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_detonating_lasherAI(creature); + } +}; + +class npc_ancient_water_spirit : public CreatureScript +{ + public: + npc_ancient_water_spirit() : CreatureScript("npc_ancient_water_spirit") { } + + struct npc_ancient_water_spiritAI : public ScriptedAI + { + npc_ancient_water_spiritAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) + waveCount = CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; + } + + void Reset() + { + tidalWaveTimer = 10000; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (tidalWaveTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + { + DoCast(target, SPELL_TIDAL_WAVE); + DoCast(target, SPELL_TIDAL_WAVE_EFFECT, true); + } + tidalWaveTimer = urand(12000, 25000); + } + else + tidalWaveTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) + { + CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; + CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(1); + } + } + + private: + InstanceScript* instance; + uint32 tidalWaveTimer; + uint8 waveCount; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_ancient_water_spiritAI(creature); + } +}; + +class npc_storm_lasher : public CreatureScript +{ + public: + npc_storm_lasher() : CreatureScript("npc_storm_lasher") { } + + struct npc_storm_lasherAI : public ScriptedAI + { + npc_storm_lasherAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) + waveCount = CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; + } + + void Reset() + { + lightningLashTimer = 10000; + stormboltTimer = 5000; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (lightningLashTimer <= diff) + { + DoCast(SPELL_LIGHTNING_LASH); + lightningLashTimer = urand(7000, 14000); + } + else + lightningLashTimer -= diff; + + if (stormboltTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_STORMBOLT); + stormboltTimer = urand(8000, 12000); + } + else + stormboltTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) + { + CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; + CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(2); + } + } + + private: + InstanceScript* instance; + uint32 lightningLashTimer; + uint32 stormboltTimer; + uint8 waveCount; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_storm_lasherAI(creature); + } +}; + +class npc_snaplasher : public CreatureScript +{ + public: + npc_snaplasher() : CreatureScript("npc_snaplasher") { } + + struct npc_snaplasherAI : public ScriptedAI + { + npc_snaplasherAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) + waveCount = CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; + } + + void UpdateAI(uint32 const /*diff*/) + { + if (!UpdateVictim()) + return; + + if (!me->HasAura(SPELL_BARK_AURA)) + DoCast(SPELL_HARDENED_BARK); + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) + { + CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; + CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(4); + } + } + + private: + InstanceScript* instance; + uint8 waveCount; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_snaplasherAI(creature); + } +}; + +class npc_ancient_conservator : public CreatureScript +{ + public: + npc_ancient_conservator() : CreatureScript("npc_ancient_conservator") { } + + struct npc_ancient_conservatorAI : public ScriptedAI + { + npc_ancient_conservatorAI(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() + { + natureFuryTimer = 7500; + healthySporeTimer = 3500; + SummonHealthySpores(2); + } + + void SummonHealthySpores(uint8 sporesCount) + { + for (uint8 n = 0; n < sporesCount; ++n) + { + DoCast(SPELL_SUMMON_PERIODIC); + DoCast(SPELL_SPORE_SUMMON_NE); + DoCast(SPELL_SPORE_SUMMON_SE); + DoCast(SPELL_SPORE_SUMMON_SW); + } + } + + void EnterCombat(Unit* who) + { + DoCast(who, SPELL_CONSERVATOR_GRIP, true); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + if (healthySporeTimer <= diff) + { + SummonHealthySpores(1); + healthySporeTimer = urand(15000, 17500); + } + else + healthySporeTimer -= diff; + + if (natureFuryTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_NATURE_FURY)) + DoCast(target, SPELL_NATURE_FURY); + me->AddAura(SPELL_CONSERVATOR_GRIP, me); + natureFuryTimer = 5000; + } + else + natureFuryTimer -= diff; + + DoMeleeAttackIfReady(); + } + + private: + uint32 natureFuryTimer; + uint32 healthySporeTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_ancient_conservatorAI(creature); + } +}; + +class npc_sun_beam : public CreatureScript +{ + public: + npc_sun_beam() : CreatureScript("npc_sun_beam") { } + + struct npc_sun_beamAI : public Scripted_NoMovementAI + { + npc_sun_beamAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + me->SetReactState(REACT_PASSIVE); + DoCastAOE(SPELL_FREYA_UNSTABLE_ENERGY_VISUAL, true); + DoCast(SPELL_FREYA_UNSTABLE_ENERGY); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_sun_beamAI(creature); + } +}; + +class npc_healthy_spore : public CreatureScript +{ + public: + npc_healthy_spore() : CreatureScript("npc_healthy_spore") { } + + struct npc_healthy_sporeAI : public Scripted_NoMovementAI + { + npc_healthy_sporeAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + DoCast(me, SPELL_HEALTHY_SPORE_VISUAL); + DoCast(me, SPELL_POTENT_PHEROMONES); + DoCast(me, SPELL_GROW); + lifeTimer = urand(22000, 30000); + } + + void UpdateAI(uint32 const diff) + { + if (lifeTimer <= diff) + { + me->RemoveAurasDueToSpell(SPELL_GROW); + me->ForcedDespawn(2200); + lifeTimer = urand(22000, 30000); + } + else + lifeTimer -= diff; + } + + private: + uint32 lifeTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_healthy_sporeAI(creature); + } +}; + +class npc_eonars_gift : public CreatureScript +{ + public: + npc_eonars_gift() : CreatureScript("npc_eonars_gift") { } + + struct npc_eonars_giftAI : public Scripted_NoMovementAI + { + npc_eonars_giftAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + lifeBindersGiftTimer = 12000; + DoCast(me, SPELL_GROW); + DoCast(me, SPELL_PHEROMONES, true); + DoCast(me, SPELL_EONAR_VISUAL, true); + } + + void UpdateAI(uint32 const diff) + { + if (lifeBindersGiftTimer <= diff) + { + me->RemoveAurasDueToSpell(SPELL_GROW); + DoCast(SPELL_LIFEBINDERS_GIFT); + me->ForcedDespawn(2500); + lifeBindersGiftTimer = 12000; + } + else + lifeBindersGiftTimer -= diff; + } + + private: + uint32 lifeBindersGiftTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_eonars_giftAI(creature); + } +}; + +class npc_nature_bomb : public CreatureScript +{ + public: + npc_nature_bomb() : CreatureScript("npc_nature_bomb") { } + + struct npc_nature_bombAI : public Scripted_NoMovementAI + { + npc_nature_bombAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + bombTimer = urand(8000, 10000); + DoCast(SPELL_OBJECT_BOMB); + } + + void UpdateAI(uint32 const diff) + { + if (bombTimer <= diff) + { + if (GameObject* go = me->FindNearestGameObject(OBJECT_NATURE_BOMB, 1.0f)) + { + DoCast(me, SPELL_NATURE_BOMB); + me->RemoveGameObject(go, true); + me->RemoveFromWorld(); + } + + bombTimer = 10000; + } + else + bombTimer -= diff; + } + + private: + uint32 bombTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_nature_bombAI(creature); + } +}; + +class npc_unstable_sun_beam : public CreatureScript +{ + public: + npc_unstable_sun_beam() : CreatureScript("npc_unstable_sun_beam") { } + + struct npc_unstable_sun_beamAI : public Scripted_NoMovementAI + { + npc_unstable_sun_beamAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + despawnTimer = urand(7000, 12000); + instance = me->GetInstanceScript(); + DoCast(me, SPELL_PHOTOSYNTHESIS); + DoCast(me, SPELL_UNSTABLE_SUN_BEAM); + me->SetReactState(REACT_PASSIVE); + } + + void UpdateAI(uint32 const diff) + { + if (despawnTimer <= diff) + { + DoCastAOE(SPELL_UNSTABLE_ENERGY, true); + me->DisappearAndDie(); + } + else + despawnTimer -= diff; + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) + { + if (target && spell->Id == SPELL_UNSTABLE_ENERGY) + { + target->RemoveAurasDueToSpell(SPELL_UNSTABLE_SUN_BEAM); + target->RemoveAurasDueToSpell(SPELL_UNSTABLE_SUN_BEAM_TRIGGERED); + } + } + + private: + InstanceScript* instance; + uint32 despawnTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_unstable_sun_beamAI(creature); + } +}; + +class spell_freya_attuned_to_nature_dose_reduction : public SpellScriptLoader +{ + public: + spell_freya_attuned_to_nature_dose_reduction() : SpellScriptLoader("spell_freya_attuned_to_nature_dose_reduction") + { + } + + class spell_freya_attuned_to_nature_dose_reduction_SpellScript : public SpellScript + { + PrepareSpellScript(spell_freya_attuned_to_nature_dose_reduction_SpellScript) + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + SpellInfo const* spellInfo = GetSpellInfo(); + switch (spellInfo->Id) + { + case SPELL_ATTUNED_TO_NATURE_2_DOSE_REDUCTION: + if (target->HasAura(GetEffectValue())) + for (uint8 n = 0; n < 2; ++n) + target->RemoveAuraFromStack(GetEffectValue(), 0, AURA_REMOVE_BY_DEFAULT); + break; + case SPELL_ATTUNED_TO_NATURE_10_DOSE_REDUCTION: + if (target->HasAura(GetEffectValue())) + for (uint8 n = 0; n < 10; ++n) + target->RemoveAuraFromStack(GetEffectValue(), 0, AURA_REMOVE_BY_DEFAULT); + break; + case SPELL_ATTUNED_TO_NATURE_25_DOSE_REDUCTION: + if (target->HasAura(GetEffectValue())) + for (uint8 n = 0; n < 25; ++n) + target->RemoveAuraFromStack(GetEffectValue(), 0, AURA_REMOVE_BY_DEFAULT); + break; + default: + break; + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_freya_attuned_to_nature_dose_reduction_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_freya_attuned_to_nature_dose_reduction_SpellScript(); + } +}; + +class spell_freya_iron_roots : public SpellScriptLoader +{ + public: + spell_freya_iron_roots() : SpellScriptLoader("spell_freya_iron_roots") + { + } + + class spell_freya_iron_roots_SpellScript : public SpellScript + { + PrepareSpellScript(spell_freya_iron_roots_SpellScript); + + void HandleSummon(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue); + + Position pos; + GetCaster()->GetPosition(&pos); + // Not good at all, but this prevents having roots in a different position then player + if (Creature* Roots = GetCaster()->SummonCreature(entry, pos)) + GetCaster()->NearTeleportTo(Roots->GetPositionX(), Roots->GetPositionY(), Roots->GetPositionZ(), GetCaster()->GetOrientation()); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_freya_iron_roots_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_freya_iron_roots_SpellScript(); + } +}; + +class achievement_getting_back_to_nature : public AchievementCriteriaScript +{ + public: + achievement_getting_back_to_nature() : AchievementCriteriaScript("achievement_getting_back_to_nature") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Freya = target->ToCreature()) + if (Freya->AI()->GetData(DATA_GETTING_BACK_TO_NATURE) >= 25) + return true; + + return false; + } +}; + +class achievement_knock_on_wood : public AchievementCriteriaScript +{ + public: + achievement_knock_on_wood() : AchievementCriteriaScript("achievement_knock_on_wood") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Freya = target->ToCreature()) + if (Freya->AI()->GetData(DATA_KNOCK_ON_WOOD) >= 1) + return true; + + return false; + } +}; + +class achievement_knock_knock_on_wood : public AchievementCriteriaScript +{ + public: + achievement_knock_knock_on_wood() : AchievementCriteriaScript("achievement_knock_knock_on_wood") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Freya = target->ToCreature()) + if (Freya->AI()->GetData(DATA_KNOCK_ON_WOOD) >= 2) + return true; + + return false; + } +}; + +class achievement_knock_knock_knock_on_wood : public AchievementCriteriaScript +{ + public: + achievement_knock_knock_knock_on_wood() : AchievementCriteriaScript("achievement_knock_knock_knock_on_wood") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Freya = target->ToCreature()) + if (Freya->AI()->GetData(DATA_KNOCK_ON_WOOD) == 3) + return true; + + return false; + } +}; + +void AddSC_boss_freya() +{ + new boss_freya(); + new boss_elder_brightleaf(); + new boss_elder_ironbranch(); + new boss_elder_stonebark(); + new npc_ancient_conservator(); + new npc_snaplasher(); + new npc_storm_lasher(); + new npc_ancient_water_spirit(); + new npc_detonating_lasher(); + new npc_sun_beam(); + new npc_nature_bomb(); + new npc_eonars_gift(); + new npc_healthy_spore(); + new npc_unstable_sun_beam(); + new npc_iron_roots(); + new spell_freya_attuned_to_nature_dose_reduction(); + new spell_freya_iron_roots(); + new achievement_getting_back_to_nature(); + new achievement_knock_on_wood(); + new achievement_knock_knock_on_wood(); + new achievement_knock_knock_knock_on_wood(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp new file mode 100644 index 00000000000..7d00c0e59fc --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -0,0 +1,514 @@ +/* + * Copyright (C) 2008-2011 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 "SpellScript.h" +#include "SpellAuraEffects.h" +#include "ulduar.h" + +enum VezaxYells +{ + SAY_AGGRO = -1603290, + SAY_SLAY_1 = -1603291, + SAY_SLAY_2 = -1603292, + SAY_SURGE_OF_DARKNESS = -1603293, + SAY_DEATH = -1603294, + SAY_BERSERK = -1603295, + SAY_HARDMODE = -1603296, +}; + +enum VezaxEmotes +{ + EMOTE_VAPORS = -1603289, + EMOTE_ANIMUS = -1603297, + EMOTE_BARRIER = -1603298, + EMOTE_SURGE_OF_DARKNESS = -1603299, +}; + +enum VezaxSpells +{ + SPELL_AURA_OF_DESPAIR = 62692, + SPELL_MARK_OF_THE_FACELESS = 63276, + SPELL_MARK_OF_THE_FACELESS_DAMAGE = 63278, + SPELL_SARONITE_BARRIER = 63364, + SPELL_SEARING_FLAMES = 62661, + SPELL_SHADOW_CRASH = 62660, + SPELL_SHADOW_CRASH_HIT = 62659, + SPELL_SURGE_OF_DARKNESS = 62662, + SPELL_SARONITE_VAPORS = 63323, + SPELL_SUMMON_SARONITE_VAPORS = 63081, + SPELL_BERSERK = 26662, + + SPELL_SUMMON_SARONITE_ANIMUS = 63145, + SPELL_VISUAL_SARONITE_ANIMUS = 63319, + SPELL_PROFOUND_OF_DARKNESS = 63420, + + SPELL_CORRUPTED_RAGE = 68415, + SPELL_SHAMANTIC_RAGE = 30823, +}; + +enum VezaxActions +{ + ACTION_VAPORS_SPAWN, + ACTION_VAPORS_DIE, + ACTION_ANIMUS_DIE, +}; + +enum VezaxEvents +{ + // Vezax + EVENT_SHADOW_CRASH = 1, + EVENT_SEARING_FLAMES = 2, + EVENT_SURGE_OF_DARKNESS = 3, + EVENT_MARK_OF_THE_FACELESS = 4, + EVENT_SARONITE_VAPORS = 5, + EVENT_BERSERK = 6, + + // Saronite Animus + EVENT_PROFOUND_OF_DARKNESS = 7, + + // Saronite Vapor + EVENT_RANDOM_MOVE = 8, +}; + +#define DATA_SMELL_SARONITE 31813188 +#define DATA_SHADOWDODGER 29962997 + +class boss_general_vezax : public CreatureScript +{ + public: + boss_general_vezax() : CreatureScript("boss_general_vezax") { } + + struct boss_general_vezaxAI : public BossAI + { + boss_general_vezaxAI(Creature* creature) : BossAI(creature, BOSS_VEZAX) + { + } + + bool shadowDodger; + bool smellSaronite; // HardMode + bool animusDead; // Check against getting a HardMode achievement before killing Saronite Animus + uint8 vaporCount; + + void Reset() + { + _Reset(); + + shadowDodger = true; + smellSaronite = true; + animusDead = false; + vaporCount = 0; + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + + DoScriptText(SAY_AGGRO, me); + DoCast(me, SPELL_AURA_OF_DESPAIR); + CheckShamanisticRage(); + + events.ScheduleEvent(EVENT_SHADOW_CRASH, urand(8000, 10000)); + events.ScheduleEvent(EVENT_SEARING_FLAMES, 12000); + events.ScheduleEvent(EVENT_MARK_OF_THE_FACELESS, urand(35000, 40000)); + events.ScheduleEvent(EVENT_SARONITE_VAPORS, 30000); + events.ScheduleEvent(EVENT_SURGE_OF_DARKNESS, 60000); + events.ScheduleEvent(EVENT_BERSERK, 600000); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHADOW_CRASH: + { + Unit* target = CheckPlayersInRange(RAID_MODE(4, 9), 15.0f, 50.0f); + if (!target) + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true); + if (target) + DoCast(target, SPELL_SHADOW_CRASH); + events.ScheduleEvent(EVENT_SHADOW_CRASH, urand(8000, 12000)); + break; + } + case EVENT_SEARING_FLAMES: + DoCastAOE(SPELL_SEARING_FLAMES); + events.ScheduleEvent(EVENT_SEARING_FLAMES, urand(14000, 17500)); + break; + case EVENT_MARK_OF_THE_FACELESS: + { + Unit* target = CheckPlayersInRange(RAID_MODE(4, 9), 15.0f, 50.0f); + if (!target) + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true); + if (target) + DoCast(target, SPELL_MARK_OF_THE_FACELESS); + events.ScheduleEvent(EVENT_MARK_OF_THE_FACELESS, urand(35000, 45000)); + break; + } + case EVENT_SURGE_OF_DARKNESS: + DoScriptText(EMOTE_SURGE_OF_DARKNESS, me); + DoScriptText(SAY_SURGE_OF_DARKNESS, me); + DoCast(me, SPELL_SURGE_OF_DARKNESS); + events.ScheduleEvent(EVENT_SURGE_OF_DARKNESS, urand(50000, 70000)); + break; + case EVENT_SARONITE_VAPORS: + DoCast(SPELL_SUMMON_SARONITE_VAPORS); + events.ScheduleEvent(EVENT_SARONITE_VAPORS, urand(30000, 35000)); + if (++vaporCount == 6 && smellSaronite) + { + DoScriptText(SAY_HARDMODE, me); + DoScriptText(EMOTE_BARRIER, me); + summons.DespawnAll(); + DoCast(me, SPELL_SARONITE_BARRIER); + DoCast(SPELL_SUMMON_SARONITE_ANIMUS); + me->AddLootMode(LOOT_MODE_HARD_MODE_1); + events.CancelEvent(EVENT_SARONITE_VAPORS); + events.CancelEvent(EVENT_SEARING_FLAMES); + } + break; + case EVENT_BERSERK: + DoScriptText(SAY_BERSERK, me); + DoCast(me, SPELL_BERSERK); + break; + } + } + + DoMeleeAttackIfReady(); + } + + void SpellHitTarget(Unit* who, SpellInfo const* spell) + { + if (who && who->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_SHADOW_CRASH_HIT) + shadowDodger = false; + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void JustDied(Unit* /*who*/) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_AURA_OF_DESPAIR); + } + + void CheckShamanisticRage() + { + Map* map = me->GetMap(); + if (map && map->IsDungeon()) + { + // If Shaman has Shamanistic Rage and use it during the fight, it will cast Corrupted Rage on him + Map::PlayerList const& Players = map->GetPlayers(); + for (Map::PlayerList::const_iterator itr = Players.begin(); itr != Players.end(); ++itr) + if (Player* player = itr->getSource()) + if (player->HasSpell(SPELL_SHAMANTIC_RAGE)) + player->CastSpell(player, SPELL_CORRUPTED_RAGE, false); + } + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_SHADOWDODGER: + return shadowDodger ? 1 : 0; + case DATA_SMELL_SARONITE: + return smellSaronite ? 1 : 0; + } + + return 0; + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_VAPORS_DIE: + smellSaronite = false; + break; + case ACTION_ANIMUS_DIE: + me->RemoveAurasDueToSpell(SPELL_SARONITE_BARRIER); + events.ScheduleEvent(EVENT_SEARING_FLAMES, urand(7000, 12000)); + animusDead = true; + break; + } + } + + /* Player Range Check + Purpose: If there are playersMin people within rangeMin, rangeMax: return a random players in that range. + If not, return NULL and allow other target selection + */ + Unit* CheckPlayersInRange(uint8 playersMin, float rangeMin, float rangeMax) + { + Map* map = me->GetMap(); + if (map && map->IsDungeon()) + { + std::list PlayerList; + Map::PlayerList const& Players = map->GetPlayers(); + for (Map::PlayerList::const_iterator itr = Players.begin(); itr != Players.end(); ++itr) + { + if (Player* player = itr->getSource()) + { + float distance = player->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); + if (rangeMin > distance || distance > rangeMax) + continue; + + PlayerList.push_back(player); + } + } + + if (PlayerList.empty()) + return NULL; + + size_t size = PlayerList.size(); + if (size < playersMin) + return NULL; + + return SelectRandomContainerElement(PlayerList); + } + + return NULL; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class boss_saronite_animus : public CreatureScript +{ + public: + boss_saronite_animus() : CreatureScript("npc_saronite_animus") { } + + struct boss_saronite_animusAI : public ScriptedAI + { + boss_saronite_animusAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + DoScriptText(EMOTE_BARRIER, me); + } + + void Reset() + { + DoCast(me, SPELL_VISUAL_SARONITE_ANIMUS); + events.Reset(); + events.ScheduleEvent(EVENT_PROFOUND_OF_DARKNESS, 3000); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Vezax = me->GetCreature(*me, instance->GetData64(BOSS_VEZAX))) + Vezax->AI()->DoAction(ACTION_ANIMUS_DIE); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_PROFOUND_OF_DARKNESS: + DoCastAOE(SPELL_PROFOUND_OF_DARKNESS, true); + events.ScheduleEvent(EVENT_PROFOUND_OF_DARKNESS, 3000); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_saronite_animusAI(creature); + } +}; + +class npc_saronite_vapors : public CreatureScript +{ + public: + npc_saronite_vapors() : CreatureScript("npc_saronite_vapors") { } + + struct npc_saronite_vaporsAI : public ScriptedAI + { + npc_saronite_vaporsAI(Creature* creature) : ScriptedAI(creature) + { + DoScriptText(EMOTE_VAPORS, me); + instance = me->GetInstanceScript(); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); + me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip jump effect + me->SetReactState(REACT_PASSIVE); + } + + void Reset() + { + events.Reset(); + events.ScheduleEvent(EVENT_RANDOM_MOVE, urand(5000, 7500)); + } + + void UpdateAI(uint32 const diff) + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RANDOM_MOVE: + me->GetMotionMaster()->MoveRandom(30.0f); + events.ScheduleEvent(EVENT_RANDOM_MOVE, urand(5000, 7500)); + break; + default: + break; + } + } + } + + void DamageTaken(Unit* /*who*/, uint32& damage) + { + // This can't be on JustDied. In 63322 dummy handler caster needs to be this NPC + // if caster == target then damage mods will increase the damage taken + if (damage >= me->GetHealth()) + { + damage = 0; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE); + me->SetStandState(UNIT_STAND_STATE_DEAD); + me->SetHealth(me->GetMaxHealth()); + me->RemoveAllAuras(); + DoCast(me, SPELL_SARONITE_VAPORS); + me->DespawnOrUnsummon(30000); + + if (Creature* Vezax = me->GetCreature(*me, instance->GetData64(BOSS_VEZAX))) + Vezax->AI()->DoAction(ACTION_VAPORS_DIE); + } + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_saronite_vaporsAI(creature); + } +}; + +class spell_mark_of_the_faceless : public SpellScriptLoader +{ + public: + spell_mark_of_the_faceless() : SpellScriptLoader("spell_mark_of_the_faceless") { } + + class spell_mark_of_the_faceless_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mark_of_the_faceless_AuraScript); + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + if (Unit* caster = GetCaster()) + caster->CastCustomSpell(SPELL_MARK_OF_THE_FACELESS_DAMAGE, SPELLVALUE_BASE_POINT1, aurEff->GetAmount(), GetTarget(), true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_the_faceless_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_mark_of_the_faceless_AuraScript(); + } +}; + +class achievement_shadowdodger : public AchievementCriteriaScript +{ + public: + achievement_shadowdodger() : AchievementCriteriaScript("achievement_shadowdodger") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Vezax = target->ToCreature()) + if (Vezax->AI()->GetData(DATA_SHADOWDODGER)) + return true; + + return false; + } +}; + +class achievement_smell_saronite : public AchievementCriteriaScript +{ + public: + achievement_smell_saronite() : AchievementCriteriaScript("achievement_smell_saronite") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* Vezax = target->ToCreature()) + if (Vezax->AI()->GetData(DATA_SMELL_SARONITE)) + return true; + + return false; + } +}; + +void AddSC_boss_general_vezax() +{ + new boss_general_vezax(); + new boss_saronite_animus(); + new npc_saronite_vapors(); + new spell_mark_of_the_faceless(); + new achievement_shadowdodger(); + new achievement_smell_saronite(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp new file mode 100644 index 00000000000..bb21da94bc5 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -0,0 +1,1013 @@ +/* + * Copyright (C) 2008-2011 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 "SpellScript.h" +#include "SpellAuraEffects.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "ulduar.h" + +/* #TODO: Achievements + Storm Cloud (Shaman ability) + Destroying of Toasty Fires +*/ + +enum HodirYells +{ + SAY_AGGRO = -1603210, + SAY_SLAY_1 = -1603211, + SAY_SLAY_2 = -1603212, + SAY_FLASH_FREEZE = -1603213, + SAY_STALACTITE = -1603214, + SAY_DEATH = -1603215, + SAY_BERSERK = -1603216, + SAY_YS_HELP = -1603217, + SAY_HARD_MODE_FAILED = -1603218, + + EMOTE_FREEZE = -1603209, + EMOTE_BLOWS = -1603219, +}; + +enum HodirSpells +{ + // Hodir + SPELL_FROZEN_BLOWS = 62478, + SPELL_FLASH_FREEZE = 61968, + SPELL_FLASH_FREEZE_VISUAL = 62148, + SPELL_BITING_COLD = 62038, + SPELL_BITING_COLD_TRIGGERED = 62039, // Needed for Achievement Getting Cold In Here + SPELL_BITING_COLD_DAMAGE = 62188, + SPELL_FREEZE = 62469, + SPELL_ICICLE = 62234, + SPELL_ICICLE_SNOWDRIFT = 62462, + SPELL_BLOCK_OF_ICE = 61969, // Player + Helper + SPELL_SUMMON_FLASH_FREEZE_HELPER = 61989, // Helper + SPELL_SUMMON_BLOCK_OF_ICE = 61970, // Player + Helper + SPELL_FLASH_FREEZE_HELPER = 61990, // Helper + SPELL_FLASH_FREEZE_KILL = 62226, + SPELL_ICICLE_FALL = 69428, + SPELL_FALL_DAMAGE = 62236, + SPELL_FALL_SNOWDRIFT = 62460, + SPELL_BERSERK = 47008, + SPELL_ICE_SHARD = 62457, + SPELL_ICE_SHARD_HIT = 65370, + + // Druids + SPELL_WRATH = 62793, + SPELL_STARLIGHT = 62807, + + // Shamans + SPELL_LAVA_BURST = 61924, + SPELL_STORM_CLOUD = 65123, + + // Mages + SPELL_FIREBALL = 61909, + SPELL_CONJURE_FIRE = 62823, + SPELL_MELT_ICE = 64528, + SPELL_SINGED = 62821, + + // Priests + SPELL_SMITE = 61923, + SPELL_GREATER_HEAL = 62809, + SPELL_DISPEL_MAGIC = 63499, +}; + +enum HodirNPC +{ + NPC_ICE_BLOCK = 32938, + NPC_FLASH_FREEZE = 32926, + NPC_SNOWPACKED_ICICLE = 33174, + NPC_ICICLE = 33169, + NPC_ICICLE_SNOWDRIFT = 33173, + NPC_TOASTY_FIRE = 33342, +}; + +enum HodirGameObjects +{ + GO_TOASTY_FIRE = 194300, + GO_SNOWDRIFT = 194173, +}; + +enum HodirEvents +{ + // Hodir + EVENT_FREEZE = 1, + EVENT_FLASH_FREEZE = 2, + EVENT_FLASH_FREEZE_EFFECT = 3, + EVENT_ICICLE = 4, + EVENT_BLOWS = 5, + EVENT_RARE_CACHE = 6, + EVENT_BERSERK = 7, + + // Priest + EVENT_HEAL = 8, + EVENT_DISPEL_MAGIC = 9, + + // Shaman + EVENT_STORM_CLOUD = 10, + + // Druid + EVENT_STARLIGHT = 11, + + // Mage + EVENT_CONJURE_FIRE = 12, + EVENT_MELT_ICE = 13, +}; + +enum HodirActions +{ + ACTION_I_HAVE_THE_COOLEST_FRIENDS = 1, + ACTION_CHEESE_THE_FREEZE = 2, +}; + +#define ACHIEVEMENT_CHEESE_THE_FREEZE RAID_MODE(2961, 2962) +#define ACHIEVEMENT_GETTING_COLD_IN_HERE RAID_MODE(2967, 2968) +#define ACHIEVEMENT_THIS_CACHE_WAS_RARE RAID_MODE(3182, 3184) +#define ACHIEVEMENT_COOLEST_FRIENDS RAID_MODE(2963, 2965) +#define FRIENDS_COUNT RAID_MODE(4, 8) +#define DATA_GETTING_COLD_IN_HERE 29672968 // 2967, 2968 are achievement IDs + +Position const SummonPositions[8] = +{ + { 1983.75f, -243.36f, 432.767f, 1.57f }, // Field Medic Penny && Battle-Priest Eliza + { 1999.90f, -230.49f, 432.767f, 1.57f }, // Eivi Nightfeather && Tor Greycloud + { 2010.06f, -243.45f, 432.767f, 1.57f }, // Elementalist Mahfuun && Spiritwalker Tara + { 2021.12f, -236.65f, 432.767f, 1.57f }, // Missy Flamecuffs && Amira Blazeweaver + { 2028.10f, -244.66f, 432.767f, 1.57f }, // Field Medic Jessi && Battle-Priest Gina + { 2014.18f, -232.80f, 432.767f, 1.57f }, // Ellie Nightfeather && Kar Greycloud + { 1992.90f, -237.54f, 432.767f, 1.57f }, // Elementalist Avuun && Spiritwalker Yona + { 1976.60f, -233.53f, 432.767f, 1.57f }, // Sissy Flamecuffs && Veesha Blazeweaver +}; + +uint32 const Entry[8] = +{ + NPC_FIELD_MEDIC_PENNY, + NPC_EIVI_NIGHTFEATHER, + NPC_ELEMENTALIST_MAHFUUN, + NPC_MISSY_FLAMECUFFS, + NPC_FIELD_MEDIC_JESSI, + NPC_ELLIE_NIGHTFEATHER, + NPC_ELEMENTALIST_AVUUN, + NPC_SISSY_FLAMECUFFS, +}; + +class npc_flash_freeze : public CreatureScript +{ + public: + npc_flash_freeze() : CreatureScript("npc_flash_freeze") { } + + struct npc_flash_freezeAI : public ScriptedAI + { + npc_flash_freezeAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + me->SetDisplayId(me->GetCreatureInfo()->Modelid2); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + } + + InstanceScript* instance; + + uint64 targetGUID; + uint32 checkDespawnTimer; + + void Reset() + { + targetGUID = 0; + checkDespawnTimer = 1000; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->getVictim()->HasAura(SPELL_BLOCK_OF_ICE) || me->getVictim()->HasAura(SPELL_FLASH_FREEZE_HELPER)) + return; + + if (me->getVictim()->GetGUID() != targetGUID || instance->GetBossState(BOSS_HODIR) != IN_PROGRESS) + me->DespawnOrUnsummon(); + + if (checkDespawnTimer <= diff) + { + if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID)) + if (!target->isAlive()) + me->DisappearAndDie(); + checkDespawnTimer = 2500; + } + else + checkDespawnTimer -= diff; + } + + void IsSummonedBy(Unit* summoner) + { + targetGUID = summoner->GetGUID(); + me->SetInCombatWith(summoner); + me->AddThreat(summoner, 250.0f); + if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID)) + { + DoCast(target, SPELL_BLOCK_OF_ICE, true); + // Prevents to have Ice Block on other place than target is + me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); + if (target->GetTypeId() == TYPEID_PLAYER) + if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) + Hodir->AI()->DoAction(ACTION_CHEESE_THE_FREEZE); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_flash_freezeAI(creature); + } +}; + +class npc_ice_block : public CreatureScript +{ + public: + npc_ice_block() : CreatureScript("npc_ice_block") { } + + struct npc_ice_blockAI : public ScriptedAI + { + npc_ice_blockAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + me->SetDisplayId(me->GetCreatureInfo()->Modelid2); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + targetGUID = 0; + } + + InstanceScript* instance; + + uint64 targetGUID; + + void IsSummonedBy(Unit* summoner) + { + targetGUID = summoner->GetGUID(); + summoner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + me->SetInCombatWith(summoner); + me->AddThreat(summoner, 250.0f); + summoner->AddThreat(me, 250.0f); + if (Creature* target = ObjectAccessor::GetCreature(*me, targetGUID)) + { + DoCast(target, SPELL_FLASH_FREEZE_HELPER, true); + // Prevents to have Ice Block on other place than target is + me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); + } + } + + void DamageTaken(Unit* who, uint32& /*damage*/) + { + if (Creature* Helper = ObjectAccessor::GetCreature(*me, targetGUID)) + { + Helper->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + + if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) + { + if (!Hodir->isInCombat()) + { + Hodir->SetReactState(REACT_AGGRESSIVE); + Hodir->AI()->DoZoneInCombat(); + Hodir->AI()->AttackStart(who); + } + + Helper->AI()->AttackStart(Hodir); + } + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_ice_blockAI(creature); + } +}; + +class boss_hodir : public CreatureScript +{ + public: + boss_hodir() : CreatureScript("boss_hodir") { } + + struct boss_hodirAI : public BossAI + { + boss_hodirAI(Creature* creature) : BossAI(creature, BOSS_HODIR) + { + me->SetReactState(REACT_PASSIVE); + } + + uint32 gettingColdInHereTimer; + + bool gettingColdInHere; + bool cheeseTheFreeze; + bool iHaveTheCoolestFriends; + bool iCouldSayThatThisCacheWasRare; + + void Reset() + { + _Reset(); + me->SetReactState(REACT_PASSIVE); + + for (uint8 n = 0; n < FRIENDS_COUNT; ++n) + if (Creature* FrozenHelper = me->SummonCreature(Entry[n], SummonPositions[n], TEMPSUMMON_MANUAL_DESPAWN)) + FrozenHelper->CastSpell(FrozenHelper, SPELL_SUMMON_FLASH_FREEZE_HELPER, true); + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + DoScriptText(SAY_AGGRO, me); + DoCast(me, SPELL_BITING_COLD, true); + + gettingColdInHereTimer = 1000; + gettingColdInHere = true; + cheeseTheFreeze = true; + iHaveTheCoolestFriends = true; + iCouldSayThatThisCacheWasRare = true; + + events.ScheduleEvent(EVENT_ICICLE, 2000); + events.ScheduleEvent(EVENT_FREEZE, 25000); + events.ScheduleEvent(EVENT_BLOWS, urand(60000, 65000)); + events.ScheduleEvent(EVENT_FLASH_FREEZE, 45000); + events.ScheduleEvent(EVENT_RARE_CACHE, 180000); + events.ScheduleEvent(EVENT_BERSERK, 480000); + } + + void KilledUnit(Unit* /*who*/) + { + if (!urand(0, 3)) + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void DamageTaken(Unit* /*who*/, uint32& damage) + { + if (damage >= me->GetHealth()) + { + damage = 0; + DoScriptText(SAY_DEATH, me); + if (iCouldSayThatThisCacheWasRare) + instance->SetData(DATA_HODIR_RARE_CACHE, 1); + + me->RemoveAllAuras(); + me->RemoveAllAttackers(); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); + me->InterruptNonMeleeSpells(true); + me->StopMoving(); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + me->SetControlled(true, UNIT_STAT_STUNNED); + me->CombatStop(true); + + me->setFaction(35); + me->DespawnOrUnsummon(10000); + + _JustDied(); + } + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FREEZE: + DoCastAOE(SPELL_FREEZE); + events.ScheduleEvent(EVENT_FREEZE, urand(30000, 45000)); + break; + case EVENT_ICICLE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_ICICLE); + events.ScheduleEvent(EVENT_ICICLE, RAID_MODE(5500, 3500)); + break; + case EVENT_FLASH_FREEZE: + DoScriptText(SAY_FLASH_FREEZE, me); + DoScriptText(EMOTE_FREEZE, me); + for (uint8 n = 0; n < RAID_MODE(2, 3); ++n) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + target->CastSpell(target, SPELL_ICICLE_SNOWDRIFT, true); + DoCast(SPELL_FLASH_FREEZE); + events.ScheduleEvent(EVENT_FLASH_FREEZE_EFFECT, 500); + break; + case EVENT_FLASH_FREEZE_EFFECT: + { + std::list IcicleSnowdriftList; + GetCreatureListWithEntryInGrid(IcicleSnowdriftList, me, NPC_SNOWPACKED_ICICLE, 100.0f); + for (std::list::iterator itr = IcicleSnowdriftList.begin(); itr != IcicleSnowdriftList.end(); ++itr) + (*itr)->CastSpell(me, SPELL_FLASH_FREEZE_VISUAL, true); + FlashFreeze(); + events.CancelEvent(EVENT_FLASH_FREEZE_EFFECT); + events.ScheduleEvent(EVENT_FLASH_FREEZE, urand(25000, 35000)); + break; + } + case EVENT_BLOWS: + DoScriptText(SAY_STALACTITE, me); + DoScriptText(EMOTE_BLOWS, me); + DoCast(me, SPELL_FROZEN_BLOWS); + events.ScheduleEvent(EVENT_BLOWS, urand(60000, 65000)); + break; + case EVENT_RARE_CACHE: + DoScriptText(SAY_HARD_MODE_FAILED, me); + iCouldSayThatThisCacheWasRare = false; + instance->SetData(DATA_HODIR_RARE_CACHE, 0); + events.CancelEvent(EVENT_RARE_CACHE); + break; + case EVENT_BERSERK: + DoScriptText(SAY_BERSERK, me); + DoCast(me, SPELL_BERSERK, true); + events.CancelEvent(EVENT_BERSERK); + break; + } + } + + if (gettingColdInHereTimer <= diff && gettingColdInHere) + { + std::list ThreatList = me->getThreatManager().getThreatList(); + for (std::list::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); ++itr) + if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) + if (Aura* BitingColdAura = target->GetAura(SPELL_BITING_COLD_TRIGGERED)) + if ((target->GetTypeId() == TYPEID_PLAYER) && (BitingColdAura->GetStackAmount() > 2)) + me->AI()->SetData(DATA_GETTING_COLD_IN_HERE, 0); + gettingColdInHereTimer = 1000; + } + else + gettingColdInHereTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_I_HAVE_THE_COOLEST_FRIENDS: + iHaveTheCoolestFriends = false; + break; + case ACTION_CHEESE_THE_FREEZE: + cheeseTheFreeze = false; + break; + default: + break; + } + } + + void FlashFreeze() + { + std::list TargetList; + Trinity::AnyUnfriendlyUnitInObjectRangeCheck checker(me, me, 100.0f); + Trinity::UnitListSearcher searcher(me, TargetList, checker); + me->VisitNearbyObject(100.0f, searcher); + for (std::list::iterator itr = TargetList.begin(); itr != TargetList.end(); ++itr) + { + Unit* target = *itr; + if (!target || !target->isAlive() || GetClosestCreatureWithEntry(target, NPC_SNOWPACKED_ICICLE, 5.0f)) + continue; + + if (target->HasAura(SPELL_FLASH_FREEZE_HELPER) || target->HasAura(SPELL_BLOCK_OF_ICE)) + { + me->CastSpell(target, SPELL_FLASH_FREEZE_KILL, true); + continue; + } + + target->CastSpell(target, SPELL_SUMMON_BLOCK_OF_ICE, true); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class npc_icicle : public CreatureScript +{ + public: + npc_icicle() : CreatureScript("npc_icicle") { } + + struct npc_icicleAI : public ScriptedAI + { + npc_icicleAI(Creature* creature) : ScriptedAI(creature) + { + me->SetDisplayId(me->GetCreatureInfo()->Modelid1); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); + } + + uint32 icicleTimer; + + void Reset() + { + icicleTimer = 2500; + } + + void UpdateAI(uint32 const diff) + { + if (icicleTimer <= diff) + { + if (me->GetEntry() == NPC_ICICLE_SNOWDRIFT) + { + DoCast(me, SPELL_FALL_SNOWDRIFT); + DoCast(me, SPELL_ICICLE_FALL); + } + else if (me->GetEntry() == NPC_ICICLE) + { + DoCast(me, SPELL_ICICLE_FALL); + DoCast(me, SPELL_FALL_DAMAGE, true); + } + icicleTimer = 10000; + } + else + icicleTimer -= diff; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class npc_snowpacked_icicle : public CreatureScript +{ + public: + npc_snowpacked_icicle() : CreatureScript("npc_snowpacked_icicle") { } + + struct npc_snowpacked_icicleAI : public ScriptedAI + { + npc_snowpacked_icicleAI(Creature* creature) : ScriptedAI(creature) + { + me->SetDisplayId(me->GetCreatureInfo()->Modelid2); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + me->SetReactState(REACT_PASSIVE); + } + + uint32 despawnTimer; + + void Reset() + { + despawnTimer = 12000; + } + + void UpdateAI(uint32 const diff) + { + if (despawnTimer <= diff) + { + if (GameObject* Snowdrift = me->FindNearestGameObject(GO_SNOWDRIFT, 2.0f)) + me->RemoveGameObject(Snowdrift, true); + me->DespawnOrUnsummon(); + } + else + despawnTimer -= diff; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class npc_hodir_priest : public CreatureScript +{ + public: + npc_hodir_priest() : CreatureScript("npc_hodir_priest") { } + + struct npc_hodir_priestAI : public ScriptedAI + { + npc_hodir_priestAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void Reset() + { + events.Reset(); + events.ScheduleEvent(EVENT_HEAL, urand(4000, 8000)); + events.ScheduleEvent(EVENT_DISPEL_MAGIC, urand(15000, 20000)); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + if (HealthBelowPct(30)) + DoCast(me, SPELL_GREATER_HEAL); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_HEAL: + DoCastAOE(SPELL_GREATER_HEAL); + events.ScheduleEvent(EVENT_HEAL, urand(7500, 10000)); + break; + case EVENT_DISPEL_MAGIC: + { + std::list TargetList; + Trinity::AnyFriendlyUnitInObjectRangeCheck checker(me, me, 30.0f); + Trinity::UnitListSearcher searcher(me, TargetList, checker); + me->VisitNearbyObject(30.0f, searcher); + for (std::list::iterator itr = TargetList.begin(); itr != TargetList.end(); ++itr) + if ((*itr)->HasAura(SPELL_FREEZE)) + DoCast(*itr, SPELL_DISPEL_MAGIC, true); + events.ScheduleEvent(EVENT_DISPEL_MAGIC, urand(15000, 20000)); + break; + } + default: + break; + } + } + + DoSpellAttackIfReady(SPELL_SMITE); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) + Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class npc_hodir_shaman : public CreatureScript +{ + public: + npc_hodir_shaman() : CreatureScript("npc_hodir_shaman") { } + + struct npc_hodir_shamanAI : public ScriptedAI + { + npc_hodir_shamanAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void Reset() + { + events.Reset(); + events.ScheduleEvent(EVENT_STORM_CLOUD, urand(10000, 12500)); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STORM_CLOUD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_STORM_CLOUD, true); + events.ScheduleEvent(EVENT_STORM_CLOUD, urand(15000, 20000)); + break; + default: + break; + } + } + + DoSpellAttackIfReady(SPELL_LAVA_BURST); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) + Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class npc_hodir_druid : public CreatureScript +{ + public: + npc_hodir_druid() : CreatureScript("npc_hodir_druid") { } + + struct npc_hodir_druidAI : public ScriptedAI + { + npc_hodir_druidAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void Reset() + { + events.Reset(); + events.ScheduleEvent(EVENT_STARLIGHT, urand(15000, 17500)); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STARLIGHT: + DoCast(me, SPELL_STARLIGHT, true); + events.ScheduleEvent(EVENT_STARLIGHT, urand(25000, 35000)); + break; + default: + break; + } + } + + DoSpellAttackIfReady(SPELL_WRATH); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) + Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class npc_hodir_mage : public CreatureScript +{ + public: + npc_hodir_mage() : CreatureScript("npc_hodir_mage") { } + + struct npc_hodir_mageAI : public ScriptedAI + { + npc_hodir_mageAI(Creature* creature) : ScriptedAI(creature), summons(me) + { + instance = me->GetInstanceScript(); + } + + void Reset() + { + events.Reset(); + summons.DespawnAll(); + events.ScheduleEvent(EVENT_CONJURE_FIRE, urand(10000, 12500)); + events.ScheduleEvent(EVENT_MELT_ICE, 5000); + } + + void JustSummoned(Creature* summoned) + { + if (summoned->GetEntry() == NPC_TOASTY_FIRE) + summons.Summon(summoned); + } + + void SummonedCreatureDespawn(Creature* summoned) + { + if (summoned->GetEntry() == NPC_TOASTY_FIRE) + summons.remove(summoned->GetGUID()); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CONJURE_FIRE: + if (summons.size() >= RAID_MODE(2, 4)) + break; + DoCast(me, SPELL_CONJURE_FIRE, true); + events.ScheduleEvent(EVENT_CONJURE_FIRE, urand(15000, 20000)); + break; + case EVENT_MELT_ICE: + if (Creature* FlashFreeze = me->FindNearestCreature(NPC_FLASH_FREEZE, 50.0f, true)) + DoCast(FlashFreeze, SPELL_MELT_ICE, true); + events.ScheduleEvent(EVENT_MELT_ICE, urand(10000, 15000)); + break; + } + } + + DoSpellAttackIfReady(SPELL_FIREBALL); + } + + void JustDied(Unit* /*who*/) + { + if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) + Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + } + + private: + InstanceScript* instance; + EventMap events; + SummonList summons; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class npc_toasty_fire : public CreatureScript +{ + public: + npc_toasty_fire() : CreatureScript("npc_toasty_fire") { } + + struct npc_toasty_fireAI : public ScriptedAI + { + npc_toasty_fireAI(Creature* creature) : ScriptedAI(creature) + { + me->SetDisplayId(me->GetCreatureInfo()->Modelid2); + } + + void Reset() + { + DoCast(me, SPELL_SINGED, true); + } + + void SpellHit(Unit* /*who*/, const SpellInfo* spell) + { + if (spell->Id == SPELL_BLOCK_OF_ICE || spell->Id == SPELL_ICE_SHARD || spell->Id == SPELL_ICE_SHARD_HIT) + { + if (GameObject* ToastyFire = me->FindNearestGameObject(GO_TOASTY_FIRE, 1.0f)) + me->RemoveGameObject(ToastyFire, true); + me->DespawnOrUnsummon(); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + }; +}; + +class spell_biting_cold : public SpellScriptLoader +{ + public: + spell_biting_cold() : SpellScriptLoader("spell_biting_cold") { } + + class spell_biting_cold_AuraScript : public AuraScript + { + PrepareAuraScript(spell_biting_cold_AuraScript); + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetTarget(); + bool found = false; + + for (TargetList::iterator itr = listOfTargets.begin(); itr != listOfTargets.end(); ++itr) + { + if (itr->first != target->GetGUID()) + return; + + if (itr->second >= 4) + { + target->CastSpell(target, SPELL_BITING_COLD_TRIGGERED, true); + itr->second = 1; + } + else + { + if (target->isMoving()) + itr->second = 1; + else + itr->second++; + } + + found = true; + break; + } + + if (!found) + listOfTargets.push_back(std::make_pair(target->GetGUID(), 1)); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_biting_cold_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + + private: + typedef std::list< std::pair > TargetList; + TargetList listOfTargets; + }; + + AuraScript* GetAuraScript() const + { + return new spell_biting_cold_AuraScript(); + } +}; + +class spell_biting_cold_dot : public SpellScriptLoader +{ +public: + spell_biting_cold_dot() : SpellScriptLoader("spell_biting_cold_dot") { } + + class spell_biting_cold_dot_AuraScript : public AuraScript + { + PrepareAuraScript(spell_biting_cold_dot_AuraScript); + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + int32 damage = int32(200 * pow(2.0f, GetStackAmount())); + caster->CastCustomSpell(caster, SPELL_BITING_COLD_DAMAGE, &damage, NULL, NULL, true); + + if (caster->isMoving()) + caster->RemoveAuraFromStack(SPELL_BITING_COLD_TRIGGERED); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_biting_cold_dot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_biting_cold_dot_AuraScript(); + } +}; + +void AddSC_boss_hodir() +{ + new boss_hodir(); + new npc_icicle(); + new npc_snowpacked_icicle(); + new npc_hodir_priest(); + new npc_hodir_shaman(); + new npc_hodir_druid(); + new npc_hodir_mage(); + new npc_toasty_fire(); + new npc_ice_block(); + new npc_flash_freeze(); + new spell_biting_cold(); + new spell_biting_cold_dot(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp new file mode 100644 index 00000000000..b8876ae577a --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -0,0 +1,495 @@ +/* + * Copyright (C) 2008-2011 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 "SpellScript.h" +#include "SpellAuraEffects.h" +#include "ulduar.h" +#include "Vehicle.h" + +enum Yells +{ + SAY_AGGRO = -1603220, + SAY_SLAY_1 = -1603221, + SAY_SLAY_2 = -1603222, + SAY_DEATH = -1603223, + SAY_SUMMON = -1603224, + SAY_SLAG_POT = -1603225, + SAY_SCORCH_1 = -1603226, + SAY_SCORCH_2 = -1603227, + SAY_BERSERK = -1603228, + EMOTE_JETS = -1603229, +}; + +enum Spells +{ + SPELL_FLAME_JETS = 62680, + SPELL_SCORCH = 62546, + SPELL_SLAG_POT = 62717, + SPELL_SLAG_POT_DAMAGE = 65722, + SPELL_SLAG_IMBUED = 62836, + SPELL_ACTIVATE_CONSTRUCT = 62488, + SPELL_STRENGHT = 64473, + SPELL_GRAB = 62707, + SPELL_BERSERK = 47008, + + // Iron Construct + SPELL_HEAT = 65667, + SPELL_MOLTEN = 62373, + SPELL_BRITTLE = 62382, + SPELL_SHATTER = 62383, + SPELL_GROUND = 62548, +}; + +enum Events +{ + EVENT_JET = 1, + EVENT_SCORCH = 2, + EVENT_SLAG_POT = 3, + EVENT_GRAB_POT = 4, + EVENT_CHANGE_POT = 5, + EVENT_END_POT = 6, + EVENT_CONSTRUCT = 7, + EVENT_BERSERK = 8, +}; + +enum Actions +{ + ACTION_REMOVE_BUFF = 20, +}; + +enum Creatures +{ + NPC_IRON_CONSTRUCT = 33121, + NPC_GROUND_SCORCH = 33221, +}; + +enum AchievementData +{ + DATA_SHATTERED = 29252926, + ACHIEVEMENT_IGNIS_START_EVENT = 20951, +}; + +#define CONSTRUCT_SPAWN_POINTS 20 + +Position const ConstructSpawnPosition[CONSTRUCT_SPAWN_POINTS] = +{ + {630.366f, 216.772f, 360.891f, 3.001970f}, + {630.594f, 231.846f, 360.891f, 3.124140f}, + {630.435f, 337.246f, 360.886f, 3.211410f}, + {630.493f, 313.349f, 360.886f, 3.054330f}, + {630.444f, 321.406f, 360.886f, 3.124140f}, + {630.366f, 247.307f, 360.888f, 3.211410f}, + {630.698f, 305.311f, 360.886f, 3.001970f}, + {630.500f, 224.559f, 360.891f, 3.054330f}, + {630.668f, 239.840f, 360.890f, 3.159050f}, + {630.384f, 329.585f, 360.886f, 3.159050f}, + {543.220f, 313.451f, 360.886f, 0.104720f}, + {543.356f, 329.408f, 360.886f, 6.248280f}, + {543.076f, 247.458f, 360.888f, 6.213370f}, + {543.117f, 232.082f, 360.891f, 0.069813f}, + {543.161f, 305.956f, 360.886f, 0.157080f}, + {543.277f, 321.482f, 360.886f, 0.052360f}, + {543.316f, 337.468f, 360.886f, 6.195920f}, + {543.280f, 239.674f, 360.890f, 6.265730f}, + {543.265f, 217.147f, 360.891f, 0.174533f}, + {543.256f, 224.831f, 360.891f, 0.122173f}, +}; + +class boss_ignis : public CreatureScript +{ + public: + boss_ignis() : CreatureScript("boss_ignis") { } + + struct boss_ignis_AI : public BossAI + { + boss_ignis_AI(Creature* creature) : BossAI(creature, BOSS_IGNIS), _vehicle(me->GetVehicleKit()) + { + ASSERT(_vehicle); + } + + void Reset() + { + _Reset(); + if (_vehicle) + _vehicle->RemoveAllPassengers(); + + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + DoScriptText(SAY_AGGRO, me); + events.ScheduleEvent(EVENT_JET, 30000); + events.ScheduleEvent(EVENT_SCORCH, 25000); + events.ScheduleEvent(EVENT_SLAG_POT, 35000); + events.ScheduleEvent(EVENT_CONSTRUCT, 15000); + events.ScheduleEvent(EVENT_END_POT, 40000); + events.ScheduleEvent(EVENT_BERSERK, 480000); + _slagPotGUID = 0; + _shattered = false; + _firstConstructKill = 0; + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); + } + + void JustDied(Unit* /*victim*/) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + } + + uint32 GetData(uint32 type) + { + if (type == DATA_SHATTERED) + return _shattered ? 1 : 0; + + return 0; + } + + void KilledUnit(Unit* /*victim*/) + { + if (!urand(0, 4)) + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void JustSummoned(Creature* summon) + { + if (summon->GetEntry() == NPC_IRON_CONSTRUCT) + { + summon->setFaction(16); + summon->SetReactState(REACT_AGGRESSIVE); + summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_DISABLE_MOVE); + } + + summon->AI()->AttackStart(me->getVictim()); + summon->AI()->DoZoneInCombat(); + summons.Summon(summon); + } + + void DoAction(const int32 action) + { + if (action != ACTION_REMOVE_BUFF) + return; + + me->RemoveAuraFromStack(SPELL_STRENGHT); + // Shattered Achievement + time_t secondKill = sWorld->GetGameTime(); + if ((secondKill - _firstConstructKill) < 5) + _shattered = true; + _firstConstructKill = secondKill; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_JET: + me->MonsterTextEmote(EMOTE_JETS, 0, true); + DoCast(me, SPELL_FLAME_JETS); + events.ScheduleEvent(EVENT_JET, urand(35000, 40000)); + break; + case EVENT_SLAG_POT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + DoScriptText(SAY_SLAG_POT, me); + _slagPotGUID = target->GetGUID(); + DoCast(target, SPELL_GRAB); + events.DelayEvents(3000); + events.ScheduleEvent(EVENT_GRAB_POT, 500); + } + events.ScheduleEvent(EVENT_SLAG_POT, RAID_MODE(30000, 15000)); + break; + case EVENT_GRAB_POT: + if (Unit* slagPotTarget = ObjectAccessor::GetUnit(*me, _slagPotGUID)) + { + slagPotTarget->EnterVehicle(me, 0); + events.CancelEvent(EVENT_GRAB_POT); + events.ScheduleEvent(EVENT_CHANGE_POT, 1000); + } + break; + case EVENT_CHANGE_POT: + if (Unit* slagPotTarget = ObjectAccessor::GetUnit(*me, _slagPotGUID)) + { + slagPotTarget->AddAura(SPELL_SLAG_POT, slagPotTarget); + slagPotTarget->EnterVehicle(me, 1); + events.CancelEvent(EVENT_CHANGE_POT); + events.ScheduleEvent(EVENT_END_POT, 10000); + } + break; + case EVENT_END_POT: + if (Unit* slagPotTarget = ObjectAccessor::GetUnit(*me, _slagPotGUID)) + { + slagPotTarget->ExitVehicle(); + slagPotTarget = NULL; + _slagPotGUID = 0; + events.CancelEvent(EVENT_END_POT); + } + break; + case EVENT_SCORCH: + DoScriptText(RAND(SAY_SCORCH_1, SAY_SCORCH_2), me); + if (Unit* target = me->getVictim()) + me->SummonCreature(NPC_GROUND_SCORCH, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 45000); + DoCast(SPELL_SCORCH); + events.ScheduleEvent(EVENT_SCORCH, 25000); + break; + case EVENT_CONSTRUCT: + DoScriptText(SAY_SUMMON, me); + DoSummon(NPC_IRON_CONSTRUCT, ConstructSpawnPosition[urand(0, CONSTRUCT_SPAWN_POINTS - 1)], 30000, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT); + DoCast(SPELL_STRENGHT); + DoCast(me, SPELL_ACTIVATE_CONSTRUCT); + events.ScheduleEvent(EVENT_CONSTRUCT, RAID_MODE(40000, 30000)); + break; + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK, true); + DoScriptText(SAY_BERSERK, me); + break; + } + } + + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(diff); + } + + private: + uint64 _slagPotGUID; + Vehicle* _vehicle; + time_t _firstConstructKill; + bool _shattered; + + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class npc_iron_construct : public CreatureScript +{ + public: + npc_iron_construct() : CreatureScript("npc_iron_construct") { } + + struct npc_iron_constructAI : public ScriptedAI + { + npc_iron_constructAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) + { + creature->SetReactState(REACT_PASSIVE); + } + + void Reset() + { + _brittled = false; + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (me->HasAura(SPELL_BRITTLE) && damage >= 5000) + { + DoCast(SPELL_SHATTER); + if (Creature* ignis = ObjectAccessor::GetCreature(*me, _instance->GetData64(BOSS_IGNIS))) + if (ignis->AI()) + ignis->AI()->DoAction(ACTION_REMOVE_BUFF); + + me->DespawnOrUnsummon(1000); + } + } + + void UpdateAI(const uint32 /*uiDiff*/) + { + if (!UpdateVictim()) + return; + + if (Aura* aur = me->GetAura(SPELL_HEAT)) + { + if (aur->GetStackAmount() >= 10) + { + me->RemoveAura(SPELL_HEAT); + DoCast(SPELL_MOLTEN); + _brittled = false; + } + } + + // Water pools + if (me->IsInWater() && !_brittled && me->HasAura(SPELL_MOLTEN)) + { + DoCast(SPELL_BRITTLE); + me->RemoveAura(SPELL_MOLTEN); + _brittled = true; + } + + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* _instance; + bool _brittled; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class npc_scorch_ground : public CreatureScript +{ + public: + npc_scorch_ground() : CreatureScript("npc_scorch_ground") { } + + struct npc_scorch_groundAI : public ScriptedAI + { + npc_scorch_groundAI(Creature* creature) : ScriptedAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE |UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + creature->SetDisplayId(16925); //model 2 in db cannot overwrite wdb fields + } + + void MoveInLineOfSight(Unit* unit) + { + if (!_heat) + { + if (unit->GetEntry() == NPC_IRON_CONSTRUCT) + { + if (!unit->HasAura(SPELL_HEAT) || !unit->HasAura(SPELL_MOLTEN)) + { + _constructGUID = unit->GetGUID(); + _heat = true; + } + } + } + } + + void Reset() + { + _heat = false; + DoCast(me, SPELL_GROUND); + _constructGUID = 0; + _heatTimer = 0; + } + + void UpdateAI(const uint32 uiDiff) + { + if (_heat) + { + if (_heatTimer <= uiDiff) + { + Creature* construct = me->GetCreature(*me, _constructGUID); + if (construct && !construct->HasAura(SPELL_MOLTEN)) + { + me->AddAura(SPELL_HEAT, construct); + _heatTimer = 1000; + } + } + else + _heatTimer -= uiDiff; + } + } + + private: + uint64 _constructGUID; + uint32 _heatTimer; + bool _heat; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class spell_ignis_slag_pot : public SpellScriptLoader +{ + public: + spell_ignis_slag_pot() : SpellScriptLoader("spell_ignis_slag_pot") { } + + class spell_ignis_slag_pot_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ignis_slag_pot_AuraScript); + + bool Validate(SpellInfo const* /*spellEntry*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SLAG_POT_DAMAGE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SLAG_IMBUED)) + return false; + return true; + } + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + Unit* aurEffCaster = aurEff->GetCaster(); + if (!aurEffCaster) + return; + + Unit* target = GetTarget(); + aurEffCaster->CastSpell(target, SPELL_SLAG_POT_DAMAGE, true); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->isAlive()) + GetTarget()->CastSpell(GetTarget(), SPELL_SLAG_IMBUED, true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_slag_pot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + AfterEffectRemove += AuraEffectRemoveFn(spell_ignis_slag_pot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_ignis_slag_pot_AuraScript(); + } +}; + +class achievement_ignis_shattered : public AchievementCriteriaScript +{ + public: + achievement_ignis_shattered() : AchievementCriteriaScript("achievement_ignis_shattered") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (target && target->IsAIEnabled) + return target->GetAI()->GetData(DATA_SHATTERED); + + return false; + } +}; + +void AddSC_boss_ignis() +{ + new boss_ignis(); + new npc_iron_construct(); + new npc_scorch_ground(); + new spell_ignis_slag_pot(); + new achievement_ignis_shattered(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp new file mode 100644 index 00000000000..5da1c485986 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -0,0 +1,658 @@ +/* + * Copyright (C) 2008-2011 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 "SpellScript.h" +#include "SpellAuraEffects.h" +#include "ulduar.h" +#include "Vehicle.h" + +/* ScriptData +SDName: boss_kologarn +SD%Complete: 90 +SDComment: TODO: Achievements +SDCategory: Ulduar +EndScriptData */ + +#define SPELL_ARM_DEAD_DAMAGE RAID_MODE(63629, 63979) +#define SPELL_TWO_ARM_SMASH RAID_MODE(63356, 64003) +#define SPELL_ONE_ARM_SMASH RAID_MODE(63573, 64006) +#define SPELL_ARM_SWEEP RAID_MODE(63766, 63983) +#define SPELL_STONE_SHOUT RAID_MODE(63716, 64005) +#define SPELL_PETRIFY_BREATH RAID_MODE(62030, 63980) +#define SPELL_STONE_GRIP RAID_MODE(62166, 63981) +#define SPELL_STONE_GRIP_CANCEL 65594 +#define SPELL_SUMMON_RUBBLE 63633 +#define SPELL_FALLING_RUBBLE 63821 +#define SPELL_ARM_ENTER_VEHICLE 65343 +#define SPELL_ARM_ENTER_VISUAL 64753 + +#define SPELL_SUMMON_FOCUSED_EYEBEAM 63342 +#define SPELL_FOCUSED_EYEBEAM_PERIODIC RAID_MODE(63347, 63977) +#define SPELL_FOCUSED_EYEBEAM_VISUAL 63369 +#define SPELL_FOCUSED_EYEBEAM_VISUAL_LEFT 63676 +#define SPELL_FOCUSED_EYEBEAM_VISUAL_RIGHT 63702 + +// Passive +#define SPELL_KOLOGARN_REDUCE_PARRY 64651 +#define SPELL_KOLOGARN_PACIFY 63726 +#define SPELL_KOLOGARN_UNK_0 65219 // Not found in DBC + +#define SPELL_BERSERK 47008 // guess + +#define NPC_RUBBLE_STALKER 33809 +#define NPC_ARM_SWEEP_STALKER 33661 + +enum Events +{ + EVENT_NONE = 0, + EVENT_INSTALL_ACCESSORIES, + EVENT_MELEE_CHECK, + EVENT_SMASH, + EVENT_SWEEP, + EVENT_STONE_SHOUT, + EVENT_STONE_GRIP, + EVENT_FOCUSED_EYEBEAM, + EVENT_RESPAWN_LEFT_ARM, + EVENT_RESPAWN_RIGHT_ARM, + EVENT_ENRAGE, +}; + +enum Yells +{ + SAY_AGGRO = -1603230, + SAY_SLAY_1 = -1603231, + SAY_SLAY_2 = -1603232, + SAY_LEFT_ARM_GONE = -1603233, + SAY_RIGHT_ARM_GONE = -1603234, + SAY_SHOCKWAVE = -1603235, + SAY_GRAB_PLAYER = -1603236, + SAY_DEATH = -1603237, + SAY_BERSERK = -1603238, +}; + +class boss_kologarn : public CreatureScript +{ + public: + boss_kologarn() : CreatureScript("boss_kologarn") { } + + struct boss_kologarnAI : public BossAI + { + boss_kologarnAI(Creature* creature) : BossAI(creature, BOSS_KOLOGARN), vehicle(creature->GetVehicleKit()), + left(false), right(false) + { + ASSERT(vehicle); + + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + + DoCast(SPELL_KOLOGARN_REDUCE_PARRY); + SetCombatMovement(false); + Reset(); + } + + Vehicle* vehicle; + bool left, right; + uint64 eyebeamTarget; + + void EnterCombat(Unit* /*who*/) + { + DoScriptText(SAY_AGGRO, me); + + events.ScheduleEvent(EVENT_MELEE_CHECK, 6000); + events.ScheduleEvent(EVENT_SMASH, 5000); + events.ScheduleEvent(EVENT_SWEEP, 19000); + events.ScheduleEvent(EVENT_STONE_GRIP, 25000); + events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 21000); + events.ScheduleEvent(EVENT_ENRAGE, 600000); + + for (uint8 i = 0; i < 2; ++i) + if (Unit* arm = vehicle->GetPassenger(i)) + arm->ToCreature()->SetInCombatWithZone(); + + _EnterCombat(); + } + + void Reset() + { + _Reset(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + eyebeamTarget = 0; + } + + void JustDied(Unit* /*victim*/) + { + DoScriptText(SAY_DEATH, me); + DoCast(SPELL_KOLOGARN_PACIFY); + me->GetMotionMaster()->MoveTargetedHome(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetCorpseDelay(604800); // Prevent corpse from despawning. + _JustDied(); + } + + void KilledUnit(Unit* /*who*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) + { + bool isEncounterInProgress = instance->GetBossState(BOSS_KOLOGARN) == IN_PROGRESS; + if (who->GetEntry() == NPC_LEFT_ARM) + { + left = apply; + if (!apply && isEncounterInProgress) + { + who->ToCreature()->DisappearAndDie(); + DoScriptText(SAY_LEFT_ARM_GONE, me); + events.ScheduleEvent(EVENT_RESPAWN_LEFT_ARM, 40000); + } + } + + else if (who->GetEntry() == NPC_RIGHT_ARM) + { + right = apply; + if (!apply && isEncounterInProgress) + { + who->ToCreature()->DisappearAndDie(); + DoScriptText(SAY_RIGHT_ARM_GONE, me); + events.ScheduleEvent(EVENT_RESPAWN_RIGHT_ARM, 40000); + } + } + + if (!isEncounterInProgress) + return; + + if (!apply) + { + who->CastSpell(me, SPELL_ARM_DEAD_DAMAGE, true); + + if (Creature* rubbleStalker = who->FindNearestCreature(NPC_RUBBLE_STALKER, 70.0f)) + { + if (rubbleStalker) + { + rubbleStalker->CastSpell(rubbleStalker, SPELL_FALLING_RUBBLE, true); + rubbleStalker->CastSpell(rubbleStalker, SPELL_SUMMON_RUBBLE, true); + } + } + + if (!right && !left) + events.ScheduleEvent(EVENT_STONE_SHOUT, 5000); + + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_DISARMED); + } + else + { + events.CancelEvent(EVENT_STONE_SHOUT); + who->ToCreature()->SetInCombatWithZone(); + } + } + + void JustSummoned(Creature* summon) + { + switch (summon->GetEntry()) + { + case NPC_FOCUSED_EYEBEAM: + summon->CastSpell(me, SPELL_FOCUSED_EYEBEAM_VISUAL_LEFT, true); + break; + case NPC_FOCUSED_EYEBEAM_RIGHT: + summon->CastSpell(me, SPELL_FOCUSED_EYEBEAM_VISUAL_RIGHT, true); + break; + case NPC_RUBBLE: + summons.push_back(summon->GetGUID()); + // absence of break intended + default: + return; + } + + summon->CastSpell(summon, SPELL_FOCUSED_EYEBEAM_PERIODIC, true); + summon->CastSpell(summon, SPELL_FOCUSED_EYEBEAM_VISUAL, true); + summon->SetReactState(REACT_PASSIVE); + // One of the above spells is a channeled spell, we need to clear this unit state for MoveChase to work + summon->ClearUnitState(UNIT_STAT_CASTING); + + // Victim gets 67351 + if (eyebeamTarget) + { + if (Unit* target = Unit::GetUnit(*summon, eyebeamTarget)) + { + summon->Attack(target, false); + summon->GetMotionMaster()->MoveChase(target); + } + } + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MELEE_CHECK: + if (!me->IsWithinMeleeRange(me->getVictim())) + DoCast(SPELL_PETRIFY_BREATH); + events.ScheduleEvent(EVENT_MELEE_CHECK, 1 * IN_MILLISECONDS); + break; + case EVENT_SWEEP: + if (left) + DoCast(me->FindNearestCreature(NPC_ARM_SWEEP_STALKER, 500.0f, true), SPELL_ARM_SWEEP, true); + events.ScheduleEvent(EVENT_SWEEP, 25 * IN_MILLISECONDS); + break; + case EVENT_SMASH: + if (left && right) + DoCastVictim(SPELL_TWO_ARM_SMASH); + else if (left || right) + DoCastVictim(SPELL_ONE_ARM_SMASH); + events.ScheduleEvent(EVENT_SMASH, 15 * IN_MILLISECONDS); + break; + case EVENT_STONE_SHOUT: + DoCast(SPELL_STONE_SHOUT); + events.ScheduleEvent(EVENT_STONE_SHOUT, 2 * IN_MILLISECONDS); + break; + case EVENT_ENRAGE: + DoCast(SPELL_BERSERK); + DoScriptText(SAY_BERSERK, me); + break; + case EVENT_RESPAWN_LEFT_ARM: + case EVENT_RESPAWN_RIGHT_ARM: + { + if (vehicle) + { + int8 seat = eventId == EVENT_RESPAWN_LEFT_ARM ? 0 : 1; + uint32 entry = eventId == EVENT_RESPAWN_LEFT_ARM ? NPC_LEFT_ARM : NPC_RIGHT_ARM; + vehicle->InstallAccessory(entry, seat, true, TEMPSUMMON_MANUAL_DESPAWN, 0); + } + break; + } + case EVENT_STONE_GRIP: + { + if (right) + { + DoCast(SPELL_STONE_GRIP); + DoScriptText(SAY_GRAB_PLAYER, me); + } + events.ScheduleEvent(EVENT_STONE_GRIP, 25 * IN_MILLISECONDS); + } + break; + case EVENT_FOCUSED_EYEBEAM: + if (Unit* eyebeamTargetUnit = SelectTarget(SELECT_TARGET_FARTHEST, 0, 0, true)) + { + eyebeamTarget = eyebeamTargetUnit->GetGUID(); + DoCast(me, SPELL_SUMMON_FOCUSED_EYEBEAM, true); + } + events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, urand(15, 35) * IN_MILLISECONDS); + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class spell_ulduar_rubble_summon : public SpellScriptLoader +{ + public: + spell_ulduar_rubble_summon() : SpellScriptLoader("spell_ulduar_rubble_summon") { } + + class spell_ulduar_rubble_summonSpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_rubble_summonSpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + uint64 originalCaster = caster->GetInstanceScript() ? caster->GetInstanceScript()->GetData64(BOSS_KOLOGARN) : 0; + uint32 spellId = GetEffectValue(); + for (uint8 i = 0; i < 5; ++i) + caster->CastSpell(caster, spellId, true, NULL, NULL, originalCaster); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_ulduar_rubble_summonSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_ulduar_rubble_summonSpellScript(); + } +}; + +// predicate function to select non main tank target +class StoneGripTargetSelector : public std::unary_function +{ + public: + StoneGripTargetSelector(Creature* me, Unit const* victim) : _me(me), _victim(victim) {} + + bool operator() (Unit* target) + { + if (target == _victim && _me->getThreatManager().getThreatList().size() > 1) + return true; + + if (target->GetTypeId() != TYPEID_PLAYER) + return true; + + return false; + } + + Creature* _me; + Unit const* _victim; +}; + +class spell_ulduar_stone_grip_cast_target : public SpellScriptLoader +{ + public: + spell_ulduar_stone_grip_cast_target() : SpellScriptLoader("spell_ulduar_stone_grip_cast_target") { } + + class spell_ulduar_stone_grip_cast_target_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_stone_grip_cast_target_SpellScript); + + bool Load() + { + if (GetCaster()->GetTypeId() != TYPEID_UNIT) + return false; + return true; + } + + void FilterTargetsInitial(std::list& unitList) + { + // Remove "main tank" and non-player targets + unitList.remove_if (StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->getVictim())); + // Maximum affected targets per difficulty mode + uint32 maxTargets = 1; + if (GetSpellInfo()->Id == 63981) + maxTargets = 3; + + // Return a random amount of targets based on maxTargets + while (maxTargets < unitList.size()) + { + std::list::iterator itr = unitList.begin(); + advance(itr, urand(0, unitList.size()-1)); + unitList.erase(itr); + } + + // For subsequent effects + m_unitList = unitList; + } + + void FillTargetsSubsequential(std::list& unitList) + { + unitList = m_unitList; + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_ulduar_stone_grip_cast_target_SpellScript::FilterTargetsInitial, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnUnitTargetSelect += SpellUnitTargetFn(spell_ulduar_stone_grip_cast_target_SpellScript::FillTargetsSubsequential, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnUnitTargetSelect += SpellUnitTargetFn(spell_ulduar_stone_grip_cast_target_SpellScript::FillTargetsSubsequential, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY); + } + + // Shared between effects + std::list m_unitList; + }; + + SpellScript* GetSpellScript() const + { + return new spell_ulduar_stone_grip_cast_target_SpellScript(); + } +}; + +class spell_ulduar_cancel_stone_grip : public SpellScriptLoader +{ + public: + spell_ulduar_cancel_stone_grip() : SpellScriptLoader("spell_ulduar_cancel_stone_grip") { } + + class spell_ulduar_cancel_stone_gripSpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_cancel_stone_gripSpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + if (!target || !target->GetVehicle()) + return; + + switch (target->GetMap()->GetDifficulty()) + { + case RAID_DIFFICULTY_10MAN_NORMAL: + target->RemoveAura(GetSpellInfo()->Effects[EFFECT_0].CalcValue()); + break; + case RAID_DIFFICULTY_25MAN_NORMAL: + target->RemoveAura(GetSpellInfo()->Effects[EFFECT_1].CalcValue()); + break; + default: + break; + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_ulduar_cancel_stone_gripSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_ulduar_cancel_stone_gripSpellScript(); + } +}; + +class spell_ulduar_squeezed_lifeless : public SpellScriptLoader +{ + public: + spell_ulduar_squeezed_lifeless() : SpellScriptLoader("spell_ulduar_squeezed_lifeless") { } + + class spell_ulduar_squeezed_lifeless_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_squeezed_lifeless_SpellScript); + + void HandleInstaKill(SpellEffIndex /*effIndex*/) + { + if (!GetHitPlayer() || !GetHitPlayer()->GetVehicle()) + return; + + Position pos; + pos.m_positionX = 1756.25f + irand(-3, 3); + pos.m_positionY = -8.3f + irand(-3, 3); + pos.m_positionZ = 448.8f; + pos.m_orientation = M_PI; + GetHitPlayer()->DestroyForNearbyPlayers(); + GetHitPlayer()->ExitVehicle(&pos); + GetHitPlayer()->UpdateObjectVisibility(false); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_ulduar_squeezed_lifeless_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_ulduar_squeezed_lifeless_SpellScript(); + } +}; + +class spell_ulduar_stone_grip_absorb : public SpellScriptLoader +{ + public: + spell_ulduar_stone_grip_absorb() : SpellScriptLoader("spell_ulduar_stone_grip_absorb") { } + + class spell_ulduar_stone_grip_absorb_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ulduar_stone_grip_absorb_AuraScript); + + //! This will be called when Right Arm (vehicle) has sustained a specific amount of damage depending on instance mode + //! What we do here is remove all harmful aura's related and teleport to safe spot. + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL) + return; + + if (!GetOwner()->ToCreature()) + return; + + uint32 rubbleStalkerEntry = (GetOwner()->GetMap()->GetDifficulty() == DUNGEON_DIFFICULTY_NORMAL ? 33809 : 33942); + Creature* rubbleStalker = GetOwner()->FindNearestCreature(rubbleStalkerEntry, 200.0f, true); + if (rubbleStalker) + rubbleStalker->CastSpell(rubbleStalker, SPELL_STONE_GRIP_CANCEL, true); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_absorb_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_ulduar_stone_grip_absorb_AuraScript(); + } +}; + +class spell_ulduar_stone_grip : public SpellScriptLoader +{ + public: + spell_ulduar_stone_grip() : SpellScriptLoader("spell_ulduar_stone_grip") { } + + class spell_ulduar_stone_grip_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ulduar_stone_grip_AuraScript); + + void OnRemoveStun(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* owner = GetOwner()->ToPlayer()) + owner->RemoveAurasDueToSpell(aurEff->GetAmount()); + } + + void OnRemoveVehicle(AuraEffect const* /*aurEff*/, AuraEffectHandleModes mode) + { + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + if (GetOwner()->GetTypeId() != TYPEID_UNIT) + return; + + Player* caster = GetCaster() ? GetCaster()->ToPlayer() : NULL; + if (!caster || !caster->IsOnVehicle(GetOwner()->ToUnit())) + return; + + caster->RemoveAurasDueToSpell(GetId()); + caster->ExitVehicle(); + caster->GetMotionMaster()->MoveJump(1756.25f + irand(-3, 3), -8.3f + irand(-3, 3), 448.8f, 5.0f, 5.0f); + PreventDefaultAction(); + } + + void Register() + { + OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveVehicle, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveStun, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_ulduar_stone_grip_AuraScript(); + } +}; + +class spell_kologarn_stone_shout : public SpellScriptLoader +{ + public: + spell_kologarn_stone_shout() : SpellScriptLoader("spell_kologarn_stone_shout") { } + + class spell_kologarn_stone_shout_SpellScript : public SpellScript + { + PrepareSpellScript(spell_kologarn_stone_shout_SpellScript); + + void FilterTargets(std::list& unitList) + { + unitList.remove_if (PlayerOrPetCheck()); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_kologarn_stone_shout_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_kologarn_stone_shout_SpellScript(); + } +}; + +class spell_kologarn_summon_focused_eyebeam : public SpellScriptLoader +{ + public: + spell_kologarn_summon_focused_eyebeam() : SpellScriptLoader("spell_kologarn_summon_focused_eyebeam") { } + + class spell_kologarn_summon_focused_eyebeam_SpellScript : public SpellScript + { + PrepareSpellScript(spell_kologarn_summon_focused_eyebeam_SpellScript); + + void HandleForceCast(SpellEffIndex eff) + { + PreventHitDefaultEffect(eff); + GetCaster()->CastSpell(GetCaster(), GetSpellInfo()->Effects[eff].TriggerSpell, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_kologarn_summon_focused_eyebeam_SpellScript::HandleForceCast, EFFECT_0, SPELL_EFFECT_FORCE_CAST); + OnEffectHitTarget += SpellEffectFn(spell_kologarn_summon_focused_eyebeam_SpellScript::HandleForceCast, EFFECT_1, SPELL_EFFECT_FORCE_CAST); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_kologarn_summon_focused_eyebeam_SpellScript(); + } +}; + +void AddSC_boss_kologarn() +{ + new boss_kologarn(); + new spell_ulduar_rubble_summon(); + new spell_ulduar_squeezed_lifeless(); + new spell_ulduar_cancel_stone_grip(); + new spell_ulduar_stone_grip_cast_target(); + new spell_ulduar_stone_grip_absorb(); + new spell_ulduar_stone_grip(); + new spell_kologarn_stone_shout(); + new spell_kologarn_summon_focused_eyebeam(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp new file mode 100644 index 00000000000..11b7c54975e --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008-2011 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 "SpellScript.h" +#include "ulduar.h" + +enum Yells +{ + SAY_AGGRO = -1603240, + SAY_HARDMODE_ON = -1603241, + SAY_MKII_ACTIVATE = -1603242, + SAY_MKII_SLAY_1 = -1603243, + SAY_MKII_SLAY_2 = -1603244, + SAY_MKII_DEATH = -1603245, + SAY_VX001_ACTIVATE = -1603246, + SAY_VX001_SLAY_1 = -1603247, + SAY_VX001_SLAY_2 = -1603248, + SAY_VX001_DEATH = -1603249, + SAY_AERIAL_ACTIVATE = -1603250, + SAY_AERIAL_SLAY_1 = -1603251, + SAY_AERIAL_SLAY_2 = -1603252, + SAY_AERIAL_DEATH = -1603253, + SAY_V07TRON_ACTIVATE = -1603254, + SAY_V07TRON_SLAY_1 = -1603255, + SAY_V07TRON_SLAY_2 = -1603256, + SAY_V07TRON_DEATH = -1603257, + SAY_BERSERK = -1603258, + SAY_YS_HELP = -1603259, +}; + +enum Spells +{ + SPELL_JETPACK = 63341, + SPELL_EMERGENCY_MODE = 64582, + SPELL_SELF_REPAIR = 64383, + SPELL_MAGNETIC_CORE = 64444, + // Leviathan MK II + SPELL_FLAME_SUPPRESSANT_MK = 64570, + SPELL_NAPALM_SHELL = 63666, + SPELL_PLASMA_BLAST = 62977, + SPELL_PROXIMITY_MINES = 63027, + SPELL_SHOCK_BLAST = 63631, + // VX 001 + SPELL_FLAME_SUPPRESSANT_VX = 65192, + SPELL_FROSTBOMB = 64623, + SPELL_HAND_PULSE = 64348, + SPELL_SPINNING_UP = 63414, + SPELL_RAPID_BURST = 63387, + SPELL_P3WX2_LASER_BARRAGE = 63293, + SPELL_ROCKET_STRIKE = 63041, + SPELL_HEAT_WAVE = 63677, + // Aerial Command Unit + SPELL_PLASMA_BALL = 63689, + // Additonal spells + SPELL_MAGNETIC_FIELD = 64668, + SPELL_DEAFENING_SIREN = 64616, + SPELL_WATER_SPRAY = 64619, + SPELL_FROST_BOMB_HARD_MODE = 64627, + SPELL_EXPLOSION = 66351, + SPELL_DISARM = 1842, + SPELL_RIDE_VEHICLE = 46598, + SPELL_TRIGGER_MISSILE = 65347, +}; + +enum Npc +{ + NPC_ASSAULT_BOT = 34057, + NPC_BOMB_BOT = 33836, + NPC_JUNK_BOT = 33855, + NPC_EMERGENCE_FIRE_BOT = 34147, + NPC_FROST_BOMB = 34149, +}; + +class spell_ulduar_proximity_mines : public SpellScriptLoader +{ + public: + spell_ulduar_proximity_mines() : SpellScriptLoader("spell_ulduar_proximity_mines") { } + + class spell_ulduar_proximity_minesSpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_proximity_minesSpellScript) + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + for (uint8 i = 0; i < 10; ++i) + GetCaster()->CastSpell(GetCaster(), SPELL_TRIGGER_MISSILE, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_ulduar_proximity_minesSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_ulduar_proximity_minesSpellScript(); + } +}; + +void AddSC_boss_mimiron() +{ + new spell_ulduar_proximity_mines(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp new file mode 100644 index 00000000000..0e3a8926203 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -0,0 +1,1103 @@ +/* +* Copyright (C) 2008-2011 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 . +*/ + +//TODO: Harpoon chain from 62505 should not get removed when other chain is applied + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "ScriptedGossip.h" +#include "SpellScript.h" +#include "ulduar.h" +#include "SpellInfo.h" + +enum Says +{ + SAY_GREET = -1603260, + SAY_GROUND_PHASE = -1603261, + SAY_AGGRO_1 = -1603262, + SAY_AGGRO_2 = -1603263, + SAY_AGGRO_3 = -1603264, + SAY_TURRETS = -1603265, + EMOTE_HARPOON = -1603266, + EMOTE_BREATH = -1603267, + EMOTE_PERMA = -1603268, +}; + +enum Spells +{ + SPELL_FLAMEBUFFET = 64016, + SPELL_FIREBALL = 62796, + SPELL_FLAME_GROUND = 64734, + SPELL_WINGBUFFET = 62666, + SPELL_FLAMEBREATH = 63317, + SPELL_FUSEARMOR = 64771, + SPELL_FLAMED = 62696, + SPELL_STUN = 9032, + SPELL_BERSERK = 47008, + // Additonal Spells + // Devouring Flame Spells + SPELL_DEVOURING_FLAME = 63308, + SPELL_DEVOURING_FLAME_DAMAGE = 64704, + SPELL_DEVOURING_FLAME_TRIGGER = 64709, + // HarpoonSpells + SPELL_HARPOON_TRIGGER = 62505, + SPELL_HARPOON_SHOT_1 = 63658, + SPELL_HARPOON_SHOT_2 = 63657, + SPELL_HARPOON_SHOT_3 = 63659, + SPELL_HARPOON_SHOT_4 = 63524, + // MoleMachine Spells + SPELL_SUMMON_MOLE_MACHINE = 62899, + SPELL_SUMMON_IRON_DWARVES = 63116, + SPELL_SUMMON_IRON_DWARVES_2 = 63114, + SPELL_SUMMON_IRON_DWARVE_GUARDIAN = 62926, + SPELL_SUMMON_IRON_DWARVE_WATCHER = 63135, +}; + +enum NPC +{ + NPC_DARK_RUNE_GUARDIAN = 33388, + NPC_DARK_RUNE_SENTINEL = 33846, + NPC_DARK_RUNE_WATCHER = 33453, + MOLE_MACHINE_TRIGGER = 33245, + NPC_COMMANDER = 33210, + NPC_ENGINEER = 33287, + NPC_DEFENDER = 33816, +}; + +enum DarkRuneSpells +{ + // Dark Rune Watcher + SPELL_CHAIN_LIGHTNING = 64758, + SPELL_LIGHTNING_BOLT = 63809, + // Dark Rune Guardian + SPELL_STORMSTRIKE = 64757, + // Dark Rune Sentinel + SPELL_BATTLE_SHOUT = 46763, + SPELL_HEROIC_STRIKE = 45026, + SPELL_WHIRLWIND = 63807, +}; + +enum Actions +{ + ACTION_EVENT_START = 1, + ACTION_GROUND_PHASE = 2, + ACTION_HARPOON_BUILD = 3, + ACTION_PLACE_BROKEN_HARPOON = 4, + ACTION_COMMANDER_RESET = 7, +}; + +enum Phases +{ + PHASE_PERMAGROUND = 1, + PHASE_GROUND = 2, + PHASE_FLIGHT = 3, +}; + +enum Events +{ + EVENT_BERSERK = 1, + EVENT_BREATH = 2, + EVENT_BUFFET = 3, + EVENT_FIREBALL = 5, + EVENT_FLIGHT = 6, + EVENT_DEVOURING = 7, + EVENT_FLAME = 8, + EVENT_LAND = 9, + EVENT_GROUND = 10, + EVENT_FUSE = 11, + EVENT_SUMMON = 12, + // Razorscale Controller + EVENT_BUILD_HARPOON_1 = 13, + EVENT_BUILD_HARPOON_2 = 14, + EVENT_BUILD_HARPOON_3 = 15, + EVENT_BUILD_HARPOON_4 = 16, +}; + +#define GROUND_Z 391.517f +#define GOSSIP_ITEM_1 "Activate Harpoons!" +#define DATA_QUICK_SHAVE 29192921 // 2919, 2921 are achievement IDs +#define DATA_IRON_DWARF_MEDIUM_RARE 29232924 + +const Position PosEngRepair[4] = +{ + { 590.442f, -130.550f, GROUND_Z, 4.789f }, + { 574.850f, -133.687f, GROUND_Z, 4.252f }, + { 606.567f, -143.369f, GROUND_Z, 4.434f }, + { 560.609f, -142.967f, GROUND_Z, 5.074f }, +}; + +const Position PosDefSpawn[4] = +{ + { 600.75f, -104.850f, GROUND_Z, 0 }, + { 596.38f, -110.262f, GROUND_Z, 0 }, + { 566.47f, -103.633f, GROUND_Z, 0 }, + { 570.41f, -108.791f, GROUND_Z, 0 }, +}; + +const Position PosDefCombat[4] = +{ + { 614.975f, -155.138f, GROUND_Z, 4.154f }, + { 609.814f, -204.968f, GROUND_Z, 5.385f }, + { 563.531f, -201.557f, GROUND_Z, 4.108f }, + { 560.231f, -153.677f, GROUND_Z, 5.403f }, +}; + +const Position PosHarpoon[4] = +{ + { 571.901f, -136.554f, GROUND_Z, 0 }, + { 589.450f, -134.888f, GROUND_Z, 0 }, + { 559.119f, -140.505f, GROUND_Z, 0 }, + { 606.229f, -136.721f, GROUND_Z, 0 }, +}; + +const Position RazorFlight = { 588.050f, -251.191f, 470.536f, 1.498f }; +const Position RazorGround = { 586.966f, -175.534f, GROUND_Z, 4.682f }; +const Position PosEngSpawn = { 591.951f, -95.9680f, GROUND_Z, 0.000f }; + +class boss_razorscale_controller : public CreatureScript +{ + public: + boss_razorscale_controller() : CreatureScript("boss_razorscale_controller") { } + + struct boss_razorscale_controllerAI : public BossAI + { + boss_razorscale_controllerAI(Creature* creature) : BossAI(creature, DATA_RAZORSCALE_CONTROL) + { + me->SetDisplayId(me->GetCreatureInfo()->Modelid2); + } + + void Reset() + { + _Reset(); + me->SetReactState(REACT_PASSIVE); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + switch (spell->Id) + { + case SPELL_FLAMED: + if (GameObject* Harpoon1 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_1))) + Harpoon1->RemoveFromWorld(); + if (GameObject* Harpoon2 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_2))) + Harpoon2->RemoveFromWorld(); + if (GameObject* Harpoon3 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_3))) + Harpoon3->RemoveFromWorld(); + if (GameObject* Harpoon4 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_4))) + Harpoon4->RemoveFromWorld(); + me->AI()->DoAction(ACTION_HARPOON_BUILD); + me->AI()->DoAction(ACTION_PLACE_BROKEN_HARPOON); + break; + case SPELL_HARPOON_SHOT_1: + case SPELL_HARPOON_SHOT_2: + case SPELL_HARPOON_SHOT_3: + case SPELL_HARPOON_SHOT_4: + DoCast(SPELL_HARPOON_TRIGGER); + break; + } + } + + void JustDied(Unit* /*who*/) + { + _JustDied(); + } + + void DoAction(int32 const action) + { + if (instance->GetBossState(BOSS_RAZORSCALE) != IN_PROGRESS) + return; + + switch (action) + { + case ACTION_HARPOON_BUILD: + events.ScheduleEvent(EVENT_BUILD_HARPOON_1, 50000); + if (me->GetMap()->GetSpawnMode() == RAID_DIFFICULTY_25MAN_NORMAL) + events.ScheduleEvent(EVENT_BUILD_HARPOON_3, 90000); + break; + case ACTION_PLACE_BROKEN_HARPOON: + for (uint8 n = 0; n < RAID_MODE(2, 4); n++) + me->SummonGameObject(GO_RAZOR_BROKEN_HARPOON, PosHarpoon[n].GetPositionX(), PosHarpoon[n].GetPositionY(), PosHarpoon[n].GetPositionZ(), 2.286f, 0, 0, 0, 0, 180000); + break; + } + } + + void UpdateAI(uint32 const Diff) + { + events.Update(Diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BUILD_HARPOON_1: + DoScriptText(EMOTE_HARPOON, me); + if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[0].GetPositionX(), PosHarpoon[0].GetPositionY(), PosHarpoon[0].GetPositionZ(), 4.790f, 0.0f, 0.0f, 0.0f, 0.0f, uint32(me->GetRespawnTime()))) + { + if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) //only nearest broken harpoon + BrokenHarpoon->RemoveFromWorld(); + events.ScheduleEvent(EVENT_BUILD_HARPOON_2, 20000); + events.CancelEvent(EVENT_BUILD_HARPOON_1); + } + return; + case EVENT_BUILD_HARPOON_2: + DoScriptText(EMOTE_HARPOON, me); + if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[1].GetPositionX(), PosHarpoon[1].GetPositionY(), PosHarpoon[1].GetPositionZ(), 4.659f, 0, 0, 0, 0, uint32(me->GetRespawnTime()))) + { + if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) + BrokenHarpoon->RemoveFromWorld(); + events.CancelEvent(EVENT_BUILD_HARPOON_2); + } + return; + case EVENT_BUILD_HARPOON_3: + DoScriptText(EMOTE_HARPOON, me); + if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_3, PosHarpoon[2].GetPositionX(), PosHarpoon[2].GetPositionY(), PosHarpoon[2].GetPositionZ(), 5.382f, 0, 0, 0, 0, uint32(me->GetRespawnTime()))) + { + if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) + BrokenHarpoon->RemoveFromWorld(); + events.ScheduleEvent(EVENT_BUILD_HARPOON_4, 20000); + events.CancelEvent(EVENT_BUILD_HARPOON_3); + } + return; + case EVENT_BUILD_HARPOON_4: + DoScriptText(EMOTE_HARPOON, me); + if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_4, PosHarpoon[3].GetPositionX(), PosHarpoon[3].GetPositionY(), PosHarpoon[3].GetPositionZ(), 4.266f, 0, 0, 0, 0, uint32(me->GetRespawnTime()))) + { + if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) + BrokenHarpoon->RemoveFromWorld(); + events.CancelEvent(EVENT_BUILD_HARPOON_4); + } + return; + } + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_razorscale_controllerAI(creature); + } +}; + +class go_razorscale_harpoon : public GameObjectScript +{ + public: + go_razorscale_harpoon() : GameObjectScript("go_razorscale_harpoon") {} + + bool OnGossipHello(Player* /*player*/, GameObject* go) + { + InstanceScript* instance = go->GetInstanceScript(); + if (ObjectAccessor::GetCreature(*go, instance ? instance->GetData64(BOSS_RAZORSCALE) : 0)) + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + return false; + } +}; + +class boss_razorscale : public CreatureScript +{ + public: + boss_razorscale() : CreatureScript("boss_razorscale") { } + + struct boss_razorscaleAI : public BossAI + { + boss_razorscaleAI(Creature* creature) : BossAI(creature, BOSS_RAZORSCALE) + { + // Do not let Razorscale be affected by Battle Shout buff + me->ApplySpellImmune(0, IMMUNITY_ID, (SPELL_BATTLE_SHOUT), true); + } + + Phases phase; + + uint32 EnrageTimer; + uint8 FlyCount; + uint8 HarpoonCounter; + bool PermaGround; + bool Enraged; + + void Reset() + { + _Reset(); + me->SetFlying(true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); + PermaGround = false; + HarpoonCounter = 0; + if (Creature* commander = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_EXPEDITION_COMMANDER) : 0)) + commander->AI()->DoAction(ACTION_COMMANDER_RESET); + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + if (Creature* controller = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_RAZORSCALE_CONTROL) : 0)) + controller->AI()->DoAction(ACTION_HARPOON_BUILD); + me->SetSpeed(MOVE_FLIGHT, 3.0f, true); + me->SetReactState(REACT_PASSIVE); + phase = PHASE_GROUND; + events.SetPhase(PHASE_GROUND); + FlyCount = 0; + EnrageTimer = 600000; + Enraged = false; + events.ScheduleEvent(EVENT_FLIGHT, 0, 0, PHASE_GROUND); + } + + void JustDied(Unit* /*who*/) + { + _JustDied(); + if (Creature* controller = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_RAZORSCALE_CONTROL) : 0)) + controller->AI()->Reset(); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_HARPOON_TRIGGER) + ++HarpoonCounter; + } + + void MovementInform(uint32 type, uint32 id) + { + if (type == POINT_MOTION_TYPE && id == 1) + { + phase = PHASE_GROUND; + events.SetPhase(PHASE_GROUND); + events.ScheduleEvent(EVENT_LAND, 0, 0, PHASE_GROUND); + } + } + + uint32 GetData(uint32 type) + { + if (type == DATA_QUICK_SHAVE) + if (FlyCount <= 2) + return 1; + + return 0; + } + + void UpdateAI(uint32 const Diff) + { + if (!UpdateVictim()) + return; + + events.Update(Diff); + + if (HealthBelowPct(50) && !PermaGround) + EnterPermaGround(); + + if (EnrageTimer <= Diff && !Enraged) + { + DoCast(me, SPELL_BERSERK); + Enraged = true; + } + else + EnrageTimer -= Diff; + + if (HarpoonCounter == RAID_MODE(2, 4)) + { + HarpoonCounter = 0; + me->GetMotionMaster()->MovePoint(1, RazorGround); + } + + if (phase == PHASE_GROUND) + { + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FLIGHT: + phase = PHASE_FLIGHT; + events.SetPhase(PHASE_FLIGHT); + me->SetFlying(true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->GetMotionMaster()->MovePoint(0, RazorFlight); + events.ScheduleEvent(EVENT_FIREBALL, 7000, 0, PHASE_FLIGHT); + events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT); + events.ScheduleEvent(EVENT_SUMMON, 5000, 0, PHASE_FLIGHT); + ++FlyCount; + return; + case EVENT_LAND: + me->SetFlying(false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + if (Creature* commander = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_EXPEDITION_COMMANDER) : 0)) + commander->AI()->DoAction(ACTION_GROUND_PHASE); + events.ScheduleEvent(EVENT_BREATH, 30000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_BUFFET, 33000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_FLIGHT, 35000, 0, PHASE_GROUND); + return; + case EVENT_BREATH: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + me->RemoveAllAuras(); + me->SetReactState(REACT_AGGRESSIVE); + DoScriptText(EMOTE_BREATH, me, 0); + DoCastAOE(SPELL_FLAMEBREATH); + events.CancelEvent(EVENT_BREATH); + return; + case EVENT_BUFFET: + DoCastAOE(SPELL_WINGBUFFET); + if (Creature* controller = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_RAZORSCALE_CONTROL) : 0)) + controller->CastSpell(controller, SPELL_FLAMED, true); + events.CancelEvent(EVENT_BUFFET); + return; + } + } + } + if (phase == PHASE_PERMAGROUND) + { + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FLAME: + DoCastAOE(SPELL_FLAMEBUFFET); + events.ScheduleEvent(EVENT_FLAME, 10000, 0, PHASE_PERMAGROUND); + return; + case EVENT_BREATH: + me->MonsterTextEmote(EMOTE_BREATH, 0, true); + DoCastVictim(SPELL_FLAMEBREATH); + events.ScheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND); + return; + case EVENT_FIREBALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) + DoCast(target, SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND); + return; + case EVENT_DEVOURING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) + DoCast(target, SPELL_DEVOURING_FLAME); + events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_PERMAGROUND); + return; + case EVENT_BUFFET: + DoCastAOE(SPELL_WINGBUFFET); + events.CancelEvent(EVENT_BUFFET); + return; + case EVENT_FUSE: + DoCast(me->getVictim(), SPELL_FUSEARMOR); + events.ScheduleEvent(EVENT_FUSE, 10000, 0, PHASE_PERMAGROUND); + return; + } + } + + DoMeleeAttackIfReady(); + } + else + { + if (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FIREBALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) + DoCast(target, SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_FLIGHT); + return; + case EVENT_DEVOURING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) + me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_DEVOURING_FLAME, true); + events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT); + return; + case EVENT_SUMMON: + SummonMoleMachines(); + events.ScheduleEvent(EVENT_SUMMON, 45000, 0, PHASE_FLIGHT); + return; + } + } + } + } + + void EnterPermaGround() + { + me->MonsterTextEmote(EMOTE_PERMA, 0, true); + phase = PHASE_PERMAGROUND; + events.SetPhase(PHASE_PERMAGROUND); + me->SetFlying(false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveAurasDueToSpell(SPELL_HARPOON_TRIGGER); + me->SetSpeed(MOVE_FLIGHT, 1.0f, true); + PermaGround = true; + DoCastAOE(SPELL_FLAMEBREATH); + events.ScheduleEvent(EVENT_FLAME, 15000, 0, PHASE_PERMAGROUND); + events.RescheduleEvent(EVENT_DEVOURING, 15000, 0, PHASE_PERMAGROUND); + events.RescheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND); + events.RescheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND); + events.RescheduleEvent(EVENT_DEVOURING, 6000, 0, PHASE_PERMAGROUND); + events.RescheduleEvent(EVENT_BUFFET, 2500, 0, PHASE_PERMAGROUND); + events.RescheduleEvent(EVENT_FUSE, 5000, 0, PHASE_PERMAGROUND); + } + + void SummonMoleMachines() + { + // Adds will come in waves from mole machines. One mole can spawn a Dark Rune Watcher + // with 1-2 Guardians, or a lone Sentinel. Up to 4 mole machines can spawn adds at any given time. + uint8 random = urand(2, 4); + for (uint8 n = 0; n < random; n++) + { + float x = float(irand(540, 640)); // Safe range is between 500 and 650 + float y = float(irand(-230, -195)); // Safe range is between -235 and -145 + float z = GROUND_Z; // Ground level + me->SummonCreature(MOLE_MACHINE_TRIGGER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); + } + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_EVENT_START: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(me, 150.0f); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } +}; + +class npc_expedition_commander : public CreatureScript +{ + public: + npc_expedition_commander() : CreatureScript("npc_expedition_commander") { } + + struct npc_expedition_commanderAI : public ScriptedAI + { + npc_expedition_commanderAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + Greet = false; + } + + InstanceScript* instance; + std::list summons; + + bool Greet; + uint32 AttackStartTimer; + uint8 Phase; + Creature* Engineer[4]; + Creature* Defender[4]; + + void Reset() + { + AttackStartTimer = 0; + Phase = 0; + Greet = false; + summons.clear(); + } + + void MoveInLineOfSight(Unit* who) + { + if (!Greet && me->IsWithinDistInMap(who, 10.0f) && who->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_GREET, me); + Greet = true; + } + } + + void JustSummoned(Creature* summoned) + { + summons.push_back(summoned->GetGUID()); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_GROUND_PHASE: + DoScriptText(SAY_GROUND_PHASE, me); + break; + case ACTION_COMMANDER_RESET: + summons.clear(); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + } + } + + void UpdateAI(uint32 const Diff) + { + if (AttackStartTimer <= Diff) + { + switch (Phase) + { + case 1: + instance->SetBossState(BOSS_RAZORSCALE, IN_PROGRESS); + summons.clear(); + AttackStartTimer = 1000; + Phase = 2; + break; + case 2: + for (uint8 n = 0; n < RAID_MODE(2, 4); n++) + { + Engineer[n] = me->SummonCreature(NPC_ENGINEER, PosEngSpawn, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + Engineer[n]->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + Engineer[n]->SetSpeed(MOVE_RUN, 0.5f); + Engineer[n]->SetHomePosition(PosEngRepair[n]); + Engineer[n]->GetMotionMaster()->MoveTargetedHome(); + } + Engineer[0]->MonsterYell(SAY_AGGRO_3, LANG_UNIVERSAL, 0); + Phase = 3; + AttackStartTimer = 14000; + break; + case 3: + for (uint8 n = 0; n < 4; n++) + { + Defender[n] = me->SummonCreature(NPC_DEFENDER, PosDefSpawn[n], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + Defender[n]->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + Defender[n]->SetHomePosition(PosDefCombat[n]); + Defender[n]->GetMotionMaster()->MoveTargetedHome(); + } + Phase = 4; + break; + case 4: + for (uint8 n = 0; n < RAID_MODE(2, 4); n++) + Engineer[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USESTANDING); + for (uint8 n = 0; n < 4; ++n) + Defender[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); + me->MonsterYell(SAY_AGGRO_2, LANG_UNIVERSAL, 0); + AttackStartTimer = 16000; + Phase = 5; + break; + case 5: + if (Creature* Razorscale = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_RAZORSCALE) : 0)) + { + Razorscale->AI()->DoAction(ACTION_EVENT_START); + me->SetInCombatWith(Razorscale); + } + Engineer[0]->MonsterYell(SAY_AGGRO_1, LANG_UNIVERSAL, 0); + Phase = 6; + break; + } + } + else + AttackStartTimer -= Diff; + } + }; + + bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) + { + player->PlayerTalkClass->ClearMenus(); + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->CLOSE_GOSSIP_MENU(); + CAST_AI(npc_expedition_commanderAI, creature->AI())->Phase = 1; + break; + } + return true; + } + + bool OnGossipHello(Player* player, Creature* creature) + { + InstanceScript* instance = creature->GetInstanceScript(); + if (instance && instance->GetBossState(BOSS_RAZORSCALE) == NOT_STARTED) + { + player->PrepareGossipMenu(creature); + + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(13853, creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(13910, creature->GetGUID()); + + return true; + } + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_expedition_commanderAI(creature); + } +}; + +class npc_mole_machine_trigger : public CreatureScript +{ + public: + npc_mole_machine_trigger() : CreatureScript("npc_mole_machine_trigger") { } + + struct npc_mole_machine_triggerAI : public Scripted_NoMovementAI + { + npc_mole_machine_triggerAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); + } + + uint32 SummonGobTimer; + uint32 SummonNpcTimer; + uint32 DissapearTimer; + bool GobSummoned; + bool NpcSummoned; + + void Reset() + { + SummonGobTimer = 2000; + SummonNpcTimer = 6000; + DissapearTimer = 10000; + GobSummoned = false; + NpcSummoned = false; + } + + void UpdateAI(uint32 const Diff) + { + if (!GobSummoned && SummonGobTimer <= Diff) + { + DoCast(SPELL_SUMMON_MOLE_MACHINE); + GobSummoned = true; + } + else + SummonGobTimer -= Diff; + + if (!NpcSummoned && SummonNpcTimer <= Diff) + { + switch (urand(0, 1 )) + { + case 0: + DoCast(SPELL_SUMMON_IRON_DWARVES); + break; + case 1: + DoCast(SPELL_SUMMON_IRON_DWARVES_2); + break; + } + + DoCast(SPELL_SUMMON_IRON_DWARVE_GUARDIAN); + DoCast(SPELL_SUMMON_IRON_DWARVE_WATCHER); + NpcSummoned = true; + } + else + SummonNpcTimer -= Diff; + + if (DissapearTimer <= Diff) + { + if (GameObject* molemachine = me->FindNearestGameObject(GO_MOLE_MACHINE, 1)) + molemachine->Delete(); + + me->DisappearAndDie(); + } + else + DissapearTimer -= Diff; + } + + void JustSummoned(Creature* summoned) + { + summoned->AI()->DoZoneInCombat(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_mole_machine_triggerAI(creature); + } +}; + +class npc_devouring_flame : public CreatureScript +{ + public: + npc_devouring_flame() : CreatureScript("npc_devouring_flame") { } + + struct npc_devouring_flameAI : public Scripted_NoMovementAI + { + npc_devouring_flameAI(Creature* creature) : Scripted_NoMovementAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); + } + + void Reset() + { + DoCast(SPELL_FLAME_GROUND); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_devouring_flameAI(creature); + } +}; + +class npc_darkrune_watcher : public CreatureScript +{ + public: + npc_darkrune_watcher() : CreatureScript("npc_darkrune_watcher") { } + + struct npc_darkrune_watcherAI : public ScriptedAI + { + npc_darkrune_watcherAI(Creature* creature) : ScriptedAI(creature){} + + uint32 ChainTimer; + uint32 LightTimer; + + void Reset() + { + ChainTimer = urand(10000, 15000); + LightTimer = urand(1000, 3000); + } + + void UpdateAI(uint32 const Diff) + { + if (!UpdateVictim()) + return; + + if (ChainTimer <= Diff) + { + DoCast(me->getVictim(), SPELL_CHAIN_LIGHTNING); + ChainTimer = urand(10000, 15000); + } + else + ChainTimer -= Diff; + + if (LightTimer <= Diff) + { + DoCastVictim(SPELL_LIGHTNING_BOLT); + LightTimer = urand(5000, 7000); + } + else + LightTimer -= Diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_darkrune_watcherAI(creature); + } +}; + +class npc_darkrune_guardian : public CreatureScript +{ + public: + npc_darkrune_guardian() : CreatureScript("npc_darkrune_guardian") { } + + struct npc_darkrune_guardianAI : public ScriptedAI + { + npc_darkrune_guardianAI(Creature* creature) : ScriptedAI(creature){} + + uint32 StormTimer; + + void Reset() + { + StormTimer = urand(3000, 6000); + killedByBreath = false; + } + + uint32 GetData(uint32 type) + { + return type == DATA_IRON_DWARF_MEDIUM_RARE ? killedByBreath : 0; + } + + void SetData(uint32 type, uint32 value) + { + if (type == DATA_IRON_DWARF_MEDIUM_RARE) + killedByBreath = value; + } + + + void UpdateAI(uint32 const Diff) + { + if (!UpdateVictim()) + return; + + if (StormTimer <= Diff) + { + DoCast(me->getVictim(), SPELL_STORMSTRIKE); + StormTimer = urand(4000, 8000); + } + else + StormTimer -= Diff; + + DoMeleeAttackIfReady(); + } + + private: + bool killedByBreath; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_darkrune_guardianAI(creature); + } +}; + +class npc_darkrune_sentinel : public CreatureScript +{ + public: + npc_darkrune_sentinel() : CreatureScript("npc_darkrune_sentinel") { } + + struct npc_darkrune_sentinelAI : public ScriptedAI + { + npc_darkrune_sentinelAI(Creature* creature) : ScriptedAI(creature){} + + uint32 HeroicTimer; + uint32 WhirlTimer; + uint32 ShoutTimer; + + void Reset() + { + HeroicTimer = urand(4000, 8000); + WhirlTimer = urand(20000, 25000); + ShoutTimer = urand(15000, 30000); + } + + void UpdateAI(uint32 const Diff) + { + if (!UpdateVictim()) + return; + + if (HeroicTimer <= Diff) + { + DoCast(me->getVictim(), SPELL_HEROIC_STRIKE); + HeroicTimer = urand(4000, 6000); + } + else + HeroicTimer -= Diff; + + if (WhirlTimer <= Diff) + { + DoCast(me->getVictim(), SPELL_WHIRLWIND); + WhirlTimer = urand(20000, 25000); + } + else + WhirlTimer -= Diff; + + if (ShoutTimer <= Diff) + { + DoCast(me, SPELL_BATTLE_SHOUT); + ShoutTimer = urand(30000, 40000); + } + else + ShoutTimer -= Diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_darkrune_sentinelAI(creature); + } +}; + +class spell_razorscale_devouring_flame : public SpellScriptLoader +{ + public: + spell_razorscale_devouring_flame() : SpellScriptLoader("spell_razorscale_devouring_flame") { } + + class spell_razorscale_devouring_flame_SpellScript : public SpellScript + { + PrepareSpellScript(spell_razorscale_devouring_flame_SpellScript); + + void HandleSummon(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Unit* caster = GetCaster(); + uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue); + WorldLocation const* summonLocation = GetTargetDest(); + if (!caster || !summonLocation) + return; + + caster->SummonCreature(entry, summonLocation->GetPositionX(), summonLocation->GetPositionY(), GROUND_Z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_razorscale_devouring_flame_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_razorscale_devouring_flame_SpellScript(); + } +}; + +class spell_razorscale_flame_breath : public SpellScriptLoader +{ + public: + spell_razorscale_flame_breath() : SpellScriptLoader("spell_razorscale_flame_breath") { } + + class spell_razorscale_flame_breath_SpellScript : public SpellScript + { + PrepareSpellScript(spell_razorscale_flame_breath_SpellScript); + + void CheckDamage() + { + Creature* target = GetHitCreature(); + if (!target || target->GetEntry() != NPC_DARK_RUNE_GUARDIAN) + return; + + if (GetHitDamage() >= int32(target->GetHealth())) + target->AI()->SetData(DATA_IRON_DWARF_MEDIUM_RARE, 1); + } + + void Register() + { + OnHit += SpellHitFn(spell_razorscale_flame_breath_SpellScript::CheckDamage); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_razorscale_flame_breath_SpellScript(); + } +}; + +class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript +{ + public: + achievement_iron_dwarf_medium_rare() : AchievementCriteriaScript("achievement_iron_dwarf_medium_rare") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_IRON_DWARF_MEDIUM_RARE); + } +}; + +class achievement_quick_shave : public AchievementCriteriaScript +{ + public: + achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (target) + if (Creature* razorscale = target->ToCreature()) + if (razorscale->AI()->GetData(DATA_QUICK_SHAVE)) + return true; + + return false; + } +}; + +void AddSC_boss_razorscale() +{ + new boss_razorscale_controller(); + new go_razorscale_harpoon(); + new boss_razorscale(); + new npc_expedition_commander(); + new npc_mole_machine_trigger(); + new npc_devouring_flame(); + new npc_darkrune_watcher(); + new npc_darkrune_guardian(); + new npc_darkrune_sentinel(); + new spell_razorscale_devouring_flame(); + new spell_razorscale_flame_breath(); + new achievement_iron_dwarf_medium_rare(); + new achievement_quick_shave(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp new file mode 100644 index 00000000000..f993c419b8c --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008-2011 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 "ulduar.h" + +enum Yells +{ + SAY_AGGRO_1 = -1603270, + SAY_AGGRO_2 = -1603271, + SAY_SPECIAL_1 = -1603272, + SAY_SPECIAL_2 = -1603273, + SAY_SPECIAL_3 = -1603274, + SAY_JUMPDOWN = -1603275, + SAY_SLAY_1 = -1603276, + SAY_SLAY_2 = -1603277, + SAY_BERSERK = -1603278, + SAY_WIPE = -1603279, + SAY_DEATH = -1603280, + SAY_END_NORMAL_1 = -1603281, + SAY_END_NORMAL_2 = -1603282, + SAY_END_NORMAL_3 = -1603283, + SAY_END_HARD_1 = -1603284, + SAY_END_HARD_2 = -1603285, + SAY_END_HARD_3 = -1603286, + SAY_YS_HELP = -1603287, +}; + +class boss_thorim : public CreatureScript +{ +public: + boss_thorim() : CreatureScript("boss_thorim") { } + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } + + struct boss_thorimAI : public BossAI + { + boss_thorimAI(Creature* creature) : BossAI(creature, BOSS_THORIM) + { + } + + void Reset() + { + _Reset(); + } + + void EnterEvadeMode() + { + DoScriptText(SAY_WIPE, me); + _EnterEvadeMode(); + } + + void KilledUnit(Unit* /*victim*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void JustDied(Unit* /*victim*/) + { + DoScriptText(SAY_DEATH, me); + _JustDied(); + } + + void EnterCombat(Unit* /*who*/) + { + DoScriptText(RAND(SAY_AGGRO_1, SAY_AGGRO_2), me); + _EnterCombat(); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + //SPELLS TODO: + + // + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(diff); + } + }; + +}; + +void AddSC_boss_thorim() +{ + new boss_thorim(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp new file mode 100644 index 00000000000..ae803b24642 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -0,0 +1,1091 @@ +/* + * Copyright (C) 2008-2011 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 . + */ + +/* + TODO: + Fix void zone damage + If the boss is to close to a scrap pile -> no summon -- Needs retail confirmation + make the life sparks visible... /? Need test + Codestyle +*/ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "ulduar.h" +#include "Vehicle.h" + +enum Spells +{ + SPELL_TYMPANIC_TANTRUM = 62776, + SPELL_SEARING_LIGHT_10 = 63018, + SPELL_SEARING_LIGHT_25 = 65121, + + SPELL_SUMMON_LIFE_SPARK = 64210, + SPELL_SUMMON_VOID_ZONE = 64203, + + SPELL_GRAVITY_BOMB_10 = 63024, + SPELL_GRAVITY_BOMB_25 = 64234, + + SPELL_HEARTBREAK_10 = 65737, + SPELL_HEARTBREAK_25 = 64193, + + // Cast by 33337 at Heartbreak: + SPELL_RECHARGE_PUMMELER = 62831, // Summons 33344 + SPELL_RECHARGE_SCRAPBOT = 62828, // Summons 33343 + SPELL_RECHARGE_BOOMBOT = 62835, // Summons 33346 + + // Cast by 33329 on 33337 (visual?) + SPELL_ENERGY_ORB = 62790, // Triggers 62826 - needs spellscript for periodic tick to cast one of the random spells above + + SPELL_HEART_HEAL_TO_FULL = 17683, + SPELL_HEART_OVERLOAD = 62789, + + SPELL_HEART_LIGHTNING_TETHER = 64799, // Cast on self? + SPELL_HEART_RIDE_VEHICLE = 63313, + SPELL_ENRAGE = 26662, + SPELL_STAND = 37752, + SPELL_SUBMERGE = 37751, + + //------------------VOID ZONE-------------------- + SPELL_VOID_ZONE_10 = 64203, + SPELL_VOID_ZONE_25 = 64235, + + // Life Spark + SPELL_STATIC_CHARGED_10 = 64227, + SPELL_STATIC_CHARGED_25 = 64236, + SPELL_SHOCK = 64230, + + //----------------XT-002 HEART------------------- + SPELL_EXPOSED_HEART = 63849, + // Channeled + + //---------------XM-024 PUMMELLER---------------- + SPELL_ARCING_SMASH = 8374, + SPELL_TRAMPLE = 5568, + SPELL_UPPERCUT = 10966, + + // Scrabot: + SPELL_SCRAPBOT_RIDE_VEHICLE = 47020, + SPELL_SUICIDE = 7, + + //------------------BOOMBOT----------------------- + SPELL_AURA_BOOMBOT = 65032, + SPELL_BOOM = 62834, + + // Achievement-related spells + SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS = 65037 +}; + +enum Events +{ + EVENT_TYMPANIC_TANTRUM = 1, + EVENT_SEARING_LIGHT, + EVENT_GRAVITY_BOMB, + EVENT_HEART_PHASE, + EVENT_ENERGY_ORB, + EVENT_DISPOSE_HEART, + EVENT_ENRAGE, + EVENT_ENTER_HARD_MODE, +}; + +enum Timers +{ + TIMER_TYMPANIC_TANTRUM_MIN = 32000, + TIMER_TYMPANIC_TANTRUM_MAX = 36000, + TIMER_SEARING_LIGHT = 20000, + TIMER_GRAVITY_BOMB = 20000, + TIMER_HEART_PHASE = 30000, + TIMER_ENERGY_ORB_MIN = 9000, + TIMER_ENERGY_ORB_MAX = 10000, + TIMER_ENRAGE = 600000, + + TIMER_VOID_ZONE = 3000, + + // Life Spark + TIMER_SHOCK = 12000, + + // Pummeller + // Timers may be off + TIMER_ARCING_SMASH = 27000, + TIMER_TRAMPLE = 22000, + TIMER_UPPERCUT = 17000, + + TIMER_SPAWN_ADD = 12000, +}; + +enum Creatures +{ + NPC_VOID_ZONE = 34001, + NPC_LIFE_SPARK = 34004, + NPC_XT002_HEART = 33329, + NPC_XS013_SCRAPBOT = 33343, + NPC_XM024_PUMMELLER = 33344, + NPC_XE321_BOOMBOT = 33346, +}; + +enum Actions +{ + ACTION_ENTER_HARD_MODE, +}; + +enum XT002Data +{ + DATA_TRANSFERED_HEALTH, + DATA_HARD_MODE, + DATA_HEALTH_RECOVERED, + DATA_GRAVITY_BOMB_CASUALTY, +}; + +enum Yells +{ + SAY_AGGRO = -1603300, + SAY_HEART_OPENED = -1603301, + SAY_HEART_CLOSED = -1603302, + SAY_TYMPANIC_TANTRUM = -1603303, + SAY_SLAY_1 = -1603304, + SAY_SLAY_2 = -1603305, + SAY_BERSERK = -1603306, + SAY_DEATH = -1603307, + SAY_SUMMON = -1603308, +}; + +enum AchievementCredits +{ + ACHIEV_MUST_DECONSTRUCT_FASTER = 21027, +}; + +#define HEART_VEHICLE_SEAT 0 + +/*------------------------------------------------------- + * + * XT-002 DECONSTRUCTOR + * + *///---------------------------------------------------- +class boss_xt002 : public CreatureScript +{ + public: + boss_xt002() : CreatureScript("boss_xt002") { } + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI(creature); + } + + struct boss_xt002_AI : public BossAI + { + boss_xt002_AI(Creature* creature) : BossAI(creature, BOSS_XT002) + { + } + + void Reset() + { + _Reset(); + + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + _healthRecovered = false; + _gravityBombCasualty = false; + _hardMode = false; + + _phase = 1; + _heartExposed = 0; + + if (!instance) + return; + + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); + } + + void EnterCombat(Unit* /*who*/) + { + DoScriptText(SAY_AGGRO, me); + _EnterCombat(); + + events.ScheduleEvent(EVENT_ENRAGE, TIMER_ENRAGE); + events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); + events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT); + //Tantrum is casted a bit slower the first time. + events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX) * 2); + + if (!instance) + return; + + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); + } + + void DoAction(const int32 action) + { + switch (action) + { + case ACTION_ENTER_HARD_MODE: + events.ScheduleEvent(EVENT_ENTER_HARD_MODE, 1); + break; + } + } + + void KilledUnit(Unit* /*victim*/) + { + DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); + } + + void JustDied(Unit* /*victim*/) + { + DoScriptText(SAY_DEATH, me); + _JustDied(); + } + + void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) + { + if (!_hardMode && _phase == 1 && !HealthAbovePct(100 - 25 * (_heartExposed+1))) + ExposeHeart(); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SEARING_LIGHT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25)); + + events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT); + break; + case EVENT_GRAVITY_BOMB: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25)); + + events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); + break; + case EVENT_TYMPANIC_TANTRUM: + DoScriptText(SAY_TYMPANIC_TANTRUM, me); + DoCast(SPELL_TYMPANIC_TANTRUM); + events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)); + break; + case EVENT_DISPOSE_HEART: + SetPhaseOne(); + break; + case EVENT_ENRAGE: + DoScriptText(SAY_BERSERK, me); + DoCast(me, SPELL_ENRAGE); + break; + case EVENT_ENTER_HARD_MODE: + me->SetFullHealth(); + DoCast(me, RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25), true); + me->AddLootMode(LOOT_MODE_HARD_MODE_1); + _hardMode = true; + SetPhaseOne(); + break; + } + } + + if (_phase == 1) + DoMeleeAttackIfReady(); + } + + void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) + { + if (apply && who->GetEntry() == NPC_XS013_SCRAPBOT) + { + // Need this so we can properly determine when to expose heart again in damagetaken hook + if (me->GetHealthPct() > (25 * (4 - _heartExposed))) + ++_heartExposed; + + _healthRecovered = true; + } + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_HARD_MODE: + return _hardMode ? 1 : 0; + case DATA_HEALTH_RECOVERED: + return _healthRecovered ? 1 : 0; + case DATA_GRAVITY_BOMB_CASUALTY: + return _gravityBombCasualty ? 1 : 0; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch (type) + { + case DATA_TRANSFERED_HEALTH: + _transferHealth = data; + break; + case DATA_GRAVITY_BOMB_CASUALTY: + _gravityBombCasualty = (data > 0) ? true : false; + break; + } + } + + void ExposeHeart() + { + DoScriptText(SAY_HEART_OPENED, me); + + DoCast(me, SPELL_SUBMERGE); // WIll make creature untargetable + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + + Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : NULL; + if (heart) + { + heart->CastSpell(heart, SPELL_HEART_OVERLOAD, false); + heart->CastSpell(me, SPELL_HEART_LIGHTNING_TETHER, false); + heart->CastSpell(heart, SPELL_HEART_HEAL_TO_FULL, true); + heart->CastSpell(heart, SPELL_EXPOSED_HEART, false); // Channeled + + heart->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + } + + events.CancelEvent(EVENT_SEARING_LIGHT); + events.CancelEvent(EVENT_GRAVITY_BOMB); + events.CancelEvent(EVENT_TYMPANIC_TANTRUM); + + // Start "end of phase 2 timer" + events.ScheduleEvent(EVENT_DISPOSE_HEART, TIMER_HEART_PHASE); + + // Phase 2 has officially started + _phase = 2; + _heartExposed++; + } + + void SetPhaseOne() + { + DoScriptText(SAY_HEART_CLOSED, me); + + DoCast(me, SPELL_STAND); + me->SetReactState(REACT_AGGRESSIVE); + + _phase = 1; + + events.RescheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT / 2); + events.RescheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); + events.RescheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)); + + Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : NULL; + if (!heart) + return; + + heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + heart->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART); + + if (!_hardMode) + { + if (!_transferHealth) + _transferHealth = (heart->GetMaxHealth() - heart->GetHealth()); + + me->ModifyHealth(-((int32)_transferHealth)); + } + } + + private: + // Achievement related + bool _healthRecovered; // Did a scrapbot recover XT-002's health during the encounter? + bool _hardMode; // Are we in hard mode? Or: was the heart killed during phase 2? + bool _gravityBombCasualty; // Did someone die because of Gravity Bomb damage? + + uint8 _phase; + uint8 _heartExposed; + uint32 _transferHealth; + }; +}; + +/*------------------------------------------------------- + * + * XT-002 HEART + * + *///---------------------------------------------------- +class mob_xt002_heart : public CreatureScript +{ + public: + mob_xt002_heart() : CreatureScript("mob_xt002_heart") { } + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_xt002_heartAI(creature); + } + + struct mob_xt002_heartAI : public ScriptedAI + { + mob_xt002_heartAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); + } + + void DamageTaken(Unit* /*pDone*/, uint32 &damage) + { + Creature* xt002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002)); + if (!xt002 || !xt002->AI()) + return; + + if (damage >= me->GetHealth()) + { + xt002->AI()->SetData(DATA_TRANSFERED_HEALTH, me->GetMaxHealth()); + xt002->AI()->DoAction(ACTION_ENTER_HARD_MODE); + damage = 0; + } + } + + private: + InstanceScript* _instance; + uint32 _damageTaken; + }; +}; + +/*------------------------------------------------------- + * + * XS-013 SCRAPBOT + * + *///---------------------------------------------------- +class mob_scrapbot : public CreatureScript +{ + public: + mob_scrapbot() : CreatureScript("mob_scrapbot") { } + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_scrapbotAI(creature); + } + + struct mob_scrapbotAI : public ScriptedAI + { + mob_scrapbotAI(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + } + + void Reset() + { + me->SetReactState(REACT_PASSIVE); + + _rangeCheckTimer = 500; + + if (Creature* pXT002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) + me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + } + + void UpdateAI(const uint32 diff) + { + if (_rangeCheckTimer <= diff) + { + if (Creature* xt002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) + { + if (me->IsWithinMeleeRange(xt002)) + { + DoCast(xt002, SPELL_SCRAPBOT_RIDE_VEHICLE); + // Unapply vehicle aura again + xt002->RemoveAurasDueToSpell(SPELL_SCRAPBOT_RIDE_VEHICLE); + me->DespawnOrUnsummon(); + } + } + } + else + _rangeCheckTimer -= diff; + } + + private: + InstanceScript* _instance; + uint32 _rangeCheckTimer; + }; +}; + +/*------------------------------------------------------- + * + * XM-024 PUMMELLER + * + *///---------------------------------------------------- +class mob_pummeller : public CreatureScript +{ + public: + mob_pummeller() : CreatureScript("mob_pummeller") { } + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_pummellerAI(creature); + } + + struct mob_pummellerAI : public ScriptedAI + { + mob_pummellerAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() + { + _arcingSmashTimer = TIMER_ARCING_SMASH; + _trampleTimer = TIMER_TRAMPLE; + _uppercutTimer = TIMER_UPPERCUT; + + if (Creature* xt002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) + { + Position pos; + xt002->GetPosition(&pos); + me->GetMotionMaster()->MovePoint(0, pos); + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (me->IsWithinMeleeRange(me->getVictim())) + { + if (_arcingSmashTimer <= diff) + { + DoCast(me->getVictim(), SPELL_ARCING_SMASH); + _arcingSmashTimer = TIMER_ARCING_SMASH; + } + else + _arcingSmashTimer -= diff; + + if (_trampleTimer <= diff) + { + DoCast(me->getVictim(), SPELL_TRAMPLE); + _trampleTimer = TIMER_TRAMPLE; + } + else + _trampleTimer -= diff; + + if (_uppercutTimer <= diff) + { + DoCast(me->getVictim(), SPELL_UPPERCUT); + _uppercutTimer = TIMER_UPPERCUT; + } + else + _uppercutTimer -= diff; + } + + DoMeleeAttackIfReady(); + } + + private: + InstanceScript* _instance; + uint32 _arcingSmashTimer; + uint32 _trampleTimer; + uint32 _uppercutTimer; + }; +}; + +/*------------------------------------------------------- + * + * XE-321 BOOMBOT + * + *///---------------------------------------------------- +class BoomEvent : public BasicEvent +{ + public: + BoomEvent(Creature* me) : _me(me) + { + } + + bool Execute(uint64 /*time*/, uint32 /*diff*/) + { + // This hack is here because we suspect our implementation of spell effect execution on targets + // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets, + // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc. + // The above situation causes the visual for this spell to be bugged, so we remove the instakill + // effect and implement a script hack for that. + + _me->CastSpell(_me, SPELL_BOOM, false); + return true; + } + + private: + Creature* _me; +}; + +class mob_boombot : public CreatureScript +{ + public: + mob_boombot() : CreatureScript("mob_boombot") { } + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_boombotAI(creature); + } + + struct mob_boombotAI : public ScriptedAI + { + mob_boombotAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() + { + _boomed = false; + + DoCast(SPELL_AURA_BOOMBOT); // For achievement + + // HACK/workaround: + // these values aren't confirmed - lack of data - and the values in DB are incorrect + // these values are needed for correct damage of Boom spell + me->SetFloatValue(UNIT_FIELD_MINDAMAGE, 15000.0f); + me->SetFloatValue(UNIT_FIELD_MAXDAMAGE, 18000.0f); + + // Todo: proper waypoints? + if (Creature* pXT002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) + me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + } + + void DamageTaken(Unit* /*who*/, uint32& damage) + { + if (damage >= (me->GetHealth() - me->GetMaxHealth() * 0.5f) && !_boomed) + { + _boomed = true; // Prevent recursive calls + + WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8+8+4); + data << uint64(me->GetGUID()); + data << uint64(me->GetGUID()); + data << uint32(SPELL_BOOM); + me->SendMessageToSet(&data, false); + + me->DealDamage(me, me->GetHealth(), NULL, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + damage = 0; + + // Visual only seems to work if the instant kill event is delayed or the spell itself is delayed + // Casting done from player and caster source has the same targetinfo flags, + // so that can't be the issue + // See BoomEvent class + // Schedule 1s delayed + me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1*IN_MILLISECONDS)); + } + } + + void UpdateAI(uint32 const /*diff*/) + { + if (!UpdateVictim()) + return; + + // No melee attack + } + + private: + InstanceScript* _instance; + bool _boomed; + }; +}; + + +/*------------------------------------------------------- + * + * LIFE SPARK + * + *///---------------------------------------------------- +class mob_life_spark : public CreatureScript +{ + public: + mob_life_spark() : CreatureScript("mob_life_spark") { } + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_life_sparkAI(creature); + } + + struct mob_life_sparkAI : public ScriptedAI + { + mob_life_sparkAI(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() + { + DoCast(me, RAID_MODE(SPELL_STATIC_CHARGED_10, SPELL_STATIC_CHARGED_25)); + _shockTimer = 0; // first one is immediate. + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (_shockTimer <= diff) + { + if (me->IsWithinMeleeRange(me->getVictim())) + { + DoCast(me->getVictim(), SPELL_SHOCK); + _shockTimer = TIMER_SHOCK; + } + } + else _shockTimer -= diff; + } + + private: + uint32 _shockTimer; + }; +}; + +class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader +{ + public: + spell_xt002_searing_light_spawn_life_spark() : SpellScriptLoader("spell_xt002_searing_light_spawn_life_spark") { } + + class spell_xt002_searing_light_spawn_life_spark_AuraScript : public AuraScript + { + PrepareAuraScript(spell_xt002_searing_light_spawn_life_spark_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_LIFE_SPARK)) + return false; + return true; + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetOwner()->ToPlayer()) + if (Unit* xt002 = GetCaster()) + if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode + player->CastSpell(player, SPELL_SUMMON_LIFE_SPARK, true); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_xt002_searing_light_spawn_life_spark_AuraScript(); + } +}; + +class spell_xt002_gravity_bomb_aura : public SpellScriptLoader +{ + public: + spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { } + + class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_VOID_ZONE)) + return false; + return true; + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetOwner()->ToPlayer()) + if (Unit* xt002 = GetCaster()) + if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode + player->CastSpell(player, SPELL_SUMMON_VOID_ZONE, true); + } + + void OnPeriodic(AuraEffect const* aurEff) + { + Unit* xt002 = GetCaster(); + if (!xt002) + return; + + Unit* owner = GetOwner()->ToUnit(); + if (!owner) + return; + + if (aurEff->GetAmount() >= int32(owner->GetHealth())) + if (xt002->GetAI()) + xt002->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE); + AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_xt002_gravity_bomb_aura_AuraScript(); + } +}; + +class spell_xt002_gravity_bomb_damage : public SpellScriptLoader +{ + public: + spell_xt002_gravity_bomb_damage() : SpellScriptLoader("spell_xt002_gravity_bomb_damage") { } + + class spell_xt002_gravity_bomb_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_gravity_bomb_damage_SpellScript); + + void HandleScript(SpellEffIndex /*eff*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + if (GetHitDamage() >= int32(GetHitUnit()->GetHealth())) + if (caster->GetAI()) + caster->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_xt002_gravity_bomb_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_xt002_gravity_bomb_damage_SpellScript(); + } +}; + +class spell_xt002_heart_overload_periodic : public SpellScriptLoader +{ + public: + spell_xt002_heart_overload_periodic() : SpellScriptLoader("spell_xt002_heart_overload_periodic") { } + + class spell_xt002_heart_overload_periodic_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_heart_overload_periodic_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ENERGY_ORB)) + return false; + + if (!sSpellMgr->GetSpellInfo(SPELL_RECHARGE_BOOMBOT)) + return false; + + if (!sSpellMgr->GetSpellInfo(SPELL_RECHARGE_PUMMELER)) + return false; + + if (!sSpellMgr->GetSpellInfo(SPELL_RECHARGE_SCRAPBOT)) + return false; + + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + if (InstanceScript* instance = caster->GetInstanceScript()) + { + if (Unit* toyPile = ObjectAccessor::GetUnit(*caster, instance->GetData64(DATA_TOY_PILE_0 + urand(0, 3)))) + { + caster->CastSpell(toyPile, SPELL_ENERGY_ORB, true); + + // This should probably be incorporated in a dummy effect handler, but I've had trouble getting the correct target + // Weighed randomization (approximation) + uint32 const spells[] = { SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT, + SPELL_RECHARGE_PUMMELER, SPELL_RECHARGE_BOOMBOT }; + + for (uint8 i = 0; i < 5; ++i) + { + uint8 a = urand(0, 4); + uint32 spellId = spells[a]; + toyPile->CastSpell(toyPile, spellId, true); + } + } + } + + DoScriptText(SAY_SUMMON, caster->GetVehicleBase()); + } + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_xt002_heart_overload_periodic_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_xt002_heart_overload_periodic_SpellScript(); + } +}; + +class spell_xt002_tympanic_tantrum : public SpellScriptLoader +{ + public: + spell_xt002_tympanic_tantrum() : SpellScriptLoader("spell_xt002_tympanic_tantrum") { } + + class spell_xt002_tympanic_tantrum_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_tympanic_tantrum_SpellScript); + + void FilterTargets(std::list& unitList) + { + unitList.remove_if (PlayerOrPetCheck()); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnUnitTargetSelect += SpellUnitTargetFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_xt002_tympanic_tantrum_SpellScript(); + } +}; + +class spell_xt002_submerged : public SpellScriptLoader +{ + public: + spell_xt002_submerged() : SpellScriptLoader("spell_xt002_submerged") { } + + class spell_xt002_submerged_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_submerged_SpellScript); + + void HandleScript(SpellEffIndex /*eff*/) + { + Creature* target = GetHitCreature(); + if (!target) + return; + + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + target->SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_SUBMERGED); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_xt002_submerged_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_xt002_submerged_SpellScript(); + } +}; + +class spell_xt002_stand : public SpellScriptLoader +{ + public: + spell_xt002_stand() : SpellScriptLoader("spell_xt002_stand") { } + + class spell_xt002_stand_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_stand_SpellScript); + + void HandleScript(SpellEffIndex /*eff*/) + { + Creature* target = GetHitCreature(); + if (!target) + return; + + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + target->SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_xt002_stand_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_xt002_stand_SpellScript(); + } +}; + +class achievement_nerf_engineering : public AchievementCriteriaScript +{ + public: + achievement_nerf_engineering() : AchievementCriteriaScript("achievement_nerf_engineering") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target || !target->GetAI()) + return false; + + return !(target->GetAI()->GetData(DATA_HEALTH_RECOVERED)); + } +}; + +class achievement_heartbreaker : public AchievementCriteriaScript +{ + public: + achievement_heartbreaker() : AchievementCriteriaScript("achievement_heartbreaker") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target || !target->GetAI()) + return false; + + return target->GetAI()->GetData(DATA_HARD_MODE); + } +}; + +class achievement_nerf_gravity_bombs : public AchievementCriteriaScript +{ + public: + achievement_nerf_gravity_bombs() : AchievementCriteriaScript("achievement_nerf_gravity_bombs") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target || !target->GetAI()) + return false; + + return !(target->GetAI()->GetData(DATA_GRAVITY_BOMB_CASUALTY)); + } +}; + +void AddSC_boss_xt002() +{ + new mob_xt002_heart(); + new mob_scrapbot(); + new mob_pummeller(); + new mob_boombot(); + + new mob_life_spark(); + new boss_xt002(); + + new spell_xt002_searing_light_spawn_life_spark(); + new spell_xt002_gravity_bomb_aura(); + new spell_xt002_gravity_bomb_damage(); + new spell_xt002_heart_overload_periodic(); + new spell_xt002_tympanic_tantrum(); + new spell_xt002_submerged(); + new spell_xt002_stand(); + + new achievement_nerf_engineering(); + new achievement_heartbreaker(); + new achievement_nerf_gravity_bombs(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp new file mode 100644 index 00000000000..e4b21e1f66e --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008-2011 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 "ulduar.h" + +enum Sara_Yells +{ + SAY_SARA_PREFIGHT_1 = -1603310, + SAY_SARA_PREFIGHT_2 = -1603311, + SAY_SARA_AGGRO_1 = -1603312, + SAY_SARA_AGGRO_2 = -1603313, + SAY_SARA_AGGRO_3 = -1603314, + SAY_SARA_SLAY_1 = -1603315, + SAY_SARA_SLAY_2 = -1603316, + WHISP_SARA_INSANITY = -1603317, + SAY_SARA_PHASE2_1 = -1603318, + SAY_SARA_PHASE2_2 = -1603319, +}; + +enum YoggSaron_Yells +{ + SAY_PHASE2_1 = -1603330, + SAY_PHASE2_2 = -1603331, + SAY_PHASE2_3 = -1603332, + SAY_PHASE2_4 = -1603333, + SAY_PHASE2_5 = -1603334, + SAY_PHASE3 = -1603335, + SAY_VISION = -1603336, + SAY_SLAY_1 = -1603337, + SAY_SLAY_2 = -1603338, + WHISP_INSANITY_1 = -1603339, + WHISP_INSANITY_2 = -1603340, + SAY_DEATH = -1603341, +}; + +enum +{ + ACHIEV_TIMED_START_EVENT = 21001, +}; +//not in scriptloader yet just to remove warning boss_yoggsaron.obj : warning LNK4221: no public symbols found; archive member will be inaccessible +void AddSC_boss_yoggsaron() +{ +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp new file mode 100644 index 00000000000..3c5697a7995 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2008-2011 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 "InstanceScript.h" +#include "ulduar.h" + +static DoorData const doorData[] = +{ + { GO_LEVIATHAN_DOOR, BOSS_LEVIATHAN, DOOR_TYPE_ROOM, BOUNDARY_S }, + { GO_XT_002_DOOR, BOSS_XT002, DOOR_TYPE_ROOM, BOUNDARY_S }, + { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }, +}; + +class instance_ulduar : public InstanceMapScript +{ + public: + instance_ulduar() : InstanceMapScript("instance_ulduar", 603) { } + + struct instance_ulduar_InstanceMapScript : public InstanceScript + { + instance_ulduar_InstanceMapScript(InstanceMap* map) : InstanceScript(map) { } + + uint32 Encounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + // Creatures + uint64 LeviathanGUID; + uint64 IgnisGUID; + uint64 RazorscaleGUID; + uint64 RazorscaleController; + uint64 RazorHarpoonGUIDs[4]; + uint64 ExpeditionCommanderGUID; + uint64 XT002GUID; + uint64 XTToyPileGUIDs[4]; + uint64 AssemblyGUIDs[3]; + uint64 KologarnGUID; + uint64 AuriayaGUID; + uint64 MimironGUID; + uint64 HodirGUID; + uint64 ThorimGUID; + uint64 FreyaGUID; + uint64 KeeperGUIDs[3]; + uint64 VezaxGUID; + uint64 YoggSaronGUID; + uint64 AlgalonGUID; + uint64 LeviathanGateGUID; + uint64 VezaxDoorGUID; + + // GameObjects + uint64 KologarnChestGUID; + uint64 KologarnBridgeGUID; + uint64 KologarnDoorGUID; + uint64 ThorimChestGUID; + uint64 HodirRareCacheGUID; + uint64 HodirChestGUID; + uint64 HodirDoorGUID; + uint64 HodirIceDoorGUID; + uint64 ArchivumDoorGUID; + + // Miscellaneous + uint32 TeamInInstance; + uint32 HodirRareCacheData; + uint32 ColossusData; + uint8 elderCount; + bool conSpeedAtory; + bool Unbroken; + + std::set mRubbleSpawns; + + void Initialize() + { + SetBossNumber(MAX_ENCOUNTER); + LoadDoorData(doorData); + IgnisGUID = 0; + RazorscaleGUID = 0; + RazorscaleController = 0; + ExpeditionCommanderGUID = 0; + XT002GUID = 0; + KologarnGUID = 0; + AuriayaGUID = 0; + MimironGUID = 0; + HodirGUID = 0; + ThorimGUID = 0; + FreyaGUID = 0; + VezaxGUID = 0; + YoggSaronGUID = 0; + AlgalonGUID = 0; + KologarnChestGUID = 0; + KologarnBridgeGUID = 0; + ThorimChestGUID = 0; + HodirRareCacheGUID = 0; + HodirChestGUID = 0; + LeviathanGateGUID = 0; + VezaxDoorGUID = 0; + HodirDoorGUID = 0; + HodirIceDoorGUID = 0; + ArchivumDoorGUID = 0; + TeamInInstance = 0; + HodirRareCacheData = 0; + ColossusData = 0; + elderCount = 0; + conSpeedAtory = false; + Unbroken = true; + + memset(Encounter, 0, sizeof(Encounter)); + memset(XTToyPileGUIDs, 0, sizeof(XTToyPileGUIDs)); + memset(AssemblyGUIDs, 0, sizeof(AssemblyGUIDs)); + memset(RazorHarpoonGUIDs, 0, sizeof(RazorHarpoonGUIDs)); + memset(KeeperGUIDs, 0, sizeof(KeeperGUIDs)); + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (Encounter[i] == IN_PROGRESS) + return true; + } + + return false; + } + + void OnPlayerEnter(Player* player) + { + if (!TeamInInstance) + TeamInInstance = player->GetTeam(); + } + + void OnCreatureCreate(Creature* creature) + { + if (!TeamInInstance) + { + Map::PlayerList const& Players = instance->GetPlayers(); + if (!Players.isEmpty()) + if (Player* player = Players.begin()->getSource()) + TeamInInstance = player->GetTeam(); + } + + switch (creature->GetEntry()) + { + case NPC_LEVIATHAN: + LeviathanGUID = creature->GetGUID(); + break; + case NPC_IGNIS: + IgnisGUID = creature->GetGUID(); + break; + case NPC_RAZORSCALE: + RazorscaleGUID = creature->GetGUID(); + break; + case NPC_RAZORSCALE_CONTROLLER: + RazorscaleController = creature->GetGUID(); + break; + case NPC_EXPEDITION_COMMANDER: + ExpeditionCommanderGUID = creature->GetGUID(); + break; + case NPC_XT002: + XT002GUID = creature->GetGUID(); + break; + case NPC_XT_TOY_PILE: + for (uint8 i = 0; i < 4; ++i) + if (!XTToyPileGUIDs[i]) + XTToyPileGUIDs[i] = creature->GetGUID(); + break; + + // Assembly of Iron + case NPC_STEELBREAKER: + AssemblyGUIDs[0] = creature->GetGUID(); + break; + case NPC_MOLGEIM: + AssemblyGUIDs[1] = creature->GetGUID(); + break; + case NPC_BRUNDIR: + AssemblyGUIDs[2] = creature->GetGUID(); + break; + + // Freya's Keeper + case NPC_IRONBRANCH: + KeeperGUIDs[0] = creature->GetGUID(); + if (GetBossState(BOSS_FREYA) == DONE) + creature->DespawnOrUnsummon(); + break; + case NPC_BRIGHTLEAF: + KeeperGUIDs[1] = creature->GetGUID(); + if (GetBossState(BOSS_FREYA) == DONE) + creature->DespawnOrUnsummon(); + break; + case NPC_STONEBARK: + KeeperGUIDs[2] = creature->GetGUID(); + if (GetBossState(BOSS_FREYA) == DONE) + creature->DespawnOrUnsummon(); + break; + + // Kologarn + case NPC_KOLOGARN: + KologarnGUID = creature->GetGUID(); + break; + case NPC_AURIAYA: + AuriayaGUID = creature->GetGUID(); + break; + case NPC_MIMIRON: + MimironGUID = creature->GetGUID(); + break; + case NPC_HODIR: + HodirGUID = creature->GetGUID(); + break; + case NPC_THORIM: + ThorimGUID = creature->GetGUID(); + break; + case NPC_FREYA: + FreyaGUID = creature->GetGUID(); + break; + case NPC_VEZAX: + VezaxGUID = creature->GetGUID(); + break; + case NPC_YOGGSARON: + YoggSaronGUID = creature->GetGUID(); + break; + case NPC_ALGALON: + AlgalonGUID = creature->GetGUID(); + break; + + // Hodir's Helper NPCs + case NPC_EIVI_NIGHTFEATHER: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_TOR_GREYCLOUD, HORDE); + break; + case NPC_ELLIE_NIGHTFEATHER: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_KAR_GREYCLOUD, HORDE); + break; + case NPC_ELEMENTALIST_MAHFUUN: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_SPIRITWALKER_TARA, HORDE); + break; + case NPC_ELEMENTALIST_AVUUN: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_SPIRITWALKER_YONA, HORDE); + break; + case NPC_MISSY_FLAMECUFFS: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_AMIRA_BLAZEWEAVER, HORDE); + break; + case NPC_SISSY_FLAMECUFFS: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_VEESHA_BLAZEWEAVER, HORDE); + break; + case NPC_FIELD_MEDIC_PENNY: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_BATTLE_PRIEST_ELIZA, HORDE); + break; + case NPC_FIELD_MEDIC_JESSI: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA, HORDE); + break; + } + + } + + void OnGameObjectCreate(GameObject* gameObject) + { + switch (gameObject->GetEntry()) + { + case GO_KOLOGARN_CHEST_HERO: + case GO_KOLOGARN_CHEST: + KologarnChestGUID = gameObject->GetGUID(); + break; + case GO_KOLOGARN_BRIDGE: + KologarnBridgeGUID = gameObject->GetGUID(); + if (GetBossState(BOSS_KOLOGARN) == DONE) + HandleGameObject(0, false, gameObject); + break; + case GO_KOLOGARN_DOOR: + KologarnDoorGUID = gameObject->GetGUID(); + break; + case GO_THORIM_CHEST_HERO: + case GO_THORIM_CHEST: + ThorimChestGUID = gameObject->GetGUID(); + break; + case GO_HODIR_RARE_CACHE_OF_WINTER_HERO: + case GO_HODIR_RARE_CACHE_OF_WINTER: + HodirRareCacheGUID = gameObject->GetGUID(); + break; + case GO_HODIR_CHEST_HERO: + case GO_HODIR_CHEST: + HodirChestGUID = gameObject->GetGUID(); + break; + case GO_LEVIATHAN_DOOR: + AddDoor(gameObject, true); + break; + case GO_LEVIATHAN_GATE: + LeviathanGateGUID = gameObject->GetGUID(); + if (GetBossState(BOSS_LEVIATHAN) == DONE) + gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + break; + case GO_XT_002_DOOR: + AddDoor(gameObject, true); + break; + case GO_VEZAX_DOOR: + VezaxDoorGUID = gameObject->GetGUID(); + HandleGameObject(0, false, gameObject); + break; + case GO_RAZOR_HARPOON_1: + RazorHarpoonGUIDs[0] = gameObject->GetGUID(); + break; + case GO_RAZOR_HARPOON_2: + RazorHarpoonGUIDs[1] = gameObject->GetGUID(); + break; + case GO_RAZOR_HARPOON_3: + RazorHarpoonGUIDs[2] = gameObject->GetGUID(); + break; + case GO_RAZOR_HARPOON_4: + RazorHarpoonGUIDs[3] = gameObject->GetGUID(); + break; + case GO_MOLE_MACHINE: + if (GetBossState(BOSS_RAZORSCALE) == IN_PROGRESS) + gameObject->SetGoState(GO_STATE_ACTIVE); + case GO_HODIR_DOOR: + HodirDoorGUID = gameObject->GetGUID(); + break; + case GO_HODIR_ICE_DOOR: + HodirIceDoorGUID = gameObject->GetGUID(); + break; + case GO_ARCHIVUM_DOOR: + ArchivumDoorGUID = gameObject->GetGUID(); + if (GetBossState(BOSS_ASSEMBLY_OF_IRON) != DONE) + HandleGameObject(ArchivumDoorGUID, false); + break; + } + } + + void OnGameObjectRemove(GameObject* gameObject) + { + switch (gameObject->GetEntry()) + { + case GO_LEVIATHAN_DOOR: + AddDoor(gameObject, false); + break; + case GO_XT_002_DOOR: + AddDoor(gameObject, false); + default: + break; + } + } + + void OnCreatureDeath(Creature* creature) + { + switch (creature->GetEntry()) + { + case NPC_CORRUPTED_SERVITOR: + case NPC_MISGUIDED_NYMPH: + case NPC_GUARDIAN_LASHER: + case NPC_FOREST_SWARMER: + case NPC_MANGROVE_ENT: + case NPC_IRONROOT_LASHER: + case NPC_NATURES_BLADE: + case NPC_GUARDIAN_OF_LIFE: + if (!conSpeedAtory) + { + DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_CON_SPEED_ATORY); + conSpeedAtory = true; + } + break; + default: + break; + } + } + + void ProcessEvent(WorldObject* /*gameObject*/, uint32 eventId) + { + // Flame Leviathan's Tower Event triggers + Creature* FlameLeviathan = instance->GetCreature(LeviathanGUID); + if (FlameLeviathan && FlameLeviathan->isAlive()) // No leviathan, no event triggering ;) + switch (eventId) + { + case EVENT_TOWER_OF_STORM_DESTROYED: + FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_STORM_DESTROYED); + break; + case EVENT_TOWER_OF_FROST_DESTROYED: + FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FROST_DESTROYED); + break; + case EVENT_TOWER_OF_FLAMES_DESTROYED: + FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FLAMES_DESTROYED); + break; + case EVENT_TOWER_OF_LIFE_DESTROYED: + FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_LIFE_DESTROYED); + break; + } + } + + + bool SetBossState(uint32 type, EncounterState state) + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case BOSS_LEVIATHAN: + case BOSS_IGNIS: + case BOSS_RAZORSCALE: + case BOSS_XT002: + case BOSS_AURIAYA: + case BOSS_MIMIRON: + case BOSS_FREYA: + break; + case BOSS_ASSEMBLY_OF_IRON: + if (state == DONE) + HandleGameObject(ArchivumDoorGUID, true); + break; + case BOSS_VEZAX: + if (state == DONE) + HandleGameObject(VezaxDoorGUID, true); + break; + case BOSS_YOGGSARON: + break; + case BOSS_KOLOGARN: + if (state == DONE) + { + if (GameObject* gameObject = instance->GetGameObject(KologarnChestGUID)) + { + gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); + gameObject->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } + HandleGameObject(KologarnBridgeGUID, false); + } + if (state == IN_PROGRESS) + HandleGameObject(KologarnDoorGUID, false); + else + HandleGameObject(KologarnDoorGUID, true); + break; + case BOSS_HODIR: + if (state == DONE) + { + if (GameObject* HodirRareCache = instance->GetGameObject(HodirRareCacheGUID)) + if (GetData(DATA_HODIR_RARE_CACHE)) + HodirRareCache->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + if (GameObject* HodirChest = instance->GetGameObject(HodirChestGUID)) + HodirChest->SetRespawnTime(HodirChest->GetRespawnDelay()); + HandleGameObject(HodirDoorGUID, true); + HandleGameObject(HodirIceDoorGUID, true); + } + break; + case BOSS_THORIM: + if (state == DONE) + if (GameObject* gameObject = instance->GetGameObject(ThorimChestGUID)) + gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); + break; + } + + return true; + } + + void SetData(uint32 type, uint32 data) + { + switch (type) + { + case DATA_COLOSSUS: + ColossusData = data; + if (data == 2) + { + if (Creature* Leviathan = instance->GetCreature(LeviathanGUID)) + Leviathan->AI()->DoAction(ACTION_MOVE_TO_CENTER_POSITION); + if (GameObject* gameObject = instance->GetGameObject(LeviathanGateGUID)) + gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + SaveToDB(); + } + break; + case DATA_HODIR_RARE_CACHE: + HodirRareCacheData = data; + if (!HodirRareCacheData) + { + if (Creature* Hodir = instance->GetCreature(HodirGUID)) + if (GameObject* gameObject = instance->GetGameObject(HodirRareCacheGUID)) + Hodir->RemoveGameObject(gameObject, false); + } + break; + case DATA_UNBROKEN: + Unbroken = bool(data); + break; + default: + break; + } + } + + void SetData64(uint32 /*type*/, uint64 /*data*/) + { + } + + uint64 GetData64(uint32 data) + { + switch (data) + { + case BOSS_LEVIATHAN: + return LeviathanGUID; + case BOSS_IGNIS: + return IgnisGUID; + case BOSS_RAZORSCALE: + return RazorscaleGUID; + case DATA_RAZORSCALE_CONTROL: + return RazorscaleController; + case BOSS_XT002: + return XT002GUID; + case DATA_TOY_PILE_0: + case DATA_TOY_PILE_1: + case DATA_TOY_PILE_2: + case DATA_TOY_PILE_3: + return XTToyPileGUIDs[data - DATA_TOY_PILE_0]; + case BOSS_KOLOGARN: + return KologarnGUID; + case BOSS_AURIAYA: + return AuriayaGUID; + case BOSS_MIMIRON: + return MimironGUID; + case BOSS_HODIR: + return HodirGUID; + case BOSS_THORIM: + return ThorimGUID; + case BOSS_FREYA: + return FreyaGUID; + case BOSS_VEZAX: + return VezaxGUID; + case BOSS_YOGGSARON: + return YoggSaronGUID; + case BOSS_ALGALON: + return AlgalonGUID; + + // Razorscale expedition commander + case DATA_EXPEDITION_COMMANDER: + return ExpeditionCommanderGUID; + case GO_RAZOR_HARPOON_1: + return RazorHarpoonGUIDs[0]; + case GO_RAZOR_HARPOON_2: + return RazorHarpoonGUIDs[1]; + case GO_RAZOR_HARPOON_3: + return RazorHarpoonGUIDs[2]; + case GO_RAZOR_HARPOON_4: + return RazorHarpoonGUIDs[3]; + + // Assembly of Iron + case BOSS_STEELBREAKER: + return AssemblyGUIDs[0]; + case BOSS_MOLGEIM: + return AssemblyGUIDs[1]; + case BOSS_BRUNDIR: + return AssemblyGUIDs[2]; + + // Freya's Keepers + case BOSS_BRIGHTLEAF: + return KeeperGUIDs[0]; + case BOSS_IRONBRANCH: + return KeeperGUIDs[1]; + case BOSS_STONEBARK: + return KeeperGUIDs[2]; + } + + return 0; + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_COLOSSUS: + return ColossusData; + case DATA_HODIR_RARE_CACHE: + return HodirRareCacheData; + case DATA_UNBROKEN: + return uint32(Unbroken); + default: + break; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "U U " << GetBossSaveData() << GetData(DATA_COLOSSUS); + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); + } + + void Load(char const* strIn) + { + if (!strIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(strIn); + + char dataHead1, dataHead2; + + std::istringstream loadStream(strIn); + loadStream >> dataHead1 >> dataHead2; + + if (dataHead1 == 'U' && dataHead2 == 'U') + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + + if (i == DATA_COLOSSUS) + SetData(i, tmpState); + else + SetBossState(i, EncounterState(tmpState)); + } + } + + OUT_LOAD_INST_DATA_COMPLETE; + } + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const + { + return new instance_ulduar_InstanceMapScript(map); + } +}; + +void AddSC_instance_ulduar() +{ + new instance_ulduar(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h new file mode 100644 index 00000000000..f11212d535e --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2008-2011 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 DEF_ULDUAR_H +#define DEF_ULDUAR_H + +#include "ObjectMgr.h" +#define UlduarScriptName "instance_ulduar" + +enum UlduarBosses +{ + MAX_ENCOUNTER = 20, + + BOSS_LEVIATHAN = 0, + BOSS_IGNIS = 1, + BOSS_RAZORSCALE = 2, + BOSS_XT002 = 3, + BOSS_ASSEMBLY_OF_IRON = 4, + BOSS_STEELBREAKER = 5, + BOSS_MOLGEIM = 6, + BOSS_BRUNDIR = 7, + BOSS_KOLOGARN = 8, + BOSS_AURIAYA = 9, + BOSS_MIMIRON = 10, + BOSS_HODIR = 11, + BOSS_THORIM = 12, + BOSS_FREYA = 13, + BOSS_BRIGHTLEAF = 14, + BOSS_IRONBRANCH = 15, + BOSS_STONEBARK = 16, + BOSS_VEZAX = 17, + BOSS_YOGGSARON = 18, + BOSS_ALGALON = 19, +}; + +enum UlduarNPCs +{ + // General + NPC_LEVIATHAN = 33113, + NPC_SALVAGED_DEMOLISHER = 33109, + NPC_SALVAGED_SIEGE_ENGINE = 33060, + NPC_IGNIS = 33118, + NPC_RAZORSCALE = 33186, + NPC_RAZORSCALE_CONTROLLER = 33233, + NPC_STEELFORGED_DEFFENDER = 33236, + NPC_EXPEDITION_COMMANDER = 33210, + NPC_XT002 = 33293, + NPC_XT_TOY_PILE = 33337, + NPC_STEELBREAKER = 32867, + NPC_MOLGEIM = 32927, + NPC_BRUNDIR = 32857, + NPC_KOLOGARN = 32930, + NPC_FOCUSED_EYEBEAM = 33632, + NPC_FOCUSED_EYEBEAM_RIGHT = 33802, + NPC_LEFT_ARM = 32933, + NPC_RIGHT_ARM = 32934, + NPC_RUBBLE = 33768, + NPC_AURIAYA = 33515, + NPC_MIMIRON = 33350, + NPC_HODIR = 32845, + NPC_THORIM = 32865, + NPC_FREYA = 32906, + NPC_VEZAX = 33271, + NPC_YOGGSARON = 33288, + NPC_ALGALON = 32871, + + // Mimiron + NPC_LEVIATHAN_MKII = 33432, + NPC_VX_001 = 33651, + NPC_AERIAL_COMMAND_UNIT = 33670, + + // Freya's Keepers + NPC_IRONBRANCH = 32913, + NPC_BRIGHTLEAF = 32915, + NPC_STONEBARK = 32914, + + // Hodir's Helper NPCs + NPC_TOR_GREYCLOUD = 32941, + NPC_KAR_GREYCLOUD = 33333, + NPC_EIVI_NIGHTFEATHER = 33325, + NPC_ELLIE_NIGHTFEATHER = 32901, + NPC_SPIRITWALKER_TARA = 33332, + NPC_SPIRITWALKER_YONA = 32950, + NPC_ELEMENTALIST_MAHFUUN = 33328, + NPC_ELEMENTALIST_AVUUN = 32900, + NPC_AMIRA_BLAZEWEAVER = 33331, + NPC_VEESHA_BLAZEWEAVER = 32946, + NPC_MISSY_FLAMECUFFS = 32893, + NPC_SISSY_FLAMECUFFS = 33327, + NPC_BATTLE_PRIEST_ELIZA = 32948, + NPC_BATTLE_PRIEST_GINA = 33330, + NPC_FIELD_MEDIC_PENNY = 32897, + NPC_FIELD_MEDIC_JESSI = 33326, + + // Freya's trash NPCs + NPC_CORRUPTED_SERVITOR = 33354, + NPC_MISGUIDED_NYMPH = 33355, + NPC_GUARDIAN_LASHER = 33430, + NPC_FOREST_SWARMER = 33431, + NPC_MANGROVE_ENT = 33525, + NPC_IRONROOT_LASHER = 33526, + NPC_NATURES_BLADE = 33527, + NPC_GUARDIAN_OF_LIFE = 33528, +}; + +enum UlduarGameObjects +{ + GO_KOLOGARN_CHEST_HERO = 195047, + GO_KOLOGARN_CHEST = 195046, + GO_KOLOGARN_BRIDGE = 194232, + GO_KOLOGARN_DOOR = 194553, + GO_THORIM_CHEST_HERO = 194315, + GO_THORIM_CHEST = 194314, + GO_HODIR_RARE_CACHE_OF_WINTER = 194200, + GO_HODIR_RARE_CACHE_OF_WINTER_HERO = 194201, + GO_HODIR_CHEST_HERO = 194308, + GO_HODIR_CHEST = 194307, + GO_LEVIATHAN_DOOR = 194905, + GO_LEVIATHAN_GATE = 194630, + GO_XT_002_DOOR = 194631, + GO_VEZAX_DOOR = 194750, + GO_MOLE_MACHINE = 194316, + GO_RAZOR_HARPOON_1 = 194542, + GO_RAZOR_HARPOON_2 = 194541, + GO_RAZOR_HARPOON_3 = 194543, + GO_RAZOR_HARPOON_4 = 194519, + GO_RAZOR_BROKEN_HARPOON = 194565, + GO_HODIR_DOOR = 194634, + GO_HODIR_ICE_DOOR = 194441, + GO_ARCHIVUM_DOOR = 194556, +}; + +enum LeviathanData +{ + EVENT_TOWER_OF_STORM_DESTROYED = 21031, + EVENT_TOWER_OF_FROST_DESTROYED = 21032, + EVENT_TOWER_OF_FLAMES_DESTROYED = 21033, + EVENT_TOWER_OF_LIFE_DESTROYED = 21030, + ACTION_TOWER_OF_STORM_DESTROYED = 1, + ACTION_TOWER_OF_FROST_DESTROYED = 2, + ACTION_TOWER_OF_FLAMES_DESTROYED = 3, + ACTION_TOWER_OF_LIFE_DESTROYED = 4, + ACTION_MOVE_TO_CENTER_POSITION = 10, +}; + +enum UlduarAchievementCriteriaIds +{ + CRITERIA_CON_SPEED_ATORY = 21597, + CRITERIA_DISARMED = 21687, +}; + +enum UlduarData +{ + // Collosus (Leviathan) + DATA_COLOSSUS = 20, + + // Razorscale + DATA_EXPEDITION_COMMANDER, + DATA_RAZORSCALE_CONTROL, + + // XT-002 + DATA_TOY_PILE_0, + DATA_TOY_PILE_1, + DATA_TOY_PILE_2, + DATA_TOY_PILE_3, + + // Hodir + DATA_HODIR_RARE_CACHE, +}; + +enum UlduarAchievementData +{ + // FL Achievement boolean + DATA_UNBROKEN = 29052906, // 2905, 2906 are achievement IDs, +}; + +template +CreatureAI* GetUlduarAI(Creature* creature) +{ + if (InstanceMap* instance = creature->GetMap()->ToInstanceMap()) + if (instance->GetInstanceScript()) + if (instance->GetScriptId() == sObjectMgr->GetScriptId(UlduarScriptName)) + return new AI(creature); + + return NULL; +} + +class PlayerOrPetCheck +{ + public: + bool operator() (Unit* unit) + { + if (unit->GetTypeId() != TYPEID_PLAYER) + if (!unit->ToCreature()->isPet()) + return true; + + return false; + } +}; + +#endif diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp new file mode 100644 index 00000000000..05b1e395d1e --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2008-2011 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 + * 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 "ScriptedGossip.h" +#include "ulduar.h" +#include "InstanceScript.h" + +/* +The teleporter appears to be active and stable. + +- Expedition Base Camp +- Formation Grounds +- Colossal Forge +- Scrapyard +- Antechamber of Ulduar +- Shattered Walkway +- Conservatory of Life +*/ + +enum UlduarTeleporter +{ + BASE_CAMP = 200, + GROUNDS = 201, + FORGE = 202, + SCRAPYARD = 203, + ANTECHAMBER = 204, + WALKWAY = 205, + CONSERVATORY = 206, +}; + +class ulduar_teleporter : public GameObjectScript +{ + public: + ulduar_teleporter() : GameObjectScript("ulduar_teleporter") { } + + bool OnGossipSelect(Player* player, GameObject* /*gameObject*/, uint32 sender, uint32 action) + { + player->PlayerTalkClass->ClearMenus(); + if (sender != GOSSIP_SENDER_MAIN) + return false; + if (!player->getAttackers().empty()) + return false; + + switch (action) + { + case BASE_CAMP: + player->TeleportTo(603, -706.122f, -92.6024f, 429.876f, 0.0f); + player->CLOSE_GOSSIP_MENU(); + break; + case GROUNDS: + player->TeleportTo(603, 131.248f, -35.3802f, 409.804f, 0.0f); + player->CLOSE_GOSSIP_MENU(); + break; + case FORGE: + player->TeleportTo(603, 553.233f, -12.3247f, 409.679f, 0.0f); + player->CLOSE_GOSSIP_MENU(); + break; + case SCRAPYARD: + player->TeleportTo(603, 926.292f, -11.4635f, 418.595f, 0.0f); + player->CLOSE_GOSSIP_MENU(); + break; + case ANTECHAMBER: + player->TeleportTo(603, 1498.09f, -24.246f, 420.967f, 0.0f); + player->CLOSE_GOSSIP_MENU(); + break; + case WALKWAY: + player->TeleportTo(603, 1859.45f, -24.1f, 448.9f, 0.0f); + player->CLOSE_GOSSIP_MENU(); + break; + case CONSERVATORY: + player->TeleportTo(603, 2086.27f, -24.3134f, 421.239f, 0.0f); + player->CLOSE_GOSSIP_MENU(); + break; + } + + return true; + } + + bool OnGossipHello(Player* player, GameObject* gameObject) + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Expedition Base Camp", GOSSIP_SENDER_MAIN, BASE_CAMP); + if (InstanceScript* instance = gameObject->GetInstanceScript()) + { + if (instance->GetData(DATA_COLOSSUS) == 2) //count of 2 collossus death + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Formation Grounds", GOSSIP_SENDER_MAIN, GROUNDS); + if (instance->GetBossState(BOSS_LEVIATHAN) == DONE) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Colossal Forge", GOSSIP_SENDER_MAIN, FORGE); + if (instance->GetBossState(BOSS_XT002) == DONE) + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Scrapyard", GOSSIP_SENDER_MAIN, SCRAPYARD); + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Antechamber of Ulduar", GOSSIP_SENDER_MAIN, ANTECHAMBER); + } + if (instance->GetBossState(BOSS_KOLOGARN) == DONE) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Shattered Walkway", GOSSIP_SENDER_MAIN, WALKWAY); + if (instance->GetBossState(BOSS_AURIAYA) == DONE) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Conservatory of Life", GOSSIP_SENDER_MAIN, CONSERVATORY); + } + + player->SEND_GOSSIP_MENU(gameObject->GetGOInfo()->GetGossipMenuId(), gameObject->GetGUID()); + return true; + } +}; + +void AddSC_ulduar_teleporter() +{ + new ulduar_teleporter(); +} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_algalon.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_algalon.cpp deleted file mode 100644 index 3888cc43bc9..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_algalon.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "ulduar.h" - -#define GAMEOBJECT_GIVE_OF_THE_OBSERVER 194821 - -enum Spells -{ - SPELL_ASCEND = 64487, - SPELL_BERSERK = 47008, - SPELL_BIG_BANG = 64443, - H_SPELL_BIG_BANG = 64584, - SPELL_COSMIC_SMASH = 62301, - H_SPELL_COSMIC_SMASH = 64598, - SPELL_PHASE_PUNCH = 64412, - SPELL_QUANTUM_STRIKE = 64395, - H_SPELL_QUANTUM_STRIKE = 64592, - SPELL_BLACK_HOLE_EXPLOSION = 64122, - SPELL_ARCANE_BARAGE = 64599, - H_SPELL_ARCANE_BARAGE = 64607 -}; - -enum Creatures -{ - CREATURE_COLLAPSING_STAR = 32955, - CREATURE_BLACK_HOLE = 32953, - CREATURE_LIVING_CONSTELLATION = 33052, - CREATURE_DARK_MATTER = 33089 -}; - -enum Yells -{ - SAY_AGGRO = -1603000, - SAY_SLAY_1 = -1603001, - SAY_SLAY_2 = -1603002, - SAY_ENGADED_FOR_FIRTS_TIME = -1603003, - SAY_PHASE_2 = -1603004, - SAY_SUMMON_COLLAPSING_STAR = -1603005, - SAY_DEATH_1 = -1603006, - SAY_DEATH_2 = -1603007, - SAY_DEATH_3 = -1603008, - SAY_DEATH_4 = -1603009, - SAY_DEATH_5 = -1603010, - SAY_BERSERK = -1603011, - SAY_BIG_BANG_1 = -1603012, - SAY_BIG_BANG_2 = -1603013, - SAY_TIMER_1 = -1603014, - SAY_TIMER_2 = -1603015, - SAY_TIMER_3 = -1603016, - SAY_SUMMON_1 = -1603017, - SAY_SUMMON_2 = -1603018, - SAY_SUMMON_3 = -1603019, -}; - -class boss_algalon : public CreatureScript -{ -public: - boss_algalon() : CreatureScript("boss_algalon") { } - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } - - struct boss_algalonAI : public ScriptedAI - { - boss_algalonAI(Creature* c) : ScriptedAI(c) - { - instance = c->GetInstanceScript(); - Summon = false; // not in reset. intro speech done only once. - } - - InstanceScript* instance; - - std::list m_lCollapsingStarGUIDList; - - uint32 Phase; - uint32 Ascend_Timer; - uint32 Berserk_Timer; - uint32 BigBang_Timer; - uint32 CosmicSmash_Timer; - uint32 PhasePunch_Timer; - uint32 QuantumStrike_Timer; - uint32 CollapsingStar_Timer; - uint32 uiPhase_timer; - uint32 uiStep; - - uint64 BlackHoleGUID; - - bool Enrage; - bool Summon; - - void EnterCombat(Unit* who) - { - if (Summon) - { - DoScriptText(SAY_AGGRO, me); - me->InterruptSpell(CURRENT_CHANNELED_SPELL); - DoZoneInCombat(who->ToCreature()); - } - else - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_PASSIVE); - uiStep = 1; - } - - if (instance) - instance->SetData(BOSS_ALGALON, IN_PROGRESS); - } - - void KilledUnit(Unit* /*victim*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void Reset() - { - Phase = 1; - - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if (instance) - instance->SetData(BOSS_ALGALON, NOT_STARTED); - - BlackHoleGUID = 0; - - uiPhase_timer = 0; - Ascend_Timer = 480000; //8 minutes - QuantumStrike_Timer = 4000 + rand()%10000; - Berserk_Timer = 360000; //6 minutes - CollapsingStar_Timer = urand(15000, 20000); //Spawns between 15 to 20 seconds - BigBang_Timer = 90000; - PhasePunch_Timer = 8000; - CosmicSmash_Timer = urand(30000, 60000); - Enrage = false; - } - - void JumpToNextStep(uint32 uiTimer) - { - uiPhase_timer = uiTimer; - ++uiStep; - } - - void DespawnCollapsingStar() - { - if (m_lCollapsingStarGUIDList.empty()) - return; - - for (std::list::const_iterator itr = m_lCollapsingStarGUIDList.begin(); itr != m_lCollapsingStarGUIDList.end(); ++itr) - { - if (Creature* temp = Unit::GetCreature(*me, *itr)) - { - if (temp->isAlive()) - temp->DespawnOrUnsummon(); - } - } - m_lCollapsingStarGUIDList.clear(); - } - - void JustSummoned(Creature* summoned) - { - if (summoned->GetEntry() == CREATURE_COLLAPSING_STAR) - { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (me->getVictim()) - summoned->AI()->AttackStart(target ? target : me->getVictim()); - m_lCollapsingStarGUIDList.push_back(summoned->GetGUID()); - } - } - - void SummonCollapsingStar(Unit* target) - { - DoScriptText(SAY_SUMMON_COLLAPSING_STAR, me); - me->SummonCreature(CREATURE_COLLAPSING_STAR, target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 100000); - me->SummonCreature(CREATURE_BLACK_HOLE, target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 27000); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (Phase == 1 && HealthBelowPct(20)) - { - Phase = 2; - DoScriptText(SAY_PHASE_2, me); - } - - if (HealthBelowPct(2)) - { - me->SummonGameObject(GAMEOBJECT_GIVE_OF_THE_OBSERVER, 1634.258667f, -295.101166f, 417.321381f, 0, 0, 0, 0, 0, 0); - - // All of them. or random? - DoScriptText(SAY_DEATH_1, me); - DoScriptText(SAY_DEATH_2, me); - DoScriptText(SAY_DEATH_3, me); - DoScriptText(SAY_DEATH_4, me); - DoScriptText(SAY_DEATH_5, me); - - me->DisappearAndDie(); - - if (instance) - instance->SetData(BOSS_ALGALON, DONE); - - return; - } - - if (Phase == 1) - { - if (!Summon) - { - if (uiPhase_timer <= diff) - { - switch (uiStep) - { - case 1: - DoScriptText(SAY_SUMMON_1, me); - JumpToNextStep(3000); - break; - case 2: - DoScriptText(SAY_SUMMON_2, me); - JumpToNextStep(3000); - break; - case 3: - DoScriptText(SAY_SUMMON_3, me); - JumpToNextStep(3000); - break; - case 4: - DoScriptText(SAY_ENGADED_FOR_FIRTS_TIME, me); - JumpToNextStep(3000); - break; - case 5: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_AGGRESSIVE); - Summon = true; - break; - } - } else uiPhase_timer -= diff; - - return; - } - - if (QuantumStrike_Timer <= diff) - { - DoCast(me->getVictim(), RAID_MODE(SPELL_QUANTUM_STRIKE, H_SPELL_QUANTUM_STRIKE), true); - - QuantumStrike_Timer = urand(4000, 14000); - } else QuantumStrike_Timer -= diff; - - if (BigBang_Timer <= diff) - { - DoScriptText(RAND(SAY_BIG_BANG_1, SAY_BIG_BANG_2), me); - DoCast(me->getVictim(), RAID_MODE(SPELL_BIG_BANG, H_SPELL_BIG_BANG), true); - - BigBang_Timer = 90000; - } else BigBang_Timer -= diff; - - if (Ascend_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ASCEND, true); - - Ascend_Timer = 480000; - } else Ascend_Timer -= diff; - - if (PhasePunch_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_PHASE_PUNCH, true); - - PhasePunch_Timer = 8000; - } else PhasePunch_Timer -= diff; - - if (CosmicSmash_Timer <= diff) - { - DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), RAID_MODE(SPELL_COSMIC_SMASH, H_SPELL_COSMIC_SMASH), true); - - CosmicSmash_Timer = urand(30000, 60000); - } else CosmicSmash_Timer -= diff; - - if (Berserk_Timer <= diff) - { - DoScriptText(SAY_BERSERK, me); - DoCast(me->getVictim(), SPELL_BERSERK, true); - - Berserk_Timer = 360000; - } else Berserk_Timer -= diff; - - DoMeleeAttackIfReady(); - - EnterEvadeIfOutOfCombatArea(diff); - } - - if (Phase == 2) - { - if (Enrage) - { - if (Ascend_Timer <= diff) - { - DoCast(me, SPELL_ASCEND); - DoScriptText(SAY_BERSERK, me); - Ascend_Timer = urand(360000, 365000); - Enrage = false; - } else Ascend_Timer -= diff; - } - } - - DoMeleeAttackIfReady(); - } - }; - -}; - -//Collapsing Star -class mob_collapsing_star : public CreatureScript -{ -public: - mob_collapsing_star() : CreatureScript("mob_collapsing_star") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_collapsing_starAI(creature); - } - - struct mob_collapsing_starAI : public ScriptedAI - { - mob_collapsing_starAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 BlackHoleExplosion_Timer; - - void Reset() - { - BlackHoleExplosion_Timer = 0; - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; - - if (BlackHoleExplosion_Timer <= diff) - { - me->CastSpell(me, SPELL_BLACK_HOLE_EXPLOSION, false); - BlackHoleExplosion_Timer = 0; - } else BlackHoleExplosion_Timer -= diff; - } - }; - -}; - -void AddSC_boss_Algalon() -{ - new boss_algalon(); - new mob_collapsing_star(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp deleted file mode 100644 index a8a4fad5e4e..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp +++ /dev/null @@ -1,812 +0,0 @@ -/* - * Copyright (C) 2008-2011 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: Assembly of Iron encounter -SD%Complete: 60% -SDComment: Runes need DB support, chain lightning won't cast, supercharge won't cast (target error?) - it worked before during debugging. -SDCategory: Ulduar - Ulduar -EndScriptData */ - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "SpellScript.h" -#include "SpellAuraEffects.h" -#include "ulduar.h" - -enum AssemblySpells -{ - // General - SPELL_SUPERCHARGE = 61920, - SPELL_BERSERK = 47008, // Hard enrage, don't know the correct ID. - - // Steelbreaker - SPELL_HIGH_VOLTAGE = 61890, - SPELL_FUSION_PUNCH = 61903, - SPELL_STATIC_DISRUPTION = 44008, - SPELL_OVERWHELMING_POWER = 64637, - SPELL_ELECTRICAL_CHARGE = 61902, - - // Runemaster Molgeim - SPELL_SHIELD_OF_RUNES = 62274, - SPELL_SHIELD_OF_RUNES_BUFF = 62277, - SPELL_SUMMON_RUNE_OF_POWER = 63513, - SPELL_RUNE_OF_POWER = 61974, - SPELL_RUNE_OF_DEATH = 62269, - SPELL_RUNE_OF_SUMMONING = 62273, // This is the spell that summons the rune - SPELL_RUNE_OF_SUMMONING_VIS = 62019, // Visual - SPELL_RUNE_OF_SUMMONING_SUMMON = 62020, // Spell that summons - SPELL_LIGHTNING_ELEMENTAL_PASSIVE = 62052, - - // Stormcaller Brundir - SPELL_CHAIN_LIGHTNING = 61879, - SPELL_OVERLOAD = 61869, - SPELL_LIGHTNING_WHIRL = 61915, - SPELL_LIGHTNING_TENDRILS_10M = 61887, - SPELL_LIGHTNING_TENDRILS_25M = 63486, - SPELL_LIGHTNING_TENDRILS_VISUAL = 61883, - SPELL_STORMSHIELD = 64187, -}; - -enum AssemblyEvents -{ - // General - EVENT_BERSERK = 1, - - // Steelbreaker - EVENT_FUSION_PUNCH = 2, - EVENT_STATIC_DISRUPTION = 3, - EVENT_OVERWHELMING_POWER = 4, - - // Molgeim - EVENT_RUNE_OF_POWER = 5, - EVENT_SHIELD_OF_RUNES = 6, - EVENT_RUNE_OF_DEATH = 7, - EVENT_RUNE_OF_SUMMONING = 8, - EVENT_LIGHTNING_BLAST = 9, - - // Brundir - EVENT_CHAIN_LIGHTNING = 10, - EVENT_OVERLOAD = 11, - EVENT_LIGHTNING_WHIRL = 12, - EVENT_LIGHTNING_TENDRILS = 13, - EVENT_FLIGHT = 14, - EVENT_ENDFLIGHT = 15, - EVENT_GROUND = 16, - EVENT_LAND = 17, - EVENT_MOVE_POSITION = 18, -}; - -enum AssemblyActions -{ - ACTION_STEELBREAKER = 0, - ACTION_MOLGEIM = 1, - ACTION_BRUNDIR = 2, - ACTION_ADD_CHARGE = 3, -}; - -enum AssemblyYells -{ - SAY_STEELBREAKER_AGGRO = -1603020, - SAY_STEELBREAKER_SLAY_1 = -1603021, - SAY_STEELBREAKER_SLAY_2 = -1603022, - SAY_STEELBREAKER_POWER = -1603023, - SAY_STEELBREAKER_DEATH_1 = -1603024, - SAY_STEELBREAKER_DEATH_2 = -1603025, - SAY_STEELBREAKER_BERSERK = -1603026, - - SAY_MOLGEIM_AGGRO = -1603030, - SAY_MOLGEIM_SLAY_1 = -1603031, - SAY_MOLGEIM_SLAY_2 = -1603032, - SAY_MOLGEIM_RUNE_DEATH = -1603033, - SAY_MOLGEIM_SUMMON = -1603034, - SAY_MOLGEIM_DEATH_1 = -1603035, - SAY_MOLGEIM_DEATH_2 = -1603036, - SAY_MOLGEIM_BERSERK = -1603037, - - SAY_BRUNDIR_AGGRO = -1603040, - SAY_BRUNDIR_SLAY_1 = -1603041, - SAY_BRUNDIR_SLAY_2 = -1603042, - SAY_BRUNDIR_SPECIAL = -1603043, - SAY_BRUNDIR_FLIGHT = -1603044, - SAY_BRUNDIR_DEATH_1 = -1603045, - SAY_BRUNDIR_DEATH_2 = -1603046, - SAY_BRUNDIR_BERSERK = -1603047, -}; - -enum AssemblyNPCs -{ - NPC_WORLD_TRIGGER = 22515, -}; - -#define EMOTE_OVERLOAD "Stormcaller Brundir begins to Overload!" // Move it to DB -#define FLOOR_Z 427.28f -#define FINAL_FLIGHT_Z 435.0f - -bool IsEncounterComplete(InstanceScript* instance, Creature* me) -{ - if (!instance || !me) - return false; - - for (uint8 i = 0; i < 3; ++i) - { - uint64 guid = instance->GetData64(BOSS_STEELBREAKER + i); - if (!guid) - return false; - - if (Creature* boss = ObjectAccessor::GetCreature(*me, guid)) - { - if (boss->isAlive()) - return false; - } - else - return false; - } - - return true; -} - -void RespawnEncounter(InstanceScript* instance, Creature* me) -{ - for (uint8 i = 0; i < 3; ++i) - { - uint64 guid = instance->GetData64(BOSS_STEELBREAKER + i); - if (!guid) - continue; - - if (Creature* boss = ObjectAccessor::GetCreature(*me, guid)) - { - if (!boss->isAlive()) - { - boss->Respawn(); - boss->GetMotionMaster()->MoveTargetedHome(); - } - } - } -} - -void StartEncounter(InstanceScript* instance, Creature* me, Unit* /*target*/) -{ - if (instance->GetBossState(BOSS_ASSEMBLY_OF_IRON) == IN_PROGRESS) - return; // Prevent recursive calls - - instance->SetBossState(BOSS_ASSEMBLY_OF_IRON, IN_PROGRESS); - - for (uint8 i = 0; i < 3; ++i) - { - uint64 guid = instance->GetData64(BOSS_STEELBREAKER + i); - if (!guid) - continue; - - if (Creature* boss = ObjectAccessor::GetCreature(*me, guid)) - boss->SetInCombatWithZone(); - } -} - -class boss_steelbreaker : public CreatureScript -{ - public: - boss_steelbreaker() : CreatureScript("boss_steelbreaker") { } - - struct boss_steelbreakerAI : public BossAI - { - boss_steelbreakerAI(Creature* creature) : BossAI(creature, BOSS_ASSEMBLY_OF_IRON) - { - instance = me->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 phase; - - void Reset() - { - _Reset(); - phase = 0; - me->RemoveAllAuras(); - RespawnEncounter(instance, me); - } - - void EnterCombat(Unit* who) - { - StartEncounter(instance, me, who); - DoScriptText(SAY_STEELBREAKER_AGGRO, me); - DoZoneInCombat(); - DoCast(me, SPELL_HIGH_VOLTAGE); - events.SetPhase(++phase); - events.ScheduleEvent(EVENT_BERSERK, 900000); - events.ScheduleEvent(EVENT_FUSION_PUNCH, 15000); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_STEELBREAKER: - me->SetHealth(me->GetMaxHealth()); - me->AddAura(SPELL_SUPERCHARGE, me); - events.SetPhase(++phase); - events.RescheduleEvent(EVENT_FUSION_PUNCH, 15000); - if (phase >= 2) - events.RescheduleEvent(EVENT_STATIC_DISRUPTION, 30000); - if (phase >= 3) - events.RescheduleEvent(EVENT_OVERWHELMING_POWER, urand(2000, 5000)); - break; - case ACTION_ADD_CHARGE: - DoCast(me, SPELL_ELECTRICAL_CHARGE, true); - break; - } - } - - void JustDied(Unit* /*who*/) - { - DoScriptText(RAND(SAY_STEELBREAKER_DEATH_1, SAY_STEELBREAKER_DEATH_2), me); - if (IsEncounterComplete(instance, me)) - instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE); - else - me->SetLootRecipient(NULL); - - if (Creature* Brundir = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRUNDIR))) - if (Brundir->isAlive()) - Brundir->AI()->DoAction(ACTION_BRUNDIR); - - if (Creature* Molgeim = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MOLGEIM))) - if (Molgeim->isAlive()) - Molgeim->AI()->DoAction(ACTION_MOLGEIM); - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_STEELBREAKER_SLAY_1, SAY_STEELBREAKER_SLAY_2), me); - - if (phase == 3) - DoCast(me, SPELL_ELECTRICAL_CHARGE); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_BERSERK: - DoScriptText(SAY_STEELBREAKER_BERSERK, me); - DoCast(SPELL_BERSERK); - events.CancelEvent(EVENT_BERSERK); - break; - case EVENT_FUSION_PUNCH: - if (me->IsWithinMeleeRange(me->getVictim())) - DoCastVictim(SPELL_FUSION_PUNCH); - events.ScheduleEvent(EVENT_FUSION_PUNCH, urand(13000, 22000)); - break; - case EVENT_STATIC_DISRUPTION: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_STATIC_DISRUPTION); - events.ScheduleEvent(EVENT_STATIC_DISRUPTION, urand(20000, 40000)); - break; - case EVENT_OVERWHELMING_POWER: - DoScriptText(SAY_STEELBREAKER_POWER, me); - DoCastVictim(SPELL_OVERWHELMING_POWER); - events.ScheduleEvent(EVENT_OVERWHELMING_POWER, RAID_MODE(60000, 35000)); - break; - } - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class boss_runemaster_molgeim : public CreatureScript -{ - public: - boss_runemaster_molgeim() : CreatureScript("boss_runemaster_molgeim") { } - - struct boss_runemaster_molgeimAI : public BossAI - { - boss_runemaster_molgeimAI(Creature* creature) : BossAI(creature, BOSS_ASSEMBLY_OF_IRON) - { - instance = me->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 phase; - - void Reset() - { - _Reset(); - phase = 0; - me->RemoveAllAuras(); - RespawnEncounter(instance, me); - } - - void EnterCombat(Unit* who) - { - StartEncounter(instance, me, who); - DoScriptText(SAY_MOLGEIM_AGGRO, me); - DoZoneInCombat(); - events.SetPhase(++phase); - events.ScheduleEvent(EVENT_BERSERK, 900000); - events.ScheduleEvent(EVENT_SHIELD_OF_RUNES, 30000); - events.ScheduleEvent(EVENT_RUNE_OF_POWER, 20000); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_MOLGEIM: - me->SetHealth(me->GetMaxHealth()); - me->AddAura(SPELL_SUPERCHARGE, me); - events.SetPhase(++phase); - events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 27000); - events.RescheduleEvent(EVENT_RUNE_OF_POWER, 25000); - if (phase >= 2) - events.RescheduleEvent(EVENT_RUNE_OF_DEATH, 30000); - if (phase >= 3) - events.RescheduleEvent(EVENT_RUNE_OF_SUMMONING, urand(20000, 30000)); - break; - } - } - - void JustDied(Unit* /*who*/) - { - DoScriptText(RAND(SAY_MOLGEIM_DEATH_1, SAY_MOLGEIM_DEATH_2), me); - if (IsEncounterComplete(instance, me)) - instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE); - else - me->SetLootRecipient(NULL); - - if (Creature* Brundir = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRUNDIR))) - if (Brundir->isAlive()) - Brundir->AI()->DoAction(ACTION_BRUNDIR); - - if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) - if (Steelbreaker->isAlive()) - Steelbreaker->AI()->DoAction(ACTION_STEELBREAKER); - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_MOLGEIM_SLAY_1, SAY_MOLGEIM_SLAY_2), me); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_BERSERK: - DoScriptText(SAY_MOLGEIM_BERSERK, me); - DoCast(SPELL_BERSERK); - events.CancelEvent(EVENT_BERSERK); - break; - case EVENT_RUNE_OF_POWER: - { - Unit* target = NULL; - switch (urand(0, 2)) - { - case 0: - target = me; - break; - case 1: - if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) - if (Steelbreaker->isAlive()) - target = Steelbreaker; - break; - case 2: - if (Creature* Brundir = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) - if (Brundir->isAlive()) - target = Brundir; - break; - } - DoCast(target, SPELL_SUMMON_RUNE_OF_POWER); - events.ScheduleEvent(EVENT_RUNE_OF_POWER, 60000); - break; - } - case EVENT_SHIELD_OF_RUNES: - DoCast(me, SPELL_SHIELD_OF_RUNES); - events.ScheduleEvent(EVENT_SHIELD_OF_RUNES, urand(27000, 34000)); - break; - case EVENT_RUNE_OF_DEATH: - DoScriptText(SAY_MOLGEIM_RUNE_DEATH, me); - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_RUNE_OF_DEATH); - events.ScheduleEvent(EVENT_RUNE_OF_DEATH, urand(30000, 40000)); - break; - case EVENT_RUNE_OF_SUMMONING: - DoScriptText(SAY_MOLGEIM_SUMMON, me); - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_RUNE_OF_SUMMONING); - events.ScheduleEvent(EVENT_RUNE_OF_SUMMONING, urand(30000, 45000)); - break; - } - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class mob_rune_of_power : public CreatureScript -{ - public: - mob_rune_of_power() : CreatureScript("mob_rune_of_power") { } - - struct mob_rune_of_powerAI : public ScriptedAI - { - mob_rune_of_powerAI(Creature* creature) : ScriptedAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->setFaction(16); // Same faction as bosses - DoCast(SPELL_RUNE_OF_POWER); - - me->DespawnOrUnsummon(60000); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_rune_of_powerAI(creature); - } -}; - -class mob_lightning_elemental : public CreatureScript -{ - public: - mob_lightning_elemental() : CreatureScript("mob_lightning_elemental") { } - - struct mob_lightning_elementalAI : public ScriptedAI - { - mob_lightning_elementalAI(Creature* creature) : ScriptedAI(creature) - { - me->SetInCombatWithZone(); - me->AddAura(SPELL_LIGHTNING_ELEMENTAL_PASSIVE, me); - } - - // Nothing to do here, just let the creature chase players and procflags == 2 on the applied aura will trigger explosion - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_lightning_elementalAI(creature); - } -}; - -class mob_rune_of_summoning : public CreatureScript -{ - public: - mob_rune_of_summoning() : CreatureScript("mob_rune_of_summoning") { } - - struct mob_rune_of_summoningAI : public ScriptedAI - { - mob_rune_of_summoningAI(Creature* creature) : ScriptedAI(creature) - { - me->AddAura(SPELL_RUNE_OF_SUMMONING_VIS, me); - summonCount = 0; - summonTimer = 2000; - } - - uint32 summonCount; - uint32 summonTimer; - - void UpdateAI(uint32 const diff) - { - if (summonTimer <= diff) - SummonLightningElemental(); - else - summonTimer -= diff; - } - - void SummonLightningElemental() - { - me->CastSpell(me, SPELL_RUNE_OF_SUMMONING_SUMMON, false); - if (++summonCount == 10) // TODO: Find out if this amount is right - me->DespawnOrUnsummon(); - else - summonTimer = 2000; // TODO: Find out of timer is right - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_rune_of_summoningAI(creature); - } -}; - -class boss_stormcaller_brundir : public CreatureScript -{ - public: - boss_stormcaller_brundir() : CreatureScript("boss_stormcaller_brundir") { } - - struct boss_stormcaller_brundirAI : public BossAI - { - boss_stormcaller_brundirAI(Creature* creature) : BossAI(creature, BOSS_ASSEMBLY_OF_IRON) - { - instance = me->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 phase; - - void Reset() - { - _Reset(); - phase = 0; - me->RemoveAllAuras(); - me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, false); // Should be interruptable unless overridden by spell (Overload) - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, false); // Reset immumity, Brundir should be stunnable by default - RespawnEncounter(instance, me); - } - - void EnterCombat(Unit* who) - { - StartEncounter(instance, me, who); - DoScriptText(SAY_BRUNDIR_AGGRO, me); - DoZoneInCombat(); - events.SetPhase(++phase); - events.ScheduleEvent(EVENT_MOVE_POSITION, 1000); - events.ScheduleEvent(EVENT_BERSERK, 900000); - events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 4000); - events.ScheduleEvent(EVENT_OVERLOAD, urand(60000, 120000)); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_BRUNDIR: - me->SetHealth(me->GetMaxHealth()); - me->AddAura(SPELL_SUPERCHARGE, me); - events.SetPhase(++phase); - events.RescheduleEvent(EVENT_CHAIN_LIGHTNING, urand(7000, 12000)); - events.RescheduleEvent(EVENT_OVERLOAD, urand(40000, 50000)); - if (phase >= 2) - events.RescheduleEvent(EVENT_LIGHTNING_WHIRL, urand(15000, 250000)); - if (phase >= 3) - { - DoCast(me, SPELL_STORMSHIELD); - events.RescheduleEvent(EVENT_LIGHTNING_TENDRILS, urand(50000, 60000)); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); // Apply immumity to stuns - } - break; - - } - } - - void JustDied(Unit* /*who*/) - { - DoScriptText(RAND(SAY_BRUNDIR_DEATH_1, SAY_BRUNDIR_DEATH_2), me); - if (IsEncounterComplete(instance, me)) - instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE); - else - me->SetLootRecipient(NULL); - - if (Creature* Molgeim = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MOLGEIM))) - if (Molgeim->isAlive()) - Molgeim->AI()->DoAction(ACTION_MOLGEIM); - - if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STEELBREAKER))) - if (Steelbreaker->isAlive()) - Steelbreaker->AI()->DoAction(ACTION_STEELBREAKER); - - // Prevent to have Brundir somewhere in the air when he die in Air phase - if (me->GetPositionZ() > FLOOR_Z) - me->GetMotionMaster()->MoveFall(FLOOR_Z); - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_BRUNDIR_SLAY_1, SAY_BRUNDIR_SLAY_2), me); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_BERSERK: - DoScriptText(SAY_BRUNDIR_BERSERK, me); - DoCast(SPELL_BERSERK); - events.CancelEvent(EVENT_BERSERK); - break; - case EVENT_CHAIN_LIGHTNING: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_CHAIN_LIGHTNING); - events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, urand(7000, 10000)); - break; - case EVENT_OVERLOAD: - me->MonsterTextEmote(EMOTE_OVERLOAD, 0, true); - DoScriptText(SAY_BRUNDIR_SPECIAL, me); - DoCast(SPELL_OVERLOAD); - events.ScheduleEvent(EVENT_OVERLOAD, urand(60000, 120000)); - break; - case EVENT_LIGHTNING_WHIRL: - DoCast(SPELL_LIGHTNING_WHIRL); - events.ScheduleEvent(EVENT_LIGHTNING_WHIRL, urand(15000, 20000)); - break; - case EVENT_LIGHTNING_TENDRILS: - DoScriptText(SAY_BRUNDIR_FLIGHT, me); - DoCast(RAID_MODE(SPELL_LIGHTNING_TENDRILS_10M, SPELL_LIGHTNING_TENDRILS_25M)); - DoCast(SPELL_LIGHTNING_TENDRILS_VISUAL); - me->AttackStop(); - //me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - me->GetMotionMaster()->Initialize(); - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), FINAL_FLIGHT_Z); - events.DelayEvents(35000); - events.ScheduleEvent(EVENT_FLIGHT, 2500); - events.ScheduleEvent(EVENT_ENDFLIGHT, 32500); - events.ScheduleEvent(EVENT_LIGHTNING_TENDRILS, 90000); - break; - case EVENT_FLIGHT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - me->GetMotionMaster()->MovePoint(0, target->GetPositionX(), target->GetPositionY(), FINAL_FLIGHT_Z); - events.ScheduleEvent(EVENT_FLIGHT, 6000); - break; - case EVENT_ENDFLIGHT: - me->GetMotionMaster()->Initialize(); - me->GetMotionMaster()->MovePoint(0, 1586.920166f, 119.848984f, FINAL_FLIGHT_Z); - events.CancelEvent(EVENT_FLIGHT); - events.CancelEvent(EVENT_ENDFLIGHT); - events.ScheduleEvent(EVENT_LAND, 4000); - break; - case EVENT_LAND: - me->GetMotionMaster()->Initialize(); - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), FLOOR_Z); - events.CancelEvent(EVENT_LAND); - events.ScheduleEvent(EVENT_GROUND, 2500); - break; - case EVENT_GROUND: - //me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - me->RemoveAurasDueToSpell(RAID_MODE(SPELL_LIGHTNING_TENDRILS_10M, SPELL_LIGHTNING_TENDRILS_25M)); - me->RemoveAurasDueToSpell(SPELL_LIGHTNING_TENDRILS_VISUAL); - DoStartMovement(me->getVictim()); - events.CancelEvent(EVENT_GROUND); - me->getThreatManager().resetAllAggro(); - break; - case EVENT_MOVE_POSITION: - if (me->IsWithinMeleeRange(me->getVictim())) - { - float x = float(irand(-25, 25)); - float y = float(irand(-25, 25)); - me->GetMotionMaster()->MovePoint(0, me->GetPositionX() + x, me->GetPositionY() + y, FLOOR_Z); - // Prevention to go outside the room or into the walls - if (Creature* trigger = me->FindNearestCreature(NPC_WORLD_TRIGGER, 100.0f, true)) - if (me->GetDistance(trigger) >= 50.0f) - me->GetMotionMaster()->MovePoint(0, trigger->GetPositionX(), trigger->GetPositionY(), FLOOR_Z); - } - events.ScheduleEvent(EVENT_MOVE_POSITION, urand(7500, 10000)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class spell_shield_of_runes : public SpellScriptLoader -{ - public: - spell_shield_of_runes() : SpellScriptLoader("spell_shield_of_runes") { } - - class spell_shield_of_runes_AuraScript : public AuraScript - { - PrepareAuraScript(spell_shield_of_runes_AuraScript); - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) - caster->CastSpell(caster, SPELL_SHIELD_OF_RUNES_BUFF, false); - } - - void Register() - { - AfterEffectRemove += AuraEffectRemoveFn(spell_shield_of_runes_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_shield_of_runes_AuraScript(); - } -}; - -class spell_assembly_meltdown : public SpellScriptLoader -{ - public: - spell_assembly_meltdown() : SpellScriptLoader("spell_assembly_meltdown") { } - - class spell_assembly_meltdown_SpellScript : public SpellScript - { - PrepareSpellScript(spell_assembly_meltdown_SpellScript); - - void HandleInstaKill(SpellEffIndex /*effIndex*/) - { - if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(BOSS_STEELBREAKER))) - Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_assembly_meltdown_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_assembly_meltdown_SpellScript(); - } -}; - -void AddSC_boss_assembly_of_iron() -{ - new boss_steelbreaker(); - new boss_runemaster_molgeim(); - new boss_stormcaller_brundir(); - new mob_lightning_elemental(); - new mob_rune_of_summoning(); - new mob_rune_of_power(); - new spell_shield_of_runes(); - new spell_assembly_meltdown(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_auriaya.cpp deleted file mode 100644 index bcc417c50cd..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_auriaya.cpp +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "SpellScript.h" -#include "ulduar.h" - -enum AuriayaSpells -{ - // Auriaya - SPELL_SENTINEL_BLAST = 64389, - SPELL_SONIC_SCREECH = 64422, - SPELL_TERRIFYING_SCREECH = 64386, - SPELL_SUMMON_SWARMING_GUARDIAN = 64396, - SPELL_ACTIVATE_DEFENDER = 64449, - SPELL_DEFENDER_TRIGGER = 64448, - SPELL_SUMMON_DEFENDER = 64447, - SPELL_BERSERK = 47008, - - // Feral Defender - SPELL_FERAL_RUSH = 64496, - SPELL_FERAL_POUNCE = 64478, - SPELL_SEEPING_ESSENCE = 64458, - SPELL_SUMMON_ESSENCE = 64457, - SPELL_FERAL_ESSENCE = 64455, - - // Sanctum Sentry - SPELL_SAVAGE_POUNCE = 64666, - SPELL_RIP_FLESH = 64375, - SPELL_STRENGHT_PACK = 64369, -}; - -enum AuriayaNPCs -{ - NPC_SANCTUM_SENTRY = 34014, - NPC_FERAL_DEFENDER = 34035, - NPC_FERAL_DEFENDER_TRIGGER = 34096, - NPC_SEEPING_TRIGGER = 34098, -}; - -enum AuriayaEvents -{ - // Auriaya - EVENT_SCREECH = 1, - EVENT_BLAST = 2, - EVENT_TERRIFYING = 3, - EVENT_SUMMON = 4, - EVENT_DEFENDER = 5, - EVENT_ACTIVATE_DEFENDER = 6, - EVENT_RESPAWN_DEFENDER = 7, - EVENT_BERSERK = 8, - - // Sanctum Sentry - EVENT_RIP = 9, - EVENT_POUNCE = 10, - - // Feral Defender - EVENT_FERAL_POUNCE = 11, - EVENT_RUSH = 12, -}; - -enum AuriayaYells -{ - // Yells - SAY_AGGRO = -1603050, - SAY_SLAY_1 = -1603051, - SAY_SLAY_2 = -1603052, - SAY_DEATH = -1603053, - SAY_BERSERK = -1603054, - - // Emotes - EMOTE_FEAR = -1603055, - EMOTE_DEFENDER = -1603056, -}; - -enum AuriayaActions -{ - ACTION_CRAZY_CAT_LADY = 0, - ACTION_RESPAWN_DEFENDER -}; - -#define SENTRY_NUMBER RAID_MODE(2, 4) -#define DATA_NINE_LIVES 30763077 -#define DATA_CRAZY_CAT_LADY 30063007 - -class boss_auriaya : public CreatureScript -{ - public: - boss_auriaya() : CreatureScript("boss_auriaya") { } - - struct boss_auriayaAI : public BossAI - { - boss_auriayaAI(Creature* creature) : BossAI(creature, BOSS_AURIAYA) - { - } - - void Reset() - { - _Reset(); - DefenderGUID = 0; - defenderLives = 8; - crazyCatLady = true; - nineLives = false; - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - DoScriptText(SAY_AGGRO, me); - - events.ScheduleEvent(EVENT_SCREECH, urand(45000, 65000)); - events.ScheduleEvent(EVENT_BLAST, urand(20000, 25000)); - events.ScheduleEvent(EVENT_TERRIFYING, urand(20000, 30000)); - events.ScheduleEvent(EVENT_DEFENDER, urand(40000, 55000)); - events.ScheduleEvent(EVENT_SUMMON, urand(45000, 55000)); - events.ScheduleEvent(EVENT_BERSERK, 600000); - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void JustSummoned(Creature* summoned) - { - summons.Summon(summoned); - - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - { - summoned->AI()->AttackStart(target); - summoned->AddThreat(target, 250.0f); - DoZoneInCombat(summoned); - } - - if (summoned->GetEntry() == NPC_FERAL_DEFENDER) - { - if (!summoned->isInCombat() && me->getVictim()) - summoned->AI()->AttackStart(me->getVictim()); - summoned->SetAuraStack(SPELL_FERAL_ESSENCE, summoned, 9); - DefenderGUID = summoned->GetGUID(); - DoZoneInCombat(summoned); - } - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_CRAZY_CAT_LADY: - SetData(DATA_CRAZY_CAT_LADY, 0); - break; - case ACTION_RESPAWN_DEFENDER: - --defenderLives; - if (!defenderLives) - { - SetData(DATA_NINE_LIVES, 1); - break; - } - events.ScheduleEvent(EVENT_RESPAWN_DEFENDER, 30000); - break; - default: - break; - } - } - - uint32 GetData(uint32 type) - { - switch (type) - { - case DATA_NINE_LIVES: - return nineLives ? 1 : 0; - case DATA_CRAZY_CAT_LADY: - return crazyCatLady ? 1 : 0; - } - - return 0; - } - - void SetData(uint32 id, uint32 data) - { - switch (id) - { - case DATA_NINE_LIVES: - nineLives = data ? true : false; - break; - case DATA_CRAZY_CAT_LADY: - crazyCatLady = data ? true : false; - break; - } - } - - void JustDied(Unit* /*who*/) - { - DoScriptText(SAY_DEATH, me); - _JustDied(); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SCREECH: - DoCast(SPELL_SONIC_SCREECH); - events.ScheduleEvent(EVENT_SCREECH, urand(40000, 60000)); - break; - case EVENT_TERRIFYING: - DoScriptText(EMOTE_FEAR, me); - DoCast(SPELL_TERRIFYING_SCREECH); - events.ScheduleEvent(EVENT_TERRIFYING, urand(20000, 30000)); - break; - case EVENT_BLAST: - DoCastAOE(SPELL_SENTINEL_BLAST); - events.ScheduleEvent(EVENT_BLAST, urand(25000, 35000)); - break; - case EVENT_DEFENDER: - DoScriptText(EMOTE_DEFENDER, me); - DoCast(SPELL_DEFENDER_TRIGGER); - if (Creature* trigger = me->FindNearestCreature(NPC_FERAL_DEFENDER_TRIGGER, 15.0f, true)) - DoCast(trigger, SPELL_ACTIVATE_DEFENDER, true); - break; - case EVENT_RESPAWN_DEFENDER: - if (Creature* Defender = ObjectAccessor::GetCreature(*me, DefenderGUID)) - { - Defender->Respawn(); - if (defenderLives) - Defender->SetAuraStack(SPELL_FERAL_ESSENCE, Defender, defenderLives); - Defender->SetInCombatWithZone(); - if (!Defender->isInCombat()) - Defender->AI()->AttackStart(me->getVictim()); - events.CancelEvent(EVENT_RESPAWN_DEFENDER); - } - break; - case EVENT_SUMMON: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - DoCast(target, SPELL_SUMMON_SWARMING_GUARDIAN); - events.ScheduleEvent(EVENT_SUMMON, urand(30000, 45000)); - break; - case EVENT_BERSERK: - DoCast(me, SPELL_BERSERK, true); - DoScriptText(SAY_BERSERK, me); - events.CancelEvent(EVENT_BERSERK); - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - uint64 DefenderGUID; - uint8 defenderLives; - bool crazyCatLady; - bool nineLives; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class npc_auriaya_seeping_trigger : public CreatureScript -{ - public: - npc_auriaya_seeping_trigger() : CreatureScript("npc_auriaya_seeping_trigger") { } - - struct npc_auriaya_seeping_triggerAI : public ScriptedAI - { - npc_auriaya_seeping_triggerAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - void Reset() - { - me->ForcedDespawn(600000); - DoCast(me, SPELL_SEEPING_ESSENCE); - } - - void UpdateAI(uint32 const /*diff*/) - { - if (instance->GetBossState(BOSS_AURIAYA) != IN_PROGRESS) - me->ForcedDespawn(); - } - - private: - InstanceScript* instance; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_auriaya_seeping_triggerAI(creature); - } -}; - -class npc_sanctum_sentry : public CreatureScript -{ - public: - npc_sanctum_sentry() : CreatureScript("npc_sanctum_sentry") { } - - struct npc_sanctum_sentryAI : public ScriptedAI - { - npc_sanctum_sentryAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - void Reset() - { - events.ScheduleEvent(EVENT_RIP, urand(4000, 8000)); - events.ScheduleEvent(EVENT_POUNCE, urand(12000, 15000)); - } - - void EnterCombat(Unit* /*who*/) - { - DoCast(me, SPELL_STRENGHT_PACK, true); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_RIP: - DoCastVictim(SPELL_RIP_FLESH); - events.ScheduleEvent(EVENT_RIP, urand(12000, 15000)); - break; - case EVENT_POUNCE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - { - me->AddThreat(target, 100.0f); - me->AI()->AttackStart(target); - DoCast(target, SPELL_SAVAGE_POUNCE); - } - events.ScheduleEvent(EVENT_POUNCE, urand(12000, 17000)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Auriaya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_AURIAYA))) - Auriaya->AI()->DoAction(ACTION_CRAZY_CAT_LADY); - } - - private: - InstanceScript* instance; - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_sanctum_sentryAI(creature); - } -}; - -class npc_feral_defender : public CreatureScript -{ - public: - npc_feral_defender() : CreatureScript("npc_feral_defender") { } - - struct npc_feral_defenderAI : public ScriptedAI - { - npc_feral_defenderAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - void Reset() - { - events.ScheduleEvent(EVENT_FERAL_POUNCE, 5000); - events.ScheduleEvent(EVENT_RUSH, 10000); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FERAL_POUNCE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - { - me->AddThreat(target, 100.0f); - me->AI()->AttackStart(target); - DoCast(target, SPELL_FERAL_POUNCE); - } - events.ScheduleEvent(EVENT_FERAL_POUNCE, urand(10000, 12000)); - break; - case EVENT_RUSH: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - { - me->AddThreat(target, 100.0f); - me->AI()->AttackStart(target); - DoCast(target, SPELL_FERAL_RUSH); - } - events.ScheduleEvent(EVENT_RUSH, urand(10000, 12000)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*who*/) - { - DoCast(me, SPELL_SUMMON_ESSENCE); - if (Creature* Auriaya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_AURIAYA))) - Auriaya->AI()->DoAction(ACTION_RESPAWN_DEFENDER); - } - - private: - InstanceScript* instance; - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_feral_defenderAI(creature); - } -}; - -class SanctumSentryCheck -{ - public: - bool operator() (Unit* unit) - { - if (unit->GetEntry() == NPC_SANCTUM_SENTRY) - return false; - - return true; - } -}; - -class spell_auriaya_strenght_of_the_pack : public SpellScriptLoader -{ - public: - spell_auriaya_strenght_of_the_pack() : SpellScriptLoader("spell_auriaya_strenght_of_the_pack") { } - - class spell_auriaya_strenght_of_the_pack_SpellScript : public SpellScript - { - PrepareSpellScript(spell_auriaya_strenght_of_the_pack_SpellScript); - - void FilterTargets(std::list& unitList) - { - unitList.remove_if (SanctumSentryCheck()); - } - - void Register() - { - OnUnitTargetSelect += SpellUnitTargetFn(spell_auriaya_strenght_of_the_pack_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_auriaya_strenght_of_the_pack_SpellScript(); - } -}; - -class spell_auriaya_sentinel_blast : public SpellScriptLoader -{ - public: - spell_auriaya_sentinel_blast() : SpellScriptLoader("spell_auriaya_sentinel_blast") { } - - class spell_auriaya_sentinel_blast_SpellScript : public SpellScript - { - PrepareSpellScript(spell_auriaya_sentinel_blast_SpellScript); - - void FilterTargets(std::list& unitList) - { - unitList.remove_if (PlayerOrPetCheck()); - } - - void Register() - { - OnUnitTargetSelect += SpellUnitTargetFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnUnitTargetSelect += SpellUnitTargetFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_auriaya_sentinel_blast_SpellScript(); - } -}; - - -class achievement_nine_lives : public AchievementCriteriaScript -{ - public: - achievement_nine_lives() : AchievementCriteriaScript("achievement_nine_lives") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Auriaya = target->ToCreature()) - if (Auriaya->AI()->GetData(DATA_NINE_LIVES)) - return true; - - return false; - } -}; - -class achievement_crazy_cat_lady : public AchievementCriteriaScript -{ - public: - achievement_crazy_cat_lady() : AchievementCriteriaScript("achievement_crazy_cat_lady") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Auriaya = target->ToCreature()) - if (Auriaya->AI()->GetData(DATA_CRAZY_CAT_LADY)) - return true; - - return false; - } -}; - -void AddSC_boss_auriaya() -{ - new boss_auriaya(); - new npc_auriaya_seeping_trigger(); - new npc_feral_defender(); - new npc_sanctum_sentry(); - new spell_auriaya_strenght_of_the_pack(); - new spell_auriaya_sentinel_blast(); - new achievement_nine_lives(); - new achievement_crazy_cat_lady(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp deleted file mode 100644 index ad79d1b56cc..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp +++ /dev/null @@ -1,1755 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 . - */ - -/* - * Comment: there is missing code on triggers, - * brann bronzebeard needs correct gossip info. - * requires more work involving area triggers. - * if reached brann speaks through his radio.. - */ - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "ScriptedGossip.h" -#include "ScriptedEscortAI.h" -#include "CombatAI.h" -#include "PassiveAI.h" -#include "ObjectMgr.h" -#include "SpellInfo.h" -#include "SpellScript.h" -#include "Vehicle.h" -#include "VehicleDefines.h" -#include "ulduar.h" - -enum Spells -{ - SPELL_PURSUED = 62374, - SPELL_GATHERING_SPEED = 62375, - SPELL_BATTERING_RAM = 62376, - SPELL_FLAME_VENTS = 62396, - SPELL_MISSILE_BARRAGE = 62400, - SPELL_SYSTEMS_SHUTDOWN = 62475, - SPELL_OVERLOAD_CIRCUIT = 62399, - SPELL_START_THE_ENGINE = 62472, - SPELL_SEARING_FLAME = 62402, - SPELL_BLAZE = 62292, - SPELL_TAR_PASSIVE = 62288, - SPELL_SMOKE_TRAIL = 63575, - SPELL_ELECTROSHOCK = 62522, - SPELL_NAPALM = 63666, - SPELL_INVIS_AND_STEALTH_DETECT = 18950, // Passive - //TOWER Additional SPELLS - SPELL_THORIM_S_HAMMER = 62911, // Tower of Storms - SPELL_MIMIRON_S_INFERNO = 62909, // Tower of Flames - SPELL_HODIR_S_FURY = 62533, // Tower of Frost - SPELL_FREYA_S_WARD = 62906, // Tower of Nature - SPELL_FREYA_SUMMONS = 62947, // Tower of Nature - //TOWER ap & health spells - SPELL_BUFF_TOWER_OF_STORMS = 65076, - SPELL_BUFF_TOWER_OF_FLAMES = 65075, - SPELL_BUFF_TOWER_OF_FR0ST = 65077, - SPELL_BUFF_TOWER_OF_LIFE = 64482, - //Additional Spells - SPELL_LASH = 65062, - SPELL_FREYA_S_WARD_EFFECT_1 = 62947, - SPELL_FREYA_S_WARD_EFFECT_2 = 62907, - SPELL_AUTO_REPAIR = 62705, - AURA_DUMMY_BLUE = 63294, - AURA_DUMMY_GREEN = 63295, - AURA_DUMMY_YELLOW = 63292, - SPELL_LIQUID_PYRITE = 62494, - SPELL_DUSTY_EXPLOSION = 63360, - SPELL_DUST_CLOUD_IMPACT = 54740, - AURA_STEALTH_DETECTION = 18950, - SPELL_RIDE_VEHICLE = 46598, -}; - -enum Creatures -{ - NPC_SEAT = 33114, - NPC_MECHANOLIFT = 33214, - NPC_LIQUID = 33189, - NPC_CONTAINER = 33218, - NPC_THORIM_BEACON = 33365, - NPC_MIMIRON_BEACON = 33370, - NPC_HODIR_BEACON = 33212, - NPC_FREYA_BEACON = 33367, - NPC_THORIM_TARGET_BEACON = 33364, - NPC_MIMIRON_TARGET_BEACON = 33369, - NPC_HODIR_TARGET_BEACON = 33108, - NPC_FREYA_TARGET_BEACON = 33366, - NPC_LOREKEEPER = 33686, // Hard mode starter - NPC_BRANZ_BRONZBEARD = 33579, - NPC_DELORAH = 33701, - NPC_ULDUAR_GAUNTLET_GENERATOR = 33571, // Trigger tied to towers -}; - -enum Towers -{ - GO_TOWER_OF_STORMS = 194377, - GO_TOWER_OF_FLAMES = 194371, - GO_TOWER_OF_FROST = 194370, - GO_TOWER_OF_LIFE = 194375, -}; - -enum Events -{ - EVENT_PURSUE = 1, - EVENT_MISSILE = 2, - EVENT_VENT = 3, - EVENT_SPEED = 4, - EVENT_SUMMON = 5, - EVENT_SHUTDOWN = 6, - EVENT_REPAIR = 7, - EVENT_THORIM_S_HAMMER = 8, // Tower of Storms - EVENT_MIMIRON_S_INFERNO = 9, // Tower of Flames - EVENT_HODIR_S_FURY = 10, // Tower of Frost - EVENT_FREYA_S_WARD = 11, // Tower of Nature -}; - -enum Seats -{ - SEAT_PLAYER = 0, - SEAT_TURRET = 1, - SEAT_DEVICE = 2, - SEAT_CANNON = 7, -}; - -enum Vehicles -{ - VEHICLE_SIEGE = 33060, - VEHICLE_CHOPPER = 33062, - VEHICLE_DEMOLISHER = 33109, -}; - -#define EMOTE_PURSUE "Flame Leviathan pursues $N." -#define EMOTE_OVERLOAD "Flame Leviathan's circuits overloaded." -#define EMOTE_REPAIR "Automatic repair sequence initiated." -#define DATA_SHUTOUT 29112912 // 2911, 2912 are achievement IDs -#define DATA_ORBIT_ACHIEVEMENTS 1 -#define VEHICLE_SPAWNS 5 -#define FREYA_SPAWNS 4 - -enum Yells -{ - SAY_AGGRO = -1603060, - SAY_SLAY = -1603061, - SAY_DEATH = -1603062, - SAY_TARGET_1 = -1603063, - SAY_TARGET_2 = -1603064, - SAY_TARGET_3 = -1603065, - SAY_HARDMODE = -1603066, - SAY_TOWER_NONE = -1603067, - SAY_TOWER_FROST = -1603068, - SAY_TOWER_FLAME = -1603069, - SAY_TOWER_NATURE = -1603070, - SAY_TOWER_STORM = -1603071, - SAY_PLAYER_RIDING = -1603072, - SAY_OVERLOAD_1 = -1603073, - SAY_OVERLOAD_2 = -1603074, - SAY_OVERLOAD_3 = -1603075, -}; - -enum MiscellanousData -{ - // Other actions are in Ulduar.h - ACTION_START_HARD_MODE = 5, - ACTION_SPAWN_VEHICLES = 6, - // Amount of seats depending on Raid mode - TWO_SEATS = 2, - FOUR_SEATS = 4, -}; - -Position const Center[]= -{ - {354.8771f, -12.90240f, 409.803650f, 0.0f}, -}; - -Position const InfernoStart[]= -{ - {390.93f, -13.91f, 409.81f, 0.0f}, -}; - -Position const PosSiege[VEHICLE_SPAWNS] = -{ - {-814.59f, -64.54f, 429.92f, 5.969f}, - {-784.37f, -33.31f, 429.92f, 5.096f}, - {-808.99f, -52.10f, 429.92f, 5.668f}, - {-798.59f, -44.00f, 429.92f, 5.663f}, - {-812.83f, -77.71f, 429.92f, 0.046f}, -}; - -Position const PosChopper[VEHICLE_SPAWNS] = -{ - {-717.83f, -106.56f, 430.02f, 0.122f}, - {-717.83f, -114.23f, 430.44f, 0.122f}, - {-717.83f, -109.70f, 430.22f, 0.122f}, - {-718.45f, -118.24f, 430.26f, 0.052f}, - {-718.45f, -123.58f, 430.41f, 0.085f}, -}; - -Position const PosDemolisher[VEHICLE_SPAWNS] = -{ - {-724.12f, -176.64f, 430.03f, 2.543f}, - {-766.70f, -225.03f, 430.50f, 1.710f}, - {-729.54f, -186.26f, 430.12f, 1.902f}, - {-756.01f, -219.23f, 430.50f, 2.369f}, - {-798.01f, -227.24f, 429.84f, 1.446f}, -}; - -Position const FreyaBeacons[FREYA_SPAWNS] = -{ - {377.02f, -119.10f, 409.81f, 0.0f}, - {185.62f, -119.10f, 409.81f, 0.0f}, - {377.02f, 54.78f, 409.81f, 0.0f}, - {185.62f, 54.78f, 409.81f, 0.0f}, -}; - -class boss_flame_leviathan : public CreatureScript -{ - public: - boss_flame_leviathan() : CreatureScript("boss_flame_leviathan") { } - - struct boss_flame_leviathanAI : public BossAI - { - boss_flame_leviathanAI(Creature* creature) : BossAI(creature, BOSS_LEVIATHAN), vehicle(creature->GetVehicleKit()) - { - } - - void InitializeAI() - { - ASSERT(vehicle); - if (!me->isDead()) - Reset(); - - ActiveTowersCount = 4; - Shutdown = 0; - ActiveTowers = false; - towerOfStorms = false; - towerOfLife = false; - towerOfFlames = false; - towerOfFrost = false; - Shutout = true; - Unbroken = true; - - DoCast(SPELL_INVIS_AND_STEALTH_DETECT); - - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); - me->SetReactState(REACT_PASSIVE); - } - - Vehicle* vehicle; - uint8 ActiveTowersCount; - uint8 Shutdown; - bool ActiveTowers; - bool towerOfStorms; - bool towerOfLife; - bool towerOfFlames; - bool towerOfFrost; - bool Shutout; - bool Unbroken; - - void Reset() - { - _Reset(); - //resets shutdown counter to 0. 2 or 4 depending on raid mode - Shutdown = 0; - _pursueTarget = 0; - - me->SetReactState(REACT_DEFENSIVE); - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - me->SetReactState(REACT_PASSIVE); - events.ScheduleEvent(EVENT_PURSUE, 1); - events.ScheduleEvent(EVENT_MISSILE, urand(1500, 4*IN_MILLISECONDS)); - events.ScheduleEvent(EVENT_VENT, 20*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SHUTDOWN, 150*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SPEED, 15*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SUMMON, 1*IN_MILLISECONDS); - ActiveTower(); //void ActiveTower - } - - void ActiveTower() - { - if (ActiveTowers) - { - if (towerOfStorms) - { - me->AddAura(SPELL_BUFF_TOWER_OF_STORMS, me); - events.ScheduleEvent(EVENT_THORIM_S_HAMMER, 35*IN_MILLISECONDS); - } - - if (towerOfFlames) - { - me->AddAura(SPELL_BUFF_TOWER_OF_FLAMES, me); - events.ScheduleEvent(EVENT_MIMIRON_S_INFERNO, 70*IN_MILLISECONDS); - } - - if (towerOfFrost) - { - me->AddAura(SPELL_BUFF_TOWER_OF_FR0ST, me); - events.ScheduleEvent(EVENT_HODIR_S_FURY, 105*IN_MILLISECONDS); - } - - if (towerOfLife) - { - me->AddAura(SPELL_BUFF_TOWER_OF_LIFE, me); - events.ScheduleEvent(EVENT_FREYA_S_WARD, 140*IN_MILLISECONDS); - } - - if (!towerOfLife && !towerOfFrost && !towerOfFlames && !towerOfStorms) - DoScriptText(SAY_TOWER_NONE, me); - else - DoScriptText(SAY_HARDMODE, me); - } - else - DoScriptText(SAY_AGGRO, me); - } - - void JustDied(Unit* /*victim*/) - { - _JustDied(); - // Set Field Flags 67108928 = 64 | 67108864 = UNIT_FLAG_UNK_6 | UNIT_FLAG_SKINNABLE - // Set DynFlags 12 - // Set NPCFlags 0 - DoScriptText(SAY_DEATH, me); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) - { - if (spell->Id == SPELL_START_THE_ENGINE) - vehicle->InstallAllAccessories(false); - - if (spell->Id == SPELL_ELECTROSHOCK) - me->InterruptSpell(CURRENT_CHANNELED_SPELL); - - if (spell->Id == SPELL_OVERLOAD_CIRCUIT) - ++Shutdown; - } - - uint32 GetData(uint32 type) - { - switch (type) - { - case DATA_SHUTOUT: - return Shutout ? 1 : 0; - case DATA_UNBROKEN: - return Unbroken ? 1 : 0; - case DATA_ORBIT_ACHIEVEMENTS: - if (ActiveTowers) // Only on HardMode - return ActiveTowersCount; - default: - break; - } - - return 0; - } - - void SetData(uint32 id, uint32 data) - { - if (id == DATA_UNBROKEN) - Unbroken = data ? true : false; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || !CheckInRoom()) - return; - - events.Update(diff); - - if (Shutdown == RAID_MODE(TWO_SEATS, FOUR_SEATS)) - { - Shutdown = 0; - events.ScheduleEvent(EVENT_SHUTDOWN, 4000); - me->RemoveAurasDueToSpell(SPELL_OVERLOAD_CIRCUIT); - me->InterruptNonMeleeSpells(true); - return; - } - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_PURSUE: - DoScriptText(RAND(SAY_TARGET_1, SAY_TARGET_2, SAY_TARGET_3), me); - DoCast(SPELL_PURSUED); // Will select target in spellscript - events.ScheduleEvent(EVENT_PURSUE, 35*IN_MILLISECONDS); - break; - case EVENT_MISSILE: - DoCast(me, SPELL_MISSILE_BARRAGE, true); - events.ScheduleEvent(EVENT_MISSILE, 2*IN_MILLISECONDS); - break; - case EVENT_VENT: - DoCastAOE(SPELL_FLAME_VENTS); - events.ScheduleEvent(EVENT_VENT, 20*IN_MILLISECONDS); - break; - case EVENT_SPEED: - DoCastAOE(SPELL_GATHERING_SPEED); - events.ScheduleEvent(EVENT_SPEED, 15*IN_MILLISECONDS); - break; - case EVENT_SUMMON: - if (summons.size() < 15) - if (Creature* lift = DoSummonFlyer(NPC_MECHANOLIFT, me, 30.0f, 50.0f, 0)) - lift->GetMotionMaster()->MoveRandom(100); - events.ScheduleEvent(EVENT_SUMMON, 2*IN_MILLISECONDS); - break; - case EVENT_SHUTDOWN: - DoScriptText(RAND(SAY_OVERLOAD_1, SAY_OVERLOAD_2, SAY_OVERLOAD_3), me); - me->MonsterTextEmote(EMOTE_OVERLOAD, 0, true); - me->CastSpell(me, SPELL_SYSTEMS_SHUTDOWN, true); - if (Shutout) - Shutout = false; - events.ScheduleEvent(EVENT_REPAIR, 4000); - events.DelayEvents(20 * IN_MILLISECONDS, 0); - break; - case EVENT_REPAIR: - me->MonsterTextEmote(EMOTE_REPAIR, 0, true); - me->ClearUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT); - events.ScheduleEvent(EVENT_SHUTDOWN, 150*IN_MILLISECONDS); - events.CancelEvent(EVENT_REPAIR); - break; - case EVENT_THORIM_S_HAMMER: // Tower of Storms - for (uint8 i = 0; i < 7; ++i) - { - if (Creature* thorim = DoSummon(NPC_THORIM_BEACON, me, float(urand(20, 60)), 20000, TEMPSUMMON_TIMED_DESPAWN)) - thorim->GetMotionMaster()->MoveRandom(100); - } - DoScriptText(SAY_TOWER_STORM, me); - events.CancelEvent(EVENT_THORIM_S_HAMMER); - break; - case EVENT_MIMIRON_S_INFERNO: // Tower of Flames - me->SummonCreature(NPC_MIMIRON_BEACON, InfernoStart->GetPositionX(), InfernoStart->GetPositionY(), InfernoStart->GetPositionZ()); - DoScriptText(SAY_TOWER_FLAME, me); - events.CancelEvent(EVENT_MIMIRON_S_INFERNO); - break; - case EVENT_HODIR_S_FURY: // Tower of Frost - for (uint8 i = 0; i < 7; ++i) - { - if (Creature* hodir = DoSummon(NPC_HODIR_BEACON, me, 50, 0)) - hodir->GetMotionMaster()->MoveRandom(100); - } - DoScriptText(SAY_TOWER_FROST, me); - events.CancelEvent(EVENT_HODIR_S_FURY); - break; - case EVENT_FREYA_S_WARD: // Tower of Nature - DoScriptText(SAY_TOWER_NATURE, me); - for (int32 i = 0; i < 4; ++i) - me->SummonCreature(NPC_FREYA_BEACON, FreyaBeacons[i]); - - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_FREYA_S_WARD); - events.CancelEvent(EVENT_FREYA_S_WARD); - break; - } - } - - DoBatteringRamIfReady(); - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) - { - if (spell->Id == SPELL_PURSUED) - _pursueTarget = target->GetGUID(); - } - - void DoAction(int32 const action) - { - if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count - { - if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4) && ActiveTowersCount == 4) - { - me->RemoveLootMode(LOOT_MODE_HARD_MODE_4); - --ActiveTowersCount; - } - if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3) && ActiveTowersCount == 3) - { - me->RemoveLootMode(LOOT_MODE_HARD_MODE_3); - --ActiveTowersCount; - } - if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2) && ActiveTowersCount == 2) - { - me->RemoveLootMode(LOOT_MODE_HARD_MODE_2); - --ActiveTowersCount; - } - if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1) && ActiveTowersCount == 1) - { - me->RemoveLootMode(LOOT_MODE_HARD_MODE_1); - --ActiveTowersCount; - } - } - - switch (action) - { - case ACTION_TOWER_OF_STORM_DESTROYED: - towerOfStorms = false; - break; - case ACTION_TOWER_OF_FROST_DESTROYED: - towerOfFrost = false; - break; - case ACTION_TOWER_OF_FLAMES_DESTROYED: - towerOfFlames = false; - break; - case ACTION_TOWER_OF_LIFE_DESTROYED: - towerOfLife = false; - break; - case ACTION_START_HARD_MODE: // Activate hard-mode enable all towers, apply buffs on leviathan - ActiveTowers = true; - towerOfStorms = true; - towerOfLife = true; - towerOfFlames = true; - towerOfFrost = true; - me->SetLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4); - break; - case ACTION_MOVE_TO_CENTER_POSITION: // Triggered by 2 Collossus near door - if (!me->isDead()) - { - me->SetHomePosition(Center->GetPositionX(), Center->GetPositionY(), Center->GetPositionZ(), 0); - me->GetMotionMaster()->MoveCharge(Center->GetPositionX(), Center->GetPositionY(), Center->GetPositionZ()); //position center - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); - return; - } - break; - default: - break; - } - } - - private: - //! Copypasta from DoSpellAttackIfReady, only difference is the target - it cannot be selected trough getVictim this way - - //! I also removed the spellInfo check - void DoBatteringRamIfReady() - { - if (me->isAttackReady()) - { - Unit* target = ObjectAccessor::GetUnit(*me, _pursueTarget); - if (me->IsWithinCombatRange(target, 30.0f)) - { - DoCast(target, SPELL_BATTERING_RAM); - me->resetAttackTimer(); - } - } - } - - uint64 _pursueTarget; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class boss_flame_leviathan_seat : public CreatureScript -{ - public: - boss_flame_leviathan_seat() : CreatureScript("boss_flame_leviathan_seat") { } - - struct boss_flame_leviathan_seatAI : public ScriptedAI - { - boss_flame_leviathan_seatAI(Creature* creature) : ScriptedAI(creature), vehicle(creature->GetVehicleKit()) - { - ASSERT(vehicle); - me->SetReactState(REACT_PASSIVE); - me->SetDisplayId(me->GetCreatureInfo()->Modelid2); - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - Vehicle* vehicle; - - void PassengerBoarded(Unit* who, int8 seatId, bool apply) - { - if (!me->GetVehicle()) - return; - - if (seatId == SEAT_PLAYER) - { - if (!apply) - return; - else - DoScriptText(SAY_PLAYER_RIDING, me); - - if (Creature* turret = me->GetVehicleKit()->GetPassenger(SEAT_TURRET)->ToCreature()) - { - turret->setFaction(me->GetVehicleBase()->getFaction()); - turret->SetUInt32Value(UNIT_FIELD_FLAGS, 0); // unselectable - turret->AI()->AttackStart(who); - } - if (Creature* device = me->GetVehicleKit()->GetPassenger(SEAT_DEVICE)->ToCreature()) - { - device->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - device->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - else if (seatId == SEAT_TURRET) - { - if (apply) - return; - - if (Unit* device = vehicle->GetPassenger(SEAT_DEVICE)) - { - device->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - device->SetUInt32Value(UNIT_FIELD_FLAGS, 0); // unselectable - } - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_flame_leviathan_seatAI(creature); - } -}; - -class boss_flame_leviathan_defense_cannon : public CreatureScript -{ - public: - boss_flame_leviathan_defense_cannon() : CreatureScript("boss_flame_leviathan_defense_cannon") { } - - struct boss_flame_leviathan_defense_cannonAI : public ScriptedAI - { - boss_flame_leviathan_defense_cannonAI(Creature* creature) : ScriptedAI(creature) - { - } - - uint32 NapalmTimer; - - void Reset () - { - NapalmTimer = 5*IN_MILLISECONDS; - DoCast(me, AURA_STEALTH_DETECTION); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (NapalmTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - if (CanAIAttack(target)) - DoCast(target, SPELL_NAPALM, true); - - NapalmTimer = 5000; - } - else - NapalmTimer -= diff; - } - - bool CanAIAttack(Unit const* who) const - { - if (who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() == NPC_SEAT) - return false; - return true; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_flame_leviathan_defense_cannonAI(creature); - } -}; - -class boss_flame_leviathan_defense_turret : public CreatureScript -{ - public: - boss_flame_leviathan_defense_turret() : CreatureScript("boss_flame_leviathan_defense_turret") { } - - struct boss_flame_leviathan_defense_turretAI : public TurretAI - { - boss_flame_leviathan_defense_turretAI(Creature* creature) : TurretAI(creature) {} - - void DamageTaken(Unit* who, uint32 &damage) - { - if (!CanAIAttack(who)) - damage = 0; - } - - bool CanAIAttack(Unit const* who) const - { - if (who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() != NPC_SEAT) - return false; - return true; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_flame_leviathan_defense_turretAI(creature); - } -}; - -class boss_flame_leviathan_overload_device : public CreatureScript -{ - public: - boss_flame_leviathan_overload_device() : CreatureScript("boss_flame_leviathan_overload_device") { } - - struct boss_flame_leviathan_overload_deviceAI : public PassiveAI - { - boss_flame_leviathan_overload_deviceAI(Creature* creature) : PassiveAI(creature) - { - } - - void DoAction(const int32 param) - { - if (param == EVENT_SPELLCLICK) - { - if (me->GetVehicle()) - { - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - if (Unit* player = me->GetVehicle()->GetPassenger(SEAT_PLAYER)) - { - me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true); - player->GetMotionMaster()->MoveKnockbackFrom(me->GetVehicleBase()->GetPositionX(), me->GetVehicleBase()->GetPositionY(), 30, 30); - player->ExitVehicle(); - } - } - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_flame_leviathan_overload_deviceAI(creature); - } -}; - -class boss_flame_leviathan_safety_container : public CreatureScript -{ - public: - boss_flame_leviathan_safety_container() : CreatureScript("boss_flame_leviathan_safety_container") { } - - struct boss_flame_leviathan_safety_containerAI : public PassiveAI - { - boss_flame_leviathan_safety_containerAI(Creature* creature) : PassiveAI(creature) - { - } - - void JustDied(Unit* /*killer*/) - { - float x, y, z; - me->GetPosition(x, y, z); - z = me->GetMap()->GetHeight(x, y, z); - me->GetMotionMaster()->MovePoint(0, x, y, z); - me->SetPosition(x, y, z, 0); - } - - void UpdateAI(uint32 const /*diff*/) - { - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_flame_leviathan_safety_containerAI(creature); - } -}; - -class npc_mechanolift : public CreatureScript -{ - public: - npc_mechanolift() : CreatureScript("npc_mechanolift") { } - - struct npc_mechanoliftAI : public PassiveAI - { - npc_mechanoliftAI(Creature* creature) : PassiveAI(creature) - { - ASSERT(me->GetVehicleKit()); - } - - uint32 MoveTimer; - - void Reset() - { - MoveTimer = 0; - me->GetMotionMaster()->MoveRandom(50); - } - - void JustDied(Unit* /*killer*/) - { - me->GetMotionMaster()->MoveTargetedHome(); - DoCast(SPELL_DUSTY_EXPLOSION); - Creature* liquid = DoSummon(NPC_LIQUID, me, 0); - if (liquid) - { - liquid->CastSpell(liquid, SPELL_LIQUID_PYRITE, true); - liquid->CastSpell(liquid, SPELL_DUST_CLOUD_IMPACT, true); - } - } - - void MovementInform(uint32 type, uint32 id) - { - if (type == POINT_MOTION_TYPE && id == 1) - if (Creature* container = me->FindNearestCreature(NPC_CONTAINER, 5, true)) - container->EnterVehicle(me); - } - - void UpdateAI(const uint32 diff) - { - if (MoveTimer <= diff) - { - if (me->GetVehicleKit()->HasEmptySeat(-1)) - { - Creature* container = me->FindNearestCreature(NPC_CONTAINER, 50, true); - if (container && !container->GetVehicle()) - me->GetMotionMaster()->MovePoint(1, container->GetPositionX(), container->GetPositionY(), container->GetPositionZ()); - } - - MoveTimer = 30000; //check next 30 seconds - } - else - MoveTimer -= diff; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_mechanoliftAI(creature); - } -}; - -class npc_pool_of_tar : public CreatureScript -{ - public: - npc_pool_of_tar() : CreatureScript("npc_pool_of_tar") { } - - struct npc_pool_of_tarAI : public ScriptedAI - { - npc_pool_of_tarAI(Creature* creature) : ScriptedAI(creature) - { - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); - me->CastSpell(me, SPELL_TAR_PASSIVE, true); - } - - void DamageTaken(Unit* /*who*/, uint32& damage) - { - damage = 0; - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) - { - if (spell->SchoolMask & SPELL_SCHOOL_MASK_FIRE && !me->HasAura(SPELL_BLAZE)) - me->CastSpell(me, SPELL_BLAZE, true); - } - - void UpdateAI(uint32 const /*diff*/) {} - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_pool_of_tarAI(creature); - } -}; - -class npc_colossus : public CreatureScript -{ - public: - npc_colossus() : CreatureScript("npc_colossus") { } - - struct npc_colossusAI : public ScriptedAI - { - npc_colossusAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - void JustDied(Unit* /*Who*/) - { - if (me->GetHomePosition().IsInDist(Center, 50.f)) - instance->SetData(DATA_COLOSSUS, instance->GetData(DATA_COLOSSUS)+1); - } - - void UpdateAI(uint32 const /*diff*/) - { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_colossusAI(creature); - } -}; - -class npc_thorims_hammer : public CreatureScript -{ - public: - npc_thorims_hammer() : CreatureScript("npc_thorims_hammer") { } - - struct npc_thorims_hammerAI : public ScriptedAI - { - npc_thorims_hammerAI(Creature* creature) : ScriptedAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->CastSpell(me, AURA_DUMMY_BLUE, true); - } - - void MoveInLineOfSight(Unit* who) - { - if (who->GetTypeId() == TYPEID_PLAYER && who->IsVehicle() && me->IsInRange(who, 0, 10, false)) - { - if (Creature* trigger = DoSummonFlyer(NPC_THORIM_TARGET_BEACON, me, 20, 0, 1000, TEMPSUMMON_TIMED_DESPAWN)) - trigger->CastSpell(who, SPELL_THORIM_S_HAMMER, true); - } - } - - void UpdateAI(uint32 const /*diff*/) - { - if (!me->HasAura(AURA_DUMMY_BLUE)) - me->CastSpell(me, AURA_DUMMY_BLUE, true); - - UpdateVictim(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_thorims_hammerAI(creature); - } -}; - -class npc_mimirons_inferno : public CreatureScript -{ -public: - npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_mimirons_infernoAI(creature); - } - - struct npc_mimirons_infernoAI : public npc_escortAI - { - npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->CastSpell(me, AURA_DUMMY_YELLOW, true); - me->SetReactState(REACT_PASSIVE); - } - - void WaypointReached(uint32 /*i*/) - { - } - - void Reset() - { - infernoTimer = 2000; - } - - uint32 infernoTimer; - - void UpdateAI(uint32 const diff) - { - npc_escortAI::UpdateAI(diff); - - if (!HasEscortState(STATE_ESCORT_ESCORTING)) - Start(false, true, 0, NULL, false, true); - else - { - if (infernoTimer <= diff) - { - if (Creature* trigger = DoSummonFlyer(NPC_MIMIRON_TARGET_BEACON, me, 20, 0, 1000, TEMPSUMMON_TIMED_DESPAWN)) - { - trigger->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), SPELL_MIMIRON_S_INFERNO, true); - infernoTimer = 2000; - } - } - else - infernoTimer -= diff; - - if (!me->HasAura(AURA_DUMMY_YELLOW)) - me->CastSpell(me, AURA_DUMMY_YELLOW, true); - } - } - }; - -}; - -class npc_hodirs_fury : public CreatureScript -{ - public: - npc_hodirs_fury() : CreatureScript("npc_hodirs_fury") { } - - struct npc_hodirs_furyAI : public ScriptedAI - { - npc_hodirs_furyAI(Creature* creature) : ScriptedAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->CastSpell(me, AURA_DUMMY_GREEN, true); - } - - void MoveInLineOfSight(Unit* who) - { - if (who->GetTypeId() == TYPEID_PLAYER && who->IsVehicle() && me->IsInRange(who, 0, 5, false)) - { - if (Creature* trigger = DoSummonFlyer(NPC_HODIR_TARGET_BEACON, me, 20, 0, 1000, TEMPSUMMON_TIMED_DESPAWN)) - trigger->CastSpell(who, SPELL_HODIR_S_FURY, true); - } - } - - void UpdateAI(uint32 const /*diff*/) - { - if (!me->HasAura(AURA_DUMMY_GREEN)) - me->CastSpell(me, AURA_DUMMY_GREEN, true); - - UpdateVictim(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_hodirs_furyAI(creature); - } -}; - -class npc_freyas_ward : public CreatureScript -{ - public: - npc_freyas_ward() : CreatureScript("npc_freyas_ward") { } - - struct npc_freyas_wardAI : public ScriptedAI - { - npc_freyas_wardAI(Creature* creature) : ScriptedAI(creature) - { - me->CastSpell(me, AURA_DUMMY_GREEN, true); - } - - uint32 summonTimer; - - void Reset() - { - summonTimer = 5000; - } - - void UpdateAI(uint32 const diff) - { - if (summonTimer <= diff) - { - DoCast(SPELL_FREYA_S_WARD_EFFECT_1); - DoCast(SPELL_FREYA_S_WARD_EFFECT_2); - summonTimer = 20000; - } - else - summonTimer -= diff; - - if (!me->HasAura(AURA_DUMMY_GREEN)) - me->CastSpell(me, AURA_DUMMY_GREEN, true); - - UpdateVictim(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_freyas_wardAI(creature); - } -}; - -class npc_freya_ward_summon : public CreatureScript -{ - public: - npc_freya_ward_summon() : CreatureScript("npc_freya_ward_summon") { } - - struct npc_freya_ward_summonAI : public ScriptedAI - { - npc_freya_ward_summonAI(Creature* creature) : ScriptedAI(creature) - { - creature->GetMotionMaster()->MoveRandom(100); - } - - uint32 lashTimer; - - void Reset() - { - lashTimer = 5000; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (lashTimer <= diff) - { - DoCast(SPELL_LASH); - lashTimer = 20000; - } - else - lashTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_freya_ward_summonAI(creature); - } -}; - -//npc lore keeper -#define GOSSIP_ITEM_1 "Activate secondary defensive systems" -#define GOSSIP_ITEM_2 "Confirmed" - -class npc_lorekeeper : public CreatureScript -{ - public: - npc_lorekeeper() : CreatureScript("npc_lorekeeper") { } - - struct npc_lorekeeperAI : public ScriptedAI - { - npc_lorekeeperAI(Creature* creature) : ScriptedAI(creature) - { - } - - void DoAction(int32 const action) - { - // Start encounter - if (action == ACTION_SPAWN_VEHICLES) - { - for (int32 i = 0; i < RAID_MODE(2, 5); ++i) - DoSummon(VEHICLE_SIEGE, PosSiege[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - for (int32 i = 0; i < RAID_MODE(2, 5); ++i) - DoSummon(VEHICLE_CHOPPER, PosChopper[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - for (int32 i = 0; i < RAID_MODE(2, 5); ++i) - DoSummon(VEHICLE_DEMOLISHER, PosDemolisher[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - return; - } - } - }; - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 action) - { - player->PlayerTalkClass->ClearMenus(); - InstanceScript* instance = creature->GetInstanceScript(); - if (!instance) - return true; - - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - if (player) - { - player->PrepareGossipMenu(creature); - instance->instance->LoadGrid(364, -16); //make sure leviathan is loaded - - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - } - break; - case GOSSIP_ACTION_INFO_DEF+2: - if (player) - player->CLOSE_GOSSIP_MENU(); - - if (Creature* leviathan = instance->instance->GetCreature(instance->GetData64(BOSS_LEVIATHAN))) - { - leviathan->AI()->DoAction(ACTION_START_HARD_MODE); - creature->SetVisible(false); - creature->AI()->DoAction(ACTION_SPAWN_VEHICLES); // spawn the vehicles - if (Creature* Delorah = creature->FindNearestCreature(NPC_DELORAH, 1000, true)) - { - if (Creature* Branz = creature->FindNearestCreature(NPC_BRANZ_BRONZBEARD, 1000, true)) - { - Delorah->GetMotionMaster()->MovePoint(0, Branz->GetPositionX()-4, Branz->GetPositionY(), Branz->GetPositionZ()); - //TODO DoScriptText(xxxx, Delorah, Branz); when reached at branz - } - } - } - break; - } - - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) - { - InstanceScript* instance = creature->GetInstanceScript(); - if (instance && instance->GetData(BOSS_LEVIATHAN) !=DONE && player) - { - player->PrepareGossipMenu(creature); - - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - } - return true; - } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_lorekeeperAI(creature); - } -}; - -//enable hardmode -////npc_brann_bronzebeard this requires more work involving area triggers. if reached this guy speaks through his radio.. -//#define GOSSIP_ITEM_1 "xxxxx" -//#define GOSSIP_ITEM_2 "xxxxx" -// -/* -class npc_brann_bronzebeard : public CreatureScript -{ -public: - npc_brann_bronzebeard() : CreatureScript("npc_brann_bronzebeard") { } - - //bool OnGossipSelect(Player* player, Creature* creature, uint32 uiSender, uint32 uiAction) - //{ - // player->PlayerTalkClass->ClearMenus(); - // switch(uiAction) - // { - // case GOSSIP_ACTION_INFO_DEF+1: - // if (player) - // { - // player->PrepareGossipMenu(creature); - // - // player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - // player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - // } - // break; - // case GOSSIP_ACTION_INFO_DEF+2: - // if (player) - // player->CLOSE_GOSSIP_MENU(); - // if (Creature* Lorekeeper = creature->FindNearestCreature(NPC_LOREKEEPER, 1000, true)) //lore keeper of lorgannon - // Lorekeeper->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - // break; - // } - // return true; - //} - //bool OnGossipHello(Player* player, Creature* creature) - //{ - // InstanceScript* instance = creature->GetInstanceScript(); - // if (instance && instance->GetData(BOSS_LEVIATHAN) !=DONE) - // { - // player->PrepareGossipMenu(creature); - // - // player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - // player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - // } - // return true; - //} - // -} -*/ - -class go_ulduar_tower : public GameObjectScript -{ - public: - go_ulduar_tower() : GameObjectScript("go_ulduar_tower") { } - - void OnDestroyed(GameObject* go, Player* /*player*/, uint32 /*value*/) - { - InstanceScript* instance = go->GetInstanceScript(); - if (!instance) - return; - - switch (go->GetEntry()) - { - case GO_TOWER_OF_STORMS: - instance->ProcessEvent(go, EVENT_TOWER_OF_STORM_DESTROYED); - break; - case GO_TOWER_OF_FLAMES: - instance->ProcessEvent(go, EVENT_TOWER_OF_FLAMES_DESTROYED); - break; - case GO_TOWER_OF_FROST: - instance->ProcessEvent(go, EVENT_TOWER_OF_FROST_DESTROYED); - break; - case GO_TOWER_OF_LIFE: - instance->ProcessEvent(go, EVENT_TOWER_OF_LIFE_DESTROYED); - break; - } - - Creature* trigger = go->FindNearestCreature(NPC_ULDUAR_GAUNTLET_GENERATOR, 15.0f, true); - if (trigger) - trigger->DisappearAndDie(); - } -}; - -class achievement_three_car_garage_demolisher : public AchievementCriteriaScript -{ - public: - achievement_three_car_garage_demolisher() : AchievementCriteriaScript("achievement_three_car_garage_demolisher") { } - - bool OnCheck(Player* source, Unit* /*target*/) - { - if (Creature* vehicle = source->GetVehicleCreatureBase()) - { - if (vehicle->GetEntry() == VEHICLE_DEMOLISHER) - return true; - } - - return false; - } -}; - -class achievement_three_car_garage_chopper : public AchievementCriteriaScript -{ - public: - achievement_three_car_garage_chopper() : AchievementCriteriaScript("achievement_three_car_garage_chopper") { } - - bool OnCheck(Player* source, Unit* /*target*/) - { - if (Creature* vehicle = source->GetVehicleCreatureBase()) - { - if (vehicle->GetEntry() == VEHICLE_CHOPPER) - return true; - } - - return false; - } -}; - -class achievement_three_car_garage_siege : public AchievementCriteriaScript -{ - public: - achievement_three_car_garage_siege() : AchievementCriteriaScript("achievement_three_car_garage_siege") { } - - bool OnCheck(Player* source, Unit* /*target*/) - { - if (Creature* vehicle = source->GetVehicleCreatureBase()) - { - if (vehicle->GetEntry() == VEHICLE_SIEGE) - return true; - } - - return false; - } -}; - -class achievement_shutout : public AchievementCriteriaScript -{ - public: - achievement_shutout() : AchievementCriteriaScript("achievement_shutout") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (target) - if (Creature* leviathan = target->ToCreature()) - if (leviathan->AI()->GetData(DATA_SHUTOUT)) - return true; - - return false; - } -}; - -class achievement_unbroken : public AchievementCriteriaScript -{ - public: - achievement_unbroken() : AchievementCriteriaScript("achievement_unbroken") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - return instance->GetData(DATA_UNBROKEN); - - return false; - } -}; - -class achievement_orbital_bombardment : public AchievementCriteriaScript -{ - public: - achievement_orbital_bombardment() : AchievementCriteriaScript("achievement_orbital_bombardment") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Leviathan = target->ToCreature()) - if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) >= 1) - return true; - - return false; - } -}; - -class achievement_orbital_devastation : public AchievementCriteriaScript -{ - public: - achievement_orbital_devastation() : AchievementCriteriaScript("achievement_orbital_devastation") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Leviathan = target->ToCreature()) - if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) >= 2) - return true; - - return false; - } -}; - -class achievement_nuked_from_orbit : public AchievementCriteriaScript -{ - public: - achievement_nuked_from_orbit() : AchievementCriteriaScript("achievement_nuked_from_orbit") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Leviathan = target->ToCreature()) - if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) >= 3) - return true; - - return false; - } -}; - -class achievement_orbit_uary : public AchievementCriteriaScript -{ - public: - achievement_orbit_uary() : AchievementCriteriaScript("achievement_orbit_uary") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Leviathan = target->ToCreature()) - if (Leviathan->AI()->GetData(DATA_ORBIT_ACHIEVEMENTS) == 4) - return true; - - return false; - } -}; - -class spell_load_into_catapult : public SpellScriptLoader -{ - enum Spells - { - SPELL_PASSENGER_LOADED = 62340, - }; - - public: - spell_load_into_catapult() : SpellScriptLoader("spell_load_into_catapult") { } - - class spell_load_into_catapult_AuraScript : public AuraScript - { - PrepareAuraScript(spell_load_into_catapult_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* owner = GetOwner()->ToUnit(); - if (!owner) - return; - - owner->CastSpell(owner, SPELL_PASSENGER_LOADED, true); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* owner = GetOwner()->ToUnit(); - if (!owner) - return; - - owner->RemoveAurasDueToSpell(SPELL_PASSENGER_LOADED); - } - - void Register() - { - OnEffectApply += AuraEffectApplyFn(spell_load_into_catapult_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_load_into_catapult_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_load_into_catapult_AuraScript(); - } -}; - -class spell_auto_repair : public SpellScriptLoader -{ - enum Spells - { - SPELL_AUTO_REPAIR = 62705, - }; - - public: - spell_auto_repair() : SpellScriptLoader("spell_auto_repair") {} - - class spell_auto_repair_SpellScript : public SpellScript - { - PrepareSpellScript(spell_auto_repair_SpellScript); - - void CheckCooldownForTarget() - { - if (GetHitUnit()->HasAuraEffect(SPELL_AUTO_REPAIR, EFFECT_2)) // Check presence of dummy aura indicating cooldown - { - PreventHitEffect(EFFECT_0); - PreventHitDefaultEffect(EFFECT_1); - PreventHitDefaultEffect(EFFECT_2); - //! Currently this doesn't work: if we call PreventHitAura(), the existing aura will be removed - //! because of recent aura refreshing changes. Since removing the existing aura negates the idea - //! of a cooldown marker, we just let the dummy aura refresh itself without executing the other spelleffects. - //! The spelleffects can be executed by letting the dummy aura expire naturally. - //! This is a temporary solution only. - //PreventHitAura(); - } - } - - void HandleScript(SpellEffIndex /*eff*/) - { - Vehicle* vehicle = GetHitUnit()->GetVehicleKit(); - if (!vehicle) - return; - - Player* driver = vehicle->GetPassenger(0) ? vehicle->GetPassenger(0)->ToPlayer() : NULL; - if (!driver) - return; - - driver->MonsterTextEmote(EMOTE_REPAIR, driver->GetGUID(), true); - - InstanceScript* instance = driver->GetInstanceScript(); - if (!instance) - return; - - // Actually should/could use basepoints (100) for this spell effect as percentage of health, but oh well. - vehicle->GetBase()->SetFullHealth(); - - // For achievement - instance->SetData(DATA_UNBROKEN, 0); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_auto_repair_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - BeforeHit += SpellHitFn(spell_auto_repair_SpellScript::CheckCooldownForTarget); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_auto_repair_SpellScript(); - } -}; - -class spell_systems_shutdown : public SpellScriptLoader -{ - public: - spell_systems_shutdown() : SpellScriptLoader("spell_systems_shutdown") { } - - class spell_systems_shutdown_AuraScript : public AuraScript - { - PrepareAuraScript(spell_systems_shutdown_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Creature* owner = GetOwner()->ToCreature(); - if (!owner) - return; - - //! This could probably in the SPELL_EFFECT_SEND_EVENT handler too: - owner->AddUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT); - owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - owner->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Creature* owner = GetOwner()->ToCreature(); - if (!owner) - return; - - owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - } - - void Register() - { - OnEffectApply += AuraEffectApplyFn(spell_systems_shutdown_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_systems_shutdown_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_systems_shutdown_AuraScript(); - } -}; - -class FlameLeviathanPursuedTargetSelector -{ - enum Area - { - AREA_FORMATION_GROUNDS = 4652, - }; - - public: - explicit FlameLeviathanPursuedTargetSelector(Unit* unit) : _me(unit) {}; - - bool operator()(Unit* target) const - { - //! No players, only vehicles (todo: check if blizzlike) - Creature* creatureTarget = target->ToCreature(); - if (!creatureTarget) - return true; - - //! NPC entries must match - if (creatureTarget->GetEntry() != NPC_SALVAGED_DEMOLISHER && creatureTarget->GetEntry() != NPC_SALVAGED_SIEGE_ENGINE) - return true; - - //! NPC must be a valid vehicle installation - Vehicle* vehicle = creatureTarget->GetVehicleKit(); - if (!vehicle) - return true; - - //! Entity needs to be in appropriate area - if (target->GetAreaId() != AREA_FORMATION_GROUNDS) - return true; - - //! Vehicle must be in use by player - bool playerFound = false; - for (SeatMap::const_iterator itr = vehicle->Seats.begin(); itr != vehicle->Seats.end() && !playerFound; ++itr) - if (IS_PLAYER_GUID(itr->second.Passenger)) - playerFound = true; - - return !playerFound; - } - - private: - Unit const* _me; -}; - -class spell_pursue : public SpellScriptLoader -{ - public: - spell_pursue() : SpellScriptLoader("spell_pursue") {} - - class spell_pursue_SpellScript : public SpellScript - { - PrepareSpellScript(spell_pursue_SpellScript); - - bool Load() - { - _target = NULL; - return true; - } - - void FilterTargets(std::list& targets) - { - targets.remove_if(FlameLeviathanPursuedTargetSelector(GetCaster())); - if (targets.empty()) - { - if (Creature* caster = GetCaster()->ToCreature()) - caster->AI()->EnterEvadeMode(); - } - else - { - //! In the end, only one target should be selected - _target = SelectRandomContainerElement(targets); - FilterTargetsSubsequently(targets); - } - } - - void FilterTargetsSubsequently(std::list& targets) - { - targets.clear(); - if(_target) - targets.push_back(_target); - } - - void HandleScript(SpellEffIndex /*eff*/) - { - Creature* caster = GetCaster()->ToCreature(); - if (!caster) - return; - - caster->AI()->AttackStart(GetHitUnit()); // Chase target - - for (SeatMap::const_iterator itr = caster->GetVehicleKit()->Seats.begin(); itr != caster->GetVehicleKit()->Seats.end(); ++itr) - { - if (IS_PLAYER_GUID(itr->second.Passenger)) - { - caster->MonsterTextEmote(EMOTE_PURSUE, itr->second.Passenger, true); - return; - } - } - } - - void Register() - { - OnUnitTargetSelect += SpellUnitTargetFn(spell_pursue_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnUnitTargetSelect += SpellUnitTargetFn(spell_pursue_SpellScript::FilterTargetsSubsequently, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget += SpellEffectFn(spell_pursue_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); - } - - Unit* _target; - }; - - SpellScript* GetSpellScript() const - { - return new spell_pursue_SpellScript(); - } -}; - -void AddSC_boss_flame_leviathan() -{ - new boss_flame_leviathan(); - new boss_flame_leviathan_seat(); - new boss_flame_leviathan_defense_turret(); - new boss_flame_leviathan_defense_cannon(); - new boss_flame_leviathan_overload_device(); - new boss_flame_leviathan_safety_container(); - new npc_mechanolift(); - new npc_pool_of_tar(); - new npc_colossus(); - new npc_thorims_hammer(); - new npc_mimirons_inferno(); - new npc_hodirs_fury(); - new npc_freyas_ward(); - new npc_freya_ward_summon(); - new npc_lorekeeper(); - // new npc_brann_bronzebeard(); - new go_ulduar_tower(); - - new achievement_three_car_garage_demolisher(); - new achievement_three_car_garage_chopper(); - new achievement_three_car_garage_siege(); - new achievement_shutout(); - new achievement_unbroken(); - new achievement_orbital_bombardment(); - new achievement_orbital_devastation(); - new achievement_nuked_from_orbit(); - new achievement_orbit_uary(); - - new spell_load_into_catapult(); - new spell_auto_repair(); - new spell_systems_shutdown(); - new spell_pursue(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp deleted file mode 100644 index f59ef8afe10..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp +++ /dev/null @@ -1,1717 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "SpellScript.h" -#include "Cell.h" -#include "CellImpl.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "ulduar.h" - -enum FreyaYells -{ - // Freya - SAY_AGGRO = -1603180, - SAY_AGGRO_WITH_ELDER = -1603181, - SAY_SLAY_1 = -1603182, - SAY_SLAY_2 = -1603183, - SAY_DEATH = -1603184, - SAY_BERSERK = -1603185, - SAY_SUMMON_CONSERVATOR = -1603186, - SAY_SUMMON_TRIO = -1603187, - SAY_SUMMON_LASHERS = -1603188, - SAY_YS_HELP = -1603189, - - // Elder Brightleaf - SAY_BRIGHTLEAF_AGGRO = -1603190, - SAY_BRIGHTLEAF_SLAY_1 = -1603191, - SAY_BRIGHTLEAF_SLAY_2 = -1603192, - SAY_BRIGHTLEAF_DEATH = -1603193, - - // Elder Ironbranch - SAY_IRONBRANCH_AGGRO = -1603194, - SAY_IRONBRANCH_SLAY_1 = -1603195, - SAY_IRONBRANCH_SLAY_2 = -1603196, - SAY_IRONBRANCH_DEATH = -1603197, - - // Elder Stonebark - SAY_STONEBARK_AGGRO = -1603198, - SAY_STONEBARK_SLAY_1 = -1603199, - SAY_STONEBARK_SLAY_2 = -1603200, - SAY_STONEBARK_DEATH = -1603201, -}; - -enum FreyaSpells -{ - // Freya - SPELL_ATTUNED_TO_NATURE = 62519, - SPELL_TOUCH_OF_EONAR = 62528, - SPELL_SUNBEAM = 62623, - SPELL_ENRAGE = 47008, - SPELL_FREYA_GROUND_TREMOR = 62437, - SPELL_ROOTS_FREYA = 62283, - SPELL_STONEBARK_ESSENCE = 62483, - SPELL_IRONBRANCH_ESSENCE = 62484, - SPELL_BRIGHTLEAF_ESSENCE = 62485, - SPELL_DRAINED_OF_POWER = 62467, - SPELL_SUMMON_EONAR_GIFT = 62572, - - // Stonebark - SPELL_FISTS_OF_STONE = 62344, - SPELL_GROUND_TREMOR = 62325, - SPELL_PETRIFIED_BARK = 62337, - SPELL_PETRIFIED_BARK_DMG = 62379, - - // Ironbranch - SPELL_IMPALE = 62310, - SPELL_ROOTS_IRONBRANCH = 62438, - SPELL_THORN_SWARM = 62285, - - // Brightleaf - SPELL_FLUX_AURA = 62239, - SPELL_FLUX = 62262, - SPELL_FLUX_PLUS = 62251, - SPELL_FLUX_MINUS = 62252, - SPELL_SOLAR_FLARE = 62240, - SPELL_UNSTABLE_SUN_BEAM_SUMMON = 62207, // Trigger 62221 - - // Stack Removing of Attuned to Nature - SPELL_REMOVE_25STACK = 62521, - SPELL_REMOVE_10STACK = 62525, - SPELL_REMOVE_2STACK = 62524, - - // Achievement spells - SPELL_DEFORESTATION_CREDIT = 65015, - SPELL_KNOCK_ON_WOOD_CREDIT = 65074, - - // Wave summoning spells - SPELL_SUMMON_LASHERS = 62687, - SPELL_SUMMON_TRIO = 62686, - SPELL_SUMMON_ANCIENT_CONSERVATOR = 62685, - - // Detonating Lasher - SPELL_DETONATE = 62598, - SPELL_FLAME_LASH = 62608, - - // Ancient Water Spirit - SPELL_TIDAL_WAVE = 62653, - SPELL_TIDAL_WAVE_EFFECT = 62654, - - // Storm Lasher - SPELL_LIGHTNING_LASH = 62648, - SPELL_STORMBOLT = 62649, - - // Snaplasher - SPELL_HARDENED_BARK = 62664, - SPELL_BARK_AURA = 62663, - - // Ancient Conservator - SPELL_CONSERVATOR_GRIP = 62532, - SPELL_NATURE_FURY = 62589, - SPELL_SUMMON_PERIODIC = 62566, - SPELL_SPORE_SUMMON_NW = 62582, // Not used, triggered by SPELL_SUMMON_PERIODIC - SPELL_SPORE_SUMMON_NE = 62591, - SPELL_SPORE_SUMMON_SE = 62592, - SPELL_SPORE_SUMMON_SW = 62593, - - // Healthly Spore - SPELL_HEALTHY_SPORE_VISUAL = 62538, - SPELL_GROW = 62559, - SPELL_POTENT_PHEROMONES = 62541, - - // Eonar's Gift - SPELL_LIFEBINDERS_GIFT = 62584, - SPELL_PHEROMONES = 62619, - SPELL_EONAR_VISUAL = 62579, - - // Nature Bomb - SPELL_NATURE_BOMB = 64587, - SPELL_OBJECT_BOMB = 64600, - SPELL_SUMMON_NATURE_BOMB = 64606, - - // Unstable Sun Beam - SPELL_UNSTABLE_SUN_BEAM = 62211, - SPELL_UNSTABLE_ENERGY = 62217, - SPELL_PHOTOSYNTHESIS = 62209, - SPELL_UNSTABLE_SUN_BEAM_TRIGGERED = 62243, - SPELL_FREYA_UNSTABLE_SUNBEAM = 62450, // Or maybe 62866? - - // Sun Beam - SPELL_FREYA_UNSTABLE_ENERGY = 62451, - SPELL_FREYA_UNSTABLE_ENERGY_VISUAL = 62216, - - // Attuned To Nature spells - SPELL_ATTUNED_TO_NATURE_2_DOSE_REDUCTION = 62524, - SPELL_ATTUNED_TO_NATURE_10_DOSE_REDUCTION = 62525, - SPELL_ATTUNED_TO_NATURE_25_DOSE_REDUCTION = 62521, -}; - -enum FreyaNpcs -{ - NPC_SUN_BEAM = 33170, - NPC_DETONATING_LASHER = 32918, - NPC_ANCIENT_CONSERVATOR = 33203, - NPC_ANCIENT_WATER_SPIRIT = 33202, - NPC_STORM_LASHER = 32919, - NPC_SNAPLASHER = 32916, - NPC_NATURE_BOMB = 34129, - NPC_EONARS_GIFT = 33228, - NPC_HEALTHY_SPORE = 33215, - NPC_UNSTABLE_SUN_BEAM = 33050, - NPC_IRON_ROOTS = 33088, - NPC_STRENGTHENED_IRON_ROOTS = 33168, - - OBJECT_NATURE_BOMB = 194902, -}; - -enum FreyaActions -{ - ACTION_ELDER_DEATH = 1, - ACTION_ELDER_FREYA_KILLED = 2, -}; - -enum FreyaEvents -{ - // Freya - EVENT_WAVE = 1, - EVENT_EONAR_GIFT = 2, - EVENT_NATURE_BOMB = 3, - EVENT_UNSTABLE_ENERGY = 4, - EVENT_STRENGTHENED_IRON_ROOTS = 5, - EVENT_GROUND_TREMOR = 6, - EVENT_SUNBEAM = 7, - EVENT_ENRAGE = 8, - - // Elder Stonebark - EVENT_TREMOR = 9, - EVENT_BARK = 10, - EVENT_FISTS = 11, - - // Elder Ironbranch - EVENT_IMPALE = 12, - EVENT_IRON_ROOTS = 13, - EVENT_THORN_SWARM = 14, - - // Elder Brightleaf - EVENT_SOLAR_FLARE = 15, - EVENT_UNSTABLE_SUN_BEAM = 16, - EVENT_FLUX = 17, -}; - -#define WAVE_TIME 60000 // Normal wave is one minute -#define TIME_DIFFERENCE 10000 // If difference between waveTime and WAVE_TIME is bigger then TIME_DIFFERENCE, schedule EVENT_WAVE in 10 seconds -#define DATA_GETTING_BACK_TO_NATURE 1 -#define DATA_KNOCK_ON_WOOD 2 - -class npc_iron_roots : public CreatureScript -{ - public: - npc_iron_roots() : CreatureScript("npc_iron_roots") { } - - struct npc_iron_rootsAI : public Scripted_NoMovementAI - { - npc_iron_rootsAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); - me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip - me->setFaction(14); - me->SetReactState(REACT_PASSIVE); - summonerGUID = 0; - } - - void IsSummonedBy(Unit* summoner) - { - if (summoner->GetTypeId() != TYPEID_PLAYER) - return; - // Summoner is a player, who should have root aura on self - summonerGUID = summoner->GetGUID(); - me->SetFacingToObject(summoner); - me->SetInCombatWith(summoner); - } - - void JustDied(Unit* /*who*/) - { - if (Player* target = ObjectAccessor::GetPlayer(*me, summonerGUID)) - { - target->RemoveAurasDueToSpell(SPELL_ROOTS_IRONBRANCH); - target->RemoveAurasDueToSpell(SPELL_ROOTS_FREYA); - } - - me->RemoveCorpse(false); - } - - private: - uint64 summonerGUID; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_iron_rootsAI(creature); - } -}; - -class boss_freya : public CreatureScript -{ - public: - boss_freya() : CreatureScript("boss_freya") { } - - struct boss_freyaAI : public BossAI - { - boss_freyaAI(Creature* creature) : BossAI(creature, BOSS_FREYA) - { - } - - uint64 ElementalGUID[3][2]; - - uint32 deforestation[6][2]; - uint32 elementalTimer[2]; - uint32 diffTimer; - uint8 trioWaveCount; - uint8 trioWaveController; - uint8 waveCount; - uint8 elderCount; - uint8 attunedToNature; - - bool checkElementalAlive[2]; - bool trioDefeated[2]; - bool random[3]; - - void Reset() - { - _Reset(); - summons.clear(); - trioWaveCount = 0; - trioWaveController = 0; - waveCount = 0; - elderCount = 0; - - for (uint8 i = 0; i < 3; ++i) - for (uint8 n = 0; n < 2; ++n) - ElementalGUID[i][n] = 0; - for (uint8 i = 0; i < 6; ++i) - for (uint8 n = 0; n < 2; ++n) - deforestation[i][n] = 0; - for (uint8 n = 0; n < 2; ++n) - { - checkElementalAlive[n] = true; - trioDefeated[n] = false; - } - for (uint8 n = 0; n < 3; ++n) - random[n] = false; - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void DamageTaken(Unit* /*who*/, uint32& damage) - { - if (damage >= me->GetHealth()) - { - damage = 0; - DoScriptText(SAY_DEATH, me); - me->SetReactState(REACT_PASSIVE); - _JustDied(); - me->RemoveAllAuras(); - me->AttackStop(); - me->setFaction(35); - me->DeleteThreatList(); - me->CombatStop(true); - me->DespawnOrUnsummon(7500); - me->CastSpell(me, SPELL_KNOCK_ON_WOOD_CREDIT, true); - - Creature* Elder[3]; - for (uint8 n = 0; n < 3; ++n) - { - Elder[n] = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF + n)); - if (Elder[n] && Elder[n]->isAlive()) - { - Elder[n]->RemoveAllAuras(); - Elder[n]->AttackStop(); - Elder[n]->CombatStop(true); - Elder[n]->DeleteThreatList(); - Elder[n]->GetAI()->DoAction(ACTION_ELDER_FREYA_KILLED); - } - } - } - } - - void EnterCombat(Unit* who) - { - _EnterCombat(); - DoZoneInCombat(); - Creature* Elder[3]; - for (uint8 n = 0; n < 3; ++n) - { - Elder[n] = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF + n)); - if (Elder[n] && Elder[n]->isAlive()) - { - me->AddAura(SPELL_DRAINED_OF_POWER, Elder[n]); - Elder[n]->CastSpell(me, SPELL_IRONBRANCH_ESSENCE, true); - Elder[n]->RemoveLootMode(LOOT_MODE_DEFAULT); //! Why? - Elder[n]->AI()->AttackStart(who); - Elder[n]->AddThreat(who, 250.0f); - Elder[n]->SetInCombatWith(who); - ++elderCount; - } - } - - if (Elder[0] && Elder[0]->isAlive()) - { - Elder[0]->CastSpell(me, SPELL_BRIGHTLEAF_ESSENCE, true); - events.ScheduleEvent(EVENT_UNSTABLE_ENERGY, urand(10000, 20000)); - } - - if (Elder[1] && Elder[1]->isAlive()) - { - Elder[1]->CastSpell(me, SPELL_STONEBARK_ESSENCE, true); - events.ScheduleEvent(EVENT_GROUND_TREMOR, urand(10000, 20000)); - } - - if (Elder[2] && Elder[2]->isAlive()) - { - Elder[2]->CastSpell(me, SPELL_IRONBRANCH_ESSENCE, true); - events.ScheduleEvent(EVENT_STRENGTHENED_IRON_ROOTS, urand(10000, 20000)); - } - - if (elderCount == 0) - DoScriptText(SAY_AGGRO, me); - else - DoScriptText(SAY_AGGRO_WITH_ELDER, me); - - me->CastCustomSpell(SPELL_ATTUNED_TO_NATURE, SPELLVALUE_AURA_STACK, 150, me, true); - - events.ScheduleEvent(EVENT_WAVE, 10000); - events.ScheduleEvent(EVENT_EONAR_GIFT, 25000); - events.ScheduleEvent(EVENT_ENRAGE, 600000); - events.ScheduleEvent(EVENT_SUNBEAM, urand(5000, 15000)); - } - - uint32 GetData(uint32 type) - { - switch (type) - { - case DATA_GETTING_BACK_TO_NATURE: - return attunedToNature; - case DATA_KNOCK_ON_WOOD: - return elderCount; - } - - return 0; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ENRAGE: - DoScriptText(SAY_BERSERK, me); - DoCast(me, SPELL_ENRAGE); - break; - case EVENT_SUNBEAM: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - DoCast(target, SPELL_SUNBEAM); - events.ScheduleEvent(EVENT_SUNBEAM, urand(10000, 15000)); - break; - case EVENT_NATURE_BOMB: - { - // On every player - std::list PlayerList; - Trinity::AnyPlayerInObjectRangeCheck checker(me, 50.0f); - Trinity::PlayerListSearcher searcher(me, PlayerList, checker); - me->VisitNearbyWorldObject(50.0f, searcher); - for (std::list::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) - (*itr)->CastSpell(*itr, SPELL_SUMMON_NATURE_BOMB, true); - events.ScheduleEvent(EVENT_NATURE_BOMB, urand(10000, 12000)); - break; - } - case EVENT_UNSTABLE_ENERGY: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - DoCast(target, SPELL_FREYA_UNSTABLE_SUNBEAM, true); - events.ScheduleEvent(EVENT_UNSTABLE_ENERGY, urand(15000, 20000)); - break; - case EVENT_WAVE: - SpawnWave(); - if (waveCount < 6) - events.ScheduleEvent(EVENT_WAVE, WAVE_TIME); - else - events.ScheduleEvent(EVENT_NATURE_BOMB, urand(10000, 20000)); - break; - case EVENT_EONAR_GIFT: - DoCast(me, SPELL_SUMMON_EONAR_GIFT); - events.ScheduleEvent(EVENT_EONAR_GIFT, urand(40000, 50000)); - break; - case EVENT_STRENGTHENED_IRON_ROOTS: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_ROOTS_FREYA)) - target->CastSpell(target, SPELL_ROOTS_FREYA, true); // This must be casted by Target self - events.ScheduleEvent(EVENT_STRENGTHENED_IRON_ROOTS, urand(12000, 20000)); - break; - case EVENT_GROUND_TREMOR: - DoCastAOE(SPELL_FREYA_GROUND_TREMOR); - events.ScheduleEvent(EVENT_GROUND_TREMOR, urand(25000, 28000)); - break; - } - } - - if (!me->HasAura(SPELL_TOUCH_OF_EONAR)) - me->CastSpell(me, SPELL_TOUCH_OF_EONAR, true); - - // For achievement check - if (Aura* aura = me->GetAura(SPELL_ATTUNED_TO_NATURE)) - attunedToNature = aura->GetStackAmount(); - else - attunedToNature = 0; - - diffTimer += diff; // For getting time difference for Deforestation achievement - - // Elementals must be killed within 12 seconds of each other, or they will all revive and heal - Creature* Elemental[3][2]; - for (uint8 i = 0; i < 2; ++i) - { - if (checkElementalAlive[i]) - elementalTimer[i] = 0; - else - { - elementalTimer[i] += diff; - for (uint8 k = 0; k < 3; ++k) - Elemental[k][i] = ObjectAccessor::GetCreature(*me, ElementalGUID[k][i]); - if (elementalTimer[i] > 12000) - { - if (!trioDefeated[i]) // Do *NOT* merge this bool with bool few lines below! - { - if (Elemental[0][i] && Elemental[1][i] && Elemental[2][i]) - { - for (uint8 n = 0; n < 3; ++n) - { - if (Elemental[n][i]->isAlive()) - Elemental[n][i]->SetHealth(Elemental[n][i]->GetMaxHealth()); - else - Elemental[n][i]->Respawn(); - } - } - } - checkElementalAlive[i] = true; - } - else - { - if (!trioDefeated[i]) - { - if (Elemental[0][i] && Elemental[1][i] && Elemental[2][i]) - { - if (Elemental[0][i]->isDead() && Elemental[1][i]->isDead() && Elemental[2][i]->isDead()) - { - for (uint8 n = 0; n < 3; ++n) - { - summons.remove(Elemental[n][i]->GetGUID()); - Elemental[n][i]->ForcedDespawn(5000); - trioDefeated[i] = true; - Elemental[n][i]->CastSpell(me, SPELL_REMOVE_10STACK, true); - } - } - } - } - } - } - } - - DoMeleeAttackIfReady(); - } - - // Check if all Trio NPCs are dead - achievement check - void LasherDead(uint32 type) // Type must be in format of a binary mask - { - uint8 n = 0; - - // Handling recieved data - for (uint8 i = 0; i < 5; ++i) // We have created "instances" for keeping informations about last 6 death lashers - needed because of respawning - { - deforestation[i][0] = deforestation[(i + 1)][0]; // Time - deforestation[i][1] = deforestation[(i + 1)][1]; // Type - } - deforestation[5][0] = diffTimer; - deforestation[5][1] = type; - - // Check for achievement completion - if (deforestation[0][1]) // Check for proper functionality of binary masks (overflow would not be problem) - { - for (uint8 i = 0; i < 6; ++i) // Count binary mask - { - n += deforestation[i][1]; - } - if ((deforestation[5][0] - deforestation[0][0]) < 10000) // Time check - { - if (n == 14 && instance) // Binary mask check - verification of lasher types - { - instance->DoCastSpellOnPlayers(SPELL_DEFORESTATION_CREDIT); - } - } - } - } - - // Random order of spawning waves - int GetWaveId() - { - if (random[0] && random[1] && random[2]) - for (uint8 n = 0; n < 3; ++n) - random[n] = false; - - uint8 randomId = urand(0, 2); - - while (random[randomId]) - randomId = urand(0, 2); - - random[randomId] = true; - return randomId; - } - - void SpawnWave() - { - switch (GetWaveId()) - { - case 0: - DoScriptText(SAY_SUMMON_LASHERS, me); - for (uint8 n = 0; n < 10; ++n) - DoCast(SPELL_SUMMON_LASHERS); - break; - case 1: - DoScriptText(SAY_SUMMON_TRIO, me); - DoCast(SPELL_SUMMON_TRIO); - trioWaveCount++; - break; - case 2: - DoScriptText(SAY_SUMMON_CONSERVATOR, me); - DoCast(SPELL_SUMMON_ANCIENT_CONSERVATOR); - break; - } - waveCount++; - } - - void JustDied(Unit* who) - { - //! Freya's chest is dynamically spawned on death by different spells. - const uint32 summonSpell[2][4] = - { - /* 0Elder, 1Elder, 2Elder, 3Elder */ - /* 10N */ {62950, 62953, 62955, 62957}, - /* 25N */ {62952, 62954, 62956, 62958} - }; - - me->CastSpell((Unit*)NULL, summonSpell[me->GetMap()->GetDifficulty()][elderCount], true); - - _JustDied(); - } - - void JustSummoned(Creature* summoned) - { - switch (summoned->GetEntry()) - { - case NPC_SNAPLASHER: - case NPC_ANCIENT_WATER_SPIRIT: - case NPC_STORM_LASHER: - ElementalGUID[trioWaveController][trioWaveCount] = summoned->GetGUID(); - summons.push_back(summoned->GetGUID()); - ++trioWaveController; - if (trioWaveController > 2) - trioWaveController = 0; - break; - case NPC_DETONATING_LASHER: - case NPC_ANCIENT_CONSERVATOR: - default: - summons.push_back(summoned->GetGUID()); - break; - } - - // Need to have it there, or summoned units would do nothing untill attacked - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 250.0f, true)) - { - summoned->AI()->AttackStart(target); - summoned->AddThreat(target, 250.0f); - DoZoneInCombat(summoned); - } - } - - void SummonedCreatureDies(Creature* summoned, Unit* who) - { - switch (summoned->GetEntry()) - { - case NPC_DETONATING_LASHER: - summoned->CastSpell(me, SPELL_REMOVE_2STACK, true); - summoned->CastSpell(who, SPELL_DETONATE, true); - summoned->ForcedDespawn(5000); - summons.remove(summoned->GetGUID()); - break; - case NPC_ANCIENT_CONSERVATOR: - summoned->CastSpell(me, SPELL_REMOVE_25STACK, true); - summoned->ForcedDespawn(5000); - summons.remove(summoned->GetGUID()); - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class boss_elder_brightleaf : public CreatureScript -{ - public: - boss_elder_brightleaf() : CreatureScript("boss_elder_brightleaf") { } - - struct boss_elder_brightleafAI : public BossAI - { - boss_elder_brightleafAI(Creature* creature) : BossAI(creature, BOSS_BRIGHTLEAF) - { - } - - void Reset() - { - _Reset(); - if (me->HasAura(SPELL_DRAINED_OF_POWER)) - me->RemoveAurasDueToSpell(SPELL_DRAINED_OF_POWER); - events.ScheduleEvent(EVENT_SOLAR_FLARE, urand(5000, 7000)); - events.ScheduleEvent(EVENT_UNSTABLE_SUN_BEAM, urand(7000, 12000)); - events.ScheduleEvent(EVENT_FLUX, 5000); - elderCount = 0; - lumberjack = false; - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_BRIGHTLEAF_SLAY_1, SAY_BRIGHTLEAF_SLAY_2), me); - } - - void JustDied(Unit* who) - { - _JustDied(); - DoScriptText(SAY_BRIGHTLEAF_DEATH, me); - - if (who && who->GetTypeId() == TYPEID_PLAYER) - { - if (Creature* Ironbranch = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_IRONBRANCH))) - Ironbranch->AI()->DoAction(ACTION_ELDER_DEATH); - - if (Creature* Stonebark = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STONEBARK))) - Stonebark->AI()->DoAction(ACTION_ELDER_DEATH); - } - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - if (!me->HasAura(SPELL_DRAINED_OF_POWER)) - DoScriptText(SAY_BRIGHTLEAF_AGGRO, me); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_UNSTABLE_SUN_BEAM: - me->CastSpell(me, SPELL_UNSTABLE_SUN_BEAM_SUMMON, true); - events.ScheduleEvent(EVENT_UNSTABLE_SUN_BEAM, urand(10000, 15000)); - break; - case EVENT_SOLAR_FLARE: - { - uint8 stackAmount = 0; - if (me->GetAura(SPELL_FLUX_AURA)) - stackAmount = me->GetAura(SPELL_FLUX_AURA)->GetStackAmount(); - me->CastCustomSpell(SPELL_SOLAR_FLARE, SPELLVALUE_MAX_TARGETS, stackAmount, me, false); - events.ScheduleEvent(EVENT_SOLAR_FLARE, urand(5000, 10000)); - break; - } - case EVENT_FLUX: - me->RemoveAurasDueToSpell(SPELL_FLUX_AURA); - me->AddAura(SPELL_FLUX_AURA, me); - if (Aura* Flux = me->GetAura(SPELL_FLUX_AURA)) - Flux->SetStackAmount(urand(1, 8)); - events.ScheduleEvent(EVENT_FLUX, 7500); - break; - } - } - - if (lumberjack) - lumberjackTimer += diff; - - DoMeleeAttackIfReady(); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_ELDER_DEATH: - ++elderCount; - lumberjack = true; - break; - case ACTION_ELDER_FREYA_KILLED: - me->DespawnOrUnsummon(10000); - _JustDied(); - break; - } - } - - private: - uint32 lumberjackTimer; - uint8 elderCount; - bool lumberjack; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class boss_elder_stonebark : public CreatureScript -{ - public: - boss_elder_stonebark() : CreatureScript("boss_elder_stonebark") { } - - struct boss_elder_stonebarkAI : public BossAI - { - boss_elder_stonebarkAI(Creature* creature) : BossAI(creature, BOSS_STONEBARK) - { - } - - void Reset() - { - _Reset(); - if (me->HasAura(SPELL_DRAINED_OF_POWER)) - me->RemoveAurasDueToSpell(SPELL_DRAINED_OF_POWER); - events.ScheduleEvent(EVENT_TREMOR, urand(10000, 12000)); - events.ScheduleEvent(EVENT_FISTS, urand(25000, 35000)); - events.ScheduleEvent(EVENT_BARK, urand(37500, 40000)); - elderCount = 0; - lumberjack = false; - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_STONEBARK_SLAY_1, SAY_STONEBARK_SLAY_2), me); - } - - void JustDied(Unit* who) - { - _JustDied(); - DoScriptText(SAY_STONEBARK_DEATH, me); - - if (who && who->GetTypeId() == TYPEID_PLAYER) - { - if (Creature* Ironbranch = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_IRONBRANCH))) - Ironbranch->AI()->DoAction(ACTION_ELDER_DEATH); - - if (Creature* Brightleaf = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF))) - Brightleaf->AI()->DoAction(ACTION_ELDER_DEATH); - } - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - if (!me->HasAura(SPELL_DRAINED_OF_POWER)) - DoScriptText(SAY_STONEBARK_AGGRO, me); - } - - void DamageTaken(Unit* who, uint32& damage) - { - if (who == me) - return; - - if (me->HasAura(SPELL_PETRIFIED_BARK)) - { - int32 reflect = damage; - who->CastCustomSpell(who, SPELL_PETRIFIED_BARK_DMG, &reflect, NULL, NULL, true); - damage = 0; - } - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_BARK: - DoCast(me, SPELL_PETRIFIED_BARK); - events.ScheduleEvent(EVENT_BARK, urand(30000, 50000)); - break; - case EVENT_FISTS: - DoCastVictim(SPELL_FISTS_OF_STONE); - events.ScheduleEvent(EVENT_FISTS, urand(20000, 30000)); - break; - case EVENT_TREMOR: - if (!me->HasAura(SPELL_FISTS_OF_STONE)) - DoCastVictim(SPELL_GROUND_TREMOR); - events.ScheduleEvent(EVENT_TREMOR, urand(10000, 20000)); - break; - } - } - - if (lumberjack) - lumberjackTimer += diff; - - DoMeleeAttackIfReady(); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_ELDER_DEATH: - ++elderCount; - lumberjack = true; - break; - case ACTION_ELDER_FREYA_KILLED: - me->DespawnOrUnsummon(10000); - _JustDied(); - break; - } - } - - private: - uint32 lumberjackTimer; - uint8 elderCount; - bool lumberjack; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class boss_elder_ironbranch : public CreatureScript -{ - public: - boss_elder_ironbranch() : CreatureScript("boss_elder_ironbranch") { } - - struct boss_elder_ironbranchAI : public BossAI - { - boss_elder_ironbranchAI(Creature* creature) : BossAI(creature, BOSS_IRONBRANCH) - { - } - - void Reset() - { - _Reset(); - if (me->HasAura(SPELL_DRAINED_OF_POWER)) - me->RemoveAurasDueToSpell(SPELL_DRAINED_OF_POWER); - events.ScheduleEvent(EVENT_IMPALE, urand(18000, 22000)); - events.ScheduleEvent(EVENT_IRON_ROOTS, urand(12000, 17000)); - events.ScheduleEvent(EVENT_THORN_SWARM, urand(7500, 12500)); - elderCount = 0; - lumberjack = false; - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_IRONBRANCH_SLAY_1, SAY_IRONBRANCH_SLAY_2), me); - } - - void JustDied(Unit* who) - { - _JustDied(); - DoScriptText(SAY_IRONBRANCH_DEATH, me); - - if (who && who->GetTypeId() == TYPEID_PLAYER) - { - if (Creature* Brightleaf = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_BRIGHTLEAF))) - Brightleaf->AI()->DoAction(ACTION_ELDER_DEATH); - - if (Creature* Stonebark = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_STONEBARK))) - Stonebark->AI()->DoAction(ACTION_ELDER_DEATH); - } - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - if (!me->HasAura(SPELL_DRAINED_OF_POWER)) - DoScriptText(SAY_IRONBRANCH_AGGRO, me); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_IMPALE: - DoCastVictim(SPELL_IMPALE); - events.ScheduleEvent(EVENT_IMPALE, urand(15000, 25000)); - break; - case EVENT_IRON_ROOTS: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_ROOTS_IRONBRANCH)) - target->CastSpell(target, SPELL_ROOTS_IRONBRANCH, true); - events.ScheduleEvent(EVENT_IRON_ROOTS, urand(10000, 20000)); - break; - case EVENT_THORN_SWARM: - DoCastVictim(SPELL_THORN_SWARM); - events.ScheduleEvent(EVENT_THORN_SWARM, urand(8000, 13000)); - break; - } - } - - if (lumberjack) - lumberjackTimer += diff; - - DoMeleeAttackIfReady(); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_ELDER_DEATH: - ++elderCount; - lumberjack = true; - break; - case ACTION_ELDER_FREYA_KILLED: - me->DespawnOrUnsummon(10000); - _JustDied(); - break; - } - } - - private: - uint32 lumberjackTimer; - uint8 elderCount; - bool lumberjack; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class npc_detonating_lasher : public CreatureScript -{ - public: - npc_detonating_lasher() : CreatureScript("npc_detonating_lasher") { } - - struct npc_detonating_lasherAI : public ScriptedAI - { - npc_detonating_lasherAI(Creature* creature) : ScriptedAI(creature) - { - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - } - - void Reset() - { - lashTimer = 5000; - changeTargetTimer = 7500; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (lashTimer <= diff) - { - DoCast(SPELL_FLAME_LASH); - lashTimer = urand(5000, 10000); - } - else - lashTimer -= diff; - - if (changeTargetTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - { - // Switching to other target - modify aggro of new target by 20% from current target's aggro - me->AddThreat(target, me->getThreatManager().getThreat(me->getVictim(), false) * 1.2f); - me->AI()->AttackStart(target); - } - changeTargetTimer = urand(5000, 10000); - } - else - changeTargetTimer -= diff; - - DoMeleeAttackIfReady(); - } - - private: - uint32 lashTimer; - uint32 changeTargetTimer; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_detonating_lasherAI(creature); - } -}; - -class npc_ancient_water_spirit : public CreatureScript -{ - public: - npc_ancient_water_spirit() : CreatureScript("npc_ancient_water_spirit") { } - - struct npc_ancient_water_spiritAI : public ScriptedAI - { - npc_ancient_water_spiritAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) - waveCount = CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; - } - - void Reset() - { - tidalWaveTimer = 10000; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (tidalWaveTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - { - DoCast(target, SPELL_TIDAL_WAVE); - DoCast(target, SPELL_TIDAL_WAVE_EFFECT, true); - } - tidalWaveTimer = urand(12000, 25000); - } - else - tidalWaveTimer -= diff; - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) - { - CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; - CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(1); - } - } - - private: - InstanceScript* instance; - uint32 tidalWaveTimer; - uint8 waveCount; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_ancient_water_spiritAI(creature); - } -}; - -class npc_storm_lasher : public CreatureScript -{ - public: - npc_storm_lasher() : CreatureScript("npc_storm_lasher") { } - - struct npc_storm_lasherAI : public ScriptedAI - { - npc_storm_lasherAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) - waveCount = CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; - } - - void Reset() - { - lightningLashTimer = 10000; - stormboltTimer = 5000; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (lightningLashTimer <= diff) - { - DoCast(SPELL_LIGHTNING_LASH); - lightningLashTimer = urand(7000, 14000); - } - else - lightningLashTimer -= diff; - - if (stormboltTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - DoCast(target, SPELL_STORMBOLT); - stormboltTimer = urand(8000, 12000); - } - else - stormboltTimer -= diff; - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) - { - CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; - CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(2); - } - } - - private: - InstanceScript* instance; - uint32 lightningLashTimer; - uint32 stormboltTimer; - uint8 waveCount; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_storm_lasherAI(creature); - } -}; - -class npc_snaplasher : public CreatureScript -{ - public: - npc_snaplasher() : CreatureScript("npc_snaplasher") { } - - struct npc_snaplasherAI : public ScriptedAI - { - npc_snaplasherAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) - waveCount = CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; - } - - void UpdateAI(uint32 const /*diff*/) - { - if (!UpdateVictim()) - return; - - if (!me->HasAura(SPELL_BARK_AURA)) - DoCast(SPELL_HARDENED_BARK); - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_FREYA))) - { - CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; - CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(4); - } - } - - private: - InstanceScript* instance; - uint8 waveCount; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_snaplasherAI(creature); - } -}; - -class npc_ancient_conservator : public CreatureScript -{ - public: - npc_ancient_conservator() : CreatureScript("npc_ancient_conservator") { } - - struct npc_ancient_conservatorAI : public ScriptedAI - { - npc_ancient_conservatorAI(Creature* creature) : ScriptedAI(creature) - { - } - - void Reset() - { - natureFuryTimer = 7500; - healthySporeTimer = 3500; - SummonHealthySpores(2); - } - - void SummonHealthySpores(uint8 sporesCount) - { - for (uint8 n = 0; n < sporesCount; ++n) - { - DoCast(SPELL_SUMMON_PERIODIC); - DoCast(SPELL_SPORE_SUMMON_NE); - DoCast(SPELL_SPORE_SUMMON_SE); - DoCast(SPELL_SPORE_SUMMON_SW); - } - } - - void EnterCombat(Unit* who) - { - DoCast(who, SPELL_CONSERVATOR_GRIP, true); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - if (healthySporeTimer <= diff) - { - SummonHealthySpores(1); - healthySporeTimer = urand(15000, 17500); - } - else - healthySporeTimer -= diff; - - if (natureFuryTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_NATURE_FURY)) - DoCast(target, SPELL_NATURE_FURY); - me->AddAura(SPELL_CONSERVATOR_GRIP, me); - natureFuryTimer = 5000; - } - else - natureFuryTimer -= diff; - - DoMeleeAttackIfReady(); - } - - private: - uint32 natureFuryTimer; - uint32 healthySporeTimer; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_ancient_conservatorAI(creature); - } -}; - -class npc_sun_beam : public CreatureScript -{ - public: - npc_sun_beam() : CreatureScript("npc_sun_beam") { } - - struct npc_sun_beamAI : public Scripted_NoMovementAI - { - npc_sun_beamAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - me->SetReactState(REACT_PASSIVE); - DoCastAOE(SPELL_FREYA_UNSTABLE_ENERGY_VISUAL, true); - DoCast(SPELL_FREYA_UNSTABLE_ENERGY); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_sun_beamAI(creature); - } -}; - -class npc_healthy_spore : public CreatureScript -{ - public: - npc_healthy_spore() : CreatureScript("npc_healthy_spore") { } - - struct npc_healthy_sporeAI : public Scripted_NoMovementAI - { - npc_healthy_sporeAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); - me->SetReactState(REACT_PASSIVE); - DoCast(me, SPELL_HEALTHY_SPORE_VISUAL); - DoCast(me, SPELL_POTENT_PHEROMONES); - DoCast(me, SPELL_GROW); - lifeTimer = urand(22000, 30000); - } - - void UpdateAI(uint32 const diff) - { - if (lifeTimer <= diff) - { - me->RemoveAurasDueToSpell(SPELL_GROW); - me->ForcedDespawn(2200); - lifeTimer = urand(22000, 30000); - } - else - lifeTimer -= diff; - } - - private: - uint32 lifeTimer; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_healthy_sporeAI(creature); - } -}; - -class npc_eonars_gift : public CreatureScript -{ - public: - npc_eonars_gift() : CreatureScript("npc_eonars_gift") { } - - struct npc_eonars_giftAI : public Scripted_NoMovementAI - { - npc_eonars_giftAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - lifeBindersGiftTimer = 12000; - DoCast(me, SPELL_GROW); - DoCast(me, SPELL_PHEROMONES, true); - DoCast(me, SPELL_EONAR_VISUAL, true); - } - - void UpdateAI(uint32 const diff) - { - if (lifeBindersGiftTimer <= diff) - { - me->RemoveAurasDueToSpell(SPELL_GROW); - DoCast(SPELL_LIFEBINDERS_GIFT); - me->ForcedDespawn(2500); - lifeBindersGiftTimer = 12000; - } - else - lifeBindersGiftTimer -= diff; - } - - private: - uint32 lifeBindersGiftTimer; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_eonars_giftAI(creature); - } -}; - -class npc_nature_bomb : public CreatureScript -{ - public: - npc_nature_bomb() : CreatureScript("npc_nature_bomb") { } - - struct npc_nature_bombAI : public Scripted_NoMovementAI - { - npc_nature_bombAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - bombTimer = urand(8000, 10000); - DoCast(SPELL_OBJECT_BOMB); - } - - void UpdateAI(uint32 const diff) - { - if (bombTimer <= diff) - { - if (GameObject* go = me->FindNearestGameObject(OBJECT_NATURE_BOMB, 1.0f)) - { - DoCast(me, SPELL_NATURE_BOMB); - me->RemoveGameObject(go, true); - me->RemoveFromWorld(); - } - - bombTimer = 10000; - } - else - bombTimer -= diff; - } - - private: - uint32 bombTimer; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_nature_bombAI(creature); - } -}; - -class npc_unstable_sun_beam : public CreatureScript -{ - public: - npc_unstable_sun_beam() : CreatureScript("npc_unstable_sun_beam") { } - - struct npc_unstable_sun_beamAI : public Scripted_NoMovementAI - { - npc_unstable_sun_beamAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - despawnTimer = urand(7000, 12000); - instance = me->GetInstanceScript(); - DoCast(me, SPELL_PHOTOSYNTHESIS); - DoCast(me, SPELL_UNSTABLE_SUN_BEAM); - me->SetReactState(REACT_PASSIVE); - } - - void UpdateAI(uint32 const diff) - { - if (despawnTimer <= diff) - { - DoCastAOE(SPELL_UNSTABLE_ENERGY, true); - me->DisappearAndDie(); - } - else - despawnTimer -= diff; - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) - { - if (target && spell->Id == SPELL_UNSTABLE_ENERGY) - { - target->RemoveAurasDueToSpell(SPELL_UNSTABLE_SUN_BEAM); - target->RemoveAurasDueToSpell(SPELL_UNSTABLE_SUN_BEAM_TRIGGERED); - } - } - - private: - InstanceScript* instance; - uint32 despawnTimer; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_unstable_sun_beamAI(creature); - } -}; - -class spell_freya_attuned_to_nature_dose_reduction : public SpellScriptLoader -{ - public: - spell_freya_attuned_to_nature_dose_reduction() : SpellScriptLoader("spell_freya_attuned_to_nature_dose_reduction") - { - } - - class spell_freya_attuned_to_nature_dose_reduction_SpellScript : public SpellScript - { - PrepareSpellScript(spell_freya_attuned_to_nature_dose_reduction_SpellScript) - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* target = GetHitUnit(); - SpellInfo const* spellInfo = GetSpellInfo(); - switch (spellInfo->Id) - { - case SPELL_ATTUNED_TO_NATURE_2_DOSE_REDUCTION: - if (target->HasAura(GetEffectValue())) - for (uint8 n = 0; n < 2; ++n) - target->RemoveAuraFromStack(GetEffectValue(), 0, AURA_REMOVE_BY_DEFAULT); - break; - case SPELL_ATTUNED_TO_NATURE_10_DOSE_REDUCTION: - if (target->HasAura(GetEffectValue())) - for (uint8 n = 0; n < 10; ++n) - target->RemoveAuraFromStack(GetEffectValue(), 0, AURA_REMOVE_BY_DEFAULT); - break; - case SPELL_ATTUNED_TO_NATURE_25_DOSE_REDUCTION: - if (target->HasAura(GetEffectValue())) - for (uint8 n = 0; n < 25; ++n) - target->RemoveAuraFromStack(GetEffectValue(), 0, AURA_REMOVE_BY_DEFAULT); - break; - default: - break; - } - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_freya_attuned_to_nature_dose_reduction_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_freya_attuned_to_nature_dose_reduction_SpellScript(); - } -}; - -class spell_freya_iron_roots : public SpellScriptLoader -{ - public: - spell_freya_iron_roots() : SpellScriptLoader("spell_freya_iron_roots") - { - } - - class spell_freya_iron_roots_SpellScript : public SpellScript - { - PrepareSpellScript(spell_freya_iron_roots_SpellScript); - - void HandleSummon(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue); - - Position pos; - GetCaster()->GetPosition(&pos); - // Not good at all, but this prevents having roots in a different position then player - if (Creature* Roots = GetCaster()->SummonCreature(entry, pos)) - GetCaster()->NearTeleportTo(Roots->GetPositionX(), Roots->GetPositionY(), Roots->GetPositionZ(), GetCaster()->GetOrientation()); - } - - void Register() - { - OnEffectHit += SpellEffectFn(spell_freya_iron_roots_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_freya_iron_roots_SpellScript(); - } -}; - -class achievement_getting_back_to_nature : public AchievementCriteriaScript -{ - public: - achievement_getting_back_to_nature() : AchievementCriteriaScript("achievement_getting_back_to_nature") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Freya = target->ToCreature()) - if (Freya->AI()->GetData(DATA_GETTING_BACK_TO_NATURE) >= 25) - return true; - - return false; - } -}; - -class achievement_knock_on_wood : public AchievementCriteriaScript -{ - public: - achievement_knock_on_wood() : AchievementCriteriaScript("achievement_knock_on_wood") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Freya = target->ToCreature()) - if (Freya->AI()->GetData(DATA_KNOCK_ON_WOOD) >= 1) - return true; - - return false; - } -}; - -class achievement_knock_knock_on_wood : public AchievementCriteriaScript -{ - public: - achievement_knock_knock_on_wood() : AchievementCriteriaScript("achievement_knock_knock_on_wood") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Freya = target->ToCreature()) - if (Freya->AI()->GetData(DATA_KNOCK_ON_WOOD) >= 2) - return true; - - return false; - } -}; - -class achievement_knock_knock_knock_on_wood : public AchievementCriteriaScript -{ - public: - achievement_knock_knock_knock_on_wood() : AchievementCriteriaScript("achievement_knock_knock_knock_on_wood") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Freya = target->ToCreature()) - if (Freya->AI()->GetData(DATA_KNOCK_ON_WOOD) == 3) - return true; - - return false; - } -}; - -void AddSC_boss_freya() -{ - new boss_freya(); - new boss_elder_brightleaf(); - new boss_elder_ironbranch(); - new boss_elder_stonebark(); - new npc_ancient_conservator(); - new npc_snaplasher(); - new npc_storm_lasher(); - new npc_ancient_water_spirit(); - new npc_detonating_lasher(); - new npc_sun_beam(); - new npc_nature_bomb(); - new npc_eonars_gift(); - new npc_healthy_spore(); - new npc_unstable_sun_beam(); - new npc_iron_roots(); - new spell_freya_attuned_to_nature_dose_reduction(); - new spell_freya_iron_roots(); - new achievement_getting_back_to_nature(); - new achievement_knock_on_wood(); - new achievement_knock_knock_on_wood(); - new achievement_knock_knock_knock_on_wood(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp deleted file mode 100644 index 7d00c0e59fc..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "SpellScript.h" -#include "SpellAuraEffects.h" -#include "ulduar.h" - -enum VezaxYells -{ - SAY_AGGRO = -1603290, - SAY_SLAY_1 = -1603291, - SAY_SLAY_2 = -1603292, - SAY_SURGE_OF_DARKNESS = -1603293, - SAY_DEATH = -1603294, - SAY_BERSERK = -1603295, - SAY_HARDMODE = -1603296, -}; - -enum VezaxEmotes -{ - EMOTE_VAPORS = -1603289, - EMOTE_ANIMUS = -1603297, - EMOTE_BARRIER = -1603298, - EMOTE_SURGE_OF_DARKNESS = -1603299, -}; - -enum VezaxSpells -{ - SPELL_AURA_OF_DESPAIR = 62692, - SPELL_MARK_OF_THE_FACELESS = 63276, - SPELL_MARK_OF_THE_FACELESS_DAMAGE = 63278, - SPELL_SARONITE_BARRIER = 63364, - SPELL_SEARING_FLAMES = 62661, - SPELL_SHADOW_CRASH = 62660, - SPELL_SHADOW_CRASH_HIT = 62659, - SPELL_SURGE_OF_DARKNESS = 62662, - SPELL_SARONITE_VAPORS = 63323, - SPELL_SUMMON_SARONITE_VAPORS = 63081, - SPELL_BERSERK = 26662, - - SPELL_SUMMON_SARONITE_ANIMUS = 63145, - SPELL_VISUAL_SARONITE_ANIMUS = 63319, - SPELL_PROFOUND_OF_DARKNESS = 63420, - - SPELL_CORRUPTED_RAGE = 68415, - SPELL_SHAMANTIC_RAGE = 30823, -}; - -enum VezaxActions -{ - ACTION_VAPORS_SPAWN, - ACTION_VAPORS_DIE, - ACTION_ANIMUS_DIE, -}; - -enum VezaxEvents -{ - // Vezax - EVENT_SHADOW_CRASH = 1, - EVENT_SEARING_FLAMES = 2, - EVENT_SURGE_OF_DARKNESS = 3, - EVENT_MARK_OF_THE_FACELESS = 4, - EVENT_SARONITE_VAPORS = 5, - EVENT_BERSERK = 6, - - // Saronite Animus - EVENT_PROFOUND_OF_DARKNESS = 7, - - // Saronite Vapor - EVENT_RANDOM_MOVE = 8, -}; - -#define DATA_SMELL_SARONITE 31813188 -#define DATA_SHADOWDODGER 29962997 - -class boss_general_vezax : public CreatureScript -{ - public: - boss_general_vezax() : CreatureScript("boss_general_vezax") { } - - struct boss_general_vezaxAI : public BossAI - { - boss_general_vezaxAI(Creature* creature) : BossAI(creature, BOSS_VEZAX) - { - } - - bool shadowDodger; - bool smellSaronite; // HardMode - bool animusDead; // Check against getting a HardMode achievement before killing Saronite Animus - uint8 vaporCount; - - void Reset() - { - _Reset(); - - shadowDodger = true; - smellSaronite = true; - animusDead = false; - vaporCount = 0; - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - - DoScriptText(SAY_AGGRO, me); - DoCast(me, SPELL_AURA_OF_DESPAIR); - CheckShamanisticRage(); - - events.ScheduleEvent(EVENT_SHADOW_CRASH, urand(8000, 10000)); - events.ScheduleEvent(EVENT_SEARING_FLAMES, 12000); - events.ScheduleEvent(EVENT_MARK_OF_THE_FACELESS, urand(35000, 40000)); - events.ScheduleEvent(EVENT_SARONITE_VAPORS, 30000); - events.ScheduleEvent(EVENT_SURGE_OF_DARKNESS, 60000); - events.ScheduleEvent(EVENT_BERSERK, 600000); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHADOW_CRASH: - { - Unit* target = CheckPlayersInRange(RAID_MODE(4, 9), 15.0f, 50.0f); - if (!target) - target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true); - if (target) - DoCast(target, SPELL_SHADOW_CRASH); - events.ScheduleEvent(EVENT_SHADOW_CRASH, urand(8000, 12000)); - break; - } - case EVENT_SEARING_FLAMES: - DoCastAOE(SPELL_SEARING_FLAMES); - events.ScheduleEvent(EVENT_SEARING_FLAMES, urand(14000, 17500)); - break; - case EVENT_MARK_OF_THE_FACELESS: - { - Unit* target = CheckPlayersInRange(RAID_MODE(4, 9), 15.0f, 50.0f); - if (!target) - target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true); - if (target) - DoCast(target, SPELL_MARK_OF_THE_FACELESS); - events.ScheduleEvent(EVENT_MARK_OF_THE_FACELESS, urand(35000, 45000)); - break; - } - case EVENT_SURGE_OF_DARKNESS: - DoScriptText(EMOTE_SURGE_OF_DARKNESS, me); - DoScriptText(SAY_SURGE_OF_DARKNESS, me); - DoCast(me, SPELL_SURGE_OF_DARKNESS); - events.ScheduleEvent(EVENT_SURGE_OF_DARKNESS, urand(50000, 70000)); - break; - case EVENT_SARONITE_VAPORS: - DoCast(SPELL_SUMMON_SARONITE_VAPORS); - events.ScheduleEvent(EVENT_SARONITE_VAPORS, urand(30000, 35000)); - if (++vaporCount == 6 && smellSaronite) - { - DoScriptText(SAY_HARDMODE, me); - DoScriptText(EMOTE_BARRIER, me); - summons.DespawnAll(); - DoCast(me, SPELL_SARONITE_BARRIER); - DoCast(SPELL_SUMMON_SARONITE_ANIMUS); - me->AddLootMode(LOOT_MODE_HARD_MODE_1); - events.CancelEvent(EVENT_SARONITE_VAPORS); - events.CancelEvent(EVENT_SEARING_FLAMES); - } - break; - case EVENT_BERSERK: - DoScriptText(SAY_BERSERK, me); - DoCast(me, SPELL_BERSERK); - break; - } - } - - DoMeleeAttackIfReady(); - } - - void SpellHitTarget(Unit* who, SpellInfo const* spell) - { - if (who && who->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_SHADOW_CRASH_HIT) - shadowDodger = false; - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void JustDied(Unit* /*who*/) - { - _JustDied(); - DoScriptText(SAY_DEATH, me); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_AURA_OF_DESPAIR); - } - - void CheckShamanisticRage() - { - Map* map = me->GetMap(); - if (map && map->IsDungeon()) - { - // If Shaman has Shamanistic Rage and use it during the fight, it will cast Corrupted Rage on him - Map::PlayerList const& Players = map->GetPlayers(); - for (Map::PlayerList::const_iterator itr = Players.begin(); itr != Players.end(); ++itr) - if (Player* player = itr->getSource()) - if (player->HasSpell(SPELL_SHAMANTIC_RAGE)) - player->CastSpell(player, SPELL_CORRUPTED_RAGE, false); - } - } - - uint32 GetData(uint32 type) - { - switch (type) - { - case DATA_SHADOWDODGER: - return shadowDodger ? 1 : 0; - case DATA_SMELL_SARONITE: - return smellSaronite ? 1 : 0; - } - - return 0; - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_VAPORS_DIE: - smellSaronite = false; - break; - case ACTION_ANIMUS_DIE: - me->RemoveAurasDueToSpell(SPELL_SARONITE_BARRIER); - events.ScheduleEvent(EVENT_SEARING_FLAMES, urand(7000, 12000)); - animusDead = true; - break; - } - } - - /* Player Range Check - Purpose: If there are playersMin people within rangeMin, rangeMax: return a random players in that range. - If not, return NULL and allow other target selection - */ - Unit* CheckPlayersInRange(uint8 playersMin, float rangeMin, float rangeMax) - { - Map* map = me->GetMap(); - if (map && map->IsDungeon()) - { - std::list PlayerList; - Map::PlayerList const& Players = map->GetPlayers(); - for (Map::PlayerList::const_iterator itr = Players.begin(); itr != Players.end(); ++itr) - { - if (Player* player = itr->getSource()) - { - float distance = player->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); - if (rangeMin > distance || distance > rangeMax) - continue; - - PlayerList.push_back(player); - } - } - - if (PlayerList.empty()) - return NULL; - - size_t size = PlayerList.size(); - if (size < playersMin) - return NULL; - - return SelectRandomContainerElement(PlayerList); - } - - return NULL; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class boss_saronite_animus : public CreatureScript -{ - public: - boss_saronite_animus() : CreatureScript("npc_saronite_animus") { } - - struct boss_saronite_animusAI : public ScriptedAI - { - boss_saronite_animusAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - DoScriptText(EMOTE_BARRIER, me); - } - - void Reset() - { - DoCast(me, SPELL_VISUAL_SARONITE_ANIMUS); - events.Reset(); - events.ScheduleEvent(EVENT_PROFOUND_OF_DARKNESS, 3000); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Vezax = me->GetCreature(*me, instance->GetData64(BOSS_VEZAX))) - Vezax->AI()->DoAction(ACTION_ANIMUS_DIE); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_PROFOUND_OF_DARKNESS: - DoCastAOE(SPELL_PROFOUND_OF_DARKNESS, true); - events.ScheduleEvent(EVENT_PROFOUND_OF_DARKNESS, 3000); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* instance; - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_saronite_animusAI(creature); - } -}; - -class npc_saronite_vapors : public CreatureScript -{ - public: - npc_saronite_vapors() : CreatureScript("npc_saronite_vapors") { } - - struct npc_saronite_vaporsAI : public ScriptedAI - { - npc_saronite_vaporsAI(Creature* creature) : ScriptedAI(creature) - { - DoScriptText(EMOTE_VAPORS, me); - instance = me->GetInstanceScript(); - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); - me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip jump effect - me->SetReactState(REACT_PASSIVE); - } - - void Reset() - { - events.Reset(); - events.ScheduleEvent(EVENT_RANDOM_MOVE, urand(5000, 7500)); - } - - void UpdateAI(uint32 const diff) - { - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_RANDOM_MOVE: - me->GetMotionMaster()->MoveRandom(30.0f); - events.ScheduleEvent(EVENT_RANDOM_MOVE, urand(5000, 7500)); - break; - default: - break; - } - } - } - - void DamageTaken(Unit* /*who*/, uint32& damage) - { - // This can't be on JustDied. In 63322 dummy handler caster needs to be this NPC - // if caster == target then damage mods will increase the damage taken - if (damage >= me->GetHealth()) - { - damage = 0; - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE); - me->SetStandState(UNIT_STAND_STATE_DEAD); - me->SetHealth(me->GetMaxHealth()); - me->RemoveAllAuras(); - DoCast(me, SPELL_SARONITE_VAPORS); - me->DespawnOrUnsummon(30000); - - if (Creature* Vezax = me->GetCreature(*me, instance->GetData64(BOSS_VEZAX))) - Vezax->AI()->DoAction(ACTION_VAPORS_DIE); - } - } - - private: - InstanceScript* instance; - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_saronite_vaporsAI(creature); - } -}; - -class spell_mark_of_the_faceless : public SpellScriptLoader -{ - public: - spell_mark_of_the_faceless() : SpellScriptLoader("spell_mark_of_the_faceless") { } - - class spell_mark_of_the_faceless_AuraScript : public AuraScript - { - PrepareAuraScript(spell_mark_of_the_faceless_AuraScript); - - void HandleEffectPeriodic(AuraEffect const* aurEff) - { - if (Unit* caster = GetCaster()) - caster->CastCustomSpell(SPELL_MARK_OF_THE_FACELESS_DAMAGE, SPELLVALUE_BASE_POINT1, aurEff->GetAmount(), GetTarget(), true); - } - - void Register() - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_the_faceless_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_mark_of_the_faceless_AuraScript(); - } -}; - -class achievement_shadowdodger : public AchievementCriteriaScript -{ - public: - achievement_shadowdodger() : AchievementCriteriaScript("achievement_shadowdodger") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Vezax = target->ToCreature()) - if (Vezax->AI()->GetData(DATA_SHADOWDODGER)) - return true; - - return false; - } -}; - -class achievement_smell_saronite : public AchievementCriteriaScript -{ - public: - achievement_smell_saronite() : AchievementCriteriaScript("achievement_smell_saronite") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* Vezax = target->ToCreature()) - if (Vezax->AI()->GetData(DATA_SMELL_SARONITE)) - return true; - - return false; - } -}; - -void AddSC_boss_general_vezax() -{ - new boss_general_vezax(); - new boss_saronite_animus(); - new npc_saronite_vapors(); - new spell_mark_of_the_faceless(); - new achievement_shadowdodger(); - new achievement_smell_saronite(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp deleted file mode 100644 index bb21da94bc5..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp +++ /dev/null @@ -1,1013 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "SpellScript.h" -#include "SpellAuraEffects.h" -#include "Cell.h" -#include "CellImpl.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "ulduar.h" - -/* #TODO: Achievements - Storm Cloud (Shaman ability) - Destroying of Toasty Fires -*/ - -enum HodirYells -{ - SAY_AGGRO = -1603210, - SAY_SLAY_1 = -1603211, - SAY_SLAY_2 = -1603212, - SAY_FLASH_FREEZE = -1603213, - SAY_STALACTITE = -1603214, - SAY_DEATH = -1603215, - SAY_BERSERK = -1603216, - SAY_YS_HELP = -1603217, - SAY_HARD_MODE_FAILED = -1603218, - - EMOTE_FREEZE = -1603209, - EMOTE_BLOWS = -1603219, -}; - -enum HodirSpells -{ - // Hodir - SPELL_FROZEN_BLOWS = 62478, - SPELL_FLASH_FREEZE = 61968, - SPELL_FLASH_FREEZE_VISUAL = 62148, - SPELL_BITING_COLD = 62038, - SPELL_BITING_COLD_TRIGGERED = 62039, // Needed for Achievement Getting Cold In Here - SPELL_BITING_COLD_DAMAGE = 62188, - SPELL_FREEZE = 62469, - SPELL_ICICLE = 62234, - SPELL_ICICLE_SNOWDRIFT = 62462, - SPELL_BLOCK_OF_ICE = 61969, // Player + Helper - SPELL_SUMMON_FLASH_FREEZE_HELPER = 61989, // Helper - SPELL_SUMMON_BLOCK_OF_ICE = 61970, // Player + Helper - SPELL_FLASH_FREEZE_HELPER = 61990, // Helper - SPELL_FLASH_FREEZE_KILL = 62226, - SPELL_ICICLE_FALL = 69428, - SPELL_FALL_DAMAGE = 62236, - SPELL_FALL_SNOWDRIFT = 62460, - SPELL_BERSERK = 47008, - SPELL_ICE_SHARD = 62457, - SPELL_ICE_SHARD_HIT = 65370, - - // Druids - SPELL_WRATH = 62793, - SPELL_STARLIGHT = 62807, - - // Shamans - SPELL_LAVA_BURST = 61924, - SPELL_STORM_CLOUD = 65123, - - // Mages - SPELL_FIREBALL = 61909, - SPELL_CONJURE_FIRE = 62823, - SPELL_MELT_ICE = 64528, - SPELL_SINGED = 62821, - - // Priests - SPELL_SMITE = 61923, - SPELL_GREATER_HEAL = 62809, - SPELL_DISPEL_MAGIC = 63499, -}; - -enum HodirNPC -{ - NPC_ICE_BLOCK = 32938, - NPC_FLASH_FREEZE = 32926, - NPC_SNOWPACKED_ICICLE = 33174, - NPC_ICICLE = 33169, - NPC_ICICLE_SNOWDRIFT = 33173, - NPC_TOASTY_FIRE = 33342, -}; - -enum HodirGameObjects -{ - GO_TOASTY_FIRE = 194300, - GO_SNOWDRIFT = 194173, -}; - -enum HodirEvents -{ - // Hodir - EVENT_FREEZE = 1, - EVENT_FLASH_FREEZE = 2, - EVENT_FLASH_FREEZE_EFFECT = 3, - EVENT_ICICLE = 4, - EVENT_BLOWS = 5, - EVENT_RARE_CACHE = 6, - EVENT_BERSERK = 7, - - // Priest - EVENT_HEAL = 8, - EVENT_DISPEL_MAGIC = 9, - - // Shaman - EVENT_STORM_CLOUD = 10, - - // Druid - EVENT_STARLIGHT = 11, - - // Mage - EVENT_CONJURE_FIRE = 12, - EVENT_MELT_ICE = 13, -}; - -enum HodirActions -{ - ACTION_I_HAVE_THE_COOLEST_FRIENDS = 1, - ACTION_CHEESE_THE_FREEZE = 2, -}; - -#define ACHIEVEMENT_CHEESE_THE_FREEZE RAID_MODE(2961, 2962) -#define ACHIEVEMENT_GETTING_COLD_IN_HERE RAID_MODE(2967, 2968) -#define ACHIEVEMENT_THIS_CACHE_WAS_RARE RAID_MODE(3182, 3184) -#define ACHIEVEMENT_COOLEST_FRIENDS RAID_MODE(2963, 2965) -#define FRIENDS_COUNT RAID_MODE(4, 8) -#define DATA_GETTING_COLD_IN_HERE 29672968 // 2967, 2968 are achievement IDs - -Position const SummonPositions[8] = -{ - { 1983.75f, -243.36f, 432.767f, 1.57f }, // Field Medic Penny && Battle-Priest Eliza - { 1999.90f, -230.49f, 432.767f, 1.57f }, // Eivi Nightfeather && Tor Greycloud - { 2010.06f, -243.45f, 432.767f, 1.57f }, // Elementalist Mahfuun && Spiritwalker Tara - { 2021.12f, -236.65f, 432.767f, 1.57f }, // Missy Flamecuffs && Amira Blazeweaver - { 2028.10f, -244.66f, 432.767f, 1.57f }, // Field Medic Jessi && Battle-Priest Gina - { 2014.18f, -232.80f, 432.767f, 1.57f }, // Ellie Nightfeather && Kar Greycloud - { 1992.90f, -237.54f, 432.767f, 1.57f }, // Elementalist Avuun && Spiritwalker Yona - { 1976.60f, -233.53f, 432.767f, 1.57f }, // Sissy Flamecuffs && Veesha Blazeweaver -}; - -uint32 const Entry[8] = -{ - NPC_FIELD_MEDIC_PENNY, - NPC_EIVI_NIGHTFEATHER, - NPC_ELEMENTALIST_MAHFUUN, - NPC_MISSY_FLAMECUFFS, - NPC_FIELD_MEDIC_JESSI, - NPC_ELLIE_NIGHTFEATHER, - NPC_ELEMENTALIST_AVUUN, - NPC_SISSY_FLAMECUFFS, -}; - -class npc_flash_freeze : public CreatureScript -{ - public: - npc_flash_freeze() : CreatureScript("npc_flash_freeze") { } - - struct npc_flash_freezeAI : public ScriptedAI - { - npc_flash_freezeAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - me->SetDisplayId(me->GetCreatureInfo()->Modelid2); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); - } - - InstanceScript* instance; - - uint64 targetGUID; - uint32 checkDespawnTimer; - - void Reset() - { - targetGUID = 0; - checkDespawnTimer = 1000; - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->getVictim()->HasAura(SPELL_BLOCK_OF_ICE) || me->getVictim()->HasAura(SPELL_FLASH_FREEZE_HELPER)) - return; - - if (me->getVictim()->GetGUID() != targetGUID || instance->GetBossState(BOSS_HODIR) != IN_PROGRESS) - me->DespawnOrUnsummon(); - - if (checkDespawnTimer <= diff) - { - if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID)) - if (!target->isAlive()) - me->DisappearAndDie(); - checkDespawnTimer = 2500; - } - else - checkDespawnTimer -= diff; - } - - void IsSummonedBy(Unit* summoner) - { - targetGUID = summoner->GetGUID(); - me->SetInCombatWith(summoner); - me->AddThreat(summoner, 250.0f); - if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID)) - { - DoCast(target, SPELL_BLOCK_OF_ICE, true); - // Prevents to have Ice Block on other place than target is - me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); - if (target->GetTypeId() == TYPEID_PLAYER) - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) - Hodir->AI()->DoAction(ACTION_CHEESE_THE_FREEZE); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_flash_freezeAI(creature); - } -}; - -class npc_ice_block : public CreatureScript -{ - public: - npc_ice_block() : CreatureScript("npc_ice_block") { } - - struct npc_ice_blockAI : public ScriptedAI - { - npc_ice_blockAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - me->SetDisplayId(me->GetCreatureInfo()->Modelid2); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); - targetGUID = 0; - } - - InstanceScript* instance; - - uint64 targetGUID; - - void IsSummonedBy(Unit* summoner) - { - targetGUID = summoner->GetGUID(); - summoner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); - me->SetInCombatWith(summoner); - me->AddThreat(summoner, 250.0f); - summoner->AddThreat(me, 250.0f); - if (Creature* target = ObjectAccessor::GetCreature(*me, targetGUID)) - { - DoCast(target, SPELL_FLASH_FREEZE_HELPER, true); - // Prevents to have Ice Block on other place than target is - me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); - } - } - - void DamageTaken(Unit* who, uint32& /*damage*/) - { - if (Creature* Helper = ObjectAccessor::GetCreature(*me, targetGUID)) - { - Helper->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); - - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) - { - if (!Hodir->isInCombat()) - { - Hodir->SetReactState(REACT_AGGRESSIVE); - Hodir->AI()->DoZoneInCombat(); - Hodir->AI()->AttackStart(who); - } - - Helper->AI()->AttackStart(Hodir); - } - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_ice_blockAI(creature); - } -}; - -class boss_hodir : public CreatureScript -{ - public: - boss_hodir() : CreatureScript("boss_hodir") { } - - struct boss_hodirAI : public BossAI - { - boss_hodirAI(Creature* creature) : BossAI(creature, BOSS_HODIR) - { - me->SetReactState(REACT_PASSIVE); - } - - uint32 gettingColdInHereTimer; - - bool gettingColdInHere; - bool cheeseTheFreeze; - bool iHaveTheCoolestFriends; - bool iCouldSayThatThisCacheWasRare; - - void Reset() - { - _Reset(); - me->SetReactState(REACT_PASSIVE); - - for (uint8 n = 0; n < FRIENDS_COUNT; ++n) - if (Creature* FrozenHelper = me->SummonCreature(Entry[n], SummonPositions[n], TEMPSUMMON_MANUAL_DESPAWN)) - FrozenHelper->CastSpell(FrozenHelper, SPELL_SUMMON_FLASH_FREEZE_HELPER, true); - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - DoScriptText(SAY_AGGRO, me); - DoCast(me, SPELL_BITING_COLD, true); - - gettingColdInHereTimer = 1000; - gettingColdInHere = true; - cheeseTheFreeze = true; - iHaveTheCoolestFriends = true; - iCouldSayThatThisCacheWasRare = true; - - events.ScheduleEvent(EVENT_ICICLE, 2000); - events.ScheduleEvent(EVENT_FREEZE, 25000); - events.ScheduleEvent(EVENT_BLOWS, urand(60000, 65000)); - events.ScheduleEvent(EVENT_FLASH_FREEZE, 45000); - events.ScheduleEvent(EVENT_RARE_CACHE, 180000); - events.ScheduleEvent(EVENT_BERSERK, 480000); - } - - void KilledUnit(Unit* /*who*/) - { - if (!urand(0, 3)) - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void DamageTaken(Unit* /*who*/, uint32& damage) - { - if (damage >= me->GetHealth()) - { - damage = 0; - DoScriptText(SAY_DEATH, me); - if (iCouldSayThatThisCacheWasRare) - instance->SetData(DATA_HODIR_RARE_CACHE, 1); - - me->RemoveAllAuras(); - me->RemoveAllAttackers(); - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); - me->InterruptNonMeleeSpells(true); - me->StopMoving(); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveIdle(); - me->SetControlled(true, UNIT_STAT_STUNNED); - me->CombatStop(true); - - me->setFaction(35); - me->DespawnOrUnsummon(10000); - - _JustDied(); - } - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FREEZE: - DoCastAOE(SPELL_FREEZE); - events.ScheduleEvent(EVENT_FREEZE, urand(30000, 45000)); - break; - case EVENT_ICICLE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - DoCast(target, SPELL_ICICLE); - events.ScheduleEvent(EVENT_ICICLE, RAID_MODE(5500, 3500)); - break; - case EVENT_FLASH_FREEZE: - DoScriptText(SAY_FLASH_FREEZE, me); - DoScriptText(EMOTE_FREEZE, me); - for (uint8 n = 0; n < RAID_MODE(2, 3); ++n) - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - target->CastSpell(target, SPELL_ICICLE_SNOWDRIFT, true); - DoCast(SPELL_FLASH_FREEZE); - events.ScheduleEvent(EVENT_FLASH_FREEZE_EFFECT, 500); - break; - case EVENT_FLASH_FREEZE_EFFECT: - { - std::list IcicleSnowdriftList; - GetCreatureListWithEntryInGrid(IcicleSnowdriftList, me, NPC_SNOWPACKED_ICICLE, 100.0f); - for (std::list::iterator itr = IcicleSnowdriftList.begin(); itr != IcicleSnowdriftList.end(); ++itr) - (*itr)->CastSpell(me, SPELL_FLASH_FREEZE_VISUAL, true); - FlashFreeze(); - events.CancelEvent(EVENT_FLASH_FREEZE_EFFECT); - events.ScheduleEvent(EVENT_FLASH_FREEZE, urand(25000, 35000)); - break; - } - case EVENT_BLOWS: - DoScriptText(SAY_STALACTITE, me); - DoScriptText(EMOTE_BLOWS, me); - DoCast(me, SPELL_FROZEN_BLOWS); - events.ScheduleEvent(EVENT_BLOWS, urand(60000, 65000)); - break; - case EVENT_RARE_CACHE: - DoScriptText(SAY_HARD_MODE_FAILED, me); - iCouldSayThatThisCacheWasRare = false; - instance->SetData(DATA_HODIR_RARE_CACHE, 0); - events.CancelEvent(EVENT_RARE_CACHE); - break; - case EVENT_BERSERK: - DoScriptText(SAY_BERSERK, me); - DoCast(me, SPELL_BERSERK, true); - events.CancelEvent(EVENT_BERSERK); - break; - } - } - - if (gettingColdInHereTimer <= diff && gettingColdInHere) - { - std::list ThreatList = me->getThreatManager().getThreatList(); - for (std::list::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); ++itr) - if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) - if (Aura* BitingColdAura = target->GetAura(SPELL_BITING_COLD_TRIGGERED)) - if ((target->GetTypeId() == TYPEID_PLAYER) && (BitingColdAura->GetStackAmount() > 2)) - me->AI()->SetData(DATA_GETTING_COLD_IN_HERE, 0); - gettingColdInHereTimer = 1000; - } - else - gettingColdInHereTimer -= diff; - - DoMeleeAttackIfReady(); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_I_HAVE_THE_COOLEST_FRIENDS: - iHaveTheCoolestFriends = false; - break; - case ACTION_CHEESE_THE_FREEZE: - cheeseTheFreeze = false; - break; - default: - break; - } - } - - void FlashFreeze() - { - std::list TargetList; - Trinity::AnyUnfriendlyUnitInObjectRangeCheck checker(me, me, 100.0f); - Trinity::UnitListSearcher searcher(me, TargetList, checker); - me->VisitNearbyObject(100.0f, searcher); - for (std::list::iterator itr = TargetList.begin(); itr != TargetList.end(); ++itr) - { - Unit* target = *itr; - if (!target || !target->isAlive() || GetClosestCreatureWithEntry(target, NPC_SNOWPACKED_ICICLE, 5.0f)) - continue; - - if (target->HasAura(SPELL_FLASH_FREEZE_HELPER) || target->HasAura(SPELL_BLOCK_OF_ICE)) - { - me->CastSpell(target, SPELL_FLASH_FREEZE_KILL, true); - continue; - } - - target->CastSpell(target, SPELL_SUMMON_BLOCK_OF_ICE, true); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class npc_icicle : public CreatureScript -{ - public: - npc_icicle() : CreatureScript("npc_icicle") { } - - struct npc_icicleAI : public ScriptedAI - { - npc_icicleAI(Creature* creature) : ScriptedAI(creature) - { - me->SetDisplayId(me->GetCreatureInfo()->Modelid1); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); - } - - uint32 icicleTimer; - - void Reset() - { - icicleTimer = 2500; - } - - void UpdateAI(uint32 const diff) - { - if (icicleTimer <= diff) - { - if (me->GetEntry() == NPC_ICICLE_SNOWDRIFT) - { - DoCast(me, SPELL_FALL_SNOWDRIFT); - DoCast(me, SPELL_ICICLE_FALL); - } - else if (me->GetEntry() == NPC_ICICLE) - { - DoCast(me, SPELL_ICICLE_FALL); - DoCast(me, SPELL_FALL_DAMAGE, true); - } - icicleTimer = 10000; - } - else - icicleTimer -= diff; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class npc_snowpacked_icicle : public CreatureScript -{ - public: - npc_snowpacked_icicle() : CreatureScript("npc_snowpacked_icicle") { } - - struct npc_snowpacked_icicleAI : public ScriptedAI - { - npc_snowpacked_icicleAI(Creature* creature) : ScriptedAI(creature) - { - me->SetDisplayId(me->GetCreatureInfo()->Modelid2); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); - me->SetReactState(REACT_PASSIVE); - } - - uint32 despawnTimer; - - void Reset() - { - despawnTimer = 12000; - } - - void UpdateAI(uint32 const diff) - { - if (despawnTimer <= diff) - { - if (GameObject* Snowdrift = me->FindNearestGameObject(GO_SNOWDRIFT, 2.0f)) - me->RemoveGameObject(Snowdrift, true); - me->DespawnOrUnsummon(); - } - else - despawnTimer -= diff; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class npc_hodir_priest : public CreatureScript -{ - public: - npc_hodir_priest() : CreatureScript("npc_hodir_priest") { } - - struct npc_hodir_priestAI : public ScriptedAI - { - npc_hodir_priestAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - void Reset() - { - events.Reset(); - events.ScheduleEvent(EVENT_HEAL, urand(4000, 8000)); - events.ScheduleEvent(EVENT_DISPEL_MAGIC, urand(15000, 20000)); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - if (HealthBelowPct(30)) - DoCast(me, SPELL_GREATER_HEAL); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_HEAL: - DoCastAOE(SPELL_GREATER_HEAL); - events.ScheduleEvent(EVENT_HEAL, urand(7500, 10000)); - break; - case EVENT_DISPEL_MAGIC: - { - std::list TargetList; - Trinity::AnyFriendlyUnitInObjectRangeCheck checker(me, me, 30.0f); - Trinity::UnitListSearcher searcher(me, TargetList, checker); - me->VisitNearbyObject(30.0f, searcher); - for (std::list::iterator itr = TargetList.begin(); itr != TargetList.end(); ++itr) - if ((*itr)->HasAura(SPELL_FREEZE)) - DoCast(*itr, SPELL_DISPEL_MAGIC, true); - events.ScheduleEvent(EVENT_DISPEL_MAGIC, urand(15000, 20000)); - break; - } - default: - break; - } - } - - DoSpellAttackIfReady(SPELL_SMITE); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); - } - - private: - InstanceScript* instance; - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class npc_hodir_shaman : public CreatureScript -{ - public: - npc_hodir_shaman() : CreatureScript("npc_hodir_shaman") { } - - struct npc_hodir_shamanAI : public ScriptedAI - { - npc_hodir_shamanAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - void Reset() - { - events.Reset(); - events.ScheduleEvent(EVENT_STORM_CLOUD, urand(10000, 12500)); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_STORM_CLOUD: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) - DoCast(target, SPELL_STORM_CLOUD, true); - events.ScheduleEvent(EVENT_STORM_CLOUD, urand(15000, 20000)); - break; - default: - break; - } - } - - DoSpellAttackIfReady(SPELL_LAVA_BURST); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); - } - - private: - InstanceScript* instance; - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class npc_hodir_druid : public CreatureScript -{ - public: - npc_hodir_druid() : CreatureScript("npc_hodir_druid") { } - - struct npc_hodir_druidAI : public ScriptedAI - { - npc_hodir_druidAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - } - - void Reset() - { - events.Reset(); - events.ScheduleEvent(EVENT_STARLIGHT, urand(15000, 17500)); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_STARLIGHT: - DoCast(me, SPELL_STARLIGHT, true); - events.ScheduleEvent(EVENT_STARLIGHT, urand(25000, 35000)); - break; - default: - break; - } - } - - DoSpellAttackIfReady(SPELL_WRATH); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); - } - - private: - InstanceScript* instance; - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class npc_hodir_mage : public CreatureScript -{ - public: - npc_hodir_mage() : CreatureScript("npc_hodir_mage") { } - - struct npc_hodir_mageAI : public ScriptedAI - { - npc_hodir_mageAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - instance = me->GetInstanceScript(); - } - - void Reset() - { - events.Reset(); - summons.DespawnAll(); - events.ScheduleEvent(EVENT_CONJURE_FIRE, urand(10000, 12500)); - events.ScheduleEvent(EVENT_MELT_ICE, 5000); - } - - void JustSummoned(Creature* summoned) - { - if (summoned->GetEntry() == NPC_TOASTY_FIRE) - summons.Summon(summoned); - } - - void SummonedCreatureDespawn(Creature* summoned) - { - if (summoned->GetEntry() == NPC_TOASTY_FIRE) - summons.remove(summoned->GetGUID()); - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_CONJURE_FIRE: - if (summons.size() >= RAID_MODE(2, 4)) - break; - DoCast(me, SPELL_CONJURE_FIRE, true); - events.ScheduleEvent(EVENT_CONJURE_FIRE, urand(15000, 20000)); - break; - case EVENT_MELT_ICE: - if (Creature* FlashFreeze = me->FindNearestCreature(NPC_FLASH_FREEZE, 50.0f, true)) - DoCast(FlashFreeze, SPELL_MELT_ICE, true); - events.ScheduleEvent(EVENT_MELT_ICE, urand(10000, 15000)); - break; - } - } - - DoSpellAttackIfReady(SPELL_FIREBALL); - } - - void JustDied(Unit* /*who*/) - { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_HODIR) : 0)) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); - } - - private: - InstanceScript* instance; - EventMap events; - SummonList summons; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class npc_toasty_fire : public CreatureScript -{ - public: - npc_toasty_fire() : CreatureScript("npc_toasty_fire") { } - - struct npc_toasty_fireAI : public ScriptedAI - { - npc_toasty_fireAI(Creature* creature) : ScriptedAI(creature) - { - me->SetDisplayId(me->GetCreatureInfo()->Modelid2); - } - - void Reset() - { - DoCast(me, SPELL_SINGED, true); - } - - void SpellHit(Unit* /*who*/, const SpellInfo* spell) - { - if (spell->Id == SPELL_BLOCK_OF_ICE || spell->Id == SPELL_ICE_SHARD || spell->Id == SPELL_ICE_SHARD_HIT) - { - if (GameObject* ToastyFire = me->FindNearestGameObject(GO_TOASTY_FIRE, 1.0f)) - me->RemoveGameObject(ToastyFire, true); - me->DespawnOrUnsummon(); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - }; -}; - -class spell_biting_cold : public SpellScriptLoader -{ - public: - spell_biting_cold() : SpellScriptLoader("spell_biting_cold") { } - - class spell_biting_cold_AuraScript : public AuraScript - { - PrepareAuraScript(spell_biting_cold_AuraScript); - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - Unit* target = GetTarget(); - bool found = false; - - for (TargetList::iterator itr = listOfTargets.begin(); itr != listOfTargets.end(); ++itr) - { - if (itr->first != target->GetGUID()) - return; - - if (itr->second >= 4) - { - target->CastSpell(target, SPELL_BITING_COLD_TRIGGERED, true); - itr->second = 1; - } - else - { - if (target->isMoving()) - itr->second = 1; - else - itr->second++; - } - - found = true; - break; - } - - if (!found) - listOfTargets.push_back(std::make_pair(target->GetGUID(), 1)); - } - - void Register() - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_biting_cold_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - - private: - typedef std::list< std::pair > TargetList; - TargetList listOfTargets; - }; - - AuraScript* GetAuraScript() const - { - return new spell_biting_cold_AuraScript(); - } -}; - -class spell_biting_cold_dot : public SpellScriptLoader -{ -public: - spell_biting_cold_dot() : SpellScriptLoader("spell_biting_cold_dot") { } - - class spell_biting_cold_dot_AuraScript : public AuraScript - { - PrepareAuraScript(spell_biting_cold_dot_AuraScript); - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - Unit* caster = GetCaster(); - if (!caster) - return; - - int32 damage = int32(200 * pow(2.0f, GetStackAmount())); - caster->CastCustomSpell(caster, SPELL_BITING_COLD_DAMAGE, &damage, NULL, NULL, true); - - if (caster->isMoving()) - caster->RemoveAuraFromStack(SPELL_BITING_COLD_TRIGGERED); - } - - void Register() - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_biting_cold_dot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_biting_cold_dot_AuraScript(); - } -}; - -void AddSC_boss_hodir() -{ - new boss_hodir(); - new npc_icicle(); - new npc_snowpacked_icicle(); - new npc_hodir_priest(); - new npc_hodir_shaman(); - new npc_hodir_druid(); - new npc_hodir_mage(); - new npc_toasty_fire(); - new npc_ice_block(); - new npc_flash_freeze(); - new spell_biting_cold(); - new spell_biting_cold_dot(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp deleted file mode 100644 index b8876ae577a..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "SpellScript.h" -#include "SpellAuraEffects.h" -#include "ulduar.h" -#include "Vehicle.h" - -enum Yells -{ - SAY_AGGRO = -1603220, - SAY_SLAY_1 = -1603221, - SAY_SLAY_2 = -1603222, - SAY_DEATH = -1603223, - SAY_SUMMON = -1603224, - SAY_SLAG_POT = -1603225, - SAY_SCORCH_1 = -1603226, - SAY_SCORCH_2 = -1603227, - SAY_BERSERK = -1603228, - EMOTE_JETS = -1603229, -}; - -enum Spells -{ - SPELL_FLAME_JETS = 62680, - SPELL_SCORCH = 62546, - SPELL_SLAG_POT = 62717, - SPELL_SLAG_POT_DAMAGE = 65722, - SPELL_SLAG_IMBUED = 62836, - SPELL_ACTIVATE_CONSTRUCT = 62488, - SPELL_STRENGHT = 64473, - SPELL_GRAB = 62707, - SPELL_BERSERK = 47008, - - // Iron Construct - SPELL_HEAT = 65667, - SPELL_MOLTEN = 62373, - SPELL_BRITTLE = 62382, - SPELL_SHATTER = 62383, - SPELL_GROUND = 62548, -}; - -enum Events -{ - EVENT_JET = 1, - EVENT_SCORCH = 2, - EVENT_SLAG_POT = 3, - EVENT_GRAB_POT = 4, - EVENT_CHANGE_POT = 5, - EVENT_END_POT = 6, - EVENT_CONSTRUCT = 7, - EVENT_BERSERK = 8, -}; - -enum Actions -{ - ACTION_REMOVE_BUFF = 20, -}; - -enum Creatures -{ - NPC_IRON_CONSTRUCT = 33121, - NPC_GROUND_SCORCH = 33221, -}; - -enum AchievementData -{ - DATA_SHATTERED = 29252926, - ACHIEVEMENT_IGNIS_START_EVENT = 20951, -}; - -#define CONSTRUCT_SPAWN_POINTS 20 - -Position const ConstructSpawnPosition[CONSTRUCT_SPAWN_POINTS] = -{ - {630.366f, 216.772f, 360.891f, 3.001970f}, - {630.594f, 231.846f, 360.891f, 3.124140f}, - {630.435f, 337.246f, 360.886f, 3.211410f}, - {630.493f, 313.349f, 360.886f, 3.054330f}, - {630.444f, 321.406f, 360.886f, 3.124140f}, - {630.366f, 247.307f, 360.888f, 3.211410f}, - {630.698f, 305.311f, 360.886f, 3.001970f}, - {630.500f, 224.559f, 360.891f, 3.054330f}, - {630.668f, 239.840f, 360.890f, 3.159050f}, - {630.384f, 329.585f, 360.886f, 3.159050f}, - {543.220f, 313.451f, 360.886f, 0.104720f}, - {543.356f, 329.408f, 360.886f, 6.248280f}, - {543.076f, 247.458f, 360.888f, 6.213370f}, - {543.117f, 232.082f, 360.891f, 0.069813f}, - {543.161f, 305.956f, 360.886f, 0.157080f}, - {543.277f, 321.482f, 360.886f, 0.052360f}, - {543.316f, 337.468f, 360.886f, 6.195920f}, - {543.280f, 239.674f, 360.890f, 6.265730f}, - {543.265f, 217.147f, 360.891f, 0.174533f}, - {543.256f, 224.831f, 360.891f, 0.122173f}, -}; - -class boss_ignis : public CreatureScript -{ - public: - boss_ignis() : CreatureScript("boss_ignis") { } - - struct boss_ignis_AI : public BossAI - { - boss_ignis_AI(Creature* creature) : BossAI(creature, BOSS_IGNIS), _vehicle(me->GetVehicleKit()) - { - ASSERT(_vehicle); - } - - void Reset() - { - _Reset(); - if (_vehicle) - _vehicle->RemoveAllPassengers(); - - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - DoScriptText(SAY_AGGRO, me); - events.ScheduleEvent(EVENT_JET, 30000); - events.ScheduleEvent(EVENT_SCORCH, 25000); - events.ScheduleEvent(EVENT_SLAG_POT, 35000); - events.ScheduleEvent(EVENT_CONSTRUCT, 15000); - events.ScheduleEvent(EVENT_END_POT, 40000); - events.ScheduleEvent(EVENT_BERSERK, 480000); - _slagPotGUID = 0; - _shattered = false; - _firstConstructKill = 0; - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); - } - - void JustDied(Unit* /*victim*/) - { - _JustDied(); - DoScriptText(SAY_DEATH, me); - } - - uint32 GetData(uint32 type) - { - if (type == DATA_SHATTERED) - return _shattered ? 1 : 0; - - return 0; - } - - void KilledUnit(Unit* /*victim*/) - { - if (!urand(0, 4)) - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void JustSummoned(Creature* summon) - { - if (summon->GetEntry() == NPC_IRON_CONSTRUCT) - { - summon->setFaction(16); - summon->SetReactState(REACT_AGGRESSIVE); - summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_DISABLE_MOVE); - } - - summon->AI()->AttackStart(me->getVictim()); - summon->AI()->DoZoneInCombat(); - summons.Summon(summon); - } - - void DoAction(const int32 action) - { - if (action != ACTION_REMOVE_BUFF) - return; - - me->RemoveAuraFromStack(SPELL_STRENGHT); - // Shattered Achievement - time_t secondKill = sWorld->GetGameTime(); - if ((secondKill - _firstConstructKill) < 5) - _shattered = true; - _firstConstructKill = secondKill; - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_JET: - me->MonsterTextEmote(EMOTE_JETS, 0, true); - DoCast(me, SPELL_FLAME_JETS); - events.ScheduleEvent(EVENT_JET, urand(35000, 40000)); - break; - case EVENT_SLAG_POT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - { - DoScriptText(SAY_SLAG_POT, me); - _slagPotGUID = target->GetGUID(); - DoCast(target, SPELL_GRAB); - events.DelayEvents(3000); - events.ScheduleEvent(EVENT_GRAB_POT, 500); - } - events.ScheduleEvent(EVENT_SLAG_POT, RAID_MODE(30000, 15000)); - break; - case EVENT_GRAB_POT: - if (Unit* slagPotTarget = ObjectAccessor::GetUnit(*me, _slagPotGUID)) - { - slagPotTarget->EnterVehicle(me, 0); - events.CancelEvent(EVENT_GRAB_POT); - events.ScheduleEvent(EVENT_CHANGE_POT, 1000); - } - break; - case EVENT_CHANGE_POT: - if (Unit* slagPotTarget = ObjectAccessor::GetUnit(*me, _slagPotGUID)) - { - slagPotTarget->AddAura(SPELL_SLAG_POT, slagPotTarget); - slagPotTarget->EnterVehicle(me, 1); - events.CancelEvent(EVENT_CHANGE_POT); - events.ScheduleEvent(EVENT_END_POT, 10000); - } - break; - case EVENT_END_POT: - if (Unit* slagPotTarget = ObjectAccessor::GetUnit(*me, _slagPotGUID)) - { - slagPotTarget->ExitVehicle(); - slagPotTarget = NULL; - _slagPotGUID = 0; - events.CancelEvent(EVENT_END_POT); - } - break; - case EVENT_SCORCH: - DoScriptText(RAND(SAY_SCORCH_1, SAY_SCORCH_2), me); - if (Unit* target = me->getVictim()) - me->SummonCreature(NPC_GROUND_SCORCH, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 45000); - DoCast(SPELL_SCORCH); - events.ScheduleEvent(EVENT_SCORCH, 25000); - break; - case EVENT_CONSTRUCT: - DoScriptText(SAY_SUMMON, me); - DoSummon(NPC_IRON_CONSTRUCT, ConstructSpawnPosition[urand(0, CONSTRUCT_SPAWN_POINTS - 1)], 30000, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT); - DoCast(SPELL_STRENGHT); - DoCast(me, SPELL_ACTIVATE_CONSTRUCT); - events.ScheduleEvent(EVENT_CONSTRUCT, RAID_MODE(40000, 30000)); - break; - case EVENT_BERSERK: - DoCast(me, SPELL_BERSERK, true); - DoScriptText(SAY_BERSERK, me); - break; - } - } - - DoMeleeAttackIfReady(); - - EnterEvadeIfOutOfCombatArea(diff); - } - - private: - uint64 _slagPotGUID; - Vehicle* _vehicle; - time_t _firstConstructKill; - bool _shattered; - - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class npc_iron_construct : public CreatureScript -{ - public: - npc_iron_construct() : CreatureScript("npc_iron_construct") { } - - struct npc_iron_constructAI : public ScriptedAI - { - npc_iron_constructAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) - { - creature->SetReactState(REACT_PASSIVE); - } - - void Reset() - { - _brittled = false; - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) - { - if (me->HasAura(SPELL_BRITTLE) && damage >= 5000) - { - DoCast(SPELL_SHATTER); - if (Creature* ignis = ObjectAccessor::GetCreature(*me, _instance->GetData64(BOSS_IGNIS))) - if (ignis->AI()) - ignis->AI()->DoAction(ACTION_REMOVE_BUFF); - - me->DespawnOrUnsummon(1000); - } - } - - void UpdateAI(const uint32 /*uiDiff*/) - { - if (!UpdateVictim()) - return; - - if (Aura* aur = me->GetAura(SPELL_HEAT)) - { - if (aur->GetStackAmount() >= 10) - { - me->RemoveAura(SPELL_HEAT); - DoCast(SPELL_MOLTEN); - _brittled = false; - } - } - - // Water pools - if (me->IsInWater() && !_brittled && me->HasAura(SPELL_MOLTEN)) - { - DoCast(SPELL_BRITTLE); - me->RemoveAura(SPELL_MOLTEN); - _brittled = true; - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - bool _brittled; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class npc_scorch_ground : public CreatureScript -{ - public: - npc_scorch_ground() : CreatureScript("npc_scorch_ground") { } - - struct npc_scorch_groundAI : public ScriptedAI - { - npc_scorch_groundAI(Creature* creature) : ScriptedAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE |UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); - creature->SetDisplayId(16925); //model 2 in db cannot overwrite wdb fields - } - - void MoveInLineOfSight(Unit* unit) - { - if (!_heat) - { - if (unit->GetEntry() == NPC_IRON_CONSTRUCT) - { - if (!unit->HasAura(SPELL_HEAT) || !unit->HasAura(SPELL_MOLTEN)) - { - _constructGUID = unit->GetGUID(); - _heat = true; - } - } - } - } - - void Reset() - { - _heat = false; - DoCast(me, SPELL_GROUND); - _constructGUID = 0; - _heatTimer = 0; - } - - void UpdateAI(const uint32 uiDiff) - { - if (_heat) - { - if (_heatTimer <= uiDiff) - { - Creature* construct = me->GetCreature(*me, _constructGUID); - if (construct && !construct->HasAura(SPELL_MOLTEN)) - { - me->AddAura(SPELL_HEAT, construct); - _heatTimer = 1000; - } - } - else - _heatTimer -= uiDiff; - } - } - - private: - uint64 _constructGUID; - uint32 _heatTimer; - bool _heat; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class spell_ignis_slag_pot : public SpellScriptLoader -{ - public: - spell_ignis_slag_pot() : SpellScriptLoader("spell_ignis_slag_pot") { } - - class spell_ignis_slag_pot_AuraScript : public AuraScript - { - PrepareAuraScript(spell_ignis_slag_pot_AuraScript); - - bool Validate(SpellInfo const* /*spellEntry*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_SLAG_POT_DAMAGE)) - return false; - if (!sSpellMgr->GetSpellInfo(SPELL_SLAG_IMBUED)) - return false; - return true; - } - - void HandleEffectPeriodic(AuraEffect const* aurEff) - { - Unit* aurEffCaster = aurEff->GetCaster(); - if (!aurEffCaster) - return; - - Unit* target = GetTarget(); - aurEffCaster->CastSpell(target, SPELL_SLAG_POT_DAMAGE, true); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (GetTarget()->isAlive()) - GetTarget()->CastSpell(GetTarget(), SPELL_SLAG_IMBUED, true); - } - - void Register() - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_slag_pot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - AfterEffectRemove += AuraEffectRemoveFn(spell_ignis_slag_pot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_ignis_slag_pot_AuraScript(); - } -}; - -class achievement_ignis_shattered : public AchievementCriteriaScript -{ - public: - achievement_ignis_shattered() : AchievementCriteriaScript("achievement_ignis_shattered") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (target && target->IsAIEnabled) - return target->GetAI()->GetData(DATA_SHATTERED); - - return false; - } -}; - -void AddSC_boss_ignis() -{ - new boss_ignis(); - new npc_iron_construct(); - new npc_scorch_ground(); - new spell_ignis_slag_pot(); - new achievement_ignis_shattered(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp deleted file mode 100644 index 5da1c485986..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp +++ /dev/null @@ -1,658 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "SpellScript.h" -#include "SpellAuraEffects.h" -#include "ulduar.h" -#include "Vehicle.h" - -/* ScriptData -SDName: boss_kologarn -SD%Complete: 90 -SDComment: TODO: Achievements -SDCategory: Ulduar -EndScriptData */ - -#define SPELL_ARM_DEAD_DAMAGE RAID_MODE(63629, 63979) -#define SPELL_TWO_ARM_SMASH RAID_MODE(63356, 64003) -#define SPELL_ONE_ARM_SMASH RAID_MODE(63573, 64006) -#define SPELL_ARM_SWEEP RAID_MODE(63766, 63983) -#define SPELL_STONE_SHOUT RAID_MODE(63716, 64005) -#define SPELL_PETRIFY_BREATH RAID_MODE(62030, 63980) -#define SPELL_STONE_GRIP RAID_MODE(62166, 63981) -#define SPELL_STONE_GRIP_CANCEL 65594 -#define SPELL_SUMMON_RUBBLE 63633 -#define SPELL_FALLING_RUBBLE 63821 -#define SPELL_ARM_ENTER_VEHICLE 65343 -#define SPELL_ARM_ENTER_VISUAL 64753 - -#define SPELL_SUMMON_FOCUSED_EYEBEAM 63342 -#define SPELL_FOCUSED_EYEBEAM_PERIODIC RAID_MODE(63347, 63977) -#define SPELL_FOCUSED_EYEBEAM_VISUAL 63369 -#define SPELL_FOCUSED_EYEBEAM_VISUAL_LEFT 63676 -#define SPELL_FOCUSED_EYEBEAM_VISUAL_RIGHT 63702 - -// Passive -#define SPELL_KOLOGARN_REDUCE_PARRY 64651 -#define SPELL_KOLOGARN_PACIFY 63726 -#define SPELL_KOLOGARN_UNK_0 65219 // Not found in DBC - -#define SPELL_BERSERK 47008 // guess - -#define NPC_RUBBLE_STALKER 33809 -#define NPC_ARM_SWEEP_STALKER 33661 - -enum Events -{ - EVENT_NONE = 0, - EVENT_INSTALL_ACCESSORIES, - EVENT_MELEE_CHECK, - EVENT_SMASH, - EVENT_SWEEP, - EVENT_STONE_SHOUT, - EVENT_STONE_GRIP, - EVENT_FOCUSED_EYEBEAM, - EVENT_RESPAWN_LEFT_ARM, - EVENT_RESPAWN_RIGHT_ARM, - EVENT_ENRAGE, -}; - -enum Yells -{ - SAY_AGGRO = -1603230, - SAY_SLAY_1 = -1603231, - SAY_SLAY_2 = -1603232, - SAY_LEFT_ARM_GONE = -1603233, - SAY_RIGHT_ARM_GONE = -1603234, - SAY_SHOCKWAVE = -1603235, - SAY_GRAB_PLAYER = -1603236, - SAY_DEATH = -1603237, - SAY_BERSERK = -1603238, -}; - -class boss_kologarn : public CreatureScript -{ - public: - boss_kologarn() : CreatureScript("boss_kologarn") { } - - struct boss_kologarnAI : public BossAI - { - boss_kologarnAI(Creature* creature) : BossAI(creature, BOSS_KOLOGARN), vehicle(creature->GetVehicleKit()), - left(false), right(false) - { - ASSERT(vehicle); - - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); - - DoCast(SPELL_KOLOGARN_REDUCE_PARRY); - SetCombatMovement(false); - Reset(); - } - - Vehicle* vehicle; - bool left, right; - uint64 eyebeamTarget; - - void EnterCombat(Unit* /*who*/) - { - DoScriptText(SAY_AGGRO, me); - - events.ScheduleEvent(EVENT_MELEE_CHECK, 6000); - events.ScheduleEvent(EVENT_SMASH, 5000); - events.ScheduleEvent(EVENT_SWEEP, 19000); - events.ScheduleEvent(EVENT_STONE_GRIP, 25000); - events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 21000); - events.ScheduleEvent(EVENT_ENRAGE, 600000); - - for (uint8 i = 0; i < 2; ++i) - if (Unit* arm = vehicle->GetPassenger(i)) - arm->ToCreature()->SetInCombatWithZone(); - - _EnterCombat(); - } - - void Reset() - { - _Reset(); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - eyebeamTarget = 0; - } - - void JustDied(Unit* /*victim*/) - { - DoScriptText(SAY_DEATH, me); - DoCast(SPELL_KOLOGARN_PACIFY); - me->GetMotionMaster()->MoveTargetedHome(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetCorpseDelay(604800); // Prevent corpse from despawning. - _JustDied(); - } - - void KilledUnit(Unit* /*who*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) - { - bool isEncounterInProgress = instance->GetBossState(BOSS_KOLOGARN) == IN_PROGRESS; - if (who->GetEntry() == NPC_LEFT_ARM) - { - left = apply; - if (!apply && isEncounterInProgress) - { - who->ToCreature()->DisappearAndDie(); - DoScriptText(SAY_LEFT_ARM_GONE, me); - events.ScheduleEvent(EVENT_RESPAWN_LEFT_ARM, 40000); - } - } - - else if (who->GetEntry() == NPC_RIGHT_ARM) - { - right = apply; - if (!apply && isEncounterInProgress) - { - who->ToCreature()->DisappearAndDie(); - DoScriptText(SAY_RIGHT_ARM_GONE, me); - events.ScheduleEvent(EVENT_RESPAWN_RIGHT_ARM, 40000); - } - } - - if (!isEncounterInProgress) - return; - - if (!apply) - { - who->CastSpell(me, SPELL_ARM_DEAD_DAMAGE, true); - - if (Creature* rubbleStalker = who->FindNearestCreature(NPC_RUBBLE_STALKER, 70.0f)) - { - if (rubbleStalker) - { - rubbleStalker->CastSpell(rubbleStalker, SPELL_FALLING_RUBBLE, true); - rubbleStalker->CastSpell(rubbleStalker, SPELL_SUMMON_RUBBLE, true); - } - } - - if (!right && !left) - events.ScheduleEvent(EVENT_STONE_SHOUT, 5000); - - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_DISARMED); - } - else - { - events.CancelEvent(EVENT_STONE_SHOUT); - who->ToCreature()->SetInCombatWithZone(); - } - } - - void JustSummoned(Creature* summon) - { - switch (summon->GetEntry()) - { - case NPC_FOCUSED_EYEBEAM: - summon->CastSpell(me, SPELL_FOCUSED_EYEBEAM_VISUAL_LEFT, true); - break; - case NPC_FOCUSED_EYEBEAM_RIGHT: - summon->CastSpell(me, SPELL_FOCUSED_EYEBEAM_VISUAL_RIGHT, true); - break; - case NPC_RUBBLE: - summons.push_back(summon->GetGUID()); - // absence of break intended - default: - return; - } - - summon->CastSpell(summon, SPELL_FOCUSED_EYEBEAM_PERIODIC, true); - summon->CastSpell(summon, SPELL_FOCUSED_EYEBEAM_VISUAL, true); - summon->SetReactState(REACT_PASSIVE); - // One of the above spells is a channeled spell, we need to clear this unit state for MoveChase to work - summon->ClearUnitState(UNIT_STAT_CASTING); - - // Victim gets 67351 - if (eyebeamTarget) - { - if (Unit* target = Unit::GetUnit(*summon, eyebeamTarget)) - { - summon->Attack(target, false); - summon->GetMotionMaster()->MoveChase(target); - } - } - } - - void UpdateAI(uint32 const diff) - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_MELEE_CHECK: - if (!me->IsWithinMeleeRange(me->getVictim())) - DoCast(SPELL_PETRIFY_BREATH); - events.ScheduleEvent(EVENT_MELEE_CHECK, 1 * IN_MILLISECONDS); - break; - case EVENT_SWEEP: - if (left) - DoCast(me->FindNearestCreature(NPC_ARM_SWEEP_STALKER, 500.0f, true), SPELL_ARM_SWEEP, true); - events.ScheduleEvent(EVENT_SWEEP, 25 * IN_MILLISECONDS); - break; - case EVENT_SMASH: - if (left && right) - DoCastVictim(SPELL_TWO_ARM_SMASH); - else if (left || right) - DoCastVictim(SPELL_ONE_ARM_SMASH); - events.ScheduleEvent(EVENT_SMASH, 15 * IN_MILLISECONDS); - break; - case EVENT_STONE_SHOUT: - DoCast(SPELL_STONE_SHOUT); - events.ScheduleEvent(EVENT_STONE_SHOUT, 2 * IN_MILLISECONDS); - break; - case EVENT_ENRAGE: - DoCast(SPELL_BERSERK); - DoScriptText(SAY_BERSERK, me); - break; - case EVENT_RESPAWN_LEFT_ARM: - case EVENT_RESPAWN_RIGHT_ARM: - { - if (vehicle) - { - int8 seat = eventId == EVENT_RESPAWN_LEFT_ARM ? 0 : 1; - uint32 entry = eventId == EVENT_RESPAWN_LEFT_ARM ? NPC_LEFT_ARM : NPC_RIGHT_ARM; - vehicle->InstallAccessory(entry, seat, true, TEMPSUMMON_MANUAL_DESPAWN, 0); - } - break; - } - case EVENT_STONE_GRIP: - { - if (right) - { - DoCast(SPELL_STONE_GRIP); - DoScriptText(SAY_GRAB_PLAYER, me); - } - events.ScheduleEvent(EVENT_STONE_GRIP, 25 * IN_MILLISECONDS); - } - break; - case EVENT_FOCUSED_EYEBEAM: - if (Unit* eyebeamTargetUnit = SelectTarget(SELECT_TARGET_FARTHEST, 0, 0, true)) - { - eyebeamTarget = eyebeamTargetUnit->GetGUID(); - DoCast(me, SPELL_SUMMON_FOCUSED_EYEBEAM, true); - } - events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, urand(15, 35) * IN_MILLISECONDS); - break; - } - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class spell_ulduar_rubble_summon : public SpellScriptLoader -{ - public: - spell_ulduar_rubble_summon() : SpellScriptLoader("spell_ulduar_rubble_summon") { } - - class spell_ulduar_rubble_summonSpellScript : public SpellScript - { - PrepareSpellScript(spell_ulduar_rubble_summonSpellScript); - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - if (!caster) - return; - - uint64 originalCaster = caster->GetInstanceScript() ? caster->GetInstanceScript()->GetData64(BOSS_KOLOGARN) : 0; - uint32 spellId = GetEffectValue(); - for (uint8 i = 0; i < 5; ++i) - caster->CastSpell(caster, spellId, true, NULL, NULL, originalCaster); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_ulduar_rubble_summonSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_ulduar_rubble_summonSpellScript(); - } -}; - -// predicate function to select non main tank target -class StoneGripTargetSelector : public std::unary_function -{ - public: - StoneGripTargetSelector(Creature* me, Unit const* victim) : _me(me), _victim(victim) {} - - bool operator() (Unit* target) - { - if (target == _victim && _me->getThreatManager().getThreatList().size() > 1) - return true; - - if (target->GetTypeId() != TYPEID_PLAYER) - return true; - - return false; - } - - Creature* _me; - Unit const* _victim; -}; - -class spell_ulduar_stone_grip_cast_target : public SpellScriptLoader -{ - public: - spell_ulduar_stone_grip_cast_target() : SpellScriptLoader("spell_ulduar_stone_grip_cast_target") { } - - class spell_ulduar_stone_grip_cast_target_SpellScript : public SpellScript - { - PrepareSpellScript(spell_ulduar_stone_grip_cast_target_SpellScript); - - bool Load() - { - if (GetCaster()->GetTypeId() != TYPEID_UNIT) - return false; - return true; - } - - void FilterTargetsInitial(std::list& unitList) - { - // Remove "main tank" and non-player targets - unitList.remove_if (StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->getVictim())); - // Maximum affected targets per difficulty mode - uint32 maxTargets = 1; - if (GetSpellInfo()->Id == 63981) - maxTargets = 3; - - // Return a random amount of targets based on maxTargets - while (maxTargets < unitList.size()) - { - std::list::iterator itr = unitList.begin(); - advance(itr, urand(0, unitList.size()-1)); - unitList.erase(itr); - } - - // For subsequent effects - m_unitList = unitList; - } - - void FillTargetsSubsequential(std::list& unitList) - { - unitList = m_unitList; - } - - void Register() - { - OnUnitTargetSelect += SpellUnitTargetFn(spell_ulduar_stone_grip_cast_target_SpellScript::FilterTargetsInitial, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnUnitTargetSelect += SpellUnitTargetFn(spell_ulduar_stone_grip_cast_target_SpellScript::FillTargetsSubsequential, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); - OnUnitTargetSelect += SpellUnitTargetFn(spell_ulduar_stone_grip_cast_target_SpellScript::FillTargetsSubsequential, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY); - } - - // Shared between effects - std::list m_unitList; - }; - - SpellScript* GetSpellScript() const - { - return new spell_ulduar_stone_grip_cast_target_SpellScript(); - } -}; - -class spell_ulduar_cancel_stone_grip : public SpellScriptLoader -{ - public: - spell_ulduar_cancel_stone_grip() : SpellScriptLoader("spell_ulduar_cancel_stone_grip") { } - - class spell_ulduar_cancel_stone_gripSpellScript : public SpellScript - { - PrepareSpellScript(spell_ulduar_cancel_stone_gripSpellScript); - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* target = GetHitUnit(); - if (!target || !target->GetVehicle()) - return; - - switch (target->GetMap()->GetDifficulty()) - { - case RAID_DIFFICULTY_10MAN_NORMAL: - target->RemoveAura(GetSpellInfo()->Effects[EFFECT_0].CalcValue()); - break; - case RAID_DIFFICULTY_25MAN_NORMAL: - target->RemoveAura(GetSpellInfo()->Effects[EFFECT_1].CalcValue()); - break; - default: - break; - } - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_ulduar_cancel_stone_gripSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_ulduar_cancel_stone_gripSpellScript(); - } -}; - -class spell_ulduar_squeezed_lifeless : public SpellScriptLoader -{ - public: - spell_ulduar_squeezed_lifeless() : SpellScriptLoader("spell_ulduar_squeezed_lifeless") { } - - class spell_ulduar_squeezed_lifeless_SpellScript : public SpellScript - { - PrepareSpellScript(spell_ulduar_squeezed_lifeless_SpellScript); - - void HandleInstaKill(SpellEffIndex /*effIndex*/) - { - if (!GetHitPlayer() || !GetHitPlayer()->GetVehicle()) - return; - - Position pos; - pos.m_positionX = 1756.25f + irand(-3, 3); - pos.m_positionY = -8.3f + irand(-3, 3); - pos.m_positionZ = 448.8f; - pos.m_orientation = M_PI; - GetHitPlayer()->DestroyForNearbyPlayers(); - GetHitPlayer()->ExitVehicle(&pos); - GetHitPlayer()->UpdateObjectVisibility(false); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_ulduar_squeezed_lifeless_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_ulduar_squeezed_lifeless_SpellScript(); - } -}; - -class spell_ulduar_stone_grip_absorb : public SpellScriptLoader -{ - public: - spell_ulduar_stone_grip_absorb() : SpellScriptLoader("spell_ulduar_stone_grip_absorb") { } - - class spell_ulduar_stone_grip_absorb_AuraScript : public AuraScript - { - PrepareAuraScript(spell_ulduar_stone_grip_absorb_AuraScript); - - //! This will be called when Right Arm (vehicle) has sustained a specific amount of damage depending on instance mode - //! What we do here is remove all harmful aura's related and teleport to safe spot. - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL) - return; - - if (!GetOwner()->ToCreature()) - return; - - uint32 rubbleStalkerEntry = (GetOwner()->GetMap()->GetDifficulty() == DUNGEON_DIFFICULTY_NORMAL ? 33809 : 33942); - Creature* rubbleStalker = GetOwner()->FindNearestCreature(rubbleStalkerEntry, 200.0f, true); - if (rubbleStalker) - rubbleStalker->CastSpell(rubbleStalker, SPELL_STONE_GRIP_CANCEL, true); - } - - void Register() - { - AfterEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_absorb_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_ulduar_stone_grip_absorb_AuraScript(); - } -}; - -class spell_ulduar_stone_grip : public SpellScriptLoader -{ - public: - spell_ulduar_stone_grip() : SpellScriptLoader("spell_ulduar_stone_grip") { } - - class spell_ulduar_stone_grip_AuraScript : public AuraScript - { - PrepareAuraScript(spell_ulduar_stone_grip_AuraScript); - - void OnRemoveStun(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (Player* owner = GetOwner()->ToPlayer()) - owner->RemoveAurasDueToSpell(aurEff->GetAmount()); - } - - void OnRemoveVehicle(AuraEffect const* /*aurEff*/, AuraEffectHandleModes mode) - { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - return; - - if (GetOwner()->GetTypeId() != TYPEID_UNIT) - return; - - Player* caster = GetCaster() ? GetCaster()->ToPlayer() : NULL; - if (!caster || !caster->IsOnVehicle(GetOwner()->ToUnit())) - return; - - caster->RemoveAurasDueToSpell(GetId()); - caster->ExitVehicle(); - caster->GetMotionMaster()->MoveJump(1756.25f + irand(-3, 3), -8.3f + irand(-3, 3), 448.8f, 5.0f, 5.0f); - PreventDefaultAction(); - } - - void Register() - { - OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveVehicle, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveStun, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_ulduar_stone_grip_AuraScript(); - } -}; - -class spell_kologarn_stone_shout : public SpellScriptLoader -{ - public: - spell_kologarn_stone_shout() : SpellScriptLoader("spell_kologarn_stone_shout") { } - - class spell_kologarn_stone_shout_SpellScript : public SpellScript - { - PrepareSpellScript(spell_kologarn_stone_shout_SpellScript); - - void FilterTargets(std::list& unitList) - { - unitList.remove_if (PlayerOrPetCheck()); - } - - void Register() - { - OnUnitTargetSelect += SpellUnitTargetFn(spell_kologarn_stone_shout_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_kologarn_stone_shout_SpellScript(); - } -}; - -class spell_kologarn_summon_focused_eyebeam : public SpellScriptLoader -{ - public: - spell_kologarn_summon_focused_eyebeam() : SpellScriptLoader("spell_kologarn_summon_focused_eyebeam") { } - - class spell_kologarn_summon_focused_eyebeam_SpellScript : public SpellScript - { - PrepareSpellScript(spell_kologarn_summon_focused_eyebeam_SpellScript); - - void HandleForceCast(SpellEffIndex eff) - { - PreventHitDefaultEffect(eff); - GetCaster()->CastSpell(GetCaster(), GetSpellInfo()->Effects[eff].TriggerSpell, true); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_kologarn_summon_focused_eyebeam_SpellScript::HandleForceCast, EFFECT_0, SPELL_EFFECT_FORCE_CAST); - OnEffectHitTarget += SpellEffectFn(spell_kologarn_summon_focused_eyebeam_SpellScript::HandleForceCast, EFFECT_1, SPELL_EFFECT_FORCE_CAST); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_kologarn_summon_focused_eyebeam_SpellScript(); - } -}; - -void AddSC_boss_kologarn() -{ - new boss_kologarn(); - new spell_ulduar_rubble_summon(); - new spell_ulduar_squeezed_lifeless(); - new spell_ulduar_cancel_stone_grip(); - new spell_ulduar_stone_grip_cast_target(); - new spell_ulduar_stone_grip_absorb(); - new spell_ulduar_stone_grip(); - new spell_kologarn_stone_shout(); - new spell_kologarn_summon_focused_eyebeam(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_mimiron.cpp deleted file mode 100644 index 11b7c54975e..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_mimiron.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "SpellScript.h" -#include "ulduar.h" - -enum Yells -{ - SAY_AGGRO = -1603240, - SAY_HARDMODE_ON = -1603241, - SAY_MKII_ACTIVATE = -1603242, - SAY_MKII_SLAY_1 = -1603243, - SAY_MKII_SLAY_2 = -1603244, - SAY_MKII_DEATH = -1603245, - SAY_VX001_ACTIVATE = -1603246, - SAY_VX001_SLAY_1 = -1603247, - SAY_VX001_SLAY_2 = -1603248, - SAY_VX001_DEATH = -1603249, - SAY_AERIAL_ACTIVATE = -1603250, - SAY_AERIAL_SLAY_1 = -1603251, - SAY_AERIAL_SLAY_2 = -1603252, - SAY_AERIAL_DEATH = -1603253, - SAY_V07TRON_ACTIVATE = -1603254, - SAY_V07TRON_SLAY_1 = -1603255, - SAY_V07TRON_SLAY_2 = -1603256, - SAY_V07TRON_DEATH = -1603257, - SAY_BERSERK = -1603258, - SAY_YS_HELP = -1603259, -}; - -enum Spells -{ - SPELL_JETPACK = 63341, - SPELL_EMERGENCY_MODE = 64582, - SPELL_SELF_REPAIR = 64383, - SPELL_MAGNETIC_CORE = 64444, - // Leviathan MK II - SPELL_FLAME_SUPPRESSANT_MK = 64570, - SPELL_NAPALM_SHELL = 63666, - SPELL_PLASMA_BLAST = 62977, - SPELL_PROXIMITY_MINES = 63027, - SPELL_SHOCK_BLAST = 63631, - // VX 001 - SPELL_FLAME_SUPPRESSANT_VX = 65192, - SPELL_FROSTBOMB = 64623, - SPELL_HAND_PULSE = 64348, - SPELL_SPINNING_UP = 63414, - SPELL_RAPID_BURST = 63387, - SPELL_P3WX2_LASER_BARRAGE = 63293, - SPELL_ROCKET_STRIKE = 63041, - SPELL_HEAT_WAVE = 63677, - // Aerial Command Unit - SPELL_PLASMA_BALL = 63689, - // Additonal spells - SPELL_MAGNETIC_FIELD = 64668, - SPELL_DEAFENING_SIREN = 64616, - SPELL_WATER_SPRAY = 64619, - SPELL_FROST_BOMB_HARD_MODE = 64627, - SPELL_EXPLOSION = 66351, - SPELL_DISARM = 1842, - SPELL_RIDE_VEHICLE = 46598, - SPELL_TRIGGER_MISSILE = 65347, -}; - -enum Npc -{ - NPC_ASSAULT_BOT = 34057, - NPC_BOMB_BOT = 33836, - NPC_JUNK_BOT = 33855, - NPC_EMERGENCE_FIRE_BOT = 34147, - NPC_FROST_BOMB = 34149, -}; - -class spell_ulduar_proximity_mines : public SpellScriptLoader -{ - public: - spell_ulduar_proximity_mines() : SpellScriptLoader("spell_ulduar_proximity_mines") { } - - class spell_ulduar_proximity_minesSpellScript : public SpellScript - { - PrepareSpellScript(spell_ulduar_proximity_minesSpellScript) - - void HandleScript(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - for (uint8 i = 0; i < 10; ++i) - GetCaster()->CastSpell(GetCaster(), SPELL_TRIGGER_MISSILE, true); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_ulduar_proximity_minesSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_ulduar_proximity_minesSpellScript(); - } -}; - -void AddSC_boss_mimiron() -{ - new spell_ulduar_proximity_mines(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp deleted file mode 100644 index 0e3a8926203..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp +++ /dev/null @@ -1,1103 +0,0 @@ -/* -* Copyright (C) 2008-2011 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 . -*/ - -//TODO: Harpoon chain from 62505 should not get removed when other chain is applied - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "ScriptedGossip.h" -#include "SpellScript.h" -#include "ulduar.h" -#include "SpellInfo.h" - -enum Says -{ - SAY_GREET = -1603260, - SAY_GROUND_PHASE = -1603261, - SAY_AGGRO_1 = -1603262, - SAY_AGGRO_2 = -1603263, - SAY_AGGRO_3 = -1603264, - SAY_TURRETS = -1603265, - EMOTE_HARPOON = -1603266, - EMOTE_BREATH = -1603267, - EMOTE_PERMA = -1603268, -}; - -enum Spells -{ - SPELL_FLAMEBUFFET = 64016, - SPELL_FIREBALL = 62796, - SPELL_FLAME_GROUND = 64734, - SPELL_WINGBUFFET = 62666, - SPELL_FLAMEBREATH = 63317, - SPELL_FUSEARMOR = 64771, - SPELL_FLAMED = 62696, - SPELL_STUN = 9032, - SPELL_BERSERK = 47008, - // Additonal Spells - // Devouring Flame Spells - SPELL_DEVOURING_FLAME = 63308, - SPELL_DEVOURING_FLAME_DAMAGE = 64704, - SPELL_DEVOURING_FLAME_TRIGGER = 64709, - // HarpoonSpells - SPELL_HARPOON_TRIGGER = 62505, - SPELL_HARPOON_SHOT_1 = 63658, - SPELL_HARPOON_SHOT_2 = 63657, - SPELL_HARPOON_SHOT_3 = 63659, - SPELL_HARPOON_SHOT_4 = 63524, - // MoleMachine Spells - SPELL_SUMMON_MOLE_MACHINE = 62899, - SPELL_SUMMON_IRON_DWARVES = 63116, - SPELL_SUMMON_IRON_DWARVES_2 = 63114, - SPELL_SUMMON_IRON_DWARVE_GUARDIAN = 62926, - SPELL_SUMMON_IRON_DWARVE_WATCHER = 63135, -}; - -enum NPC -{ - NPC_DARK_RUNE_GUARDIAN = 33388, - NPC_DARK_RUNE_SENTINEL = 33846, - NPC_DARK_RUNE_WATCHER = 33453, - MOLE_MACHINE_TRIGGER = 33245, - NPC_COMMANDER = 33210, - NPC_ENGINEER = 33287, - NPC_DEFENDER = 33816, -}; - -enum DarkRuneSpells -{ - // Dark Rune Watcher - SPELL_CHAIN_LIGHTNING = 64758, - SPELL_LIGHTNING_BOLT = 63809, - // Dark Rune Guardian - SPELL_STORMSTRIKE = 64757, - // Dark Rune Sentinel - SPELL_BATTLE_SHOUT = 46763, - SPELL_HEROIC_STRIKE = 45026, - SPELL_WHIRLWIND = 63807, -}; - -enum Actions -{ - ACTION_EVENT_START = 1, - ACTION_GROUND_PHASE = 2, - ACTION_HARPOON_BUILD = 3, - ACTION_PLACE_BROKEN_HARPOON = 4, - ACTION_COMMANDER_RESET = 7, -}; - -enum Phases -{ - PHASE_PERMAGROUND = 1, - PHASE_GROUND = 2, - PHASE_FLIGHT = 3, -}; - -enum Events -{ - EVENT_BERSERK = 1, - EVENT_BREATH = 2, - EVENT_BUFFET = 3, - EVENT_FIREBALL = 5, - EVENT_FLIGHT = 6, - EVENT_DEVOURING = 7, - EVENT_FLAME = 8, - EVENT_LAND = 9, - EVENT_GROUND = 10, - EVENT_FUSE = 11, - EVENT_SUMMON = 12, - // Razorscale Controller - EVENT_BUILD_HARPOON_1 = 13, - EVENT_BUILD_HARPOON_2 = 14, - EVENT_BUILD_HARPOON_3 = 15, - EVENT_BUILD_HARPOON_4 = 16, -}; - -#define GROUND_Z 391.517f -#define GOSSIP_ITEM_1 "Activate Harpoons!" -#define DATA_QUICK_SHAVE 29192921 // 2919, 2921 are achievement IDs -#define DATA_IRON_DWARF_MEDIUM_RARE 29232924 - -const Position PosEngRepair[4] = -{ - { 590.442f, -130.550f, GROUND_Z, 4.789f }, - { 574.850f, -133.687f, GROUND_Z, 4.252f }, - { 606.567f, -143.369f, GROUND_Z, 4.434f }, - { 560.609f, -142.967f, GROUND_Z, 5.074f }, -}; - -const Position PosDefSpawn[4] = -{ - { 600.75f, -104.850f, GROUND_Z, 0 }, - { 596.38f, -110.262f, GROUND_Z, 0 }, - { 566.47f, -103.633f, GROUND_Z, 0 }, - { 570.41f, -108.791f, GROUND_Z, 0 }, -}; - -const Position PosDefCombat[4] = -{ - { 614.975f, -155.138f, GROUND_Z, 4.154f }, - { 609.814f, -204.968f, GROUND_Z, 5.385f }, - { 563.531f, -201.557f, GROUND_Z, 4.108f }, - { 560.231f, -153.677f, GROUND_Z, 5.403f }, -}; - -const Position PosHarpoon[4] = -{ - { 571.901f, -136.554f, GROUND_Z, 0 }, - { 589.450f, -134.888f, GROUND_Z, 0 }, - { 559.119f, -140.505f, GROUND_Z, 0 }, - { 606.229f, -136.721f, GROUND_Z, 0 }, -}; - -const Position RazorFlight = { 588.050f, -251.191f, 470.536f, 1.498f }; -const Position RazorGround = { 586.966f, -175.534f, GROUND_Z, 4.682f }; -const Position PosEngSpawn = { 591.951f, -95.9680f, GROUND_Z, 0.000f }; - -class boss_razorscale_controller : public CreatureScript -{ - public: - boss_razorscale_controller() : CreatureScript("boss_razorscale_controller") { } - - struct boss_razorscale_controllerAI : public BossAI - { - boss_razorscale_controllerAI(Creature* creature) : BossAI(creature, DATA_RAZORSCALE_CONTROL) - { - me->SetDisplayId(me->GetCreatureInfo()->Modelid2); - } - - void Reset() - { - _Reset(); - me->SetReactState(REACT_PASSIVE); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) - { - switch (spell->Id) - { - case SPELL_FLAMED: - if (GameObject* Harpoon1 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_1))) - Harpoon1->RemoveFromWorld(); - if (GameObject* Harpoon2 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_2))) - Harpoon2->RemoveFromWorld(); - if (GameObject* Harpoon3 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_3))) - Harpoon3->RemoveFromWorld(); - if (GameObject* Harpoon4 = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_RAZOR_HARPOON_4))) - Harpoon4->RemoveFromWorld(); - me->AI()->DoAction(ACTION_HARPOON_BUILD); - me->AI()->DoAction(ACTION_PLACE_BROKEN_HARPOON); - break; - case SPELL_HARPOON_SHOT_1: - case SPELL_HARPOON_SHOT_2: - case SPELL_HARPOON_SHOT_3: - case SPELL_HARPOON_SHOT_4: - DoCast(SPELL_HARPOON_TRIGGER); - break; - } - } - - void JustDied(Unit* /*who*/) - { - _JustDied(); - } - - void DoAction(int32 const action) - { - if (instance->GetBossState(BOSS_RAZORSCALE) != IN_PROGRESS) - return; - - switch (action) - { - case ACTION_HARPOON_BUILD: - events.ScheduleEvent(EVENT_BUILD_HARPOON_1, 50000); - if (me->GetMap()->GetSpawnMode() == RAID_DIFFICULTY_25MAN_NORMAL) - events.ScheduleEvent(EVENT_BUILD_HARPOON_3, 90000); - break; - case ACTION_PLACE_BROKEN_HARPOON: - for (uint8 n = 0; n < RAID_MODE(2, 4); n++) - me->SummonGameObject(GO_RAZOR_BROKEN_HARPOON, PosHarpoon[n].GetPositionX(), PosHarpoon[n].GetPositionY(), PosHarpoon[n].GetPositionZ(), 2.286f, 0, 0, 0, 0, 180000); - break; - } - } - - void UpdateAI(uint32 const Diff) - { - events.Update(Diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_BUILD_HARPOON_1: - DoScriptText(EMOTE_HARPOON, me); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[0].GetPositionX(), PosHarpoon[0].GetPositionY(), PosHarpoon[0].GetPositionZ(), 4.790f, 0.0f, 0.0f, 0.0f, 0.0f, uint32(me->GetRespawnTime()))) - { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) //only nearest broken harpoon - BrokenHarpoon->RemoveFromWorld(); - events.ScheduleEvent(EVENT_BUILD_HARPOON_2, 20000); - events.CancelEvent(EVENT_BUILD_HARPOON_1); - } - return; - case EVENT_BUILD_HARPOON_2: - DoScriptText(EMOTE_HARPOON, me); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[1].GetPositionX(), PosHarpoon[1].GetPositionY(), PosHarpoon[1].GetPositionZ(), 4.659f, 0, 0, 0, 0, uint32(me->GetRespawnTime()))) - { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - BrokenHarpoon->RemoveFromWorld(); - events.CancelEvent(EVENT_BUILD_HARPOON_2); - } - return; - case EVENT_BUILD_HARPOON_3: - DoScriptText(EMOTE_HARPOON, me); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_3, PosHarpoon[2].GetPositionX(), PosHarpoon[2].GetPositionY(), PosHarpoon[2].GetPositionZ(), 5.382f, 0, 0, 0, 0, uint32(me->GetRespawnTime()))) - { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - BrokenHarpoon->RemoveFromWorld(); - events.ScheduleEvent(EVENT_BUILD_HARPOON_4, 20000); - events.CancelEvent(EVENT_BUILD_HARPOON_3); - } - return; - case EVENT_BUILD_HARPOON_4: - DoScriptText(EMOTE_HARPOON, me); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_4, PosHarpoon[3].GetPositionX(), PosHarpoon[3].GetPositionY(), PosHarpoon[3].GetPositionZ(), 4.266f, 0, 0, 0, 0, uint32(me->GetRespawnTime()))) - { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - BrokenHarpoon->RemoveFromWorld(); - events.CancelEvent(EVENT_BUILD_HARPOON_4); - } - return; - } - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_razorscale_controllerAI(creature); - } -}; - -class go_razorscale_harpoon : public GameObjectScript -{ - public: - go_razorscale_harpoon() : GameObjectScript("go_razorscale_harpoon") {} - - bool OnGossipHello(Player* /*player*/, GameObject* go) - { - InstanceScript* instance = go->GetInstanceScript(); - if (ObjectAccessor::GetCreature(*go, instance ? instance->GetData64(BOSS_RAZORSCALE) : 0)) - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - return false; - } -}; - -class boss_razorscale : public CreatureScript -{ - public: - boss_razorscale() : CreatureScript("boss_razorscale") { } - - struct boss_razorscaleAI : public BossAI - { - boss_razorscaleAI(Creature* creature) : BossAI(creature, BOSS_RAZORSCALE) - { - // Do not let Razorscale be affected by Battle Shout buff - me->ApplySpellImmune(0, IMMUNITY_ID, (SPELL_BATTLE_SHOUT), true); - } - - Phases phase; - - uint32 EnrageTimer; - uint8 FlyCount; - uint8 HarpoonCounter; - bool PermaGround; - bool Enraged; - - void Reset() - { - _Reset(); - me->SetFlying(true); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); - PermaGround = false; - HarpoonCounter = 0; - if (Creature* commander = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_EXPEDITION_COMMANDER) : 0)) - commander->AI()->DoAction(ACTION_COMMANDER_RESET); - } - - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - if (Creature* controller = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_RAZORSCALE_CONTROL) : 0)) - controller->AI()->DoAction(ACTION_HARPOON_BUILD); - me->SetSpeed(MOVE_FLIGHT, 3.0f, true); - me->SetReactState(REACT_PASSIVE); - phase = PHASE_GROUND; - events.SetPhase(PHASE_GROUND); - FlyCount = 0; - EnrageTimer = 600000; - Enraged = false; - events.ScheduleEvent(EVENT_FLIGHT, 0, 0, PHASE_GROUND); - } - - void JustDied(Unit* /*who*/) - { - _JustDied(); - if (Creature* controller = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_RAZORSCALE_CONTROL) : 0)) - controller->AI()->Reset(); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) - { - if (spell->Id == SPELL_HARPOON_TRIGGER) - ++HarpoonCounter; - } - - void MovementInform(uint32 type, uint32 id) - { - if (type == POINT_MOTION_TYPE && id == 1) - { - phase = PHASE_GROUND; - events.SetPhase(PHASE_GROUND); - events.ScheduleEvent(EVENT_LAND, 0, 0, PHASE_GROUND); - } - } - - uint32 GetData(uint32 type) - { - if (type == DATA_QUICK_SHAVE) - if (FlyCount <= 2) - return 1; - - return 0; - } - - void UpdateAI(uint32 const Diff) - { - if (!UpdateVictim()) - return; - - events.Update(Diff); - - if (HealthBelowPct(50) && !PermaGround) - EnterPermaGround(); - - if (EnrageTimer <= Diff && !Enraged) - { - DoCast(me, SPELL_BERSERK); - Enraged = true; - } - else - EnrageTimer -= Diff; - - if (HarpoonCounter == RAID_MODE(2, 4)) - { - HarpoonCounter = 0; - me->GetMotionMaster()->MovePoint(1, RazorGround); - } - - if (phase == PHASE_GROUND) - { - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FLIGHT: - phase = PHASE_FLIGHT; - events.SetPhase(PHASE_FLIGHT); - me->SetFlying(true); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->GetMotionMaster()->MovePoint(0, RazorFlight); - events.ScheduleEvent(EVENT_FIREBALL, 7000, 0, PHASE_FLIGHT); - events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT); - events.ScheduleEvent(EVENT_SUMMON, 5000, 0, PHASE_FLIGHT); - ++FlyCount; - return; - case EVENT_LAND: - me->SetFlying(false); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); - if (Creature* commander = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_EXPEDITION_COMMANDER) : 0)) - commander->AI()->DoAction(ACTION_GROUND_PHASE); - events.ScheduleEvent(EVENT_BREATH, 30000, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_BUFFET, 33000, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_FLIGHT, 35000, 0, PHASE_GROUND); - return; - case EVENT_BREATH: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); - me->RemoveAllAuras(); - me->SetReactState(REACT_AGGRESSIVE); - DoScriptText(EMOTE_BREATH, me, 0); - DoCastAOE(SPELL_FLAMEBREATH); - events.CancelEvent(EVENT_BREATH); - return; - case EVENT_BUFFET: - DoCastAOE(SPELL_WINGBUFFET); - if (Creature* controller = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_RAZORSCALE_CONTROL) : 0)) - controller->CastSpell(controller, SPELL_FLAMED, true); - events.CancelEvent(EVENT_BUFFET); - return; - } - } - } - if (phase == PHASE_PERMAGROUND) - { - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FLAME: - DoCastAOE(SPELL_FLAMEBUFFET); - events.ScheduleEvent(EVENT_FLAME, 10000, 0, PHASE_PERMAGROUND); - return; - case EVENT_BREATH: - me->MonsterTextEmote(EMOTE_BREATH, 0, true); - DoCastVictim(SPELL_FLAMEBREATH); - events.ScheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND); - return; - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - DoCast(target, SPELL_FIREBALL); - events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND); - return; - case EVENT_DEVOURING: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - DoCast(target, SPELL_DEVOURING_FLAME); - events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_PERMAGROUND); - return; - case EVENT_BUFFET: - DoCastAOE(SPELL_WINGBUFFET); - events.CancelEvent(EVENT_BUFFET); - return; - case EVENT_FUSE: - DoCast(me->getVictim(), SPELL_FUSEARMOR); - events.ScheduleEvent(EVENT_FUSE, 10000, 0, PHASE_PERMAGROUND); - return; - } - } - - DoMeleeAttackIfReady(); - } - else - { - if (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - DoCast(target, SPELL_FIREBALL); - events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_FLIGHT); - return; - case EVENT_DEVOURING: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_DEVOURING_FLAME, true); - events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT); - return; - case EVENT_SUMMON: - SummonMoleMachines(); - events.ScheduleEvent(EVENT_SUMMON, 45000, 0, PHASE_FLIGHT); - return; - } - } - } - } - - void EnterPermaGround() - { - me->MonsterTextEmote(EMOTE_PERMA, 0, true); - phase = PHASE_PERMAGROUND; - events.SetPhase(PHASE_PERMAGROUND); - me->SetFlying(false); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveAurasDueToSpell(SPELL_HARPOON_TRIGGER); - me->SetSpeed(MOVE_FLIGHT, 1.0f, true); - PermaGround = true; - DoCastAOE(SPELL_FLAMEBREATH); - events.ScheduleEvent(EVENT_FLAME, 15000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_DEVOURING, 15000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_DEVOURING, 6000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_BUFFET, 2500, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_FUSE, 5000, 0, PHASE_PERMAGROUND); - } - - void SummonMoleMachines() - { - // Adds will come in waves from mole machines. One mole can spawn a Dark Rune Watcher - // with 1-2 Guardians, or a lone Sentinel. Up to 4 mole machines can spawn adds at any given time. - uint8 random = urand(2, 4); - for (uint8 n = 0; n < random; n++) - { - float x = float(irand(540, 640)); // Safe range is between 500 and 650 - float y = float(irand(-230, -195)); // Safe range is between -235 and -145 - float z = GROUND_Z; // Ground level - me->SummonCreature(MOLE_MACHINE_TRIGGER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); - } - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_EVENT_START: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - DoZoneInCombat(me, 150.0f); - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } -}; - -class npc_expedition_commander : public CreatureScript -{ - public: - npc_expedition_commander() : CreatureScript("npc_expedition_commander") { } - - struct npc_expedition_commanderAI : public ScriptedAI - { - npc_expedition_commanderAI(Creature* creature) : ScriptedAI(creature) - { - instance = me->GetInstanceScript(); - Greet = false; - } - - InstanceScript* instance; - std::list summons; - - bool Greet; - uint32 AttackStartTimer; - uint8 Phase; - Creature* Engineer[4]; - Creature* Defender[4]; - - void Reset() - { - AttackStartTimer = 0; - Phase = 0; - Greet = false; - summons.clear(); - } - - void MoveInLineOfSight(Unit* who) - { - if (!Greet && me->IsWithinDistInMap(who, 10.0f) && who->GetTypeId() == TYPEID_PLAYER) - { - DoScriptText(SAY_GREET, me); - Greet = true; - } - } - - void JustSummoned(Creature* summoned) - { - summons.push_back(summoned->GetGUID()); - } - - void DoAction(int32 const action) - { - switch (action) - { - case ACTION_GROUND_PHASE: - DoScriptText(SAY_GROUND_PHASE, me); - break; - case ACTION_COMMANDER_RESET: - summons.clear(); - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - break; - } - } - - void UpdateAI(uint32 const Diff) - { - if (AttackStartTimer <= Diff) - { - switch (Phase) - { - case 1: - instance->SetBossState(BOSS_RAZORSCALE, IN_PROGRESS); - summons.clear(); - AttackStartTimer = 1000; - Phase = 2; - break; - case 2: - for (uint8 n = 0; n < RAID_MODE(2, 4); n++) - { - Engineer[n] = me->SummonCreature(NPC_ENGINEER, PosEngSpawn, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); - Engineer[n]->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - Engineer[n]->SetSpeed(MOVE_RUN, 0.5f); - Engineer[n]->SetHomePosition(PosEngRepair[n]); - Engineer[n]->GetMotionMaster()->MoveTargetedHome(); - } - Engineer[0]->MonsterYell(SAY_AGGRO_3, LANG_UNIVERSAL, 0); - Phase = 3; - AttackStartTimer = 14000; - break; - case 3: - for (uint8 n = 0; n < 4; n++) - { - Defender[n] = me->SummonCreature(NPC_DEFENDER, PosDefSpawn[n], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); - Defender[n]->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - Defender[n]->SetHomePosition(PosDefCombat[n]); - Defender[n]->GetMotionMaster()->MoveTargetedHome(); - } - Phase = 4; - break; - case 4: - for (uint8 n = 0; n < RAID_MODE(2, 4); n++) - Engineer[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USESTANDING); - for (uint8 n = 0; n < 4; ++n) - Defender[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); - me->MonsterYell(SAY_AGGRO_2, LANG_UNIVERSAL, 0); - AttackStartTimer = 16000; - Phase = 5; - break; - case 5: - if (Creature* Razorscale = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(BOSS_RAZORSCALE) : 0)) - { - Razorscale->AI()->DoAction(ACTION_EVENT_START); - me->SetInCombatWith(Razorscale); - } - Engineer[0]->MonsterYell(SAY_AGGRO_1, LANG_UNIVERSAL, 0); - Phase = 6; - break; - } - } - else - AttackStartTimer -= Diff; - } - }; - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->CLOSE_GOSSIP_MENU(); - CAST_AI(npc_expedition_commanderAI, creature->AI())->Phase = 1; - break; - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) - { - InstanceScript* instance = creature->GetInstanceScript(); - if (instance && instance->GetBossState(BOSS_RAZORSCALE) == NOT_STARTED) - { - player->PrepareGossipMenu(creature); - - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(13853, creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(13910, creature->GetGUID()); - - return true; - } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_expedition_commanderAI(creature); - } -}; - -class npc_mole_machine_trigger : public CreatureScript -{ - public: - npc_mole_machine_trigger() : CreatureScript("npc_mole_machine_trigger") { } - - struct npc_mole_machine_triggerAI : public Scripted_NoMovementAI - { - npc_mole_machine_triggerAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); - } - - uint32 SummonGobTimer; - uint32 SummonNpcTimer; - uint32 DissapearTimer; - bool GobSummoned; - bool NpcSummoned; - - void Reset() - { - SummonGobTimer = 2000; - SummonNpcTimer = 6000; - DissapearTimer = 10000; - GobSummoned = false; - NpcSummoned = false; - } - - void UpdateAI(uint32 const Diff) - { - if (!GobSummoned && SummonGobTimer <= Diff) - { - DoCast(SPELL_SUMMON_MOLE_MACHINE); - GobSummoned = true; - } - else - SummonGobTimer -= Diff; - - if (!NpcSummoned && SummonNpcTimer <= Diff) - { - switch (urand(0, 1 )) - { - case 0: - DoCast(SPELL_SUMMON_IRON_DWARVES); - break; - case 1: - DoCast(SPELL_SUMMON_IRON_DWARVES_2); - break; - } - - DoCast(SPELL_SUMMON_IRON_DWARVE_GUARDIAN); - DoCast(SPELL_SUMMON_IRON_DWARVE_WATCHER); - NpcSummoned = true; - } - else - SummonNpcTimer -= Diff; - - if (DissapearTimer <= Diff) - { - if (GameObject* molemachine = me->FindNearestGameObject(GO_MOLE_MACHINE, 1)) - molemachine->Delete(); - - me->DisappearAndDie(); - } - else - DissapearTimer -= Diff; - } - - void JustSummoned(Creature* summoned) - { - summoned->AI()->DoZoneInCombat(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_mole_machine_triggerAI(creature); - } -}; - -class npc_devouring_flame : public CreatureScript -{ - public: - npc_devouring_flame() : CreatureScript("npc_devouring_flame") { } - - struct npc_devouring_flameAI : public Scripted_NoMovementAI - { - npc_devouring_flameAI(Creature* creature) : Scripted_NoMovementAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); - } - - void Reset() - { - DoCast(SPELL_FLAME_GROUND); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_devouring_flameAI(creature); - } -}; - -class npc_darkrune_watcher : public CreatureScript -{ - public: - npc_darkrune_watcher() : CreatureScript("npc_darkrune_watcher") { } - - struct npc_darkrune_watcherAI : public ScriptedAI - { - npc_darkrune_watcherAI(Creature* creature) : ScriptedAI(creature){} - - uint32 ChainTimer; - uint32 LightTimer; - - void Reset() - { - ChainTimer = urand(10000, 15000); - LightTimer = urand(1000, 3000); - } - - void UpdateAI(uint32 const Diff) - { - if (!UpdateVictim()) - return; - - if (ChainTimer <= Diff) - { - DoCast(me->getVictim(), SPELL_CHAIN_LIGHTNING); - ChainTimer = urand(10000, 15000); - } - else - ChainTimer -= Diff; - - if (LightTimer <= Diff) - { - DoCastVictim(SPELL_LIGHTNING_BOLT); - LightTimer = urand(5000, 7000); - } - else - LightTimer -= Diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_darkrune_watcherAI(creature); - } -}; - -class npc_darkrune_guardian : public CreatureScript -{ - public: - npc_darkrune_guardian() : CreatureScript("npc_darkrune_guardian") { } - - struct npc_darkrune_guardianAI : public ScriptedAI - { - npc_darkrune_guardianAI(Creature* creature) : ScriptedAI(creature){} - - uint32 StormTimer; - - void Reset() - { - StormTimer = urand(3000, 6000); - killedByBreath = false; - } - - uint32 GetData(uint32 type) - { - return type == DATA_IRON_DWARF_MEDIUM_RARE ? killedByBreath : 0; - } - - void SetData(uint32 type, uint32 value) - { - if (type == DATA_IRON_DWARF_MEDIUM_RARE) - killedByBreath = value; - } - - - void UpdateAI(uint32 const Diff) - { - if (!UpdateVictim()) - return; - - if (StormTimer <= Diff) - { - DoCast(me->getVictim(), SPELL_STORMSTRIKE); - StormTimer = urand(4000, 8000); - } - else - StormTimer -= Diff; - - DoMeleeAttackIfReady(); - } - - private: - bool killedByBreath; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_darkrune_guardianAI(creature); - } -}; - -class npc_darkrune_sentinel : public CreatureScript -{ - public: - npc_darkrune_sentinel() : CreatureScript("npc_darkrune_sentinel") { } - - struct npc_darkrune_sentinelAI : public ScriptedAI - { - npc_darkrune_sentinelAI(Creature* creature) : ScriptedAI(creature){} - - uint32 HeroicTimer; - uint32 WhirlTimer; - uint32 ShoutTimer; - - void Reset() - { - HeroicTimer = urand(4000, 8000); - WhirlTimer = urand(20000, 25000); - ShoutTimer = urand(15000, 30000); - } - - void UpdateAI(uint32 const Diff) - { - if (!UpdateVictim()) - return; - - if (HeroicTimer <= Diff) - { - DoCast(me->getVictim(), SPELL_HEROIC_STRIKE); - HeroicTimer = urand(4000, 6000); - } - else - HeroicTimer -= Diff; - - if (WhirlTimer <= Diff) - { - DoCast(me->getVictim(), SPELL_WHIRLWIND); - WhirlTimer = urand(20000, 25000); - } - else - WhirlTimer -= Diff; - - if (ShoutTimer <= Diff) - { - DoCast(me, SPELL_BATTLE_SHOUT); - ShoutTimer = urand(30000, 40000); - } - else - ShoutTimer -= Diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_darkrune_sentinelAI(creature); - } -}; - -class spell_razorscale_devouring_flame : public SpellScriptLoader -{ - public: - spell_razorscale_devouring_flame() : SpellScriptLoader("spell_razorscale_devouring_flame") { } - - class spell_razorscale_devouring_flame_SpellScript : public SpellScript - { - PrepareSpellScript(spell_razorscale_devouring_flame_SpellScript); - - void HandleSummon(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - Unit* caster = GetCaster(); - uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue); - WorldLocation const* summonLocation = GetTargetDest(); - if (!caster || !summonLocation) - return; - - caster->SummonCreature(entry, summonLocation->GetPositionX(), summonLocation->GetPositionY(), GROUND_Z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000); - } - - void Register() - { - OnEffectHit += SpellEffectFn(spell_razorscale_devouring_flame_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_razorscale_devouring_flame_SpellScript(); - } -}; - -class spell_razorscale_flame_breath : public SpellScriptLoader -{ - public: - spell_razorscale_flame_breath() : SpellScriptLoader("spell_razorscale_flame_breath") { } - - class spell_razorscale_flame_breath_SpellScript : public SpellScript - { - PrepareSpellScript(spell_razorscale_flame_breath_SpellScript); - - void CheckDamage() - { - Creature* target = GetHitCreature(); - if (!target || target->GetEntry() != NPC_DARK_RUNE_GUARDIAN) - return; - - if (GetHitDamage() >= int32(target->GetHealth())) - target->AI()->SetData(DATA_IRON_DWARF_MEDIUM_RARE, 1); - } - - void Register() - { - OnHit += SpellHitFn(spell_razorscale_flame_breath_SpellScript::CheckDamage); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_razorscale_flame_breath_SpellScript(); - } -}; - -class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript -{ - public: - achievement_iron_dwarf_medium_rare() : AchievementCriteriaScript("achievement_iron_dwarf_medium_rare") - { - } - - bool OnCheck(Player* /*player*/, Unit* target) - { - return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_IRON_DWARF_MEDIUM_RARE); - } -}; - -class achievement_quick_shave : public AchievementCriteriaScript -{ - public: - achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (target) - if (Creature* razorscale = target->ToCreature()) - if (razorscale->AI()->GetData(DATA_QUICK_SHAVE)) - return true; - - return false; - } -}; - -void AddSC_boss_razorscale() -{ - new boss_razorscale_controller(); - new go_razorscale_harpoon(); - new boss_razorscale(); - new npc_expedition_commander(); - new npc_mole_machine_trigger(); - new npc_devouring_flame(); - new npc_darkrune_watcher(); - new npc_darkrune_guardian(); - new npc_darkrune_sentinel(); - new spell_razorscale_devouring_flame(); - new spell_razorscale_flame_breath(); - new achievement_iron_dwarf_medium_rare(); - new achievement_quick_shave(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_thorim.cpp deleted file mode 100644 index f993c419b8c..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_thorim.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "ulduar.h" - -enum Yells -{ - SAY_AGGRO_1 = -1603270, - SAY_AGGRO_2 = -1603271, - SAY_SPECIAL_1 = -1603272, - SAY_SPECIAL_2 = -1603273, - SAY_SPECIAL_3 = -1603274, - SAY_JUMPDOWN = -1603275, - SAY_SLAY_1 = -1603276, - SAY_SLAY_2 = -1603277, - SAY_BERSERK = -1603278, - SAY_WIPE = -1603279, - SAY_DEATH = -1603280, - SAY_END_NORMAL_1 = -1603281, - SAY_END_NORMAL_2 = -1603282, - SAY_END_NORMAL_3 = -1603283, - SAY_END_HARD_1 = -1603284, - SAY_END_HARD_2 = -1603285, - SAY_END_HARD_3 = -1603286, - SAY_YS_HELP = -1603287, -}; - -class boss_thorim : public CreatureScript -{ -public: - boss_thorim() : CreatureScript("boss_thorim") { } - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } - - struct boss_thorimAI : public BossAI - { - boss_thorimAI(Creature* creature) : BossAI(creature, BOSS_THORIM) - { - } - - void Reset() - { - _Reset(); - } - - void EnterEvadeMode() - { - DoScriptText(SAY_WIPE, me); - _EnterEvadeMode(); - } - - void KilledUnit(Unit* /*victim*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void JustDied(Unit* /*victim*/) - { - DoScriptText(SAY_DEATH, me); - _JustDied(); - } - - void EnterCombat(Unit* /*who*/) - { - DoScriptText(RAND(SAY_AGGRO_1, SAY_AGGRO_2), me); - _EnterCombat(); - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; - //SPELLS TODO: - - // - DoMeleeAttackIfReady(); - - EnterEvadeIfOutOfCombatArea(diff); - } - }; - -}; - -void AddSC_boss_thorim() -{ - new boss_thorim(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp deleted file mode 100644 index ae803b24642..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 . - */ - -/* - TODO: - Fix void zone damage - If the boss is to close to a scrap pile -> no summon -- Needs retail confirmation - make the life sparks visible... /? Need test - Codestyle -*/ - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "SpellScript.h" -#include "SpellAuraEffects.h" -#include "ulduar.h" -#include "Vehicle.h" - -enum Spells -{ - SPELL_TYMPANIC_TANTRUM = 62776, - SPELL_SEARING_LIGHT_10 = 63018, - SPELL_SEARING_LIGHT_25 = 65121, - - SPELL_SUMMON_LIFE_SPARK = 64210, - SPELL_SUMMON_VOID_ZONE = 64203, - - SPELL_GRAVITY_BOMB_10 = 63024, - SPELL_GRAVITY_BOMB_25 = 64234, - - SPELL_HEARTBREAK_10 = 65737, - SPELL_HEARTBREAK_25 = 64193, - - // Cast by 33337 at Heartbreak: - SPELL_RECHARGE_PUMMELER = 62831, // Summons 33344 - SPELL_RECHARGE_SCRAPBOT = 62828, // Summons 33343 - SPELL_RECHARGE_BOOMBOT = 62835, // Summons 33346 - - // Cast by 33329 on 33337 (visual?) - SPELL_ENERGY_ORB = 62790, // Triggers 62826 - needs spellscript for periodic tick to cast one of the random spells above - - SPELL_HEART_HEAL_TO_FULL = 17683, - SPELL_HEART_OVERLOAD = 62789, - - SPELL_HEART_LIGHTNING_TETHER = 64799, // Cast on self? - SPELL_HEART_RIDE_VEHICLE = 63313, - SPELL_ENRAGE = 26662, - SPELL_STAND = 37752, - SPELL_SUBMERGE = 37751, - - //------------------VOID ZONE-------------------- - SPELL_VOID_ZONE_10 = 64203, - SPELL_VOID_ZONE_25 = 64235, - - // Life Spark - SPELL_STATIC_CHARGED_10 = 64227, - SPELL_STATIC_CHARGED_25 = 64236, - SPELL_SHOCK = 64230, - - //----------------XT-002 HEART------------------- - SPELL_EXPOSED_HEART = 63849, - // Channeled - - //---------------XM-024 PUMMELLER---------------- - SPELL_ARCING_SMASH = 8374, - SPELL_TRAMPLE = 5568, - SPELL_UPPERCUT = 10966, - - // Scrabot: - SPELL_SCRAPBOT_RIDE_VEHICLE = 47020, - SPELL_SUICIDE = 7, - - //------------------BOOMBOT----------------------- - SPELL_AURA_BOOMBOT = 65032, - SPELL_BOOM = 62834, - - // Achievement-related spells - SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS = 65037 -}; - -enum Events -{ - EVENT_TYMPANIC_TANTRUM = 1, - EVENT_SEARING_LIGHT, - EVENT_GRAVITY_BOMB, - EVENT_HEART_PHASE, - EVENT_ENERGY_ORB, - EVENT_DISPOSE_HEART, - EVENT_ENRAGE, - EVENT_ENTER_HARD_MODE, -}; - -enum Timers -{ - TIMER_TYMPANIC_TANTRUM_MIN = 32000, - TIMER_TYMPANIC_TANTRUM_MAX = 36000, - TIMER_SEARING_LIGHT = 20000, - TIMER_GRAVITY_BOMB = 20000, - TIMER_HEART_PHASE = 30000, - TIMER_ENERGY_ORB_MIN = 9000, - TIMER_ENERGY_ORB_MAX = 10000, - TIMER_ENRAGE = 600000, - - TIMER_VOID_ZONE = 3000, - - // Life Spark - TIMER_SHOCK = 12000, - - // Pummeller - // Timers may be off - TIMER_ARCING_SMASH = 27000, - TIMER_TRAMPLE = 22000, - TIMER_UPPERCUT = 17000, - - TIMER_SPAWN_ADD = 12000, -}; - -enum Creatures -{ - NPC_VOID_ZONE = 34001, - NPC_LIFE_SPARK = 34004, - NPC_XT002_HEART = 33329, - NPC_XS013_SCRAPBOT = 33343, - NPC_XM024_PUMMELLER = 33344, - NPC_XE321_BOOMBOT = 33346, -}; - -enum Actions -{ - ACTION_ENTER_HARD_MODE, -}; - -enum XT002Data -{ - DATA_TRANSFERED_HEALTH, - DATA_HARD_MODE, - DATA_HEALTH_RECOVERED, - DATA_GRAVITY_BOMB_CASUALTY, -}; - -enum Yells -{ - SAY_AGGRO = -1603300, - SAY_HEART_OPENED = -1603301, - SAY_HEART_CLOSED = -1603302, - SAY_TYMPANIC_TANTRUM = -1603303, - SAY_SLAY_1 = -1603304, - SAY_SLAY_2 = -1603305, - SAY_BERSERK = -1603306, - SAY_DEATH = -1603307, - SAY_SUMMON = -1603308, -}; - -enum AchievementCredits -{ - ACHIEV_MUST_DECONSTRUCT_FASTER = 21027, -}; - -#define HEART_VEHICLE_SEAT 0 - -/*------------------------------------------------------- - * - * XT-002 DECONSTRUCTOR - * - *///---------------------------------------------------- -class boss_xt002 : public CreatureScript -{ - public: - boss_xt002() : CreatureScript("boss_xt002") { } - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI(creature); - } - - struct boss_xt002_AI : public BossAI - { - boss_xt002_AI(Creature* creature) : BossAI(creature, BOSS_XT002) - { - } - - void Reset() - { - _Reset(); - - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - _healthRecovered = false; - _gravityBombCasualty = false; - _hardMode = false; - - _phase = 1; - _heartExposed = 0; - - if (!instance) - return; - - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); - } - - void EnterCombat(Unit* /*who*/) - { - DoScriptText(SAY_AGGRO, me); - _EnterCombat(); - - events.ScheduleEvent(EVENT_ENRAGE, TIMER_ENRAGE); - events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); - events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT); - //Tantrum is casted a bit slower the first time. - events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX) * 2); - - if (!instance) - return; - - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); - } - - void DoAction(const int32 action) - { - switch (action) - { - case ACTION_ENTER_HARD_MODE: - events.ScheduleEvent(EVENT_ENTER_HARD_MODE, 1); - break; - } - } - - void KilledUnit(Unit* /*victim*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void JustDied(Unit* /*victim*/) - { - DoScriptText(SAY_DEATH, me); - _JustDied(); - } - - void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) - { - if (!_hardMode && _phase == 1 && !HealthAbovePct(100 - 25 * (_heartExposed+1))) - ExposeHeart(); - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim() || !CheckInRoom()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STAT_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SEARING_LIGHT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25)); - - events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT); - break; - case EVENT_GRAVITY_BOMB: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25)); - - events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); - break; - case EVENT_TYMPANIC_TANTRUM: - DoScriptText(SAY_TYMPANIC_TANTRUM, me); - DoCast(SPELL_TYMPANIC_TANTRUM); - events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)); - break; - case EVENT_DISPOSE_HEART: - SetPhaseOne(); - break; - case EVENT_ENRAGE: - DoScriptText(SAY_BERSERK, me); - DoCast(me, SPELL_ENRAGE); - break; - case EVENT_ENTER_HARD_MODE: - me->SetFullHealth(); - DoCast(me, RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25), true); - me->AddLootMode(LOOT_MODE_HARD_MODE_1); - _hardMode = true; - SetPhaseOne(); - break; - } - } - - if (_phase == 1) - DoMeleeAttackIfReady(); - } - - void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) - { - if (apply && who->GetEntry() == NPC_XS013_SCRAPBOT) - { - // Need this so we can properly determine when to expose heart again in damagetaken hook - if (me->GetHealthPct() > (25 * (4 - _heartExposed))) - ++_heartExposed; - - _healthRecovered = true; - } - } - - uint32 GetData(uint32 type) - { - switch (type) - { - case DATA_HARD_MODE: - return _hardMode ? 1 : 0; - case DATA_HEALTH_RECOVERED: - return _healthRecovered ? 1 : 0; - case DATA_GRAVITY_BOMB_CASUALTY: - return _gravityBombCasualty ? 1 : 0; - } - - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch (type) - { - case DATA_TRANSFERED_HEALTH: - _transferHealth = data; - break; - case DATA_GRAVITY_BOMB_CASUALTY: - _gravityBombCasualty = (data > 0) ? true : false; - break; - } - } - - void ExposeHeart() - { - DoScriptText(SAY_HEART_OPENED, me); - - DoCast(me, SPELL_SUBMERGE); // WIll make creature untargetable - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - - Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : NULL; - if (heart) - { - heart->CastSpell(heart, SPELL_HEART_OVERLOAD, false); - heart->CastSpell(me, SPELL_HEART_LIGHTNING_TETHER, false); - heart->CastSpell(heart, SPELL_HEART_HEAL_TO_FULL, true); - heart->CastSpell(heart, SPELL_EXPOSED_HEART, false); // Channeled - - heart->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - } - - events.CancelEvent(EVENT_SEARING_LIGHT); - events.CancelEvent(EVENT_GRAVITY_BOMB); - events.CancelEvent(EVENT_TYMPANIC_TANTRUM); - - // Start "end of phase 2 timer" - events.ScheduleEvent(EVENT_DISPOSE_HEART, TIMER_HEART_PHASE); - - // Phase 2 has officially started - _phase = 2; - _heartExposed++; - } - - void SetPhaseOne() - { - DoScriptText(SAY_HEART_CLOSED, me); - - DoCast(me, SPELL_STAND); - me->SetReactState(REACT_AGGRESSIVE); - - _phase = 1; - - events.RescheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT / 2); - events.RescheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); - events.RescheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)); - - Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : NULL; - if (!heart) - return; - - heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - heart->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART); - - if (!_hardMode) - { - if (!_transferHealth) - _transferHealth = (heart->GetMaxHealth() - heart->GetHealth()); - - me->ModifyHealth(-((int32)_transferHealth)); - } - } - - private: - // Achievement related - bool _healthRecovered; // Did a scrapbot recover XT-002's health during the encounter? - bool _hardMode; // Are we in hard mode? Or: was the heart killed during phase 2? - bool _gravityBombCasualty; // Did someone die because of Gravity Bomb damage? - - uint8 _phase; - uint8 _heartExposed; - uint32 _transferHealth; - }; -}; - -/*------------------------------------------------------- - * - * XT-002 HEART - * - *///---------------------------------------------------- -class mob_xt002_heart : public CreatureScript -{ - public: - mob_xt002_heart() : CreatureScript("mob_xt002_heart") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_xt002_heartAI(creature); - } - - struct mob_xt002_heartAI : public ScriptedAI - { - mob_xt002_heartAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); - } - - void DamageTaken(Unit* /*pDone*/, uint32 &damage) - { - Creature* xt002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002)); - if (!xt002 || !xt002->AI()) - return; - - if (damage >= me->GetHealth()) - { - xt002->AI()->SetData(DATA_TRANSFERED_HEALTH, me->GetMaxHealth()); - xt002->AI()->DoAction(ACTION_ENTER_HARD_MODE); - damage = 0; - } - } - - private: - InstanceScript* _instance; - uint32 _damageTaken; - }; -}; - -/*------------------------------------------------------- - * - * XS-013 SCRAPBOT - * - *///---------------------------------------------------- -class mob_scrapbot : public CreatureScript -{ - public: - mob_scrapbot() : CreatureScript("mob_scrapbot") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_scrapbotAI(creature); - } - - struct mob_scrapbotAI : public ScriptedAI - { - mob_scrapbotAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - } - - void Reset() - { - me->SetReactState(REACT_PASSIVE); - - _rangeCheckTimer = 500; - - if (Creature* pXT002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) - me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); - } - - void UpdateAI(const uint32 diff) - { - if (_rangeCheckTimer <= diff) - { - if (Creature* xt002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) - { - if (me->IsWithinMeleeRange(xt002)) - { - DoCast(xt002, SPELL_SCRAPBOT_RIDE_VEHICLE); - // Unapply vehicle aura again - xt002->RemoveAurasDueToSpell(SPELL_SCRAPBOT_RIDE_VEHICLE); - me->DespawnOrUnsummon(); - } - } - } - else - _rangeCheckTimer -= diff; - } - - private: - InstanceScript* _instance; - uint32 _rangeCheckTimer; - }; -}; - -/*------------------------------------------------------- - * - * XM-024 PUMMELLER - * - *///---------------------------------------------------- -class mob_pummeller : public CreatureScript -{ - public: - mob_pummeller() : CreatureScript("mob_pummeller") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_pummellerAI(creature); - } - - struct mob_pummellerAI : public ScriptedAI - { - mob_pummellerAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - } - - void Reset() - { - _arcingSmashTimer = TIMER_ARCING_SMASH; - _trampleTimer = TIMER_TRAMPLE; - _uppercutTimer = TIMER_UPPERCUT; - - if (Creature* xt002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) - { - Position pos; - xt002->GetPosition(&pos); - me->GetMotionMaster()->MovePoint(0, pos); - } - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; - - if (me->IsWithinMeleeRange(me->getVictim())) - { - if (_arcingSmashTimer <= diff) - { - DoCast(me->getVictim(), SPELL_ARCING_SMASH); - _arcingSmashTimer = TIMER_ARCING_SMASH; - } - else - _arcingSmashTimer -= diff; - - if (_trampleTimer <= diff) - { - DoCast(me->getVictim(), SPELL_TRAMPLE); - _trampleTimer = TIMER_TRAMPLE; - } - else - _trampleTimer -= diff; - - if (_uppercutTimer <= diff) - { - DoCast(me->getVictim(), SPELL_UPPERCUT); - _uppercutTimer = TIMER_UPPERCUT; - } - else - _uppercutTimer -= diff; - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - uint32 _arcingSmashTimer; - uint32 _trampleTimer; - uint32 _uppercutTimer; - }; -}; - -/*------------------------------------------------------- - * - * XE-321 BOOMBOT - * - *///---------------------------------------------------- -class BoomEvent : public BasicEvent -{ - public: - BoomEvent(Creature* me) : _me(me) - { - } - - bool Execute(uint64 /*time*/, uint32 /*diff*/) - { - // This hack is here because we suspect our implementation of spell effect execution on targets - // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets, - // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc. - // The above situation causes the visual for this spell to be bugged, so we remove the instakill - // effect and implement a script hack for that. - - _me->CastSpell(_me, SPELL_BOOM, false); - return true; - } - - private: - Creature* _me; -}; - -class mob_boombot : public CreatureScript -{ - public: - mob_boombot() : CreatureScript("mob_boombot") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_boombotAI(creature); - } - - struct mob_boombotAI : public ScriptedAI - { - mob_boombotAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - } - - void Reset() - { - _boomed = false; - - DoCast(SPELL_AURA_BOOMBOT); // For achievement - - // HACK/workaround: - // these values aren't confirmed - lack of data - and the values in DB are incorrect - // these values are needed for correct damage of Boom spell - me->SetFloatValue(UNIT_FIELD_MINDAMAGE, 15000.0f); - me->SetFloatValue(UNIT_FIELD_MAXDAMAGE, 18000.0f); - - // Todo: proper waypoints? - if (Creature* pXT002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) - me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); - } - - void DamageTaken(Unit* /*who*/, uint32& damage) - { - if (damage >= (me->GetHealth() - me->GetMaxHealth() * 0.5f) && !_boomed) - { - _boomed = true; // Prevent recursive calls - - WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8+8+4); - data << uint64(me->GetGUID()); - data << uint64(me->GetGUID()); - data << uint32(SPELL_BOOM); - me->SendMessageToSet(&data, false); - - me->DealDamage(me, me->GetHealth(), NULL, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - damage = 0; - - // Visual only seems to work if the instant kill event is delayed or the spell itself is delayed - // Casting done from player and caster source has the same targetinfo flags, - // so that can't be the issue - // See BoomEvent class - // Schedule 1s delayed - me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1*IN_MILLISECONDS)); - } - } - - void UpdateAI(uint32 const /*diff*/) - { - if (!UpdateVictim()) - return; - - // No melee attack - } - - private: - InstanceScript* _instance; - bool _boomed; - }; -}; - - -/*------------------------------------------------------- - * - * LIFE SPARK - * - *///---------------------------------------------------- -class mob_life_spark : public CreatureScript -{ - public: - mob_life_spark() : CreatureScript("mob_life_spark") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_life_sparkAI(creature); - } - - struct mob_life_sparkAI : public ScriptedAI - { - mob_life_sparkAI(Creature* creature) : ScriptedAI(creature) - { - } - - void Reset() - { - DoCast(me, RAID_MODE(SPELL_STATIC_CHARGED_10, SPELL_STATIC_CHARGED_25)); - _shockTimer = 0; // first one is immediate. - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; - - if (_shockTimer <= diff) - { - if (me->IsWithinMeleeRange(me->getVictim())) - { - DoCast(me->getVictim(), SPELL_SHOCK); - _shockTimer = TIMER_SHOCK; - } - } - else _shockTimer -= diff; - } - - private: - uint32 _shockTimer; - }; -}; - -class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader -{ - public: - spell_xt002_searing_light_spawn_life_spark() : SpellScriptLoader("spell_xt002_searing_light_spawn_life_spark") { } - - class spell_xt002_searing_light_spawn_life_spark_AuraScript : public AuraScript - { - PrepareAuraScript(spell_xt002_searing_light_spawn_life_spark_AuraScript); - - bool Validate(SpellInfo const* /*spell*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_LIFE_SPARK)) - return false; - return true; - } - - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (Player* player = GetOwner()->ToPlayer()) - if (Unit* xt002 = GetCaster()) - if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode - player->CastSpell(player, SPELL_SUMMON_LIFE_SPARK, true); - } - - void Register() - { - AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_xt002_searing_light_spawn_life_spark_AuraScript(); - } -}; - -class spell_xt002_gravity_bomb_aura : public SpellScriptLoader -{ - public: - spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { } - - class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript - { - PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript); - - bool Validate(SpellInfo const* /*spell*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_VOID_ZONE)) - return false; - return true; - } - - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (Player* player = GetOwner()->ToPlayer()) - if (Unit* xt002 = GetCaster()) - if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode - player->CastSpell(player, SPELL_SUMMON_VOID_ZONE, true); - } - - void OnPeriodic(AuraEffect const* aurEff) - { - Unit* xt002 = GetCaster(); - if (!xt002) - return; - - Unit* owner = GetOwner()->ToUnit(); - if (!owner) - return; - - if (aurEff->GetAmount() >= int32(owner->GetHealth())) - if (xt002->GetAI()) - xt002->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); - } - - void Register() - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE); - AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_xt002_gravity_bomb_aura_AuraScript(); - } -}; - -class spell_xt002_gravity_bomb_damage : public SpellScriptLoader -{ - public: - spell_xt002_gravity_bomb_damage() : SpellScriptLoader("spell_xt002_gravity_bomb_damage") { } - - class spell_xt002_gravity_bomb_damage_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_gravity_bomb_damage_SpellScript); - - void HandleScript(SpellEffIndex /*eff*/) - { - Unit* caster = GetCaster(); - if (!caster) - return; - - if (GetHitDamage() >= int32(GetHitUnit()->GetHealth())) - if (caster->GetAI()) - caster->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_xt002_gravity_bomb_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_xt002_gravity_bomb_damage_SpellScript(); - } -}; - -class spell_xt002_heart_overload_periodic : public SpellScriptLoader -{ - public: - spell_xt002_heart_overload_periodic() : SpellScriptLoader("spell_xt002_heart_overload_periodic") { } - - class spell_xt002_heart_overload_periodic_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_heart_overload_periodic_SpellScript); - - bool Validate(SpellInfo const* /*spell*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_ENERGY_ORB)) - return false; - - if (!sSpellMgr->GetSpellInfo(SPELL_RECHARGE_BOOMBOT)) - return false; - - if (!sSpellMgr->GetSpellInfo(SPELL_RECHARGE_PUMMELER)) - return false; - - if (!sSpellMgr->GetSpellInfo(SPELL_RECHARGE_SCRAPBOT)) - return false; - - return true; - } - - void HandleScript(SpellEffIndex /*effIndex*/) - { - if (Unit* caster = GetCaster()) - { - if (InstanceScript* instance = caster->GetInstanceScript()) - { - if (Unit* toyPile = ObjectAccessor::GetUnit(*caster, instance->GetData64(DATA_TOY_PILE_0 + urand(0, 3)))) - { - caster->CastSpell(toyPile, SPELL_ENERGY_ORB, true); - - // This should probably be incorporated in a dummy effect handler, but I've had trouble getting the correct target - // Weighed randomization (approximation) - uint32 const spells[] = { SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT, - SPELL_RECHARGE_PUMMELER, SPELL_RECHARGE_BOOMBOT }; - - for (uint8 i = 0; i < 5; ++i) - { - uint8 a = urand(0, 4); - uint32 spellId = spells[a]; - toyPile->CastSpell(toyPile, spellId, true); - } - } - } - - DoScriptText(SAY_SUMMON, caster->GetVehicleBase()); - } - } - - void Register() - { - OnEffectHit += SpellEffectFn(spell_xt002_heart_overload_periodic_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_xt002_heart_overload_periodic_SpellScript(); - } -}; - -class spell_xt002_tympanic_tantrum : public SpellScriptLoader -{ - public: - spell_xt002_tympanic_tantrum() : SpellScriptLoader("spell_xt002_tympanic_tantrum") { } - - class spell_xt002_tympanic_tantrum_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_tympanic_tantrum_SpellScript); - - void FilterTargets(std::list& unitList) - { - unitList.remove_if (PlayerOrPetCheck()); - } - - void Register() - { - OnUnitTargetSelect += SpellUnitTargetFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnUnitTargetSelect += SpellUnitTargetFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_xt002_tympanic_tantrum_SpellScript(); - } -}; - -class spell_xt002_submerged : public SpellScriptLoader -{ - public: - spell_xt002_submerged() : SpellScriptLoader("spell_xt002_submerged") { } - - class spell_xt002_submerged_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_submerged_SpellScript); - - void HandleScript(SpellEffIndex /*eff*/) - { - Creature* target = GetHitCreature(); - if (!target) - return; - - target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - target->SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_SUBMERGED); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_xt002_submerged_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_xt002_submerged_SpellScript(); - } -}; - -class spell_xt002_stand : public SpellScriptLoader -{ - public: - spell_xt002_stand() : SpellScriptLoader("spell_xt002_stand") { } - - class spell_xt002_stand_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_stand_SpellScript); - - void HandleScript(SpellEffIndex /*eff*/) - { - Creature* target = GetHitCreature(); - if (!target) - return; - - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - target->SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND); - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_xt002_stand_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_xt002_stand_SpellScript(); - } -}; - -class achievement_nerf_engineering : public AchievementCriteriaScript -{ - public: - achievement_nerf_engineering() : AchievementCriteriaScript("achievement_nerf_engineering") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (!target || !target->GetAI()) - return false; - - return !(target->GetAI()->GetData(DATA_HEALTH_RECOVERED)); - } -}; - -class achievement_heartbreaker : public AchievementCriteriaScript -{ - public: - achievement_heartbreaker() : AchievementCriteriaScript("achievement_heartbreaker") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (!target || !target->GetAI()) - return false; - - return target->GetAI()->GetData(DATA_HARD_MODE); - } -}; - -class achievement_nerf_gravity_bombs : public AchievementCriteriaScript -{ - public: - achievement_nerf_gravity_bombs() : AchievementCriteriaScript("achievement_nerf_gravity_bombs") { } - - bool OnCheck(Player* /*source*/, Unit* target) - { - if (!target || !target->GetAI()) - return false; - - return !(target->GetAI()->GetData(DATA_GRAVITY_BOMB_CASUALTY)); - } -}; - -void AddSC_boss_xt002() -{ - new mob_xt002_heart(); - new mob_scrapbot(); - new mob_pummeller(); - new mob_boombot(); - - new mob_life_spark(); - new boss_xt002(); - - new spell_xt002_searing_light_spawn_life_spark(); - new spell_xt002_gravity_bomb_aura(); - new spell_xt002_gravity_bomb_damage(); - new spell_xt002_heart_overload_periodic(); - new spell_xt002_tympanic_tantrum(); - new spell_xt002_submerged(); - new spell_xt002_stand(); - - new achievement_nerf_engineering(); - new achievement_heartbreaker(); - new achievement_nerf_gravity_bombs(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_yoggsaron.cpp deleted file mode 100644 index e4b21e1f66e..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_yoggsaron.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "ulduar.h" - -enum Sara_Yells -{ - SAY_SARA_PREFIGHT_1 = -1603310, - SAY_SARA_PREFIGHT_2 = -1603311, - SAY_SARA_AGGRO_1 = -1603312, - SAY_SARA_AGGRO_2 = -1603313, - SAY_SARA_AGGRO_3 = -1603314, - SAY_SARA_SLAY_1 = -1603315, - SAY_SARA_SLAY_2 = -1603316, - WHISP_SARA_INSANITY = -1603317, - SAY_SARA_PHASE2_1 = -1603318, - SAY_SARA_PHASE2_2 = -1603319, -}; - -enum YoggSaron_Yells -{ - SAY_PHASE2_1 = -1603330, - SAY_PHASE2_2 = -1603331, - SAY_PHASE2_3 = -1603332, - SAY_PHASE2_4 = -1603333, - SAY_PHASE2_5 = -1603334, - SAY_PHASE3 = -1603335, - SAY_VISION = -1603336, - SAY_SLAY_1 = -1603337, - SAY_SLAY_2 = -1603338, - WHISP_INSANITY_1 = -1603339, - WHISP_INSANITY_2 = -1603340, - SAY_DEATH = -1603341, -}; - -enum -{ - ACHIEV_TIMED_START_EVENT = 21001, -}; -//not in scriptloader yet just to remove warning boss_yoggsaron.obj : warning LNK4221: no public symbols found; archive member will be inaccessible -void AddSC_boss_yoggsaron() -{ -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp deleted file mode 100644 index 3c5697a7995..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp +++ /dev/null @@ -1,647 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 "InstanceScript.h" -#include "ulduar.h" - -static DoorData const doorData[] = -{ - { GO_LEVIATHAN_DOOR, BOSS_LEVIATHAN, DOOR_TYPE_ROOM, BOUNDARY_S }, - { GO_XT_002_DOOR, BOSS_XT002, DOOR_TYPE_ROOM, BOUNDARY_S }, - { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }, -}; - -class instance_ulduar : public InstanceMapScript -{ - public: - instance_ulduar() : InstanceMapScript("instance_ulduar", 603) { } - - struct instance_ulduar_InstanceMapScript : public InstanceScript - { - instance_ulduar_InstanceMapScript(InstanceMap* map) : InstanceScript(map) { } - - uint32 Encounter[MAX_ENCOUNTER]; - std::string m_strInstData; - - // Creatures - uint64 LeviathanGUID; - uint64 IgnisGUID; - uint64 RazorscaleGUID; - uint64 RazorscaleController; - uint64 RazorHarpoonGUIDs[4]; - uint64 ExpeditionCommanderGUID; - uint64 XT002GUID; - uint64 XTToyPileGUIDs[4]; - uint64 AssemblyGUIDs[3]; - uint64 KologarnGUID; - uint64 AuriayaGUID; - uint64 MimironGUID; - uint64 HodirGUID; - uint64 ThorimGUID; - uint64 FreyaGUID; - uint64 KeeperGUIDs[3]; - uint64 VezaxGUID; - uint64 YoggSaronGUID; - uint64 AlgalonGUID; - uint64 LeviathanGateGUID; - uint64 VezaxDoorGUID; - - // GameObjects - uint64 KologarnChestGUID; - uint64 KologarnBridgeGUID; - uint64 KologarnDoorGUID; - uint64 ThorimChestGUID; - uint64 HodirRareCacheGUID; - uint64 HodirChestGUID; - uint64 HodirDoorGUID; - uint64 HodirIceDoorGUID; - uint64 ArchivumDoorGUID; - - // Miscellaneous - uint32 TeamInInstance; - uint32 HodirRareCacheData; - uint32 ColossusData; - uint8 elderCount; - bool conSpeedAtory; - bool Unbroken; - - std::set mRubbleSpawns; - - void Initialize() - { - SetBossNumber(MAX_ENCOUNTER); - LoadDoorData(doorData); - IgnisGUID = 0; - RazorscaleGUID = 0; - RazorscaleController = 0; - ExpeditionCommanderGUID = 0; - XT002GUID = 0; - KologarnGUID = 0; - AuriayaGUID = 0; - MimironGUID = 0; - HodirGUID = 0; - ThorimGUID = 0; - FreyaGUID = 0; - VezaxGUID = 0; - YoggSaronGUID = 0; - AlgalonGUID = 0; - KologarnChestGUID = 0; - KologarnBridgeGUID = 0; - ThorimChestGUID = 0; - HodirRareCacheGUID = 0; - HodirChestGUID = 0; - LeviathanGateGUID = 0; - VezaxDoorGUID = 0; - HodirDoorGUID = 0; - HodirIceDoorGUID = 0; - ArchivumDoorGUID = 0; - TeamInInstance = 0; - HodirRareCacheData = 0; - ColossusData = 0; - elderCount = 0; - conSpeedAtory = false; - Unbroken = true; - - memset(Encounter, 0, sizeof(Encounter)); - memset(XTToyPileGUIDs, 0, sizeof(XTToyPileGUIDs)); - memset(AssemblyGUIDs, 0, sizeof(AssemblyGUIDs)); - memset(RazorHarpoonGUIDs, 0, sizeof(RazorHarpoonGUIDs)); - memset(KeeperGUIDs, 0, sizeof(KeeperGUIDs)); - } - - bool IsEncounterInProgress() const - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (Encounter[i] == IN_PROGRESS) - return true; - } - - return false; - } - - void OnPlayerEnter(Player* player) - { - if (!TeamInInstance) - TeamInInstance = player->GetTeam(); - } - - void OnCreatureCreate(Creature* creature) - { - if (!TeamInInstance) - { - Map::PlayerList const& Players = instance->GetPlayers(); - if (!Players.isEmpty()) - if (Player* player = Players.begin()->getSource()) - TeamInInstance = player->GetTeam(); - } - - switch (creature->GetEntry()) - { - case NPC_LEVIATHAN: - LeviathanGUID = creature->GetGUID(); - break; - case NPC_IGNIS: - IgnisGUID = creature->GetGUID(); - break; - case NPC_RAZORSCALE: - RazorscaleGUID = creature->GetGUID(); - break; - case NPC_RAZORSCALE_CONTROLLER: - RazorscaleController = creature->GetGUID(); - break; - case NPC_EXPEDITION_COMMANDER: - ExpeditionCommanderGUID = creature->GetGUID(); - break; - case NPC_XT002: - XT002GUID = creature->GetGUID(); - break; - case NPC_XT_TOY_PILE: - for (uint8 i = 0; i < 4; ++i) - if (!XTToyPileGUIDs[i]) - XTToyPileGUIDs[i] = creature->GetGUID(); - break; - - // Assembly of Iron - case NPC_STEELBREAKER: - AssemblyGUIDs[0] = creature->GetGUID(); - break; - case NPC_MOLGEIM: - AssemblyGUIDs[1] = creature->GetGUID(); - break; - case NPC_BRUNDIR: - AssemblyGUIDs[2] = creature->GetGUID(); - break; - - // Freya's Keeper - case NPC_IRONBRANCH: - KeeperGUIDs[0] = creature->GetGUID(); - if (GetBossState(BOSS_FREYA) == DONE) - creature->DespawnOrUnsummon(); - break; - case NPC_BRIGHTLEAF: - KeeperGUIDs[1] = creature->GetGUID(); - if (GetBossState(BOSS_FREYA) == DONE) - creature->DespawnOrUnsummon(); - break; - case NPC_STONEBARK: - KeeperGUIDs[2] = creature->GetGUID(); - if (GetBossState(BOSS_FREYA) == DONE) - creature->DespawnOrUnsummon(); - break; - - // Kologarn - case NPC_KOLOGARN: - KologarnGUID = creature->GetGUID(); - break; - case NPC_AURIAYA: - AuriayaGUID = creature->GetGUID(); - break; - case NPC_MIMIRON: - MimironGUID = creature->GetGUID(); - break; - case NPC_HODIR: - HodirGUID = creature->GetGUID(); - break; - case NPC_THORIM: - ThorimGUID = creature->GetGUID(); - break; - case NPC_FREYA: - FreyaGUID = creature->GetGUID(); - break; - case NPC_VEZAX: - VezaxGUID = creature->GetGUID(); - break; - case NPC_YOGGSARON: - YoggSaronGUID = creature->GetGUID(); - break; - case NPC_ALGALON: - AlgalonGUID = creature->GetGUID(); - break; - - // Hodir's Helper NPCs - case NPC_EIVI_NIGHTFEATHER: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_TOR_GREYCLOUD, HORDE); - break; - case NPC_ELLIE_NIGHTFEATHER: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_KAR_GREYCLOUD, HORDE); - break; - case NPC_ELEMENTALIST_MAHFUUN: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_SPIRITWALKER_TARA, HORDE); - break; - case NPC_ELEMENTALIST_AVUUN: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_SPIRITWALKER_YONA, HORDE); - break; - case NPC_MISSY_FLAMECUFFS: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_AMIRA_BLAZEWEAVER, HORDE); - break; - case NPC_SISSY_FLAMECUFFS: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_VEESHA_BLAZEWEAVER, HORDE); - break; - case NPC_FIELD_MEDIC_PENNY: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_BATTLE_PRIEST_ELIZA, HORDE); - break; - case NPC_FIELD_MEDIC_JESSI: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA, HORDE); - break; - } - - } - - void OnGameObjectCreate(GameObject* gameObject) - { - switch (gameObject->GetEntry()) - { - case GO_KOLOGARN_CHEST_HERO: - case GO_KOLOGARN_CHEST: - KologarnChestGUID = gameObject->GetGUID(); - break; - case GO_KOLOGARN_BRIDGE: - KologarnBridgeGUID = gameObject->GetGUID(); - if (GetBossState(BOSS_KOLOGARN) == DONE) - HandleGameObject(0, false, gameObject); - break; - case GO_KOLOGARN_DOOR: - KologarnDoorGUID = gameObject->GetGUID(); - break; - case GO_THORIM_CHEST_HERO: - case GO_THORIM_CHEST: - ThorimChestGUID = gameObject->GetGUID(); - break; - case GO_HODIR_RARE_CACHE_OF_WINTER_HERO: - case GO_HODIR_RARE_CACHE_OF_WINTER: - HodirRareCacheGUID = gameObject->GetGUID(); - break; - case GO_HODIR_CHEST_HERO: - case GO_HODIR_CHEST: - HodirChestGUID = gameObject->GetGUID(); - break; - case GO_LEVIATHAN_DOOR: - AddDoor(gameObject, true); - break; - case GO_LEVIATHAN_GATE: - LeviathanGateGUID = gameObject->GetGUID(); - if (GetBossState(BOSS_LEVIATHAN) == DONE) - gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - break; - case GO_XT_002_DOOR: - AddDoor(gameObject, true); - break; - case GO_VEZAX_DOOR: - VezaxDoorGUID = gameObject->GetGUID(); - HandleGameObject(0, false, gameObject); - break; - case GO_RAZOR_HARPOON_1: - RazorHarpoonGUIDs[0] = gameObject->GetGUID(); - break; - case GO_RAZOR_HARPOON_2: - RazorHarpoonGUIDs[1] = gameObject->GetGUID(); - break; - case GO_RAZOR_HARPOON_3: - RazorHarpoonGUIDs[2] = gameObject->GetGUID(); - break; - case GO_RAZOR_HARPOON_4: - RazorHarpoonGUIDs[3] = gameObject->GetGUID(); - break; - case GO_MOLE_MACHINE: - if (GetBossState(BOSS_RAZORSCALE) == IN_PROGRESS) - gameObject->SetGoState(GO_STATE_ACTIVE); - case GO_HODIR_DOOR: - HodirDoorGUID = gameObject->GetGUID(); - break; - case GO_HODIR_ICE_DOOR: - HodirIceDoorGUID = gameObject->GetGUID(); - break; - case GO_ARCHIVUM_DOOR: - ArchivumDoorGUID = gameObject->GetGUID(); - if (GetBossState(BOSS_ASSEMBLY_OF_IRON) != DONE) - HandleGameObject(ArchivumDoorGUID, false); - break; - } - } - - void OnGameObjectRemove(GameObject* gameObject) - { - switch (gameObject->GetEntry()) - { - case GO_LEVIATHAN_DOOR: - AddDoor(gameObject, false); - break; - case GO_XT_002_DOOR: - AddDoor(gameObject, false); - default: - break; - } - } - - void OnCreatureDeath(Creature* creature) - { - switch (creature->GetEntry()) - { - case NPC_CORRUPTED_SERVITOR: - case NPC_MISGUIDED_NYMPH: - case NPC_GUARDIAN_LASHER: - case NPC_FOREST_SWARMER: - case NPC_MANGROVE_ENT: - case NPC_IRONROOT_LASHER: - case NPC_NATURES_BLADE: - case NPC_GUARDIAN_OF_LIFE: - if (!conSpeedAtory) - { - DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_CON_SPEED_ATORY); - conSpeedAtory = true; - } - break; - default: - break; - } - } - - void ProcessEvent(WorldObject* /*gameObject*/, uint32 eventId) - { - // Flame Leviathan's Tower Event triggers - Creature* FlameLeviathan = instance->GetCreature(LeviathanGUID); - if (FlameLeviathan && FlameLeviathan->isAlive()) // No leviathan, no event triggering ;) - switch (eventId) - { - case EVENT_TOWER_OF_STORM_DESTROYED: - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_STORM_DESTROYED); - break; - case EVENT_TOWER_OF_FROST_DESTROYED: - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FROST_DESTROYED); - break; - case EVENT_TOWER_OF_FLAMES_DESTROYED: - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FLAMES_DESTROYED); - break; - case EVENT_TOWER_OF_LIFE_DESTROYED: - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_LIFE_DESTROYED); - break; - } - } - - - bool SetBossState(uint32 type, EncounterState state) - { - if (!InstanceScript::SetBossState(type, state)) - return false; - - switch (type) - { - case BOSS_LEVIATHAN: - case BOSS_IGNIS: - case BOSS_RAZORSCALE: - case BOSS_XT002: - case BOSS_AURIAYA: - case BOSS_MIMIRON: - case BOSS_FREYA: - break; - case BOSS_ASSEMBLY_OF_IRON: - if (state == DONE) - HandleGameObject(ArchivumDoorGUID, true); - break; - case BOSS_VEZAX: - if (state == DONE) - HandleGameObject(VezaxDoorGUID, true); - break; - case BOSS_YOGGSARON: - break; - case BOSS_KOLOGARN: - if (state == DONE) - { - if (GameObject* gameObject = instance->GetGameObject(KologarnChestGUID)) - { - gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); - gameObject->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - } - HandleGameObject(KologarnBridgeGUID, false); - } - if (state == IN_PROGRESS) - HandleGameObject(KologarnDoorGUID, false); - else - HandleGameObject(KologarnDoorGUID, true); - break; - case BOSS_HODIR: - if (state == DONE) - { - if (GameObject* HodirRareCache = instance->GetGameObject(HodirRareCacheGUID)) - if (GetData(DATA_HODIR_RARE_CACHE)) - HodirRareCache->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - if (GameObject* HodirChest = instance->GetGameObject(HodirChestGUID)) - HodirChest->SetRespawnTime(HodirChest->GetRespawnDelay()); - HandleGameObject(HodirDoorGUID, true); - HandleGameObject(HodirIceDoorGUID, true); - } - break; - case BOSS_THORIM: - if (state == DONE) - if (GameObject* gameObject = instance->GetGameObject(ThorimChestGUID)) - gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); - break; - } - - return true; - } - - void SetData(uint32 type, uint32 data) - { - switch (type) - { - case DATA_COLOSSUS: - ColossusData = data; - if (data == 2) - { - if (Creature* Leviathan = instance->GetCreature(LeviathanGUID)) - Leviathan->AI()->DoAction(ACTION_MOVE_TO_CENTER_POSITION); - if (GameObject* gameObject = instance->GetGameObject(LeviathanGateGUID)) - gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - SaveToDB(); - } - break; - case DATA_HODIR_RARE_CACHE: - HodirRareCacheData = data; - if (!HodirRareCacheData) - { - if (Creature* Hodir = instance->GetCreature(HodirGUID)) - if (GameObject* gameObject = instance->GetGameObject(HodirRareCacheGUID)) - Hodir->RemoveGameObject(gameObject, false); - } - break; - case DATA_UNBROKEN: - Unbroken = bool(data); - break; - default: - break; - } - } - - void SetData64(uint32 /*type*/, uint64 /*data*/) - { - } - - uint64 GetData64(uint32 data) - { - switch (data) - { - case BOSS_LEVIATHAN: - return LeviathanGUID; - case BOSS_IGNIS: - return IgnisGUID; - case BOSS_RAZORSCALE: - return RazorscaleGUID; - case DATA_RAZORSCALE_CONTROL: - return RazorscaleController; - case BOSS_XT002: - return XT002GUID; - case DATA_TOY_PILE_0: - case DATA_TOY_PILE_1: - case DATA_TOY_PILE_2: - case DATA_TOY_PILE_3: - return XTToyPileGUIDs[data - DATA_TOY_PILE_0]; - case BOSS_KOLOGARN: - return KologarnGUID; - case BOSS_AURIAYA: - return AuriayaGUID; - case BOSS_MIMIRON: - return MimironGUID; - case BOSS_HODIR: - return HodirGUID; - case BOSS_THORIM: - return ThorimGUID; - case BOSS_FREYA: - return FreyaGUID; - case BOSS_VEZAX: - return VezaxGUID; - case BOSS_YOGGSARON: - return YoggSaronGUID; - case BOSS_ALGALON: - return AlgalonGUID; - - // Razorscale expedition commander - case DATA_EXPEDITION_COMMANDER: - return ExpeditionCommanderGUID; - case GO_RAZOR_HARPOON_1: - return RazorHarpoonGUIDs[0]; - case GO_RAZOR_HARPOON_2: - return RazorHarpoonGUIDs[1]; - case GO_RAZOR_HARPOON_3: - return RazorHarpoonGUIDs[2]; - case GO_RAZOR_HARPOON_4: - return RazorHarpoonGUIDs[3]; - - // Assembly of Iron - case BOSS_STEELBREAKER: - return AssemblyGUIDs[0]; - case BOSS_MOLGEIM: - return AssemblyGUIDs[1]; - case BOSS_BRUNDIR: - return AssemblyGUIDs[2]; - - // Freya's Keepers - case BOSS_BRIGHTLEAF: - return KeeperGUIDs[0]; - case BOSS_IRONBRANCH: - return KeeperGUIDs[1]; - case BOSS_STONEBARK: - return KeeperGUIDs[2]; - } - - return 0; - } - - uint32 GetData(uint32 type) - { - switch (type) - { - case DATA_COLOSSUS: - return ColossusData; - case DATA_HODIR_RARE_CACHE: - return HodirRareCacheData; - case DATA_UNBROKEN: - return uint32(Unbroken); - default: - break; - } - - return 0; - } - - std::string GetSaveData() - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << "U U " << GetBossSaveData() << GetData(DATA_COLOSSUS); - - OUT_SAVE_INST_DATA_COMPLETE; - return saveStream.str(); - } - - void Load(char const* strIn) - { - if (!strIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(strIn); - - char dataHead1, dataHead2; - - std::istringstream loadStream(strIn); - loadStream >> dataHead1 >> dataHead2; - - if (dataHead1 == 'U' && dataHead2 == 'U') - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - uint32 tmpState; - loadStream >> tmpState; - if (tmpState == IN_PROGRESS || tmpState > SPECIAL) - tmpState = NOT_STARTED; - - if (i == DATA_COLOSSUS) - SetData(i, tmpState); - else - SetBossState(i, EncounterState(tmpState)); - } - } - - OUT_LOAD_INST_DATA_COMPLETE; - } - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const - { - return new instance_ulduar_InstanceMapScript(map); - } -}; - -void AddSC_instance_ulduar() -{ - new instance_ulduar(); -} diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h deleted file mode 100644 index f11212d535e..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 DEF_ULDUAR_H -#define DEF_ULDUAR_H - -#include "ObjectMgr.h" -#define UlduarScriptName "instance_ulduar" - -enum UlduarBosses -{ - MAX_ENCOUNTER = 20, - - BOSS_LEVIATHAN = 0, - BOSS_IGNIS = 1, - BOSS_RAZORSCALE = 2, - BOSS_XT002 = 3, - BOSS_ASSEMBLY_OF_IRON = 4, - BOSS_STEELBREAKER = 5, - BOSS_MOLGEIM = 6, - BOSS_BRUNDIR = 7, - BOSS_KOLOGARN = 8, - BOSS_AURIAYA = 9, - BOSS_MIMIRON = 10, - BOSS_HODIR = 11, - BOSS_THORIM = 12, - BOSS_FREYA = 13, - BOSS_BRIGHTLEAF = 14, - BOSS_IRONBRANCH = 15, - BOSS_STONEBARK = 16, - BOSS_VEZAX = 17, - BOSS_YOGGSARON = 18, - BOSS_ALGALON = 19, -}; - -enum UlduarNPCs -{ - // General - NPC_LEVIATHAN = 33113, - NPC_SALVAGED_DEMOLISHER = 33109, - NPC_SALVAGED_SIEGE_ENGINE = 33060, - NPC_IGNIS = 33118, - NPC_RAZORSCALE = 33186, - NPC_RAZORSCALE_CONTROLLER = 33233, - NPC_STEELFORGED_DEFFENDER = 33236, - NPC_EXPEDITION_COMMANDER = 33210, - NPC_XT002 = 33293, - NPC_XT_TOY_PILE = 33337, - NPC_STEELBREAKER = 32867, - NPC_MOLGEIM = 32927, - NPC_BRUNDIR = 32857, - NPC_KOLOGARN = 32930, - NPC_FOCUSED_EYEBEAM = 33632, - NPC_FOCUSED_EYEBEAM_RIGHT = 33802, - NPC_LEFT_ARM = 32933, - NPC_RIGHT_ARM = 32934, - NPC_RUBBLE = 33768, - NPC_AURIAYA = 33515, - NPC_MIMIRON = 33350, - NPC_HODIR = 32845, - NPC_THORIM = 32865, - NPC_FREYA = 32906, - NPC_VEZAX = 33271, - NPC_YOGGSARON = 33288, - NPC_ALGALON = 32871, - - // Mimiron - NPC_LEVIATHAN_MKII = 33432, - NPC_VX_001 = 33651, - NPC_AERIAL_COMMAND_UNIT = 33670, - - // Freya's Keepers - NPC_IRONBRANCH = 32913, - NPC_BRIGHTLEAF = 32915, - NPC_STONEBARK = 32914, - - // Hodir's Helper NPCs - NPC_TOR_GREYCLOUD = 32941, - NPC_KAR_GREYCLOUD = 33333, - NPC_EIVI_NIGHTFEATHER = 33325, - NPC_ELLIE_NIGHTFEATHER = 32901, - NPC_SPIRITWALKER_TARA = 33332, - NPC_SPIRITWALKER_YONA = 32950, - NPC_ELEMENTALIST_MAHFUUN = 33328, - NPC_ELEMENTALIST_AVUUN = 32900, - NPC_AMIRA_BLAZEWEAVER = 33331, - NPC_VEESHA_BLAZEWEAVER = 32946, - NPC_MISSY_FLAMECUFFS = 32893, - NPC_SISSY_FLAMECUFFS = 33327, - NPC_BATTLE_PRIEST_ELIZA = 32948, - NPC_BATTLE_PRIEST_GINA = 33330, - NPC_FIELD_MEDIC_PENNY = 32897, - NPC_FIELD_MEDIC_JESSI = 33326, - - // Freya's trash NPCs - NPC_CORRUPTED_SERVITOR = 33354, - NPC_MISGUIDED_NYMPH = 33355, - NPC_GUARDIAN_LASHER = 33430, - NPC_FOREST_SWARMER = 33431, - NPC_MANGROVE_ENT = 33525, - NPC_IRONROOT_LASHER = 33526, - NPC_NATURES_BLADE = 33527, - NPC_GUARDIAN_OF_LIFE = 33528, -}; - -enum UlduarGameObjects -{ - GO_KOLOGARN_CHEST_HERO = 195047, - GO_KOLOGARN_CHEST = 195046, - GO_KOLOGARN_BRIDGE = 194232, - GO_KOLOGARN_DOOR = 194553, - GO_THORIM_CHEST_HERO = 194315, - GO_THORIM_CHEST = 194314, - GO_HODIR_RARE_CACHE_OF_WINTER = 194200, - GO_HODIR_RARE_CACHE_OF_WINTER_HERO = 194201, - GO_HODIR_CHEST_HERO = 194308, - GO_HODIR_CHEST = 194307, - GO_LEVIATHAN_DOOR = 194905, - GO_LEVIATHAN_GATE = 194630, - GO_XT_002_DOOR = 194631, - GO_VEZAX_DOOR = 194750, - GO_MOLE_MACHINE = 194316, - GO_RAZOR_HARPOON_1 = 194542, - GO_RAZOR_HARPOON_2 = 194541, - GO_RAZOR_HARPOON_3 = 194543, - GO_RAZOR_HARPOON_4 = 194519, - GO_RAZOR_BROKEN_HARPOON = 194565, - GO_HODIR_DOOR = 194634, - GO_HODIR_ICE_DOOR = 194441, - GO_ARCHIVUM_DOOR = 194556, -}; - -enum LeviathanData -{ - EVENT_TOWER_OF_STORM_DESTROYED = 21031, - EVENT_TOWER_OF_FROST_DESTROYED = 21032, - EVENT_TOWER_OF_FLAMES_DESTROYED = 21033, - EVENT_TOWER_OF_LIFE_DESTROYED = 21030, - ACTION_TOWER_OF_STORM_DESTROYED = 1, - ACTION_TOWER_OF_FROST_DESTROYED = 2, - ACTION_TOWER_OF_FLAMES_DESTROYED = 3, - ACTION_TOWER_OF_LIFE_DESTROYED = 4, - ACTION_MOVE_TO_CENTER_POSITION = 10, -}; - -enum UlduarAchievementCriteriaIds -{ - CRITERIA_CON_SPEED_ATORY = 21597, - CRITERIA_DISARMED = 21687, -}; - -enum UlduarData -{ - // Collosus (Leviathan) - DATA_COLOSSUS = 20, - - // Razorscale - DATA_EXPEDITION_COMMANDER, - DATA_RAZORSCALE_CONTROL, - - // XT-002 - DATA_TOY_PILE_0, - DATA_TOY_PILE_1, - DATA_TOY_PILE_2, - DATA_TOY_PILE_3, - - // Hodir - DATA_HODIR_RARE_CACHE, -}; - -enum UlduarAchievementData -{ - // FL Achievement boolean - DATA_UNBROKEN = 29052906, // 2905, 2906 are achievement IDs, -}; - -template -CreatureAI* GetUlduarAI(Creature* creature) -{ - if (InstanceMap* instance = creature->GetMap()->ToInstanceMap()) - if (instance->GetInstanceScript()) - if (instance->GetScriptId() == sObjectMgr->GetScriptId(UlduarScriptName)) - return new AI(creature); - - return NULL; -} - -class PlayerOrPetCheck -{ - public: - bool operator() (Unit* unit) - { - if (unit->GetTypeId() != TYPEID_PLAYER) - if (!unit->ToCreature()->isPet()) - return true; - - return false; - } -}; - -#endif diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar_teleporter.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar_teleporter.cpp deleted file mode 100644 index 05b1e395d1e..00000000000 --- a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar_teleporter.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2008-2011 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 - * 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 "ScriptedGossip.h" -#include "ulduar.h" -#include "InstanceScript.h" - -/* -The teleporter appears to be active and stable. - -- Expedition Base Camp -- Formation Grounds -- Colossal Forge -- Scrapyard -- Antechamber of Ulduar -- Shattered Walkway -- Conservatory of Life -*/ - -enum UlduarTeleporter -{ - BASE_CAMP = 200, - GROUNDS = 201, - FORGE = 202, - SCRAPYARD = 203, - ANTECHAMBER = 204, - WALKWAY = 205, - CONSERVATORY = 206, -}; - -class ulduar_teleporter : public GameObjectScript -{ - public: - ulduar_teleporter() : GameObjectScript("ulduar_teleporter") { } - - bool OnGossipSelect(Player* player, GameObject* /*gameObject*/, uint32 sender, uint32 action) - { - player->PlayerTalkClass->ClearMenus(); - if (sender != GOSSIP_SENDER_MAIN) - return false; - if (!player->getAttackers().empty()) - return false; - - switch (action) - { - case BASE_CAMP: - player->TeleportTo(603, -706.122f, -92.6024f, 429.876f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case GROUNDS: - player->TeleportTo(603, 131.248f, -35.3802f, 409.804f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case FORGE: - player->TeleportTo(603, 553.233f, -12.3247f, 409.679f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case SCRAPYARD: - player->TeleportTo(603, 926.292f, -11.4635f, 418.595f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case ANTECHAMBER: - player->TeleportTo(603, 1498.09f, -24.246f, 420.967f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case WALKWAY: - player->TeleportTo(603, 1859.45f, -24.1f, 448.9f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case CONSERVATORY: - player->TeleportTo(603, 2086.27f, -24.3134f, 421.239f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - } - - return true; - } - - bool OnGossipHello(Player* player, GameObject* gameObject) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Expedition Base Camp", GOSSIP_SENDER_MAIN, BASE_CAMP); - if (InstanceScript* instance = gameObject->GetInstanceScript()) - { - if (instance->GetData(DATA_COLOSSUS) == 2) //count of 2 collossus death - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Formation Grounds", GOSSIP_SENDER_MAIN, GROUNDS); - if (instance->GetBossState(BOSS_LEVIATHAN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Colossal Forge", GOSSIP_SENDER_MAIN, FORGE); - if (instance->GetBossState(BOSS_XT002) == DONE) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Scrapyard", GOSSIP_SENDER_MAIN, SCRAPYARD); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Antechamber of Ulduar", GOSSIP_SENDER_MAIN, ANTECHAMBER); - } - if (instance->GetBossState(BOSS_KOLOGARN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Shattered Walkway", GOSSIP_SENDER_MAIN, WALKWAY); - if (instance->GetBossState(BOSS_AURIAYA) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Conservatory of Life", GOSSIP_SENDER_MAIN, CONSERVATORY); - } - - player->SEND_GOSSIP_MENU(gameObject->GetGOInfo()->GetGossipMenuId(), gameObject->GetGUID()); - return true; - } -}; - -void AddSC_ulduar_teleporter() -{ - new ulduar_teleporter(); -} -- cgit v1.2.3