diff options
| author | Rat <none@none> | 2010-01-19 11:36:05 +0100 |
|---|---|---|
| committer | Rat <none@none> | 2010-01-19 11:36:05 +0100 |
| commit | 0cc053ea4d42ce405a915857f75ee00f0f65666b (patch) | |
| tree | 7c25955ee5db618deee963f515ba061fbb1e1e8c /src/scripts/northrend | |
| parent | f5dea61b66a616110cfc82ff640ec448b1efa702 (diff) | |
*Integrate Script system to Core
-added ScriptMgr for loading scripts
-removed bindings
-moved script system to src/game
-moved scripts to src/scripts
-VC project files updated
-cmakes updated (not 100% done yet)
NOTE to Devs:
-file locations changed
-precompiled renamed to ScriptedPch
-ecsort_ai renamed to ScriptedEscortAI
-follower_ai renamed to ScriptedFollowerAI
-guard_ai renamed to ScriptedGuardAI
-simple_ai renamed to ScriptedSimpleAI
-sc_creature renamed to ScriptedCreature
-sc_gossip renamed to ScriptedGossip
-sc_instance renamed to ScriptedInstance
*use the new headers in scripts, thank you
NOTE to ALL:
cmake not fully tested, please report any errors with it
could make creashes, incompability
USE AT YOUR OWN RISK before further tests!!
--HG--
branch : trunk
Diffstat (limited to 'src/scripts/northrend')
134 files changed, 33120 insertions, 0 deletions
diff --git a/src/scripts/northrend/azjol_nerub/ahnkahet/ahnkahet.h b/src/scripts/northrend/azjol_nerub/ahnkahet/ahnkahet.h new file mode 100644 index 00000000000..e6d3bd387ae --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/ahnkahet/ahnkahet.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DEF_AHNKAHET_H +#define DEF_AHNKAHET_H + +#define DATA_ELDER_NADOX 1 +#define DATA_PRINCE_TALDARAM 2 +#define DATA_JEDOGA_SHADOWSEEKER 3 +#define DATA_HERALD_VOLAZJ 4 +#define DATA_AMANITAR 5 + +#define DATA_ELDER_NADOX_EVENT 6 +#define DATA_PRINCE_TALDARAM_EVENT 7 +#define DATA_JEDOGA_SHADOWSEEKER_EVENT 8 +#define DATA_HERALD_VOLAZJ_EVENT 9 +#define DATA_AMANITAR_EVENT 10 + +#define DATA_SPHERE1 11 +#define DATA_SPHERE2 12 +#define DATA_SPHERE1_EVENT 13 +#define DATA_SPHERE2_EVENT 14 +#define DATA_PRINCE_TALDARAM_PLATFORM 15 + +#define DATA_PL_JEDOGA_TARGET 16 +#define DATA_ADD_JEDOGA_OPFER 17 +#define DATA_JEDOGA_RESET_INITIANDS 18 +#define DATA_JEDOGA_TRIGGER_SWITCH 19 +#define DATA_ADD_JEDOGA_INITIAND 20 +#define DATA_ALL_INITIAND_DEAD 21 +#define DATA_INITIAND_KILLED 22 + +#endif diff --git a/src/scripts/northrend/azjol_nerub/ahnkahet/boss_amanitar.cpp b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_amanitar.cpp new file mode 100644 index 00000000000..8ae95c6a18c --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_amanitar.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: boss_amanitar +SDAuthor: WarHead +SD%Complete: 80% +SDComment: Find correct mushrooms spell to make them visible - buffs of the mushrooms not ever applied to the users... +SDCategory: Ahn'kahet +Script Data End */ + +#include "ScriptedPch.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 + + HEALTHY_MUSHROOM_SPELL_POTENT_FUNGUS = 56648, // Killer 3Y + + POISONOUS_MUSHROOM_SPELL_POISON_CLOUD = 57061, // Self - Duration 8 Sec + POISONOUS_MUSHROOM_SPELL_VISUAL_AREA = 61566, // Self + POISONOUS_MUSHROOM_SPELL_VISUAL_AURA = 56741, // Self + + SPELL_PUTRID_MUSHROOM = 31690, // To make the mushrooms visible +}; + +enum Creatures +{ +#define NPC_HEALTHY_MUSHROOM 30391 +#define NPC_POISONOUS_MUSHROOM 30435 +}; + +struct TRINITY_DLL_DECL boss_amanitarAI : public ScriptedAI +{ + boss_amanitarAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + FirstTime = true; + } + + ScriptedInstance* pInstance; + + uint32 roottimer, + bashtimer, + bolttimer, + spawntimer; + + bool FirstTime; + + void Reset() + { + roottimer = urand(5000,9000); + bashtimer = urand(10000,14000); + bolttimer = urand(15000,30000); + spawntimer = 0; + + m_creature->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + + if (pInstance) + { + pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI); + if (!FirstTime) + { + pInstance->SetData(DATA_AMANITAR_EVENT, FAIL); + } + else FirstTime = false; + } + } + + void JustDied(Unit *Killer) + { + if (pInstance) + { + pInstance->SetData(DATA_AMANITAR_EVENT, DONE); + pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI); + } + } + + void EnterCombat(Unit *who) + { + if (pInstance) + pInstance->SetData(DATA_AMANITAR_EVENT, IN_PROGRESS); + + DoCast(m_creature, SPELL_MINI, false); + } + + void SpawnAdds() + { + for (uint8 i = 0; i < 30; ++i) + { + Unit* victim = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if (victim) + { + Position pos; + victim->GetPosition(&pos); + m_creature->GetRandomNearPosition(pos, float(urand(5,80))); + m_creature->SummonCreature(NPC_POISONOUS_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + m_creature->GetRandomNearPosition(pos, float(urand(5,80))); + m_creature->SummonCreature(NPC_HEALTHY_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (spawntimer <= diff) + { + SpawnAdds(); + spawntimer = urand(35000,40000); + } else spawntimer -= diff; + + if (roottimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_ENTANGLING_ROOTS); + roottimer = urand(15000,30000); + } + + if (bashtimer <= diff) + { + DoCastVictim(SPELL_BASH); + bashtimer = urand(15000,30000); + } else bashtimer -= diff; + + if (bolttimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_VENOM_BOLT_VOLLEY); + bolttimer = urand(15000,30000); + } else bolttimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL mob_amanitar_mushroomsAI : public Scripted_NoMovementAI +{ + mob_amanitar_mushroomsAI(Creature* c) : Scripted_NoMovementAI(c) + { + c->SetUInt32Value(UNIT_FIELD_DISPLAYID, 26981); // Unsichtbar... + } + + uint32 auratimer, + deathtimer; // Without not all will despawn after 30000! :-( + + void Reset() + { + DoCast(m_creature, SPELL_PUTRID_MUSHROOM, true); // Hack, to make the mushrooms visible, can't find orig. spell... + + if (m_creature->GetEntry() == NPC_POISONOUS_MUSHROOM) + DoCast(m_creature, POISONOUS_MUSHROOM_SPELL_VISUAL_AURA, true); + + auratimer = 0; + deathtimer = 30000; + } + + void JustDied(Unit *killer) + { + if (!killer) + return; + + if (m_creature->GetEntry() == NPC_HEALTHY_MUSHROOM && killer->GetTypeId() == TYPEID_PLAYER) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(killer, HEALTHY_MUSHROOM_SPELL_POTENT_FUNGUS, false); + } + } + + void EnterCombat(Unit *who) {} + void AttackStart(Unit *victim) {} + + void UpdateAI(const uint32 diff) + { + if (m_creature->GetEntry() == NPC_POISONOUS_MUSHROOM) + { + if (auratimer <= diff) + { + DoCast(m_creature, POISONOUS_MUSHROOM_SPELL_VISUAL_AREA, true); + DoCast(m_creature, POISONOUS_MUSHROOM_SPELL_POISON_CLOUD, false); + auratimer = 7000; + } else auratimer -= diff; + } + if (deathtimer <= diff) + { + m_creature->DisappearAndDie(); + } else deathtimer -= diff; + } +}; + +CreatureAI* GetAI_boss_amanitar(Creature* pCreature) +{ + return new boss_amanitarAI (pCreature); +} + +CreatureAI* GetAI_mob_amanitar_mushrooms(Creature *pCreature) +{ + return new mob_amanitar_mushroomsAI (pCreature); +} + +void AddSC_boss_amanitar() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_amanitar"; + newscript->GetAI = &GetAI_boss_amanitar; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_amanitar_mushrooms"; + newscript->GetAI = &GetAI_mob_amanitar_mushrooms; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/ahnkahet/boss_elder_nadox.cpp b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_elder_nadox.cpp new file mode 100644 index 00000000000..aad211d7f89 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_elder_nadox.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_elder_nadox +SD%Complete: 100 +SDComment: +SDCategory: Ahn'kahet +EndScriptData */ + +#include "ScriptedPch.h" +#include "ahnkahet.h" + +bool DeadAhnkaharGuardian; // needed for achievement: Respect Your Elders(2038) + +#define ACHIEVEMENT_RESPECT_YOUR_ELDERS 2038 + +//not in db +#define SAY_AGGRO -1619014 +#define SAY_SLAY_1 -1619015 +#define SAY_SLAY_2 -1619016 +#define SAY_SLAY_3 -1619017 +#define SAY_DEATH -1619018 +#define SAY_EGG_SAC_1 -1619019 +#define SAY_EGG_SAC_2 -1619020 + +#define SPELL_BROOD_PLAGUE 56130 +#define H_SPELL_BROOD_PLAGUE 59467 +#define H_SPELL_BROOD_RAGE 59465 +#define SPELL_ENRAGE 26662// Enraged if too far away from home + +#define MOB_AHNKAHAR_SWARMER 30178 +#define SPELL_SUMMON_SWARMERS 56119//2x 30178 -- 2x every 10secs + +#define MOB_AHNKAHAR_GUARDIAN_ENTRY 30176 +#define SPELL_SUMMON_SWARM_GUARD 56120//1x 30176 -- every 25secs +#define SPELL_GUARDIAN_AURA 56151 + +#define EMOTE_HATCHES "An Ahn'kahar Guardian hatches!" + +struct TRINITY_DLL_DECL boss_elder_nadoxAI : public ScriptedAI +{ + boss_elder_nadoxAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 plague_Timer; + uint32 rage_Timer; + + uint32 swarmer_spawn_Timer; + uint32 guard_spawn_Timer; + uint32 enrage_Timer; + + ScriptedInstance *pInstance; + + void Reset() + { + plague_Timer = 13000; + rage_Timer = 20000; + + swarmer_spawn_Timer = 10000; + guard_spawn_Timer = 25000; + + enrage_Timer = 5000; + + DeadAhnkaharGuardian = false; + + if (pInstance) + pInstance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit *who) + { + DoScriptText(SAY_DEATH,m_creature); + + if (pInstance) + pInstance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_SLAY_3,m_creature); //SAY_SLAY_3 on death? + + if (IsHeroic() && !DeadAhnkaharGuardian) + { + AchievementEntry const *AchievRespectYourElders = GetAchievementStore()->LookupEntry(ACHIEVEMENT_RESPECT_YOUR_ELDERS); + if (AchievRespectYourElders) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievRespectYourElders); + } + } + } + + if (pInstance) + pInstance->SetData(DATA_ELDER_NADOX_EVENT, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (plague_Timer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_BROOD_PLAGUE, H_SPELL_BROOD_PLAGUE)); + plague_Timer = 15000; + } else plague_Timer -= diff; + + if (IsHeroic()) + if (rage_Timer <= diff) + { + Unit* Swarmer = m_creature->FindNearestCreature(MOB_AHNKAHAR_SWARMER, 35); + + if (Swarmer) + { + DoCast(Swarmer, H_SPELL_BROOD_RAGE, true); + rage_Timer = 15000; + } + } else rage_Timer -= diff; + + if (swarmer_spawn_Timer <= diff) + { + DoCast(m_creature, SPELL_SUMMON_SWARMERS, true); + DoCast(m_creature, SPELL_SUMMON_SWARMERS); + if (urand(1,3) == 3) // 33% chance of dialog + DoScriptText(RAND(SAY_EGG_SAC_1,SAY_EGG_SAC_2), m_creature); + + swarmer_spawn_Timer = 10000; + } else swarmer_spawn_Timer -= diff; + + if (guard_spawn_Timer <= diff) + { + m_creature->MonsterTextEmote(EMOTE_HATCHES,m_creature->GetGUID(),true); + DoCast(m_creature, SPELL_SUMMON_SWARM_GUARD); + guard_spawn_Timer = 25000; + } else guard_spawn_Timer -= diff; + + if (enrage_Timer <= diff) + { + if (m_creature->HasAura(SPELL_ENRAGE,0)) + return; + + float x, y, z, o; + m_creature->GetHomePosition(x, y, z, o); + if (z < 24) + if (!m_creature->IsNonMeleeSpellCasted(false)) + DoCast(m_creature, SPELL_ENRAGE, true); + + enrage_Timer = 5000; + } else enrage_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_elder_nadox(Creature* pCreature) +{ + return new boss_elder_nadoxAI(pCreature); +} + +#define SPELL_SPRINT 56354 + +struct TRINITY_DLL_DECL mob_ahnkahar_nerubianAI : public ScriptedAI +{ + mob_ahnkahar_nerubianAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance *pInstance; + uint32 sprint_Timer; + + void Reset() + { + if (m_creature->GetEntry() == 30176) //magic numbers are bad! + DoCast(m_creature, SPELL_GUARDIAN_AURA, true); + sprint_Timer = 10000; + } + + void JustDied(Unit *killer) + { + if (m_creature->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) + DeadAhnkaharGuardian = true; + } + + void EnterCombat(Unit *who){} + + void UpdateAI(const uint32 diff) + { + if (m_creature->GetEntry() == 30176) //magic numbers are bad! + m_creature->RemoveAurasDueToSpell(SPELL_GUARDIAN_AURA); + + if (pInstance) + { + if (pInstance->GetData(DATA_ELDER_NADOX_EVENT) != IN_PROGRESS) + { + m_creature->DealDamage(m_creature,m_creature->GetHealth()); + m_creature->RemoveCorpse(); + } + } + + if (!UpdateVictim()) + return; + + if (sprint_Timer <= diff) + { + DoCast(m_creature, SPELL_SPRINT); + sprint_Timer = 25000; + } else sprint_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL 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_mob_ahnkahar_nerubian(Creature* pCreature) +{ + return new mob_ahnkahar_nerubianAI(pCreature); +} + +CreatureAI* GetAI_mob_nadox_eggs(Creature* _Creature) +{ + return new mob_nadox_eggsAI(_Creature); +} + +void AddSC_boss_elder_nadox() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_elder_nadox"; + newscript->GetAI = &GetAI_boss_elder_nadox; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ahnkahar_nerubian"; + newscript->GetAI = &GetAI_mob_ahnkahar_nerubian; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_nadox_eggs"; + newscript->GetAI = &GetAI_mob_nadox_eggs; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/ahnkahet/boss_herald_volazj.cpp b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_herald_volazj.cpp new file mode 100644 index 00000000000..63a2a16634d --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_herald_volazj.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_herald_volazj +SDAuthor: Tartalo +SD%Complete: 20 +SDComment: Coded all but Insanity +SDCategory: Ahn'kahet +EndScriptData */ + +#include "ScriptedPch.h" +#include "ahnkahet.h" + +enum Spells +{ + SPELL_INSANITY = 57496, //Dummy + INSANITY_VISUAL = 57561, + SPELL_MIND_FLAY = 57941, + H_SPELL_MIND_FLAY = 59974, + SPELL_SHADOW_BOLT_VOLLEY = 57942, + H_SPELL_SHADOW_BOLT_VOLLEY = 59975, + SPELL_SHIVER = 57949, + H_SPELL_SHIVER = 59978 +}; + +//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 +{ + ACHIEVEMENT_QUICK_DEMISE = 1862 +}; + +struct TRINITY_DLL_DECL boss_volazjAI : public ScriptedAI +{ + boss_volazjAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance *pInstance; + + uint32 uiMindFlayTimer; + uint32 uiShadowBoltVolleyTimer; + uint32 uiShiverTimer; + uint32 uiEncounterTimer; + + void Reset() + { + uiEncounterTimer = 0; + uiMindFlayTimer = 8000; + uiShadowBoltVolleyTimer = 5000; + uiShiverTimer = 15000; + + if (pInstance) + pInstance->SetData(DATA_HERALD_VOLAZJ, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_HERALD_VOLAZJ, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiMindFlayTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_MIND_FLAY, H_SPELL_MIND_FLAY)); + uiMindFlayTimer = 20000; + } else uiMindFlayTimer -= diff; + + if (uiShadowBoltVolleyTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_SHADOW_BOLT_VOLLEY, H_SPELL_SHADOW_BOLT_VOLLEY)); + uiShadowBoltVolleyTimer = 5000; + } else uiShadowBoltVolleyTimer -= diff; + + if (uiShiverTimer <= diff) + { + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, DUNGEON_MODE(SPELL_SHIVER, H_SPELL_SHIVER)); + uiShiverTimer = 15000; + } else uiShiverTimer -= diff; + + uiEncounterTimer += diff; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH_1, m_creature); + + if (pInstance) + pInstance->SetData(DATA_HERALD_VOLAZJ, DONE); + + AchievementEntry const *AchievQuickDemise = GetAchievementStore()->LookupEntry(ACHIEVEMENT_QUICK_DEMISE); + Map* pMap = m_creature->GetMap(); + + if (IsHeroic() && uiEncounterTimer < 120000 && pMap && pMap->IsDungeon() && AchievQuickDemise) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievQuickDemise); + } + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_volazj(Creature* pCreature) +{ + return new boss_volazjAI (pCreature); +} + +void AddSC_boss_volazj() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_volazj"; + newscript->GetAI = &GetAI_boss_volazj; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/ahnkahet/boss_jedoga_shadowseeker.cpp b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_jedoga_shadowseeker.cpp new file mode 100644 index 00000000000..76f9e32a007 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_jedoga_shadowseeker.cpp @@ -0,0 +1,594 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_jedoga_shadowseeker +SDAuthor: WarHead +SD%Complete: 100% +SDComment: Complete - BUT THE TRIGGER NEEDS DATA WHETHER THE PRISON OF TALDARAM IS OFFLINE ! +SDCategory: Ahn'kahet +EndScriptData */ + +#include "ScriptedPch.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 +}; + +float JEDOGA_POS[2][4] = +{ + {372.330994f, -705.278015f, -0.624178f, 5.427970f}, + {372.330994f, -705.278015f, -16.179716f, 5.427970f} +}; + +struct TRINITY_DLL_DECL boss_jedoga_shadowseekerAI : public ScriptedAI +{ + boss_jedoga_shadowseekerAI(Creature* c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + FirstTime = true; + predone = false; + } + + ScriptedInstance* pInstance; + + uint32 uiOpFerTimer, + uiCycloneTimer, + uiBoltTimer, + uiThunderTimer; + + bool predone, + bOpFerok, + bOnGround, + bOpFerokFail, + bCanDown; + + bool FirstTime; + + void Reset() + { + uiOpFerTimer = urand(15000,20000); + + uiCycloneTimer = 3000; + uiBoltTimer = 7000; + uiThunderTimer = 12000; + + bOpFerok = false; + bOpFerokFail = false; + bOnGround = false; + bCanDown = false; + + if (pInstance) + { + if (!FirstTime) + pInstance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, FAIL); + + pInstance->SetData64(DATA_PL_JEDOGA_TARGET, 0); + pInstance->SetData64(DATA_ADD_JEDOGA_OPFER, 0); + pInstance->SetData(DATA_JEDOGA_RESET_INITIANDS, 0); + } + MoveUp(); + + FirstTime = false; + } + + void EnterCombat(Unit* who) + { + if (!pInstance || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == 30181)) + return; + + DoScriptText(TEXT_AGGRO, m_creature); + m_creature->SetInCombatWithZone(); + pInstance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, IN_PROGRESS); + } + + void AttackStart(Unit* who) + { + if (!who || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == 30181)) + 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), m_creature); + } + + void JustDied(Unit* Killer) + { + DoScriptText(TEXT_DEATH, m_creature); + if (pInstance) + pInstance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, DONE); + } + + void MoveInLineOfSight(Unit* who) + { + if (!pInstance || !who || (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == 30181)) + return; + + if (!predone && who->GetTypeId() == TYPEID_PLAYER && m_creature->GetDistance(who) < 100.0f) + { + DoScriptText(RAND(TEXT_PREACHING_1, TEXT_PREACHING_2, TEXT_PREACHING_3, TEXT_PREACHING_4, TEXT_PREACHING_5), m_creature); + predone = true; + } + + if (pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS || !bOnGround) + return; + + if (!m_creature->getVictim() && who->isTargetableForAttack() && m_creature->IsHostileTo(who) && who->isInAccessiblePlaceFor(m_creature)) + { + float attackRadius = m_creature->GetAttackDistance(who); + if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) + { + if (!m_creature->getVictim()) + { + who->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); + AttackStart(who); + } + else if (m_creature->GetMap()->IsDungeon()) + { + who->SetInCombatWith(m_creature); + m_creature->AddThreat(who, 0.0f); + } + } + } + } + + void MoveDown() + { + if (!pInstance) + return; + + bOpFerokFail = false; + + pInstance->SetData(DATA_JEDOGA_TRIGGER_SWITCH, 0); + m_creature->GetMotionMaster()->MovePoint(1, JEDOGA_POS[1][0], JEDOGA_POS[1][1], JEDOGA_POS[1][2]); + + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_JUMPING); + m_creature->SendMonsterMove(JEDOGA_POS[1][0], JEDOGA_POS[1][1], JEDOGA_POS[1][2], 0, MOVEFLAG_JUMP, 0); + m_creature->Relocate(JEDOGA_POS[1][0], JEDOGA_POS[1][1], JEDOGA_POS[1][2], JEDOGA_POS[1][3]); + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); + + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + + m_creature->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + + bOnGround = true; + + if (UpdateVictim()) + { + AttackStart(m_creature->getVictim()); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + else + { + if (Unit* pTarget = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_PL_JEDOGA_TARGET))) + { + AttackStart(pTarget); + pInstance->SetData(DATA_JEDOGA_RESET_INITIANDS, 0); + if (pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS) + EnterCombat(pTarget); + } + else if (!m_creature->isInCombat()) + EnterEvadeMode(); + } + } + + void MoveUp() + { + if (!pInstance) + return; + + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + + m_creature->AttackStop(); + m_creature->RemoveAllAuras(); + m_creature->LoadCreaturesAddon(); + m_creature->GetMotionMaster()->MovePoint(0, JEDOGA_POS[0][0], JEDOGA_POS[0][1], JEDOGA_POS[0][2]); + + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_JUMPING); + m_creature->SendMonsterMove(JEDOGA_POS[0][0], JEDOGA_POS[0][1], JEDOGA_POS[0][2], 0, MOVEFLAG_JUMP, 0); + m_creature->Relocate(JEDOGA_POS[0][0], JEDOGA_POS[0][1], JEDOGA_POS[0][2], JEDOGA_POS[0][3]); + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->StopMoving(); + + pInstance->SetData(DATA_JEDOGA_TRIGGER_SWITCH, 1); + if (pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) OpferRufen(); + + bOnGround = false; + uiOpFerTimer = urand(15000,30000); + } + + void OpferRufen() + { + if (!pInstance) + return; + + uint64 opfer = pInstance->GetData64(DATA_ADD_JEDOGA_INITIAND); + + if (opfer) + { + DoScriptText(RAND(TEXT_SACRIFICE_1_1, TEXT_SACRIFICE_1_2), m_creature); + pInstance->SetData64(DATA_ADD_JEDOGA_OPFER, opfer); + } else + bCanDown = true; + } + + void Opfern() + { + DoScriptText(RAND(TEXT_SACRIFICE_2_1, TEXT_SACRIFICE_2_2), m_creature); + + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_GIFT_OF_THE_HERALD, false); + + bOpFerok = false; + bCanDown = true; + } + + void UpdateAI(const uint32 diff) + { + if (!pInstance) + return; + + if (pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS && pInstance->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(m_creature, DUNGEON_MODE(SPELL_CYCLONE_STRIKE, SPELL_CYCLONE_STRIKE_H), false); + uiCycloneTimer = urand(15000,30000); + } else uiCycloneTimer -= diff; + + if (uiBoltTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + m_creature->CastSpell(pTarget, DUNGEON_MODE(SPELL_LIGHTNING_BOLT, SPELL_LIGHTNING_BOLT_H), false); + + uiBoltTimer = urand(15000,30000); + } else uiBoltTimer -= diff; + + if (uiThunderTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + m_creature->CastSpell(pTarget, DUNGEON_MODE(SPELL_THUNDERSHOCK, SPELL_THUNDERSHOCK_H), false); + + uiThunderTimer = urand(15000,30000); + } else uiThunderTimer -= diff; + + if (uiOpFerTimer <= diff) + MoveUp(); + else + uiOpFerTimer -= diff; + + DoMeleeAttackIfReady(); + } + } +}; + +struct TRINITY_DLL_DECL mob_jedoga_initiandAI : public ScriptedAI +{ + mob_jedoga_initiandAI(Creature* c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 checktimer; + + bool walking; + + void Reset() + { + if (!pInstance) + return; + + walking = false; + checktimer = 2000; + + if (pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS) + { + m_creature->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + else + { + DoCast(m_creature, SPELL_SPHERE_VISUAL, false); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + } + + void JustDied(Unit* Killer) + { + if (!Killer || !pInstance) return; + + if (walking) + { + Creature* boss = m_creature->GetMap()->GetCreature(pInstance->GetData64(DATA_JEDOGA_SHADOWSEEKER)); + if (boss && !CAST_AI(boss_jedoga_shadowseekerAI, boss->AI())->bOpFerok) CAST_AI(boss_jedoga_shadowseekerAI, boss->AI())->bOpFerokFail = true; + + if (Killer->GetTypeId() == TYPEID_PLAYER) pInstance->SetData(DATA_INITIAND_KILLED, 1); + pInstance->SetData64(DATA_ADD_JEDOGA_OPFER, 0); + + walking = false; + } + if (Killer->GetTypeId() == TYPEID_PLAYER) pInstance->SetData64(DATA_PL_JEDOGA_TARGET, Killer->GetGUID()); + } + + void EnterCombat(Unit* who) + { + if ((pInstance && pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !who) return; + } + + void AttackStart(Unit* victim) + { + if ((pInstance && pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !victim) return; + + ScriptedAI::AttackStart(victim); + } + + void MoveInLineOfSight(Unit* who) + { + if ((pInstance && pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS) || !who) return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) + { + if (uiType != POINT_MOTION_TYPE || !pInstance) return; + + switch(uiPointId) + { + case 1: + { + Creature* boss = m_creature->GetMap()->GetCreature(pInstance->GetData64(DATA_JEDOGA_SHADOWSEEKER)); + if (boss) + { + CAST_AI(boss_jedoga_shadowseekerAI, boss->AI())->bOpFerok = true; + CAST_AI(boss_jedoga_shadowseekerAI, boss->AI())->bOpFerokFail = false; + m_creature->Kill(m_creature); + } + } + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (pInstance && checktimer <= diff) + { + if (m_creature->GetGUID() == pInstance->GetData64(DATA_ADD_JEDOGA_OPFER) && !walking) + { + m_creature->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + + float distance = m_creature->GetDistance(JEDOGA_POS[1][0], JEDOGA_POS[1][1], JEDOGA_POS[1][2]); + + if (distance < 9.0f) + m_creature->SetSpeed(MOVE_WALK, 0.5f, true); + else if (distance < 15.0f) + m_creature->SetSpeed(MOVE_WALK, 0.75f, true); + else if (distance < 20.0f) + m_creature->SetSpeed(MOVE_WALK, 1.0f, true); + + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MovePoint(1, JEDOGA_POS[1][0], JEDOGA_POS[1][1], JEDOGA_POS[1][2]); + walking = true; + } + if (!walking) + { + if (pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) != IN_PROGRESS && m_creature->HasAura(SPELL_SPHERE_VISUAL)) + { + m_creature->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, false); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + if (pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == IN_PROGRESS && !m_creature->HasAura(SPELL_SPHERE_VISUAL)) + { + DoCast(m_creature, SPELL_SPHERE_VISUAL, false); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + } + } + checktimer = 2000; + } else checktimer -= diff; + + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +// ------------------------------------------------------------------------------------------------------------ +// Jedogas Aufseher - Entry: 30181 +// ------------------------------------------------------------------------------------------------------------ +enum AufseherSpell +{ + SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_1 = 60342, + SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_2 = 56312 +}; + +struct TRINITY_DLL_DECL npc_jedogas_aufseher_triggerAI : public Scripted_NoMovementAI +{ + npc_jedogas_aufseher_triggerAI(Creature* c) : Scripted_NoMovementAI(c) + { + pInstance = c->GetInstanceData(); + c->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); + c->setFaction(35); + removed = false; + removed2 = false; + casted = false; + casted2 = false; + } + + ScriptedInstance* pInstance; + + bool removed, + removed2, + casted, + casted2; + + void Reset() {} + void EnterCombat(Unit* who) {} + void AttackStart(Unit* victim) {} + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (!pInstance) + return; + + if (!removed && m_creature->GetPositionX() > 440.0f) + { /* NEEDS DATA WHETHER THE PRISON OF TALDARAM IS OFFLINE ! + if (pInstance->GetData(EVENT_VORRICHTUNGEN)) + { + m_creature->InterruptNonMeleeSpells(true); + removed = true; + return; + }*/ + if (pInstance->GetData(DATA_PRINCE_TALDARAM_EVENT) == DONE) + { + m_creature->InterruptNonMeleeSpells(true); + removed = true; + return; + } + if (!casted) + { + DoCast(m_creature, SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_1, false); + casted = true; + } + } + if (!removed2 && m_creature->GetPositionX() < 440.0f) + { + if (!casted2 && pInstance->GetData(DATA_JEDOGA_TRIGGER_SWITCH)) + { + DoCast(m_creature, SPELL_BEAM_VISUAL_JEDOGAS_AUFSEHER_2, false); + casted2 = true; + } + if (casted2 && !pInstance->GetData(DATA_JEDOGA_TRIGGER_SWITCH)) + { + m_creature->InterruptNonMeleeSpells(true); + casted2 = false; + } + if (!removed2 && pInstance->GetData(DATA_JEDOGA_SHADOWSEEKER_EVENT) == DONE) + { + m_creature->InterruptNonMeleeSpells(true); + removed2 = true; + } + } + } +}; + +CreatureAI* GetAI_boss_jedoga_shadowseeker(Creature* pCreature) +{ + return new boss_jedoga_shadowseekerAI (pCreature); +} + +CreatureAI* GetAI_mob_jedoga_initiand(Creature* pCreature) +{ + return new mob_jedoga_initiandAI (pCreature); +} + +CreatureAI* GetAI_npc_jedogas_aufseher_trigger(Creature* pCreature) +{ + return new npc_jedogas_aufseher_triggerAI (pCreature); +} + +void AddSC_boss_jedoga_shadowseeker() +{ + Script* newscript; + + newscript = new Script; + newscript->Name = "boss_jedoga_shadowseeker"; + newscript->GetAI = &GetAI_boss_jedoga_shadowseeker; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_jedoga_initiand"; + newscript->GetAI = &GetAI_mob_jedoga_initiand; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_jedogas_aufseher_trigger"; + newscript->GetAI = &GetAI_npc_jedogas_aufseher_trigger; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/ahnkahet/boss_prince_taldaram.cpp b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_prince_taldaram.cpp new file mode 100644 index 00000000000..3bc5c8e8ba9 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/ahnkahet/boss_prince_taldaram.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_prince_taldaram +SDAuthor: Tartalo & tlexii +SD%Complete: 0 +SDComment: +SDCategory: Ahn'kahet +EndScriptData */ + +#include "ScriptedPch.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.7 +#define DATA_GROUND_POSITION_Z 11.4 +enum Achievements +{ + ACHIEVEMENT_THE_PARTY_IS_OVER = 1861 +}; +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 +}; + +struct TRINITY_DLL_DECL boss_taldaramAI : public ScriptedAI +{ + boss_taldaramAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + uint32 uiBloodthirstTimer; + uint32 uiVanishTimer; + uint32 uiWaitTimer; + uint32 uiEmbraceTimer; + uint32 uiEmbraceTakenDamage; + uint32 uiFlamesphereTimer; + uint32 uiPhaseTimer; + + uint64 uiSphereGuids[2]; + + Unit *pEmbraceTarget; + Unit *pSphereTarget; + + Creature* pSpheres[3]; + + CombatPhase Phase; + + ScriptedInstance* pInstance; + + void Reset() + { + uiBloodthirstTimer = 10000; + uiVanishTimer = (25 + rand()%10)*1000; + uiEmbraceTimer = 20000; + uiFlamesphereTimer = 5000; + uiEmbraceTakenDamage = 0; + Phase = NORMAL; + uiPhaseTimer = 0; + pEmbraceTarget = NULL; + if (pInstance) + pInstance->SetData(DATA_PRINCE_TALDARAM_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + if (pInstance) + pInstance->SetData(DATA_PRINCE_TALDARAM_EVENT, IN_PROGRESS); + DoScriptText(SAY_AGGRO, m_creature); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + if (uiPhaseTimer <= diff) + { + switch (Phase) + { + case CASTING_FLAME_SPHERES: + //DoCast(m_creature, SPELL_FLAME_SPHERE_SUMMON_1); + pSpheres[0] = DoSpawnCreature(CREATURE_FLAME_SPHERE, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); + 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(m_creature, H_SPELL_FLAME_SPHERE_SUMMON_1); + pSpheres[1] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_1, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); + //DoCast(m_creature, H_SPELL_FLAME_SPHERE_SUMMON_2); + pSpheres[2] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_2, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); + 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(pEmbraceTarget) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->SetSpeed(MOVE_WALK, 2.0f, true); + m_creature->GetMotionMaster()->MoveChase(pEmbraceTarget); + } + Phase = VANISHED; + uiPhaseTimer = 1300; + break; + case VANISHED: + if(pEmbraceTarget) + DoCast(pEmbraceTarget, DUNGEON_MODE(SPELL_EMBRACE_OF_THE_VAMPYR, H_SPELL_EMBRACE_OF_THE_VAMPYR)); + m_creature->GetMotionMaster()->Clear(); + m_creature->SetSpeed(MOVE_WALK, 1.0f, true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + Phase = FEEDING; + uiPhaseTimer = 20000; + break; + case FEEDING: + Phase = NORMAL; + uiPhaseTimer = 0; + pEmbraceTarget = NULL; + break; + case NORMAL: + if (uiBloodthirstTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_BLOODTHIRST); + uiBloodthirstTimer = 10000; + } else uiBloodthirstTimer -= diff; + + if (uiFlamesphereTimer <= diff) + { + DoCast(m_creature, SPELL_CONJURE_FLAME_SPHERE); + Phase = CASTING_FLAME_SPHERES; + uiPhaseTimer = 3000 + diff; + uiFlamesphereTimer = 15000; + } else uiFlamesphereTimer -= diff; + + if (uiVanishTimer <= diff) + { + //Count alive players + Unit *pTarget = NULL; + std::list<HostilReference *> t_list = m_creature->getThreatManager().getThreatList(); + std::vector<Unit *> target_list; + for (std::list<HostilReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + pTarget = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + // exclude pets & totems + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && pTarget->isAlive()) + target_list.push_back(pTarget); + pTarget = 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), m_creature); + DoCast(m_creature, SPELL_VANISH); + Phase = JUST_VANISHED; + uiPhaseTimer = 500; + pEmbraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); + } + uiVanishTimer = urand(25000,35000); + } else uiVanishTimer -= diff; + + DoMeleeAttackIfReady(); + break; + } + } else uiPhaseTimer -= diff; + } + + void DamageTaken(Unit* done_by, uint32 &damage) + { + if (Phase == FEEDING && pEmbraceTarget && pEmbraceTarget->isAlive()) + { + uiEmbraceTakenDamage += damage; + if (uiEmbraceTakenDamage > DUNGEON_MODE(DATA_EMBRACE_DMG, H_DATA_EMBRACE_DMG)) + { + Phase = NORMAL; + uiPhaseTimer = 0; + pEmbraceTarget = NULL; + m_creature->CastStop(); + } + } + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + { + pInstance->SetData(DATA_PRINCE_TALDARAM_EVENT, DONE); + + //The Party's Over achievement: + AchievementEntry const *AchievThePartyIsOver = GetAchievementStore()->LookupEntry(ACHIEVEMENT_THE_PARTY_IS_OVER); + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon() && IsHeroic() && AchievThePartyIsOver) + { + Map::PlayerList const &players = pMap->GetPlayers(); + if (players.getSize() < 5) + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievThePartyIsOver); + } + } + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + if (Phase == FEEDING && pEmbraceTarget && victim == pEmbraceTarget) + { + Phase = NORMAL; + uiPhaseTimer = 0; + pEmbraceTarget = NULL; + } + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), m_creature); + } + + bool CheckSpheres() + { + if(!pInstance) + return false; + uiSphereGuids[0] = pInstance->GetData64(DATA_SPHERE1); + uiSphereGuids[1] = pInstance->GetData64(DATA_SPHERE2); + + GameObject *pSpheres[2]; + for (uint8 i=0; i < 2; ++i) + { + pSpheres[i] = pInstance->instance->GetGameObject(uiSphereGuids[i]); + if (!pSpheres[i]) + return false; + if (pSpheres[i]->GetGoState() != GO_STATE_ACTIVE) + return false; + } + RemovePrison(); + return true; + } + + void RemovePrison() + { + if(!pInstance) + return; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveAurasDueToSpell(SPELL_BEAM_VISUAL); + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); + m_creature->SetHomePosition(m_creature->GetPositionX(), m_creature->GetPositionY(), DATA_GROUND_POSITION_Z, m_creature->GetOrientation()); + uint64 prison_GUID = pInstance->GetData64(DATA_PRINCE_TALDARAM_PLATFORM); + pInstance->HandleGameObject(prison_GUID,true); + } +}; + +struct TRINITY_DLL_DECL mob_taldaram_flamesphereAI : public ScriptedAI +{ + mob_taldaram_flamesphereAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiDespawnTimer; + ScriptedInstance* pInstance; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); + m_creature->setFaction(16); + m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); + DoCast(m_creature, SPELL_FLAME_SPHERE_VISUAL); + DoCast(m_creature, SPELL_FLAME_SPHERE_SPAWN_EFFECT); + DoCast(m_creature, DUNGEON_MODE(SPELL_FLAME_SPHERE_PERIODIC, H_SPELL_FLAME_SPHERE_PERIODIC)); + uiDespawnTimer = 10000; + } + + void EnterCombat(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + + void JustDied(Unit* slayer) + { + DoCast(m_creature, SPELL_FLAME_SPHERE_DEATH_EFFECT); + } + + void UpdateAI(const uint32 diff) + { + if (uiDespawnTimer <= diff) + m_creature->DisappearAndDie(); + else + uiDespawnTimer -= diff; + } +}; + +CreatureAI* GetAI_boss_taldaram(Creature* pCreature) +{ + return new boss_taldaramAI (pCreature); +} + +CreatureAI* GetAI_mob_taldaram_flamesphere(Creature* pCreature) +{ + return new mob_taldaram_flamesphereAI (pCreature); +} + +bool GOHello_prince_taldaram_sphere(Player *pPlayer, GameObject *pGO) +{ + ScriptedInstance *pInstance = pGO->GetInstanceData(); + + Creature *pPrinceTaldaram = Unit::GetCreature(*pGO, pInstance ? pInstance->GetData64(DATA_PRINCE_TALDARAM) : 0); + if (pPrinceTaldaram && pPrinceTaldaram->isAlive()) + { + // maybe these are hacks :( + pGO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGO->SetGoState(GO_STATE_ACTIVE); + + switch(pGO->GetEntry()) + { + case 193093: pInstance->SetData(DATA_SPHERE1_EVENT,IN_PROGRESS); break; + case 193094: pInstance->SetData(DATA_SPHERE2_EVENT,IN_PROGRESS); break; + } + + CAST_AI(boss_taldaramAI, pPrinceTaldaram->AI())->CheckSpheres(); + } + return true; +} + +void AddSC_boss_taldaram() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_taldaram"; + newscript->GetAI = &GetAI_boss_taldaram; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_taldaram_flamesphere"; + newscript->GetAI = &GetAI_mob_taldaram_flamesphere; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "prince_taldaram_sphere"; + newscript->pGOHello = &GOHello_prince_taldaram_sphere; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/ahnkahet/instance_ahnkahet.cpp b/src/scripts/northrend/azjol_nerub/ahnkahet/instance_ahnkahet.cpp new file mode 100644 index 00000000000..e4cc5d2e422 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/ahnkahet/instance_ahnkahet.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Instance_Azjol_Nerub +SD%Complete: 0 +SDComment: +SDCategory: Azjol Nerub +EndScriptData */ + +#include "ScriptedPch.h" +#include "ahnkahet.h" + +#define MAX_ENCOUNTER 5 +#define MAX_JEDOGA_INITIANDS 15 + +#define AchievementVolunteerWork 2056 + +/* Ahn'kahet encounters: +0 - Elder Nadox +1 - Prince Taldaram +2 - Jedoga Shadowseeker +3 - Herald Volazj +4 - Amanitar (Heroic only) +*/ + +struct TRINITY_DLL_DECL instance_ahnkahet : public ScriptedInstance +{ + instance_ahnkahet(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + 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<uint64> InitiandGUIDs; + uint64 JedogaSacrifices; + uint64 JedogaTarget; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + uint32 spheres[2]; + + uint8 InitiandCnt, + switchtrigger, + initiandkilled; + + 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; + initiandkilled = 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* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case 29309: Elder_Nadox = pCreature->GetGUID(); break; + case 29308: Prince_Taldaram = pCreature->GetGUID(); break; + case 29310: Jedoga_Shadowseeker = pCreature->GetGUID(); break; + case 29311: Herald_Volazj = pCreature->GetGUID(); break; + case 30258: Amanitar = pCreature->GetGUID(); break; + case 30114: InitiandGUIDs.insert(pCreature->GetGUID()); break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case 193564: Prince_TaldaramPlatform = pGo->GetGUID(); + if (m_auiEncounter[1] == DONE) HandleGameObject(NULL,true,pGo); break; + case 193093: Prince_TaldaramSpheres[0] = pGo->GetGUID(); + if (spheres[0] == IN_PROGRESS) + { + pGo->SetGoState(GO_STATE_ACTIVE); + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + } + else pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + break; + case 193094: Prince_TaldaramSpheres[1] = pGo->GetGUID(); + if (spheres[1] == IN_PROGRESS) + { + pGo->SetGoState(GO_STATE_ACTIVE); + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + } + else pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + break; + case 192236: Prince_TaldaramGate = pGo->GetGUID(); // Web gate past Prince Taldaram + if (m_auiEncounter[1] == DONE)HandleGameObject(NULL,true,pGo);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<uint64> vInitiands; + vInitiands.clear(); + for (std::set<uint64>::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<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + { + Creature* cr = instance->GetCreature(*itr); + if (cr && cr->isAlive()) + { + cr->SetVisibility(VISIBILITY_OFF); + cr->setDeathState(JUST_DIED); + cr->RemoveCorpse(); + } + } + if (!initiandkilled && instance->IsHeroic()) + DoCompleteAchievement(AchievementVolunteerWork); + } + break; + case DATA_HERALD_VOLAZJ: m_auiEncounter[3] = data; break; + case DATA_AMANITAR: 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_INITIAND_KILLED: initiandkilled = data; break; + case DATA_JEDOGA_RESET_INITIANDS: + for (std::set<uint64>::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: 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<uint64>::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; + case DATA_INITIAND_KILLED: return initiandkilled; + } + 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; + } +}; + +InstanceData* GetInstanceData_instance_ahnkahet(Map* pMap) +{ + return new instance_ahnkahet(pMap); +} + +void AddSC_instance_ahnkahet() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_ahnkahet"; + newscript->GetInstanceData = &GetInstanceData_instance_ahnkahet; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/azjol_nerub/azjol_nerub.h b/src/scripts/northrend/azjol_nerub/azjol_nerub/azjol_nerub.h new file mode 100644 index 00000000000..df02f9e13d3 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/azjol_nerub/azjol_nerub.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DEF_AZJOL_NERUB_H +#define DEF_AZJOL_NERUB_H + +enum Data64 +{ + DATA_KRIKTHIR_THE_GATEWATCHER, + DATA_HADRONOX, + DATA_ANUBARAK, + DATA_WATCHER_GASHRA, + DATA_WATCHER_SILTHIK, + DATA_WATCHER_NARJIL +}; +enum Data +{ + DATA_KRIKTHIR_THE_GATEWATCHER_EVENT, + DATA_HADRONOX_EVENT, + DATA_ANUBARAK_EVENT +}; + +#endif diff --git a/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_anubarak.cpp b/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_anubarak.cpp new file mode 100644 index 00000000000..81d8a6daae9 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_anubarak.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_anubarak +SD%Complete: 90 % +SDComment: Says are not implemented. +SDCategory: Azjol Nerub +EndScriptData */ + + +#include "ScriptedPch.h" +#include "azjol_nerub.h" + +enum Spells +{ + SPELL_CARRION_BEETLES = 53520, + SPELL_SUMMON_CARRION_BEETLES = 53521, + SPELL_LEECHING_SWARM = 53467, + + SPELL_IMPALE = 53454, + H_SPELL_IMPALE = 59446, + + SPELL_POUND = 53472, + H_SPELL_POUND = 59433, + + SPELL_SUBMERGE = 53421, +}; + +enum Creatures +{ + CREATURE_GUARDIAN = 29216, + CREATURE_VENOMANCER = 29217, + CREATURE_DATTER = 29213 +}; + +// not in db +enum Yells +{ + SAY_INTRO = -1601010, + SAY_AGGRO = -1601000, + SAY_SLAY_1 = -1601001, + SAY_SLAY_2 = -1601002, + SAY_SLAY_3 = -1601003, + SAY_LOCUST_1 = -1601005, + SAY_LOCUST_2 = -1601006, + SAY_LOCUST_3 = -1601007, + SAY_SUBMERGE_1 = -1601008, + SAY_SUBMERGE_2 = -1601009, + SAY_DEATH = -1601004 +}; +#define SPAWNPOINT_Z 224.3 + +float SpawnPoint[2][2] = +{ + {550.7, 282.8}, + {551.1, 229.4}, +}; + +struct TRINITY_DLL_DECL boss_anub_arakAI : public ScriptedAI +{ + boss_anub_arakAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance *pInstance; + + bool Channeling; + bool HeroicMode; + bool Summoned_Guardian; + bool Summoned_Venomancer; + bool Summoned_Datter; + uint32 Phase; + uint32 Phase_Time; + + uint32 SPELL_CARRION_BEETLES_Timer; + uint32 SPELL_LEECHING_SWARM_Timer; + uint32 SPELL_IMPALE_Timer; + uint32 SPELL_POUND_Timer; + uint32 SPELL_SUBMERGE_Timer; + uint32 UNDERGROUND_Timer; + uint32 VENOMANCER_Timer; + uint32 DATTER_Timer; + + void Reset() + { + + SPELL_CARRION_BEETLES_Timer = 8000; + SPELL_LEECHING_SWARM_Timer = 20000; + SPELL_IMPALE_Timer = 9000; + SPELL_POUND_Timer = 15000; + + Phase = 0; + Phase_Time = 0; + Channeling = false; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAura(SPELL_SUBMERGE); + + if (pInstance) + pInstance->SetData(DATA_ANUBARAK_EVENT, NOT_STARTED); + } + + + void EnterCombat(Unit *pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_ANUBARAK_EVENT, IN_PROGRESS); + } + + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (Channeling == true) + { + for (uint8 i = 0; i < 4; ++i) + DoCast(m_creature->getVictim(), SPELL_SUMMON_CARRION_BEETLES, true); + Channeling = false; + } + + if (Phase == 1) + { + if (SPELL_IMPALE_Timer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + m_creature->CastSpell(pTarget, DUNGEON_MODE(SPELL_IMPALE,H_SPELL_IMPALE), true); + + SPELL_IMPALE_Timer = 9000; + } else SPELL_IMPALE_Timer -= diff; + + if (!Summoned_Guardian) + { + for (uint8 i = 0; i < 2; ++i) + { + if (Creature *Guardian = m_creature->SummonCreature(CREATURE_GUARDIAN,SpawnPoint[i][0],SpawnPoint[i][1],SPAWNPOINT_Z,0,TEMPSUMMON_CORPSE_DESPAWN,0)) + { + Guardian->AddThreat(m_creature->getVictim(), 0.0f); + DoZoneInCombat(Guardian); + } + } + Summoned_Guardian = true; + } + + if(!Summoned_Venomancer) + { + if (VENOMANCER_Timer <= diff) + { + if (Phase_Time > 1) + { + for (uint8 i = 0; i < 2; ++i) + { + if (Creature *Venomancer = m_creature->SummonCreature(CREATURE_VENOMANCER,SpawnPoint[i][0],SpawnPoint[i][1],SPAWNPOINT_Z,0,TEMPSUMMON_CORPSE_DESPAWN,0)) + { + Venomancer->AddThreat(m_creature->getVictim(), 0.0f); + DoZoneInCombat(Venomancer); + } + } + Summoned_Venomancer = true; + } + } else VENOMANCER_Timer -= diff; + } + + if(!Summoned_Datter) + { + if (DATTER_Timer <= diff) + { + if (Phase_Time > 2) + { + for (uint8 i = 0; i < 2; ++i) + { + if (Creature *Datter = m_creature->SummonCreature(CREATURE_DATTER,SpawnPoint[i][0],SpawnPoint[i][1],SPAWNPOINT_Z,0,TEMPSUMMON_CORPSE_DESPAWN,0)) + { + Datter->AddThreat(m_creature->getVictim(), 0.0f); + DoZoneInCombat(Datter); + } + } + Summoned_Datter = true; + } + } else DATTER_Timer -= diff; + } + + if (UNDERGROUND_Timer <= diff) + { + m_creature->RemoveAura(SPELL_SUBMERGE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + Phase = 0; + } else UNDERGROUND_Timer -= diff; + } + + if (Phase == 0) + { + if (SPELL_LEECHING_SWARM_Timer <= diff) + { + DoCast(m_creature, SPELL_LEECHING_SWARM, true); + SPELL_LEECHING_SWARM_Timer = 19000; + } else SPELL_LEECHING_SWARM_Timer -= diff; + + if (SPELL_CARRION_BEETLES_Timer <= diff) + { + Channeling = true; + DoCastVictim(SPELL_CARRION_BEETLES); + SPELL_CARRION_BEETLES_Timer = 25000; + } else SPELL_CARRION_BEETLES_Timer -= diff; + + if (SPELL_POUND_Timer <= diff) + { + DoCastVictim(DUNGEON_MODE(SPELL_POUND, H_SPELL_POUND)); + SPELL_POUND_Timer = 16500; + } else SPELL_POUND_Timer -= diff; + } + + if ((Phase_Time == 0 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 75) + || (Phase_Time == 1 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50) + || (Phase_Time == 2 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 25)) + { + ++Phase_Time; + + Summoned_Guardian = false; + Summoned_Venomancer = false; + Summoned_Datter = false; + + UNDERGROUND_Timer = 40000; + VENOMANCER_Timer = 25000; + DATTER_Timer = 32000; + + DoCast(m_creature, SPELL_SUBMERGE, false); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + + Phase = 1; + } + + if (Phase != 1) + DoMeleeAttackIfReady(); + } + + void JustDied(Unit *pKiller) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_ANUBARAK_EVENT, DONE); + } + + void KilledUnit(Unit *pVictim) + { + if (pVictim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_anub_arak(Creature *pCreature) +{ + return new boss_anub_arakAI (pCreature); +} + +void AddSC_boss_anub_arak() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_anub_arak"; + newscript->GetAI = &GetAI_boss_anub_arak; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_hadronox.cpp b/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_hadronox.cpp new file mode 100644 index 00000000000..1a290b8e7df --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_hadronox.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: Boss hadronox +SDAuthor: WarHead +SD%Complete: 50 +SDComment: No Waves atm and the doors spells are crazy... +SDCategory: +Script Data End */ + +//Phase 0 => Gauntlet Event described below +//Phase 1 => Boss Encounter + +/*When your group enters the main room (the one after the bridge), you will notice a group of 3 Nerubians. +When you engage them, 2 more groups like this one spawn behind the first one - it is important to pull the first group back, +so you don't aggro all 3. Hadronox will be under you, fighting Nerubians. + +This is the timed gauntlet - waves of non-elite spiders + will spawn from the 3 doors located a little above the main room, and will then head down to fight Hadronox. After clearing the + main room, it is recommended to just stay in it, kill the occasional non-elites that will attack you instead of the boss, and wait for + Hadronox to make his way to you. When Hadronox enters the main room, she will web the doors, and no more non-elites will spawn.*/ + +#include "ScriptedPch.h" +#include "azjol_nerub.h" + +#define SPELL_ACID_CLOUD 53400 // Victim +#define SPELL_LEECH_POISON 53030 // Victim +#define SPELL_PIERCE_ARMOR 53418 // Victim +#define SPELL_WEB_GRAB 57731 // Victim +#define SPELL_WEB_FRONT_DOORS 53177 // Self +#define SPELL_WEB_SIDE_DOORS 53185 // Self + +#define SPELL_ACID_CLOUD_H 59419 +#define SPELL_LEECH_POISON_H 59417 +#define SPELL_WEB_GRAB_H 59421 + +struct TRINITY_DLL_DECL boss_hadronoxAI : public ScriptedAI +{ + boss_hadronoxAI(Creature* c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + MaxDistance = 50.0f; + FirstTime = true; + } + + ScriptedInstance* pInstance; + + uint32 acidtimer, + leechtimer, + piercetimer, + grabtimer, + doorstimer, + CheckDistanceTimer; + + bool FirstTime; + + float MaxDistance; + + void Reset() + { + m_creature->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 9.0f); + m_creature->SetFloatValue(UNIT_FIELD_COMBATREACH, 9.0f); + + acidtimer = urand(10000,14000); + leechtimer = urand(3000,9000); + piercetimer = urand(1000,3000); + grabtimer = urand(15000,19000); + doorstimer = urand(20000,30000); + + CheckDistanceTimer = 2000; + + if (pInstance && (pInstance->GetData(DATA_HADRONOX_EVENT) != DONE && !FirstTime)) + pInstance->SetData(DATA_HADRONOX_EVENT, FAIL); + + FirstTime = false; + } + + //when Hadronox kills any enemy (that includes a party member) she will regain 10% of her HP if the target had Leech Poison on + void KilledUnit(Unit* Victim) + { + // not sure if this aura check is correct, I think it is though + if (!Victim || !Victim->HasAura(DUNGEON_MODE(SPELL_LEECH_POISON, SPELL_LEECH_POISON_H)) || !m_creature->isAlive()) + return; + + uint32 health = (m_creature->GetMaxHealth()/100)*10; + + if ((m_creature->GetHealth()+health) >= m_creature->GetMaxHealth()) + m_creature->SetHealth(m_creature->GetMaxHealth()); + else + m_creature->SetHealth(m_creature->GetHealth()+health); + } + + void JustDied(Unit* Killer) + { + if (pInstance) + pInstance->SetData(DATA_HADRONOX_EVENT, DONE); + } + + void EnterCombat(Unit* who) + { + if (pInstance) + pInstance->SetData(DATA_HADRONOX_EVENT, IN_PROGRESS); + m_creature->SetInCombatWithZone(); + } + + void CheckDistance(float dist, const uint32 uiDiff) + { + if (!m_creature->isInCombat()) + return; + + float x=0.0f, y=0.0f, z=0.0f; + m_creature->GetRespawnCoord(x,y,z); + + if (CheckDistanceTimer <= uiDiff) + CheckDistanceTimer = 5000; + else + { + CheckDistanceTimer -= uiDiff; + return; + } + if (m_creature->IsInEvadeMode() || !m_creature->getVictim()) + return; + if (m_creature->GetDistance(x,y,z) > dist) + EnterEvadeMode(); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) return; + + // Without he comes up through the air to players on the bridge after krikthir if players crossing this bridge! + CheckDistance(MaxDistance, diff); + + if (m_creature->HasAura(SPELL_WEB_FRONT_DOORS) || m_creature->HasAura(SPELL_WEB_SIDE_DOORS)) + { + if (IsCombatMovement()) + SetCombatMovement(false); + } + else if (!IsCombatMovement()) + SetCombatMovement(true); + + if (piercetimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_PIERCE_ARMOR); + piercetimer = 8000; + } else piercetimer -= diff; + + if (acidtimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_ACID_CLOUD, SPELL_ACID_CLOUD_H)); + + acidtimer = urand(20000,30000); + } else acidtimer -= diff; + + if (leechtimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_LEECH_POISON, SPELL_LEECH_POISON_H)); + + leechtimer = urand(11000,14000); + } else leechtimer -= diff; + + if (grabtimer <= diff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) // Draws all players (and attacking Mobs) to itself. + DoCast(pTarget, DUNGEON_MODE(SPELL_WEB_GRAB, SPELL_WEB_GRAB_H)); + + grabtimer = urand(15000,30000); + } else grabtimer -= diff; + + if (doorstimer <= diff) + {/* Debuff bleibt auf den Spielern bis zum Tod... + DoCast(m_creature, RAND(SPELL_WEB_FRONT_DOORS, SPELL_WEB_SIDE_DOORS)); + */ + doorstimer = urand(30000,60000); + } else doorstimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_hadronox(Creature* pCreature) +{ + return new boss_hadronoxAI (pCreature); +} + +void AddSC_boss_hadronox() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_hadronox"; + newscript->GetAI = &GetAI_boss_hadronox; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_krikthir_the_gatewatcher.cpp b/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_krikthir_the_gatewatcher.cpp new file mode 100644 index 00000000000..cb50470a2a0 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/azjol_nerub/boss_krikthir_the_gatewatcher.cpp @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_krikthir_the_gatewatcher +SD%Complete: 80 % +SDComment: Find in the future best timers and the event is not implemented. +SDCategory: Azjol Nerub +EndScriptData */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_krik_thir' where entry = ''; +*** SQL END ***/ + +#include "ScriptedPch.h" +#include "azjol_nerub.h" + +enum Spells +{ + SPELL_MIND_FLAY = 52586, + H_SPELL_MIND_FLAY = 59367, + SPELL_CURSE_OF_FATIGUE = 52592, + H_SPELL_CURSE_OF_FATIGUE = 59368, + SPELL_FRENZY = 28747, //maybe 53361 + + SPELL_SUMMON_SKITTERING_SWARMER = 52438, //AOE Effect 140, maybe 52439 + SPELL_SUMMON_SKITTERING_SWARMER_1 = 52439, //Summon 3x 28735 + + H_SPELL_ACID_SPLASH = 59363, + SPELL_ACID_SPLASH = 52446, + + SPELL_CHARGE = 16979,//maybe is another spell + SPELL_BACKSTAB = 52540, + + SPELL_SHADOW_BOLT = 52534, + H_SPELL_SHADOW_BOLT = 59357, + SPELL_SHADOW_NOVA = 52535, + H_SPELL_SHADOW_NOVA = 59358, + + SPELL_STRIKE = 52532, + SPELL_CLEAVE = 49806, + + SPELL_ENRAGE = 52470, + + SPELL_INFECTED_BITE = 52469, + H_SPELL_INFECTED_BITE = 59364, + SPELL_WEB_WRAP = 52086,//the spell is not working propperly + + SPELL_BLINDING_WEBS = 52524, + H_SPELL_BLINDING_WEBS = 59365, + + SPELL_POSION_SPRAY = 52493, + H_SPELL_POSION_SPRAY = 59366, +}; + +enum Mobs +{ + MOB_SKITTERING_SWARMER = 28735, + MOB_SKITTERING_SWARMER_CONTROLLER = 32593, + MOB_SKITTERING_INFECTIOR = 28736, +}; + +enum Yells +{ + SAY_AGGRO = -1601000, + SAY_SLAY_1 = -1601001, + SAY_SLAY_2 = -1601002, + SAY_DEATH = -1601003, + //Not in db + SAY_SEND_GROUP_1 = -1601004, + SAY_SEND_GROUP_2 = -1601005, + SAY_SEND_GROUP_3 = -1601006, + SAY_SWARM_1 = -1601007, + SAY_SWARM_2 = -1601008, + SAY_PREFIGHT_1 = -1601009, + SAY_PREFIGHT_2 = -1601010, + SAY_PREFIGHT_3 = -1601011, +}; +enum Misc +{ + ACHIEVEMENT_WATCH_HIM_DIE = 1296 +}; +struct TRINITY_DLL_DECL boss_krik_thirAI : public ScriptedAI +{ + boss_krik_thirAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 MindFlayTimer; + uint32 CurseFatigueTimer; + uint32 SummonTimer; + + void Reset() + { + MindFlayTimer = 15000; + CurseFatigueTimer = 12000; + + if (pInstance) + pInstance->SetData(DATA_KRIKTHIR_THE_GATEWATCHER_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + Summon(); + SummonTimer = 15000; + + if (pInstance) + pInstance->SetData(DATA_KRIKTHIR_THE_GATEWATCHER_EVENT, IN_PROGRESS); + } + + void Summon() + { + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,566.164,682.087,769.079,2.21657,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,566.164,682.087,769.079,2.21657,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,529.042,706.941,777.298,1.0821,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,529.042,706.941,777.298,1.0821,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,489.975,671.239,772.131,0.261799,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,489.975,671.239,772.131,0.261799,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,488.556,692.95,771.764,4.88692,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,488.556,692.95,771.764,4.88692,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_INFECTIOR,553.34,640.387,777.419,1.20428,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,553.34,640.387,777.419,1.20428,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_INFECTIOR,517.486,706.398,777.335,5.35816,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,517.486,706.398,777.335,5.35816,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_INFECTIOR,504.01,637.693,777.479,0.506145,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,504.01,637.693,777.479,0.506145,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,552.625,706.408,777.177,3.4383,TEMPSUMMON_TIMED_DESPAWN,25000); + m_creature->SummonCreature(MOB_SKITTERING_SWARMER,552.625,706.408,777.177,3.4383,TEMPSUMMON_TIMED_DESPAWN,25000); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (SummonTimer <= diff) + { + Summon(); + SummonTimer = 15000; + } else SummonTimer -= diff; + + if (MindFlayTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_MIND_FLAY, H_SPELL_MIND_FLAY)); + MindFlayTimer = 15000; + } else MindFlayTimer -= diff; + + if (CurseFatigueTimer <= diff) + { + //WowWiki say "Curse of Fatigue-Kirk'thir will cast Curse of Fatigue on 2-3 targets periodically." + Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); + Unit *pTarget_1 = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true); + + DoCast(pTarget, DUNGEON_MODE(SPELL_CURSE_OF_FATIGUE, H_SPELL_CURSE_OF_FATIGUE)); + DoCast(pTarget_1, DUNGEON_MODE(SPELL_CURSE_OF_FATIGUE, H_SPELL_CURSE_OF_FATIGUE)); + + CurseFatigueTimer = 10000; + } else CurseFatigueTimer -= diff; + + if (!m_creature->HasAura(SPELL_FRENZY) && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 10) + DoCast(m_creature, SPELL_FRENZY, true); + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + { + pInstance->SetData(DATA_KRIKTHIR_THE_GATEWATCHER_EVENT, DONE); + //Achievement: Watch him die + AchievementEntry const *AchievWatchHimDie = GetAchievementStore()->LookupEntry(ACHIEVEMENT_WATCH_HIM_DIE); + Map* pMap = m_creature->GetMap(); + Creature *pAdd1, *pAdd2, *pAdd3; + if ((pAdd1 = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_WATCHER_GASHRA))) && pAdd1->isAlive() && + (pAdd2 = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_WATCHER_SILTHIK))) && pAdd2->isAlive() && + (pAdd3 = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_WATCHER_NARJIL))) && pAdd3->isAlive() && + IsHeroic() && pMap && pMap->IsDungeon() && AchievWatchHimDie) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (itr->getSource()) + itr->getSource()->CompletedAchievement(AchievWatchHimDie); + } + } + } + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), m_creature); + } + + void JustSummoned(Creature* summoned) + { + summoned->GetMotionMaster()->MovePoint(m_creature->GetEntry(),m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ()); + } +}; + +struct TRINITY_DLL_DECL npc_skittering_infectorAI : public ScriptedAI +{ + npc_skittering_infectorAI(Creature *c) : ScriptedAI(c) {} + + void JustDied(Unit* killer) + { + //The spell is not working propperly + DoCast(m_creature->getVictim(),DUNGEON_MODE(SPELL_ACID_SPLASH, H_SPELL_ACID_SPLASH), true); + } + +}; + +struct TRINITY_DLL_DECL npc_anub_ar_skirmisherAI : public ScriptedAI +{ + npc_anub_ar_skirmisherAI(Creature *c) : ScriptedAI(c) {} + + uint32 ChargeTimer; + uint32 BackstabTimer; + + void Reset() + { + ChargeTimer = 11000; + BackstabTimer = 7000; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (ChargeTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + DoResetThreat(); + m_creature->AddThreat(pTarget,1.0f); + DoCast(pTarget, SPELL_CHARGE, true); + } + + ChargeTimer = 15000; + } else ChargeTimer -= diff; + + if (BackstabTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_BACKSTAB); + BackstabTimer = 12000; + } else BackstabTimer -= diff; + + DoMeleeAttackIfReady(); + + } +}; + +struct TRINITY_DLL_DECL npc_anub_ar_shadowcasterAI : public ScriptedAI +{ + npc_anub_ar_shadowcasterAI(Creature *c) : ScriptedAI(c) {} + + uint32 ShadowBoltTimer; + uint32 ShadowNovaTimer; + + void Reset() + { + ShadowBoltTimer = 6000; + ShadowNovaTimer = 15000; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (ShadowBoltTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_SHADOW_BOLT, H_SPELL_SHADOW_BOLT), true); + ShadowBoltTimer = 15000; + } else ShadowBoltTimer -= diff; + + if (ShadowNovaTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_SHADOW_NOVA, H_SPELL_SHADOW_NOVA), true); + ShadowNovaTimer = 17000; + } else ShadowNovaTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL npc_anub_ar_warriorAI : public ScriptedAI +{ + npc_anub_ar_warriorAI(Creature *c) : ScriptedAI(c){} + + uint32 CleaveTimer; + uint32 StrikeTimer; + + void Reset() + { + CleaveTimer = 11000; + StrikeTimer = 6000; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (StrikeTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_STRIKE, true); + StrikeTimer = 15000; + } else StrikeTimer -= diff; + + if (CleaveTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE, true); + CleaveTimer = 17000; + } else CleaveTimer -= diff; + + DoMeleeAttackIfReady(); + + } + +}; + +struct TRINITY_DLL_DECL npc_watcher_gashraAI : public ScriptedAI +{ + npc_watcher_gashraAI(Creature *c) : ScriptedAI(c) {} + + uint32 WebWrapTimer; + uint32 InfectedBiteTimer; + + void Reset() + { + WebWrapTimer = 11000; + InfectedBiteTimer = 4000; + } + + void EnterCombat(Unit* who) + { + DoCast(m_creature, SPELL_ENRAGE, true); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (WebWrapTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_WEB_WRAP, true); + WebWrapTimer = 17000; + } else WebWrapTimer -= diff; + + if (InfectedBiteTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_INFECTED_BITE, H_SPELL_INFECTED_BITE), true); + InfectedBiteTimer = 15000; + } else InfectedBiteTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL npc_watcher_narjilAI : public ScriptedAI +{ + npc_watcher_narjilAI(Creature *c) : ScriptedAI(c) {} + + uint32 WebWrapTimer; + uint32 InfectedBiteTimer; + uint32 BlindingWebsTimer; + + void Reset() + { + WebWrapTimer = 11000; + InfectedBiteTimer = 4000; + BlindingWebsTimer = 17000; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (WebWrapTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_WEB_WRAP, true); + WebWrapTimer = 15000; + } else WebWrapTimer -= diff; + + if (InfectedBiteTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_INFECTED_BITE, H_SPELL_INFECTED_BITE), true); + InfectedBiteTimer = 11000; + } else InfectedBiteTimer -= diff; + + if (BlindingWebsTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_BLINDING_WEBS, H_SPELL_BLINDING_WEBS), true); + BlindingWebsTimer = 17000; + } else BlindingWebsTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL npc_watcher_silthikAI : public ScriptedAI +{ + npc_watcher_silthikAI(Creature *c) : ScriptedAI(c) {} + + uint32 WebWrapTimer; + uint32 InfectedBiteTimer; + uint32 PosionSprayTimer; + + void Reset() + { + WebWrapTimer = 11000; + InfectedBiteTimer = 4000; + PosionSprayTimer = 15000; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (WebWrapTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_WEB_WRAP, true); + + WebWrapTimer = 15000; + } else WebWrapTimer -= diff; + + if (InfectedBiteTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_INFECTED_BITE, H_SPELL_INFECTED_BITE), true); + InfectedBiteTimer = 15000; + } else InfectedBiteTimer -= diff; + + if (PosionSprayTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_POSION_SPRAY, H_SPELL_POSION_SPRAY), true); + PosionSprayTimer = 17000; + } else PosionSprayTimer -= diff; + + DoMeleeAttackIfReady(); + + } +}; + +CreatureAI* GetAI_boss_krik_thir(Creature* pCreature) +{ + return new boss_krik_thirAI (pCreature); +} + +CreatureAI* GetAI_npc_anub_ar_skirmisher (Creature* pCreature) +{ + return new npc_anub_ar_skirmisherAI (pCreature); +} + +CreatureAI* GetAI_npc_skittering_infector (Creature* pCreature) +{ + return new npc_skittering_infectorAI (pCreature); +} + +CreatureAI* GetAI_npc_anub_ar_shadowcaster (Creature* pCreature) +{ + return new npc_anub_ar_shadowcasterAI (pCreature); +} + +CreatureAI* GetAI_npc_anub_ar_warrior (Creature* pCreature) +{ + return new npc_anub_ar_warriorAI (pCreature); +} + +CreatureAI* GetAI_npc_watcher_gashra (Creature* pCreature) +{ + return new npc_watcher_gashraAI (pCreature); +} + +CreatureAI* GetAI_npc_watcher_narjil (Creature* pCreature) +{ + return new npc_watcher_narjilAI (pCreature); +} + +CreatureAI* GetAI_npc_watcher_silthik (Creature* pCreature) +{ + return new npc_watcher_silthikAI (pCreature); +} + +void AddSC_boss_krik_thir() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_krik_thir"; + newscript->GetAI = &GetAI_boss_krik_thir; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_skittering_infector"; + newscript->GetAI = &GetAI_npc_skittering_infector; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_anub_ar_skirmisher"; + newscript->GetAI = &GetAI_npc_anub_ar_skirmisher; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_anub_ar_shadowcaster"; + newscript->GetAI = &GetAI_npc_anub_ar_shadowcaster; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_watcher_gashra"; + newscript->GetAI = &GetAI_npc_watcher_gashra; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_anub_ar_warrior"; + newscript->GetAI = &GetAI_npc_anub_ar_warrior; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_watcher_silthik"; + newscript->GetAI = &GetAI_npc_watcher_silthik; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_watcher_narjil"; + newscript->GetAI = &GetAI_npc_watcher_narjil; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp b/src/scripts/northrend/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp new file mode 100644 index 00000000000..0de63148a08 --- /dev/null +++ b/src/scripts/northrend/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Instance_Azjol_Nerub +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Azjol Nerub +EndScriptData */ + +#include "ScriptedPch.h" +#include "azjol_nerub.h" + +#define MAX_ENCOUNTER 3 + +/* Azjol Nerub encounters: +0 - Krik'thir the Gatewatcher +1 - Hadronox +2 - Anub'arak +*/ + +struct TRINITY_DLL_DECL instance_azjol_nerub : public ScriptedInstance +{ + instance_azjol_nerub(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint64 m_uiKrikthir; + uint64 m_uiHadronox; + uint64 m_uiAnubarak; + uint64 m_uiWatcherGashra; + uint64 m_uiWatcherSilthik; + uint64 m_uiWatcherNarjil; + + uint64 m_uiKrikthirDoor; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + void Initialize() + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + m_uiKrikthir = 0; + m_uiHadronox = 0; + m_uiAnubarak = 0; + m_uiWatcherGashra = 0; + m_uiWatcherSilthik = 0; + m_uiWatcherNarjil = 0; + m_uiKrikthirDoor = 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* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case 28684: m_uiKrikthir = pCreature->GetGUID(); break; + case 28921: m_uiHadronox = pCreature->GetGUID(); break; + case 29120: m_uiAnubarak = pCreature->GetGUID(); break; + case 28730: m_uiWatcherGashra = pCreature->GetGUID(); break; + case 28731: m_uiWatcherSilthik = pCreature->GetGUID(); break; + case 28729: m_uiWatcherNarjil = pCreature->GetGUID(); break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch (pGo->GetEntry()) + { + case 192395: + m_uiKrikthirDoor = pGo->GetGUID(); + if (m_auiEncounter[0] == DONE) + HandleGameObject(NULL,true,pGo); + break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_KRIKTHIR_THE_GATEWATCHER: return m_uiKrikthir; + case DATA_HADRONOX: return m_uiHadronox; + case DATA_ANUBARAK: return m_uiAnubarak; + case DATA_WATCHER_GASHRA: return m_uiWatcherGashra; + case DATA_WATCHER_SILTHIK: return m_uiWatcherSilthik; + case DATA_WATCHER_NARJIL: return m_uiWatcherNarjil; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_KRIKTHIR_THE_GATEWATCHER_EVENT: + m_auiEncounter[0] = data; + if (data == DONE) + HandleGameObject(m_uiKrikthirDoor,true); + break; + case DATA_HADRONOX_EVENT: + m_auiEncounter[1] = data; break; + case DATA_ANUBARAK_EVENT: + m_auiEncounter[2] = data; break; + } + + if (data == DONE) + { + SaveToDB(); + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_KRIKTHIR_THE_GATEWATCHER_EVENT: return m_auiEncounter[0]; + case DATA_HADRONOX_EVENT: return m_auiEncounter[1]; + case DATA_ANUBARAK_EVENT: return m_auiEncounter[2]; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::string str_data; + + std::ostringstream saveStream; + saveStream << "A N " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2]; + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2; + + if (dataHead1 == 'A' && dataHead2 == 'N') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_azjol_nerub(Map* pMap) +{ + return new instance_azjol_nerub(pMap); +} + +void AddSC_instance_azjol_nerub() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_azjol_nerub"; + newscript->GetInstanceData = &GetInstanceData_instance_azjol_nerub; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/borean_tundra.cpp b/src/scripts/northrend/borean_tundra.cpp new file mode 100644 index 00000000000..48a0c8c354b --- /dev/null +++ b/src/scripts/northrend/borean_tundra.cpp @@ -0,0 +1,2122 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Borean_Tundra +SD%Complete: 100 +SDComment: Quest support: 11708. Taxi vendors. +SDCategory: Borean Tundra +EndScriptData */ + +/* ContentData +npc_fizzcrank_fullthrottle +npc_surristrasz +npc_tiare +npc_iruk +npc_corastrasza +npc_jenny +npc_sinkhole_kill_credit +npc_khunok_the_behemoth +npc_scourge_prisoner +mob_nerubar_victim +npc_keristrasza +npc_nesingwary_trapper +npc_lurgglbr +npc_nexus_drake_hatchling +EndContentData */ + +#include "ScriptedPch.h" +#include "ScriptedEscortAI.h" +#include "ScriptedFollowerAI.h" + +/*###### +## npc_fizzcrank_fullthrottle +######*/ + +#define GOSSIP_ITEM_GO_ON "Go on." +#define GOSSIP_ITEM_TELL_ME "Tell me what's going on out here, Fizzcrank." + +enum eFizzcrank +{ + GOSSIP_TEXTID_FIZZCRANK1 = 12456, + GOSSIP_TEXTID_FIZZCRANK2 = 12457, + GOSSIP_TEXTID_FIZZCRANK3 = 12458, + GOSSIP_TEXTID_FIZZCRANK4 = 12459, + GOSSIP_TEXTID_FIZZCRANK5 = 12460, + GOSSIP_TEXTID_FIZZCRANK6 = 12461, + GOSSIP_TEXTID_FIZZCRANK7 = 12462, + GOSSIP_TEXTID_FIZZCRANK8 = 12463, + GOSSIP_TEXTID_FIZZCRANK9 = 12464, + + QUEST_THE_MECHAGNOMES = 11708 +}; + +bool GossipHello_npc_fizzcrank_fullthrottle(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_THE_MECHAGNOMES) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELL_ME, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_fizzcrank_fullthrottle(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK1, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK3, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK4, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK5, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK6, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK7, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+8: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK8, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+9: + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK9, pCreature->GetGUID()); + pPlayer->AreaExploredOrEventHappens(QUEST_THE_MECHAGNOMES); + break; + } + return true; +} + +/*###### +## npc_surristrasz +######*/ + +#define GOSSIP_ITEM_FREE_FLIGHT "I'd like passage to the Transitus Shield." +#define GOSSIP_ITEM_FLIGHT "May I use a drake to fly elsewhere?" + +enum eSurristrasz +{ + SPELL_ABMER_TO_COLDARRA = 46064 +}; + +bool GossipHello_npc_surristrasz(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pCreature->isTaxi()) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FREE_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_OPTION_GOSSIP); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, GOSSIP_ITEM_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_OPTION_TAXIVENDOR); + } + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_surristrasz(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_OPTION_GOSSIP) + { + pPlayer->CLOSE_GOSSIP_MENU(); + + //TaxiPath 795 (amber to coldarra) + pPlayer->CastSpell(pPlayer, SPELL_ABMER_TO_COLDARRA, true); + } + + if (uiAction == GOSSIP_OPTION_TAXIVENDOR) + pPlayer->GetSession()->SendTaxiMenu(pCreature); + + return true; +} + +/*###### +## npc_tiare +######*/ + +#define GOSSIP_ITEM_TELEPORT "Teleport me to Amber Ledge, please." + +enum eTiare +{ + SPELL_TELEPORT_COLDARRA = 50135 +}; + +bool GossipHello_npc_tiare(Player* pPlayer, Creature* pCreature) +{ + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_OPTION_GOSSIP); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_tiare(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_OPTION_GOSSIP) + { + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->CastSpell(pPlayer, SPELL_TELEPORT_COLDARRA, true); + } + return true; +} + +/*###### +## npc_sinkhole_kill_credit +######*/ + +enum eSinkhole +{ + SPELL_SET_CART = 46797, + SPELL_EXPLODE_CART = 46799, + SPELL_SUMMON_CART = 46798, + SPELL_SUMMON_WORM = 46800, +}; + +struct TRINITY_DLL_DECL npc_sinkhole_kill_creditAI : public ScriptedAI +{ + npc_sinkhole_kill_creditAI(Creature* c) : ScriptedAI(c){} + + uint32 Phase_Timer; + uint8 Phase; + uint64 casterGuid; + + void Reset() + { + Phase_Timer = 500; + Phase = 0; + casterGuid = 0; + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (Phase) + return; + + if (spell->Id == SPELL_SET_CART && caster->GetTypeId() == TYPEID_PLAYER + && CAST_PLR(caster)->GetQuestStatus(11897) == QUEST_STATUS_INCOMPLETE) + { + Phase = 1; + casterGuid = caster->GetGUID(); + } + } + + void EnterCombat(Unit* who){} + + void UpdateAI(const uint32 diff) + { + if (!Phase) + return; + + if (Phase_Timer <= diff) + { + switch (Phase) + { + case 1: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + DoCast(m_creature, SPELL_SUMMON_CART, true); + if (GameObject* cart = m_creature->FindNearestGameObject(188160,3)) + cart->SetUInt32Value(GAMEOBJECT_FACTION, 14); + Phase_Timer = 3000; + Phase = 2; + break; + case 2: + if (GameObject* cart = m_creature->FindNearestGameObject(188160,3)) + cart->UseDoorOrButton(); + DoCast(m_creature, SPELL_EXPLODE_CART, true); + Phase_Timer = 3000; + Phase = 3; + break; + case 3: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + Phase_Timer = 2000; + Phase = 4; + case 5: + DoCast(m_creature, SPELL_SUMMON_WORM, true); + if (Unit* worm = m_creature->FindNearestCreature(26250, 3)) + { + worm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + worm->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + } + Phase_Timer = 1000; + Phase = 6; + break; + case 6: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + if (Unit* worm = m_creature->FindNearestCreature(26250, 3)) + { + m_creature->Kill(worm); + worm->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + Phase_Timer = 2000; + Phase = 7; + break; + case 7: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + if(Player *caster = Unit::GetPlayer(casterGuid)) + caster->KilledMonster(m_creature->GetCreatureInfo(),m_creature->GetGUID()); + Phase_Timer = 5000; + Phase = 8; + break; + case 8: + EnterEvadeMode(); + break; + } + } else Phase_Timer -= diff; + + } + +}; + +CreatureAI* GetAI_npc_sinkhole_kill_credit(Creature* pCreature) +{ + return new npc_sinkhole_kill_creditAI(pCreature); +} + +/*###### +## npc_khunok_the_behemoth +######*/ + +struct TRINITY_DLL_DECL npc_khunok_the_behemothAI : public ScriptedAI +{ + npc_khunok_the_behemothAI(Creature *c) : ScriptedAI(c) {} + + void MoveInLineOfSight(Unit *who) + { + ScriptedAI::MoveInLineOfSight(who); + + if (who->GetTypeId() != TYPEID_UNIT) + return; + + if (who->GetEntry() == 25861 && me->IsWithinDistInMap(who, 10.0f)) + { + if (Unit *owner = who->GetOwner()) + { + if (owner->GetTypeId() == TYPEID_PLAYER) + { + owner->CastSpell(owner, 46231, true); + CAST_CRE(who)->ForcedDespawn(); + } + } + } + } +}; + +CreatureAI* GetAI_npc_khunok_the_behemoth(Creature* pCreature) +{ + return new npc_khunok_the_behemothAI(pCreature); +} + +/*###### +## npc_keristrasza +######*/ + +enum eKeristrasza +{ + SPELL_TELEPORT_TO_SARAGOSA = 46772 +}; + +#define GOSSIP_HELLO_KERI "I am prepared to face Saragosa!" + +bool GossipHello_npc_keristrasza(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(11957) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_KERI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_keristrasza(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->CastSpell(pPlayer, SPELL_TELEPORT_TO_SARAGOSA, true); + } + + return true; +} + +/*###### +## npc_corastrasza +######*/ + +#define GOSSIP_ITEM_C_1 "I... I think so..." + +enum eCorastrasza +{ + SPELL_SUMMON_WYRMREST_SKYTALON = 61240, + SPELL_WYRMREST_SKYTALON_RIDE_PERIODIC = 61244, + + QUEST_ACES_HIGH_DAILY = 13414, + QUEST_ACES_HIGH = 13413 +}; + +bool GossipHello_npc_corastrasza(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_ACES_HIGH) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_ACES_HIGH_DAILY) == QUEST_STATUS_INCOMPLETE) //It's the same dragon for both quests. + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_C_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_corastrasza(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + + pPlayer->CastSpell(pPlayer, SPELL_SUMMON_WYRMREST_SKYTALON, true); + pPlayer->CastSpell(pPlayer, SPELL_WYRMREST_SKYTALON_RIDE_PERIODIC, true); + + } + + return true; +} + +/*###### +## npc_iruk +######*/ + +#define GOSSIP_ITEM_I "<Search corpse for Issliruk's Totem.>" + +enum eIruk +{ + QUEST_SPIRITS_WATCH_OVER_US = 11961, + SPELL_CREATURE_TOTEM_OF_ISSLIRUK = 46816, + GOSSIP_TEXT_I = 12585 +}; + +bool GossipHello_npc_iruk(Player* pPlayer, Creature* pCreature) +{ + + if (pPlayer->GetQuestStatus(QUEST_SPIRITS_WATCH_OVER_US) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_I, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->PlayerTalkClass->SendGossipMenu(GOSSIP_TEXT_I, pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_iruk(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->CastSpell(pPlayer, SPELL_CREATURE_TOTEM_OF_ISSLIRUK, true); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + + } + return true; +} +/*###### +## mob_nerubar_victim +######*/ + +#define WARSONG_PEON 25270 + +const uint32 nerubarVictims[3] = +{ + 45526, 45527, 45514 +}; +struct TRINITY_DLL_DECL mob_nerubar_victimAI : public ScriptedAI +{ + mob_nerubar_victimAI(Creature *c) : ScriptedAI(c) {} + + void Reset() {} + void EnterCombat(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + + void JustDied(Unit* Killer) + { + if (Killer->GetTypeId() == TYPEID_PLAYER) + { + if (CAST_PLR(Killer)->GetQuestStatus(11611) == QUEST_STATUS_INCOMPLETE) + { + uint8 uiRand = urand(0,99); + if (uiRand < 25) + { + Killer->CastSpell(m_creature,45532,true); + CAST_PLR(Killer)->KilledMonsterCredit(WARSONG_PEON, 0); + } + else if (uiRand < 75) + Killer->CastSpell(m_creature, nerubarVictims[urand(0,2)], true); + } + } + } +}; +CreatureAI* GetAI_mob_nerubar_victim(Creature *pCreature) +{ + return new mob_nerubar_victimAI (pCreature); +} +/*###### +## npc_scourge_prisoner +######*/ + +enum eScourgePrisoner +{ + GO_SCOURGE_CAGE = 187867 +}; + +struct TRINITY_DLL_DECL npc_scourge_prisonerAI : public ScriptedAI +{ + npc_scourge_prisonerAI(Creature* pCreature) : ScriptedAI (pCreature){} + + void Reset() + { + m_creature->SetReactState(REACT_PASSIVE); + + if (GameObject* pGO = m_creature->FindNearestGameObject(GO_SCOURGE_CAGE,5.0f)) + if (pGO->GetGoState() == GO_STATE_ACTIVE) + pGO->SetGoState(GO_STATE_READY); + } + +}; +CreatureAI* GetAI_npc_scourge_prisoner(Creature* pCreature) +{ + return new npc_scourge_prisonerAI(pCreature); +} + +/*###### +## npc_jenny +######*/ +enum eJenny +{ + QUEST_LOADER_UP = 11881, + + NPC_FEZZIX_GEARTWIST = 25849, + NPC_JENNY = 25969, + + SPELL_GIVE_JENNY_CREDIT = 46358, + SPELL_CRATES_CARRIED = 46340, + SPELL_DROP_CRATE = 46342 +}; + +struct TRINITY_DLL_DECL npc_jennyAI : public ScriptedAI +{ + npc_jennyAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + bool setCrateNumber; + + void Reset() + { + if(!setCrateNumber) + setCrateNumber = true; + + m_creature->SetReactState(REACT_PASSIVE); + + switch (CAST_PLR(m_creature->GetOwner())->GetTeamId()) + { + case TEAM_ALLIANCE: + m_creature->setFaction(FACTION_ESCORT_A_NEUTRAL_ACTIVE); + break; + default: + case TEAM_HORDE: + m_creature->setFaction(FACTION_ESCORT_H_NEUTRAL_ACTIVE); + break; + } + } + + void DamageTaken(Unit* pDone_by, uint32& uiDamage) + { + DoCast(m_creature, SPELL_DROP_CRATE, true); + } + + void UpdateAI(const uint32 diff) + { + if(setCrateNumber) + { + m_creature->AddAura(SPELL_CRATES_CARRIED,m_creature); + setCrateNumber = false; + } + + if (!setCrateNumber && !m_creature->HasAura(SPELL_CRATES_CARRIED)) + m_creature->DisappearAndDie(); + + if (!UpdateVictim()) + return; + } +}; + +CreatureAI* GetAI_npc_jenny(Creature *pCreature) +{ + return new npc_jennyAI (pCreature); +} + +/*###### +## npc_fezzix_geartwist +######*/ + +struct TRINITY_DLL_DECL npc_fezzix_geartwistAI : public ScriptedAI +{ + npc_fezzix_geartwistAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + void MoveInLineOfSight(Unit* pWho) + { + ScriptedAI::MoveInLineOfSight(pWho); + + if (pWho->GetTypeId() != TYPEID_UNIT) + return; + + if (pWho->GetEntry() == NPC_JENNY && m_creature->IsWithinDistInMap(pWho, 10.0f)) + { + if (Unit* pOwner = pWho->GetOwner()) + { + if (pOwner->GetTypeId() == TYPEID_PLAYER) + { + if (pWho->HasAura(SPELL_CRATES_CARRIED)) + { + pOwner->CastSpell(pOwner, SPELL_GIVE_JENNY_CREDIT, true); // Maybe is not working. + CAST_PLR(pOwner)->CompleteQuest(QUEST_LOADER_UP); + CAST_CRE(pWho)->DisappearAndDie(); + } + } + } + } + } +}; + +CreatureAI* GetAI_npc_fezzix_geartwist(Creature* pCreature) +{ + return new npc_fezzix_geartwistAI(pCreature); +} + +/*###### +## npc_nesingwary_trapper +######*/ + +enum eNesingwaryTrapper +{ + GO_HIGH_QUALITY_FUR = 187983, + + GO_CARIBOU_TRAP_1 = 187982, + GO_CARIBOU_TRAP_2 = 187995, + GO_CARIBOU_TRAP_3 = 187996, + GO_CARIBOU_TRAP_4 = 187997, + GO_CARIBOU_TRAP_5 = 187998, + GO_CARIBOU_TRAP_6 = 187999, + GO_CARIBOU_TRAP_7 = 188000, + GO_CARIBOU_TRAP_8 = 188001, + GO_CARIBOU_TRAP_9 = 188002, + GO_CARIBOU_TRAP_10 = 188003, + GO_CARIBOU_TRAP_11 = 188004, + GO_CARIBOU_TRAP_12 = 188005, + GO_CARIBOU_TRAP_13 = 188006, + GO_CARIBOU_TRAP_14 = 188007, + GO_CARIBOU_TRAP_15 = 188008, + + SPELL_TRAPPED = 46104, +}; + +//#define SAY_NESINGWARY_1 -1571008 + +struct TRINITY_DLL_DECL npc_nesingwary_trapperAI : public ScriptedAI +{ + npc_nesingwary_trapperAI(Creature *c) : ScriptedAI(c) { c->SetVisibility(VISIBILITY_OFF); } + + GameObject *go_caribou; + uint8 Phase; + uint32 Phase_Timer; + + void Reset() + { + m_creature->SetVisibility(VISIBILITY_OFF); + Phase_Timer = 2500; + Phase = 1; + go_caribou = NULL; + } + void EnterCombat(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + + void JustDied(Unit *who) + { + if (go_caribou && go_caribou->GetTypeId() == TYPEID_GAMEOBJECT) + go_caribou->SetLootState(GO_JUST_DEACTIVATED); + + if (TempSummon *summon = (TempSummon*)m_creature) + if (summon->isSummon()) + if (Unit *pTemp = summon->GetSummoner()) + if (pTemp->GetTypeId() == TYPEID_PLAYER) + CAST_PLR(pTemp)->KilledMonsterCredit(m_creature->GetEntry(),0); + + if (go_caribou && go_caribou->GetTypeId() == TYPEID_GAMEOBJECT) + go_caribou->SetGoState(GO_STATE_READY); + } + + void UpdateAI(const uint32 diff) + { + if (Phase_Timer <= diff) + { + switch (Phase) + { + case 1: + m_creature->SetVisibility(VISIBILITY_ON); + Phase_Timer = 2000; + Phase = 2; + break; + + case 2: + if (GameObject *go_fur = m_creature->FindNearestGameObject(GO_HIGH_QUALITY_FUR, 11.0f)) + m_creature->GetMotionMaster()->MovePoint(0, go_fur->GetPositionX(), go_fur->GetPositionY(), go_fur->GetPositionZ()); + Phase_Timer = 1500; + Phase = 3; + break; + case 3: + //DoScriptText(SAY_NESINGWARY_1, m_creature); + Phase_Timer = 2000; + Phase = 4; + break; + case 4: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LOOT); + Phase_Timer = 1000; + Phase = 5; + break; + case 5: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_NONE); + Phase_Timer = 500; + Phase = 6; + break; + case 6: + if (GameObject *go_fur = m_creature->FindNearestGameObject(GO_HIGH_QUALITY_FUR, 11.0f)) + go_fur->Delete(); + Phase_Timer = 500; + Phase = 7; + break; + + case 7: + if ((go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_1, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_2, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_3, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_4, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_5, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_6, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_7, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_8, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_9, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_10, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_11, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_12, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_13, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_14, 5.0f)) || + (go_caribou = m_creature->FindNearestGameObject(GO_CARIBOU_TRAP_15, 5.0f))) + go_caribou->SetGoState(GO_STATE_ACTIVE); + Phase = 8; + Phase_Timer = 1000; + break; + case 8: + DoCast(m_creature, SPELL_TRAPPED, true); + Phase = 0; + break; + } + } else Phase_Timer -= diff; + } +}; + +CreatureAI* GetAI_npc_nesingwary_trapper(Creature *pCreature) +{ + return new npc_nesingwary_trapperAI (pCreature); +} + +/*###### +## npc_lurgglbr +######*/ + +enum eLurgglbr +{ + QUEST_ESCAPE_WINTERFIN_CAVERNS = 11570, + + GO_CAGE = 187369, + + FACTION_ESCORTEE_A = 774, + FACTION_ESCORTEE_H = 775, +}; + +/*#define SAY_WP_1_LUR_START -1571004 +#define SAY_WP_1_LUR_END -1571005 +#define SAY_WP_41_LUR_START -1571006 +#define SAY_WP_41_LUR_END -1571007*/ + +struct TRINITY_DLL_DECL npc_lurgglbrAI : public npc_escortAI +{ + npc_lurgglbrAI(Creature* pCreature) : npc_escortAI(pCreature){} + + uint32 IntroTimer; + uint32 IntroPhase; + + void Reset() + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + IntroTimer = 0; + IntroPhase = 0; + } + } + + void WaypointReached(uint32 i) + { + switch (i) + { + case 0: + IntroPhase = 1; + IntroTimer = 2000; + break; + case 41: + IntroPhase = 4; + IntroTimer = 2000; + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (IntroPhase) + { + if (IntroTimer <= diff) + { + switch(IntroPhase) + { + case 1: + //DoScriptText(SAY_WP_1_LUR_START,m_creature); + IntroPhase = 2; + IntroTimer = 7500; + break; + case 2: + //DoScriptText(SAY_WP_1_LUR_END,m_creature); + IntroPhase = 3; + IntroTimer = 7500; + break; + case 3: + m_creature->SetReactState(REACT_AGGRESSIVE); + IntroPhase = 0; + IntroTimer = 0; + break; + case 4: + //DoScriptText(SAY_WP_41_LUR_START,m_creature); + IntroPhase = 5; + IntroTimer = 8000; + break; + case 5: + //DoScriptText(SAY_WP_41_LUR_END,m_creature); + IntroPhase = 6; + IntroTimer = 2500; + break; + + case 6: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->AreaExploredOrEventHappens(QUEST_ESCAPE_WINTERFIN_CAVERNS); + IntroPhase = 7; + IntroTimer = 2500; + break; + + case 7: + m_creature->ForcedDespawn(); + IntroPhase = 0; + IntroTimer = 0; + break; + } + } else IntroTimer -= diff; + } + npc_escortAI::UpdateAI(diff); + + if (!UpdateVictim()) + return; + } +}; + +CreatureAI* GetAI_npc_lurgglbr(Creature* pCreature) +{ + return new npc_lurgglbrAI(pCreature); +} + +bool QuestAccept_npc_lurgglbr(Player* pPlayer, Creature* pCreature, Quest const *pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ESCAPE_WINTERFIN_CAVERNS) + { + if(GameObject* pGo = pCreature->FindNearestGameObject(GO_CAGE, 5.0f)) + { + pGo->SetRespawnTime(0); + pGo->SetGoType(GAMEOBJECT_TYPE_BUTTON); + pGo->UseDoorOrButton(20); + } + + if (npc_escortAI* pEscortAI = CAST_AI(npc_lurgglbrAI, pCreature->AI())) + pEscortAI->Start(true, false, pPlayer->GetGUID()); + + switch (pPlayer->GetTeam()) + { + case ALLIANCE: + pCreature->setFaction(FACTION_ESCORTEE_A); + break; + default: + case HORDE: + pCreature->setFaction(FACTION_ESCORTEE_H); + break; + } + + return true; + } + return false; +} + +/*###### +## npc_nexus_drake_hatchling +######*/ + +enum eNexusDrakeHatchling +{ + SPELL_DRAKE_HARPOON = 46607, + SPELL_RED_DRAGONBLOOD = 46620, + SPELL_DRAKE_HATCHLING_SUBDUED = 46691, + SPELL_SUBDUED = 46675, + + NPC_RAELORASZ = 26117, + + QUEST_DRAKE_HUNT = 11919, + QUEST_DRAKE_HUNT_D = 11940 +}; + +struct TRINITY_DLL_DECL npc_nexus_drake_hatchlingAI : public FollowerAI //The spell who makes the npc follow the player is missing, also we can use FollowerAI! +{ + npc_nexus_drake_hatchlingAI(Creature *c) : FollowerAI(c) + { + pHarpooner = NULL; + } + + Player *pHarpooner; + bool WithRedDragonBlood; + + void Reset() + { + WithRedDragonBlood = false; + } + + void EnterCombat(Unit* pWho) + { + if (m_creature->canAttack(pWho)) + m_creature->AI()->AttackStart(pWho); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (spell->Id == SPELL_DRAKE_HARPOON && caster->GetTypeId() == TYPEID_PLAYER) + { + pHarpooner = CAST_PLR(caster); + DoCast(m_creature, SPELL_RED_DRAGONBLOOD, true); + } + WithRedDragonBlood = true; + } + + void MoveInLineOfSight(Unit *pWho) + { + FollowerAI::MoveInLineOfSight(pWho); + + if (!pHarpooner || !pHarpooner->IsInWorld()) + return; + + if (m_creature->HasAura(SPELL_SUBDUED) && pWho->GetEntry() == NPC_RAELORASZ) + { + if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) + { + pHarpooner->KilledMonsterCredit(26175,0); + pHarpooner->RemoveAura(SPELL_DRAKE_HATCHLING_SUBDUED); + SetFollowComplete(); + pHarpooner = NULL; + m_creature->DisappearAndDie(); + } + } + } + + void UpdateAI(const uint32 diff) + { + if (WithRedDragonBlood && pHarpooner && pHarpooner->IsInWorld() && !m_creature->HasAura(SPELL_RED_DRAGONBLOOD)) + { + if (npc_nexus_drake_hatchlingAI* pDrakeAI = CAST_AI(npc_nexus_drake_hatchlingAI, m_creature->AI())) + { + EnterEvadeMode(); + pDrakeAI->StartFollow(pHarpooner, 35, NULL); + } + + DoCast(m_creature, SPELL_SUBDUED, true); + pHarpooner->CastSpell(pHarpooner, SPELL_DRAKE_HATCHLING_SUBDUED, true); + + m_creature->AttackStop(); + WithRedDragonBlood = false; + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_nexus_drake_hatchling(Creature* pCreature) +{ + return new npc_nexus_drake_hatchlingAI(pCreature); +} + +/*###### +## npc_thassarian +######*/ + +enum eThassarian +{ + QUEST_LAST_RITES = 12019, + + SPELL_TRANSFORM_VALANAR = 46753, + SPELL_STUN = 46957, + SPELL_SHADOW_BOLT = 15537, + + NPC_IMAGE_LICH_KING = 26203, + NPC_COUNSELOR_TALBOT = 25301, + NPC_PRINCE_VALANAR = 28189, + NPC_GENERAL_ARLOS = 25250, + NPC_LERYSSA = 25251, + + SAY_TALBOT_1 = -1571004, + SAY_LICH_1 = -1571005, + SAY_TALBOT_2 = -1571006, + SAY_THASSARIAN_1 = -1571007, + SAY_THASSARIAN_2 = -1571008, + SAY_LICH_2 = -1571009, + SAY_THASSARIAN_3 = -1571010, + SAY_TALBOT_3 = -1571011, + SAY_LICH_3 = -1571012, + SAY_TALBOT_4 = -1571013, + SAY_ARLOS_1 = -1571014, + SAY_ARLOS_2 = -1571015, + SAY_LERYSSA_1 = -1571016, + SAY_THASSARIAN_4 = -1571017, + SAY_LERYSSA_2 = -1571018, + SAY_THASSARIAN_5 = -1571019, + SAY_LERYSSA_3 = -1571020, + SAY_THASSARIAN_6 = -1571021, + SAY_LERYSSA_4 = -1571022, + SAY_THASSARIAN_7 = -1571023, +}; + +#define GOSSIP_ITEM_T "Let's do this, Thassarian. It's now or never." + +struct TRINITY_DLL_DECL npc_thassarianAI : public npc_escortAI +{ + npc_thassarianAI(Creature* pCreature) : npc_escortAI(pCreature) + { + pArthas = NULL; + pTalbot = NULL; + pLeryssa = NULL; + pArlos = NULL; + pCreature->RemoveStandFlags(UNIT_STAND_STATE_SIT); + } + + Creature* pArthas; + Creature* pTalbot; + Creature* pLeryssa; + Creature* pArlos; + + bool bArthasInPosition; + bool bArlosInPosition; + bool bLeryssaInPosition; + bool bTalbotInPosition; + + uint32 uiPhase; + uint32 uiPhase_Timer; + + void Reset() + { + m_creature->RestoreFaction(); + m_creature->RemoveStandFlags(UNIT_STAND_STATE_SIT); + + bArthasInPosition = false; + bArlosInPosition = false; + bLeryssaInPosition = false; + bTalbotInPosition = false; + + uiPhase = 0; + uiPhase_Timer = 0; + } + + void WaypointReached(uint32 uiPointId) + { + Player* pPlayer = GetPlayerForEscort(); + + if (!pPlayer) + return; + + switch(uiPointId) + { + case 3: + SetEscortPaused(true); + if (pArthas = m_creature->SummonCreature(NPC_IMAGE_LICH_KING, 3730.313, 3518.689, 473.324, 1.562, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000)) + { + pArthas->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pArthas->SetReactState(REACT_PASSIVE); + pArthas->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + pArthas->GetMotionMaster()->MovePoint(0, 3737.374756,3564.841309,477.433014); + } + if (pTalbot = m_creature->SummonCreature(NPC_COUNSELOR_TALBOT, 3747.23, 3614.936, 473.321, 4.462012, TEMPSUMMON_CORPSE_TIMED_DESPAWN,120000)) + { + pTalbot->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + pTalbot->GetMotionMaster()->MovePoint(0, 3738.000977,3568.882080,477.433014); + } + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + + case 4: + SetEscortPaused(true); + uiPhase = 7; + break; + } + } + + void UpdateAI(const uint32 uiDiff) + { + npc_escortAI::UpdateAI(uiDiff); + + if (bArthasInPosition && bTalbotInPosition) + { + uiPhase = 1; + bArthasInPosition = false; + bTalbotInPosition = false; + } + + if (bArlosInPosition && bLeryssaInPosition) + { + bArlosInPosition = false; + bLeryssaInPosition = false; + DoScriptText(SAY_THASSARIAN_1, m_creature); + SetEscortPaused(false); + } + + if (uiPhase_Timer <= uiDiff) + { + switch (uiPhase) + { + case 1: + if (pTalbot) + pTalbot->SetStandState(UNIT_STAND_STATE_KNEEL); + uiPhase_Timer = 3000; + ++uiPhase; + break; + + case 2: + if (pTalbot) + { + pTalbot->UpdateEntry(NPC_PRINCE_VALANAR,ALLIANCE); + pTalbot->setFaction(14); + pTalbot->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pTalbot->SetReactState(REACT_PASSIVE); + } + uiPhase_Timer = 5000; + ++uiPhase; + break; + + case 3: + if (pTalbot) + DoScriptText(SAY_TALBOT_1, pTalbot); + uiPhase_Timer = 5000; + ++uiPhase; + break; + + case 4: + if (pArthas) + DoScriptText(SAY_LICH_1, pArthas); + uiPhase_Timer = 5000; + ++uiPhase; + break; + + case 5: + if (pTalbot) + DoScriptText(SAY_TALBOT_2, pTalbot); + uiPhase_Timer = 5000; + ++uiPhase; + break; + + case 6: + if (pArlos = m_creature->SummonCreature(NPC_GENERAL_ARLOS, 3745.527100, 3615.655029, 473.321533, 4.447805, TEMPSUMMON_CORPSE_TIMED_DESPAWN,120000)) + { + pArlos->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + pArlos->GetMotionMaster()->MovePoint(0, 3735.570068, 3572.419922, 477.441010); + } + if (pLeryssa = m_creature->SummonCreature(NPC_LERYSSA, 3749.654541, 3614.959717, 473.323486, 4.524959, TEMPSUMMON_CORPSE_TIMED_DESPAWN,120000)) + { + pLeryssa->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + pLeryssa->SetReactState(REACT_PASSIVE); + pLeryssa->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pLeryssa->GetMotionMaster()->MovePoint(0, 3741.969971, 3571.439941, 477.441010); + } + uiPhase_Timer = 2000; + uiPhase = 0; + break; + + case 7: + DoScriptText(SAY_THASSARIAN_2, m_creature); + uiPhase_Timer = 5000; + ++uiPhase; + break; + + case 8: + if (pArthas && pTalbot) + { + pArthas->SetInFront(m_creature); //The client doesen't update with the new orientation :l + pTalbot->SetStandState(UNIT_STAND_STATE_STAND); + DoScriptText(SAY_LICH_2, pArthas); + } + uiPhase_Timer = 5000; + uiPhase = 9; + break; + + case 9: + DoScriptText(SAY_THASSARIAN_3, m_creature); + uiPhase_Timer = 5000; + uiPhase = 10; + break; + + case 10: + if (pTalbot) + DoScriptText(SAY_TALBOT_3, pTalbot); + uiPhase_Timer = 5000; + uiPhase = 11; + break; + + case 11: + if (pArthas) + DoScriptText(SAY_LICH_3, pArthas); + uiPhase_Timer = 5000; + uiPhase = 12; + break; + + case 12: + if (pTalbot) + DoScriptText(SAY_TALBOT_4, pTalbot); + uiPhase_Timer = 2000; + uiPhase = 13; + break; + + case 13: + if (pArthas) + pArthas->RemoveFromWorld(); + ++uiPhase; + break; + + case 14: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (pTalbot) + { + pTalbot->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pTalbot->SetReactState(REACT_AGGRESSIVE); + pTalbot->CastSpell(m_creature, SPELL_SHADOW_BOLT, false); + } + uiPhase_Timer = 1500; + ++uiPhase; + break; + + case 15: + m_creature->SetReactState(REACT_AGGRESSIVE); + m_creature->AI()->AttackStart(pTalbot); + uiPhase = 0; + break; + + case 16: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + uiPhase_Timer = 20000; + ++uiPhase; + break; + + case 17: + if (pLeryssa) + pLeryssa->RemoveFromWorld(); + if (pArlos) + pArlos->RemoveFromWorld(); + if (pTalbot) + pTalbot->RemoveFromWorld(); + m_creature->RemoveStandFlags(UNIT_STAND_STATE_SIT); + SetEscortPaused(false); + uiPhase_Timer = 0; + uiPhase = 0; + } + } else uiPhase_Timer -= uiDiff; + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + if (pTalbot) + pTalbot->RemoveFromWorld(); + if (pLeryssa) + pLeryssa->RemoveFromWorld(); + if (pArlos) + pArlos->RemoveFromWorld(); + if (pArthas) + pArthas->RemoveFromWorld(); + } +}; + +bool GossipHello_npc_thassarian(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_LAST_RITES) == QUEST_STATUS_INCOMPLETE && pCreature->GetAreaId() == 4125) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_T, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_thassarian(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + CAST_AI(npc_escortAI, (pCreature->AI()))->Start(true, false, pPlayer->GetGUID()); + CAST_AI(npc_escortAI, (pCreature->AI()))->SetMaxPlayerDistance(200.0f); + break; + } + return true; +} + +CreatureAI* GetAI_npc_thassarian(Creature *pCreature) +{ + return new npc_thassarianAI (pCreature); +} + +/*###### +## npc_image_lich_king +######*/ + +struct TRINITY_DLL_DECL npc_image_lich_kingAI : public ScriptedAI +{ + npc_image_lich_kingAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + void Reset() + { + m_creature->RestoreFaction(); + } + + void MovementInform(uint32 uiType, uint32 uiId) + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_thassarianAI,CAST_CRE(pSummoner)->AI())->bArthasInPosition = true; + } +}; + +CreatureAI* GetAI_npc_image_lich_king(Creature* pCreature) +{ + return new npc_image_lich_kingAI (pCreature); +} + +/*###### +## npc_general_arlos +######*/ + +struct TRINITY_DLL_DECL npc_general_arlosAI : public ScriptedAI +{ + npc_general_arlosAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + void MovementInform(uint32 uiType, uint32 uiId) + { + if (uiType != POINT_MOTION_TYPE) + return; + + m_creature->addUnitState(UNIT_STAT_STUNNED); + m_creature->CastSpell(m_creature, SPELL_STUN, true); + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_thassarianAI,CAST_CRE(pSummoner)->AI())->bArlosInPosition = true; + } +}; + +CreatureAI* GetAI_npc_general_arlos(Creature *pCreature) +{ + return new npc_general_arlosAI (pCreature); +} + +/*###### +## npc_counselor_talbot +######*/ + +enum eCounselotTalbot +{ + SPELL_DEFLECTION = 51009, + SPELL_SOUL_BLAST = 50992, +}; + +struct TRINITY_DLL_DECL npc_counselor_talbotAI : public ScriptedAI +{ + npc_counselor_talbotAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pCreature->RestoreFaction(); + } + + Creature* pLeryssa; + Creature* pArlos; + + bool bCheck; + + uint32 uiShadowBoltTimer; + uint32 uiDeflectionTimer; + uint32 uiSoulBlastTimer; + + void Reset() + { + pLeryssa = NULL; + pArlos = NULL; + bCheck = false; + uiShadowBoltTimer = urand(5000,12000); + uiDeflectionTimer = urand(20000,25000); + uiSoulBlastTimer = urand (12000,18000); + } + void MovementInform(uint32 uiType, uint32 uiId) + { + if(uiType != POINT_MOTION_TYPE) + return; + + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_thassarianAI,CAST_CRE(pSummoner)->AI())->bTalbotInPosition = true; + } + + void UpdateAI(const uint32 uiDiff) + { + if (bCheck) + { + pLeryssa = m_creature->FindNearestCreature(NPC_LERYSSA, 50.0f, true); + pArlos = m_creature->FindNearestCreature(NPC_GENERAL_ARLOS, 50.0f, true); + bCheck = false; + } + + if (!UpdateVictim()) + return; + + if (m_creature->GetAreaId() == 4125) + { + if (uiShadowBoltTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SHADOW_BOLT); + uiShadowBoltTimer = urand(5000,12000); + } else uiShadowBoltTimer -= uiDiff; + + if (uiDeflectionTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_DEFLECTION); + uiDeflectionTimer = urand(20000,25000); + } else uiDeflectionTimer -= uiDiff; + + if (uiSoulBlastTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SOUL_BLAST); + uiSoulBlastTimer = urand (12000,18000); + } else uiSoulBlastTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + if (!pArlos || !pLeryssa) + return; + + DoScriptText(SAY_ARLOS_1, pArlos); + DoScriptText(SAY_ARLOS_2, pArlos); + DoScriptText(SAY_LERYSSA_1, pLeryssa); + pArlos->Kill(pArlos, false); + pLeryssa->RemoveAura(SPELL_STUN); + pLeryssa->clearUnitState(UNIT_STAT_STUNNED); + pLeryssa->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + pLeryssa->GetMotionMaster()->MovePoint(0,3722.114502, 3564.201660, 477.441437); + + if (pKiller->GetTypeId() == TYPEID_PLAYER) + CAST_PLR(pKiller)->RewardPlayerAndGroupAtEvent(NPC_PRINCE_VALANAR, 0); + } +}; + +CreatureAI* GetAI_npc_counselor_talbot(Creature* pCreature) +{ + return new npc_counselor_talbotAI (pCreature); +} + +/*###### +## npc_leryssa +######*/ + +struct TRINITY_DLL_DECL npc_leryssaAI : public ScriptedAI +{ + npc_leryssaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + bDone = false; + Phase = 0; + Phase_Timer = 0; + + pCreature->RemoveStandFlags(UNIT_STAND_STATE_SIT); + } + + bool bDone; + + uint32 Phase; + uint32 Phase_Timer; + + void MovementInform(uint32 uiType, uint32 uiId) + { + if(uiType != POINT_MOTION_TYPE) + return; + + if (!bDone) + { + if (Creature* pTalbot = m_creature->FindNearestCreature(NPC_PRINCE_VALANAR, 50.0f, true)) + CAST_AI(npc_counselor_talbotAI, pTalbot->AI())->bCheck = true; + + m_creature->addUnitState(UNIT_STAT_STUNNED); + m_creature->CastSpell(m_creature, SPELL_STUN, true); + + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_thassarianAI,CAST_CRE(pSummoner)->AI())->bLeryssaInPosition = true; + bDone = true; + } + else + { + m_creature->SetStandState(UNIT_STAND_STATE_SIT); + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + pSummoner->SetStandState(UNIT_STAND_STATE_SIT); + Phase_Timer = 1500; + Phase = 1; + } + } + + void UpdateAI(const uint32 uiDiff) + { + ScriptedAI::UpdateAI(uiDiff); + + if (Phase_Timer <= uiDiff) + { + switch (Phase) + { + case 1: + if (m_creature->isSummon()) + if (Unit* pThassarian = CAST_SUM(m_creature)->GetSummoner()) + DoScriptText(SAY_THASSARIAN_4, pThassarian); + Phase_Timer = 5000; + ++Phase; + break; + case 2: + DoScriptText(SAY_LERYSSA_2, m_creature); + Phase_Timer = 5000; + ++Phase; + break; + case 3: + if (m_creature->isSummon()) + if (Unit* pThassarian = CAST_SUM(m_creature)->GetSummoner()) + DoScriptText(SAY_THASSARIAN_5, pThassarian); + Phase_Timer = 5000; + ++Phase; + break; + case 4: + DoScriptText(SAY_LERYSSA_3, m_creature); + Phase_Timer = 5000; + ++Phase; + break; + case 5: + if (m_creature->isSummon()) + if (Unit* pThassarian = CAST_SUM(m_creature)->GetSummoner()) + DoScriptText(SAY_THASSARIAN_6, pThassarian); + Phase_Timer = 5000; + ++Phase; + break; + + case 6: + DoScriptText(SAY_LERYSSA_4, m_creature); + Phase_Timer = 5000; + ++Phase; + break; + case 7: + if (m_creature->isSummon()) + if (Unit* pThassarian = CAST_SUM(m_creature)->GetSummoner()) + { + DoScriptText(SAY_THASSARIAN_7, pThassarian); + CAST_AI(npc_thassarianAI,CAST_CRE(pThassarian)->AI())->uiPhase = 16; + } + Phase_Timer = 5000; + Phase = 0; + break; + } + } else Phase_Timer -= uiDiff; + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_leryssa(Creature *pCreature) +{ + return new npc_leryssaAI (pCreature); +} + +/*###### +## npc_beryl_sorcerer +######*/ + +enum eBerylSorcerer +{ + NPC_CAPTURED_BERLY_SORCERER = 25474, + NPC_LIBRARIAN_DONATHAN = 25262, + + SPELL_ARCANE_CHAINS = 45611, + SPELL_COSMETIC_CHAINS = 54324, + SPELL_COSMETIC_ENSLAVE_CHAINS_SELF = 45631 +}; + +struct TRINITY_DLL_DECL npc_beryl_sorcererAI : public FollowerAI +{ + npc_beryl_sorcererAI(Creature* pCreature) : FollowerAI(pCreature) {} + + bool bEnslaved; + + void Reset() + { + m_creature->SetReactState(REACT_AGGRESSIVE); + bEnslaved = false; + } + + void EnterCombat(Unit* pWho) + { + if (m_creature->canAttack(pWho)) + m_creature->AI()->AttackStart(pWho); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + { + if (pSpell->Id == SPELL_ARCANE_CHAINS && pCaster->GetTypeId() == TYPEID_PLAYER && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !bEnslaved) + { + EnterEvadeMode(); //We make sure that the npc is not attacking the player! + m_creature->SetReactState(REACT_PASSIVE); + if (npc_beryl_sorcererAI* pBerylAI = CAST_AI(npc_beryl_sorcererAI, m_creature->AI())) + pBerylAI->StartFollow(CAST_PLR(pCaster), NULL, NULL); + m_creature->UpdateEntry(NPC_CAPTURED_BERLY_SORCERER, TEAM_NEUTRAL); + DoCast(m_creature, SPELL_COSMETIC_ENSLAVE_CHAINS_SELF, true); + CAST_PLR(pCaster)->KilledMonsterCredit(NPC_CAPTURED_BERLY_SORCERER, 0); + bEnslaved = true; + } + } + + void MoveInLineOfSight(Unit* pWho) + { + FollowerAI::MoveInLineOfSight(pWho); + + if (pWho->GetEntry() == NPC_LIBRARIAN_DONATHAN && m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) + { + SetFollowComplete(); + m_creature->DisappearAndDie(); + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_beryl_sorcerer(Creature* pCreature) +{ + return new npc_beryl_sorcererAI(pCreature); +} + +/*###### +## npc_imprisoned_beryl_sorcerer +######*/ + +enum eImprisionedBerylSorcerer +{ + SPELL_NEURAL_NEEDLE = 45634, + + NPC_IMPRISONED_BERYL_SORCERER = 25478, + + SAY_IMPRISIONED_BERYL_1 = -1571024, + SAY_IMPRISIONED_BERYL_2 = -1571025, + SAY_IMPRISIONED_BERYL_3 = -1571026, + SAY_IMPRISIONED_BERYL_4 = -1571027, + SAY_IMPRISIONED_BERYL_5 = -1571028, + SAY_IMPRISIONED_BERYL_6 = -1571029, + SAY_IMPRISIONED_BERYL_7 = -1571030, +}; + +struct TRINITY_DLL_DECL npc_imprisoned_beryl_sorcererAI : public ScriptedAI +{ + npc_imprisoned_beryl_sorcererAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pCaster = NULL; + } + + Player *pCaster; + + uint32 uiStep; + uint32 uiPhase; + + void Reset() + { + uiStep = 1; + uiPhase = 0; + } + + void EnterCombat(Unit* pWho) + { + return; + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + { + if (pSpell->Id == SPELL_NEURAL_NEEDLE && pCaster->GetTypeId() == TYPEID_PLAYER) + { + ++uiPhase; + pCaster = CAST_PLR(pCaster); + } + } + + void UpdateAI(const uint32 uiDiff) + { + ScriptedAI::UpdateAI(uiDiff); + + if (!m_creature->HasAura(SPELL_COSMETIC_ENSLAVE_CHAINS_SELF)) + DoCast(m_creature, SPELL_COSMETIC_ENSLAVE_CHAINS_SELF); + + if (m_creature->GetReactState() != REACT_PASSIVE) + m_creature->SetReactState(REACT_PASSIVE); + + switch (uiPhase) + { + case 1: + if (uiStep == 1) + { + DoScriptText(SAY_IMPRISIONED_BERYL_1, m_creature); + uiStep = 2; + } + break; + + case 2: + if (uiStep == 2) + { + DoScriptText(SAY_IMPRISIONED_BERYL_2, m_creature); + uiStep = 3; + } + break; + + case 3: + if (uiStep == 3) + { + DoScriptText(SAY_IMPRISIONED_BERYL_3, m_creature); + uiStep = 4; + } + break; + + case 4: + if (uiStep == 4) + { + DoScriptText(SAY_IMPRISIONED_BERYL_4, m_creature); + uiStep = 5; + } + break; + + case 5: + if (uiStep == 5) + { + if (pCaster) + { + DoScriptText(SAY_IMPRISIONED_BERYL_5, m_creature); + pCaster->KilledMonsterCredit(25478,0); + uiStep = 6; + } + } + break; + + case 6: + if (uiStep == 6) + { + DoScriptText(SAY_IMPRISIONED_BERYL_6, m_creature); + uiStep = 7; + } + break; + + case 7: + if (uiStep == 7) + { + DoScriptText(SAY_IMPRISIONED_BERYL_7, m_creature); + uiStep = 1; + uiPhase = 0; + } + break; + } + + if (!UpdateVictim()) + return; + } +}; + +CreatureAI* GetAI_npc_imprisoned_beryl_sorcerer(Creature* pCreature) +{ + return new npc_imprisoned_beryl_sorcererAI(pCreature); +} + +/*###### +## npc_mootoo_the_younger +######*/ +enum Script_Texts_Mootoo_the_Younger +{ + SAY_1 =-1750040, + SAY_2 =-1750041, + SAY_3 =-1750042, + SAY_4 =-1750043, + SAY_5 =-1750044 +}; +enum Mootoo_the_Younger_Entries +{ + NPC_MOOTOO_THE_YOUNGER =25504, + QUEST_ESCAPING_THE_MIST =11664 +}; +bool QuestAccept_npc_mootoo_the_younger(Player* pPlayer, Creature* pCreature, Quest const* quest) +{ + if (quest->GetQuestId()==QUEST_ESCAPING_THE_MIST) + { + switch (pPlayer->GetTeam()) + { + case ALLIANCE: + pCreature->setFaction(FACTION_ESCORTEE_A); + break; + case HORDE: + pCreature->setFaction(FACTION_ESCORTEE_H); + break; + } + DoScriptText(SAY_1, pCreature); + CAST_AI(npc_escortAI, (pCreature->AI()))->Start(true, false, pPlayer->GetGUID()); + } + return true; +} +struct TRINITY_DLL_DECL npc_mootoo_the_youngerAI : public npc_escortAI +{ + npc_mootoo_the_youngerAI(Creature *c) : npc_escortAI(c) {} + + void Reset() + { + SetDespawnAtFar(false); + } + + void JustDied(Unit* killer) + { + if (Player* pPlayer=GetPlayerForEscort()) + pPlayer->FailQuest(QUEST_ESCAPING_THE_MIST); + } + + void WaypointReached(uint32 i) + { + Player* pPlayer = GetPlayerForEscort(); + + if (!pPlayer) + return; + + switch(i) + { + case 10: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + DoScriptText(SAY_2, m_creature); + break; + case 12: + DoScriptText(SAY_3, m_creature); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LOOT); + break; + case 16: + DoScriptText(SAY_4, m_creature); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + break; + case 20: + me->SetPhaseMask(1,true); + DoScriptText(SAY_5, m_creature); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + if (pPlayer) + pPlayer->GroupEventHappens(QUEST_ESCAPING_THE_MIST, m_creature); + SetRun(true); + break; + } + } +}; +CreatureAI* GetAI_npc_mootoo_the_younger(Creature* pCreature) +{ + return new npc_mootoo_the_youngerAI(pCreature); +} + +/*###### +## npc_bonker_togglevolt +######*/ + +enum Bonker_Togglevolt_Entries +{ + NPC_BONKER_TOGGLEVOLT =25589, + QUEST_GET_ME_OUTA_HERE =11673 +}; +enum Script_Texts_Bonker_Togglevolt +{ + SAY_bonker_1 =-1700002, + SAY_bonker_2 =-1700003 +}; + +bool QuestAccept_npc_bonker_togglevolt(Player* pPlayer, Creature* pCreature, Quest const* quest) +{ + if (quest->GetQuestId()==QUEST_GET_ME_OUTA_HERE) + { + switch (pPlayer->GetTeam()) + { + case ALLIANCE: + pCreature->setFaction(FACTION_ESCORTEE_A); + break; + case HORDE: + pCreature->setFaction(FACTION_ESCORTEE_H); + break; + } + DoScriptText(SAY_bonker_2, pCreature, pPlayer); + CAST_AI(npc_escortAI, (pCreature->AI()))->Start(true, true, pPlayer->GetGUID()); + } + return true; +} +struct TRINITY_DLL_DECL npc_bonker_togglevoltAI : public npc_escortAI +{ + npc_bonker_togglevoltAI(Creature *c) : npc_escortAI(c) {} + uint32 Bonker_agro; + + void Reset() + { + Bonker_agro=0; + SetDespawnAtFar(false); + } + + void JustDied(Unit* killer) + { + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->FailQuest(QUEST_ESCAPING_THE_MIST); + } + + void UpdateEscortAI(const uint32 diff) + { + if (GetAttack() && UpdateVictim()) + { + if(Bonker_agro==0) + { + DoScriptText(SAY_bonker_1,m_creature); + Bonker_agro++; + } + DoMeleeAttackIfReady(); + } + else Bonker_agro=0; + } + + void WaypointReached(uint32 i) + { + Player* pPlayer = GetPlayerForEscort(); + + if (!pPlayer) + return; + + switch(i) + { + case 29: + if (pPlayer) + pPlayer->GroupEventHappens(QUEST_GET_ME_OUTA_HERE, m_creature); + break; + } + } +}; + +CreatureAI* GetAI_npc_bonker_togglevolt(Creature* pCreature) +{ + return new npc_bonker_togglevoltAI(pCreature); +} + +void AddSC_borean_tundra() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_fizzcrank_fullthrottle"; + newscript->pGossipHello = &GossipHello_npc_fizzcrank_fullthrottle; + newscript->pGossipSelect = &GossipSelect_npc_fizzcrank_fullthrottle; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_surristrasz"; + newscript->pGossipHello = &GossipHello_npc_surristrasz; + newscript->pGossipSelect = &GossipSelect_npc_surristrasz; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_tiare"; + newscript->pGossipHello = &GossipHello_npc_tiare; + newscript->pGossipSelect = &GossipSelect_npc_tiare; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_sinkhole_kill_credit"; + newscript->GetAI = &GetAI_npc_sinkhole_kill_credit; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_khunok_the_behemoth"; + newscript->GetAI = &GetAI_npc_khunok_the_behemoth; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_keristrasza"; + newscript->pGossipHello = &GossipHello_npc_keristrasza; + newscript->pGossipSelect = &GossipSelect_npc_keristrasza; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_corastrasza"; + newscript->pGossipHello = &GossipHello_npc_corastrasza; + newscript->pGossipSelect = &GossipSelect_npc_corastrasza; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_iruk"; + newscript->pGossipHello = &GossipHello_npc_iruk; + newscript->pGossipSelect = &GossipSelect_npc_iruk; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_nerubar_victim"; + newscript->GetAI = &GetAI_mob_nerubar_victim; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_scourge_prisoner"; + newscript->GetAI = &GetAI_npc_scourge_prisoner; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_jenny"; + newscript->GetAI = &GetAI_npc_jenny; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_fezzix_geartwist"; + newscript->GetAI = &GetAI_npc_fezzix_geartwist; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_nesingwary_trapper"; + newscript->GetAI = &GetAI_npc_nesingwary_trapper; + newscript->RegisterSelf(); + newscript = new Script; + + newscript = new Script; + newscript->Name = "npc_lurgglbr"; + newscript->GetAI = &GetAI_npc_lurgglbr; + newscript->pQuestAccept = &QuestAccept_npc_lurgglbr; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_nexus_drake_hatchling"; + newscript->GetAI = &GetAI_npc_nexus_drake_hatchling; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_thassarian"; + newscript->GetAI = &GetAI_npc_thassarian; + newscript->pGossipHello = &GossipHello_npc_thassarian; + newscript->pGossipSelect = &GossipSelect_npc_thassarian; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_image_lich_king"; + newscript->GetAI = &GetAI_npc_image_lich_king; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_counselor_talbot"; + newscript->GetAI = &GetAI_npc_counselor_talbot; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_leryssa"; + newscript->GetAI = &GetAI_npc_leryssa; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_general_arlos"; + newscript->GetAI = &GetAI_npc_general_arlos; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_beryl_sorcerer"; + newscript->GetAI = &GetAI_npc_beryl_sorcerer; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_imprisoned_beryl_sorcerer"; + newscript->GetAI = &GetAI_npc_imprisoned_beryl_sorcerer; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_mootoo_the_younger"; + newscript->GetAI = &GetAI_npc_mootoo_the_younger; + newscript->pQuestAccept=&QuestAccept_npc_mootoo_the_younger; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_bonker_togglevolt"; + newscript->GetAI = &GetAI_npc_bonker_togglevolt; + newscript->pQuestAccept=&QuestAccept_npc_bonker_togglevolt; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp new file mode 100644 index 00000000000..db2a46ea28e --- /dev/null +++ b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Argent Challenge Encounter. +SD%Complete: 90 % +SDComment: Texts are not implemented. +SDCategory: Trial of the Champion +EndScriptData */ + +#include "ScriptedPch.h" +#include "trial_of_the_champion.h" + +enum eSpells +{ + //Eadric + SPELL_EADRIC_ACHIEVEMENT = 68197, + SPELL_HAMMER_JUSTICE = 66863, + SPELL_HAMMER_RIGHTEOUS = 66867, + SPELL_RADIANCE = 66935, + SPELL_VENGEANCE = 66865, + + //Paletress + SPELL_SMITE = 66536, + SPELL_SMITE_H = 67674, + SPELL_HOLY_FIRE = 66538, + SPELL_HOLY_FIRE_H = 67676, + SPELL_RENEW = 66537, + SPELL_RENEW_H = 67675, + SPELL_HOLY_NOVA = 66546, + SPELL_SHIELD = 66515, + SPELL_CONFESS = 66680, + SPELL_SUMMON_MEMORY = 66545, + + //Memory + SPELL_OLD_WOUNDS = 66620, + SPELL_OLD_WOUNDS_H = 67679, + SPELL_SHADOWS_PAST = 66619, + SPELL_SHADOWS_PAST_H = 67678, + SPELL_WAKING_NIGHTMARE = 66552, + SPELL_WAKING_NIGHTMARE_H = 67677 +}; + +struct TRINITY_DLL_DECL boss_eadricAI : public ScriptedAI +{ + boss_eadricAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 uiVenganceTimer; + uint32 uiRadianceTimer; + uint32 uiHammerJusticeTimer; + + void Reset() + { + uiVenganceTimer = 10000; + uiRadianceTimer = 16000; + uiHammerJusticeTimer = 25000; + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + if (uiHammerJusticeTimer <= uiDiff) + { + m_creature->InterruptNonMeleeSpells(true); + + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 250, true)) + { + if (pTarget && pTarget->isAlive()) + { + DoCast(pTarget, SPELL_HAMMER_JUSTICE); + DoCast(pTarget, SPELL_HAMMER_RIGHTEOUS); + } + } + uiHammerJusticeTimer = 25000; + } else uiHammerJusticeTimer -= uiDiff; + + if (uiVenganceTimer <= uiDiff) + { + DoCast(m_creature,SPELL_VENGEANCE); + + uiVenganceTimer = 10000; + } else uiVenganceTimer -= uiDiff; + + if (uiRadianceTimer <= uiDiff) + { + DoCastAOE(SPELL_RADIANCE); + + uiRadianceTimer = 16000; + } else uiRadianceTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_eadric(Creature* pCreature) +{ + return new boss_eadricAI(pCreature); +} + +struct TRINITY_DLL_DECL boss_paletressAI : public ScriptedAI +{ + boss_paletressAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pMemory = NULL; + } + + ScriptedInstance* pInstance; + + Creature* pMemory; + + bool bHealth; + + uint32 uiHolyFireTimer; + uint32 uiHolySmiteTimer; + uint32 uiRenewTimer; + + uint32 uiRandomSpell; + + void Reset() + { + m_creature->RemoveAllAuras(); + + uiHolyFireTimer = urand(9000,12000); + uiHolySmiteTimer = urand(5000,7000); + uiRenewTimer = urand(2000,5000); + uiRandomSpell = 0; + + bHealth = false; + + if (pMemory && pMemory->isAlive()) + pMemory->RemoveFromWorld(); + } + + void SetData(uint32 uiId, uint32 uiValue) + { + if (uiId == 1) + m_creature->RemoveAura(SPELL_SHIELD); + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + if (uiHolyFireTimer <= uiDiff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 250, true)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget,DUNGEON_MODE(SPELL_HOLY_FIRE,SPELL_HOLY_FIRE_H)); + } + if (m_creature->HasAura(SPELL_SHIELD)) + uiHolyFireTimer = 13000; + else + uiHolyFireTimer = urand(9000,12000); + } else uiHolyFireTimer -= uiDiff; + + if (uiHolySmiteTimer <= uiDiff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 250, true)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget,DUNGEON_MODE(SPELL_SMITE,SPELL_SMITE_H)); + } + if (m_creature->HasAura(SPELL_SHIELD)) + uiHolySmiteTimer = 9000; + else + uiHolySmiteTimer = urand(5000,7000); + } else uiHolySmiteTimer -= uiDiff; + + if (m_creature->HasAura(SPELL_SHIELD)) + if (uiRenewTimer <= uiDiff) + { + m_creature->InterruptNonMeleeSpells(true); + uint8 uiTarget = urand(0,1); + switch(uiTarget) + { + case 0: + DoCast(m_creature,DUNGEON_MODE(SPELL_RENEW,SPELL_RENEW_H)); + break; + case 1: + if (pMemory && pMemory->isAlive()) + DoCast(pMemory,DUNGEON_MODE(SPELL_RENEW,SPELL_RENEW_H)); + break; + } + uiRenewTimer = urand(15000,17000); + } else uiRenewTimer -= uiDiff; + + + if (!bHealth && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 25) + { + m_creature->InterruptNonMeleeSpells(true); + uiRandomSpell = urand(1,26); + DoCastAOE(SPELL_HOLY_NOVA,false); + DoCast(m_creature, SPELL_SHIELD); + DoCastAOE(SPELL_SUMMON_MEMORY,false); + DoCastAOE(SPELL_CONFESS,false); + + bHealth = true; + } + + DoMeleeAttackIfReady(); + } + + void JustSummoned(Creature* pSummon) + { + pMemory = pSummon; + } +}; + +CreatureAI* GetAI_boss_paletress(Creature* pCreature) +{ + return new boss_paletressAI(pCreature); +} + +struct TRINITY_DLL_DECL npc_memoryAI : public ScriptedAI +{ + npc_memoryAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 uiOldWoundsTimer; + uint32 uiShadowPastTimer; + uint32 uiWakingNightmare; + + void Reset() + { + uiOldWoundsTimer = 12000; + uiShadowPastTimer = 5000; + uiWakingNightmare = 7000; + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + if (uiOldWoundsTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM,0)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget, DUNGEON_MODE(SPELL_OLD_WOUNDS,SPELL_OLD_WOUNDS_H)); + } + uiOldWoundsTimer = 12000; + }else uiOldWoundsTimer -= uiDiff; + + if (uiWakingNightmare <= uiDiff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_WAKING_NIGHTMARE,SPELL_WAKING_NIGHTMARE_H)); + uiWakingNightmare = 7000; + }else uiWakingNightmare -= uiDiff; + + if (uiShadowPastTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM,1)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget,DUNGEON_MODE(SPELL_SHADOWS_PAST,SPELL_SHADOWS_PAST_H)); + } + uiShadowPastTimer = 5000; + }else uiShadowPastTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + { + if (pSummoner && pSummoner->isAlive()) + CAST_CRE(pSummoner)->AI()->SetData(1,0); + } + } +}; + +CreatureAI* GetAI_npc_memory(Creature* pCreature) +{ + return new npc_memoryAI(pCreature); +} + +void AddSC_boss_argent_challenge() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "boss_eadric"; + NewScript->GetAI = &GetAI_boss_eadric; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "boss_paletress"; + NewScript->GetAI = &GetAI_boss_paletress; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "npc_memory"; + NewScript->GetAI = &GetAI_npc_memory; + NewScript->RegisterSelf(); +} diff --git a/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp new file mode 100644 index 00000000000..03582e4a803 --- /dev/null +++ b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss Black Knight +SD%Complete: 80% +SDComment: missing yells. not sure about timers. +SDCategory: Trial of the Champion +EndScriptData */ + +#include "ScriptedPch.h" +#include "trial_of_the_champion.h" + +enum eSpells +{ + //phase 1 + SPELL_PLAGUE_STRIKE = 67884, + SPELL_PLAGUE_STRIKE_2 = 67724, + SPELL_ICY_TOUCH_H = 67881, + SPELL_ICY_TOUCH = 67718, + SPELL_DEATH_RESPITE = 67745, + SPELL_DEATH_RESPITE_2 = 68306, + SPELL_DEATH_RESPITE_3 = 66798, + SPELL_OBLITERATE_H = 67883, + SPELL_OBLITERATE = 67725, + //in this phase should rise herald (the spell is missing) + + //phase 2 - During this phase, the Black Knight will use the same abilities as in phase 1, except for Death's Respite + SPELL_ARMY_DEAD = 67761, + SPELL_DESECRATION = 67778, + SPELL_DESECRATION_2 = 67778, + SPELL_GHOUL_EXPLODE = 67751, + + //phase 3 + SPELL_DEATH_BITE_H = 67875, + SPELL_DEATH_BITE = 67808, + SPELL_MARKED_DEATH = 67882, + SPELL_MARKED_DEATH_2 = 67823, + + SPELL_BLACK_KNIGHT_RES = 67693, + + SPELL_LEAP = 67749, + SPELL_LEAP_H = 67880 +}; + +enum eModels +{ + MODEL_SKELETON = 29846, + MODEL_GHOST = 21300 +}; + +enum ePhases +{ + PHASE_UNDEAD = 1, + PHASE_SKELETON = 2, + PHASE_GHOST = 3 +}; + +struct TRINITY_DLL_DECL boss_black_knightAI : public ScriptedAI +{ + boss_black_knightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + std::list<uint64> SummonList; + + bool bEventInProgress; + bool bEvent; + bool bSummonArmy; + bool bDeathArmyDone; + + uint8 uiPhase; + + uint32 uiPlagueStrikeTimer; + uint32 uiIcyTouchTimer; + uint32 uiDeathRespiteTimer; + uint32 uiObliterateTimer; + uint32 uiDesecration; + uint32 uiResurrectTimer; + uint32 uiDeathArmyCheckTimer; + uint32 uiGhoulExplodeTimer; + uint32 uiDeathBiteTimer; + uint32 uiMarkedDeathTimer; + + void Reset() + { + RemoveSummons(); + m_creature->SetDisplayId(m_creature->GetNativeDisplayId()); + m_creature->clearUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED); + + bEventInProgress = false; + bEvent = false; + bSummonArmy = false; + bDeathArmyDone = false; + + uiPhase = PHASE_UNDEAD; + + uiIcyTouchTimer = urand(5000,9000); + uiPlagueStrikeTimer = urand(10000,13000); + uiDeathRespiteTimer = urand(15000,16000); + uiObliterateTimer = urand(17000,19000); + uiDesecration = urand(15000,16000); + uiDeathArmyCheckTimer = 7000; + uiResurrectTimer = 4000; + uiGhoulExplodeTimer = 8000; + uiDeathBiteTimer = urand (2000,4000); + uiMarkedDeathTimer = urand (5000,7000); + } + + void RemoveSummons() + { + if (SummonList.empty()) + return; + + for(std::list<uint64>::iterator itr = SummonList.begin(); itr != SummonList.end(); ++itr) + { + if (Creature* pTemp = (Creature*)Unit::GetUnit(*m_creature, *itr)) + if (pTemp) + pTemp->DisappearAndDie(); + } + SummonList.clear(); + } + + void JustSummoned(Creature* pSummon) + { + SummonList.push_back(pSummon->GetGUID()); + pSummon->AI()->AttackStart(m_creature->getVictim()); + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (bEventInProgress) + if (uiResurrectTimer <= uiDiff) + { + m_creature->SetHealth(m_creature->GetMaxHealth()); + DoCast(m_creature,SPELL_BLACK_KNIGHT_RES,true); + uiPhase++; + uiResurrectTimer = 4000; + bEventInProgress = false; + m_creature->clearUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED); + } else uiResurrectTimer -= uiDiff; + + switch(uiPhase) + { + case PHASE_UNDEAD: + case PHASE_SKELETON: + { + if (uiIcyTouchTimer <= uiDiff) + { + DoCastVictim(DUNGEON_MODE(SPELL_ICY_TOUCH,SPELL_ICY_TOUCH_H)); + uiIcyTouchTimer = urand(5000,7000); + } else uiIcyTouchTimer -= uiDiff; + if (uiPlagueStrikeTimer <= uiDiff) + { + DoCastVictim(DUNGEON_MODE(SPELL_ICY_TOUCH,SPELL_ICY_TOUCH_H)); + uiPlagueStrikeTimer = urand(12000,15000); + } else uiPlagueStrikeTimer -= uiDiff; + if (uiObliterateTimer <= uiDiff) + { + DoCastVictim(DUNGEON_MODE(SPELL_OBLITERATE,SPELL_OBLITERATE_H)); + uiObliterateTimer = urand(17000,19000); + } else uiObliterateTimer -= uiDiff; + switch(uiPhase) + { + case PHASE_UNDEAD: + { + if (uiDeathRespiteTimer <= uiDiff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget,SPELL_DEATH_RESPITE); + } + uiDeathRespiteTimer = urand(15000,16000); + } else uiDeathRespiteTimer -= uiDiff; + break; + } + case PHASE_SKELETON: + { + if (!bSummonArmy) + { + bSummonArmy = true; + m_creature->addUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED); + DoCast(m_creature, SPELL_ARMY_DEAD); + } + if (!bDeathArmyDone) + if (uiDeathArmyCheckTimer <= uiDiff) + { + m_creature->clearUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED); + uiDeathArmyCheckTimer = 0; + bDeathArmyDone = true; + } else uiDeathArmyCheckTimer -= uiDiff; + if (uiDesecration <= uiDiff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget,SPELL_DESECRATION); + } + uiDesecration = urand(15000,16000); + } else uiDesecration -= uiDiff; + if (uiGhoulExplodeTimer <= uiDiff) + { + DoCast(m_creature, SPELL_GHOUL_EXPLODE); + uiGhoulExplodeTimer = 8000; + } else uiGhoulExplodeTimer -= uiDiff; + break; + } + break; + } + break; + } + case PHASE_GHOST: + { + if (uiDeathBiteTimer <= uiDiff) + { + DoCastAOE(DUNGEON_MODE(SPELL_DEATH_BITE,SPELL_DEATH_BITE_H)); + uiDeathBiteTimer = urand (2000, 4000); + } else uiDeathBiteTimer -= uiDiff; + if (uiMarkedDeathTimer <= uiDiff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget,SPELL_MARKED_DEATH); + } + uiMarkedDeathTimer = urand (5000, 7000); + } else uiMarkedDeathTimer -= uiDiff; + break; + } + } + + if (!m_creature->hasUnitState(UNIT_STAT_ROOT) && !m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 0) + DoMeleeAttackIfReady(); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + { + if (uiDamage > m_creature->GetHealth() && uiPhase <= PHASE_SKELETON) + { + uiDamage = 0; + m_creature->SetHealth(0); + m_creature->addUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED); + RemoveSummons(); + switch(uiPhase) + { + case PHASE_UNDEAD: + m_creature->SetDisplayId(MODEL_SKELETON); + break; + case PHASE_SKELETON: + m_creature->SetDisplayId(MODEL_GHOST); + break; + } + bEventInProgress = true; + } + } +}; + +CreatureAI* GetAI_boss_black_knight(Creature *pCreature) +{ + return new boss_black_knightAI (pCreature); +} + +struct TRINITY_DLL_DECL npc_risen_ghoulAI : public ScriptedAI +{ + npc_risen_ghoulAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 uiAttackTimer; + + void Reset() + { + uiAttackTimer = 3500; + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + if (uiAttackTimer <= uiDiff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget, (DUNGEON_MODE(SPELL_LEAP,SPELL_LEAP_H))); + } + uiAttackTimer = 3500; + } else uiAttackTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_risen_ghoul(Creature* pCreature) +{ + return new npc_risen_ghoulAI(pCreature); +} + +void AddSC_boss_black_knight() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "boss_black_knight"; + NewScript->GetAI = &GetAI_boss_black_knight; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "npc_risen_ghoul"; + NewScript->GetAI = &GetAI_npc_risen_ghoul; + NewScript->RegisterSelf(); +} diff --git a/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp new file mode 100644 index 00000000000..327faafc0db --- /dev/null +++ b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp @@ -0,0 +1,580 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +* 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_grand_champions +SD%Complete: 92% +SDComment: missing yells. hunter AI sucks. no pvp diminuishing returns(is it DB related?) +SDCategory: Trial Of the Champion +EndScriptData */ + +#include "ScriptedPch.h" +#include "trial_of_the_champion.h" + +enum Spells +{ + //yells + + //warrior + SPELL_MORTAL_STRIKE = 68783, + SPELL_MORTAL_STRIKE_H = 68784, + SPELL_BLADESTORM = 63784, + SPELL_INTERCEPT = 67540, + SPELL_ROLLING_THROW = 47115, //need core support for spell 67546, using 47115 instead + //mage + SPELL_FIREBALL = 66042, + SPELL_FIREBALL_H = 68310, + SPELL_BLAST_WAVE = 66044, + SPELL_BLAST_WAVE_H = 68312, + SPELL_HASTE = 66045, + SPELL_POLYMORPH = 66043, + SPELL_POLYMORPH_H = 68311, + //shaman + SPELL_CHAIN_LIGHTNING = 67529, + SPELL_CHAIN_LIGHTNING_H = 68319, + SPELL_EARTH_SHIELD = 67530, + SPELL_HEALING_WAVE = 67528, + SPELL_HEALING_WAVE_H = 68318, + SPELL_HEX_OF_MENDING = 67534, + //hunter + SPELL_DISENGAGE = 68340, + SPELL_LIGHTNING_ARROWS = 66083, + SPELL_MULTI_SHOT = 66081, + SPELL_SHOOT = 66079, + //rogue + SPELL_EVISCERATE = 67709, + SPELL_EVISCERATE_H = 68317, + SPELL_FAN_OF_KNIVES = 67706, + SPELL_POISON_BOTTLE = 67701 +}; + +// Warrior +struct TRINITY_DLL_DECL mob_toc5_warriorAI : public ScriptedAI +{ + mob_toc5_warriorAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 Mortal_Strike_Timer; + uint32 Bladestorm_Timer; + uint32 Rolling_Throw_Timer; + uint32 Intercept_Cooldown; + uint32 intercept_check; + + void Reset() + { + m_creature->SetRespawnDelay(999999999); + Mortal_Strike_Timer = 6000; + Bladestorm_Timer = 20000; + Rolling_Throw_Timer = 30000; + Intercept_Cooldown = 0; + intercept_check = 1000; + } + + void EnterEvadeMode() + { + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + if (m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE) + m_creature->ForcedDespawn(); + else + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) + { + if (!m_pInstance) + return; + + if(!m_creature->FindNearestCreature(35572, 200, true) && !m_creature->FindNearestCreature(35569, 200, true) && !m_creature->FindNearestCreature(35571, 200, true) && + !m_creature->FindNearestCreature(35570, 200, true) && !m_creature->FindNearestCreature(35617, 200, true) && !m_creature->FindNearestCreature(34705, 200, true) + && !m_creature->FindNearestCreature(34702, 200, true) && !m_creature->FindNearestCreature(34701, 200, true) && !m_creature->FindNearestCreature(34657, 200, true) + && !m_creature->FindNearestCreature(34703, 200, true)) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectVictim() || !m_creature->getVictim()) + return; + + if (Mortal_Strike_Timer < diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_MORTAL_STRIKE, SPELL_MORTAL_STRIKE_H)); + Mortal_Strike_Timer = 6000; + }else Mortal_Strike_Timer -= diff; + + if (Rolling_Throw_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ROLLING_THROW); + Rolling_Throw_Timer = 30000; + }else Rolling_Throw_Timer -= diff; + + if (Bladestorm_Timer < diff) + { + DoCast(m_creature, SPELL_BLADESTORM); + Bladestorm_Timer = 90000; + }else Bladestorm_Timer -= diff; + + if (intercept_check < diff) + { + if (!m_creature->IsWithinDistInMap(m_creature->getVictim(), 8) && m_creature->IsWithinDistInMap(m_creature->getVictim(), 25) && Intercept_Cooldown < diff) + { + DoCast(m_creature->getVictim(), SPELL_INTERCEPT); + Intercept_Cooldown = 15000; + } + intercept_check = 1000; + } + else + { + intercept_check -= diff; + Intercept_Cooldown -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_warrior(Creature* pCreature) +{ + return new mob_toc5_warriorAI(pCreature); +} + +// Mage +struct TRINITY_DLL_DECL mob_toc5_mageAI : public ScriptedAI +{ + mob_toc5_mageAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 Fireball_Timer; + uint32 Blast_Wave_Timer; + uint32 Haste_Timer; + uint32 Polymorph_Timer; + + void Reset() + { + m_creature->SetRespawnDelay(999999999); + Fireball_Timer = 0; + Blast_Wave_Timer = 20000; + Haste_Timer = 9000; + Polymorph_Timer = 15000; + } + + void EnterEvadeMode() + { + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + if (m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE) + m_creature->ForcedDespawn(); + else + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) + { + if (!m_pInstance) + return; + + if(!m_creature->FindNearestCreature(35572, 200, true) && !m_creature->FindNearestCreature(35569, 200, true) && !m_creature->FindNearestCreature(35571, 200, true) && + !m_creature->FindNearestCreature(35570, 200, true) && !m_creature->FindNearestCreature(35617, 200, true) && !m_creature->FindNearestCreature(34705, 200, true) + && !m_creature->FindNearestCreature(34702, 200, true) && !m_creature->FindNearestCreature(34701, 200, true) && !m_creature->FindNearestCreature(34657, 200, true) + && !m_creature->FindNearestCreature(34703, 200, true)) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectVictim() || !m_creature->getVictim()) + return; + + if (Fireball_Timer < diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_FIREBALL, SPELL_FIREBALL_H)); + Fireball_Timer = 3000; + }else Fireball_Timer -= diff; + + if (Blast_Wave_Timer < diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_BLAST_WAVE, SPELL_BLAST_WAVE_H)); + Blast_Wave_Timer = 20000; + }else Blast_Wave_Timer -= diff; + + if (Haste_Timer < diff) + { + DoCast(m_creature, SPELL_HASTE); + Haste_Timer = 10000; + }else Haste_Timer -= diff; + + if (Polymorph_Timer < diff) + { + if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1)) + DoCast(target, DUNGEON_MODE(SPELL_POLYMORPH, SPELL_POLYMORPH_H)); + Polymorph_Timer = 15000; + }else Polymorph_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_mage(Creature* pCreature) +{ + return new mob_toc5_mageAI(pCreature); +} + +// Shaman +struct TRINITY_DLL_DECL mob_toc5_shamanAI : public ScriptedAI +{ + mob_toc5_shamanAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 Chain_Lightning_Timer; + uint32 Earth_Shield_Timer; + uint32 Healing_Wave_Timer; + uint32 Hex_Timer; + + float mob1_health; + float mob2_health; + float mob3_health; + + void Reset() + { + m_creature->SetRespawnDelay(999999999); + Chain_Lightning_Timer = 1000; + Earth_Shield_Timer = 5000; + Healing_Wave_Timer = 13000; + Hex_Timer = 10000; + } + + void EnterEvadeMode() + { + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + if (m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE) + m_creature->ForcedDespawn(); + else + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) + { + if (!m_pInstance) + return; + + if(!m_creature->FindNearestCreature(35572, 200, true) && !m_creature->FindNearestCreature(35569, 200, true) && !m_creature->FindNearestCreature(35571, 200, true) && + !m_creature->FindNearestCreature(35570, 200, true) && !m_creature->FindNearestCreature(35617, 200, true) && !m_creature->FindNearestCreature(34705, 200, true) + && !m_creature->FindNearestCreature(34702, 200, true) && !m_creature->FindNearestCreature(34701, 200, true) && !m_creature->FindNearestCreature(34657, 200, true) + && !m_creature->FindNearestCreature(34703, 200, true)) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectVictim() || !m_creature->getVictim()) + return; + + if (Chain_Lightning_Timer < diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_CHAIN_LIGHTNING, SPELL_CHAIN_LIGHTNING_H)); + Chain_Lightning_Timer = 10000; + }else Chain_Lightning_Timer -= diff; + + if (Hex_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_HEX_OF_MENDING); + Hex_Timer = 20000; + }else Hex_Timer -= diff; + + if (Healing_Wave_Timer < diff) + { + if(Unit* target = m_creature->SelectNearestTarget(40)) + if(target->GetHealth() == target->GetHealth() * 100 / target->GetMaxHealth() && target->IsFriendlyTo(m_creature)) + { + DoCast(target, DUNGEON_MODE(SPELL_HEALING_WAVE, SPELL_HEALING_WAVE_H)); + Healing_Wave_Timer = 8000; + } + }else Healing_Wave_Timer -= diff; + + if (Earth_Shield_Timer < diff) + { + if(Unit* target = m_creature->SelectNearestTarget(40)) + if(!target->HasAura(SPELL_EARTH_SHIELD,m_creature->GetGUID()) && target->IsFriendlyTo(m_creature)) + { + DoCast(target, SPELL_EARTH_SHIELD); + Earth_Shield_Timer = 25000; + } + }else Earth_Shield_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_shaman(Creature* pCreature) +{ + return new mob_toc5_shamanAI(pCreature); +} + +// Hunter +struct TRINITY_DLL_DECL mob_toc5_hunterAI : public ScriptedAI +{ + mob_toc5_hunterAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 Shoot_Timer; + uint32 Lightning_Arrows_Timer; + uint32 Multi_Shot_Timer; + uint32 Disengage_Cooldown; + uint32 enemy_check; + uint32 disengage_check; + + void Reset() + { + m_creature->SetRespawnDelay(999999999); + Shoot_Timer = 0; + Lightning_Arrows_Timer = 13000; + Multi_Shot_Timer = 10000; + Disengage_Cooldown = 0; + enemy_check = 1000; + disengage_check; + } + + void EnterEvadeMode() + { + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + if (m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE) + m_creature->ForcedDespawn(); + else + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) + { + if (!m_pInstance) + return; + + if(!m_creature->FindNearestCreature(35572, 200, true) && !m_creature->FindNearestCreature(35569, 200, true) && !m_creature->FindNearestCreature(35571, 200, true) && + !m_creature->FindNearestCreature(35570, 200, true) && !m_creature->FindNearestCreature(35617, 200, true) && !m_creature->FindNearestCreature(34705, 200, true) + && !m_creature->FindNearestCreature(34702, 200, true) && !m_creature->FindNearestCreature(34701, 200, true) && !m_creature->FindNearestCreature(34657, 200, true) + && !m_creature->FindNearestCreature(34703, 200, true)) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectVictim() || !m_creature->getVictim()) + return; + + if (enemy_check < diff) + { + if (!m_creature->IsWithinDistInMap(m_creature->getVictim(), 8) && m_creature->IsWithinDistInMap(m_creature->getVictim(), 30)) + { + m_creature->SetSpeed(MOVE_RUN, 0.0001); + } + else + { + m_creature->SetSpeed(MOVE_RUN, 1); + } + enemy_check = 100; + }else enemy_check -= diff; + + if (Disengage_Cooldown>0) + Disengage_Cooldown -= diff; + + if (Shoot_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHOOT); + Shoot_Timer = 3000; + }else Shoot_Timer -= diff; + + if (Multi_Shot_Timer < diff) + { + m_creature->CastStop(SPELL_SHOOT); + DoCast(m_creature->getVictim(), SPELL_MULTI_SHOT); + Multi_Shot_Timer = 10000; + }else Multi_Shot_Timer -= diff; + + if (Lightning_Arrows_Timer < diff) + { + m_creature->CastStop(SPELL_SHOOT); + DoCast(m_creature, SPELL_LIGHTNING_ARROWS); + Lightning_Arrows_Timer = 25000; + }else Lightning_Arrows_Timer -= diff; + + if (disengage_check < diff) + { + if (m_creature->IsWithinDistInMap(m_creature->getVictim(), 5) && Disengage_Cooldown == 0) + { + DoCast(m_creature, SPELL_DISENGAGE); + Disengage_Cooldown = 15000; + } + disengage_check = 1000; + }else disengage_check -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_hunter(Creature* pCreature) +{ + return new mob_toc5_hunterAI(pCreature); +} + +// Rogue +struct TRINITY_DLL_DECL mob_toc5_rogueAI : public ScriptedAI +{ + mob_toc5_rogueAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 Eviscerate_Timer; + uint32 FoK_Timer; + uint32 Poison_Timer; + + void Reset() + { + m_creature->SetRespawnDelay(999999999); + Eviscerate_Timer = 15000; + FoK_Timer = 10000; + Poison_Timer = 7000; + } + + void EnterEvadeMode() + { + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + if (m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE) + m_creature->ForcedDespawn(); + else + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) + { + if (!m_pInstance) + return; + + if(!m_creature->FindNearestCreature(35572, 200, true) && !m_creature->FindNearestCreature(35569, 200, true) && !m_creature->FindNearestCreature(35571, 200, true) && + !m_creature->FindNearestCreature(35570, 200, true) && !m_creature->FindNearestCreature(35617, 200, true) && !m_creature->FindNearestCreature(34705, 200, true) + && !m_creature->FindNearestCreature(34702, 200, true) && !m_creature->FindNearestCreature(34701, 200, true) && !m_creature->FindNearestCreature(34657, 200, true) + && !m_creature->FindNearestCreature(34703, 200, true)) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectVictim() || !m_creature->getVictim()) + return; + + if (Eviscerate_Timer < diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_EVISCERATE, SPELL_EVISCERATE_H)); + Eviscerate_Timer = 10000; + }else Eviscerate_Timer -= diff; + + if (FoK_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FAN_OF_KNIVES); + FoK_Timer = 7000; + }else FoK_Timer -= diff; + + if (Poison_Timer < diff) + { + if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0)) + DoCast(m_creature, SPELL_POISON_BOTTLE); + Poison_Timer = 6000; + }else Poison_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_rogue(Creature* pCreature) +{ + return new mob_toc5_rogueAI(pCreature); +} + +void AddSC_boss_grand_champions() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "mob_toc5_warrior"; + NewScript->GetAI = &GetAI_mob_toc5_warrior; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_mage"; + NewScript->GetAI = &GetAI_mob_toc5_mage; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_shaman"; + NewScript->GetAI = &GetAI_mob_toc5_shaman; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_hunter"; + NewScript->GetAI = &GetAI_mob_toc5_hunter; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_rogue"; + NewScript->GetAI = &GetAI_mob_toc5_rogue; + NewScript->RegisterSelf(); +} diff --git a/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp new file mode 100644 index 00000000000..1605b7fd0ab --- /dev/null +++ b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp @@ -0,0 +1,349 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: Instance_Trial_Of_the_Champion +SD%Complete: 100 +SDComment: +SDCategory: Trial Of the Champion +EndScriptData */ + +#include "ScriptedPch.h" +#include "trial_of_the_champion.h" + +struct TRINITY_DLL_DECL instance_trial_of_the_champion : public ScriptedInstance +{ + instance_trial_of_the_champion(Map* pMap) : ScriptedInstance(pMap), m_uiChampionsLootGUID(NULL), m_uiPaletressLootGUID(NULL), m_uiEadricLootGUID(NULL) { Initialize(); } + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string strInstData; + + uint64 m_uiEadricGUID; + uint64 m_uiPaletressGUID; + uint64 m_uiBlackKnightGUID; + uint64 m_uiJaerenGUID; + uint64 m_uiArelasGUID; + uint64 m_uiAnnouncerGUID; + uint64 m_uiBlackKnightMinionGUID; + uint64 m_uiArgentChallenger; + uint64 m_uiMemoryGUID; + + GameObject* m_uiChampionsLootGUID; + GameObject* m_uiPaletressLootGUID; + GameObject* m_uiEadricLootGUID; + + void Initialize() + { + m_uiChampionsLootGUID = 0; + m_uiEadricGUID = 0; + m_uiEadricLootGUID = 0; + m_uiPaletressGUID = 0; + m_uiPaletressLootGUID = 0; + m_uiBlackKnightGUID = 0; + m_uiJaerenGUID = 0; + m_uiArelasGUID = 0; + m_uiAnnouncerGUID = 0; + m_uiBlackKnightMinionGUID = 0; + m_uiArgentChallenger = 0; + m_uiMemoryGUID = 0; + + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } + + return false; + } + + void OnCreatureCreate(Creature* pCreature, bool bAdd) + { + Map::PlayerList const &players = instance->GetPlayers(); + uint32 TeamInInstance = 0; + + if (!players.isEmpty()) + { + if (Player* pPlayer = players.begin()->getSource()) + TeamInInstance = pPlayer->GetTeam(); + } + switch(pCreature->GetEntry()) + { + + // Champions + case NPC_MOKRA: + if (TeamInInstance == HORDE) + pCreature->UpdateEntry(NPC_JACOB, ALLIANCE); + break; + case NPC_ERESSEA: + if (TeamInInstance == HORDE) + pCreature->UpdateEntry(NPC_AMBROSE, ALLIANCE); + break; + case NPC_RUNOK: + if (TeamInInstance == HORDE) + pCreature->UpdateEntry(NPC_COLOSOS, ALLIANCE); + break; + case NPC_ZULTORE: + if (TeamInInstance == HORDE) + pCreature->UpdateEntry(NPC_JAELYNE, ALLIANCE); + break; + case NPC_VISCERI: + if (TeamInInstance == HORDE) + pCreature->UpdateEntry(NPC_LANA, ALLIANCE); + break; + + // Argent Challenge + case NPC_EADRIC: + m_uiEadricGUID = pCreature->GetGUID(); + m_uiArgentChallenger = pCreature->GetGUID(); + break; + case NPC_PALETRESS: + m_uiPaletressGUID = pCreature->GetGUID(); + m_uiArgentChallenger = pCreature->GetGUID(); + break; + + // Black Knight + case NPC_BLACK_KNIGHT: + m_uiBlackKnightGUID = pCreature->GetGUID(); + break; + case NPC_RISEN_JAEREN: + m_uiBlackKnightMinionGUID = pCreature->GetGUID(); + break; + case NPC_RISEN_ARELAS: + m_uiBlackKnightMinionGUID = pCreature->GetGUID(); + break; + + // Coliseum Announcers + case NPC_JAEREN: + m_uiJaerenGUID = pCreature->GetGUID(); + break; + case NPC_ARELAS: + m_uiArelasGUID = pCreature->GetGUID(); + break; + + // memories + case MEMORY_ALGALON: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_ARCHIMONDE: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_CHROMAGGUS: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_CYANIGOSA: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_DELRISSA: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_ECK: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_ENTROPIUS: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_GRUUL: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_HAKKAR: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_HEIGAN: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_HEROD: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_HOGGER: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_IGNIS: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_ILLIDAN: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_INGVAR: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_KALITHRESH: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_LUCIFRON: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_MALCHEZAAR: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_MUTANUS: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_ONYXIA: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_THUNDERAAN: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_VANCLEEF: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_VASHJ: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_VEKNILASH: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + case MEMORY_VEZAX: + m_uiMemoryGUID = pCreature->GetGUID(); + break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case GO_CHAMPIONS_LOOT: m_uiChampionsLootGUID = add ? pGo : NULL; break; + case GO_EADRIC_LOOT: m_uiEadricLootGUID = add ? pGo : NULL; break; + case GO_PALETRESS_LOOT: m_uiPaletressLootGUID = add ? pGo : NULL; break; + case GO_CHAMPIONS_LOOT_H: m_uiChampionsLootGUID = add ? pGo : NULL; break; + case GO_EADRIC_LOOT_H: m_uiEadricLootGUID = add ? pGo : NULL; break; + case GO_PALETRESS_LOOT_H: m_uiPaletressLootGUID = add ? pGo : NULL; break; + } + } + + void SetData(uint32 Type, uint32 Data) + { + switch(Type) + { + case DATA_TOC5_ANNOUNCER: + m_uiAnnouncerGUID = Data; + break; + case DATA_BLACK_KNIGHT_MINION: + m_uiBlackKnightMinionGUID = Data; + break; + case TYPE_GRAND_CHAMPIONS: + if (Data == DONE) + m_uiChampionsLootGUID->SetRespawnTime(m_uiChampionsLootGUID->GetRespawnDelay()); + m_auiEncounter[0] = Data; + break; + case TYPE_ARGENT_CHALLENGE: + if (Data == DONE) + { + if(m_uiEadricGUID == m_uiArgentChallenger) + m_uiEadricLootGUID->SetRespawnTime(m_uiEadricLootGUID->GetRespawnDelay()); + if(m_uiPaletressGUID == m_uiArgentChallenger) + m_uiPaletressLootGUID->SetRespawnTime(m_uiPaletressLootGUID->GetRespawnDelay()); + } + m_auiEncounter[1] = Data; + break; + case TYPE_BLACK_KNIGHT: + m_auiEncounter[2] = Data; + break; + } + + if (Data == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; + + strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + uint64 GetData64(uint32 uiData) + { + switch(uiData) + { + case DATA_MEMORY: + return m_uiMemoryGUID; + case DATA_BLACK_KNIGHT: + return m_uiBlackKnightGUID; + } + + return 0; + } + + std::string GetSaveData() + { + return strInstData; + } + + uint32 GetData(uint32 uiType) + { + switch(uiType) + { + case DATA_BLACK_KNIGHT_MINION: + return m_uiBlackKnightMinionGUID; + case DATA_TOC5_ANNOUNCER: + return m_uiAnnouncerGUID; + case DATA_JAEREN: + return m_uiJaerenGUID; + case DATA_ARELAS: + return m_uiArelasGUID; + case TYPE_GRAND_CHAMPIONS: + case TYPE_ARGENT_CHALLENGE: + case TYPE_BLACK_KNIGHT: + return m_auiEncounter[uiType]; + } + + return 0; + } + + void Load(const char *chrIn) + { + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_trial_of_the_champion(Map* pMap) +{ + return new instance_trial_of_the_champion(pMap); +} + +void AddSC_instance_trial_of_the_champion() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_trial_of_the_champion"; + newscript->GetInstanceData = &GetInstanceData_instance_trial_of_the_champion; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp new file mode 100644 index 00000000000..afc11b99baf --- /dev/null +++ b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp @@ -0,0 +1,135 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Trial Of the Champion +SD%Complete: 80% +SDComment: event script +SDCategory: trial_of_the_champion +EndScriptData */ + +/* ContentData +npc_toc5_announcer +EndContentData */ + +#include "ScriptedPch.h" +#include "trial_of_the_champion.h" + +#define GOSSIP_START_EVENT1 "I'm ready to start challenge." +#define GOSSIP_START_EVENT2 "I'm ready for the next challenge." + +/*###### +## npc_toc5_announcer +######*/ + +struct TRINITY_DLL_DECL npc_toc5_announcerAI : public ScriptedAI +{ + npc_toc5_announcerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 chmp1, chmp2, chmp3, argent; + + void Reset() + { + } + + void StartEvent(Player* pPlayer) + { + if(!pInstance) + return; + if(pInstance->GetData(TYPE_GRAND_CHAMPIONS) == NOT_STARTED && pInstance->GetData(TYPE_ARGENT_CHALLENGE) == NOT_STARTED && pInstance->GetData(TYPE_BLACK_KNIGHT) == NOT_STARTED) + { + chmp1 = RAND(35572,35569,35571,35570,35617); + chmp2 = RAND(35572,35569,35571,35570,35617); + chmp3 = RAND(35572,35569,35571,35570,35617); + if(chmp1 != chmp2 && chmp2 != chmp3 && chmp1 != chmp3) + { + m_creature->SummonCreature(chmp1, 738.665771, 661.031433, 412.394623, 4.698702, TEMPSUMMON_MANUAL_DESPAWN, 0); + m_creature->SummonCreature(chmp2, 746.864441, 660.918762, 411.695465, 4.698700, TEMPSUMMON_MANUAL_DESPAWN, 0); + m_creature->SummonCreature(chmp3, 754.360779, 660.816162, 412.395996, 4.698700, TEMPSUMMON_MANUAL_DESPAWN, 0); + pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } else return; + } + + if(pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE && pInstance->GetData(TYPE_ARGENT_CHALLENGE) == NOT_STARTED && pInstance->GetData(TYPE_BLACK_KNIGHT) == NOT_STARTED) + { + argent = RAND(35119,34928); + m_creature->SummonCreature(argent, 746.864441, 660.918762, 411.695465, 4.698700, TEMPSUMMON_MANUAL_DESPAWN, 0); + pInstance->SetData(TYPE_ARGENT_CHALLENGE, IN_PROGRESS); + } + + if(pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE && pInstance->GetData(TYPE_ARGENT_CHALLENGE) == DONE && pInstance->GetData(TYPE_BLACK_KNIGHT) == NOT_STARTED) + { + m_creature->SummonCreature(NPC_BLACK_KNIGHT, 746.864441, 660.918762, 411.695465, 4.698700, TEMPSUMMON_MANUAL_DESPAWN, 0); + pInstance->SetData(TYPE_BLACK_KNIGHT, IN_PROGRESS); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + void UpdateAI(const uint32 diff) + { + + } +}; + +CreatureAI* GetAI_npc_toc5_announcer(Creature* pCreature) +{ + return new npc_toc5_announcerAI(pCreature); +} + +bool GossipHello_npc_toc5_announcer(Player* pPlayer, Creature* pCreature) +{ + ScriptedInstance* pInstance = pCreature->GetInstanceData(); + + if(!pInstance) + return false; + + if(pInstance->GetData(TYPE_GRAND_CHAMPIONS) == NOT_STARTED && pInstance->GetData(TYPE_ARGENT_CHALLENGE) == NOT_STARTED && pInstance->GetData(TYPE_BLACK_KNIGHT) == NOT_STARTED) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_START_EVENT1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + else + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_START_EVENT2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pCreature->GetEntry(), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_toc5_announcer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + CAST_AI(npc_toc5_announcerAI, pCreature->AI())->StartEvent(pPlayer); + } + + return true; +} + +void AddSC_trial_of_the_champion() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "npc_toc5_announcer"; + NewScript->GetAI = &GetAI_npc_toc5_announcer; + NewScript->pGossipHello = &GossipHello_npc_toc5_announcer; + NewScript->pGossipSelect = &GossipSelect_npc_toc5_announcer; + NewScript->RegisterSelf(); +} diff --git a/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h new file mode 100644 index 00000000000..5b76bd8e7d8 --- /dev/null +++ b/src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_TOC_H +#define DEF_TOC_H + +enum +{ + MAX_ENCOUNTER = 3, + + TYPE_GRAND_CHAMPIONS = 0, + TYPE_ARGENT_CHALLENGE = 1, + TYPE_BLACK_KNIGHT = 2, + + DATA_BLACK_KNIGHT = 6, + DATA_BLACK_KNIGHT_MINION = 7, + DATA_TOC5_ANNOUNCER = 8, + DATA_JAEREN = 9, + DATA_ARELAS = 10, + DATA_CHAMPIONID_1 = 11, + DATA_CHAMPIONID_2 = 12, + DATA_CHAMPIONID_3 = 13, + DATA_MEMORY = 14, + DATA_ARGENT_CHALLENGER = 15, + + NPC_JACOB = 34705, + NPC_AMBROSE = 34702, + NPC_COLOSOS = 34701, + NPC_JAELYNE = 34657, + NPC_LANA = 34703, + NPC_MOKRA = 35572, + NPC_ERESSEA = 35569, + NPC_RUNOK = 35571, + NPC_ZULTORE = 35570, + NPC_VISCERI = 35617, + NPC_EADRIC = 35119, + NPC_PALETRESS = 34928, + NPC_BLACK_KNIGHT = 35451, + NPC_RISEN_JAEREN = 35545, + NPC_RISEN_ARELAS = 35564, + NPC_JAEREN = 35004, + NPC_ARELAS = 35005, + MEMORY_ALGALON = 35052, + MEMORY_ARCHIMONDE = 35041, + MEMORY_CHROMAGGUS = 35033, + MEMORY_CYANIGOSA = 35046, + MEMORY_DELRISSA = 35043, + MEMORY_ECK = 35047, + MEMORY_ENTROPIUS = 35044, + MEMORY_GRUUL = 35039, + MEMORY_HAKKAR = 35034, + MEMORY_HEIGAN = 35049, + MEMORY_HEROD = 35030, + MEMORY_HOGGER = 34942, + MEMORY_IGNIS = 35050, + MEMORY_ILLIDAN = 35042, + MEMORY_INGVAR = 35045, + MEMORY_KALITHRESH = 35037, + MEMORY_LUCIFRON = 35031, + MEMORY_MALCHEZAAR = 35038, + MEMORY_MUTANUS = 35029, + MEMORY_ONYXIA = 35048, + MEMORY_THUNDERAAN = 35032, + MEMORY_VANCLEEF = 35028, + MEMORY_VASHJ = 35040, + MEMORY_VEKNILASH = 35036, + MEMORY_VEZAX = 35051, + + GO_CHAMPIONS_LOOT = 195709, + GO_CHAMPIONS_LOOT_H = 195710, + GO_EADRIC_LOOT = 195374, + GO_EADRIC_LOOT_H = 195375, + GO_PALETRESS_LOOT = 195323, + GO_PALETRESS_LOOT_H = 195324 +}; + +#endif diff --git a/src/scripts/northrend/dalaran.cpp b/src/scripts/northrend/dalaran.cpp new file mode 100644 index 00000000000..7be06f33ed0 --- /dev/null +++ b/src/scripts/northrend/dalaran.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: Dalaran +SDAuthor: WarHead, MaXiMiUS +SD%Complete: 99% +SDComment: For what is 63990+63991? Same function but don't work correct... +SDCategory: Dalaran +Script Data End */ + +#include "ScriptedPch.h" + +/******************************************************* + * npc_mageguard_dalaran + *******************************************************/ + +enum Spells +{ + SPELL_TRESPASSER_A = 54028, + SPELL_TRESPASSER_H = 54029 +}; + +enum NPCs // All outdoor guards are within 35.0f of these NPCs +{ + NPC_APPLEBOUGH_A = 29547, + NPC_SWEETBERRY_H = 29715, +}; + +struct TRINITY_DLL_DECL npc_mageguard_dalaranAI : public Scripted_NoMovementAI +{ + npc_mageguard_dalaranAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pCreature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_NORMAL, true); + pCreature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + } + + void Reset(){} + + void Aggro(Unit* pWho){} + + void AttackStart(Unit* pWho){} + + void MoveInLineOfSight(Unit *pWho) + { + if (!pWho || !pWho->IsInWorld() || pWho->GetZoneId() != 4395) + return; + + if (!me->IsWithinDist(pWho, 65.0f, false)) + return; + + Player *pPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself(); + + if (!pPlayer || pPlayer->isGameMaster() || pPlayer->IsBeingTeleported()) + return; + + switch (m_creature->GetEntry()) + { + case 29254: + if (pPlayer->GetTeam() == HORDE) // Horde unit found in Alliance area + if (Creature *pOutdoorNPC = GetClosestCreatureWithEntry(me, NPC_APPLEBOUGH_A, 32.0f)) + { + if (me->isInBackInMap(pWho, 12.0f)) // In my line of sight, "outdoors", and behind me + DoCast(pWho, SPELL_TRESPASSER_A); // Teleport the Horde unit out + } + else // In my line of sight, and "indoors" + DoCast(pWho, SPELL_TRESPASSER_A); // Teleport the Horde unit out + break; + case 29255: + if (pPlayer->GetTeam() == ALLIANCE) // Alliance unit found in Horde area + if (Creature *pOutdoorNPC = GetClosestCreatureWithEntry(me, NPC_SWEETBERRY_H, 32.0f)) + { + if (me->isInBackInMap(pWho, 12.0f)) // In my line of sight, "outdoors", and behind me + DoCast(pWho, SPELL_TRESPASSER_H); // Teleport the Alliance unit out + } + else // In my line of sight, and "indoors" + DoCast(pWho, SPELL_TRESPASSER_H); // Teleport the Alliance unit out + break; + } + me->SetOrientation(me->GetHomePosition().GetOrientation()); + return; + } + + void UpdateAI(const uint32 diff){} +}; + +CreatureAI* GetAI_npc_mageguard_dalaran(Creature* pCreature) +{ + return new npc_mageguard_dalaranAI(pCreature); +} + +void AddSC_dalaran() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_mageguard_dalaran"; + newscript->GetAI = &GetAI_npc_mageguard_dalaran; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/dragonblight.cpp b/src/scripts/northrend/dragonblight.cpp new file mode 100644 index 00000000000..62d4c6e3763 --- /dev/null +++ b/src/scripts/northrend/dragonblight.cpp @@ -0,0 +1,71 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Dragonblight +SD%Complete: 100 +SDComment: +SDCategory: Dragonblight +EndScriptData */ + +/* ContentData +npc_alexstrasza_wr_gate +EndContentData */ + +#include "ScriptedPch.h" + +enum eEnums +{ + QUEST_RETURN_TO_AG_A = 12499, + QUEST_RETURN_TO_AG_H = 12500, + MOVIE_ID_GATES = 14 +}; + +#define GOSSIP_ITEM_WHAT_HAPPENED "Alexstrasza, can you show me what happened here?" + +bool GossipHello_npc_alexstrasza_wr_gate(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestRewardStatus(QUEST_RETURN_TO_AG_A) || pPlayer->GetQuestRewardStatus(QUEST_RETURN_TO_AG_H)) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WHAT_HAPPENED, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_alexstrasza_wr_gate(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->SendMovieStart(MOVIE_ID_GATES); + } + + return true; +} + +void AddSC_dragonblight() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_alexstrasza_wr_gate"; + newscript->pGossipHello = &GossipHello_npc_alexstrasza_wr_gate; + newscript->pGossipSelect = &GossipSelect_npc_alexstrasza_wr_gate; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/draktharon_keep/boss_dred.cpp b/src/scripts/northrend/draktharon_keep/boss_dred.cpp new file mode 100644 index 00000000000..c85c850f77a --- /dev/null +++ b/src/scripts/northrend/draktharon_keep/boss_dred.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: Boss dred +SDAuthor: Manuel +SD%Complete: 100 % +SDComment: MAYBE need more improve the "Raptor Call". +SDCategory: +Script Data End */ + +#include "ScriptedPch.h" +#include "drak_tharon_keep.h" + +enum eSpells +{ + SPELL_BELLOWING_ROAR = 22686, // fears the group, can be resisted/dispelled + SPELL_GRIEVOUS_BITE = 48920, + SPELL_MANGLING_SLASH = 48873, //casted on the current tank, adds debuf + SPELL_FEARSOME_ROAR = 48849, + H_SPELL_FEARSOME_ROAR = 59422, //Not stacking, debuff + SPELL_PIERCING_SLASH = 48878, //debuff -->Armor reduced by 75% + SPELL_RAPTOR_CALL = 59416, //dummy + SPELL_GUT_RIP = 49710, + SPELL_REND = 13738 +}; + +enum eArchivements +{ + ACHIEV_BETTER_OFF_DRED = 2039 +}; + +enum Creatures +{ + NPC_RAPTOR_1 = 26641, + NPC_RAPTOR_2 = 26628 +}; + +struct TRINITY_DLL_DECL boss_dredAI : public ScriptedAI +{ + boss_dredAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 BellowingRoarTimer; + uint32 GrievousBiteTimer; + uint32 ManglingSlashTimer; + uint32 FearsomeRoarTimer; + uint32 PiercingSlashTimer; + uint32 RaptorCallTimer; + + ScriptedInstance* pInstance; + + void Reset() + { + if (pInstance) + { + pInstance->SetData(DATA_DRED_EVENT,NOT_STARTED); + pInstance->SetData(DATA_KING_DRED_ACHIEV, 0); + } + + BellowingRoarTimer = 33000; + GrievousBiteTimer = 20000; + ManglingSlashTimer = 18500; + FearsomeRoarTimer = urand(10000,20000); + PiercingSlashTimer = 17000; + RaptorCallTimer = urand(20000,25000); + } + + void EnterCombat(Unit* who) + { + if (pInstance) + pInstance->SetData(DATA_DRED_EVENT,IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (BellowingRoarTimer < diff) + { + DoCastAOE(SPELL_BELLOWING_ROAR, false); + BellowingRoarTimer = 40000; + } else BellowingRoarTimer -=diff; + + if (GrievousBiteTimer < diff) + { + DoCastVictim(SPELL_GRIEVOUS_BITE ,false); + GrievousBiteTimer = 20000; + } else GrievousBiteTimer -=diff; + + if (ManglingSlashTimer < diff) + { + DoCastVictim(SPELL_MANGLING_SLASH,false); + ManglingSlashTimer = 20000; + } else ManglingSlashTimer -=diff; + + if (FearsomeRoarTimer < diff) + { + DoCastAOE(DUNGEON_MODE(SPELL_FEARSOME_ROAR, H_SPELL_FEARSOME_ROAR),false); + FearsomeRoarTimer = urand(16,18)*1000; + } else FearsomeRoarTimer -=diff; + + if (PiercingSlashTimer < diff) + { + DoCastVictim(SPELL_PIERCING_SLASH,false); + PiercingSlashTimer = 20000; + } else PiercingSlashTimer -=diff; + + if (RaptorCallTimer < diff) + { + DoCastVictim(SPELL_RAPTOR_CALL,false); + + float x,y,z; + + m_creature->GetClosePoint(x,y,z,m_creature->GetObjectSize()/3,10.0f); + m_creature->SummonCreature(RAND(NPC_RAPTOR_1,NPC_RAPTOR_2),x,y,z,0,TEMPSUMMON_DEAD_DESPAWN,1000); + + RaptorCallTimer = urand(20000,25000); + } else RaptorCallTimer -=diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + pInstance->SetData(DATA_DRED_EVENT,DONE); + + if (IsHeroic() && pInstance->GetData(DATA_KING_DRED_ACHIEV) == 6) + pInstance->DoCompleteAchievement(ACHIEV_BETTER_OFF_DRED); + } + } +}; + +CreatureAI* GetAI_boss_dred(Creature* pCreature) +{ + return new boss_dredAI (pCreature); +} + +struct TRINITY_DLL_DECL npc_drakkari_gutripperAI : public ScriptedAI +{ + npc_drakkari_gutripperAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 GutRipTimer; + + void Reset() + { + GutRipTimer = urand(10000,15000); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (GutRipTimer < diff) + { + DoCastVictim(SPELL_GUT_RIP,false); + GutRipTimer = urand(10000,15000); + }else GutRipTimer -=diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + if (IsHeroic() && pInstance->GetData(DATA_DRED_EVENT) == IN_PROGRESS && pInstance->GetData(DATA_KING_DRED_ACHIEV) < 6) + { + pInstance->SetData(DATA_KING_DRED_ACHIEV, pInstance->GetData(DATA_KING_DRED_ACHIEV) + 1); + } + } + } +}; + +CreatureAI* GetAI_npc_drakkari_gutripper(Creature* pCreature) +{ + return new npc_drakkari_gutripperAI (pCreature); +} + +struct TRINITY_DLL_DECL npc_drakkari_scytheclawAI : public ScriptedAI +{ + npc_drakkari_scytheclawAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 RendTimer; + + void Reset() + { + RendTimer = urand(10000,15000); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (RendTimer < diff) + { + DoCastVictim(SPELL_REND,false); + RendTimer = urand(10000,15000); + }else RendTimer -=diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + if (IsHeroic() && pInstance->GetData(DATA_DRED_EVENT) == IN_PROGRESS && pInstance->GetData(DATA_KING_DRED_ACHIEV) < 6) + { + pInstance->SetData(DATA_KING_DRED_ACHIEV, pInstance->GetData(DATA_KING_DRED_ACHIEV) + 1); + } + } + } +}; + +CreatureAI* GetAI_npc_drakkari_scytheclaw(Creature* pCreature) +{ + return new npc_drakkari_scytheclawAI (pCreature); +} + +void AddSC_boss_dred() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_drakkari_gutripper"; + newscript->GetAI = &GetAI_npc_drakkari_gutripper; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_drakkari_scytheclaw"; + newscript->GetAI = &GetAI_npc_drakkari_scytheclaw; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_dred"; + newscript->GetAI = &GetAI_boss_dred; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/draktharon_keep/boss_novos.cpp b/src/scripts/northrend/draktharon_keep/boss_novos.cpp new file mode 100644 index 00000000000..bb1fae5c9ea --- /dev/null +++ b/src/scripts/northrend/draktharon_keep/boss_novos.cpp @@ -0,0 +1,291 @@ +/* +* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Script Data Start +SDName: Boss novos +SDAuthor: Tartalo +SD%Complete: 100 +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_novos' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "drak_tharon_keep.h" + +enum Spells +{ + SPELL_ARCANE_BLAST = 49198, + H_SPELL_ARCANE_BLAST = 59909, + SPELL_ARCANE_FIELD = 47346, + SPELL_BLIZZARD = 49034, + H_SPELL_BLIZZARD = 59854, + SPELL_FROSTBOLT = 49037, + H_SPELL_FROSTBOLT = 59855, + SPELL_WRATH_OF_MISERY = 50089, + H_SPELL_WRATH_OF_MISERY = 59856, + SPELL_SUMMON_MINIONS = 59910 //Summons an army of Fetid Troll Corpses to assist the caster. +}; +//not in db +enum Yells +{ + SAY_AGGRO = -1600000, + SAY_KILL = -1600001, + SAY_DEATH = -1600002, + SAY_NECRO_ADD = -1600003, + SAY_REUBBLE_1 = -1600004, + SAY_REUBBLE_2 = -1600005 +}; +enum Creatures +{ + CREATURE_RISEN_SHADOWCASTER = 27600, + CREATURE_FETID_TROLL_CORPSE = 27598, + CREATURE_HULKING_CORPSE = 27597, + CREATURE_CRYSTAL_HANDLER = 26627 +}; +enum CombatPhase +{ + IDLE, + PHASE_1, + PHASE_2 +}; +enum Achievements +{ + ACHIEV_OH_NOVOS = 2057 +}; + +struct Location +{ + float x,y,z; +}; + +static Location AddSpawnPoint = { -379.20, -816.76, 59.70}; +static Location CrystalHandlerSpawnPoint = { -326.626343, -709.956604, 27.813314 }; +static Location AddDestinyPoint = { -379.314545, -772.577637, 28.58837 }; + +struct TRINITY_DLL_DECL boss_novosAI : public Scripted_NoMovementAI +{ + boss_novosAI(Creature *c) : Scripted_NoMovementAI(c), lSummons(me) + { + pInstance = c->GetInstanceData(); + Reset(); + } + + uint32 uiTimer; + uint32 uiCrystalHandlerTimer; + + bool bAchiev; + + SummonList lSummons; + + std::list<uint64> luiCrystals; + + CombatPhase Phase; + + ScriptedInstance* pInstance; + + void Reset() + { + Phase = IDLE; + luiCrystals.clear(); + bAchiev = true; + m_creature->CastStop(); + lSummons.DespawnAll(); + if (pInstance) + { + pInstance->SetData(DATA_NOVOS_EVENT, NOT_STARTED); + luiCrystals.push_back(pInstance->GetData64(DATA_NOVOS_CRYSTAL_1)); + luiCrystals.push_back(pInstance->GetData64(DATA_NOVOS_CRYSTAL_2)); + luiCrystals.push_back(pInstance->GetData64(DATA_NOVOS_CRYSTAL_3)); + luiCrystals.push_back(pInstance->GetData64(DATA_NOVOS_CRYSTAL_4)); + for (std::list<uint64>::iterator itr = luiCrystals.begin(); itr != luiCrystals.end(); ++itr) + { + if (GameObject* pTemp = pInstance->instance->GetGameObject(*itr)) + pTemp->SetGoState(GO_STATE_READY); + } + } + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + Phase = PHASE_1; + uiCrystalHandlerTimer = 30000; + uiTimer = 1000; + DoCast(m_creature, SPELL_ARCANE_FIELD); + if (pInstance) + { + for (std::list<uint64>::iterator itr = luiCrystals.begin(); itr != luiCrystals.end(); ++itr) + { + if (GameObject *pTemp = pInstance->instance->GetGameObject(*itr)) + pTemp->SetGoState(GO_STATE_ACTIVE); + } + pInstance->SetData(DATA_NOVOS_EVENT, IN_PROGRESS); + } + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void UpdateAI(const uint32 diff) + { + switch (Phase) + { + case PHASE_1: + if (uiTimer <= diff) + { + Creature *pSummon = m_creature->SummonCreature(RAND(CREATURE_FETID_TROLL_CORPSE,CREATURE_HULKING_CORPSE,CREATURE_RISEN_SHADOWCASTER), AddSpawnPoint.x, AddSpawnPoint.y , AddSpawnPoint.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN,20000); + pSummon->GetMotionMaster()->MovePoint(0, AddDestinyPoint.x, AddDestinyPoint.y, AddDestinyPoint.z); + //If spell is casted stops casting arcane field so no spell casting + //DoCast(m_creature, SPELL_SUMMON_MINIONS); + uiTimer = 3000; + } else uiTimer -= diff; + if (uiCrystalHandlerTimer <= diff) + { + //TODO: say + Creature *pCrystalHandler = m_creature->SummonCreature(CREATURE_CRYSTAL_HANDLER, CrystalHandlerSpawnPoint.x, CrystalHandlerSpawnPoint.y , CrystalHandlerSpawnPoint.z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN,20000); + pCrystalHandler->GetMotionMaster()->MovePoint(0, AddDestinyPoint.x, AddDestinyPoint.y, AddDestinyPoint.z); + uiCrystalHandlerTimer = urand(20000,30000); + } else uiCrystalHandlerTimer -= diff; + break; + case PHASE_2: + if (uiTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(RAND(SPELL_ARCANE_BLAST,SPELL_BLIZZARD,SPELL_FROSTBOLT,SPELL_WRATH_OF_MISERY), + RAND(H_SPELL_ARCANE_BLAST,H_SPELL_BLIZZARD,H_SPELL_FROSTBOLT,H_SPELL_WRATH_OF_MISERY))); + uiTimer = urand(1000,3000); + } else uiTimer -= diff; + break; + } + } + void JustDied(Unit* killer) + { + if (pInstance) + { + pInstance->SetData(DATA_NOVOS_EVENT, DONE); + + if (IsHeroic() && bAchiev) + pInstance->DoCompleteAchievement(ACHIEV_OH_NOVOS); + } + lSummons.DespawnAll(); + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(SAY_KILL, m_creature); + } + + void JustSummoned(Creature *summon) + { + lSummons.Summon(summon); + } + + void RemoveCrystal() + { + if (!luiCrystals.empty()) + { + if (pInstance) + if (GameObject *pTemp = pInstance->instance->GetGameObject(luiCrystals.back())) + pTemp->SetGoState(GO_STATE_READY); + luiCrystals.pop_back(); + } + if (luiCrystals.empty()) + { + m_creature->CastStop(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Phase = PHASE_2; + uiTimer = 1000; + } + } +}; + +struct TRINITY_DLL_DECL mob_crystal_handlerAI : public ScriptedAI +{ + mob_crystal_handlerAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance *pInstance; + + void JustDied(Unit* killer) + { + if (Creature* pNovos = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_NOVOS) : 0)) + CAST_AI(boss_novosAI,pNovos->AI())->RemoveCrystal(); + } +}; + +struct TRINITY_DLL_DECL mob_novos_minionAI : public ScriptedAI +{ + mob_novos_minionAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance *pInstance; + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE) + return; + if (Creature* pNovos = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_NOVOS) : 0)) + CAST_AI(boss_novosAI, pNovos->AI())->bAchiev = false; + } +}; + +CreatureAI* GetAI_boss_novos(Creature* pCreature) +{ + return new boss_novosAI (pCreature); +} + +CreatureAI* GetAI_mob_crystal_handler(Creature* pCreature) +{ + return new mob_crystal_handlerAI (pCreature); +} + +CreatureAI* GetAI_mob_novos_minion(Creature* pCreature) +{ + return new mob_novos_minionAI (pCreature); +} + +void AddSC_boss_novos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_novos"; + newscript->GetAI = &GetAI_boss_novos; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_crystal_handler"; + newscript->GetAI = &GetAI_mob_crystal_handler; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_novos_minion"; + newscript->GetAI = &GetAI_mob_novos_minion; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/draktharon_keep/boss_tharon_ja.cpp b/src/scripts/northrend/draktharon_keep/boss_tharon_ja.cpp new file mode 100644 index 00000000000..87c0f717323 --- /dev/null +++ b/src/scripts/northrend/draktharon_keep/boss_tharon_ja.cpp @@ -0,0 +1,268 @@ +/* +* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Script Data Start +SDName: Boss Tharon'ja +SDAuthor: Tartalo +SD%Complete: 100 +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_tharon_ja' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "drak_tharon_keep.h" + +enum Spells +{ + //skeletal spells (phase 1) + SPELL_CURSE_OF_LIFE = 49527, + H_SPELL_CURSE_OF_LIFE = 59972, + SPELL_RAIN_OF_FIRE = 49518, + H_SPELL_RAIN_OF_FIRE = 59971, + SPELL_SHADOW_VOLLEY = 49528, + H_SPELL_SHADOW_VOLLEY = 59973, + SPELL_DECAY_FLESH = 49356, //casted at end of phase 1, starts phase 2 + //flesh spells (phase 2) + SPELL_GIFT_OF_THARON_JA = 52509, + SPELL_EYE_BEAM = 49544, + H_SPELL_EYE_BEAM = 59965, + SPELL_LIGHTNING_BREATH = 49537, + H_SPELL_LIGHTNING_BREATH = 59963, + SPELL_POISON_CLOUD = 49548, + H_SPELL_POISON_CLOUD = 59969, + SPELL_RETURN_FLESH = 53463 //Channeled spell ending phase two and returning to phase 1. This ability will stun the party for 6 seconds. +}; +/* not needed +enum PlayerSkills +{ + //Players' skills during Phase2 + SPELL_PLAYER_PHASE2_SLAYING_STRIKE = 50799, + SPELL_PLAYER_PHASE2_TAUNT = 49613, + SPELL_PLAYER_PHASE2_BONE_ARMOR = 49609, + SPELL_PLAYER_PHASE2_TOUCH_OF_LIFE = 49617 +}; +*/ +//not in db +enum Yells +{ + SAY_AGGRO = -1600011, + SAY_KILL_1 = -1600012, + SAY_KILL_2 = -1600013, + SAY_FLESH_1 = -1600014, + SAY_FLESH_2 = -1600015, + SAY_SKELETON_1 = -1600016, + SAY_SKELETON_2 = -1600017, + SAY_DEATH = -1600018 +}; +enum Models +{ + MODEL_FLESH = 27073, + MODEL_SKELETON = 27511 +}; +enum CombatPhase +{ + SKELETAL, + GOING_FLESH, + FLESH, + GOING_SKELETAL +}; + +struct TRINITY_DLL_DECL boss_tharon_jaAI : public ScriptedAI +{ + boss_tharon_jaAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiPhaseTimer; + uint32 uiCurseOfLifeTimer; + uint32 uiRainOfFireTimer; + uint32 uiShadowVolleyTimer; + uint32 uiEyeBeamTimer; + uint32 uiLightningBreathTimer; + uint32 uiPoisonCloudTimer; + + CombatPhase Phase; + + ScriptedInstance* pInstance; + + void Reset() + { + uiPhaseTimer = 20000; + uiCurseOfLifeTimer = 1000; + uiRainOfFireTimer = urand(14000,18000); + uiShadowVolleyTimer = urand(8000,10000); + Phase = SKELETAL; + m_creature->SetDisplayId(m_creature->GetNativeDisplayId()); + if (pInstance) + pInstance->SetData(DATA_THARON_JA_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_THARON_JA_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + switch (Phase) + { + case SKELETAL: + if (uiCurseOfLifeTimer < diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_CURSE_OF_LIFE, H_SPELL_CURSE_OF_LIFE)); + uiCurseOfLifeTimer = urand(10000,15000); + } else uiCurseOfLifeTimer -= diff; + + if (uiShadowVolleyTimer < diff) + { + DoCastVictim(DUNGEON_MODE(SPELL_SHADOW_VOLLEY,H_SPELL_SHADOW_VOLLEY)); + uiShadowVolleyTimer = urand(8000,10000); + } else uiShadowVolleyTimer -= diff; + + if (uiRainOfFireTimer < diff) + { + DoCastAOE(DUNGEON_MODE(SPELL_RAIN_OF_FIRE,H_SPELL_RAIN_OF_FIRE)); + uiRainOfFireTimer = urand(14000,18000); + } else uiRainOfFireTimer -= diff; + + if (uiPhaseTimer < diff) + { + DoCast(SPELL_DECAY_FLESH); + Phase = GOING_FLESH; + uiPhaseTimer = 6000; + } else uiPhaseTimer -= diff; + + DoMeleeAttackIfReady(); + break; + case GOING_FLESH: + if (uiPhaseTimer < diff) + { + DoScriptText(RAND(SAY_FLESH_1,SAY_FLESH_2),m_creature); + m_creature->SetDisplayId(MODEL_FLESH); + std::list<HostilReference*>& threatlist = m_creature->getThreatManager().getThreatList(); + for (std::list<HostilReference*>::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + { + Unit *pTemp = Unit::GetUnit((*m_creature),(*itr)->getUnitGuid()); + if (pTemp && pTemp->GetTypeId() == TYPEID_PLAYER) + { + m_creature->AddAura(SPELL_GIFT_OF_THARON_JA,pTemp); + pTemp->SetDisplayId(MODEL_SKELETON); + } + } + uiPhaseTimer = 20000; + uiLightningBreathTimer = urand(3000,4000); + uiEyeBeamTimer = urand(4000,8000); + uiPoisonCloudTimer = urand(6000,7000); + Phase = FLESH; + } else uiPhaseTimer -= diff; + break; + case FLESH: + if (uiLightningBreathTimer < diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_LIGHTNING_BREATH, H_SPELL_LIGHTNING_BREATH)); + uiLightningBreathTimer = urand(6000,7000); + } else uiLightningBreathTimer -= diff; + + if (uiEyeBeamTimer < diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_EYE_BEAM, H_SPELL_EYE_BEAM)); + uiEyeBeamTimer = urand(4000,6000); + } else uiEyeBeamTimer -= diff; + + if (uiPoisonCloudTimer < diff) + { + DoCastAOE(DUNGEON_MODE(SPELL_POISON_CLOUD, H_SPELL_POISON_CLOUD)); + uiPoisonCloudTimer = urand(10000,12000); + } else uiPoisonCloudTimer -= diff; + + if (uiPhaseTimer < diff) + { + DoCast(SPELL_RETURN_FLESH); + Phase = GOING_SKELETAL; + uiPhaseTimer = 6000; + } else uiPhaseTimer -= diff; + DoMeleeAttackIfReady(); + break; + case GOING_SKELETAL: + if (uiPhaseTimer < diff) + { + DoScriptText(RAND(SAY_SKELETON_1,SAY_SKELETON_2), m_creature); + m_creature->DeMorph(); + Phase = SKELETAL; + uiPhaseTimer = 20000; + uiCurseOfLifeTimer = 1000; + uiRainOfFireTimer = urand(14000,18000); + uiShadowVolleyTimer = urand(8000,10000); + std::list<HostilReference*>& threatlist = m_creature->getThreatManager().getThreatList(); + for (std::list<HostilReference*>::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + { + Unit *pTemp = Unit::GetUnit((*m_creature),(*itr)->getUnitGuid()); + if (pTemp && pTemp->GetTypeId() == TYPEID_PLAYER) + { + if (pTemp->HasAura(SPELL_GIFT_OF_THARON_JA)) + pTemp->RemoveAura(SPELL_GIFT_OF_THARON_JA); + pTemp->DeMorph(); + } + } + } else uiPhaseTimer -= diff; + break; + } + } + + void KilledUnit(Unit *victim) + { + DoScriptText(RAND(SAY_KILL_1,SAY_KILL_2),m_creature); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH,m_creature); + + if (pInstance) + pInstance->SetData(DATA_THARON_JA_EVENT, DONE); + } +}; + +CreatureAI* GetAI_boss_tharon_ja(Creature* pCreature) +{ + return new boss_tharon_jaAI (pCreature); +} + +void AddSC_boss_tharon_ja() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_tharon_ja"; + newscript->GetAI = &GetAI_boss_tharon_ja; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/draktharon_keep/boss_trollgore.cpp b/src/scripts/northrend/draktharon_keep/boss_trollgore.cpp new file mode 100644 index 00000000000..2fbe3fc9c65 --- /dev/null +++ b/src/scripts/northrend/draktharon_keep/boss_trollgore.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: Boss trollgore +SDAuthor: Tartalo +SD%Complete: +SDComment: TODO: spawn troll waves +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_trollgore' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "drak_tharon_keep.h" + +enum Spells +{ + SPELL_INFECTED_WOUND = 49637, + SPELL_CRUSH = 49639, + SPELL_CORPSE_EXPLODE = 49555, + SPELL_CONSUME = 49380, + //Heroic spells + H_SPELL_CORPSE_EXPLODE = 59807, + H_SPELL_CONSUME = 59803 +}; +//not in db +enum Yells +{ + SAY_AGGRO = -1600006, + SAY_KILL = -1600007, + SAY_CONSUME = -1600008, + SAY_EXPLODE = -1600009, + SAY_DEATH = -1600010 +}; +enum Achievements +{ + ACHIEV_CONSUMPTION_JUNCTION = 2151 +}; +enum Creatures +{ + NPC_DRAKKARI_INVADER_1 = 27753, + NPC_DRAKKARI_INVADER_2 = 27709 +}; + +Position AddSpawnPoint = { -260.493011, -622.968018, 26.605301, 3.036870 }; + +struct TRINITY_DLL_DECL boss_trollgoreAI : public ScriptedAI +{ + boss_trollgoreAI(Creature *c) : ScriptedAI(c), lSummons(me) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiConsumeTimer; + uint32 uiAuraCountTimer; + uint32 uiCrushTimer; + uint32 uiInfectedWoundTimer; + uint32 uiExplodeCorpseTimer; + uint32 uiSpawnTimer; + + bool bAchiev; + + SummonList lSummons; + + ScriptedInstance* pInstance; + + void Reset() + { + uiConsumeTimer = 15000; + uiAuraCountTimer = 15500; + uiCrushTimer = urand(1000,5000); + uiInfectedWoundTimer = urand(6000,10000); + uiExplodeCorpseTimer = 3000; + uiSpawnTimer = urand(30000,40000); + + bAchiev = IsHeroic(); + + lSummons.DespawnAll(); + + if (m_creature->HasAura(DUNGEON_MODE(SPELL_CONSUME,H_SPELL_CONSUME))) + m_creature->RemoveAura(DUNGEON_MODE(SPELL_CONSUME,H_SPELL_CONSUME)); + + if (pInstance) + pInstance->SetData(DATA_TROLLGORE_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_TROLLGORE_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiSpawnTimer <= diff) + { + uint32 spawnNumber = urand(2,DUNGEON_MODE(3,5)); + for (uint8 i = 0; i < spawnNumber; ++i) + DoSpawnCreature(RAND(NPC_DRAKKARI_INVADER_1,NPC_DRAKKARI_INVADER_2), AddSpawnPoint.GetPositionX(), AddSpawnPoint.GetPositionY(), AddSpawnPoint.GetPositionZ(), AddSpawnPoint.GetOrientation(), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); + uiSpawnTimer = urand(30000,40000); + } else uiSpawnTimer -= diff; + + if (uiConsumeTimer <= diff) + { + DoScriptText(SAY_CONSUME, m_creature); + DoCast(DUNGEON_MODE(SPELL_CONSUME, H_SPELL_CONSUME)); + uiConsumeTimer = 15000; + } else uiConsumeTimer -= diff; + + if (bAchiev) + { + if (uiAuraCountTimer <= diff) + { + if (Aura *pConsumeAura = m_creature->GetAura(DUNGEON_MODE(SPELL_CONSUME,H_SPELL_CONSUME))) + { + if (pConsumeAura && pConsumeAura->GetStackAmount() > 9) + bAchiev = false; + } + uiAuraCountTimer = 16000; + } else uiAuraCountTimer -= diff; + } + + if (uiCrushTimer <= diff) + { + DoCastVictim(SPELL_CRUSH); + uiCrushTimer = urand(10000,15000); + } else uiCrushTimer -= diff; + + if (uiInfectedWoundTimer <= diff) + { + DoCastVictim(SPELL_INFECTED_WOUND); + uiInfectedWoundTimer = urand(25000,35000); + } else uiInfectedWoundTimer -= diff; + + if (uiExplodeCorpseTimer <= diff) + { + DoCast(DUNGEON_MODE(SPELL_CORPSE_EXPLODE, H_SPELL_CORPSE_EXPLODE)); + DoScriptText(SAY_EXPLODE, m_creature); + uiExplodeCorpseTimer = urand(15000,19000); + } else uiExplodeCorpseTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + lSummons.DespawnAll(); + + if (pInstance) + { + if (bAchiev) + pInstance->DoCompleteAchievement(ACHIEV_CONSUMPTION_JUNCTION); + pInstance->SetData(DATA_TROLLGORE_EVENT, DONE); + } + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(SAY_KILL, m_creature); + } + + void JustSummoned(Creature* summon) + { + summon->AI()->AttackStart(m_creature); + } +}; + +CreatureAI* GetAI_boss_trollgore(Creature* pCreature) +{ + return new boss_trollgoreAI (pCreature); +} + +void AddSC_boss_trollgore() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_trollgore"; + newscript->GetAI = &GetAI_boss_trollgore; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/draktharon_keep/drak_tharon_keep.h b/src/scripts/northrend/draktharon_keep/drak_tharon_keep.h new file mode 100644 index 00000000000..bfa447e58c7 --- /dev/null +++ b/src/scripts/northrend/draktharon_keep/drak_tharon_keep.h @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DEF_DRAK_THARON_H +#define DEF_DRAK_THARON_H +enum Data +{ + DATA_TROLLGORE_EVENT, + DATA_NOVOS_EVENT, + DATA_DRED_EVENT, + DATA_THARON_JA_EVENT, + DATA_KING_DRED_ACHIEV +}; +enum Data64 +{ + DATA_TROLLGORE, + DATA_NOVOS, + DATA_DRED, + DATA_THARON_JA, + DATA_NOVOS_CRYSTAL_1, + DATA_NOVOS_CRYSTAL_2, + DATA_NOVOS_CRYSTAL_3, + DATA_NOVOS_CRYSTAL_4 +}; +#endif diff --git a/src/scripts/northrend/draktharon_keep/instance_drak_tharon_keep.cpp b/src/scripts/northrend/draktharon_keep/instance_drak_tharon_keep.cpp new file mode 100644 index 00000000000..25c5ab448a9 --- /dev/null +++ b/src/scripts/northrend/draktharon_keep/instance_drak_tharon_keep.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "drak_tharon_keep.h" + +#define MAX_ENCOUNTER 4 + +/* Drak'Tharon Keep encounters: +0 - Trollgore +1 - Novos +2 - King Dred +3 - Tharon Ja +*/ + +enum Creatures +{ + NPC_TROLLGORE = 26630, + NPC_NOVOS = 26631, + NPC_KING_DRED = 27483, + NPC_THARON_JA = 26632 +}; +enum GameObjects +{ + GO_NOVOS_CRYSTAL_1 = 189299, + GO_NOVOS_CRYSTAL_2 = 189300, + GO_NOVOS_CRYSTAL_3 = 189301, + GO_NOVOS_CRYSTAL_4 = 189302 +}; + +struct TRINITY_DLL_DECL instance_drak_tharon : public ScriptedInstance +{ + instance_drak_tharon(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint8 uiDredAchievCounter; + + uint64 uiTrollgore; + uint64 uiNovos; + uint64 uiDred; + uint64 uiTharonJa; + + uint64 uiNovosCrystal1; + uint64 uiNovosCrystal2; + uint64 uiNovosCrystal3; + uint64 uiNovosCrystal4; + + uint8 m_auiEncounter[MAX_ENCOUNTER]; + + std::string str_data; + + void Initialize() + { + uiTrollgore = 0; + uiNovos = 0; + uiDred = 0; + uiTharonJa = 0; + uiNovosCrystal1 = 0; + uiNovosCrystal2 = 0; + uiNovosCrystal3 = 0; + uiNovosCrystal4 = 0; + uiDredAchievCounter = 0; + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) return true; + + return false; + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case GO_NOVOS_CRYSTAL_1: + uiNovosCrystal1 = pGo->GetGUID(); + break; + case GO_NOVOS_CRYSTAL_2: + uiNovosCrystal2 = pGo->GetGUID(); + break; + case GO_NOVOS_CRYSTAL_3: + uiNovosCrystal3 = pGo->GetGUID(); + break; + case GO_NOVOS_CRYSTAL_4: + uiNovosCrystal4 = pGo->GetGUID(); + break; + } + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case NPC_TROLLGORE: + uiTrollgore = pCreature->GetGUID(); + break; + case NPC_NOVOS: + uiNovos = pCreature->GetGUID(); + break; + case NPC_KING_DRED: + uiDred = pCreature->GetGUID(); + break; + case NPC_THARON_JA: + uiTharonJa = pCreature->GetGUID(); + break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_TROLLGORE: return uiTrollgore; + case DATA_NOVOS: return uiNovos; + case DATA_DRED: return uiDred; + case DATA_THARON_JA: return uiTharonJa; + case DATA_NOVOS_CRYSTAL_1: return uiNovosCrystal1; + case DATA_NOVOS_CRYSTAL_2: return uiNovosCrystal2; + case DATA_NOVOS_CRYSTAL_3: return uiNovosCrystal3; + case DATA_NOVOS_CRYSTAL_4: return uiNovosCrystal4; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_TROLLGORE_EVENT: + m_auiEncounter[0] = data; + break; + case DATA_NOVOS_EVENT: + m_auiEncounter[1] = data; + break; + case DATA_DRED_EVENT: + m_auiEncounter[2] = data; + break; + case DATA_THARON_JA_EVENT: + m_auiEncounter[3] = data; + break; + + case DATA_KING_DRED_ACHIEV: + uiDredAchievCounter = data; + break; + } + + if (data == DONE) + { + SaveToDB(); + } + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_TROLLGORE_EVENT: return m_auiEncounter[0]; + case DATA_NOVOS_EVENT: return m_auiEncounter[1]; + case DATA_DRED_EVENT: return m_auiEncounter[2]; + case DATA_THARON_JA_EVENT: return m_auiEncounter[3]; + case DATA_KING_DRED_ACHIEV: return uiDredAchievCounter; + } + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::string str_data; + + std::ostringstream saveStream; + saveStream << "D K " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3; + + if (dataHead1 == 'D' && dataHead2 == 'K') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + m_auiEncounter[3] = data3; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_drak_tharon(Map* pMap) +{ + return new instance_drak_tharon(pMap); +} + +void AddSC_instance_drak_tharon() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_drak_tharon"; + newscript->GetInstanceData = &GetInstanceData_instance_drak_tharon; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/grizzly_hills.cpp b/src/scripts/northrend/grizzly_hills.cpp new file mode 100644 index 00000000000..ca1301fe287 --- /dev/null +++ b/src/scripts/northrend/grizzly_hills.cpp @@ -0,0 +1,127 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Grizzly_Hills +SD%Complete: 80 +SDComment: Quest support: 12231, 12247 +SDCategory: Grizzly Hills +EndScriptData */ + +/* ContentData +npc_orsonn_and_kodian +EndContentData */ + +#include "ScriptedPch.h" + +#define GOSSIP_ITEM1 "You're free to go Orsonn, but first tell me what's wrong with the furbolg." +#define GOSSIP_ITEM2 "What happened then?" +#define GOSSIP_ITEM3 "Thank you, Son of Ursoc. I'll see what can be done." +#define GOSSIP_ITEM4 "Who was this stranger?" +#define GOSSIP_ITEM5 "Thank you, Kodian. I'll do what I can." + +enum eEnums +{ + GOSSIP_TEXTID_ORSONN1 = 12793, + GOSSIP_TEXTID_ORSONN2 = 12794, + GOSSIP_TEXTID_ORSONN3 = 12796, + + GOSSIP_TEXTID_KODIAN1 = 12797, + GOSSIP_TEXTID_KODIAN2 = 12798, + + NPC_ORSONN = 27274, + NPC_KODIAN = 27275, + + //trigger creatures + NPC_ORSONN_CREDIT = 27322, + NPC_KODIAN_CREDIT = 27321, + + QUEST_CHILDREN_OF_URSOC = 12247, + QUEST_THE_BEAR_GODS_OFFSPRING = 12231 +}; + +bool GossipHello_npc_orsonn_and_kodian(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_CHILDREN_OF_URSOC) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_THE_BEAR_GODS_OFFSPRING) == QUEST_STATUS_INCOMPLETE) + { + switch(pCreature->GetEntry()) + { + case NPC_ORSONN: + if (!pPlayer->GetReqKillOrCastCurrentCount(QUEST_CHILDREN_OF_URSOC, NPC_ORSONN_CREDIT) || !pPlayer->GetReqKillOrCastCurrentCount(QUEST_THE_BEAR_GODS_OFFSPRING, NPC_ORSONN_CREDIT)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ORSONN1, pCreature->GetGUID()); + return true; + } + break; + case NPC_KODIAN: + if (!pPlayer->GetReqKillOrCastCurrentCount(QUEST_CHILDREN_OF_URSOC, NPC_KODIAN_CREDIT) || !pPlayer->GetReqKillOrCastCurrentCount(QUEST_THE_BEAR_GODS_OFFSPRING, NPC_KODIAN_CREDIT)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_KODIAN1, pCreature->GetGUID()); + return true; + } + break; + } + } + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_orsonn_and_kodian(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ORSONN2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ORSONN3, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->TalkedToCreature(NPC_ORSONN_CREDIT, pCreature->GetGUID()); + break; + + case GOSSIP_ACTION_INFO_DEF+4: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_KODIAN2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->TalkedToCreature(NPC_KODIAN_CREDIT, pCreature->GetGUID()); + break; + } + + return true; +} + +void AddSC_grizzly_hills() +{ + Script* newscript; + + newscript = new Script; + newscript->Name = "npc_orsonn_and_kodian"; + newscript->pGossipHello = &GossipHello_npc_orsonn_and_kodian; + newscript->pGossipSelect = &GossipSelect_npc_orsonn_and_kodian; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/gundrak/boss_drakkari_colossus.cpp b/src/scripts/northrend/gundrak/boss_drakkari_colossus.cpp new file mode 100644 index 00000000000..6f543148f5f --- /dev/null +++ b/src/scripts/northrend/gundrak/boss_drakkari_colossus.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: Boss Drakkari Colossus +SDAuthor: Manuel +SD%Complete: 95 % +SDComment: The event with the Living Mojos is not implemented, just is done that when one of the mojos around the boss take damage will make the boss enter in combat! +SDCategory: +Script Data End */ + +#include "ScriptedPch.h" +#include "gundrak.h" + +enum Spells +{ + SPELL_EMERGE = 54850, + + SPELL_MIGHTY_BLOW = 54719, + + SPELL_MERGE = 54878, + SPELL_SURGE = 54801, + + SPELL_FREEZE_ANIM = 16245, + + SPELL_MOJO_PUDDLE = 55627, + H_SPELL_MOJO_PUDDLE = 58994, + + SPELL_MOJO_WAVE = 55626, + H_SPELL_MOJO_WAVE = 58993 +}; + +struct TRINITY_DLL_DECL boss_drakkari_colossusAI : public ScriptedAI +{ + boss_drakkari_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + bool bHealth; + bool bHealth1; + + uint32 MightyBlowTimer; + + void Reset() + { + if (pInstance) + pInstance->SetData(DATA_DRAKKARI_COLOSSUS_EVENT, NOT_STARTED); + if(!m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->clearUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT); + m_creature->SetReactState(REACT_PASSIVE); + MightyBlowTimer = 10000; + bHealth = false; + bHealth1 = false; + } + + void EnterCombat(Unit* who) + { + if (pInstance) + pInstance->SetData(DATA_DRAKKARI_COLOSSUS_EVENT, IN_PROGRESS); + } + + void CreatureState(Creature* pWho, bool bRestore = false) + { + if (!pWho) + return; + + if (bRestore) + { + pWho->clearUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT); + pWho->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (pWho == m_creature) + m_creature->RemoveAura(SPELL_FREEZE_ANIM); + }else + { + pWho->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pWho->addUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT); + if (pWho == m_creature) + DoCast(m_creature,SPELL_FREEZE_ANIM); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (!bHealth && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() >= 6) + { + CreatureState(m_creature, false); + DoCast(m_creature,SPELL_FREEZE_ANIM); + DoCast(m_creature,SPELL_EMERGE); + bHealth = true; + } + + if (!bHealth1 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 5) + { + DoCast(m_creature,SPELL_EMERGE); + CreatureState(m_creature, false); + bHealth1 = true; + m_creature->RemoveAllAuras(); + } + + if (MightyBlowTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_MIGHTY_BLOW, true); + MightyBlowTimer = 10000; + } else MightyBlowTimer -= diff; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED)) + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (pInstance) + pInstance->SetData(DATA_DRAKKARI_COLOSSUS_EVENT, DONE); + } + + void JustSummoned(Creature* pSummon) + { + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 5) + pSummon->DealDamage(pSummon, pSummon->GetHealth() * 0.5 , NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + pSummon->AI()->AttackStart(m_creature->getVictim()); + } +}; + +struct TRINITY_DLL_DECL boss_drakkari_elementalAI : public ScriptedAI +{ + boss_drakkari_elementalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + if(pInstance) + { + if (pCreature->GetMap()->IsDungeon()) + pColossus = CAST_CRE(pCreature->GetUnit(*pCreature, pInstance->GetData64(DATA_DRAKKARI_COLOSSUS))); + } + } + + Creature* pColossus; + + ScriptedInstance* pInstance; + + uint32 uiSurgeTimer; + + bool bGoToColossus; + + void Reset() + { + if (pColossus) + CAST_AI(boss_drakkari_colossusAI, pColossus->AI())->CreatureState(m_creature, true); + uiSurgeTimer = 7000; + bGoToColossus = false; + } + + void EnterEvadeMode() + { + m_creature->RemoveFromWorld(); + } + + void MovementInform(uint32 uiType, uint32 uiId) + { + if (uiType != POINT_MOTION_TYPE) + return; + CAST_AI(boss_drakkari_colossusAI, pColossus->AI())->CreatureState(pColossus, true); + CAST_AI(boss_drakkari_colossusAI, pColossus->AI())->bHealth1 = false; + m_creature->RemoveFromWorld(); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if(!UpdateVictim()) + return; + + if(!bGoToColossus && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && pColossus->GetHealth()*100 / pColossus->GetMaxHealth() >= 6) + { + m_creature->InterruptNonMeleeSpells(true); + if (pColossus) + DoCast(pColossus, SPELL_MERGE); + bGoToColossus = true; + } + + if (uiSurgeTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_SURGE); + uiSurgeTimer = 7000; + } else uiSurgeTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (!pColossus) + return; + pColossus->Kill(pColossus); + } +}; + +struct TRINITY_DLL_DECL npc_living_mojoAI : public ScriptedAI +{ + npc_living_mojoAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + Creature* pColossus; + + ScriptedInstance* pInstance; + + uint32 uiMojoWaveTimer; + uint32 uiMojoPuddleTimer; + + void Reset() + { + uiMojoWaveTimer = 2000; + uiMojoPuddleTimer = 7000; + } + + void EnterCombat(Unit* who) + { + if (pInstance) + pColossus = m_creature->GetCreature(*m_creature, pInstance->GetData64(DATA_DRAKKARI_COLOSSUS)); + + //Check if the npc is near of Drakkari Colossus. + if (pColossus && pColossus->isAlive() && m_creature->IsInRange3d(pColossus->GetHomePosition().GetPositionX(),pColossus->GetHomePosition().GetPositionY(),pColossus->GetHomePosition().GetPositionZ(),0.0f,17.0f)) + m_creature->SetReactState(REACT_PASSIVE); + else + m_creature->SetReactState(REACT_AGGRESSIVE); + } + + void DamageTaken(Unit* pDone_by, uint32& uiDamage) + { + if (m_creature->HasReactState(REACT_PASSIVE)) + { + if (pColossus && pColossus->isAlive() && !pColossus->isInCombat()) + { + pColossus->RemoveAura(SPELL_FREEZE_ANIM); + pColossus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pColossus->SetReactState(REACT_AGGRESSIVE); + if (pDone_by && pDone_by->isAlive()) + pColossus->AI()->AttackStart(pDone_by); + EnterEvadeMode(); + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiMojoWaveTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_MOJO_WAVE, H_SPELL_MOJO_WAVE)); + uiMojoWaveTimer = 15000; + } else uiMojoWaveTimer -= diff; + + if (uiMojoPuddleTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_MOJO_PUDDLE, H_SPELL_MOJO_PUDDLE)); + uiMojoPuddleTimer = 18000; + } else uiMojoPuddleTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_drakkari_colossus(Creature* pCreature) +{ + return new boss_drakkari_colossusAI (pCreature); +} + +CreatureAI* GetAI_boss_drakkari_elemental(Creature* pCreature) +{ + return new boss_drakkari_elementalAI (pCreature); +} + +CreatureAI* GetAI_npc_living_mojo(Creature* pCreature) +{ + return new npc_living_mojoAI (pCreature); +} + +void AddSC_boss_drakkari_colossus() +{ + Script* newscript; + + newscript = new Script; + newscript->Name = "boss_drakkari_colossus"; + newscript->GetAI = &GetAI_boss_drakkari_colossus; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_drakkari_elemental"; + newscript->GetAI = &GetAI_boss_drakkari_elemental; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_living_mojo"; + newscript->GetAI = &GetAI_npc_living_mojo; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/gundrak/boss_eck.cpp b/src/scripts/northrend/gundrak/boss_eck.cpp new file mode 100644 index 00000000000..b11c0351cd3 --- /dev/null +++ b/src/scripts/northrend/gundrak/boss_eck.cpp @@ -0,0 +1,128 @@ +/* Script Data Start +SDName: Boss Eck the Ferocious +SDAuthor: LordVanMartin +SD%Complete: +SDComment: Only appears in Heroic mode +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "gundrak.h" + +enum Spells +{ + SPELL_ECK_BERSERK = 55816, //Eck goes berserk, increasing his attack speed by 150% and all damage he deals by 500%. + SPELL_ECK_BITE = 55813, //Eck bites down hard, inflicting 150% of his normal damage to an enemy. + SPELL_ECK_SPIT = 55814, //Eck spits toxic bile at enemies in a cone in front of him, inflicting 2970 Nature damage and draining 220 mana every 1 sec for 3 sec. + SPELL_ECK_SPRING_1 = 55815, //Eck leaps at a distant target. --> Drops aggro and charges a random player. Tank can simply taunt him back. + SPELL_ECK_SPRING_2 = 55837 //Eck leaps at a distant target. +}; +struct TRINITY_DLL_DECL boss_eckAI : public ScriptedAI +{ + boss_eckAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiBerserkTimer; + uint32 uiBiteTimer; + uint32 uiSpitTimer; + uint32 uiSpringTimer; + + bool bBerserk; + + ScriptedInstance* pInstance; + + void Reset() + { + uiBerserkTimer = 60000 + rand()%30000; //60-90 secs according to wowwiki + uiBiteTimer = 5000; + uiSpitTimer = 10000; + uiSpringTimer = 8000; + + bBerserk = false; + + if (pInstance) + pInstance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + if (pInstance) + pInstance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiBiteTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_ECK_BITE); + uiBiteTimer = 8000 + rand()%4000; + } else uiBiteTimer -= diff; + + if (uiSpitTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_ECK_SPIT); + uiSpitTimer = 6000 + rand()%8000; + } else uiSpitTimer -= diff; + + if (uiSpringTimer <= diff) + { + Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM,1); + if(pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) + { + DoCast(pTarget, RAND(SPELL_ECK_SPRING_1, SPELL_ECK_SPRING_2)); + uiSpringTimer = 5000 + rand()%10000; + } + } else uiSpringTimer -= diff; + + //Berserk on timer or 20% of health + if (!bBerserk) + { + if (uiBerserkTimer <= diff) + { + DoCast(m_creature, SPELL_ECK_BERSERK); + bBerserk = true; + } + else + { + uiBerserkTimer -= diff; + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 20) + { + DoCast(m_creature, SPELL_ECK_BERSERK); + bBerserk = true; + } + } + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (pInstance) + pInstance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, DONE); + } +}; + +CreatureAI* GetAI_boss_eck(Creature* pCreature) +{ + return new boss_eckAI (pCreature); +} + +void AddSC_boss_eck() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_eck"; + newscript->GetAI = &GetAI_boss_eck; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/gundrak/boss_gal_darah.cpp b/src/scripts/northrend/gundrak/boss_gal_darah.cpp new file mode 100644 index 00000000000..7dc6172bffa --- /dev/null +++ b/src/scripts/northrend/gundrak/boss_gal_darah.cpp @@ -0,0 +1,200 @@ +/* Script Data Start +SDName: Boss gal_darah +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "gundrak.h" + +//Spells +enum Spells +{ + SPELL_ENRAGE = 55285, + H_SPELL_ENRAGE = 59828, + SPELL_IMPALING_CHARGE = 54956, + H_SPELL_IMPALING_CHARGE = 59827, + SPELL_STOMP = 55292, + H_SPELL_STOMP = 59826, + SPELL_PUNCTURE = 55276, + H_SPELL_PUNCTURE = 59826, + SPELL_STAMPEDE = 55218, + SPELL_WHIRLING_SLASH = 55249, + H_SPELL_WHIRLING_SLASH = 55825 +}; + +//Yells +enum Yells +{ + SAY_AGGRO = -1604000, + SAY_SLAY_1 = -1604001, + SAY_SLAY_2 = -1604002, + SAY_SLAY_3 = -1604003, + SAY_DEATH = -1604004, + SAY_SUMMON_RHINO_1 = -1604005, + SAY_SUMMON_RHINO_2 = -1604006, + SAY_SUMMON_RHINO_3 = -1604007, + SAY_TRANSFORM_1 = -1604008, //Phase change + SAY_TRANSFORM_2 = -1604009 +}; + +enum CombatPhase +{ + TROLL, + RHINO +}; + +struct TRINITY_DLL_DECL boss_gal_darahAI : public ScriptedAI +{ + boss_gal_darahAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiStampedeTimer; + uint32 uiWhirlingSlashTimer; + uint32 uiPunctureTimer; + uint32 uiEnrageTimer; + uint32 uiImpalingChargeTimer; + uint32 uiStompTimer; + + CombatPhase Phase; + + uint8 uiPhaseCounter; + + ScriptedInstance* pInstance; + + void Reset() + { + uiStampedeTimer = 10000; + uiWhirlingSlashTimer = 20000; + uiPunctureTimer = 10000; + uiEnrageTimer = 15000; + uiImpalingChargeTimer = 20000; + uiStompTimer = 25000; + + Phase = TROLL; + + if (pInstance) + pInstance->SetData(DATA_GAL_DARAH_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_GAL_DARAH_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + switch (Phase) + { + case TROLL: + if (uiPhaseCounter == 2) + { + //FIX: implement transformation + Phase = RHINO; + uiPhaseCounter = 0; + DoScriptText(SAY_TRANSFORM_1,m_creature); + } + else + { + if (uiStampedeTimer <= diff) + { + DoCast(m_creature, SPELL_STAMPEDE); + DoScriptText(RAND(SAY_SUMMON_RHINO_1,SAY_SUMMON_RHINO_2,SAY_SUMMON_RHINO_3),m_creature); + uiStampedeTimer = 15000; + } else uiStampedeTimer -= diff; + + if (uiWhirlingSlashTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_WHIRLING_SLASH, H_SPELL_WHIRLING_SLASH)); + uiWhirlingSlashTimer = 20000; + ++uiPhaseCounter; + } else uiWhirlingSlashTimer -= diff; + } + break; + case RHINO: + if (uiPhaseCounter == 2) + { + //FIX: implement transformation + Phase = TROLL; + uiPhaseCounter = 0; + DoScriptText(SAY_TRANSFORM_2,m_creature); + } + else + { + if (uiPunctureTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_PUNCTURE, H_SPELL_PUNCTURE)); + uiPunctureTimer = 8000; + } else uiPunctureTimer -= diff; + + if (uiEnrageTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_ENRAGE, H_SPELL_ENRAGE)); + uiEnrageTimer = 20000; + } else uiEnrageTimer -= diff; + + if (uiStompTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_STOMP, H_SPELL_STOMP)); + uiStompTimer = 20000; + } else uiStompTimer -= diff; + + if (uiImpalingChargeTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_IMPALING_CHARGE, H_SPELL_IMPALING_CHARGE)); + uiImpalingChargeTimer = 30000; + ++uiPhaseCounter; + } else uiImpalingChargeTimer -= diff; + } + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_GAL_DARAH_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_gal_darah(Creature* pCreature) +{ + return new boss_gal_darahAI (pCreature); +} + +void AddSC_boss_gal_darah() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_gal_darah"; + newscript->GetAI = &GetAI_boss_gal_darah; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/gundrak/boss_moorabi.cpp b/src/scripts/northrend/gundrak/boss_moorabi.cpp new file mode 100644 index 00000000000..66efcea123b --- /dev/null +++ b/src/scripts/northrend/gundrak/boss_moorabi.cpp @@ -0,0 +1,177 @@ +/* Script Data Start +SDName: Boss moorabi +SDAuthor: Manuel +SD%Complete: 100% +SDComment: Maybe needs better timers. +SDCategory: Gundrak +Script Data End */ + +#include "ScriptedPch.h" +#include "gundrak.h" + +enum eSpells +{ + SPELL_DETERMINED_STAB = 55104, + SPELL_GROUND_TREMOR = 55142, + SPELL_NUMBING_SHOUT = 55106, + + SPELL_DETERMINED_GORE = 55102, + SPELL_DETERMINED_GORE_1 = 59444, + SPELL_QUAKE = 55101, + SPELL_NUMBING_ROAR = 55100, + + SPELL_MOJO_FRENZY = 55163, + SPELL_TRANSFORMATION = 55098, //Periodic, The caster transforms into a powerful mammoth, increasing Physical damage done by 25% and granting immunity to Stun effects. +}; + +enum eArchivements +{ + ACHIEVEMENT_LESS_RABI = 2040 +}; + +enum eSays +{ + SAY_AGGRO = -1604010, + //SAY_SLAY_1 = -1604011, // not in db + SAY_SLAY_2 = -1604012, + SAY_SLAY_3 = -1604013, + SAY_DEATH = -1604014, + SAY_TRANSFORM = -1604015, + SAY_QUAKE = -1604016, + EMOTE_TRANSFORM = -1604017 +}; + +struct TRINITY_DLL_DECL boss_moorabiAI : public ScriptedAI +{ + boss_moorabiAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + bool bPhase; + + uint32 uiNumblingShoutTimer; + uint32 uiGroundTremorTimer; + uint32 uiDeterminedStabTimer; + uint32 uiTransformationTImer; + + void Reset() + { + uiGroundTremorTimer = 18000; + uiNumblingShoutTimer = 10000; + uiDeterminedStabTimer = 20000; + uiTransformationTImer = 12000; + bPhase = false; + + if (pInstance) + pInstance->SetData(DATA_MOORABI_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + DoCast(m_creature, SPELL_MOJO_FRENZY, true); + + if (pInstance) + pInstance->SetData(DATA_MOORABI_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if(!bPhase && m_creature->HasAura(SPELL_TRANSFORMATION)) + { + bPhase = true; + m_creature->RemoveAura(SPELL_MOJO_FRENZY); + } + + if (uiGroundTremorTimer <= uiDiff) + { + DoScriptText(SAY_QUAKE, m_creature); + if (bPhase) + DoCast(m_creature->getVictim(), SPELL_QUAKE, true); + else + DoCast(m_creature->getVictim(), SPELL_GROUND_TREMOR, true); + uiGroundTremorTimer = 10000; + } else uiGroundTremorTimer -= uiDiff; + + if (uiNumblingShoutTimer <= uiDiff) + { + if (bPhase) + DoCast(m_creature->getVictim(), SPELL_NUMBING_ROAR, true); + else + DoCast(m_creature->getVictim(), SPELL_NUMBING_SHOUT, true); + uiNumblingShoutTimer = 10000; + } else uiNumblingShoutTimer -=uiDiff; + + if (uiDeterminedStabTimer <= uiDiff) + { + if (bPhase) + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_DETERMINED_GORE, SPELL_DETERMINED_GORE_1)); + else + DoCast(m_creature->getVictim(), SPELL_DETERMINED_STAB, true); + uiDeterminedStabTimer = 8000; + } else uiDeterminedStabTimer -=uiDiff; + + if (!bPhase && uiTransformationTImer <= uiDiff) + { + DoScriptText(EMOTE_TRANSFORM, m_creature); + DoScriptText(SAY_TRANSFORM, m_creature); + DoCast(m_creature, SPELL_TRANSFORMATION, false); + uiTransformationTImer = 10000; + } else uiTransformationTImer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + DoScriptText(SAY_DEATH, m_creature); + + if (IsHeroic() && !bPhase) + { + AchievementEntry const *AchievLessRabi = GetAchievementStore()->LookupEntry(ACHIEVEMENT_LESS_RABI); + if (AchievLessRabi) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievLessRabi); + } + } + } + + if (pInstance) + pInstance->SetData(DATA_MOORABI_EVENT, DONE); + } + + void KilledUnit(Unit* pVictim) + { + if (pVictim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_2,SAY_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_moorabi(Creature *pCreature) +{ + return new boss_moorabiAI(pCreature); +} + +void AddSC_boss_moorabi() +{ + Script* newscript; + + newscript = new Script; + newscript->Name = "boss_moorabi"; + newscript->GetAI = &GetAI_boss_moorabi; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/gundrak/boss_slad_ran.cpp b/src/scripts/northrend/gundrak/boss_slad_ran.cpp new file mode 100644 index 00000000000..663b3fb0805 --- /dev/null +++ b/src/scripts/northrend/gundrak/boss_slad_ran.cpp @@ -0,0 +1,260 @@ +/* Script Data Start +SDName: Boss slad_ran +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_slad_ran' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "gundrak.h" + +//Spells +enum Spells +{ + SPELL_POISON_NOVA = 55081, + H_SPELL_POISON_NOVA = 59842, + SPELL_POWERFULL_BITE = 48287, + H_SPELL_POWERFULL_BITE = 59840, + SPELL_VENOM_BOLT = 54970, + H_SPELL_VENOM_BOLT = 59839 +}; + +//Yell +enum Yells +{ + SAY_AGGRO = -1604017, + SAY_SLAY_1 = -1604018, + SAY_SLAY_2 = -1604019, + SAY_SLAY_3 = -1604020, + SAY_DEATH = -1604021, + SAY_SUMMON_SNAKES = -1604022, + SAY_SUMMON_CONSTRICTORS = -1604023 +}; + +//Creatures +enum Creatures +{ + CREATURE_SNAKE = 29680, + CREATURE_CONSTRICTORS = 29713 +}; + +//Creatures' spells +enum ConstrictorSpells +{ + SPELL_GRIP_OF_SLAD_RAN = 55093, + SPELL_VENOMOUS_BITE = 54987, + H_SPELL_VENOMOUS_BITE = 58996 +}; + +// Spawning locations +struct Locations +{ + float x, y, z, orientation; +}; + +static Locations SpawnLoc[]= +{ + {1783.81, 646.637, 133.948, 3.71755}, + {1775.03, 606.586, 134.165, 1.43117}, + {1717.39, 630.041, 129.282, 5.96903}, + {1765.66, 646.542, 134.02, 5.11381}, + {1716.76, 635.159, 129.282, 0.191986} +}; + +struct TRINITY_DLL_DECL boss_slad_ranAI : public ScriptedAI +{ + boss_slad_ranAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiPoisonNovaTimer; + uint32 uiPowerfullBiteTimer; + uint32 uiVenomBoltTimer; + uint32 uiSpawnTimer; + + uint8 uiPhase; + + ScriptedInstance* pInstance; + + void Reset() + { + uiPoisonNovaTimer = 10000; + uiPowerfullBiteTimer = 3000; + uiVenomBoltTimer = 15000; + uiSpawnTimer = 5000; + uiPhase = 0; + + if (pInstance) + pInstance->SetData(DATA_SLAD_RAN_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_SLAD_RAN_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiPoisonNovaTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_POISON_NOVA, H_SPELL_POISON_NOVA)); + uiPoisonNovaTimer = 15000; + } else uiPoisonNovaTimer -= diff; + + if (uiPowerfullBiteTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_POWERFULL_BITE, H_SPELL_POWERFULL_BITE)); + uiPowerfullBiteTimer = 10000; + } else uiPowerfullBiteTimer -= diff; + + if (uiVenomBoltTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_VENOM_BOLT, H_SPELL_VENOM_BOLT)); + uiVenomBoltTimer = 10000; + } else uiVenomBoltTimer -= diff; + + if (uiPhase) + { + if (uiSpawnTimer <= diff) + { + if (uiPhase == 1) + for (uint8 i = 0; i < DUNGEON_MODE(3, 5); ++i) + m_creature->SummonCreature(CREATURE_SNAKE, SpawnLoc[i].x, SpawnLoc[i].y, SpawnLoc[i].z, SpawnLoc[i].orientation, TEMPSUMMON_CORPSE_TIMED_DESPAWN,20000); + if (uiPhase == 2) + for (uint8 i = 0; i < DUNGEON_MODE(3, 5); ++i) + m_creature->SummonCreature(CREATURE_CONSTRICTORS, SpawnLoc[i].x, SpawnLoc[i].y, SpawnLoc[i].z, SpawnLoc[i].orientation, TEMPSUMMON_CORPSE_TIMED_DESPAWN,20000); + uiSpawnTimer = 5000; + } else uiSpawnTimer -= diff; + } + + if ((uiPhase == 0) && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) + { + DoScriptText(SAY_SUMMON_SNAKES,m_creature); + uiPhase = 1; + } + if ((uiPhase == 1) && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) + { + DoScriptText(SAY_SUMMON_CONSTRICTORS,m_creature); + uiPhase = 2; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_SLAD_RAN_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void JustSummoned(Creature* summoned) + { + summoned->GetMotionMaster()->MovePoint(0,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ()); + + } +}; + +struct TRINITY_DLL_DECL mob_slad_ran_constrictorAI : public ScriptedAI +{ + mob_slad_ran_constrictorAI(Creature *c) : ScriptedAI(c) {} + + uint32 uiGripOfSladRanTimer; + + void Reset() + { + uiGripOfSladRanTimer = 1000; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + if (uiGripOfSladRanTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_GRIP_OF_SLAD_RAN); + uiGripOfSladRanTimer = 5000; + } else uiGripOfSladRanTimer -= diff; + } + + ScriptedInstance* pInstance; +}; + +struct TRINITY_DLL_DECL mob_slad_ran_viperAI : public ScriptedAI +{ + mob_slad_ran_viperAI(Creature *c) : ScriptedAI(c) {} + + uint32 uiVenomousBiteTimer; + + ScriptedInstance* pInstance; + + void Reset() + { + uiVenomousBiteTimer = 2000; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (uiVenomousBiteTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_VENOMOUS_BITE, H_SPELL_VENOMOUS_BITE)); + uiVenomousBiteTimer = 10000; + } else uiVenomousBiteTimer -= diff; + } +}; + +CreatureAI* GetAI_boss_slad_ran(Creature* pCreature) +{ + return new boss_slad_ranAI (pCreature); +} + +CreatureAI* GetAI_mob_slad_ran_constrictor(Creature* pCreature) +{ + return new mob_slad_ran_constrictorAI (pCreature); +} + +CreatureAI* GetAI_mob_slad_ran_viper(Creature* pCreature) +{ + return new mob_slad_ran_viperAI (pCreature); +} + +void AddSC_boss_slad_ran() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_slad_ran"; + newscript->GetAI = &GetAI_boss_slad_ran; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_slad_ran_constrictor"; + newscript->GetAI = &GetAI_mob_slad_ran_constrictor; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_slad_ran_viper"; + newscript->GetAI = &GetAI_mob_slad_ran_viper; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/gundrak/gundrak.h b/src/scripts/northrend/gundrak/gundrak.h new file mode 100644 index 00000000000..d4c19f4ad35 --- /dev/null +++ b/src/scripts/northrend/gundrak/gundrak.h @@ -0,0 +1,24 @@ +#ifndef DEF_GUNDRAK_H +#define DEF_GUNDRAK_H + +enum Data +{ + DATA_SLAD_RAN_EVENT, + DATA_MOORABI_EVENT, + DATA_DRAKKARI_COLOSSUS_EVENT, + DATA_GAL_DARAH_EVENT, + DATA_ECK_THE_FEROCIOUS_EVENT +}; + +enum Data64 +{ + DATA_SLAD_RAN_ALTAR, + DATA_MOORABI_ALTAR, + DATA_DRAKKARI_COLOSSUS_ALTAR, + DATA_SLAD_RAN_STATUE, + DATA_MOORABI_STATUE, + DATA_DRAKKARI_COLOSSUS_STATUE, + DATA_DRAKKARI_COLOSSUS +}; + +#endif diff --git a/src/scripts/northrend/gundrak/instance_gundrak.cpp b/src/scripts/northrend/gundrak/instance_gundrak.cpp new file mode 100644 index 00000000000..dfd2ebcb5a7 --- /dev/null +++ b/src/scripts/northrend/gundrak/instance_gundrak.cpp @@ -0,0 +1,503 @@ +#include "ScriptedPch.h" +#include "gundrak.h" + +#define MAX_ENCOUNTER 5 + +/* GunDrak encounters: +0 - Slad'Ran +1 - Moorabi +2 - Drakkari Colossus +3 - Gal'Darah +4 - Eck the Ferocious +*/ + +struct TRINITY_DLL_DECL instance_gundrak : public ScriptedInstance +{ + instance_gundrak(Map* pMap) : ScriptedInstance(pMap) + { + bHeroicMode = pMap->IsHeroic(); + Initialize(); + }; + + bool bHeroicMode; + bool spawnSupport; + + uint32 timer; + uint32 phase; + uint64 toActivate; + + uint64 uiSladRan; + uint64 uiMoorabi; + uint64 uiDrakkariColossus; + uint64 uiGalDarah; + uint64 uiEckTheFerocious; + + uint64 uiSladRanAltar; + uint64 uiMoorabiAltar; + uint64 uiDrakkariColossusAltar; + uint64 uiSladRanStatue; + uint64 uiMoorabiStatue; + uint64 uiDrakkariColossusStatue; + uint64 uiGalDarahStatue; + uint64 uiEckTheFerociousDoor; + uint64 uiEckTheFerociousDoorBehind; + uint64 uiGalDarahDoor1; + uint64 uiGalDarahDoor2; + uint64 uiBridge; + uint64 uiCollision; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + GOState uiSladRanStatueState; + GOState uiMoorabiStatueState; + GOState uiDrakkariColossusStatueState; + GOState uiGalDarahStatueState; + GOState uiBridgeState; + GOState uiCollisionState; + + std::string str_data; + + void Initialize() + { + spawnSupport = false; + + timer = 0; + phase = 0; + toActivate = 0; + + uiSladRan = 0; + uiMoorabi = 0; + uiDrakkariColossus = 0; + uiGalDarah = 0; + uiEckTheFerocious = 0; + + uiSladRanAltar = 0; + uiMoorabiAltar = 0; + uiDrakkariColossusAltar = 0; + + uiSladRanStatue = 0; + uiMoorabiStatue = 0; + uiDrakkariColossusStatue = 0; + uiGalDarahStatue = 0; + + uiEckTheFerociousDoor = 0; + uiEckTheFerociousDoorBehind = 0; + uiGalDarahDoor1 = 0; + uiGalDarahDoor2 = 0; + + uiBridge = 0; + uiCollision = 0; + + uiSladRanStatueState = GO_STATE_ACTIVE; + uiMoorabiStatueState = GO_STATE_ACTIVE; + uiDrakkariColossusStatueState = GO_STATE_ACTIVE; + uiGalDarahStatueState = GO_STATE_READY; + uiBridgeState = GO_STATE_ACTIVE; + uiCollisionState = GO_STATE_READY; + + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case 29304: uiSladRan = pCreature->GetGUID(); break; + case 29305: uiMoorabi = pCreature->GetGUID(); break; + case 29306: uiGalDarah = pCreature->GetGUID(); break; + case 29307: uiDrakkariColossus = pCreature->GetGUID(); break; + case 29932: uiEckTheFerocious = pCreature->GetGUID(); break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case 192518: + uiSladRanAltar = pGo->GetGUID(); + // Make sure that they start out as unusuable + pGo->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + if (m_auiEncounter[0] == DONE) + { + if (uiSladRanStatueState == GO_STATE_ACTIVE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + else + { + ++phase; + pGo->SetGoState(GO_STATE_ACTIVE); + } + } + break; + case 192519: + uiMoorabiAltar = pGo->GetGUID(); + // Make sure that they start out as unusuable + pGo->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + if (m_auiEncounter[0] == DONE) + { + if (uiMoorabiStatueState == GO_STATE_ACTIVE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + else + { + ++phase; + pGo->SetGoState(GO_STATE_ACTIVE); + } + } + break; + case 192520: + uiDrakkariColossusAltar = pGo->GetGUID(); + // Make sure that they start out as unusuable + pGo->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + if (m_auiEncounter[0] == DONE) + { + if (uiDrakkariColossusStatueState == GO_STATE_ACTIVE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + else + { + ++phase; + pGo->SetGoState(GO_STATE_ACTIVE); + } + } + break; + case 192564: + uiSladRanStatue = pGo->GetGUID(); + pGo->SetGoState(uiSladRanStatueState); + break; + case 192565: + uiMoorabiStatue = pGo->GetGUID(); + pGo->SetGoState(uiMoorabiStatueState); + break; + case 192566: + uiGalDarahStatue = pGo->GetGUID(); + pGo->SetGoState(uiGalDarahStatueState); + break; + case 192567: + uiDrakkariColossusStatue = pGo->GetGUID(); + pGo->SetGoState(uiDrakkariColossusStatueState); + break; + case 192632: + uiEckTheFerociousDoor = pGo->GetGUID(); + if (bHeroicMode && m_auiEncounter[1] == DONE) + HandleGameObject(NULL,true,pGo); + break; + case 192569: + uiEckTheFerociousDoorBehind = pGo->GetGUID(); + if (bHeroicMode && m_auiEncounter[4] == DONE) + HandleGameObject(NULL,true,pGo); + case 193208: + uiGalDarahDoor1 = pGo->GetGUID(); + if (m_auiEncounter[3] == DONE) + HandleGameObject(NULL,true,pGo); + break; + case 193209: + uiGalDarahDoor2 = pGo->GetGUID(); + if (m_auiEncounter[3] == DONE) + HandleGameObject(NULL,true,pGo); + break; + case 193188: + uiBridge = pGo->GetGUID(); + pGo->SetGoState(uiBridgeState); + break; + case 192633: + uiCollision = pGo->GetGUID(); + pGo->SetGoState(uiCollisionState); + + // Can't spawn here with SpawnGameObject because pGo isn't added to world yet... + if (uiCollisionState == GO_STATE_ACTIVE_ALTERNATIVE) + spawnSupport = true; + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_SLAD_RAN_EVENT: + m_auiEncounter[0] = data; + if (data == DONE) + { + GameObject* pGo = instance->GetGameObject(uiSladRanAltar); + if (pGo) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + } + break; + case DATA_MOORABI_EVENT: + m_auiEncounter[1] = data; + if (data == DONE) + { + GameObject* pGo = instance->GetGameObject(uiMoorabiAltar); + if (pGo) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + if (bHeroicMode) + HandleGameObject(uiEckTheFerociousDoor,true); + } + break; + case DATA_DRAKKARI_COLOSSUS_EVENT: + m_auiEncounter[2] = data; + if (data == DONE) + { + GameObject* pGo = instance->GetGameObject(uiDrakkariColossusAltar); + if (pGo) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_UNK1); + } + break; + case DATA_GAL_DARAH_EVENT: + m_auiEncounter[3] = data; + if (data == DONE) + { + HandleGameObject(uiGalDarahDoor1,true); + HandleGameObject(uiGalDarahDoor2,true); + } + break; + case DATA_ECK_THE_FEROCIOUS_EVENT: + m_auiEncounter[4] = data; + if (bHeroicMode && data == DONE) + HandleGameObject(uiEckTheFerociousDoorBehind,true); + break; + } + + if (data == DONE) + SaveToDB(); + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_SLAD_RAN_EVENT: return m_auiEncounter[0]; + case DATA_MOORABI_EVENT: return m_auiEncounter[1]; + case DATA_GAL_DARAH_EVENT: return m_auiEncounter[2]; + case DATA_DRAKKARI_COLOSSUS_EVENT: return m_auiEncounter[3]; + case DATA_ECK_THE_FEROCIOUS_EVENT: return m_auiEncounter[4]; + } + + return 0; + } + + uint64 GetData64(uint32 type) + { + switch(type) + { + case DATA_SLAD_RAN_ALTAR: return uiSladRanAltar; + case DATA_MOORABI_ALTAR: return uiMoorabiAltar; + case DATA_DRAKKARI_COLOSSUS_ALTAR: return uiDrakkariColossusAltar; + case DATA_SLAD_RAN_STATUE: return uiSladRanStatue; + case DATA_MOORABI_STATUE: return uiMoorabiStatue; + case DATA_DRAKKARI_COLOSSUS_STATUE: return uiDrakkariColossusStatue; + case DATA_DRAKKARI_COLOSSUS: return uiDrakkariColossus; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "G D " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2] << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " + << (uiSladRanStatue ? GetObjState(uiSladRanStatue) : GO_STATE_ACTIVE) << " " << (uiMoorabiStatue ? GetObjState(uiMoorabiStatue) : GO_STATE_ACTIVE) << " " + << (uiDrakkariColossusStatue ? GetObjState(uiDrakkariColossusStatue) : GO_STATE_ACTIVE) << " " << (uiGalDarahStatue ? GetObjState(uiGalDarahStatue) : GO_STATE_READY) << " " + << (uiBridge ? GetObjState(uiBridge) : GO_STATE_ACTIVE) << " " << (uiCollision ? GetObjState(uiCollision) : GO_STATE_READY); + + + 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, data7, data8, data9, data10; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 + >> data4 >> data5 >> data6 >> data7 >> data8 >> data9 >> data10; + + if (dataHead1 == 'G' && dataHead2 == 'D') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + m_auiEncounter[3] = data3; + m_auiEncounter[4] = data4; + uiSladRanStatueState = GOState(data5); + uiMoorabiStatueState = GOState(data6); + uiDrakkariColossusStatueState = GOState(data7); + uiGalDarahStatueState = GOState(data8); + uiBridgeState = GOState(data9); + uiCollisionState = GOState(data10); + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } + + bool QueueActivation(uint64 guid, uint32 time) + { + if (timer) + return false; + + toActivate = guid; + timer = time; + phase++; + return true; + } + + void Update(uint32 diff) + { + // Spawn the support for the bridge if necessary + if (spawnSupport) + { + if (GameObject* pCollision = instance->GetGameObject(uiCollision)) + pCollision->SummonGameObject(192743, pCollision->GetPositionX(), pCollision->GetPositionY(), pCollision->GetPositionZ(), pCollision->GetOrientation(), 0, 0, 0, 0, 0); + spawnSupport = false; + } + + // If there is nothing to activate, then return + if (!toActivate) + return; + + if (timer < diff) + { + timer = 0; + if (toActivate == uiBridge) + { + toActivate = 0; + GameObject* pBridge = instance->GetGameObject(uiBridge); + GameObject* pCollision = instance->GetGameObject(uiCollision); + GameObject* pSladRanStatue = instance->GetGameObject(uiSladRanStatue); + GameObject* pMoorabiStatue = instance->GetGameObject(uiMoorabiStatue); + GameObject* pDrakkariColossusStatue = instance->GetGameObject(uiDrakkariColossusStatue); + GameObject* pGalDarahStatue = instance->GetGameObject(uiGalDarahStatue); + + if (pBridge && pCollision && pSladRanStatue && pMoorabiStatue && pDrakkariColossusStatue && pGalDarahStatue) + { + pBridge->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + pCollision->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + pSladRanStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + pMoorabiStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + pDrakkariColossusStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + pGalDarahStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + + // Add the GO that solidifies the bridge so you can walk on it + spawnSupport = true; + SaveToDB(); + } + } + else + { + uint32 spell = 0; + GameObject* pAltar = NULL; + if (toActivate == uiSladRanStatue) + { + spell = 57071; + pAltar = instance->GetGameObject(uiSladRanAltar); + } else if (toActivate == uiMoorabiStatue) + { + spell = 57068; + pAltar = instance->GetGameObject(uiMoorabiAltar); + } else if (toActivate == uiDrakkariColossusStatue) + { + spell = 57072; + pAltar = instance->GetGameObject(uiDrakkariColossusAltar); + } + + // This is a workaround to make the beam cast properly. The caster should be ID 30298 but since the spells + // all are with scripted target for that same ID, it will hit itself. + if (pAltar) + if (Creature* trigger = pAltar->SummonCreature(18721, pAltar->GetPositionX(), pAltar->GetPositionY(), pAltar->GetPositionZ() + 3, pAltar->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 5000)) + { + // Set the trigger model to invisible + trigger->SetDisplayId(11686); + trigger->CastSpell(trigger, spell, false); + } + + if (GameObject* statueGO = instance->GetGameObject(toActivate)) + statueGO->SetGoState(GO_STATE_READY); + + toActivate = 0; + + if (phase == 3) + QueueActivation(uiBridge, 3000); + else + SaveToDB(); // Don't save in between last statue and bridge turning in case of crash leading to stuck instance + } + } else timer -= diff; + } + + GOState GetObjState(uint64 guid) + { + if (GameObject* go = instance->GetGameObject(guid)) + return go->GetGoState(); + return GO_STATE_ACTIVE; + } +}; + +bool GOHello_altar(Player *pPlayer, GameObject *pGO) +{ + ScriptedInstance *pInstance = pGO->GetInstanceData(); + uint64 uiStatue; + + pGO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGO->SetGoState(GO_STATE_ACTIVE); + + if (pInstance) + { + switch(pGO->GetEntry()) + { + case 192518: uiStatue = pInstance->GetData64(DATA_SLAD_RAN_STATUE); break; + case 192519: uiStatue = pInstance->GetData64(DATA_MOORABI_STATUE); break; + case 192520: uiStatue = pInstance->GetData64(DATA_DRAKKARI_COLOSSUS_STATUE); break; + } + if (((instance_gundrak*)pInstance)->QueueActivation(uiStatue, 3500)) + { + pGO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGO->SetGoState(GO_STATE_ACTIVE); + } + return true; + } + return false; +} + +InstanceData* GetInstanceData_instance_gundrak(Map* pMap) +{ + return new instance_gundrak(pMap); +} + +void AddSC_instance_gundrak() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_gundrak"; + newscript->GetInstanceData = &GetInstanceData_instance_gundrak; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "go_gundrak_altar"; + newscript->pGOHello = &GOHello_altar; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/howling_fjord.cpp b/src/scripts/northrend/howling_fjord.cpp new file mode 100644 index 00000000000..2417f4144cb --- /dev/null +++ b/src/scripts/northrend/howling_fjord.cpp @@ -0,0 +1,338 @@ +/* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Sholazar_Basin +SD%Complete: 100 +SDComment: Quest support: 11253, 11241. +SDCategory: howling_fjord +EndScriptData */ + +/* ContentData +npc_plaguehound_tracker +npc_apothecary_hanes +EndContentData */ + +#include "ScriptedPch.h" +#include "ScriptedEscortAI.h" + +/*###### +## npc_apothecary_hanes +######*/ +enum Entries +{ + NPC_APOTHECARY_HANES = 23784, + FACTION_ESCORTEE_A = 774, + FACTION_ESCORTEE_H = 775, + NPC_HANES_FIRE_TRIGGER = 23968, + QUEST_TRAIL_OF_FIRE = 11241, + SPELL_COSMETIC_LOW_POLY_FIRE = 56274 +}; + +bool QuestAccept_npc_apothecary_hanes(Player* pPlayer, Creature* pCreature, Quest const* quest) +{ + if (quest->GetQuestId() == QUEST_TRAIL_OF_FIRE) + { + switch (pPlayer->GetTeam()) + { + case ALLIANCE: + pCreature->setFaction(FACTION_ESCORTEE_A); + break; + case HORDE: + pCreature->setFaction(FACTION_ESCORTEE_H); + break; + } + CAST_AI(npc_escortAI, (pCreature->AI()))->Start(true, false, pPlayer->GetGUID()); + } + return true; +} + +struct TRINITY_DLL_DECL npc_Apothecary_HanesAI : public npc_escortAI +{ + npc_Apothecary_HanesAI(Creature* pCreature) : npc_escortAI(pCreature){} + uint32 PotTimer; + + void Reset () + { + SetDespawnAtFar(false); + PotTimer = 10000; //10 sec cooldown on potion + } + + void JustDied(Unit* killer) + { + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->FailQuest(QUEST_TRAIL_OF_FIRE); + } + + void UpdateEscortAI(const uint32 diff) + { + if(HealthBelowPct(75)) + { + if (PotTimer <= diff) + { + DoCast(me, 17534, true); + PotTimer = 10000; + } else PotTimer -= diff; + } + if (GetAttack() && UpdateVictim()) + DoMeleeAttackIfReady(); + } + + void WaypointReached(uint32 i) + { + Player* pPlayer = GetPlayerForEscort(); + if (!pPlayer) + return; + switch(i) + { + case 1: + me->SetReactState(REACT_AGGRESSIVE); + SetRun(true); + break; + case 23: + if (pPlayer) + pPlayer->GroupEventHappens(QUEST_TRAIL_OF_FIRE, m_creature); + me->ForcedDespawn(); + break; + case 5: + if (Unit* Trigger = m_creature->FindNearestCreature(NPC_HANES_FIRE_TRIGGER,10.0f)) + Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false); + SetRun(false); + break; + case 6: + if (Unit* Trigger = m_creature->FindNearestCreature(NPC_HANES_FIRE_TRIGGER,10.0f)) + Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false); + SetRun(true); + break; + case 8: + if (Unit* Trigger = m_creature->FindNearestCreature(NPC_HANES_FIRE_TRIGGER,10.0f)) + Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false); + SetRun(false); + break; + case 9: + if (Unit* Trigger = m_creature->FindNearestCreature(NPC_HANES_FIRE_TRIGGER,10.0f)) + Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false); + break; + case 10: + SetRun(true); + break; + case 13: + SetRun(false); + break; + case 14: + if (Unit* Trigger = m_creature->FindNearestCreature(NPC_HANES_FIRE_TRIGGER,10.0f)) + Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false); + SetRun(true); + break; + } + } +}; +CreatureAI* GetAI_npc_apothecary_hanes(Creature* pCreature) +{ + return new npc_Apothecary_HanesAI(pCreature); +} +/*###### +## npc_plaguehound_tracker +######*/ + +enum ePlaguehound +{ + QUEST_SNIFF_OUT_ENEMY = 11253 +}; + +struct TRINITY_DLL_DECL npc_plaguehound_trackerAI : public npc_escortAI +{ + npc_plaguehound_trackerAI(Creature* pCreature) : npc_escortAI(pCreature) { } + + void Reset() + { + InitScriptData(); + } + + void InitScriptData() + { + Player* pPlayer = NULL; + if(me->isSummon()) + if(Unit* summoner = CAST_SUM(me)->GetSummoner()) + if(summoner->GetTypeId() == TYPEID_PLAYER) + pPlayer = CAST_PLR(summoner); + + if (!pPlayer) + return; + + me->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); + Start(false, false, pPlayer->GetGUID()); + } + + void WaypointReached(uint32 i) + { + Player* pPlayer = NULL; + if(me->isSummon()) + if(Unit* summoner = CAST_SUM(me)->GetSummoner()) + if(summoner->GetTypeId() == TYPEID_PLAYER) + pPlayer = CAST_PLR(summoner); + + if (!pPlayer) + return; + + switch(i) + { + case 26: + me->ForcedDespawn(); + break; + } + } +}; + +CreatureAI* GetAI_npc_plaguehound_tracker(Creature* pCreature) +{ + return new npc_plaguehound_trackerAI(pCreature); +} + +/*###### +## npc_razael_and_lyana +######*/ + +#define GOSSIP_RAZAEL_REPORT "High Executor Anselm wants a report on the situation." +#define GOSSIP_LYANA_REPORT "High Executor Anselm requests your report." + +enum eRazael +{ + QUEST_REPORTS_FROM_THE_FIELD = 11221, + NPC_RAZAEL = 23998, + NPC_LYANA = 23778, + GOSSIP_TEXTID_RAZAEL1 = 11562, + GOSSIP_TEXTID_RAZAEL2 = 11564, + GOSSIP_TEXTID_LYANA1 = 11586, + GOSSIP_TEXTID_LYANA2 = 11588 +}; + +bool GossipHello_npc_razael_and_lyana(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_REPORTS_FROM_THE_FIELD) == QUEST_STATUS_INCOMPLETE) + switch (pCreature->GetEntry()) + { + case NPC_RAZAEL: + if (!pPlayer->GetReqKillOrCastCurrentCount(QUEST_REPORTS_FROM_THE_FIELD, NPC_RAZAEL)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_RAZAEL_REPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RAZAEL1, pCreature->GetGUID()); + return true; + } + break; + case NPC_LYANA: + if (!pPlayer->GetReqKillOrCastCurrentCount(QUEST_REPORTS_FROM_THE_FIELD, NPC_LYANA)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LYANA_REPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LYANA1, pCreature->GetGUID()); + return true; + } + break; + } + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_razael_and_lyana(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF + 1: + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RAZAEL2, pCreature->GetGUID()); + pPlayer->TalkedToCreature(NPC_RAZAEL, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LYANA2, pCreature->GetGUID()); + pPlayer->TalkedToCreature(NPC_LYANA, pCreature->GetGUID()); + break; + } + return true; +} + +/*###### +## npc_mcgoyver +######*/ + +#define GOSSIP_ITEM_MG_I "Walt sent me to pick up some dark iron ingots." +#define GOSSIP_ITEM_MG_II "Yarp." + +enum eMcGoyver +{ + QUEST_WE_CAN_REBUILD_IT = 11483, + + SPELL_CREATURE_DARK_IRON_INGOTS = 44512, + SPELL_TAXI_EXPLORERS_LEAGUE = 44280, + + GOSSIP_TEXTID_MCGOYVER = 12193 +}; + +bool GossipHello_npc_mcgoyver(Player* pPlayer, Creature* pCreature) +{ + if(pPlayer->GetQuestStatus(QUEST_WE_CAN_REBUILD_IT) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MG_I, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_mcgoyver(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MG_II, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_MCGOYVER, pCreature->GetGUID()); + pPlayer->CastSpell(pPlayer, SPELL_CREATURE_DARK_IRON_INGOTS, true); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->CastSpell(pPlayer, SPELL_TAXI_EXPLORERS_LEAGUE, true); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + } + return true; +} + +void AddSC_howling_fjord() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_apothecary_hanes"; + newscript->GetAI = &GetAI_npc_apothecary_hanes; + newscript->pQuestAccept = &QuestAccept_npc_apothecary_hanes; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_plaguehound_tracker"; + newscript->GetAI = &GetAI_npc_plaguehound_tracker; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_razael_and_lyana"; + newscript->pGossipHello = &GossipHello_npc_razael_and_lyana; + newscript->pGossipSelect = &GossipSelect_npc_razael_and_lyana; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_mcgoyver"; + newscript->pGossipHello = &GossipHello_npc_mcgoyver; + newscript->pGossipSelect = &GossipSelect_npc_mcgoyver; + newscript->RegisterSelf(); + } diff --git a/src/scripts/northrend/icecrown.cpp b/src/scripts/northrend/icecrown.cpp new file mode 100644 index 00000000000..0867e19042c --- /dev/null +++ b/src/scripts/northrend/icecrown.cpp @@ -0,0 +1,135 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Icecrown +SD%Complete: 100 +SDComment: Quest support: 12807 +SDCategory: Icecrown +EndScriptData */ + +/* ContentData +npc_arete +EndContentData */ + +#include "ScriptedPch.h" + +/*###### +## npc_arete +######*/ + +#define GOSSIP_ARETE_ITEM1 "Lord-Commander, I would hear your tale." +#define GOSSIP_ARETE_ITEM2 "<You nod slightly but do not complete the motion as the Lord-Commander narrows his eyes before he continues.>" +#define GOSSIP_ARETE_ITEM3 "I thought that they now called themselves the Scarlet Onslaught?" +#define GOSSIP_ARETE_ITEM4 "Where did the grand admiral go?" +#define GOSSIP_ARETE_ITEM5 "That's fine. When do I start?" +#define GOSSIP_ARETE_ITEM6 "Let's finish this!" +#define GOSSIP_ARETE_ITEM7 "That's quite a tale, Lord-Commander." + +enum eArete +{ + GOSSIP_TEXTID_ARETE1 = 13525, + GOSSIP_TEXTID_ARETE2 = 13526, + GOSSIP_TEXTID_ARETE3 = 13527, + GOSSIP_TEXTID_ARETE4 = 13528, + GOSSIP_TEXTID_ARETE5 = 13529, + GOSSIP_TEXTID_ARETE6 = 13530, + GOSSIP_TEXTID_ARETE7 = 13531, + + QUEST_THE_STORY_THUS_FAR = 12807 +}; + +bool GossipHello_npc_arete(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_THE_STORY_THUS_FAR) == QUEST_STATUS_INCOMPLETE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE1, pCreature->GetGUID()); + return true; + } + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_arete(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE3, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE4, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE5, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE6, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE7, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->AreaExploredOrEventHappens(QUEST_THE_STORY_THUS_FAR); + break; + } + + return true; +} + +/*###### +## The Valiant's Challenge Quest 13699 +######*/ + +bool GossipHello_valiant_challenge(Player* player, Creature* _Creature) +{ + if (player->GetQuestStatus(13699) == QUEST_STATUS_INCOMPLETE) + { + player->SummonCreature(30675, player->GetInnPosX(),player->GetInnPosY(),player->GetInnPosZ(),0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000000); + } + return true; +} + +void AddSC_icecrown() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_arete"; + newscript->pGossipHello = &GossipHello_npc_arete; + newscript->pGossipSelect = &GossipSelect_npc_arete; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "valiant_challenge"; + newscript->pGossipHello = &GossipHello_valiant_challenge; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_anubrekhan.cpp b/src/scripts/northrend/naxxramas/boss_anubrekhan.cpp new file mode 100644 index 00000000000..b0612636f83 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_anubrekhan.cpp @@ -0,0 +1,126 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define SAY_GREET RAND(-1533000,-1533004,-1533005,-1533006,-1533007) +#define SAY_AGGRO RAND(-1533001,-1533002,-1533003) +#define SAY_SLAY -1533008 + +#define SPELL_IMPALE RAID_MODE(28783,56090) +#define SPELL_LOCUSTSWARM RAID_MODE(28785,54021) + +#define SPELL_SELF_SPAWN_5 29105 //This spawns 5 corpse scarabs ontop of us (most likely the player casts this on death) + +#define EVENT_IMPALE 1 +#define EVENT_LOCUST 2 + +#define MOB_CRYPT_GUARD 16573 + +struct TRINITY_DLL_DECL boss_anubrekhanAI : public BossAI +{ + boss_anubrekhanAI(Creature *c) : BossAI(c, BOSS_ANUBREKHAN) { Prepare(); } + + bool HasTaunted; + + void Prepare() + { + HasTaunted = false; + + if (IsHeroic()) + { + DoSpawnCreature(MOB_CRYPT_GUARD, 0, -10, 0, me->GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); + DoSpawnCreature(MOB_CRYPT_GUARD, 0, 10, 0, me->GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); + } + } + + void InitializeAI() { Prepare(); BossAI::InitializeAI(); } + void JustReachedHome() { Prepare(); _JustReachedHome(); } + + void KilledUnit(Unit* victim) + { + //Force the player to spawn corpse scarabs via spell + victim->CastSpell(victim, SPELL_SELF_SPAWN_5, true, NULL, NULL, me->GetGUID()); + + if (!(rand()%5)) + DoScriptText(SAY_SLAY, me); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + DoScriptText(SAY_AGGRO, me); + events.ScheduleEvent(EVENT_IMPALE, 15000, 1); + events.ScheduleEvent(EVENT_LOCUST, 80000 + rand()%40000, 1); + } + + void MoveInLineOfSight(Unit *who) + { + if (!HasTaunted && me->IsWithinDistInMap(who, 60.0f)) + { + DoScriptText(SAY_GREET, me); + HasTaunted = true; + } + ScriptedAI::MoveInLineOfSight(who); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_IMPALE: + //Cast Impale on a random target + //Do NOT cast it when we are afflicted by locust swarm + if (!me->HasAura(SPELL_LOCUSTSWARM)) + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_IMPALE); + events.ScheduleEvent(EVENT_IMPALE, 15000, 1); + events.DelayEvents(1500, 1); + return; + case EVENT_LOCUST: + DoCast(m_creature, SPELL_LOCUSTSWARM); + DoSpawnCreature(MOB_CRYPT_GUARD, 5, 5, 0, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); + events.ScheduleEvent(EVENT_LOCUST, 90000, 1); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_anubrekhan(Creature* pCreature) +{ + return new boss_anubrekhanAI (pCreature); +} + +void AddSC_boss_anubrekhan() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_anubrekhan"; + newscript->GetAI = &GetAI_boss_anubrekhan; + newscript->RegisterSelf(); +} + diff --git a/src/scripts/northrend/naxxramas/boss_faerlina.cpp b/src/scripts/northrend/naxxramas/boss_faerlina.cpp new file mode 100644 index 00000000000..251992c9dfb --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_faerlina.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +enum Yells +{ + SAY_GREET = -1533009, + SAY_AGGRO_1 = -1533010, + SAY_AGGRO_2 = -1533011, + SAY_AGGRO_3 = -1533012, + SAY_AGGRO_4 = -1533013, + SAY_SLAY_1 = -1533014, + SAY_SLAY_2 = -1533015, + SAY_DEATH = -1533016 +}; +//#define SOUND_RANDOM_AGGRO 8955 //soundId containing the 4 aggro sounds, we not using this + +enum Spells +{ + SPELL_POISON_BOLT_VOLLEY = 28796, + H_SPELL_POISON_BOLT_VOLLEY = 54098, + SPELL_RAIN_OF_FIRE = 28794, + H_SPELL_RAIN_OF_FIRE = 54099, + SPELL_FRENZY = 28798, + H_SPELL_FRENZY = 54100, + SPELL_WIDOWS_EMBRACE = 28732, + H_SPELL_WIDOWS_EMBRACE = 54097 +}; + +enum Events +{ + EVENT_NONE, + EVENT_POISON, + EVENT_FIRE, + EVENT_FRENZY, + EVENT_AFTERENRAGE +}; + +enum Creatures +{ + NPC_WORSHIPPER = 16506 +}; + +struct TRINITY_DLL_DECL boss_faerlinaAI : public BossAI +{ + boss_faerlinaAI(Creature *c) : BossAI(c, BOSS_FAERLINA), greet(false) {} + + bool greet; + bool delayFrenzy; + + void Reset() + { + delayFrenzy = false; + _Reset(); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + DoScriptText(RAND(SAY_AGGRO_1,SAY_AGGRO_2,SAY_AGGRO_3,SAY_AGGRO_4), me); + events.ScheduleEvent(EVENT_POISON, urand(12000,15000)); + events.ScheduleEvent(EVENT_FIRE, urand(6000,18000)); + events.ScheduleEvent(EVENT_FRENZY, urand(60000,80000),1); + } + + void MoveInLineOfSight(Unit *who) + { + if (!greet) + { + DoScriptText(SAY_GREET, me); + greet = true; + } + BossAI::MoveInLineOfSight(who); + } + + void KilledUnit(Unit* victim) + { + if (!(rand()%3)) + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), me); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_POISON: + if (!me->HasAura(SPELL_WIDOWS_EMBRACE)) + DoCastAOE(RAID_MODE(SPELL_POISON_BOLT_VOLLEY,H_SPELL_POISON_BOLT_VOLLEY)); + events.ScheduleEvent(EVENT_POISON, urand(12000,15000)); + return; + case EVENT_FIRE: + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, RAID_MODE(SPELL_RAIN_OF_FIRE, H_SPELL_RAIN_OF_FIRE)); + events.ScheduleEvent(EVENT_FIRE, urand(6000,18000)); + return; + case EVENT_FRENZY: + DoCast(me, RAID_MODE(SPELL_FRENZY, H_SPELL_FRENZY)); + delayFrenzy = false; + return; + case EVENT_AFTERENRAGE: + events.ScheduleEvent(EVENT_FRENZY, urand(60000,80000)); + } + } + + DoMeleeAttackIfReady(); + } + + void SpellHit(Unit* caster, const SpellEntry *spell) + { + if (spell->Id == SPELL_WIDOWS_EMBRACE || spell->Id == H_SPELL_WIDOWS_EMBRACE) + { + if (m_creature->HasAura(RAID_MODE(SPELL_FRENZY,H_SPELL_FRENZY))) + { + if (!delayFrenzy) + { + events.DelayEvents(30000, 1); + delayFrenzy = true; + } + } + else + events.ScheduleEvent(EVENT_AFTERENRAGE, 60000); + } + } +}; + +CreatureAI* GetAI_boss_faerlina(Creature* pCreature) +{ + return new boss_faerlinaAI (pCreature); +} + +struct TRINITY_DLL_DECL mob_faerlina_addAI : public ScriptedAI +{ + mob_faerlina_addAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance *pInstance; + + void Reset() + { + if (getDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, SPELL_EFFECT_BIND, true); + } + + void JustDied(Unit *killer) + { + if (pInstance) + { + if (Creature *pFaerlina = pInstance->instance->GetCreature(pInstance->GetData64(DATA_FAERLINA))) + DoCast(pFaerlina, RAID_MODE(SPELL_WIDOWS_EMBRACE, H_SPELL_WIDOWS_EMBRACE)); + } + } + +}; + +CreatureAI* GetAI_mob_faerlina_add(Creature* pCreature) +{ + return new mob_faerlina_addAI (pCreature); +} + +void AddSC_boss_faerlina() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_faerlina"; + newscript->GetAI = &GetAI_boss_faerlina; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_faerlina_add"; + newscript->GetAI = &GetAI_mob_faerlina_add; + newscript->RegisterSelf(); +} + + diff --git a/src/scripts/northrend/naxxramas/boss_four_horsemen.cpp b/src/scripts/northrend/naxxramas/boss_four_horsemen.cpp new file mode 100644 index 00000000000..b3e2a9fb9bb --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_four_horsemen.cpp @@ -0,0 +1,374 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +enum Horsemen +{ + HORSEMEN_THANE, + HORSEMEN_LADY, + HORSEMEN_BARON, + HORSEMEN_SIR, +}; + +enum Events +{ + EVENT_NONE, + EVENT_MARK, + EVENT_CAST, + EVENT_BERSERK, +}; + +const Position WaypointPositions[12] = +{ + // Thane waypoints + {2542.3, -2984.1, 241.49, 5.362}, + {2547.6, -2999.4, 241.34, 5.049}, + {2542.9, -3015.0, 241.35, 4.654}, + // Lady waypoints + {2498.3, -2961.8, 241.28, 3.267}, + {2487.7, -2959.2, 241.28, 2.890}, + {2469.4, -2947.6, 241.28, 2.576}, + // Baron waypoints + {2553.8, -2968.4, 241.33, 5.757}, + {2564.3, -2972.5, 241.33, 5.890}, + {2583.9, -2971.67, 241.35, 0.008}, + // Sir waypoints + {2534.5, -2921.7, 241.53, 1.363}, + {2523.5, -2902.8, 241.28, 2.095}, + {2517.8, -2896.6, 241.28, 2.315}, +}; + +const uint32 MOB_HORSEMEN[] = {16064, 16065, 30549, 16063}; +const uint32 SPELL_MARK[] = {28832, 28833, 28834, 28835}; +#define SPELL_PRIMARY(i) RAID_MODE(SPELL_PRIMARY_N[i],SPELL_PRIMARY_H[i]) +const uint32 SPELL_PRIMARY_N[] = {28884, 28863, 28882, 28883}; +const uint32 SPELL_PRIMARY_H[] = {57467, 57463, 57369, 57466}; +#define SPELL_SECONDARY(i) RAID_MODE(SPELL_SECONDARY_N[i],SPELL_SECONDARY_H[i]) +const uint32 SPELL_SECONDARY_N[]= {0, 57374, 0, 57376}; +const uint32 SPELL_SECONDARY_H[]= {0, 57464, 0, 57465}; +const uint32 SPELL_PUNISH[] = {0, 57381, 0, 57377}; +#define SPELL_BERSERK 26662 + +// used by 16063,16064,16065,30549, but signed for 16063 +const int32 SAY_AGGRO[] = {-1533051, -1533044, -1533065, -1533058}; +const int32 SAY_TAUNT[3][4] ={ {-1533052, -1533045, -1533071, -1533059}, + {-1533053, -1533046, -1533072, -1533060}, + {-1533054, -1533047, -1533073, -1533061},}; +const int32 SAY_SPECIAL[] = {-1533055, -1533048, -1533070, -1533062}; +const int32 SAY_SLAY[] = {-1533056, -1533049, -1533068, -1533063}; +const int32 SAY_DEATH[] = {-1533057, -1533050, -1533074, -1533064}; + +#define SAY_BARON_AGGRO RAND(-1533065,-1533066,-1533067) +#define SAY_BARON_SLAY RAND(-1533068,-1533069) + +struct TRINITY_DLL_DECL boss_four_horsemenAI : public BossAI +{ + boss_four_horsemenAI(Creature *c) : BossAI(c, BOSS_HORSEMEN) + { + id = Horsemen(0); + for (uint8 i = 0; i < 4; ++i) + if (me->GetEntry() == MOB_HORSEMEN[i]) + id = Horsemen(i); + caster = (id == HORSEMEN_LADY || id == HORSEMEN_SIR); + } + + Horsemen id; + Unit *eventStarter; + uint8 nextWP; + uint32 punishTimer; + bool caster; + bool nextMovementStarted; + bool movementCompleted; + bool movementStarted; + bool encounterActionAttack; + bool encounterActionReset; + bool doDelayPunish; + + void Reset() + { + if (!encounterActionReset) + DoEncounterAction(NULL, false, true, false); + + me->SetReactState(REACT_AGGRESSIVE); + eventStarter = NULL; + nextWP = 0; + punishTimer = 2000; + nextMovementStarted = false; + movementCompleted = false; + movementStarted = false; + encounterActionAttack = false; + encounterActionReset = false; + doDelayPunish = false; + _Reset(); + } + + bool DoEncounterAction(Unit *who, bool attack, bool reset, bool checkAllDead) + { + if (!instance) + return false; + + Creature *Thane = CAST_CRE(Unit::GetUnit(*me, instance->GetData64(DATA_THANE))); + Creature *Lady = CAST_CRE(Unit::GetUnit(*me, instance->GetData64(DATA_LADY))); + Creature *Baron = CAST_CRE(Unit::GetUnit(*me, instance->GetData64(DATA_BARON))); + Creature *Sir = CAST_CRE(Unit::GetUnit(*me, instance->GetData64(DATA_SIR))); + + if (Thane && Lady && Baron && Sir) + { + if (attack && who) + { + CAST_AI(boss_four_horsemenAI, Thane->AI())->encounterActionAttack = true; + CAST_AI(boss_four_horsemenAI, Lady->AI())->encounterActionAttack = true; + CAST_AI(boss_four_horsemenAI, Baron->AI())->encounterActionAttack = true; + CAST_AI(boss_four_horsemenAI, Sir->AI())->encounterActionAttack = true; + + CAST_AI(boss_four_horsemenAI, Thane->AI())->AttackStart(who); + CAST_AI(boss_four_horsemenAI, Lady->AI())->AttackStart(who); + CAST_AI(boss_four_horsemenAI, Baron->AI())->AttackStart(who); + CAST_AI(boss_four_horsemenAI, Sir->AI())->AttackStart(who); + } + + if (reset) + { + if (instance->GetBossState(BOSS_HORSEMEN) != NOT_STARTED) + { + if (!Thane->isAlive()) + Thane->Respawn(); + + if (!Lady->isAlive()) + Lady->Respawn(); + + if (!Baron->isAlive()) + Baron->Respawn(); + + if (!Sir->isAlive()) + Sir->Respawn(); + + CAST_AI(boss_four_horsemenAI, Thane->AI())->encounterActionReset = true; + CAST_AI(boss_four_horsemenAI, Lady->AI())->encounterActionReset = true; + CAST_AI(boss_four_horsemenAI, Baron->AI())->encounterActionReset = true; + CAST_AI(boss_four_horsemenAI, Sir->AI())->encounterActionReset = true; + + CAST_AI(boss_four_horsemenAI, Thane->AI())->EnterEvadeMode(); + CAST_AI(boss_four_horsemenAI, Lady->AI())->EnterEvadeMode(); + CAST_AI(boss_four_horsemenAI, Baron->AI())->EnterEvadeMode(); + CAST_AI(boss_four_horsemenAI, Sir->AI())->EnterEvadeMode(); + } + } + + if (checkAllDead) + return !Thane->isAlive() && !Lady->isAlive() && !Baron->isAlive() && !Sir->isAlive(); + } + return false; + } + + void BeginFourHorsemenMovement() + { + movementStarted = true; + me->SetReactState(REACT_PASSIVE); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true); + + switch(id) + { + case HORSEMEN_THANE: + me->GetMotionMaster()->MovePoint(0, WaypointPositions[0]); + break; + case HORSEMEN_LADY: + me->GetMotionMaster()->MovePoint(3, WaypointPositions[3]); + break; + case HORSEMEN_BARON: + me->GetMotionMaster()->MovePoint(6, WaypointPositions[6]); + break; + case HORSEMEN_SIR: + me->GetMotionMaster()->MovePoint(9, WaypointPositions[9]); + break; + } + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + + if (id == 2 || id == 5 || id == 8 || id == 11) + { + movementCompleted = true; + me->SetReactState(REACT_AGGRESSIVE); + + if (me->canAttack(eventStarter)) + AttackStart(eventStarter); + else if (!UpdateVictim()) + { + EnterEvadeMode(); + return; + } + + if (caster) + { + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + } + + return; + } + + nextMovementStarted = false; + nextWP = id + 1; + } + + void MoveInLineOfSight(Unit *who) + { + BossAI::MoveInLineOfSight(who); + if (caster) + SelectNearestTarget(who); + } + + void AttackStart(Unit *who) + { + if (!movementCompleted && !movementStarted) + { + eventStarter = who; + BeginFourHorsemenMovement(); + + if (!encounterActionAttack) + DoEncounterAction(who, true, false, false); + } + else if (movementCompleted && movementStarted) + { + if (caster) + me->Attack(who, false); + else + BossAI::AttackStart(who); + } + } + + void KilledUnit(Unit* victim) + { + if (!(rand()%5)) + { + if (id == HORSEMEN_BARON) + DoScriptText(SAY_BARON_SLAY, me); + else + DoScriptText(SAY_SLAY[id], me); + } + } + + void JustDied(Unit* killer) + { + events.Reset(); + summons.DespawnAll(); + if(instance && DoEncounterAction(NULL, false, false, true)) + { + instance->SetBossState(BOSS_HORSEMEN, DONE); + instance->SaveToDB(); + } + + DoScriptText(SAY_DEATH[id], me); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + + if (id == HORSEMEN_BARON) + DoScriptText(SAY_BARON_AGGRO, me); + else + DoScriptText(SAY_AGGRO[id], me); + + events.ScheduleEvent(EVENT_MARK, 15000); + events.ScheduleEvent(EVENT_CAST, 20000+rand()%5000); + events.ScheduleEvent(EVENT_BERSERK, 15*100*1000); + } + + void UpdateAI(const uint32 diff) + { + if (nextWP && movementStarted && !movementCompleted && !nextMovementStarted) + { + nextMovementStarted = true; + me->GetMotionMaster()->MovePoint(nextWP, WaypointPositions[nextWP]); + } + + if (!UpdateVictim() || !CheckInRoom() || !movementCompleted) + return; + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_MARK: + if (!(rand()%5)) + DoScriptText(SAY_SPECIAL[id], me); + DoCastAOE(SPELL_MARK[id]); + events.ScheduleEvent(EVENT_MARK, 15000); + break; + case EVENT_CAST: + if (!(rand()%5)) + DoScriptText(SAY_TAUNT[rand()%3][id], me); + + if (caster) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 45)) + DoCast(pTarget, SPELL_PRIMARY(id)); + } + else + DoCast(me->getVictim(), SPELL_PRIMARY(id)); + + events.ScheduleEvent(EVENT_CAST, 15000); + break; + case EVENT_BERSERK: + DoScriptText(SAY_SPECIAL[id], me); + DoCast(me, EVENT_BERSERK); + break; + } + } + + if (punishTimer <= diff) + { + if (doDelayPunish) + { + DoCastAOE(SPELL_PUNISH[id], true); + doDelayPunish = false; + } + punishTimer = 2000; + } else punishTimer -= diff; + + if (!caster) + DoMeleeAttackIfReady(); + else if ((!DoSpellAttackIfReady(SPELL_SECONDARY(id)) || !me->IsWithinLOSInMap(me->getVictim())) && movementCompleted && !doDelayPunish) + doDelayPunish = true; + } +}; + +CreatureAI* GetAI_four_horsemen(Creature* pCreature) +{ + return new boss_four_horsemenAI (pCreature); +} + +void AddSC_boss_four_horsemen() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_four_horsemen"; + newscript->GetAI = &GetAI_four_horsemen; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_gluth.cpp b/src/scripts/northrend/naxxramas/boss_gluth.cpp new file mode 100644 index 00000000000..51fe10ff001 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_gluth.cpp @@ -0,0 +1,167 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define SPELL_MORTAL_WOUND 25646 +#define SPELL_ENRAGE RAID_MODE(28371,54427) +#define SPELL_DECIMATE RAID_MODE(28374,54426) +#define SPELL_BERSERK 26662 +#define SPELL_INFECTED_WOUND 29306 + +#define MOB_ZOMBIE 16360 + +const Position PosSummon[3] = +{ + {3267.9, -3172.1, 297.42, 0.94}, + {3253.2, -3132.3, 297.42, 0}, + {3308.3, -3185.8, 297.42, 1.58}, +}; + +enum Events +{ + EVENT_NONE, + EVENT_WOUND, + EVENT_ENRAGE, + EVENT_DECIMATE, + EVENT_BERSERK, + EVENT_SUMMON, +}; + +#define EMOTE_NEARBY " spots a nearby zombie to devour!" + +struct TRINITY_DLL_DECL boss_gluthAI : public BossAI +{ + boss_gluthAI(Creature *c) : BossAI(c, BOSS_GLUTH) + { + // Do not let Gluth be affected by zombies' debuff + me->ApplySpellImmune(0, IMMUNITY_ID, SPELL_INFECTED_WOUND, true); + } + + std::vector<Creature*> triggers; + + void Reset() + { + triggers.clear(); + _Reset(); + } + + void MoveInLineOfSight(Unit *who) + { + if (who->GetEntry() == MOB_ZOMBIE && me->IsWithinDistInMap(who, 7)) + { + SetGazeOn(who); + // TODO: use a script text + me->MonsterTextEmote(EMOTE_NEARBY, 0, true); + } + else + BossAI::MoveInLineOfSight(who); + } + + void EnterCombat(Unit *who) + { + for (uint32 i = 0; i < 3; ++i) + if (Creature *trigger = DoSummon(WORLD_TRIGGER, PosSummon[i])) + triggers.push_back(trigger); + if (triggers.size() < 3) + { + error_log("Script Gluth: cannot summon triggers!"); + EnterEvadeMode(); + return; + } + + _EnterCombat(); + events.ScheduleEvent(EVENT_WOUND, 10000); + events.ScheduleEvent(EVENT_ENRAGE, 15000); + events.ScheduleEvent(EVENT_DECIMATE, 105000); + events.ScheduleEvent(EVENT_BERSERK, 8*60000); + events.ScheduleEvent(EVENT_SUMMON, 15000); + } + + void JustSummoned(Creature *summon) + { + if (summon->GetEntry() == WORLD_TRIGGER) + summon->setActive(true); + else if (summon->GetEntry() == MOB_ZOMBIE) + summon->AI()->AttackStart(me); + summons.Summon(summon); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictimWithGaze() || !CheckInRoom()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_WOUND: + DoCast(me->getVictim(), SPELL_MORTAL_WOUND); + events.ScheduleEvent(EVENT_WOUND, 10000); + break; + case EVENT_ENRAGE: + // TODO : Add missing text + DoCast(me, SPELL_ENRAGE); + events.ScheduleEvent(EVENT_ENRAGE, 15000); + break; + case EVENT_DECIMATE: + // TODO : Add missing text + DoCastAOE(SPELL_DECIMATE); + events.ScheduleEvent(EVENT_DECIMATE, 105000); + break; + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK); + events.ScheduleEvent(EVENT_BERSERK, 5*60000); + break; + case EVENT_SUMMON: + for (uint32 i = 0; i < RAID_MODE(1,2); ++i) + DoSummon(MOB_ZOMBIE, triggers[rand()%3]); + events.ScheduleEvent(EVENT_SUMMON, 10000); + break; + } + } + + if (me->getVictim()->GetEntry() == MOB_ZOMBIE) + { + if (me->IsWithinMeleeRange(me->getVictim())) + { + me->Kill(me->getVictim()); + me->ModifyHealth(me->GetMaxHealth() * 0.05f); + } + } + else + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_gluth(Creature* pCreature) +{ + return new boss_gluthAI (pCreature); +} + +void AddSC_boss_gluth() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_gluth"; + newscript->GetAI = &GetAI_boss_gluth; + newscript->RegisterSelf(); +} + diff --git a/src/scripts/northrend/naxxramas/boss_gothik.cpp b/src/scripts/northrend/naxxramas/boss_gothik.cpp new file mode 100644 index 00000000000..191a5e8e91d --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_gothik.cpp @@ -0,0 +1,534 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" +#include "SpellId.h" + +enum Yells +{ + SAY_SPEECH = -1533040, + SAY_KILL = -1533041, + SAY_DEATH = -1533042, + SAY_TELEPORT = -1533043 +}; +//Gothik +enum Spells +{ + SPELL_HARVEST_SOUL = SPELL_HARVEST_SOUL_28679, + SPELL_SHADOW_BOLT = SPELL_SHADOW_BOLT_29317, + H_SPELL_SHADOW_BOLT = SPELL_SHADOW_BOLT_56405, + SPELL_INFORM_LIVE_TRAINEE = SPELL_TO_ANCHOR_1_27892, + SPELL_INFORM_LIVE_KNIGHT = SPELL_TO_ANCHOR_1_27928, + SPELL_INFORM_LIVE_RIDER = SPELL_TO_ANCHOR_1_27935, + SPELL_INFORM_DEAD_TRAINEE = SPELL_ANCHOR_TO_SKULLS_27915, + SPELL_INFORM_DEAD_KNIGHT = SPELL_ANCHOR_TO_SKULLS_27931, + SPELL_INFORM_DEAD_RIDER = SPELL_ANCHOR_TO_SKULLS_27937 +}; +enum Creatures +{ + MOB_LIVE_TRAINEE = 16124, + MOB_LIVE_KNIGHT = 16125, + MOB_LIVE_RIDER = 16126, + MOB_DEAD_TRAINEE = 16127, + MOB_DEAD_KNIGHT = 16148, + MOB_DEAD_RIDER = 16150, + MOB_DEAD_HORSE = 16149 +}; + +struct Waves { uint32 entry, time; }; +// wave setups are the same in heroic and normal difficulty, only count of mobs is different, +// but this is handled in DoGothikSummon function +const Waves waves[] = +{ + {MOB_LIVE_TRAINEE, 20000}, + {MOB_LIVE_TRAINEE, 20000}, + {MOB_LIVE_TRAINEE, 10000}, + {MOB_LIVE_KNIGHT, 10000}, + {MOB_LIVE_TRAINEE, 15000}, + {MOB_LIVE_KNIGHT, 5000}, + {MOB_LIVE_TRAINEE, 20000}, + {MOB_LIVE_TRAINEE, 0}, + {MOB_LIVE_KNIGHT, 10000}, + {MOB_LIVE_RIDER, 10000}, + {MOB_LIVE_TRAINEE, 5000}, + {MOB_LIVE_KNIGHT, 15000}, + {MOB_LIVE_RIDER, 0}, + {MOB_LIVE_TRAINEE, 10000}, + {MOB_LIVE_KNIGHT, 10000}, + {MOB_LIVE_TRAINEE, 10000}, + {MOB_LIVE_RIDER, 5000}, + {MOB_LIVE_KNIGHT, 5000}, + {MOB_LIVE_TRAINEE, 20000}, + {MOB_LIVE_RIDER, 0}, + {MOB_LIVE_KNIGHT, 0}, + {MOB_LIVE_TRAINEE, 20000}, + {MOB_LIVE_TRAINEE, 25000}, + {0, 0}, +}; + +#define POS_Y_GATE -3360.78f +#define POS_Y_WEST -3285.0f +#define POS_Y_EAST -3434.0f +#define POS_X_NORTH 2750.49f +#define POS_X_SOUTH 2633.84f + +#define IN_LIVE_SIDE(who) (who->GetPositionY() < POS_Y_GATE) + +enum Events +{ + EVENT_NONE, + EVENT_SUMMON, + EVENT_HARVEST, + EVENT_BOLT, + EVENT_TELEPORT +}; +enum Pos +{ + POS_LIVE = 6, + POS_DEAD = 5 +}; + +const Position PosSummonLive[POS_LIVE] = +{ + {2669.7, -3428.76, 268.56, 1.6}, + {2692.1, -3428.76, 268.56, 1.6}, + {2714.4, -3428.76, 268.56, 1.6}, + {2669.7, -3431.67, 268.56, 1.6}, + {2692.1, -3431.67, 268.56, 1.6}, + {2714.4, -3431.67, 268.56, 1.6}, +}; + +const Position PosSummonDead[POS_DEAD] = +{ + {2725.1, -3310.0, 268.85, 3.4}, + {2699.3, -3322.8, 268.60, 3.3}, + {2733.1, -3348.5, 268.84, 3.1}, + {2682.8, -3304.2, 268.85, 3.9}, + {2664.8, -3340.7, 268.23, 3.7}, +}; + +const float PosGroundLiveSide[4] = {2691.2, -3387.0, 267.68, 1.52}; +const float PosGroundDeadSide[4] = {2693.5, -3334.6, 267.68, 4.67}; +const float PosPlatform[4] = {2640.5, -3360.6, 285.26, 0}; + +// Predicate function to check that the r efzr unit is NOT on the same side as the source. +struct NotOnSameSide : public std::unary_function<Unit *, bool> { + bool m_inLiveSide; + NotOnSameSide(Unit *pSource) : m_inLiveSide(IN_LIVE_SIDE(pSource)) {} + bool operator() (const Unit *pTarget) { + return (m_inLiveSide != IN_LIVE_SIDE(pTarget)); + } +}; + +struct TRINITY_DLL_DECL boss_gothikAI : public BossAI +{ + boss_gothikAI(Creature *c) : BossAI(c, BOSS_GOTHIK) {} + + uint32 waveCount; + typedef std::vector<Creature*> TriggerVct; + TriggerVct liveTrigger, deadTrigger; + bool mergedSides; + bool phaseTwo; + bool thirtyPercentReached; + + void Reset() + { + liveTrigger.clear(); + deadTrigger.clear(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE); + me->SetReactState(REACT_PASSIVE); + if (instance) + instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); + _Reset(); + mergedSides = false; + phaseTwo = false; + thirtyPercentReached = false; + } + + void EnterCombat(Unit *who) + { + for (uint32 i = 0; i < POS_LIVE; ++i) + if (Creature *trigger = DoSummon(WORLD_TRIGGER, PosSummonLive[i])) + liveTrigger.push_back(trigger); + for (uint32 i = 0; i < POS_DEAD; ++i) + if (Creature *trigger = DoSummon(WORLD_TRIGGER, PosSummonDead[i])) + deadTrigger.push_back(trigger); + + if (liveTrigger.size() < POS_LIVE || deadTrigger.size() < POS_DEAD) + { + error_log("Script Gothik: cannot summon triggers!"); + EnterEvadeMode(); + return; + } + + _EnterCombat(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE); + waveCount = 0; + events.ScheduleEvent(EVENT_SUMMON, 30000); + DoTeleportTo(PosPlatform); + DoScriptText(SAY_SPEECH, me); + if (instance) + instance->SetData(DATA_GOTHIK_GATE, GO_STATE_READY); + } + + void JustSummoned(Creature *summon) + { + if (summon->GetEntry() == WORLD_TRIGGER) + summon->setActive(true); + else if (!mergedSides) + { + summon->AI()->DoAction(me->HasReactState(REACT_PASSIVE) ? 1 : 0); + summon->AI()->EnterEvadeMode(); + } + else + { + summon->AI()->DoAction(0); + summon->AI()->DoZoneInCombat(); + } + summons.Summon(summon); + } + + void SummonedCreatureDespawn(Creature *summon) + { + summons.Despawn(summon); + } + + void KilledUnit(Unit* victim) + { + if (!(rand()%5)) + DoScriptText(SAY_KILL, me); + } + + void JustDied(Unit* Killer) + { + liveTrigger.clear(); + deadTrigger.clear(); + _JustDied(); + DoScriptText(SAY_DEATH, me); + if (instance) + instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); + } + + void DoGothikSummon(uint32 entry) + { + if (getDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + { + switch(entry) + { + case MOB_LIVE_TRAINEE: + DoSummon(MOB_LIVE_TRAINEE, liveTrigger[0], 1); + DoSummon(MOB_LIVE_TRAINEE, liveTrigger[1], 1); + DoSummon(MOB_LIVE_TRAINEE, liveTrigger[2], 1); + break; + case MOB_LIVE_KNIGHT: + DoSummon(MOB_LIVE_KNIGHT, liveTrigger[3], 1); + DoSummon(MOB_LIVE_KNIGHT, liveTrigger[5], 1); + break; + case MOB_LIVE_RIDER: + DoSummon(MOB_LIVE_RIDER, liveTrigger[4], 1); + break; + } + } + else + { + switch(entry) + { + case MOB_LIVE_TRAINEE: + DoSummon(MOB_LIVE_TRAINEE, liveTrigger[0], 1); + DoSummon(MOB_LIVE_TRAINEE, liveTrigger[1], 1); + break; + case MOB_LIVE_KNIGHT: + DoSummon(MOB_LIVE_KNIGHT, liveTrigger[5], 1); + break; + case MOB_LIVE_RIDER: + DoSummon(MOB_LIVE_RIDER, liveTrigger[4], 1); + break; + } + } + } + + bool CheckGroupSplitted() + { + bool checklife = false; + bool checkdead = false; + + Map* pMap = me->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + if (!PlayerList.isEmpty()) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (i->getSource() && i->getSource()->isAlive() && + i->getSource()->GetPositionX() <= POS_X_NORTH && + i->getSource()->GetPositionX() >= POS_X_SOUTH && + i->getSource()->GetPositionY() <= POS_Y_GATE && + i->getSource()->GetPositionY() >= POS_Y_EAST) + { + checklife = true; + } + else if (i->getSource() && i->getSource()->isAlive() && + i->getSource()->GetPositionX() <= POS_X_NORTH && + i->getSource()->GetPositionX() >= POS_X_SOUTH && + i->getSource()->GetPositionY() >= POS_Y_GATE && + i->getSource()->GetPositionY() <= POS_Y_WEST) + { + checkdead = true; + } + + if (checklife && checkdead) + return true; + } + } + } + + return false; + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + uint32 spellId = 0; + switch(spell->Id) + { + case SPELL_INFORM_LIVE_TRAINEE: spellId = SPELL_INFORM_DEAD_TRAINEE; break; + case SPELL_INFORM_LIVE_KNIGHT: spellId = SPELL_INFORM_DEAD_KNIGHT; break; + case SPELL_INFORM_LIVE_RIDER: spellId = SPELL_INFORM_DEAD_RIDER; break; + } + if (spellId && me->isInCombat()) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_SPELLCAST); + me->CastSpell(deadTrigger[rand()%POS_DEAD], spellId, true); + } + } + + void SpellHitTarget(Unit *pTarget, const SpellEntry *spell) + { + if (!me->isInCombat()) + return; + + switch(spell->Id) + { + case SPELL_INFORM_DEAD_TRAINEE: + DoSummon(MOB_DEAD_TRAINEE, pTarget, 0); + break; + case SPELL_INFORM_DEAD_KNIGHT: + DoSummon(MOB_DEAD_KNIGHT, pTarget, 0); + break; + case SPELL_INFORM_DEAD_RIDER: + DoSummon(MOB_DEAD_RIDER, pTarget, 1.0f); + DoSummon(MOB_DEAD_HORSE, pTarget, 1.0f); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateCombatState() || !CheckInRoom()) + return; + + events.Update(diff); + + if (!thirtyPercentReached && HealthBelowPct(30) && phaseTwo) + { + thirtyPercentReached = true; + if (instance) + instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); + } + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_SUMMON: + if (waves[waveCount].entry) + { + DoGothikSummon(waves[waveCount].entry); + + // if group is not splitted, open gate and merge both sides at ~ 2 minutes (wave 11) + if (waveCount == 11) + { + if (!CheckGroupSplitted()) + { + if (instance) + instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); + summons.DoAction(0, 0); + summons.DoZoneInCombat(); + mergedSides = true; + } + } + + events.ScheduleEvent(EVENT_SUMMON, waves[waveCount].time); + ++waveCount; + } + else + { + phaseTwo = true; + DoScriptText(SAY_TELEPORT, me); + DoTeleportTo(PosGroundLiveSide); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + summons.DoAction(0, 0); + summons.DoZoneInCombat(); + events.ScheduleEvent(EVENT_BOLT, 1000); + events.ScheduleEvent(EVENT_HARVEST, urand(3000,15000)); + events.ScheduleEvent(EVENT_TELEPORT, 20000); + } + break; + case EVENT_BOLT: + DoCast(me->getVictim(), RAID_MODE(SPELL_SHADOW_BOLT, H_SPELL_SHADOW_BOLT)); + events.ScheduleEvent(EVENT_BOLT, 1000); + break; + case EVENT_HARVEST: + DoCast(me->getVictim(), SPELL_HARVEST_SOUL, true); + events.ScheduleEvent(EVENT_HARVEST, urand(20000,25000)); + break; + case EVENT_TELEPORT: + if (!thirtyPercentReached) + { + m_creature->AttackStop(); + if (IN_LIVE_SIDE(m_creature)) + { + DoTeleportTo(PosGroundDeadSide); + } + else + { + DoTeleportTo(PosGroundLiveSide); + } + + m_creature->getThreatManager().resetAggro(NotOnSameSide(m_creature)); + if (Unit *pTarget = SelectTarget(SELECT_TARGET_NEAREST, 0)) + { + m_creature->getThreatManager().addThreat(pTarget, 100.0f); + AttackStart(pTarget); + } + + events.ScheduleEvent(EVENT_TELEPORT, 20000); + } + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL mob_gothik_minionAI : public CombatAI +{ + mob_gothik_minionAI(Creature *c) : CombatAI(c) + { + liveSide = IN_LIVE_SIDE(me); + } + + bool liveSide; + bool gateClose; + + bool isOnSameSide(const Unit *pWho) + { + return (liveSide == IN_LIVE_SIDE(pWho)); + } + + void DoAction(const int32 param) + { + gateClose = param; + } + + void DamageTaken(Unit *attacker, uint32 &damage) + { + if (gateClose && !isOnSameSide(attacker)) + damage = 0; + } + + void JustDied(Unit *killer) + { + if (me->isSummon()) + { + if (Unit *owner = CAST_SUM(me)->GetSummoner()) + CombatAI::JustDied(owner); + } + } + + void EnterEvadeMode() + { + if (!gateClose) + { + CombatAI::EnterEvadeMode(); + return; + } + + if (!_EnterEvadeMode()) + return; + + Map* pMap = me->GetMap(); + if (pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + if (!PlayerList.isEmpty()) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (i->getSource() && i->getSource()->isAlive() && isOnSameSide(i->getSource())) + { + AttackStart(i->getSource()); + return; + } + } + } + } + + me->GetMotionMaster()->MoveIdle(); + Reset(); + } + + void UpdateAI(const uint32 diff) + { + if (gateClose && (!isOnSameSide(me) || me->getVictim() && !isOnSameSide(me->getVictim()))) + { + EnterEvadeMode(); + return; + } + + CombatAI::UpdateAI(diff); + } +}; + +CreatureAI* GetAI_boss_gothik(Creature* pCreature) +{ + return new boss_gothikAI (pCreature); +} + +CreatureAI* GetAI_mob_gothik_minion(Creature* pCreature) +{ + return new mob_gothik_minionAI (pCreature); +} + +void AddSC_boss_gothik() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_gothik"; + newscript->GetAI = &GetAI_boss_gothik; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_gothik_minion"; + newscript->GetAI = &GetAI_mob_gothik_minion; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_grobbulus.cpp b/src/scripts/northrend/naxxramas/boss_grobbulus.cpp new file mode 100644 index 00000000000..f7b0887be4e --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_grobbulus.cpp @@ -0,0 +1,142 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define SPELL_BOMBARD_SLIME 28280 + +#define SPELL_POISON_CLOUD 28240 +#define SPELL_MUTATING_INJECTION 28169 +#define SPELL_SLIME_SPRAY RAID_MODE(28157,54364) +#define SPELL_BERSERK 26662 +#define SPELL_POISON_CLOUD_ADD 59116 + +#define EVENT_BERSERK 1 +#define EVENT_CLOUD 2 +#define EVENT_INJECT 3 +#define EVENT_SPRAY 4 + +#define MOB_FALLOUT_SLIME 16290 + +struct TRINITY_DLL_DECL boss_grobbulusAI : public BossAI +{ + boss_grobbulusAI(Creature *c) : BossAI(c, BOSS_GROBBULUS) + { + me->ApplySpellImmune(0, IMMUNITY_ID, SPELL_POISON_CLOUD_ADD, true); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_CLOUD, 15000); + events.ScheduleEvent(EVENT_INJECT, 20000); + events.ScheduleEvent(EVENT_SPRAY, 15000+rand()%15000); //not sure + events.ScheduleEvent(EVENT_BERSERK, 12*60000); + } + + void SpellHitTarget(Unit *pTarget, const SpellEntry *spell) + { + if (spell->Id == SPELL_SLIME_SPRAY) + { + if (TempSummon *slime = me->SummonCreature(MOB_FALLOUT_SLIME, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0)) + DoZoneInCombat(slime); + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_CLOUD: + DoCastAOE(SPELL_POISON_CLOUD); + events.ScheduleEvent(EVENT_CLOUD, 15000); + return; + case EVENT_BERSERK: + DoCastAOE(SPELL_BERSERK); + return; + case EVENT_SPRAY: + DoCastAOE(SPELL_SLIME_SPRAY); + events.ScheduleEvent(EVENT_SPRAY, 15000+rand()%15000); + return; + case EVENT_INJECT: + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 1)) + if (!pTarget->HasAura(SPELL_MUTATING_INJECTION)) + DoCast(pTarget, SPELL_MUTATING_INJECTION); + events.ScheduleEvent(EVENT_INJECT, 8000 + 12000 * ((float)me->GetHealth() / me->GetMaxHealth())); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL npc_grobbulus_poison_cloudAI : public Scripted_NoMovementAI +{ + npc_grobbulus_poison_cloudAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + Reset(); + } + + uint32 Cloud_Timer; + + void Reset() + { + Cloud_Timer = 1000; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void UpdateAI(const uint32 diff) + { + if (Cloud_Timer <= diff) + { + DoCast(m_creature, SPELL_POISON_CLOUD_ADD); + Cloud_Timer = 10000; + } else Cloud_Timer -= diff; + } +}; + +CreatureAI* GetAI_boss_grobbulus(Creature* pCreature) +{ + return new boss_grobbulusAI (pCreature); +} + +CreatureAI* GetAI_npc_grobbulus_poison_cloud(Creature* pCreature) +{ + return new npc_grobbulus_poison_cloudAI(pCreature); +} + +void AddSC_boss_grobbulus() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_grobbulus"; + newscript->GetAI = &GetAI_boss_grobbulus; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_grobbulus_poison_cloud"; + newscript->GetAI = &GetAI_npc_grobbulus_poison_cloud; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_heigan.cpp b/src/scripts/northrend/naxxramas/boss_heigan.cpp new file mode 100644 index 00000000000..d653e10d37a --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_heigan.cpp @@ -0,0 +1,151 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define SAY_AGGRO RAND(-1533109,-1533110,-1533111) +#define SAY_SLAY -1533112 +#define SAY_TAUNT RAND(-1533113,-1533114,-1533115,-1533116,-1533117) +#define SAY_DEATH -1533118 + +#define SPELL_SPELL_DISRUPTION 29310 +#define SPELL_DECREPIT_FEVER RAID_MODE(29998,55011) +#define SPELL_PLAGUE_CLOUD 29350 + +enum Events +{ + EVENT_NONE, + EVENT_DISRUPT, + EVENT_FEVER, + EVENT_ERUPT, + EVENT_PHASE, +}; + +enum Phases +{ + PHASE_FIGHT = 1, + PHASE_DANCE, +}; + +//Spell by eye stalks +#define SPELL_MIND_FLAY 26143 + +struct TRINITY_DLL_DECL boss_heiganAI : public BossAI +{ + boss_heiganAI(Creature *c) : BossAI(c, BOSS_HEIGAN) {} + + uint32 eruptSection; + bool eruptDirection; + Phases phase; + + void KilledUnit(Unit* Victim) + { + if (!(rand()%5)) + DoScriptText(SAY_SLAY, me); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + DoScriptText(SAY_AGGRO, me); + EnterPhase(PHASE_FIGHT); + } + + void EnterPhase(Phases newPhase) + { + phase = newPhase; + events.Reset(); + eruptSection = 3; + if (phase == PHASE_FIGHT) + { + events.ScheduleEvent(EVENT_DISRUPT, 0); + events.ScheduleEvent(EVENT_FEVER, 20000); + events.ScheduleEvent(EVENT_PHASE, 85000); + events.ScheduleEvent(EVENT_ERUPT, 10000); + } + else + { + float x, y, z, o; + me->GetHomePosition(x, y, z, o); + me->NearTeleportTo(x, y, z, o); + DoCastAOE(SPELL_PLAGUE_CLOUD); + events.ScheduleEvent(EVENT_PHASE, 45000); + events.ScheduleEvent(EVENT_ERUPT, 5000); + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_DISRUPT: + DoCastAOE(SPELL_SPELL_DISRUPTION); + events.ScheduleEvent(EVENT_DISRUPT, 5000); + return; + case EVENT_FEVER: + DoCastAOE(SPELL_DECREPIT_FEVER); + events.ScheduleEvent(EVENT_FEVER, 20000); + return; + case EVENT_PHASE: + EnterPhase(phase == PHASE_FIGHT ? PHASE_DANCE : PHASE_FIGHT); + return; + case EVENT_ERUPT: + instance->SetData(DATA_HEIGAN_ERUPT, eruptSection); + TeleportCheaters(); + + if (eruptSection == 0) + eruptDirection = true; + else if (eruptSection == 3) + eruptDirection = false; + + eruptDirection ? ++eruptSection : --eruptSection; + + events.ScheduleEvent(EVENT_ERUPT, phase == PHASE_FIGHT ? 10000 : 3000); + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_heigan(Creature* pCreature) +{ + return new boss_heiganAI (pCreature); +} + +void AddSC_boss_heigan() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_heigan"; + newscript->GetAI = &GetAI_boss_heigan; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_highlord_mograine.cpp b/src/scripts/northrend/naxxramas/boss_highlord_mograine.cpp new file mode 100644 index 00000000000..9bef8ebd3f9 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_highlord_mograine.cpp @@ -0,0 +1,179 @@ +/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Highlord_Mograine +SD%Complete: 100 +SDComment: SCRIPT OBSOLETE +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//All horsemen +#define SPELL_SHIELDWALL 29061 +#define SPELL_BESERK 26662 + +// highlord mograine +#define SPELL_MARK_OF_MOGRAINE 28834 +#define SPELL_RIGHTEOUS_FIRE 28882 // Applied as a 25% chance on melee hit to proc. m_creature->GetVictim() + +#define SAY_TAUNT1 "Enough prattling. Let them come! We shall grind their bones to dust." +#define SAY_TAUNT2 "Conserve your anger! Harness your rage! You will all have outlets for your frustration soon enough." +#define SAY_TAUNT3 "Life is meaningless. It is in death that we are truly tested." +#define SAY_AGGRO1 "You seek death?" +#define SAY_AGGRO2 "None shall pass!" +#define SAY_AGGRO3 "Be still!" +#define SAY_SLAY1 "You will find no peace in death." +#define SAY_SLAY2 "The master's will is done." +#define SAY_SPECIAL "Bow to the might of the Highlord!" +#define SAY_DEATH "I... am... released! Perhaps it's not too late to - noo! I need... more time..." + +#define SOUND_TAUNT1 8842 +#define SOUND_TAUNT2 8843 +#define SOUND_TAUNT3 8844 +#define SOUND_AGGRO1 8835 +#define SOUND_AGGRO2 8836 +#define SOUND_AGGRO3 8837 +#define SOUND_SLAY1 8839 +#define SOUND_SLAY2 8840 +#define SOUND_SPECIAL 8841 +#define SOUND_DEATH 8838 + +#define SPIRIT_OF_MOGRAINE 16775 + +struct TRINITY_DLL_DECL boss_highlord_mograineAI : public ScriptedAI +{ + boss_highlord_mograineAI(Creature *c) : ScriptedAI(c) {} + + uint32 Mark_Timer; + uint32 RighteousFire_Timer; + bool ShieldWall1; + bool ShieldWall2; + + void Reset() + { + Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. + RighteousFire_Timer = 2000; // applied approx 1 out of 4 attacks + ShieldWall1 = true; + ShieldWall2 = true; + } + + void InitialYell() + { + if (!m_creature->isInCombat()) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + } + } + } + + void KilledUnit() + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + InitialYell(); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + // Mark of Mograine + if (Mark_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MARK_OF_MOGRAINE); + Mark_Timer = 12000; + }else Mark_Timer -= diff; + + // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds + if (ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) + { + if (ShieldWall1) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall1 = false; + } + } + if (ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) + { + if (ShieldWall2) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall2 = false; + } + } + + // Righteous Fire + if (RighteousFire_Timer < diff) + { + if (rand()%4 == 1) // 1/4 + { + DoCast(m_creature->getVictim(),SPELL_RIGHTEOUS_FIRE); + } + RighteousFire_Timer = 2000; + }else RighteousFire_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_highlord_mograine(Creature* pCreature) +{ + return new boss_highlord_mograineAI (pCreature); +} + +void AddSC_boss_highlord_mograine() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_highlord_mograine"; + newscript->GetAI = &GetAI_boss_highlord_mograine; + newscript->RegisterSelf(); +} + diff --git a/src/scripts/northrend/naxxramas/boss_kelthuzad.cpp b/src/scripts/northrend/naxxramas/boss_kelthuzad.cpp new file mode 100644 index 00000000000..44333588249 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_kelthuzad.cpp @@ -0,0 +1,305 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_KelThuzud +SD%Complete: 0 +SDComment: VERIFY SCRIPT +SDCategory: Naxxramas +EndScriptData */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +enum Yells +{ + //when shappiron dies. dialog between kel and lich king (in this order) + SAY_SAPP_DIALOG1 = -1533084, //not used + SAY_SAPP_DIALOG2_LICH = -1533085, //not used + SAY_SAPP_DIALOG3 = -1533086, //not used + SAY_SAPP_DIALOG4_LICH = -1533087, //not used + SAY_SAPP_DIALOG5 = -1533088, //not used + SAY_CAT_DIED = -1533089, //when cat dies, not used + //when each of the 4 wing bosses dies + SAY_TAUNT1 = -1533090, //not used + SAY_TAUNT2 = -1533091, //not used + SAY_TAUNT3 = -1533092, //not used + SAY_TAUNT4 = -1533093, //not used + SAY_SUMMON_MINIONS = -1533105, //start of phase 1 not used + SAY_AGGRO_1 = -1533094, //start of phase 2 + SAY_AGGRO_2 = -1533095, + SAY_AGGRO_3 = -1533096, + SAY_SLAY_1 = -1533097, + SAY_SLAY_2 = -1533098, + SAY_DEATH = -1533099, + SAY_CHAIN_1 = -1533100, + SAY_CHAIN_2 = -1533101, + SAY_FROST_BLAST = -1533102, + SAY_SPECIAL_1 = -1533106, + SAY_SPECIAL_2 = -1533107, + SAY_SPECIAL_3 = -1533108, + SAY_REQUEST_AID = -1533103, //start of phase 3 + SAY_ANSWER_REQUEST = -1533104 //lich king answer +}; +enum Event +{ + EVENT_NONE, + EVENT_BOLT, + EVENT_NOVA, + EVENT_CHAIN, + EVENT_DETONATE, + EVENT_FISSURE, + EVENT_BLAST, + + EVENT_WASTE, + EVENT_ABOMIN, + EVENT_WEAVER, + EVENT_ICECROWN, + + EVENT_PHASE, +}; + +enum Spells +{ + SPELL_FROST_BOLT = 28478, + H_SPELL_FROST_BOLT = 55802, + SPELL_FROST_BOLT_AOE = 28479, + H_SPELL_FROST_BOLT_AOE = 55807, + SPELL_SHADOW_FISURE = 27810, + SPELL_VOID_BLAST = 27812, + SPELL_MANA_DETONATION = 27819, + SPELL_FROST_BLAST = 27808, + SPELL_CHAINS_OF_KELTHUZAD = 28410, //28408 script effect + SPELL_BERSERK = 28498 +}; + +enum Creatures +{ + NPC_WASTE = 16427, // Soldiers of the Frozen Wastes + NPC_ABOMINATION = 16428, // Unstoppable Abominations + NPC_WEAVER = 16429, // Soul Weavers + NPC_ICECROWN = 16441 // Guardians of Icecrown +}; + +const Position Pos[12] = +{ + {3783.272705, -5062.697266, 143.711203, 3.617599}, //LEFT_FAR + {3730.291260, -5027.239258, 143.956909, 4.461900}, //LEFT_MIDDLE + {3683.868652, -5057.281250, 143.183884, 5.237086}, //LEFT_NEAR + {3759.355225, -5174.128418, 143.802383, 2.170104}, //RIGHT_FAR + {3700.724365, -5185.123047, 143.928024, 1.309310}, //RIGHT_MIDDLE + {3665.121094, -5138.679199, 143.183212, 0.604023}, //RIGHT_NEAR + {3754.431396, -5080.727734, 142.036316, 3.736189}, //LEFT_FAR + {3724.396484, -5061.330566, 142.032700, 4.564785}, //LEFT_MIDDLE + {3687.158424, -5076.834473, 142.017319, 5.237086}, //LEFT_NEAR + {3687.571777, -5126.831055, 142.017807, 0.604023}, //RIGHT_FAR + {3707.990733, -5151.450195, 142.032562, 1.376855}, //RIGHT_MIDDLE + {3739.500000, -5141.883989, 142.014113, 2.121412} //RIGHT_NEAR +}; + +struct TRINITY_DLL_DECL boss_kelthuzadAI : public BossAI +{ + boss_kelthuzadAI(Creature* c) : BossAI(c, BOSS_KELTHUZAD) {} + + uint32 GuardiansOfIcecrown_Count; + + uint32 Phase; + uint32 GuardiansOfIcecrown_Timer; + + void Reset() + { + _Reset(); + me->SetReactState(REACT_AGGRESSIVE); + GuardiansOfIcecrown_Count = 0; + + GuardiansOfIcecrown_Timer = 5000; //5 seconds for summoning each Guardian of Icecrown in phase 3 + + Phase=0; + } + + void KilledUnit() + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), m_creature); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, m_creature); + } + + void EnterCombat(Unit* who) + { + _EnterCombat(); + DoScriptText(RAND(SAY_AGGRO_1,SAY_AGGRO_2,SAY_AGGRO_3), me); + Phase=1; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + events.ScheduleEvent(EVENT_WASTE, 5000); + events.ScheduleEvent(EVENT_ABOMIN, 25000); + events.ScheduleEvent(EVENT_WEAVER, 20000); + events.ScheduleEvent(EVENT_PHASE, 228000); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateCombatState()) + return; + + events.Update(diff); + + if (Phase == 1) + { + while(uint32 eventId = events.GetEvent()) + { + switch(eventId) + { + case EVENT_WASTE: + DoSummon(NPC_WASTE, Pos[RAND(0,3,6,9)]); + events.RepeatEvent(5000); + break; + case EVENT_ABOMIN: + DoSummon(NPC_ABOMINATION, Pos[RAND(1,4,7,10)]); + events.RepeatEvent(25000); + break; + case EVENT_WEAVER: + DoSummon(NPC_WEAVER, Pos[RAND(0,3,6,9)]); + events.RepeatEvent(20000); + break; + case EVENT_PHASE: + events.Reset(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + events.ScheduleEvent(EVENT_BOLT, urand(1000,10000)); + events.ScheduleEvent(EVENT_NOVA, urand(10000,15000)); + events.ScheduleEvent(EVENT_DETONATE, 20000); + events.ScheduleEvent(EVENT_FISSURE, 25000); + events.ScheduleEvent(EVENT_BLAST, urand(30000,60000)); + if (getDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + events.ScheduleEvent(EVENT_CHAIN, urand(30000,60000)); + Phase = 2; + return; + default: + events.PopEvent(); + break; + } + } + } + else + { + //start phase 3 when we are 40% health + if (Phase != 3) + { + if (HealthBelowPct(40)) + { + Phase = 3 ; + DoScriptText(SAY_REQUEST_AID, m_creature); + //here Lich King should respond to KelThuzad but I don't know which Creature to make talk + //so for now just make Kelthuzad says it. + DoScriptText(SAY_ANSWER_REQUEST, m_creature); + } + } + else if (GuardiansOfIcecrown_Count < RAID_MODE(2,5)) + { + if (GuardiansOfIcecrown_Timer <= diff) + { + DoSummon(NPC_ICECROWN, Pos[RAND(2,5,8)]); + ++GuardiansOfIcecrown_Count; + GuardiansOfIcecrown_Timer = 5000; + } + else GuardiansOfIcecrown_Timer -= diff; + } + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if (uint32 eventId = events.GetEvent()) + { + switch(eventId) + { + case EVENT_BOLT: + DoCastVictim(RAID_MODE(SPELL_FROST_BOLT,H_SPELL_FROST_BOLT)); + events.RepeatEvent(urand(1000,10000)); + return; + case EVENT_NOVA: + DoCastAOE(RAID_MODE(SPELL_FROST_BOLT_AOE,H_SPELL_FROST_BOLT_AOE)); + events.RepeatEvent(urand(10000,20000)); + return; + case EVENT_CHAIN: + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 1, 200, true)) + DoCast(pTarget, SPELL_CHAINS_OF_KELTHUZAD); + DoScriptText(RAND(SAY_CHAIN_1,SAY_CHAIN_2), me); + events.RepeatEvent(urand(30000,60000)); + return; + case EVENT_DETONATE: + { + std::vector<Unit*> unitList; + std::list<HostilReference*> *threatList = &me->getThreatManager().getThreatList(); + for (std::list<HostilReference*>::const_iterator itr = threatList->begin(); itr != threatList->end(); ++itr) + { + if ((*itr)->getTarget()->GetTypeId() == TYPEID_PLAYER + && (*itr)->getTarget()->getPowerType() == POWER_MANA + && (*itr)->getTarget()->GetPower(POWER_MANA)) + unitList.push_back((*itr)->getTarget()); + } + + if (!unitList.empty()) + { + std::vector<Unit*>::iterator itr = unitList.begin(); + advance(itr, rand()%unitList.size()); + DoCast(*itr, SPELL_MANA_DETONATION); + DoScriptText(RAND(SAY_SPECIAL_1,SAY_SPECIAL_2,SAY_SPECIAL_3), me); + } + + events.RepeatEvent(20000); + return; + } + case EVENT_FISSURE: + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM,0)) + DoCast(pTarget, SPELL_SHADOW_FISURE); + events.RepeatEvent(25000); + return; + case EVENT_BLAST: + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) + DoCast(pTarget, SPELL_FROST_BLAST); + if (rand()%2) + DoScriptText(SAY_FROST_BLAST, m_creature); + events.RepeatEvent(urand(30000,60000)); + return; + default: + events.PopEvent(); + return; + } + } + + DoMeleeAttackIfReady(); + } + } +}; + +CreatureAI* GetAI_boss_kelthuzadAI(Creature* pCreature) +{ + return new boss_kelthuzadAI (pCreature); +} + +void AddSC_boss_kelthuzad() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_kelthuzad"; + newscript->GetAI = &GetAI_boss_kelthuzadAI; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_loatheb.cpp b/src/scripts/northrend/naxxramas/boss_loatheb.cpp new file mode 100644 index 00000000000..e209e7c7f06 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_loatheb.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +enum Spells +{ + SPELL_NECROTIC_AURA = 55593, + SPELL_SUMMON_SPORE = 29234, + SPELL_DEATHBLOOM = 29865, + H_SPELL_DEATHBLOOM = 55053, + SPELL_INEVITABLE_DOOM = 29204, + H_SPELL_INEVITABLE_DOOM = 55052 +}; + +enum Events +{ + EVENT_NONE, + EVENT_AURA, + EVENT_BLOOM, + EVENT_DOOM, +}; + +struct TRINITY_DLL_DECL boss_loathebAI : public BossAI +{ + boss_loathebAI(Creature *c) : BossAI(c, BOSS_LOATHEB) {} + + void EnterCombat(Unit *who) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_AURA, 0); + events.ScheduleEvent(EVENT_BLOOM, 30000); + events.ScheduleEvent(EVENT_DOOM, 120000); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_AURA: + DoCastAOE(SPELL_NECROTIC_AURA); + events.ScheduleEvent(EVENT_AURA, 20000); + return; + case EVENT_BLOOM: + DoCastAOE(SPELL_SUMMON_SPORE, true); + DoCastAOE(RAID_MODE(SPELL_DEATHBLOOM,H_SPELL_DEATHBLOOM)); + events.ScheduleEvent(EVENT_BLOOM, 30000); + return; + case EVENT_DOOM: + DoCastAOE(RAID_MODE(SPELL_INEVITABLE_DOOM,H_SPELL_INEVITABLE_DOOM)); + events.ScheduleEvent(EVENT_DOOM, events.GetTimer() < 5*60000 ? 30000 : 15000); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_loatheb(Creature* pCreature) +{ + return new boss_loathebAI (pCreature); +} + +enum SporeSpells +{ + SPELL_FUNGAL_CREEP = 29232 +}; + +struct TRINITY_DLL_DECL mob_loatheb_sporeAI : public ScriptedAI +{ + mob_loatheb_sporeAI(Creature *c) : ScriptedAI(c) {} + + void JustDied(Unit* killer) + { + DoCast(killer, SPELL_FUNGAL_CREEP); + } +}; + +CreatureAI* GetAI_mob_loatheb_spore(Creature* pCreature) +{ + return new mob_loatheb_sporeAI (pCreature); +} + +void AddSC_boss_loatheb() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_loatheb"; + newscript->GetAI = &GetAI_boss_loatheb; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_loatheb_spore"; + newscript->GetAI = &GetAI_mob_loatheb_spore; + newscript->RegisterSelf(); + + // Fungal Creep + //GetAISpellInfo(29232)->condition = AICOND_DIE; +} + diff --git a/src/scripts/northrend/naxxramas/boss_maexxna.cpp b/src/scripts/northrend/naxxramas/boss_maexxna.cpp new file mode 100644 index 00000000000..3238ffababa --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_maexxna.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define SPELL_WEB_WRAP 28622 +#define SPELL_WEB_SPRAY RAID_MODE(29484,54125) +#define SPELL_POISON_SHOCK RAID_MODE(28741,54122) +#define SPELL_NECROTIC_POISON RAID_MODE(54121,28776) +#define SPELL_FRENZY RAID_MODE(54123,54124) + +#define MOB_WEB_WRAP 16486 +#define MOB_SPIDERLING 17055 + +#define MAX_POS_WRAP 3 +const float PosWrap[MAX_POS_WRAP][3] = +{ + {3546.796, -3869.082, 296.450}, + {3531.271, -3847.424, 299.450}, + {3497.067, -3843.384, 302.384}, +}; + +enum Events +{ + EVENT_NONE, + EVENT_SPRAY, + EVENT_SHOCK, + EVENT_POISON, + EVENT_WRAP, + EVENT_SUMMON, +}; + +struct TRINITY_DLL_DECL boss_maexxnaAI : public BossAI +{ + boss_maexxnaAI(Creature *c) : BossAI(c, BOSS_MAEXXNA) {} + + bool enraged; + + void EnterCombat(Unit *who) + { + _EnterCombat(); + enraged = false; + events.ScheduleEvent(EVENT_WRAP, 20000); + events.ScheduleEvent(EVENT_SPRAY, 40000); + events.ScheduleEvent(EVENT_SHOCK, 10000); + events.ScheduleEvent(EVENT_POISON, 5000); + events.ScheduleEvent(EVENT_SUMMON, 40000); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_WRAP: + for (uint8 i = 0; i < RAID_MODE(1,2); ++i) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP)) + { + pTarget->RemoveAura(SPELL_WEB_SPRAY); + uint8 pos = rand()%MAX_POS_WRAP; + pTarget->GetMotionMaster()->MoveJump(PosWrap[pos][0], PosWrap[pos][1], PosWrap[pos][2], 20, 20); + if (Creature *wrap = DoSummon(MOB_WEB_WRAP, pTarget, 0, 60000)) + { + wrap->AI()->SetGUID(pTarget->GetGUID()); + wrap->GetMotionMaster()->MoveJump(PosWrap[pos][0], PosWrap[pos][1], PosWrap[pos][2], 20, 20); + } + } + } + events.ScheduleEvent(EVENT_WRAP, 40000); + return; + case EVENT_SPRAY: + DoCastAOE(SPELL_WEB_SPRAY); + events.ScheduleEvent(EVENT_SPRAY, 40000); + return; + case EVENT_SHOCK: + DoCastAOE(SPELL_POISON_SHOCK); + events.ScheduleEvent(EVENT_SHOCK, 10000); + return; + case EVENT_POISON: + DoCast(me->getVictim(), SPELL_NECROTIC_POISON); + events.ScheduleEvent(EVENT_POISON, 30000); + return; + case EVENT_SUMMON: + { + uint8 amount = urand(8,10); + for (uint8 i = 0; i < amount; ++i) + DoSummon(MOB_SPIDERLING, me); + events.ScheduleEvent(EVENT_SUMMON, 40000); + break; + } + } + } + + if (!enraged && HealthBelowPct(30)) + { + DoCast(me, SPELL_FRENZY); + enraged = true; + } + else + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_maexxna(Creature* pCreature) +{ + return new boss_maexxnaAI (pCreature); +} + +void AddSC_boss_maexxna() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_maexxna"; + newscript->GetAI = &GetAI_boss_maexxna; + newscript->RegisterSelf(); +} + diff --git a/src/scripts/northrend/naxxramas/boss_noth.cpp b/src/scripts/northrend/naxxramas/boss_noth.cpp new file mode 100644 index 00000000000..ee08e1ae51c --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_noth.cpp @@ -0,0 +1,211 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define SAY_AGGRO RAND(-1533075,-1533076,-1533077) +#define SAY_SUMMON -1533078 +#define SAY_SLAY RAND(-1533079,-1533080) +#define SAY_DEATH -1533081 + +#define SOUND_DEATH 8848 + +#define SPELL_CURSE_PLAGUEBRINGER RAID_MODE(29213,54835) +#define SPELL_BLINK RAND(29208,29209,29210,29211) +#define SPELL_CRIPPLE RAID_MODE(29212,54814) +#define SPELL_TELEPORT 29216 + +#define MOB_WARRIOR 16984 +#define MOB_CHAMPION 16983 +#define MOB_GUARDIAN 16981 + +// Teleport position of Noth on his balcony +#define TELE_X 2631.370 +#define TELE_Y -3529.680 +#define TELE_Z 274.040 +#define TELE_O 6.277 + +#define MAX_SUMMON_POS 5 + +const float SummonPos[MAX_SUMMON_POS][4] = +{ + {2728.12, -3544.43, 261.91, 6.04}, + {2729.05, -3544.47, 261.91, 5.58}, + {2728.24, -3465.08, 264.20, 3.56}, + {2704.11, -3456.81, 265.53, 4.51}, + {2663.56, -3464.43, 262.66, 5.20}, +}; + +enum Events +{ + EVENT_NONE, + EVENT_BERSERK, + EVENT_CURSE, + EVENT_BLINK, + EVENT_WARRIOR, + EVENT_BALCONY, + EVENT_WAVE, + EVENT_GROUND, +}; + +struct TRINITY_DLL_DECL boss_nothAI : public BossAI +{ + boss_nothAI(Creature *c) : BossAI(c, BOSS_NOTH) {} + + uint32 waveCount, balconyCount; + + void Reset() + { + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + _Reset(); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + DoScriptText(SAY_AGGRO, me); + balconyCount = 0; + EnterPhaseGround(); + } + + void EnterPhaseGround() + { + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoZoneInCombat(); + if (me->getThreatManager().isThreatListEmpty()) + EnterEvadeMode(); + else + { + events.ScheduleEvent(EVENT_BALCONY, 110000); + events.ScheduleEvent(EVENT_CURSE, 20000+rand()%10000); + events.ScheduleEvent(EVENT_WARRIOR, 30000); + if (getDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + events.ScheduleEvent(EVENT_BLINK, 20000+rand()%10000); + } + } + + void KilledUnit(Unit* victim) + { + if (!(rand()%5)) + DoScriptText(SAY_SLAY, me); + } + + void JustSummoned(Creature *summon) + { + summons.Summon(summon); + summon->setActive(true); + summon->AI()->DoZoneInCombat(); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + } + + void SummonUndead(uint32 entry, uint32 num) + { + for (uint32 i = 0; i < num; ++i) + { + uint32 pos = rand()%MAX_SUMMON_POS; + me->SummonCreature(entry, SummonPos[pos][0], SummonPos[pos][1], SummonPos[pos][2], + SummonPos[pos][3], TEMPSUMMON_CORPSE_DESPAWN, 60000); + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateCombatState() || !CheckInRoom()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_CURSE: + DoCastAOE(SPELL_CURSE_PLAGUEBRINGER); + events.ScheduleEvent(EVENT_CURSE, 20000+rand()%10000); + return; + case EVENT_WARRIOR: + DoScriptText(SAY_SUMMON, me); + SummonUndead(MOB_WARRIOR, RAID_MODE(2,3)); + events.ScheduleEvent(EVENT_WARRIOR, 30000); + return; + case EVENT_BLINK: + DoCastAOE(SPELL_CRIPPLE, true); + DoCastAOE(SPELL_BLINK); + DoResetThreat(); + events.ScheduleEvent(EVENT_BLINK, 20000+rand()%10000); + return; + case EVENT_BALCONY: + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->AttackStop(); + me->RemoveAllAuras(); + me->NearTeleportTo(TELE_X, TELE_Y, TELE_Z, TELE_O); + events.Reset(); + events.ScheduleEvent(EVENT_WAVE, 2000); + waveCount = 0; + return; + case EVENT_WAVE: + DoScriptText(SAY_SUMMON, me); + switch(balconyCount) + { + case 0: SummonUndead(MOB_CHAMPION, RAID_MODE(2,4)); break; + case 1: SummonUndead(MOB_CHAMPION, RAID_MODE(1,2)); + SummonUndead(MOB_GUARDIAN, RAID_MODE(1,2)); break; + case 2: SummonUndead(MOB_GUARDIAN, RAID_MODE(2,4)); break; + default:SummonUndead(MOB_CHAMPION, RAID_MODE(5,10)); + SummonUndead(MOB_GUARDIAN, RAID_MODE(5,10));break; + } + ++waveCount; + events.ScheduleEvent(waveCount < 2 ? EVENT_WAVE : EVENT_GROUND, 34000); + return; + case EVENT_GROUND: + { + ++balconyCount; + float x, y, z, o; + me->GetHomePosition(x, y, z, o); + me->NearTeleportTo(x, y, z, o); + EnterPhaseGround(); + return; + } + } + } + + if (me->HasReactState(REACT_AGGRESSIVE)) + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_noth(Creature* pCreature) +{ + return new boss_nothAI (pCreature); +} + +void AddSC_boss_noth() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_noth"; + newscript->GetAI = &GetAI_boss_noth; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_patchwerk.cpp b/src/scripts/northrend/naxxramas/boss_patchwerk.cpp new file mode 100644 index 00000000000..8cccbdc21a2 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_patchwerk.cpp @@ -0,0 +1,156 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define SAY_AGGRO RAND(-1533017,-1533018) +#define SAY_SLAY -1533019 +#define SAY_DEATH -1533020 + +#define EMOTE_BERSERK -1533021 +#define EMOTE_ENRAGE -1533022 + +#define SPELL_HATEFULSTRIKE RAID_MODE(41926,59192) +#define SPELL_FRENZY 28131 +#define SPELL_BERSERK 26662 +#define SPELL_SLIMEBOLT 32309 + +#define EVENT_BERSERK 1 +#define EVENT_HATEFUL 2 +#define EVENT_SLIME 3 + +#define ACHIEVEMENT_MAKE_QUICK_WERK_OF_HIM RAID_MODE(1856, 1857) +#define MAX_ENCOUNTER_TIME 3 * 60 * 1000 + +struct TRINITY_DLL_DECL boss_patchwerkAI : public BossAI +{ + boss_patchwerkAI(Creature *c) : BossAI(c, BOSS_PATCHWERK) {} + + bool Enraged; + + uint32 EncounterTime; + + void KilledUnit(Unit* Victim) + { + if (!(rand()%5)) + DoScriptText(SAY_SLAY, me); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + + if(EncounterTime <= MAX_ENCOUNTER_TIME) + { + AchievementEntry const *AchievMakeQuickWerkOfHim = GetAchievementStore()->LookupEntry(ACHIEVEMENT_MAKE_QUICK_WERK_OF_HIM); + if(AchievMakeQuickWerkOfHim) + { + Map *pMap = m_creature->GetMap(); + if(pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievMakeQuickWerkOfHim); + } + } + } + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + Enraged = false; + EncounterTime = 0; + DoScriptText(SAY_AGGRO, me); + events.ScheduleEvent(EVENT_HATEFUL, 1200); + events.ScheduleEvent(EVENT_BERSERK, 360000); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + EncounterTime += diff; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_HATEFUL: + { + //Cast Hateful strike on the player with the highest + //amount of HP within melee distance + uint32 MostHP = 0; + Unit* pMostHPTarget = NULL; + std::list<HostilReference*>::iterator i = me->getThreatManager().getThreatList().begin(); + for (; i != me->getThreatManager().getThreatList().end(); ++i) + { + Unit *pTarget = (*i)->getTarget(); + if (pTarget->isAlive() && pTarget->GetHealth() > MostHP && me->IsWithinMeleeRange(pTarget)) + { + MostHP = pTarget->GetHealth(); + pMostHPTarget = pTarget; + } + } + + if (pMostHPTarget) + DoCast(pMostHPTarget, SPELL_HATEFULSTRIKE, true); + + events.ScheduleEvent(EVENT_HATEFUL, 1200); + return; + } + case EVENT_BERSERK: + DoCast(m_creature, SPELL_BERSERK); + DoScriptText(EMOTE_BERSERK, m_creature); + events.ScheduleEvent(EVENT_SLIME, 2000); + return; + case EVENT_SLIME: + DoCast(m_creature->getVictim(), SPELL_SLIMEBOLT); + events.ScheduleEvent(EVENT_SLIME, 2000); + return; + } + } + + if (!Enraged && HealthBelowPct(5)) + { + DoCast(m_creature, SPELL_FRENZY); + DoScriptText(EMOTE_ENRAGE, NULL); + Enraged = true; + return; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_patchwerk(Creature* pCreature) +{ + return new boss_patchwerkAI (pCreature); +} + +void AddSC_boss_patchwerk() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_patchwerk"; + newscript->GetAI = &GetAI_boss_patchwerk; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_razuvious.cpp b/src/scripts/northrend/naxxramas/boss_razuvious.cpp new file mode 100644 index 00000000000..fa120b27779 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_razuvious.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +//Razuvious - NO TEXT sound only +//8852 aggro01 - Hah hah, I'm just getting warmed up! +//8853 aggro02 Stand and fight! +//8854 aggro03 Show me what you've got! +//8861 slay1 - You should've stayed home! +//8863 slay2- +//8858 cmmnd3 - You disappoint me, students! +//8855 cmmnd1 - Do as I taught you! +//8856 cmmnd2 - Show them no mercy! +//8859 cmmnd4 - The time for practice is over! Show me what you've learned! +//8861 Sweep the leg! Do you have a problem with that? +//8860 death - An honorable... death... +//8947 - Aggro Mixed? - ? + +#define SOUND_AGGRO RAND(8852,8853,8854) +#define SOUND_SLAY RAND(8861,8863) +#define SOUND_COMMND RAND(8855,8856,8858,8859,8861) +#define SOUND_DEATH 8860 +#define SOUND_AGGROMIX 8847 + +#define SPELL_UNBALANCING_STRIKE 26613 +#define SPELL_DISRUPTING_SHOUT RAID_MODE(29107,55543) +#define SPELL_JAGGED_KNIFE 55550 +#define SPELL_HOPELESS 29125 + +enum Events +{ + EVENT_NONE, + EVENT_STRIKE, + EVENT_SHOUT, + EVENT_KNIFE, + EVENT_COMMAND, +}; + +struct TRINITY_DLL_DECL boss_razuviousAI : public BossAI +{ + boss_razuviousAI(Creature *c) : BossAI(c, BOSS_RAZUVIOUS) {} + + void KilledUnit(Unit* victim) + { + if (!(rand()%3)) + DoPlaySoundToSet(me, SOUND_SLAY); + } + + void DamageTaken(Unit* pDone_by, uint32& uiDamage) + { + // Damage done by the controlled Death Knight understudies should also count toward damage done by players + if(pDone_by->GetTypeId() == TYPEID_UNIT && (pDone_by->GetEntry() == 16803 || pDone_by->GetEntry() == 29941)) + { + me->LowerPlayerDamageReq(uiDamage); + } + } + + void JustDied(Unit* killer) + { + _JustDied(); + DoPlaySoundToSet(me, SOUND_DEATH); + me->CastSpell(me, SPELL_HOPELESS, true); // TODO: this may affect other creatures + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + events.ScheduleEvent(EVENT_STRIKE, 30000); + events.ScheduleEvent(EVENT_SHOUT, 25000); + events.ScheduleEvent(EVENT_COMMAND, 40000); + events.ScheduleEvent(EVENT_KNIFE, 10000); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_STRIKE: + DoCast(me->getVictim(), SPELL_UNBALANCING_STRIKE); + events.ScheduleEvent(EVENT_STRIKE, 30000); + return; + case EVENT_SHOUT: + DoCastAOE(SPELL_DISRUPTING_SHOUT); + events.ScheduleEvent(EVENT_SHOUT, 25000); + return; + case EVENT_KNIFE: + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 45)) + DoCast(pTarget, SPELL_JAGGED_KNIFE); + events.ScheduleEvent(EVENT_KNIFE, 10000); + return; + case EVENT_COMMAND: + DoPlaySoundToSet(me, SOUND_COMMND); + events.ScheduleEvent(EVENT_COMMAND, 40000); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_razuvious(Creature* pCreature) +{ + return new boss_razuviousAI (pCreature); +} + +void AddSC_boss_razuvious() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_razuvious"; + newscript->GetAI = &GetAI_boss_razuvious; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/boss_sapphiron.cpp b/src/scripts/northrend/naxxramas/boss_sapphiron.cpp new file mode 100644 index 00000000000..b9acce8d7f6 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_sapphiron.cpp @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +#define EMOTE_BREATH -1533082 +#define EMOTE_ENRAGE -1533083 + +#define SPELL_FROST_AURA RAID_MODE(28531,55799) +#define SPELL_CLEAVE 19983 +#define SPELL_TAIL_SWEEP RAID_MODE(55697,55696) +#define SPELL_SUMMON_BLIZZARD 28560 +#define SPELL_LIFE_DRAIN RAID_MODE(28542,55665) +#define SPELL_ICEBOLT 28522 +#define SPELL_FROST_BREATH 29318 +#define SPELL_FROST_EXPLOSION 28524 +#define SPELL_FROST_MISSILE 30101 +#define SPELL_BERSERK 26662 +#define SPELL_DIES 29357 + +#define SPELL_CHILL RAID_MODE(28547,55699) + +#define MOB_BLIZZARD 16474 +#define GO_ICEBLOCK 181247 + +#define ACHIEVEMENT_THE_HUNDRED_CLUB RAID_MODE(2146, 2147) +#define MAX_FROST_RESISTANCE 100 + +enum Phases +{ + PHASE_NULL = 0, + PHASE_BIRTH, + PHASE_GROUND, + PHASE_FLIGHT, +}; + +enum Events +{ + EVENT_NONE, + EVENT_BERSERK, + EVENT_CLEAVE, + EVENT_TAIL, + EVENT_DRAIN, + EVENT_BLIZZARD, + EVENT_FLIGHT, + EVENT_LIFTOFF, + EVENT_ICEBOLT, + EVENT_BREATH, + EVENT_EXPLOSION, + EVENT_LAND, + EVENT_GROUND, + EVENT_BIRTH, +}; + +typedef std::map<uint64, uint64> IceBlockMap; + +struct TRINITY_DLL_DECL boss_sapphironAI : public BossAI +{ + boss_sapphironAI(Creature* c) : BossAI(c, BOSS_SAPPHIRON) + , phase(PHASE_NULL) + { + pMap = m_creature->GetMap(); + } + + Phases phase; + uint32 iceboltCount; + IceBlockMap iceblocks; + + bool CanTheHundredClub; // needed for achievement: The Hundred Club(2146, 2147) + uint32 CheckFrostResistTimer; + Map* pMap; + + void InitializeAI() + { + float x, y, z; + me->GetPosition(x, y, z); + me->SummonGameObject(GO_BIRTH, x, y, z, 0, 0, 0, 0, 0, 0); + me->SetVisibility(VISIBILITY_OFF); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + + ScriptedAI::InitializeAI(); + } + + void Reset() + { + _Reset(); + + if (phase = PHASE_FLIGHT) + ClearIceBlock(); + + phase = PHASE_NULL; + + CanTheHundredClub = true; + CheckFrostResistTimer = 5000; + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + + me->CastSpell(me, SPELL_FROST_AURA, true); + + events.ScheduleEvent(EVENT_BERSERK, 15*60000); + EnterPhaseGround(); + + CheckPlayersFrostResist(); + } + + void SpellHitTarget(Unit *pTarget, const SpellEntry *spell) + { + if (spell->Id == SPELL_ICEBOLT) + { + IceBlockMap::iterator itr = iceblocks.find(pTarget->GetGUID()); + if (itr != iceblocks.end() && !itr->second) + { + if (GameObject *iceblock = me->SummonGameObject(GO_ICEBLOCK, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, 0, 0, 0, 0, 25000)) + itr->second = iceblock->GetGUID(); + } + } + } + + void JustDied(Unit* who) + { + _JustDied(); + me->CastSpell(me, SPELL_DIES, true); + + CheckPlayersFrostResist(); + if(CanTheHundredClub) + { + AchievementEntry const *AchievTheHundredClub = GetAchievementStore()->LookupEntry(ACHIEVEMENT_THE_HUNDRED_CLUB); + if(AchievTheHundredClub) + { + if(pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievTheHundredClub); + } + } + } + } + + void MovementInform(uint32, uint32 id) + { + if (id == 1) + events.ScheduleEvent(EVENT_LIFTOFF, 0); + } + + void DoAction(const int32 param) + { + if (param == DATA_SAPPHIRON_BIRTH) + { + phase = PHASE_BIRTH; + events.ScheduleEvent(EVENT_BIRTH, 23000); + } + } + + void CheckPlayersFrostResist() + { + if(CanTheHundredClub && pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if(itr->getSource()->GetResistance(SPELL_SCHOOL_FROST) > MAX_FROST_RESISTANCE) + { + CanTheHundredClub = false; + break; + } + } + } + } + + void EnterPhaseGround() + { + phase = PHASE_GROUND; + me->SetReactState(REACT_AGGRESSIVE); + events.SetPhase(PHASE_GROUND); + events.ScheduleEvent(EVENT_CLEAVE, 5000+rand()%10000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_TAIL, 5000+rand()%10000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_DRAIN, 24000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_BLIZZARD, 5000+rand()%5000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_FLIGHT, 45000); + } + + void ClearIceBlock() + { + for (IceBlockMap::iterator itr = iceblocks.begin(); itr != iceblocks.end(); ++itr) + { + if (Player* pPlayer = Unit::GetPlayer(itr->first)) + pPlayer->RemoveAura(SPELL_ICEBOLT); + if (GameObject* pGo = GameObject::GetGameObject(*me, itr->second)) + pGo->Delete(); + } + iceblocks.clear(); + } + + void UpdateAI(const uint32 diff) + { + if (!phase) + return; + + events.Update(diff); + + if (phase != PHASE_BIRTH && !UpdateCombatState() || !CheckInRoom()) + return; + + if(CanTheHundredClub) + { + if (CheckFrostResistTimer <= diff) + { + CheckPlayersFrostResist(); + CheckFrostResistTimer = (rand() % 5 + 5) * 1000; + } else CheckFrostResistTimer -= diff; + } + + if (phase == PHASE_GROUND) + { + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_BERSERK: + DoScriptText(EMOTE_ENRAGE, m_creature); + DoCast(me, SPELL_BERSERK); + return; + case EVENT_CLEAVE: + DoCast(me->getVictim(), SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 5000+rand()%10000, 0, PHASE_GROUND); + return; + case EVENT_TAIL: + DoCastAOE(SPELL_TAIL_SWEEP); + events.ScheduleEvent(EVENT_TAIL, 5000+rand()%10000, 0, PHASE_GROUND); + return; + case EVENT_DRAIN: + DoCastAOE(SPELL_LIFE_DRAIN); + events.ScheduleEvent(EVENT_DRAIN, 24000, 0, PHASE_GROUND); + return; + case EVENT_BLIZZARD: + { + //DoCastAOE(SPELL_SUMMON_BLIZZARD); + if (Creature *pSummon = DoSummon(MOB_BLIZZARD, me, 0.0f, urand(25000,30000), TEMPSUMMON_TIMED_DESPAWN)) + pSummon->GetMotionMaster()->MoveRandom(40); + events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(20000,7000), 0, PHASE_GROUND); + break; + } + case EVENT_FLIGHT: + phase = PHASE_FLIGHT; + events.SetPhase(PHASE_FLIGHT); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + float x, y, z, o; + me->GetHomePosition(x, y, z, o); + me->GetMotionMaster()->MovePoint(1, x, y, z); + return; + } + } + + DoMeleeAttackIfReady(); + } + else + { + if (uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_LIFTOFF: + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + events.ScheduleEvent(EVENT_ICEBOLT, 1500); + iceboltCount = RAID_MODE(2,3); + return; + case EVENT_ICEBOLT: + { + std::vector<Unit*> targets; + std::list<HostilReference*>::iterator i = me->getThreatManager().getThreatList().begin(); + for (; i != me->getThreatManager().getThreatList().end(); ++i) + if ((*i)->getTarget()->GetTypeId() == TYPEID_PLAYER && !(*i)->getTarget()->HasAura(SPELL_ICEBOLT)) + targets.push_back((*i)->getTarget()); + + if (targets.empty()) + iceboltCount = 0; + else + { + std::vector<Unit*>::iterator itr = targets.begin(); + advance(itr, rand()%targets.size()); + iceblocks.insert(std::make_pair((*itr)->GetGUID(), 0)); + DoCast(*itr, SPELL_ICEBOLT); + --iceboltCount; + } + + if (iceboltCount) + events.ScheduleEvent(EVENT_ICEBOLT, 1000); + else + events.ScheduleEvent(EVENT_BREATH, 1000); + return; + } + case EVENT_BREATH: + { + DoScriptText(EMOTE_BREATH, me); + DoCastAOE(SPELL_FROST_MISSILE); + events.ScheduleEvent(EVENT_EXPLOSION, 8000); + return; + } + case EVENT_EXPLOSION: + CastExplosion(); + ClearIceBlock(); + events.ScheduleEvent(EVENT_LAND, 3000); + return; + case EVENT_LAND: + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + events.ScheduleEvent(EVENT_GROUND, 1500); + return; + case EVENT_GROUND: + EnterPhaseGround(); + return; + case EVENT_BIRTH: + me->SetVisibility(VISIBILITY_ON); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + return; + } + }//if (uint32 eventId = events.ExecuteEvent()) + }//if (phase == PHASE_GROUND) + } + + void CastExplosion() + { + DoZoneInCombat(); // make sure everyone is in threatlist + std::vector<Unit*> targets; + std::list<HostilReference*>::iterator i = me->getThreatManager().getThreatList().begin(); + for (; i != me->getThreatManager().getThreatList().end(); ++i) + { + Unit *pTarget = (*i)->getTarget(); + if (pTarget->GetTypeId() != TYPEID_PLAYER) + continue; + + if (pTarget->HasAura(SPELL_ICEBOLT)) + { + pTarget->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true); + targets.push_back(pTarget); + continue; + } + + for (IceBlockMap::iterator itr = iceblocks.begin(); itr != iceblocks.end(); ++itr) + { + if (GameObject* pGo = GameObject::GetGameObject(*me, itr->second)) + { + if (pGo->IsInBetween(me, pTarget, 2.0f) + && me->GetExactDist2d(pTarget->GetPositionX(), pTarget->GetPositionY()) - me->GetExactDist2d(pGo->GetPositionX(), pGo->GetPositionY()) < 5.0f) + { + pTarget->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true); + targets.push_back(pTarget); + break; + } + } + } + } + + me->CastSpell(me, SPELL_FROST_EXPLOSION, true); + + for (std::vector<Unit*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + (*itr)->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, false); + } +}; + +CreatureAI* GetAI_boss_sapphiron(Creature* pCreature) +{ + return new boss_sapphironAI (pCreature); +} + +void AddSC_boss_sapphiron() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_sapphiron"; + newscript->GetAI = &GetAI_boss_sapphiron; + newscript->RegisterSelf(); + + // Chill + GetAISpellInfo(28547)->cooldown = 1000; + GetAISpellInfo(55699)->cooldown = 1000; +} diff --git a/src/scripts/northrend/naxxramas/boss_thaddius.cpp b/src/scripts/northrend/naxxramas/boss_thaddius.cpp new file mode 100644 index 00000000000..fa685759e83 --- /dev/null +++ b/src/scripts/northrend/naxxramas/boss_thaddius.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +//Stalagg +enum StalaggYells +{ + SAY_STAL_AGGRO = -1533023, //not used + SAY_STAL_SLAY = -1533024, //not used + SAY_STAL_DEATH = -1533025 //not used +}; + +enum StalagSpells +{ + SPELL_POWERSURGE = 54529, + H_SPELL_POWERSURGE = 28134 +}; + +//Feugen +enum FeugenYells +{ + SAY_FEUG_AGGRO = -1533026, //not used + SAY_FEUG_SLAY = -1533027, //not used + SAY_FEUG_DEATH = -1533028 //not used +}; + +enum FeugenSpells +{ + SPELL_STATICFIELD = 28135, + H_SPELL_STATICFIELD = 54528 +}; + +//generic +#define C_TESLA_COIL 16218 //the coils (emotes "Tesla Coil overloads!") + +//Thaddius +enum ThaddiusYells +{ + SAY_GREET = -1533029, //not used + SAY_AGGRO_1 = -1533030, + SAY_AGGRO_2 = -1533031, + SAY_AGGRO_3 = -1533032, + SAY_SLAY = -1533033, + SAY_ELECT = -1533034, //not used + SAY_DEATH = -1533035, + SAY_SCREAM1 = -1533036, //not used + SAY_SCREAM2 = -1533037, //not used + SAY_SCREAM3 = -1533038, //not used + SAY_SCREAM4 = -1533039 //not used +}; + +enum ThaddiusSpells +{ + SPELL_POLARITY_SHIFT = 28089, + SPELL_BALL_LIGHTNING = 28299, + SPELL_CHAIN_LIGHTNING = 28167, + H_SPELL_CHAIN_LIGHTNING = 54531, + SPELL_BERSERK = 27680 +}; + +enum Events +{ + EVENT_NONE, + EVENT_SHIFT, + EVENT_CHAIN, + EVENT_BERSERK, +}; + +bool CheckStalaggAlive = true; +bool CheckFeugenAlive = true; + +struct TRINITY_DLL_DECL boss_thaddiusAI : public BossAI +{ + boss_thaddiusAI(Creature *c) : BossAI(c, BOSS_THADDIUS) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); + me->SetReactState(REACT_PASSIVE); + } + + void KilledUnit(Unit* victim) + { + if (!(rand()%5)) + DoScriptText(SAY_SLAY, me); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + DoScriptText(RAND(SAY_AGGRO_1,SAY_AGGRO_2,SAY_AGGRO_3), me); + events.ScheduleEvent(EVENT_SHIFT, 30000); + events.ScheduleEvent(EVENT_CHAIN, urand(10000,20000)); + events.ScheduleEvent(EVENT_BERSERK, 360000); + } + + void UpdateAI(const uint32 diff) + { + if (CheckStalaggAlive == false && CheckFeugenAlive == false) { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); + me->SetReactState(REACT_AGGRESSIVE); + } + + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_SHIFT: + DoCastAOE(SPELL_POLARITY_SHIFT); + events.ScheduleEvent(EVENT_SHIFT, 30000); + return; + case EVENT_CHAIN: + DoCast(me->getVictim(), RAID_MODE(SPELL_CHAIN_LIGHTNING, H_SPELL_CHAIN_LIGHTNING)); + events.ScheduleEvent(EVENT_CHAIN, urand(10000,20000)); + return; + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK); + return; + } + } + + if (events.GetTimer() > 15000 && !me->IsWithinMeleeRange(me->getVictim())) + DoCast(me->getVictim(), SPELL_BALL_LIGHTNING); + else + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_thaddius(Creature* pCreature) +{ + return new boss_thaddiusAI (pCreature); +} + +struct TRINITY_DLL_DECL mob_stalaggAI : public ScriptedAI +{ + mob_stalaggAI(Creature *c) : ScriptedAI(c) {} + + uint32 PowerSurgeTimer; + + void reset() + { + PowerSurgeTimer = urand(20000,25000); + } + + void JustDied(Unit *killer) + { + CheckStalaggAlive = false; + } + + void UpdateAI(const uint32 uiDiff) + { + if (PowerSurgeTimer <= uiDiff) + { + DoCast(m_creature, RAID_MODE(SPELL_POWERSURGE, H_SPELL_POWERSURGE)); + PowerSurgeTimer = urand(15000,20000); + } else PowerSurgeTimer -= uiDiff; + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_stalagg(Creature* pCreature) +{ + return new mob_stalaggAI(pCreature); +} + +struct TRINITY_DLL_DECL mob_feugenAI : public ScriptedAI +{ + mob_feugenAI(Creature *c) : ScriptedAI(c) {} + + uint32 StaticFieldTimer; + uint32 Checktimer; + + void reset() + { + StaticFieldTimer = 5000; + } + + void JustDied(Unit *killer) + { + CheckFeugenAlive = false; + } + + void UpdateAI(const uint32 uiDiff) + { + if (StaticFieldTimer <= uiDiff) + { + DoCast(m_creature, RAID_MODE(SPELL_STATICFIELD, H_SPELL_STATICFIELD)); + StaticFieldTimer = 5000; + } else StaticFieldTimer -= uiDiff; + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_feugen(Creature* pCreature) +{ + return new mob_feugenAI(pCreature); +} + +void AddSC_boss_thaddius() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_thaddius"; + newscript->GetAI = &GetAI_boss_thaddius; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_stalagg"; + newscript->GetAI = &GetAI_mob_stalagg; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_feugen"; + newscript->GetAI = &GetAI_mob_feugen; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/instance_naxxramas.cpp b/src/scripts/northrend/naxxramas/instance_naxxramas.cpp new file mode 100644 index 00000000000..103dba7e4b8 --- /dev/null +++ b/src/scripts/northrend/naxxramas/instance_naxxramas.cpp @@ -0,0 +1,244 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "naxxramas.h" + +const DoorData doorData[] = +{ + {181126, BOSS_ANUBREKHAN,DOOR_TYPE_ROOM, BOUNDARY_S}, + {181195, BOSS_ANUBREKHAN,DOOR_TYPE_PASSAGE, 0}, + {194022, BOSS_FAERLINA, DOOR_TYPE_PASSAGE, 0}, + {181209, BOSS_FAERLINA, DOOR_TYPE_PASSAGE, 0}, + {181209, BOSS_MAEXXNA, DOOR_TYPE_ROOM, BOUNDARY_SW}, + {181200, BOSS_NOTH, DOOR_TYPE_ROOM, BOUNDARY_N}, + {181201, BOSS_NOTH, DOOR_TYPE_PASSAGE, BOUNDARY_E}, + {181202, BOSS_NOTH, DOOR_TYPE_PASSAGE, 0}, + {181202, BOSS_HEIGAN, DOOR_TYPE_ROOM, BOUNDARY_N}, + {181203, BOSS_HEIGAN, DOOR_TYPE_PASSAGE, BOUNDARY_E}, + {181241, BOSS_HEIGAN, DOOR_TYPE_PASSAGE, 0}, + {181241, BOSS_LOATHEB, DOOR_TYPE_ROOM, BOUNDARY_W}, + {181123, BOSS_PATCHWERK, DOOR_TYPE_PASSAGE, 0}, + {181123, BOSS_GROBBULUS, DOOR_TYPE_ROOM, 0}, + {181120, BOSS_GLUTH, DOOR_TYPE_PASSAGE, BOUNDARY_NW}, + {181121, BOSS_GLUTH, DOOR_TYPE_PASSAGE, 0}, + {181121, BOSS_THADDIUS, DOOR_TYPE_ROOM, 0}, + {181124, BOSS_RAZUVIOUS, DOOR_TYPE_PASSAGE, 0}, + {181124, BOSS_GOTHIK, DOOR_TYPE_ROOM, BOUNDARY_N}, + {181125, BOSS_GOTHIK, DOOR_TYPE_PASSAGE, BOUNDARY_S}, + {181119, BOSS_GOTHIK, DOOR_TYPE_PASSAGE, 0}, + {181119, BOSS_HORSEMEN, DOOR_TYPE_ROOM, BOUNDARY_NE}, + {181225, BOSS_SAPPHIRON, DOOR_TYPE_PASSAGE, BOUNDARY_W}, + {0, 0, DOOR_TYPE_ROOM, 0}, // EOF +}; + +const MinionData minionData[] = +{ + //{16573, BOSS_ANUBREKHAN}, there is no spawn point in db, so we do not add them here + {16506, BOSS_FAERLINA}, + {16803, BOSS_RAZUVIOUS}, + {16063, BOSS_HORSEMEN}, + {16064, BOSS_HORSEMEN}, + {16065, BOSS_HORSEMEN}, + {30549, BOSS_HORSEMEN}, + {0, 0,} +}; + +enum eEnums +{ + GO_HORSEMEN_CHEST_HERO = 193426, + GO_HORSEMEN_CHEST = 181366, //four horsemen event, DoRespawnGameObject() when event == DONE + GO_GOTHIK_GATE = 181170, + + SPELL_ERUPTION = 29371 +}; + +const float HeiganPos[2] = {2796, -3707}; +const float HeiganEruptionSlope[3] = +{ + (-3685 - HeiganPos[1]) /(2724 - HeiganPos[0]), + (-3647 - HeiganPos[1]) /(2749 - HeiganPos[0]), + (-3637 - HeiganPos[1]) /(2771 - HeiganPos[0]), +}; + +// 0 H x +// 1 ^ +// 2 | +// 3 y<--o +inline uint32 GetEruptionSection(float x, float y) +{ + y -= HeiganPos[1]; + if (y < 1.0f) + return 0; + + x -= HeiganPos[0]; + if (x > -1.0f) + return 3; + + float slope = y/x; + for (uint32 i = 0; i < 3; ++i) + if (slope > HeiganEruptionSlope[i]) + return i; + return 3; +} + +struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData +{ + instance_naxxramas(Map* pMap) : InstanceData(pMap) + , Sapphiron(NULL), pGothikGate(NULL), HorsemenChest(NULL), HorsemenNum(0) + { + SetBossNumber(MAX_BOSS_NUMBER); + LoadDoorData(doorData); + LoadMinionData(minionData); + } + + std::set<GameObject*> HeiganEruption[4]; + GameObject* pGothikGate, *HorsemenChest; + Creature* Sapphiron; + uint32 HorsemenNum; + uint64 uiFaerlina; + uint64 uiThane; + uint64 uiLady; + uint64 uiBaron; + uint64 uiSir; + + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case 15989: Sapphiron = add ? pCreature : NULL; return; + case 15953: uiFaerlina = pCreature->GetGUID(); return; + case 16064: uiThane = pCreature->GetGUID(); return; + case 16065: uiLady = pCreature->GetGUID(); return; + case 30549: uiBaron = pCreature->GetGUID(); return; + case 16063: uiSir = pCreature->GetGUID(); return; + } + + AddMinion(pCreature, add); + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + if (pGo->GetGOInfo()->displayId == 6785 || pGo->GetGOInfo()->displayId == 1287) + { + uint32 section = GetEruptionSection(pGo->GetPositionX(), pGo->GetPositionY()); + if (add) + HeiganEruption[section].insert(pGo); + else + HeiganEruption[section].erase(pGo); + return; + } + + switch(pGo->GetEntry()) + { + case GO_BIRTH: if (!add && Sapphiron) Sapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH); return; + case GO_GOTHIK_GATE: pGothikGate = add ? pGo : NULL; break; + case GO_HORSEMEN_CHEST: HorsemenChest = add ? pGo : NULL; break; + case GO_HORSEMEN_CHEST_HERO: HorsemenChest = add ? pGo : NULL; break; + } + + AddDoor(pGo, add); + } + + void SetData(uint32 id, uint32 value) + { + switch(id) + { + case DATA_HEIGAN_ERUPT: + HeiganErupt(value); + break; + case DATA_GOTHIK_GATE: + if (pGothikGate) + pGothikGate->SetGoState(GOState(value)); + break; + } + } + + uint64 GetData64(uint32 id) + { + if (id == DATA_FAERLINA) + return uiFaerlina; + if (id == DATA_THANE) + return uiThane; + if (id == DATA_LADY) + return uiLady; + if (id == DATA_BARON) + return uiBaron; + if (id == DATA_SIR) + return uiSir; + return 0; + } + + bool SetBossState(uint32 id, EncounterState state) + { + if (!InstanceData::SetBossState(id, state)) + return false; + + if (id == BOSS_HORSEMEN && state == DONE && HorsemenChest) + HorsemenChest->SetRespawnTime(HorsemenChest->GetRespawnDelay()); + + return true; + } + + void HeiganErupt(uint32 section) + { + for (uint32 i = 0; i < 4; ++i) + { + if (i == section) + continue; + + for (std::set<GameObject*>::iterator itr = HeiganEruption[i].begin(); itr != HeiganEruption[i].end(); ++itr) + { + (*itr)->SendCustomAnim(); + (*itr)->CastSpell(NULL, SPELL_ERUPTION); + } + } + } +}; + +bool AreaTrigger_at_naxxramas_frostwyrm_wing(Player* pPlayer, const AreaTriggerEntry *at) +{ + if (pPlayer->isGameMaster()) + return false; + + InstanceData *data = pPlayer->GetInstanceData(); + if (data) + for (uint32 i = BOSS_ANUBREKHAN; i < BOSS_SAPPHIRON; ++i) + if (data->GetBossState(i) != DONE) + return true; + + return false; +} + +InstanceData* GetInstanceData_instance_naxxramas(Map* pMap) +{ + return new instance_naxxramas(pMap); +} + +void AddSC_instance_naxxramas() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_naxxramas"; + newscript->GetInstanceData = &GetInstanceData_instance_naxxramas; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "at_naxxramas_frostwyrm_wing"; + newscript->pAreaTrigger = &AreaTrigger_at_naxxramas_frostwyrm_wing; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/naxxramas/naxxramas.h b/src/scripts/northrend/naxxramas/naxxramas.h new file mode 100644 index 00000000000..6f4dcae41a7 --- /dev/null +++ b/src/scripts/northrend/naxxramas/naxxramas.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DEF_NAXXRAMAS_H +#define DEF_NAXXRAMAS_H + +enum Encounter +{ + BOSS_ANUBREKHAN, + BOSS_FAERLINA, + BOSS_MAEXXNA, + BOSS_NOTH, + BOSS_HEIGAN, + BOSS_LOATHEB, + BOSS_PATCHWERK, + BOSS_GROBBULUS, + BOSS_GLUTH, + BOSS_THADDIUS, + BOSS_RAZUVIOUS, + BOSS_GOTHIK, + BOSS_HORSEMEN, + BOSS_SAPPHIRON, + BOSS_KELTHUZAD, + MAX_BOSS_NUMBER +}; + +enum Data +{ + DATA_HEIGAN_ERUPT, + DATA_GOTHIK_GATE, + DATA_SAPPHIRON_BIRTH, + DATA_FAERLINA, + DATA_THANE, + DATA_LADY, + DATA_BARON, + DATA_SIR +}; + +#define GO_BIRTH 181356 + +#endif + diff --git a/src/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp b/src/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp new file mode 100644 index 00000000000..2f9067bf294 --- /dev/null +++ b/src/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp @@ -0,0 +1,156 @@ +/* Script Data Start +SDName: Boss malygos +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" + +//Spells +#define SPELL_ARCANE_BREATH_N 56272 +#define SPELL_ARCANE_BREATH_H 60072 +#define SPELL_ARCANE_PULSE 57432 +#define SPELL_ARCANE_STORM_1 57459 +#define SPELL_ARCANE_STORM_2 61693 +#define SPELL_ARCANE_STORM_3 61694 +#define SPELL_STATIC_FIELD 57430 +#define SPELL_SURGE_OF_POWER_1 56505 +#define SPELL_SURGE_OF_POWER_2 57407 +#define SPELL_SURGE_OF_POWER_3 60936 +#define SPELL_VORTEX 56105 + +//Dragon "mounts" spells in Phase3 +//they use Rugelike energy +#define SPELL_DMOUNT_FLAME_SPIKE 56091 //maybe not accurate +#define SPELL_DMOUNT_ENGULF_IN_FLAMES 61621 +#define SPELL_DMOUNT_REVIVIFY 57090 +#define SPELL_DMOUNT_LIFE_BURST 57143 +#define SPELL_DMOUNT_FLAME_SHIELD 57108 +//#define SPELL_DMOUNT_UNKNOWN XYZ //Increases your drake's flight speed by 500%. + +//not in db +//Yell +//-->Other +#define SAY_ANTI_MAGIC_SHELL -1616000 +#define SAY_BREATH_ATTACK -1616001 +#define SAY_HIGH_DAMAGE_MODE -1616002 +#define SAY_MAGIC_BLAST -1616003 +//--> Generic Spells +#define SAY_GENERIC_SPELL_1 -1616004 +#define SAY_GENERIC_SPELL_2 -1616005 +#define SAY_GENERIC_SPELL_3 -1616006 +#define SAY_DEATH -1616007 +//--> Prefight +#define SAY_PREFIGHT_1 -1616008 +#define SAY_PREFIGHT_2 -1616009 +#define SAY_PREFIGHT_3 -1616010 +#define SAY_PREFIGHT_4 -1616011 +#define SAY_PREFIGHT_5 -1616012 +//--> Phase1 +#define SAY_PHASE1_AGGRO -1616013 +#define SAY_PHASE1_END -1616014 +#define SAY_PHASE1_SLAY_1 -1616015 +#define SAY_PHASE1_SLAY_2 -1616016 +#define SAY_PHASE1_SLAY_3 -1616017 + +//--> Phase2 at 50% HP, + +/*Malygos himself is not targetable during this phase, it will end when the adds he spawns are all killed. However, he does continue to play a part in the encounter. +During this phase he drops anti-magic zones onto the ground the raid MUST stand inside of, it reduces magical damage taken by 50%. They shrink over time, so it's important that your raid moves to each new one he drops. +Throughout the phase, he will deep breath doing ~4k damage per second, unless you are standing inside of the anti-magic zone. +The way the fight works during this phase is there are NPCs riding around on disks in the room. There are two types of mobs, Lords and Scions. +The Lords will move down onto the group, and need to be tanked (They will one-shot a non-tank). After they die, they drop a disk that a raid member can mount onto, which allows them to fly, to attack the Scions that do not come down to the ground. +It is recommended to let melee take the first disks, then ranged. As those mobs die, they also drop disks, which allows the rest of your dps to get onto them. +The Scions will continually cast Arcane Blast on random targets on the floor, which is mitigated by the anti-magic zones. While mounted on a disk, you will not take damage. +After all of the NPCs riding on the disks die, the players on the disks need to dismount as Phase 3 is about to begin.*/ + +//not in db +#define SAY_PHASE2_AGGRO -1616018 +#define SAY_PHASE2_END -1616019 +#define SAY_PHASE2_SLAY_1 -1616020 +#define SAY_PHASE2_SLAY_2 -1616021 +#define SAY_PHASE2_SLAY_3 -1616022 +//--> Phase3 Malygos destroys the floor, encounter continues on dragon "mounts" +#define SAY_PHASE3_INTRO -1616023 +#define SAY_PHASE3_AGGRO -1616024 +#define SAY_PHASE3_SLAY_1 -1616025 +#define SAY_PHASE3_SLAY_2 -1616026 +#define SAY_PHASE3_SLAY_3 -1616027 +#define SAY_PHASE3_BIG_ATTACK -1616028 + +struct TRINITY_DLL_DECL boss_malygosAI : public ScriptedAI +{ + boss_malygosAI(Creature *c) : ScriptedAI(c) {} + + uint32 phase, + enrage; + + void Reset() + { + //Source Deadly Boss Mod + enrage = 615000; //10 min + } + void EnterCombat(Unit* who) + { + if (phase == 1) + DoScriptText(SAY_PHASE1_AGGRO, m_creature); + if (phase == 2) + DoScriptText(SAY_PHASE1_AGGRO, m_creature); + if (phase == 3) + DoScriptText(SAY_PHASE1_AGGRO, m_creature); + } + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + phase =1; + //Return since we have no target + if (!UpdateVictim()) + return; + + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 50){ + phase = 2; + //spawn adds + //set malygos unatackable untill all adds spawned dead + //start phase3 + } + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + } + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + + if (phase ==1) + DoScriptText(RAND(SAY_PHASE1_SLAY_1,SAY_PHASE1_SLAY_2,SAY_PHASE1_SLAY_3), m_creature); + if (phase ==2) + DoScriptText(RAND(SAY_PHASE2_SLAY_1,SAY_PHASE2_SLAY_2,SAY_PHASE2_SLAY_3), m_creature); + if (phase ==3) + DoScriptText(RAND(SAY_PHASE3_SLAY_1,SAY_PHASE3_SLAY_2,SAY_PHASE3_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_malygos(Creature* pCreature) +{ + return new boss_malygosAI (pCreature); +} + +void AddSC_boss_malygos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_malygos"; + newscript->GetAI = &GetAI_boss_malygos; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h b/src/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h new file mode 100644 index 00000000000..caa82a92e95 --- /dev/null +++ b/src/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h @@ -0,0 +1,4 @@ +#ifndef DEF_EYE_OF_ETERNITY_H +#define DEF_EYE_OF_ETERNITY_H + +#endif diff --git a/src/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp b/src/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp new file mode 100644 index 00000000000..79a38899789 --- /dev/null +++ b/src/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp @@ -0,0 +1,21 @@ +#include "ScriptedPch.h" +#include "eye_of_eternity.h" + +struct TRINITY_DLL_DECL instance_eye_of_eternity : public ScriptedInstance +{ + instance_eye_of_eternity(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; +}; + +InstanceData* GetInstanceData_instance_eye_of_eternity(Map* pMap) +{ + return new instance_eye_of_eternity(pMap); +} + +void AddSC_instance_eye_of_eternity() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_eye_of_eternity"; + newscript->GetInstanceData = &GetInstanceData_instance_eye_of_eternity; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/boss_anomalus.cpp b/src/scripts/northrend/nexus/nexus/boss_anomalus.cpp new file mode 100644 index 00000000000..236dd3d1067 --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/boss_anomalus.cpp @@ -0,0 +1,307 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Anomalus +SD%Complete: +SDComment: +SDCategory: The Nexus, The Nexus +EndScriptData */ + +#include "ScriptedPch.h" +#include "nexus.h" + +bool DeadChaoticRift; // needed for achievement: Chaos Theory(2037) + +enum eEnums +{ + ACHIEVEMENT_CHAOS_THEORY = 2037, + + //Spells + SPELL_SPARK_N = 47751, + SPELL_SPARK_H = 57062, + SPELL_RIFT_SHIELD = 47748, + SPELL_CHARGE_RIFT = 47747, //Works wrong (affect players, not rifts) + SPELL_CREATE_RIFT = 47743, //Don't work, using WA + SPELL_ARCANE_ATTRACTION = 57063, //No idea, when it's used + + MOB_CRAZED_MANA_WRAITH = 26746, + MOB_CHAOTIC_RIFT = 26918, + SPELL_CHAOTIC_ENERGY_BURST = 47688, + SPELL_CHARGED_CHAOTIC_ENERGY_BURST = 47737, + SPELL_ARCANEFORM = 48019, //Chaotic Rift visual + + //Yell + SAY_AGGRO = -1576010, + SAY_DEATH = -1576011, + SAY_RIFT = -1576012, + SAY_SHIELD = -1576013 +}; + +float RiftLocation[6][3]= +{ + {652.64, -273.70, -8.75}, + {634.45, -265.94, -8.44}, + {620.73, -281.17, -9.02}, + {626.10, -304.67, -9.44}, + {639.87, -314.11, -9.49}, + {651.72, -297.44, -9.37} +}; + +struct TRINITY_DLL_DECL boss_anomalusAI : public ScriptedAI +{ + boss_anomalusAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint8 Phase; + uint32 SPELL_SPARK_Timer; + uint32 SPELL_CREATE_RIFT_Timer; + uint64 ChaoticRiftGUID; + + void Reset() + { + Phase = 0; + SPELL_SPARK_Timer = 5000; + SPELL_CREATE_RIFT_Timer = 25000; + ChaoticRiftGUID = 0; + + DeadChaoticRift = false; + + if (pInstance) + pInstance->SetData(DATA_ANOMALUS_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_ANOMALUS_EVENT, IN_PROGRESS); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (IsHeroic() && !DeadChaoticRift) + { + AchievementEntry const *AchievChaosTheory = GetAchievementStore()->LookupEntry(ACHIEVEMENT_CHAOS_THEORY); + if (AchievChaosTheory) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievChaosTheory); + } + } + } + + if (pInstance) + pInstance->SetData(DATA_ANOMALUS_EVENT, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (m_creature->GetDistance(m_creature->GetHomePosition()) > 60.0f) + { + //Not blizzlike, hack to avoid an exploit + EnterEvadeMode(); + return; + } + + if (m_creature->HasAura(SPELL_RIFT_SHIELD)) + { + if (ChaoticRiftGUID) + { + Unit* Rift = Unit::GetUnit((*m_creature), ChaoticRiftGUID); + if (Rift && Rift->isDead()) + { + m_creature->RemoveAurasDueToSpell(SPELL_RIFT_SHIELD); + ChaoticRiftGUID = 0; + } + return; + } + } else + ChaoticRiftGUID = 0; + + if ((Phase == 0) && (m_creature->GetHealth() < m_creature->GetMaxHealth() * 0.75)) + { + Phase = 1; + DoScriptText(SAY_SHIELD, m_creature); + DoCast(m_creature, SPELL_RIFT_SHIELD); + + int tmp = rand()%(2); + Creature* Rift = m_creature->SummonCreature(MOB_CHAOTIC_RIFT, RiftLocation[tmp][0], RiftLocation[tmp][1], RiftLocation[tmp][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + if (Rift) + { + //DoCast(Rift, SPELL_CHARGE_RIFT); + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + Rift->AI()->AttackStart(pTarget); + ChaoticRiftGUID = Rift->GetGUID(); + DoScriptText(SAY_RIFT , m_creature); + } + } + + if ((Phase == 1) && (m_creature->GetHealth() < m_creature->GetMaxHealth() * 0.50)) + { + Phase = 2; + DoScriptText(SAY_SHIELD , m_creature); + DoCast(m_creature, SPELL_RIFT_SHIELD); + + int tmp = rand()%(2); + Creature* Rift = m_creature->SummonCreature(MOB_CHAOTIC_RIFT, RiftLocation[tmp][0], RiftLocation[tmp][1], RiftLocation[tmp][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + if (Rift) + { + //DoCast(Rift, SPELL_CHARGE_RIFT); + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + Rift->AI()->AttackStart(pTarget); + ChaoticRiftGUID = Rift->GetGUID(); + DoScriptText(SAY_RIFT , m_creature); + } + } + + if ((Phase == 2) && (m_creature->GetHealth() < m_creature->GetMaxHealth() * 0.25)) + { + Phase = 3; + DoScriptText(SAY_SHIELD , m_creature); + DoCast(m_creature, SPELL_RIFT_SHIELD); + + int tmp = rand()%(2); + Creature* Rift = m_creature->SummonCreature(MOB_CHAOTIC_RIFT, RiftLocation[tmp][0], RiftLocation[tmp][1], RiftLocation[tmp][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + if (Rift) + { + //DoCast(Rift, SPELL_CHARGE_RIFT); + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + Rift->AI()->AttackStart(pTarget); + ChaoticRiftGUID = Rift->GetGUID(); + DoScriptText(SAY_RIFT , m_creature); + } + } + + if (SPELL_SPARK_Timer <= diff) + { + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, DUNGEON_MODE(SPELL_SPARK_N, SPELL_SPARK_H)); + SPELL_SPARK_Timer = 5000; + } else SPELL_SPARK_Timer -=diff; + + if (SPELL_CREATE_RIFT_Timer <= diff) + { + DoScriptText(SAY_RIFT , m_creature); + + int tmp = rand()%(2); + Creature* Rift = m_creature->SummonCreature(MOB_CHAOTIC_RIFT, RiftLocation[tmp][0], RiftLocation[tmp][1], RiftLocation[tmp][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + if (Rift) + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + Rift->AI()->AttackStart(pTarget); + SPELL_CREATE_RIFT_Timer = 25000; + } else SPELL_CREATE_RIFT_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_anomalus(Creature* pCreature) +{ + return new boss_anomalusAI (pCreature); +} + +struct TRINITY_DLL_DECL mob_chaotic_riftAI : public Scripted_NoMovementAI +{ + mob_chaotic_riftAI(Creature *c) : Scripted_NoMovementAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 SPELL_CHAOTIC_ENERGY_BURST_Timer; + uint32 SUMMON_CRAZED_MANA_WRAITH_Timer; + + void Reset() + { + SPELL_CHAOTIC_ENERGY_BURST_Timer = 1000; + SUMMON_CRAZED_MANA_WRAITH_Timer = 5000; + m_creature->SetDisplayId(25206); //For some reason in DB models for ally and horde are different. + //Model for ally (1126) does not show auras. Horde model works perfect. + //Set model to horde number + DoCast(m_creature, SPELL_ARCANEFORM, false); + } + + void JustDied(Unit *killer) + { + DeadChaoticRift = true; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (SPELL_CHAOTIC_ENERGY_BURST_Timer <= diff) + { + Unit* Anomalus = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_ANOMALUS) : 0); + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + if (Anomalus && Anomalus->HasAura(SPELL_RIFT_SHIELD)) + DoCast(pTarget, SPELL_CHARGED_CHAOTIC_ENERGY_BURST); + else + DoCast(pTarget, SPELL_CHAOTIC_ENERGY_BURST); + SPELL_CHAOTIC_ENERGY_BURST_Timer = 1000; + } else SPELL_CHAOTIC_ENERGY_BURST_Timer -=diff; + + if (SUMMON_CRAZED_MANA_WRAITH_Timer <= diff) + { + Creature* Wraith = m_creature->SummonCreature(MOB_CRAZED_MANA_WRAITH, m_creature->GetPositionX()+1, m_creature->GetPositionY()+1, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + if (Wraith) + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + Wraith->AI()->AttackStart(pTarget); + Unit* Anomalus = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_ANOMALUS) : 0); + if (Anomalus && Anomalus->HasAura(SPELL_RIFT_SHIELD)) + SUMMON_CRAZED_MANA_WRAITH_Timer = 5000; + else + SUMMON_CRAZED_MANA_WRAITH_Timer = 10000; + } else SUMMON_CRAZED_MANA_WRAITH_Timer -=diff; + } +}; + +CreatureAI* GetAI_mob_chaotic_rift(Creature* pCreature) +{ + return new mob_chaotic_riftAI (pCreature); +} + +void AddSC_boss_anomalus() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_anomalus"; + newscript->GetAI = &GetAI_boss_anomalus; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_chaotic_rift"; + newscript->GetAI = &GetAI_mob_chaotic_rift; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/boss_keristrasza.cpp b/src/scripts/northrend/nexus/nexus/boss_keristrasza.cpp new file mode 100644 index 00000000000..c0fd39e89d3 --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/boss_keristrasza.cpp @@ -0,0 +1,258 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Keristrasza +SD%Complete: +SDComment: +SDCategory: The Nexus, The Nexus +EndScriptData */ + +#include "ScriptedPch.h" +#include "nexus.h" + +enum eEnums +{ + CONTAINMENT_SPHERES = 3, + + ACHIEVEMENT_INTENSE_COLD = 2036, + + //Spells + SPELL_FROZEN_PRISON = 47854, + SPELL_TAIL_SWEEP = 50155, + SPELL_CRYSTAL_CHAINS = 50997, + SPELL_ENRAGE = 8599, + SPELL_CRYSTALFIRE_BREATH_N = 48096, + SPELL_CRYSTALFIRE_BREATH_H = 57091, + SPELL_CRYSTALIZE = 48179, + SPELL_INTENSE_COLD = 48094, + SPELL_INTENSE_COLD_TRIGGERED = 48095, + + //Yell + SAY_AGGRO = -1576040, + SAY_SLAY = -1576041, + SAY_ENRAGE = -1576042, + SAY_DEATH = -1576043, + SAY_CRYSTAL_NOVA = -1576044 +}; + +struct TRINITY_DLL_DECL boss_keristraszaAI : public ScriptedAI +{ + boss_keristraszaAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 CRYSTALFIRE_BREATH_Timer; + uint32 CRYSTAL_CHAINS_CRYSTALIZE_Timer; + uint32 TAIL_SWEEP_Timer; + bool Enrage; + + uint64 ContainmentSphereGUIDs[CONTAINMENT_SPHERES]; + + uint32 CheckIntenseColdTimer; + bool MoreThanTwoIntenseCold; // needed for achievement: Intense Cold(2036) + + void Reset() + { + CRYSTALFIRE_BREATH_Timer = 14000; + CRYSTAL_CHAINS_CRYSTALIZE_Timer = DUNGEON_MODE(30000,11000); + TAIL_SWEEP_Timer = 5000; + Enrage = false; + + CheckIntenseColdTimer = 2000; + MoreThanTwoIntenseCold = false; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + + RemovePrison(CheckContainmentSpheres()); + + if (pInstance) + pInstance->SetData(DATA_KERISTRASZA_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + DoCastAOE(SPELL_INTENSE_COLD); + + if (pInstance) + pInstance->SetData(DATA_KERISTRASZA_EVENT, IN_PROGRESS); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (IsHeroic() && !MoreThanTwoIntenseCold) + { + AchievementEntry const *AchievIntenseCold = GetAchievementStore()->LookupEntry(ACHIEVEMENT_INTENSE_COLD); + if (AchievIntenseCold) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievIntenseCold); + } + } + } + + if (pInstance) + pInstance->SetData(DATA_KERISTRASZA_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(SAY_SLAY, m_creature); + } + + bool CheckContainmentSpheres(bool remove_prison = false) + { + if(!pInstance) + return false; + + ContainmentSphereGUIDs[0] = pInstance->GetData64(ANOMALUS_CONTAINMET_SPHERE); + ContainmentSphereGUIDs[1] = pInstance->GetData64(ORMOROKS_CONTAINMET_SPHERE); + ContainmentSphereGUIDs[2] = pInstance->GetData64(TELESTRAS_CONTAINMET_SPHERE); + + GameObject *ContainmentSpheres[CONTAINMENT_SPHERES]; + + for (uint8 i = 0; i < CONTAINMENT_SPHERES; ++i) + { + ContainmentSpheres[i] = pInstance->instance->GetGameObject(ContainmentSphereGUIDs[i]); + if (!ContainmentSpheres[i]) + return false; + if (ContainmentSpheres[i]->GetGoState() != GO_STATE_ACTIVE) + return false; + } + if (remove_prison) + RemovePrison(true); + return true; + } + + void RemovePrison(bool remove) + { + if (remove) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (m_creature->HasAura(SPELL_FROZEN_PRISON)) + m_creature->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON); + } + else + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(m_creature, SPELL_FROZEN_PRISON, false); + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (CheckIntenseColdTimer < diff && !MoreThanTwoIntenseCold) + { + std::list<HostilReference*> ThreatList = m_creature->getThreatManager().getThreatList(); + for (std::list<HostilReference*>::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); itr++) + { + Unit *pTarget = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + if (!pTarget || pTarget->GetTypeId() != TYPEID_PLAYER) + continue; + + Aura *AuraIntenseCold = pTarget->GetAura(SPELL_INTENSE_COLD_TRIGGERED); + if (AuraIntenseCold && AuraIntenseCold->GetStackAmount() > 2) + { + MoreThanTwoIntenseCold = true; + break; + } + } + CheckIntenseColdTimer = 2000; + } else CheckIntenseColdTimer -= diff; + + if (!Enrage && (m_creature->GetHealth() < m_creature->GetMaxHealth() * 0.25)) + { + DoScriptText(SAY_ENRAGE, m_creature); + DoCast(m_creature, SPELL_ENRAGE); + Enrage = true; + } + + if (CRYSTALFIRE_BREATH_Timer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_CRYSTALFIRE_BREATH_N, SPELL_CRYSTALFIRE_BREATH_H)); + CRYSTALFIRE_BREATH_Timer = 14000; + } else CRYSTALFIRE_BREATH_Timer -=diff; + + if (TAIL_SWEEP_Timer <= diff) + { + DoCast(m_creature, SPELL_TAIL_SWEEP); + TAIL_SWEEP_Timer = 5000; + } else TAIL_SWEEP_Timer -=diff; + + if (CRYSTAL_CHAINS_CRYSTALIZE_Timer <= diff) + { + DoScriptText(SAY_CRYSTAL_NOVA, m_creature); + if (IsHeroic()) + DoCast(m_creature, SPELL_CRYSTALIZE); + else if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_CRYSTAL_CHAINS); + CRYSTAL_CHAINS_CRYSTALIZE_Timer = DUNGEON_MODE(30000,11000); + } else CRYSTAL_CHAINS_CRYSTALIZE_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_keristrasza(Creature* pCreature) +{ + return new boss_keristraszaAI (pCreature); +} + +bool GOHello_containment_sphere(Player *pPlayer, GameObject *pGO) +{ + ScriptedInstance *pInstance = pGO->GetInstanceData(); + + Creature *Keristrasza = Unit::GetCreature(*pGO, pInstance ? pInstance->GetData64(DATA_KERISTRASZA) : 0); + if (Keristrasza && Keristrasza->isAlive()) + { + // maybe these are hacks :( + pGO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGO->SetGoState(GO_STATE_ACTIVE); + + CAST_AI(boss_keristraszaAI, Keristrasza->AI())->CheckContainmentSpheres(true); + } + return true; +} + +void AddSC_boss_keristrasza() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_keristrasza"; + newscript->GetAI = &GetAI_boss_keristrasza; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "containment_sphere"; + newscript->pGOHello = &GOHello_containment_sphere; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/boss_magus_telestra.cpp b/src/scripts/northrend/nexus/nexus/boss_magus_telestra.cpp new file mode 100644 index 00000000000..f404ec234c7 --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/boss_magus_telestra.cpp @@ -0,0 +1,353 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Magus_Telestra +SD%Complete: +SDComment: +SDCategory: The Nexus, The Nexus +EndScriptData */ + +#include "ScriptedPch.h" +#include "nexus.h" + +enum eEnums +{ +//Spells + SPELL_ICE_NOVA_N = 47772, + SPELL_ICE_NOVA_H = 56935, + SPELL_FIREBOMB_N = 47773, + SPELL_FIREBOMB_H = 56934, + SPELL_GRAVITY_WELL = 47756, + SPELL_TELESTRA_BACK = 47714, + +//At 50% HP - 3 clones, Frost, Fire, Arcane (and in 10% HP in Heroic) + MOB_FIRE_MAGUS = 26928, + MOB_FROST_MAGUS = 26930, + MOB_ARCANE_MAGUS = 26929, + + SPELL_FIRE_MAGUS_VISUAL = 47705, + SPELL_FROST_MAGUS_VISUAL = 47706, + SPELL_ARCANE_MAGUS_VISUAL = 47704, + +//Yell + SAY_AGGRO = -1576000, + SAY_KILL = -1576001, + SAY_DEATH = -1576002, + SAY_MERGE = -1576003, + SAY_SPLIT_1 = -1576004, + SAY_SPLIT_2 = -1576005, + +//Achievement + ACHIEV_SPLIT_PERSONALITY = 2150, + ACHIEV_TIMER = 5 * 1000 +}; + +float CenterOfRoom[1][4] = +{ + {504.80, 89.07, -16.12, 6.27} +}; + +struct TRINITY_DLL_DECL boss_magus_telestraAI : public ScriptedAI +{ + boss_magus_telestraAI(Creature* c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint64 FireMagusGUID; + uint64 FrostMagusGUID; + uint64 ArcaneMagusGUID; + bool FireMagusDead; + bool FrostMagusDead; + bool ArcaneMagusDead; + + uint32 AppearDelay_Timer; + bool AppearDelay; + + uint8 Phase; + + uint32 SPELL_ICE_NOVA_Timer; + uint32 SPELL_FIREBOMB_Timer; + uint32 SPELL_GRAVITY_WELL_Timer; + uint32 Cooldown; + + bool AchievementTimerRunning; + uint8 AchievementProgress; + uint32 AchievementTimer; + + void Reset() + { + Phase = 0; + //These times are probably wrong + SPELL_ICE_NOVA_Timer = 7000; + SPELL_FIREBOMB_Timer = 0; + SPELL_GRAVITY_WELL_Timer = 15000; + Cooldown = 0; + + FireMagusGUID = 0; + FrostMagusGUID = 0; + ArcaneMagusGUID = 0; + + AchievementProgress = 0; + AchievementTimer = 0; + AchievementTimerRunning = false; + + AppearDelay = false; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetVisibility(VISIBILITY_ON); + + if (pInstance) + pInstance->SetData(DATA_MAGUS_TELESTRA_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_MAGUS_TELESTRA_EVENT, IN_PROGRESS); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (IsHeroic() && AchievementProgress == 2) + { + AchievementEntry const *AchievSplitPersonality = GetAchievementStore()->LookupEntry(ACHIEV_SPLIT_PERSONALITY); + if (AchievSplitPersonality) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievSplitPersonality); + } + } + } + + if (pInstance) + pInstance->SetData(DATA_MAGUS_TELESTRA_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(SAY_KILL, m_creature); + } + + uint64 SplitPersonality(uint32 entry) + { + Creature* Summoned = m_creature->SummonCreature(entry, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + if (Summoned) + { + switch (entry) + { + case MOB_FIRE_MAGUS: + { + Summoned->CastSpell(Summoned, SPELL_FIRE_MAGUS_VISUAL, false); + break; + } + case MOB_FROST_MAGUS: + { + Summoned->CastSpell(Summoned, SPELL_FROST_MAGUS_VISUAL, false); + break; + } + case MOB_ARCANE_MAGUS: + { + Summoned->CastSpell(Summoned, SPELL_ARCANE_MAGUS_VISUAL, false); + break; + } + } + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + Summoned->AI()->AttackStart(pTarget); + return Summoned->GetGUID(); + } + return 0; + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + { + return; + } + + if (AppearDelay) + { + m_creature->StopMoving(); + m_creature->AttackStop(); + if (AppearDelay_Timer <= diff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + AppearDelay = false; + } else AppearDelay_Timer -= diff; + return; + } + + if ((Phase == 1)||(Phase == 3)) + { + Unit* FireMagus; + Unit* FrostMagus; + Unit* ArcaneMagus; + if (FireMagusGUID) + FireMagus = Unit::GetUnit((*m_creature), FireMagusGUID); + if (FrostMagusGUID) + FrostMagus = Unit::GetUnit((*m_creature), FrostMagusGUID); + if (ArcaneMagusGUID) + ArcaneMagus = Unit::GetUnit((*m_creature), ArcaneMagusGUID); + if (FireMagus && FireMagus->isDead()) + { + FireMagusDead = true; + if (!AchievementTimerRunning) + AchievementTimerRunning = true; + } + if (FrostMagus && FrostMagus->isDead()) + { + FrostMagusDead = true; + if (!AchievementTimerRunning) + AchievementTimerRunning = true; + } + if (ArcaneMagus && ArcaneMagus->isDead()) + { + ArcaneMagusDead = true; + if (!AchievementTimerRunning) + AchievementTimerRunning = true; + } + if (AchievementTimerRunning) + AchievementTimer += diff; + if (FireMagusDead && FrostMagusDead && ArcaneMagusDead) + { + if (AchievementTimer <= ACHIEV_TIMER) + AchievementProgress +=1; + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMap()->CreatureRelocation(m_creature, CenterOfRoom[0][0], CenterOfRoom[0][1], CenterOfRoom[0][2], CenterOfRoom[0][3]); + DoCast(m_creature, SPELL_TELESTRA_BACK); + m_creature->SetVisibility(VISIBILITY_ON); + if (Phase == 1) + Phase = 2; + if (Phase == 3) + Phase = 4; + FireMagusGUID = 0; + FrostMagusGUID = 0; + ArcaneMagusGUID = 0; + AppearDelay = true; + AppearDelay_Timer = 4000; + DoScriptText(SAY_MERGE, m_creature); + AchievementTimerRunning = false; + AchievementTimer = 0; + }else + return; + } + + if ((Phase == 0) && (m_creature->GetHealth() <= (m_creature->GetMaxHealth() * 0.5))) + { + Phase = 1; + m_creature->CastStop(); + m_creature->RemoveAllAuras(); + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + FireMagusGUID = SplitPersonality(MOB_FIRE_MAGUS); + FrostMagusGUID = SplitPersonality(MOB_FROST_MAGUS); + ArcaneMagusGUID = SplitPersonality(MOB_ARCANE_MAGUS); + FireMagusDead = false; + FrostMagusDead = false; + ArcaneMagusDead = false; + DoScriptText(RAND(SAY_SPLIT_1,SAY_SPLIT_2), m_creature); + return; + } + + if (IsHeroic() && (Phase == 2) && (m_creature->GetHealth() <= (m_creature->GetMaxHealth() * 0.1))) + { + Phase = 3; + m_creature->CastStop(); + m_creature->RemoveAllAuras(); + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + FireMagusGUID = SplitPersonality(MOB_FIRE_MAGUS); + FrostMagusGUID = SplitPersonality(MOB_FROST_MAGUS); + ArcaneMagusGUID = SplitPersonality(MOB_ARCANE_MAGUS); + FireMagusDead = false; + FrostMagusDead = false; + ArcaneMagusDead = false; + DoScriptText(RAND(SAY_SPLIT_1,SAY_SPLIT_2), m_creature); + return; + } + + if (Cooldown) + { + if (Cooldown <= diff) + Cooldown = 0; + else + { + Cooldown -= diff; + return; + } + } + + if (SPELL_ICE_NOVA_Timer <= diff) + { + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(pTarget, DUNGEON_MODE(SPELL_ICE_NOVA_N, SPELL_ICE_NOVA_H)); + Cooldown = 1500; + } + SPELL_ICE_NOVA_Timer = 15000; + } else SPELL_ICE_NOVA_Timer -=diff; + + if (SPELL_GRAVITY_WELL_Timer <= diff) + { + if (Unit *pTarget = m_creature->getVictim()) + { + DoCast(pTarget, SPELL_GRAVITY_WELL); + Cooldown = 6000; + } + SPELL_GRAVITY_WELL_Timer = 15000; + } else SPELL_GRAVITY_WELL_Timer -=diff; + + if (SPELL_FIREBOMB_Timer <= diff) + { + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(pTarget, DUNGEON_MODE(SPELL_FIREBOMB_N, SPELL_FIREBOMB_H)); + Cooldown = 2000; + } + SPELL_FIREBOMB_Timer = 2000; + } else SPELL_FIREBOMB_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_magus_telestra(Creature* pCreature) +{ + return new boss_magus_telestraAI (pCreature); +} + +void AddSC_boss_magus_telestra() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_magus_telestra"; + newscript->GetAI = &GetAI_boss_magus_telestra; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/boss_ormorok.cpp b/src/scripts/northrend/nexus/nexus/boss_ormorok.cpp new file mode 100644 index 00000000000..66c9edb1eec --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/boss_ormorok.cpp @@ -0,0 +1,307 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Ormorok +SD%Complete: +SDComment: +SDCategory: The Nexus, The Nexus +EndScriptData */ + +#include "ScriptedPch.h" +#include "nexus.h" + +enum eEnums +{ +//Spells + SPELL_CRYSTAL_SPIKES_N = 47958, //Don't work, using walkaround + SPELL_CRYSTAL_SPIKES_H = 57082, //Don't work, using walkaround +//Walkaround for spells Crystal Spikes ----------------- + SPELL_CRYSTALL_SPIKE_DAMAGE_N = 47944, + SPELL_CRYSTALL_SPIKE_DAMAGE_H = 57067, + SPELL_CRYSTAL_SPIKE_PREVISUAL = 50442, + MOB_CRYSTAL_SPIKE = 27099, +//------------------------------------------------------ + SPELL_SPELL_REFLECTION = 47981, + SPELL_TRAMPLE_N = 48016, + SPELL_TRAMPLE_H = 57066, + SPELL_FRENZY = 48017, + SPELL_SUMMON_CRYSTALLINE_TANGLER = 61564, //summons npc 32665 + MOB_CRYSTALLINE_TANGLER = 32665, + SPELL_ROOTS = 28858, //proper spell id is unknown + +//Yell + SAY_AGGRO = -1576020, + SAY_DEATH = -1576021, + SAY_REFLECT = -1576022, + SAY_CRYSTAL_SPIKES = -1576023, + SAY_KILL = -1576024 +}; + +#define SPIKE_DISTANCE 5.0f + +struct TRINITY_DLL_DECL boss_ormorokAI : public ScriptedAI +{ + boss_ormorokAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + bool Frenzy; + bool CrystalSpikes; + uint8 CrystalSpikes_Count; + float BaseX; + float BaseY; + float BaseZ; + float BaseO; + float SpikeXY[4][2]; + + uint32 SPELL_CRYSTAL_SPIKES_Timer; + uint32 CRYSTAL_SPIKES_Timer; + uint32 SPELL_TRAMPLE_Timer; + uint32 SPELL_FRENZY_Timer; + uint32 SPELL_SPELL_REFLECTION_Timer; + uint32 SPELL_SUMMON_CRYSTALLINE_TANGLER_Timer; + + void Reset() + { + SPELL_CRYSTAL_SPIKES_Timer = 12000; + SPELL_TRAMPLE_Timer = 10000; + SPELL_SPELL_REFLECTION_Timer = 30000; + SPELL_SUMMON_CRYSTALLINE_TANGLER_Timer = 17000; + Frenzy = false; + CrystalSpikes = false; + + if (pInstance) + pInstance->SetData(DATA_ORMOROK_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_ORMOROK_EVENT, IN_PROGRESS); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_ORMOROK_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(SAY_KILL, m_creature); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + { + return; + } + if (CrystalSpikes) + if (CRYSTAL_SPIKES_Timer <= diff) + { + SpikeXY[0][0] = BaseX+(SPIKE_DISTANCE*CrystalSpikes_Count*cos(BaseO)); + SpikeXY[0][1] = BaseY+(SPIKE_DISTANCE*CrystalSpikes_Count*sin(BaseO)); + SpikeXY[1][0] = BaseX-(SPIKE_DISTANCE*CrystalSpikes_Count*cos(BaseO)); + SpikeXY[1][1] = BaseY-(SPIKE_DISTANCE*CrystalSpikes_Count*sin(BaseO)); + SpikeXY[2][0] = BaseX+(SPIKE_DISTANCE*CrystalSpikes_Count*cos(BaseO-(M_PI/2))); + SpikeXY[2][1] = BaseY+(SPIKE_DISTANCE*CrystalSpikes_Count*sin(BaseO-(M_PI/2))); + SpikeXY[3][0] = BaseX-(SPIKE_DISTANCE*CrystalSpikes_Count*cos(BaseO-(M_PI/2))); + SpikeXY[3][1] = BaseY-(SPIKE_DISTANCE*CrystalSpikes_Count*sin(BaseO-(M_PI/2))); + for (uint8 i = 0; i < 4; ++i) + Creature* Spike = m_creature->SummonCreature(MOB_CRYSTAL_SPIKE, SpikeXY[i][0], SpikeXY[i][1], BaseZ, 0, TEMPSUMMON_TIMED_DESPAWN, 7000); + if (++CrystalSpikes_Count >= 13) + CrystalSpikes = false; + CRYSTAL_SPIKES_Timer = 200; + } else CRYSTAL_SPIKES_Timer -= diff; + + if (!Frenzy && (m_creature->GetHealth() < m_creature->GetMaxHealth() * 0.25)) + { + DoCast(m_creature, SPELL_FRENZY); + Frenzy = true; + } + + if (SPELL_TRAMPLE_Timer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_TRAMPLE_N, SPELL_TRAMPLE_H)); + SPELL_TRAMPLE_Timer = 10000; + } else SPELL_TRAMPLE_Timer -= diff; + + if (SPELL_SPELL_REFLECTION_Timer <= diff) + { + DoScriptText(SAY_REFLECT, m_creature); + DoCast(m_creature, SPELL_SPELL_REFLECTION); + SPELL_SPELL_REFLECTION_Timer = 30000; + } else SPELL_SPELL_REFLECTION_Timer -= diff; + + if (SPELL_CRYSTAL_SPIKES_Timer <= diff) + { + DoScriptText(SAY_CRYSTAL_SPIKES, m_creature); + CrystalSpikes = true; + CrystalSpikes_Count = 1; + CRYSTAL_SPIKES_Timer = 0; + BaseX = m_creature->GetPositionX(); + BaseY = m_creature->GetPositionY(); + BaseZ = m_creature->GetPositionZ(); + BaseO = m_creature->GetOrientation(); + SPELL_CRYSTAL_SPIKES_Timer = 20000; + } else SPELL_CRYSTAL_SPIKES_Timer -=diff; + + if (IsHeroic() && (SPELL_SUMMON_CRYSTALLINE_TANGLER_Timer <= diff)) + { + Creature* Crystalline_Tangler = m_creature->SummonCreature(MOB_CRYSTALLINE_TANGLER, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + if (Crystalline_Tangler) + { + Unit *pTarget = NULL; + uint8 Healer = 0; + for (uint8 j = 1; j<=4; j++) + { + switch (j) + { + case 1: Healer = CLASS_PRIEST; break; + case 2: Healer = CLASS_PALADIN; break; + case 3: Healer = CLASS_DRUID; break; + case 4: Healer = CLASS_SHAMAN; break; + } + std::list<HostilReference*>::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Unit* pTemp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); + if (pTemp && pTemp->GetTypeId() == TYPEID_PLAYER && pTemp->getClass() == Healer) + { + pTarget = pTemp; + break; + } + } + if (pTarget) + break; + } + if (!pTarget) + pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (pTarget) + { + Crystalline_Tangler->AI()->AttackStart(pTarget); + Crystalline_Tangler->getThreatManager().addThreat(pTarget, 1000000000.0f); + } + } + SPELL_SUMMON_CRYSTALLINE_TANGLER_Timer = 17000; + } else SPELL_SUMMON_CRYSTALLINE_TANGLER_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL mob_crystal_spikeAI : public Scripted_NoMovementAI +{ + mob_crystal_spikeAI(Creature *c) : Scripted_NoMovementAI(c) + { + } + + uint32 SPELL_CRYSTALL_SPIKE_DAMAGE_Timer; + uint32 SPELL_CRYSTAL_SPIKE_PREVISUAL_Timer; + + void Reset() + { + SPELL_CRYSTALL_SPIKE_DAMAGE_Timer = 3700; + SPELL_CRYSTAL_SPIKE_PREVISUAL_Timer = 1000; + m_creature->SetLevel(80); // + m_creature->setFaction(16); //Walkaround to be independent from data in DB + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // + } + + void UpdateAI(const uint32 diff) + { + if (SPELL_CRYSTAL_SPIKE_PREVISUAL_Timer <= diff) + { + DoCast(m_creature, SPELL_CRYSTAL_SPIKE_PREVISUAL); + SPELL_CRYSTAL_SPIKE_PREVISUAL_Timer = 10000; + } else SPELL_CRYSTAL_SPIKE_PREVISUAL_Timer -=diff; + + if (SPELL_CRYSTALL_SPIKE_DAMAGE_Timer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_CRYSTALL_SPIKE_DAMAGE_N, SPELL_CRYSTALL_SPIKE_DAMAGE_H)); + SPELL_CRYSTALL_SPIKE_DAMAGE_Timer = 10000; + } else SPELL_CRYSTALL_SPIKE_DAMAGE_Timer -=diff; + } +}; + +struct TRINITY_DLL_DECL mob_crystalline_tanglerAI : public ScriptedAI +{ + mob_crystalline_tanglerAI(Creature *c) : ScriptedAI(c) {} + + uint32 SPELL_ROOTS_Timer; + + void Reset() + { + SPELL_ROOTS_Timer = 1000; + } + + void UpdateAI(const uint32 diff) + { + if (SPELL_ROOTS_Timer <= diff) + { + if (m_creature->IsWithinDist(m_creature->getVictim(), 5.0f, false)) + { + DoCast(m_creature->getVictim(), SPELL_ROOTS); + SPELL_ROOTS_Timer = 15000; + } + } else SPELL_ROOTS_Timer -=diff; + } +}; + +CreatureAI* GetAI_mob_crystal_spike(Creature* pCreature) +{ + return new mob_crystal_spikeAI (pCreature); +} + +CreatureAI* GetAI_mob_crystalline_tangler(Creature* pCreature) +{ + return new mob_crystalline_tanglerAI (pCreature); +} + +CreatureAI* GetAI_boss_ormorok(Creature* pCreature) +{ + return new boss_ormorokAI (pCreature); +} + +void AddSC_boss_ormorok() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_ormorok"; + newscript->GetAI = &GetAI_boss_ormorok; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_crystal_spike"; + newscript->GetAI = &GetAI_mob_crystal_spike; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_crystalline_tangler"; + newscript->GetAI = &GetAI_mob_crystalline_tangler; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/commander_kolurg.cpp b/src/scripts/northrend/nexus/nexus/commander_kolurg.cpp new file mode 100644 index 00000000000..198279659ac --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/commander_kolurg.cpp @@ -0,0 +1,58 @@ +/* Script Data Start +SDName: Boss Commander Kolurg +SDAuthor: LordVanMartin +SD%Complete: +SDComment: Only Alliance Heroic +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_commander_kolurg' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" + +#define SPELL_BATTLE_SHOUT 31403 +#define SPELL_CHARGE 60067 +#define SPELL_FRIGHTENING_SHOUT 19134 +#define SPELL_WHIRLWIND_1 38619 +#define SPELL_WHIRLWIND_2 38618 + +//not used +//Yell +#define SAY_AGGRO -1576024 +#define SAY_KILL -1576025 +#define SAY_DEATH -1576026 + +struct TRINITY_DLL_DECL boss_commander_kolurgAI : public ScriptedAI +{ + boss_commander_kolurgAI(Creature *c) : ScriptedAI(c) {} + + void Reset() {} + void EnterCombat(Unit* who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) {} +}; + +CreatureAI* GetAI_boss_commander_kolurg(Creature* pCreature) +{ + return new boss_commander_kolurgAI (pCreature); +} + +void AddSC_boss_commander_kolurg() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_commander_kolurg"; + newscript->GetAI = &GetAI_boss_commander_kolurg; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/commander_stoutbeard.cpp b/src/scripts/northrend/nexus/nexus/commander_stoutbeard.cpp new file mode 100644 index 00000000000..dc6c3fa9ee4 --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/commander_stoutbeard.cpp @@ -0,0 +1,64 @@ +/* Script Data Start +SDName: Boss Commander Stoutbeard +SDAuthor: LordVanMartin +SD%Complete: +SDComment: Only Horde Heroic +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_commander_stoutbeard' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" + +#define SPELL_BATTLE_SHOUT 31403 +#define SPELL_CHARGE 60067 +#define SPELL_FRIGHTENING_SHOUT 19134 +#define SPELL_WHIRLWIND_1 38619 +#define SPELL_WHIRLWIND_2 38618 + +//not used +//Yell +#define SAY_AGGRO -1576021 +#define SAY_KILL -1576022 +#define SAY_DEATH -1576023 + +struct TRINITY_DLL_DECL boss_commander_stoutbeardAI : public ScriptedAI +{ + boss_commander_stoutbeardAI(Creature *c) : ScriptedAI(c) {} + + void Reset() {} + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + } + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + } +}; + +CreatureAI* GetAI_boss_commander_stoutbeard(Creature* pCreature) +{ + return new boss_commander_stoutbeardAI (pCreature); +} + +void AddSC_boss_commander_stoutbeard() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_commander_stoutbeard"; + newscript->GetAI = &GetAI_boss_commander_stoutbeard; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/instance_nexus.cpp b/src/scripts/northrend/nexus/nexus/instance_nexus.cpp new file mode 100644 index 00000000000..d04a1b595cb --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/instance_nexus.cpp @@ -0,0 +1,254 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Instance_Nexus +SD%Complete: +SDComment: +SDCategory: The Nexus, The Nexus +EndScriptData */ + +#include "ScriptedPch.h" +#include "nexus.h" + +#define NUMBER_OF_ENCOUNTERS 4 + +struct TRINITY_DLL_DECL instance_nexus : public ScriptedInstance +{ + instance_nexus(Map *pMap) : ScriptedInstance(pMap) { Initialize(); } + + uint32 m_auiEncounter[NUMBER_OF_ENCOUNTERS]; + + uint64 Anomalus; + uint64 Keristrasza; + + uint64 AnomalusContainmentSphere; + uint64 OrmoroksContainmentSphere; + uint64 TelestrasContainmentSphere; + + std::string strInstData; + + void Initialize() + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + Anomalus = 0; + } + + void OnCreatureCreate(Creature *pCreature, bool bAdd) + { + Map::PlayerList const &players = instance->GetPlayers(); + uint32 TeamInInstance = 0; + + if (!players.isEmpty()) + { + if (Player* pPlayer = players.begin()->getSource()) + TeamInInstance = pPlayer->GetTeam(); + } + switch (pCreature->GetEntry()) + { + case 26763: + Anomalus = pCreature->GetGUID(); + break; + case 26723: + Keristrasza = pCreature->GetGUID(); + break; + // Alliance npcs are spawned by default, if you are alliance, you will fight against horde npcs. + case 26800: + { + pCreature->setFaction(16); + if (TeamInInstance == ALLIANCE) + pCreature->UpdateEntry(26799, HORDE); + break; + } + case 26802: + { + pCreature->setFaction(16); + if (TeamInInstance == ALLIANCE) + pCreature->UpdateEntry(26801, HORDE); + break; + } + case 26805: + { + pCreature->setFaction(16); + if (TeamInInstance == ALLIANCE) + pCreature->UpdateEntry(26803, HORDE); + break; + } + case 27949: + { + pCreature->setFaction(16); + if (TeamInInstance == ALLIANCE) + pCreature->UpdateEntry(27947, HORDE); + break; + } + case 26796: + { + pCreature->setFaction(16); + if (TeamInInstance == ALLIANCE) + pCreature->UpdateEntry(26798, HORDE); + break; + } + } + } + + void OnGameObjectCreate(GameObject *pGo, bool bAdd) + { + switch (pGo->GetEntry()) + { + case 188527: + { + AnomalusContainmentSphere = pGo->GetGUID(); + if (m_auiEncounter[1] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + break; + } + case 188528: + { + OrmoroksContainmentSphere = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + break; + } + case 188526: + { + TelestrasContainmentSphere = pGo->GetGUID(); + if (m_auiEncounter[0] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + break; + } + } + } + + uint32 GetData(uint32 identifier) + { + switch(identifier) + { + case DATA_MAGUS_TELESTRA_EVENT: return m_auiEncounter[0]; + case DATA_ANOMALUS_EVENT: return m_auiEncounter[1]; + case DATA_ORMOROK_EVENT: return m_auiEncounter[2]; + case DATA_KERISTRASZA_EVENT: return m_auiEncounter[3]; + } + return 0; + } + + void SetData(uint32 identifier, uint32 data) + { + switch (identifier) + { + case DATA_MAGUS_TELESTRA_EVENT: + { + if (data == DONE) + { + GameObject *Sphere = instance->GetGameObject(TelestrasContainmentSphere); + if (Sphere) + Sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + } + m_auiEncounter[0] = data; + break; + } + case DATA_ANOMALUS_EVENT: + { + if (data == DONE) + { + if (GameObject *Sphere = instance->GetGameObject(AnomalusContainmentSphere)) + Sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + } + m_auiEncounter[1] = data; + break; + } + case DATA_ORMOROK_EVENT: + { + if (data == DONE) + { + if (GameObject *Sphere = instance->GetGameObject(OrmoroksContainmentSphere)) + Sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + } + m_auiEncounter[2] = data; + break; + } + case DATA_KERISTRASZA_EVENT: + m_auiEncounter[3] = data; + break; + } + + if (data == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3]; + + strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + uint64 GetData64(uint32 uiIdentifier) + { + switch(uiIdentifier) + { + case DATA_ANOMALUS: return Anomalus; + case DATA_KERISTRASZA: return Keristrasza; + case ANOMALUS_CONTAINMET_SPHERE: return AnomalusContainmentSphere; + case ORMOROKS_CONTAINMET_SPHERE: return OrmoroksContainmentSphere; + case TELESTRAS_CONTAINMET_SPHERE: return TelestrasContainmentSphere; + } + return 0; + } + + std::string GetSaveData() + { + return strInstData; + } + + void Load(const char *chrIn) + { + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; + + for (uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData *GetInstanceData_instance_nexus(Map *pMap) +{ + return new instance_nexus(pMap); +} + +void AddSC_instance_nexus() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_nexus"; + newscript->GetInstanceData = &GetInstanceData_instance_nexus; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/nexus/nexus.h b/src/scripts/northrend/nexus/nexus/nexus.h new file mode 100644 index 00000000000..de36fea4b93 --- /dev/null +++ b/src/scripts/northrend/nexus/nexus/nexus.h @@ -0,0 +1,19 @@ +#ifndef DEF_NEXUS_H +#define DEF_NEXUS_H + +enum eTypes +{ + DATA_MAGUS_TELESTRA_EVENT, + DATA_ANOMALUS_EVENT, + DATA_ORMOROK_EVENT, + DATA_KERISTRASZA_EVENT, + + DATA_ANOMALUS, + DATA_KERISTRASZA, + + ANOMALUS_CONTAINMET_SPHERE, + ORMOROKS_CONTAINMET_SPHERE, + TELESTRAS_CONTAINMET_SPHERE +}; + +#endif diff --git a/src/scripts/northrend/nexus/oculus/boss_drakos.cpp b/src/scripts/northrend/nexus/oculus/boss_drakos.cpp new file mode 100644 index 00000000000..64f60b390d1 --- /dev/null +++ b/src/scripts/northrend/nexus/oculus/boss_drakos.cpp @@ -0,0 +1,98 @@ +/* Script Data Start +SDName: Boss drakos +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "oculus.h" + +enum Spells +{ + SPELL_MAGIC_PULL = 51336, + SPELL_THUNDERING_STOMP = 50774, + SPELL_THUNDERING_STOMP_2 = 59370 +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1578000, + SAY_KILL_1 = -1578001, + SAY_KILL_2 = -1578002, + SAY_KILL_3 = -1578003, + SAY_DEATH = -1578004, + SAY_PULL_1 = -1578005, + SAY_PULL_2 = -1578006, + SAY_PULL_3 = -1578007, + SAY_PULL_4 = -1578008, + SAY_STOMP_1 = -1578009, + SAY_STOMP_2 = -1578010, + SAY_STOMP_3 = -1578011 +}; + +struct TRINITY_DLL_DECL boss_drakosAI : public ScriptedAI +{ + boss_drakosAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void Reset() + { + if (pInstance) + pInstance->SetData(DATA_DRAKOS_EVENT, NOT_STARTED); + } + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_DRAKOS_EVENT, IN_PROGRESS); + } + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_DRAKOS_EVENT, DONE); + } + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_KILL_1,SAY_KILL_2,SAY_KILL_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_drakos(Creature* pCreature) +{ + return new boss_drakosAI (pCreature); +} + +void AddSC_boss_drakos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_drakos"; + newscript->GetAI = &GetAI_boss_drakos; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/oculus/boss_eregos.cpp b/src/scripts/northrend/nexus/oculus/boss_eregos.cpp new file mode 100644 index 00000000000..e96aa70afb3 --- /dev/null +++ b/src/scripts/northrend/nexus/oculus/boss_eregos.cpp @@ -0,0 +1,125 @@ +/* Script Data Start +SDName: Boss eregos +SDAuthor: LordVanMartin +SD%Complete: +SDComment: Encounter is done entirely on drake vehicles +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "oculus.h" + +//Types of drake mounts: Ruby(Tank), Amber(DPS), Emerald(Healer) +//Two Repeating phases + +enum Spells +{ + SPELL_ARCANE_BARRAGE = 50804, + SPELL_ARCANE_VOLLEY = 51153, + SPELL_ENRAGED_ASSAULT = 51170, + SPELL_PLANAR_ANOMALIES = 57959, + SPELL_PLANAR_SHIFT = 51162, + //Heroic + H_SPELL_ARCANE_BARRAGE = 59381, + H_SPELL_ARCANE_VOLLEY = 59382 +}; +/*Ruby Drake , +(npc 27756) (item 37860) +(summoned by spell Ruby Essence = 37860 ---> Call Amber Drake == 49462 ---> Summon 27756) +*/ +enum RubyDrake +{ + NPC_RUBY_DRAKE_VEHICLE = 27756, + SPELL_RIDE_RUBY_DRAKE_QUE = 49463, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49464 + SPELL_RUBY_DRAKE_SADDLE = 49464, //Allows you to ride on the back of an Amber Drake. ---> Dummy + SPELL_RUBY_SEARING_WRATH = 50232, //(60 yds) - Instant - Breathes a stream of fire at an enemy dragon, dealing 6800 to 9200 Fire damage and then jumping to additional dragons within 30 yards. Each jump increases the damage by 50%. Affects up to 5 total targets + SPELL_RUBY_EVASIVE_AURA = 50248, //Instant - Allows the Ruby Drake to generate Evasive Charges when hit by hostile attacks and spells. + SPELL_RUBY_EVASIVE_MANEUVERS = 50240, //Instant - 5 sec. cooldown - Allows your drake to dodge all incoming attacks and spells. Requires Evasive Charges to use. Each attack or spell dodged while this ability is active burns one Evasive Charge. Lasts 30 sec. or until all charges are exhausted. + //you do not have acces to until you kill Mage-Lord Urom + SPELL_RUBY_MARTYR = 50253 //Instant - 10 sec. cooldown - Redirect all harmful spells cast at friendly drakes to yourself for 10 sec. +}; +/*Amber Drake, +(npc 27755) (item 37859) +(summoned by spell Amber Essence = 37859 ---> Call Amber Drake == 49461 ---> Summon 27755) +*/ +enum AmberDrake +{ + NPC_AMBER_DRAKE_VEHICLE = 27755, + SPELL_RIDE_AMBER_DRAKE_QUE = 49459, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49460 + SPELL_AMBER_DRAKE_SADDLE = 49460, //Allows you to ride on the back of an Amber Drake. ---> Dummy + SPELL_AMBER_SHOCK_LANCE = 49840, //(60 yds) - Instant - Deals 4822 to 5602 Arcane damage and detonates all Shock Charges on an enemy dragon. Damage is increased by 6525 for each detonated. +// SPELL_AMBER_STOP_TIME //Instant - 1 min cooldown - Halts the passage of time, freezing all enemy dragons in place for 10 sec. This attack applies 5 Shock Charges to each affected target. + //you do not have access to until you kill the Mage-Lord Urom. + SPELL_AMBER_TEMPORAL_RIFT = 49592 //(60 yds) - Channeled - Channels a temporal rift on an enemy dragon for 10 sec. While trapped in the rift, all damage done to the target is increased by 100%. In addition, for every 15,000 damage done to a target affected by Temporal Rift, 1 Shock Charge is generated. +}; +/*Emerald Drake, +(npc 27692) (item 37815), + (summoned by spell Emerald Essence = 37815 ---> Call Emerald Drake == 49345 ---> Summon 27692) +*/ +enum EmeraldDrake +{ + NPC_EMERALD_DRAKE_VEHICLE = 27692, + SPELL_RIDE_EMERALD_DRAKE_QUE = 49427, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49346 + SPELL_EMERALD_DRAKE_SADDLE = 49346, //Allows you to ride on the back of an Amber Drake. ---> Dummy + SPELL_EMERALD_LEECHING_POISON = 50328, //(60 yds) - Instant - Poisons the enemy dragon, leeching 1300 to the caster every 2 sec. for 12 sec. Stacks up to 3 times. + SPELL_EMERALD_TOUCH_THE_NIGHTMARE = 50341, //(60 yds) - Instant - Consumes 30% of the caster's max health to inflict 25,000 nature damage to an enemy dragon and reduce the damage it deals by 25% for 30 sec. + // you do not have access to until you kill the Mage-Lord Urom + SPELL_EMERALD_DREAM_FUNNEL = 50344 //(60 yds) - Channeled - Transfers 5% of the caster's max health to a friendly drake every second for 10 seconds as long as the caster channels. +}; + +struct TRINITY_DLL_DECL boss_eregosAI : public ScriptedAI +{ + boss_eregosAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void Reset() + { + if (pInstance) + pInstance->SetData(DATA_EREGOS_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + if (pInstance) + pInstance->SetData(DATA_EREGOS_EVENT, IN_PROGRESS); + } + + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (pInstance) + pInstance->SetData(DATA_EREGOS_EVENT, DONE); + } +}; + +CreatureAI* GetAI_boss_eregos(Creature* pCreature) +{ + return new boss_eregosAI (pCreature); +} + +void AddSC_boss_eregos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_eregos"; + newscript->GetAI = &GetAI_boss_eregos; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/oculus/boss_urom.cpp b/src/scripts/northrend/nexus/oculus/boss_urom.cpp new file mode 100644 index 00000000000..34044ef4a4f --- /dev/null +++ b/src/scripts/northrend/nexus/oculus/boss_urom.cpp @@ -0,0 +1,103 @@ +/* Script Data Start +SDName: Boss urom +SDAuthor: LordVanMartin +SD%Complete: 1% +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "oculus.h" + +enum Spells +{ + SPELL_ARCANE_SHIELD = 53813, //Dummy --> Channeled, shields the caster from damage. + SPELL_EMPOWERED_ARCANE_EXPLOSION = 51110, + SPELL_EMPOWERED_ARCANE_EXPLOSION_2 = 59377, + SPELL_FROSTBOMB = 51103, //Urom throws a bomb, hitting its target with the highest aggro which inflict directly 650 frost damage and drops a frost zone on the ground. This zone deals 650 frost damage per second and reduce the movement speed by 35%. Lasts 1 minute. + SPELL_SUMMON_MENAGERIE = 50476, //Summons an assortment of creatures and teleports the caster to safety. + SPELL_SUMMON_MENAGERIE_2 = 50495, + SPELL_SUMMON_MENAGERIE_3 = 50496, + SPELL_TELEPORT = 51112, //Teleports to the center of Oculus + SPELL_TIME_BOMB = 51121, //Deals arcane damage to a random player, and after 6 seconds, deals zone damage to nearby equal to the health missing of the target afflicted by the debuff. + SPELL_TIME_BOMB_2 = 59376 +}; +//not in db +enum Yells +{ + SAY_AGGRO = -1578012, + SAY_KILL_1 = -1578013, + SAY_KILL_2 = -1578014, + SAY_KILL_3 = -1578015, + SAY_DEATH = -1578016, + SAY_EXPLOSION_1 = -1578017, + SAY_EXPLOSION_2 = -1578018, + SAY_SUMMON_1 = -1578019, + SAY_SUMMON_2 = -1578020, + SAY_SUMMON_3 = -1578021 +}; + +struct TRINITY_DLL_DECL boss_uromAI : public ScriptedAI +{ + boss_uromAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void Reset() + { + if (pInstance) + pInstance->SetData(DATA_UROM_EVENT, NOT_STARTED); + } + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_UROM_EVENT, IN_PROGRESS); + } + + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_UROM_EVENT, DONE); + } + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_KILL_1,SAY_KILL_2,SAY_KILL_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_urom(Creature* pCreature) +{ + return new boss_uromAI (pCreature); +} + +void AddSC_boss_urom() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_urom"; + newscript->GetAI = &GetAI_boss_urom; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/oculus/boss_varos.cpp b/src/scripts/northrend/nexus/oculus/boss_varos.cpp new file mode 100644 index 00000000000..05c5cea8472 --- /dev/null +++ b/src/scripts/northrend/nexus/oculus/boss_varos.cpp @@ -0,0 +1,100 @@ +/* Script Data Start +SDName: Boss varos +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "oculus.h" + +enum Spells +{ + SPELL_ENERGIZE_CORES = 50785, //Damage 5938 to 6562, effec2 Triggers 54069, effect3 Triggers 56251 + SPELL_ENERGIZE_CORES_TRIGGER_1 = 54069, + SPELL_ENERGIZE_CORES_TRIGGER_2 = 56251, + SPELL_ENERGIZE_CORES_2 = 59372, //Damage 9025 to 9975, effect2 Triggers 54069, effect 56251 + SPELL_CALL_AZURE_RING_CAPTAIN = 51002, //Effect Send Event (12229) + SPELL_CALL_AZURE_RING_CAPTAIN_2 = 51006, //Effect Send Event (10665) + SPELL_CALL_AZURE_RING_CAPTAIN_3 = 51007, //Effect Send Event (18454) + SPELL_CALL_AZURE_RING_CAPTAIN_4 = 51008, //Effect Send Event (18455) + SPELL_CALL_AMPLIFY_MAGIC = 51054, + SPELL_CALL_AMPLIFY_MAGIC_2 = 59371 +}; +//not in db +enum Yells +{ + SAY_AGGRO = -1578022, + SAY_KILL_1 = -1578023, + SAY_KILL_2 = -1578024, + SAY_DEATH = -1578025, + SAY_STRIKE_1 = -1578026, + SAY_STRIKE_2 = -1578027, + SAY_STRIKE_3 = -1578028, + SAY_SPAWN = -1578029 +}; + +struct TRINITY_DLL_DECL boss_varosAI : public ScriptedAI +{ + boss_varosAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void Reset() + { + if (pInstance) + pInstance->SetData(DATA_VAROS_EVENT, NOT_STARTED); + } + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_VAROS_EVENT, IN_PROGRESS); + } + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_VAROS_EVENT, DONE); + } + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_KILL_1,SAY_KILL_2), m_creature); + } +}; + +CreatureAI* GetAI_boss_varos(Creature* pCreature) +{ + return new boss_varosAI (pCreature); +} + +void AddSC_boss_varos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_varos"; + newscript->GetAI = &GetAI_boss_varos; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/oculus/instance_oculus.cpp b/src/scripts/northrend/nexus/oculus/instance_oculus.cpp new file mode 100644 index 00000000000..d57738b959c --- /dev/null +++ b/src/scripts/northrend/nexus/oculus/instance_oculus.cpp @@ -0,0 +1,150 @@ +#include "ScriptedPch.h" +#include "oculus.h" + +#define MAX_ENCOUNTER 4 + +/* The Occulus encounters: +0 - Drakos the Interrogator +1 - Varos Cloudstrider +2 - Mage-Lord Urom +3 - Ley-Guardian Eregos */ + +struct TRINITY_DLL_DECL instance_oculus : public ScriptedInstance +{ + instance_oculus(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint64 uiDrakos; + uint64 uiVaros; + uint64 uiUrom; + uint64 uiEregos; + + uint8 m_auiEncounter[MAX_ENCOUNTER]; + std::string str_data; + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case CREATURE_DRAKOS: + uiDrakos = pCreature->GetGUID(); + break; + case CREATURE_VAROS: + uiVaros = pCreature->GetGUID(); + break; + case CREATURE_UROM: + uiUrom = pCreature->GetGUID(); + break; + case CREATURE_EREGOS: + uiEregos = pCreature->GetGUID(); + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_DRAKOS_EVENT: + m_auiEncounter[0] = data; + break; + case DATA_VAROS_EVENT: + m_auiEncounter[1] = data; + break; + case DATA_UROM_EVENT: + m_auiEncounter[2] = data; + break; + case DATA_EREGOS_EVENT: + m_auiEncounter[3] = data; + break; + } + + if (data == DONE) + SaveToDB(); + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_DRAKOS_EVENT: return m_auiEncounter[0]; + case DATA_VAROS_EVENT: return m_auiEncounter[1]; + case DATA_UROM_EVENT: return m_auiEncounter[2]; + case DATA_EREGOS_EVENT: return m_auiEncounter[3]; + } + + return 0; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_DRAKOS: return uiDrakos; + case DATA_VAROS: return uiVaros; + case DATA_UROM: return uiUrom; + case DATA_EREGOS: return uiEregos; + } + + return 0; + } + + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "T O " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3; + + if (dataHead1 == 'T' && dataHead2 == 'O') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + m_auiEncounter[3] = data3; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_oculus(Map* pMap) +{ + return new instance_oculus(pMap); +} + +void AddSC_instance_oculus() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_oculus"; + newscript->GetInstanceData = &GetInstanceData_instance_oculus; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/nexus/oculus/oculus.h b/src/scripts/northrend/nexus/oculus/oculus.h new file mode 100644 index 00000000000..6680e7cf0ba --- /dev/null +++ b/src/scripts/northrend/nexus/oculus/oculus.h @@ -0,0 +1,28 @@ +#ifndef DEF_OCULUS_H +#define DEF_OCULUS_H + +enum Data +{ + DATA_DRAKOS_EVENT, + DATA_VAROS_EVENT, + DATA_UROM_EVENT, + DATA_EREGOS_EVENT +}; + +enum Data64 +{ + DATA_DRAKOS, + DATA_VAROS, + DATA_UROM, + DATA_EREGOS +}; + +enum Bosses +{ + CREATURE_DRAKOS = 27654, + CREATURE_VAROS = 27447, + CREATURE_UROM = 27655, + CREATURE_EREGOS = 27656 +}; + +#endif diff --git a/src/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp b/src/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp new file mode 100644 index 00000000000..13d7502606f --- /dev/null +++ b/src/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp @@ -0,0 +1,1149 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss Sartharion +SD%Complete: 70% +SDComment: Flame wave, achievement and portal events need to be implemented +SDCategory: Obsidian Sanctum +EndScriptData */ + +#include "ScriptedPch.h" +#include "obsidian_sanctum.h" + +enum eEnums +{ + //Sartharion Yell + SAY_SARTHARION_AGGRO = -1615018, + SAY_SARTHARION_BERSERK = -1615019, + SAY_SARTHARION_BREATH = -1615020, + SAY_SARTHARION_CALL_SHADRON = -1615021, + SAY_SARTHARION_CALL_TENEBRON = -1615022, + SAY_SARTHARION_CALL_VESPERON = -1615023, + SAY_SARTHARION_DEATH = -1615024, + SAY_SARTHARION_SPECIAL_1 = -1615025, + SAY_SARTHARION_SPECIAL_2 = -1615026, + SAY_SARTHARION_SPECIAL_3 = -1615027, + SAY_SARTHARION_SPECIAL_4 = -1615028, + SAY_SARTHARION_SLAY_1 = -1615029, + SAY_SARTHARION_SLAY_2 = -1615030, + SAY_SARTHARION_SLAY_3 = -1615031, + + WHISPER_LAVA_CHURN = -1615032, + + WHISPER_SHADRON_DICIPLE = -1615008, + WHISPER_VESPERON_DICIPLE = -1615041, + WHISPER_HATCH_EGGS = -1615017, + WHISPER_OPEN_PORTAL = -1615042, // whisper, shared by two dragons + + //Sartharion Spells + SPELL_BERSERK = 61632, // Increases the caster's attack speed by 150% and all damage it deals by 500% for 5 min. + SPELL_CLEAVE = 56909, // Inflicts 35% weapon damage to an enemy and its nearest allies, affecting up to 10 targets. + SPELL_FLAME_BREATH = 56908, // Inflicts 8750 to 11250 Fire damage to enemies in a cone in front of the caster. + SPELL_FLAME_BREATH_H = 58956, // Inflicts 10938 to 14062 Fire damage to enemies in a cone in front of the caster. + SPELL_TAIL_LASH = 56910, // A sweeping tail strike hits all enemies behind the caster, inflicting 3063 to 3937 damage and stunning them for 2 sec. + SPELL_TAIL_LASH_H = 58957, // A sweeping tail strike hits all enemies behind the caster, inflicting 4375 to 5625 damage and stunning them for 2 sec. + SPELL_WILL_OF_SARTHARION = 61254, // Sartharion's presence bolsters the resolve of the Twilight Drakes, increasing their total health by 25%. This effect also increases Sartharion's health by 25%. + SPELL_LAVA_STRIKE = 57571, // (Real spell casted should be 57578) 57571 then trigger visual missile, then summon Lava Blaze on impact(spell 57572) + SPELL_TWILIGHT_REVENGE = 60639, + + SPELL_PYROBUFFET = 56916, // currently used for hard enrage after 15 minutes + SPELL_PYROBUFFET_RANGE = 58907, // possibly used when player get too far away from dummy creatures (2x Creature entry 30494) + + SPELL_TWILIGHT_SHIFT_ENTER = 57620, // enter phase. Player get this when click GO + SPELL_TWILIGHT_SHIFT_REMOVAL = 61187, // leave phase + SPELL_TWILIGHT_SHIFT_REMOVAL_ALL = 61190, // leave phase (probably version to make all leave) + + //Mini bosses common spells + SPELL_TWILIGHT_RESIDUE = 61885, // makes immune to shadow damage, applied when leave phase + + //Miniboses (Vesperon, Shadron, Tenebron) + SPELL_SHADOW_BREATH_H = 59126, // Inflicts 8788 to 10212 Fire damage to enemies in a cone in front of the caster. + SPELL_SHADOW_BREATH = 57570, // Inflicts 6938 to 8062 Fire damage to enemies in a cone in front of the caster. + + SPELL_SHADOW_FISSURE_H = 59127, // Deals 9488 to 13512 Shadow damage to any enemy within the Shadow fissure after 5 sec. + SPELL_SHADOW_FISSURE = 57579, // Deals 6188 to 8812 Shadow damage to any enemy within the Shadow fissure after 5 sec. + + //Vesperon + //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times + NPC_ACOLYTE_OF_VESPERON = 31219, // Acolyte of Vesperon + SPELL_POWER_OF_VESPERON = 61251, // Vesperon's presence decreases the maximum health of all enemies by 25%. + SPELL_TWILIGHT_TORMENT_VESP = 57948, // (Shadow only) trigger 57935 then 57988 + SPELL_TWILIGHT_TORMENT_VESP_ACO = 58853, // (Fire and Shadow) trigger 58835 then 57988 + + //Shadron + //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times + NPC_ACOLYTE_OF_SHADRON = 31218, // Acolyte of Shadron + SPELL_POWER_OF_SHADRON = 58105, // Shadron's presence increases Fire damage taken by all enemies by 100%. + SPELL_GIFT_OF_TWILIGTH_SHA = 57835, // TARGET_SCRIPT shadron + SPELL_GIFT_OF_TWILIGTH_SAR = 58766, // TARGET_SCRIPT sartharion + + //Tenebron + //in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 + SPELL_POWER_OF_TENEBRON = 61248, // Tenebron's presence increases Shadow damage taken by all enemies by 100%. + //Tenebron, dummy spell + SPELL_SUMMON_TWILIGHT_WHELP = 58035, // doesn't work, will spawn NPC_TWILIGHT_WHELP + SPELL_SUMMON_SARTHARION_TWILIGHT_WHELP = 58826, // doesn't work, will spawn NPC_SHARTHARION_TWILIGHT_WHELP + + SPELL_HATCH_EGGS_H = 59189, + SPELL_HATCH_EGGS = 58542, + SPELL_HATCH_EGGS_EFFECT_H = 59190, + SPELL_HATCH_EGGS_EFFECT = 58685, + + //Whelps + NPC_TWILIGHT_WHELP = 30890, + NPC_SHARTHARION_TWILIGHT_WHELP = 31214, + SPELL_FADE_ARMOR = 60708, // Reduces the armor of an enemy by 1500 for 15s + + //flame tsunami + SPELL_FLAME_TSUNAMI = 57494, // the visual dummy + SPELL_FLAME_TSUNAMI_LEAP = 60241, // SPELL_EFFECT_138 some leap effect, causing caster to move in direction + SPELL_FLAME_TSUNAMI_DMG_AURA = 57492, // periodic damage, npc has this aura + + NPC_FLAME_TSUNAMI = 30616, // for the flame waves + NPC_LAVA_BLAZE = 30643, // adds spawning from flame strike + + //using these custom points for dragons start and end + POINT_ID_INIT = 100, + POINT_ID_LAND = 200, + + //Achievements + ACHIEV_TWILIGHT_ASSIST = 2049, + H_ACHIEV_TWILIGHT_ASSIST = 2052, + ACHIEV_TWILIGHT_DUO = 2050, + H_ACHIEV_TWILIGHT_DUO = 2053, + ACHIEV_TWILIGHT_ZONE = 2051, + H_ACHIEV_TWILIGHT_ZONE = 2054 +}; + +struct Waypoint +{ + float m_fX, m_fY, m_fZ; +}; + +//each dragons special points. First where fly to before connect to connon, second where land point is. +Waypoint m_aTene[]= +{ + {3212.854, 575.597, 109.856}, //init + {3246.425, 565.367, 61.249} //end +}; + +Waypoint m_aShad[]= +{ + {3293.238, 472.223, 106.968}, + {3271.669, 526.907, 61.931} +}; + +Waypoint m_aVesp[]= +{ + {3193.310, 472.861, 102.697}, + {3227.268, 533.238, 59.995} +}; + +#define MAX_WAYPOINT 6 +//points around raid "isle", counter clockwise. should probably be adjusted to be more alike +Waypoint m_aDragonCommon[MAX_WAYPOINT]= +{ + {3214.012, 468.932, 98.652}, + {3244.950, 468.427, 98.652}, + {3283.520, 496.869, 98.652}, + {3287.316, 555.875, 98.652}, + {3250.479, 585.827, 98.652}, + {3209.969, 566.523, 98.652} +}; + +/*###### +## Boss Sartharion +######*/ + +struct TRINITY_DLL_DECL boss_sartharionAI : public ScriptedAI +{ + boss_sartharionAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + bool m_bIsBerserk; + bool m_bIsSoftEnraged; + + uint32 m_uiEnrageTimer; + bool m_bIsHardEnraged; + + uint32 m_uiTenebronTimer; + uint32 m_uiShadronTimer; + uint32 m_uiVesperonTimer; + + uint32 m_uiFlameTsunamiTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiTailSweepTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiLavaStrikeTimer; + + bool m_bHasCalledTenebron; + bool m_bHasCalledShadron; + bool m_bHasCalledVesperon; + + uint32 achievProgress; + + void Reset() + { + m_bIsBerserk = false; + m_bIsSoftEnraged = false; + + m_uiEnrageTimer = 15*MINUTE*IN_MILISECONDS; + m_bIsHardEnraged = false; + + m_uiTenebronTimer = 30000; + m_uiShadronTimer = 75000; + m_uiVesperonTimer = 120000; + + m_uiFlameTsunamiTimer = 30000; + m_uiFlameBreathTimer = 20000; + m_uiTailSweepTimer = 20000; + m_uiCleaveTimer = 7000; + m_uiLavaStrikeTimer = 5000; + + m_bHasCalledTenebron = false; + m_bHasCalledShadron = false; + m_bHasCalledVesperon = false; + + if (m_creature->HasAura(SPELL_TWILIGHT_REVENGE)) + m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_REVENGE); + + m_creature->ResetLootMode(); + + achievProgress = 0; + } + + void JustReachedHome() + { + if (pInstance) + pInstance->SetData(TYPE_SARTHARION_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* pWho) + { + DoScriptText(SAY_SARTHARION_AGGRO,m_creature); + DoZoneInCombat(); + + if (pInstance) + { + pInstance->SetData(TYPE_SARTHARION_EVENT, IN_PROGRESS); + FetchDragons(); + } + } + + void JustDied(Unit* pKiller) + { + DoScriptText(SAY_SARTHARION_DEATH,m_creature); + + if (pInstance) + { + if (achievProgress == 1) + pInstance->DoCompleteAchievement(RAID_MODE(ACHIEV_TWILIGHT_ASSIST,H_ACHIEV_TWILIGHT_ASSIST)); + else if (achievProgress == 2) + pInstance->DoCompleteAchievement(RAID_MODE(ACHIEV_TWILIGHT_DUO,H_ACHIEV_TWILIGHT_DUO)); + else if (achievProgress == 3) + pInstance->DoCompleteAchievement(RAID_MODE(ACHIEV_TWILIGHT_ZONE,H_ACHIEV_TWILIGHT_ZONE)); + + pInstance->SetData(TYPE_SARTHARION_EVENT, DONE); + } + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_SARTHARION_SLAY_1,SAY_SARTHARION_SLAY_2,SAY_SARTHARION_SLAY_3), m_creature); + } + + // m_creature->ResetLootMode() is called from Reset() + // AddDrakeLootMode() should only ever be called from FetchDragons(), which is called from Aggro() + void AddDrakeLootMode() + { + if (m_creature->HasLootMode(4)) // Has two Drake loot modes + m_creature->AddLootMode(8); // Add 3rd Drake loot mode + else if (m_creature->HasLootMode(2)) // Has one Drake loot mode + m_creature->AddLootMode(4); // Add 2nd Drake loot mode + else // Has no Drake loot modes + m_creature->AddLootMode(2); // Add 1st Drake loot mode + } + + void FetchDragons() + { + if(!pInstance) + return; + Creature* pFetchTene = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_TENEBRON)); + Creature* pFetchShad = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_SHADRON)); + Creature* pFetchVesp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_VESPERON)); + + //if at least one of the dragons are alive and are being called + bool bCanUseWill = false; + + if (pFetchTene && pFetchTene->isAlive() && !pFetchTene->getVictim()) + { + bCanUseWill = true; + pFetchTene->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aTene[0].m_fX, m_aTene[0].m_fY, m_aTene[0].m_fZ); + + if (!pFetchTene->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pFetchTene->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + if (pFetchShad && pFetchShad->isAlive() && !pFetchShad->getVictim()) + { + bCanUseWill = true; + pFetchShad->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aShad[0].m_fX, m_aShad[0].m_fY, m_aShad[0].m_fZ); + + if (!pFetchShad->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pFetchShad->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + if (pFetchVesp && pFetchVesp->isAlive() && !pFetchVesp->getVictim()) + { + bCanUseWill = true; + pFetchVesp->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aVesp[0].m_fX, m_aVesp[0].m_fY, m_aVesp[0].m_fZ); + + if (!pFetchVesp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pFetchVesp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + if (bCanUseWill) + DoCast(m_creature, SPELL_WILL_OF_SARTHARION); + } + + void CallDragon(uint32 uiDataId) + { + if (pInstance) + { + if (Creature *pTemp = Unit::GetCreature(*m_creature,pInstance->GetData64(uiDataId))) + { + if (pTemp->isAlive() && !pTemp->getVictim()) + { + if (pTemp->HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE)) + pTemp->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + + if (pTemp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + int32 iTextId = 0; + AddDrakeLootMode(); + + achievProgress++; + + switch(pTemp->GetEntry()) + { + case NPC_TENEBRON: + iTextId = SAY_SARTHARION_CALL_TENEBRON; + pTemp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aTene[1].m_fX, m_aTene[1].m_fY, m_aTene[1].m_fZ); + break; + case NPC_SHADRON: + iTextId = SAY_SARTHARION_CALL_SHADRON; + pTemp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aShad[1].m_fX, m_aShad[1].m_fY, m_aShad[1].m_fZ); + break; + case NPC_VESPERON: + iTextId = SAY_SARTHARION_CALL_VESPERON; + pTemp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aVesp[1].m_fX, m_aVesp[1].m_fY, m_aVesp[1].m_fZ); + break; + } + + DoScriptText(iTextId, m_creature); + } + } + } + } + + void SendFlameTsunami() + { + if (Map* pMap = m_creature->GetMap()) + if (pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + + if (!PlayerList.isEmpty()) + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (i->getSource() && i->getSource()->isAlive()) + DoScriptText(WHISPER_LAVA_CHURN, m_creature, i->getSource()); + } + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + Unit* pTene = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_TENEBRON) : 0); + Unit* pShad = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_SHADRON) : 0); + Unit* pVesp = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_VESPERON) : 0); + + //spell will target dragons, if they are still alive at 35% + if (!m_bIsBerserk && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 35 + && ((pTene && pTene->isAlive()) || (pShad && pShad->isAlive()) || (pVesp && pVesp->isAlive()))) + { + DoScriptText(SAY_SARTHARION_BERSERK, m_creature); + DoCast(m_creature, SPELL_BERSERK); + m_bIsBerserk = true; + } + + //soft enrage + if (!m_bIsSoftEnraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 10) + { + // TODO + m_bIsSoftEnraged = true; + } + + // hard enrage + if (!m_bIsHardEnraged) + { + if (m_uiEnrageTimer <= uiDiff) + { + DoCast(m_creature, SPELL_PYROBUFFET, true); + m_bIsHardEnraged = true; + } + else + m_uiEnrageTimer -= uiDiff; + } + + // flame tsunami + if (m_uiFlameTsunamiTimer <= uiDiff) + { + SendFlameTsunami(); + m_uiFlameTsunamiTimer = 30000; + } + else + m_uiFlameTsunamiTimer -= uiDiff; + + // flame breath + if (m_uiFlameBreathTimer <= uiDiff) + { + DoScriptText(SAY_SARTHARION_BREATH, m_creature); + DoCast(m_creature->getVictim(), RAID_MODE(SPELL_FLAME_BREATH, SPELL_FLAME_BREATH_H)); + m_uiFlameBreathTimer = urand(25000,35000); + } + else + m_uiFlameBreathTimer -= uiDiff; + + // Tail Sweep + if (m_uiTailSweepTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), RAID_MODE(SPELL_TAIL_LASH, SPELL_TAIL_LASH_H)); + m_uiTailSweepTimer = urand(15000,20000); + } + else + m_uiTailSweepTimer -= uiDiff; + + // Cleave + if (m_uiCleaveTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + m_uiCleaveTimer = urand(7000,10000); + } + else + m_uiCleaveTimer -= uiDiff; + + // Lavas Strike + if (m_uiLavaStrikeTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(pTarget, SPELL_LAVA_STRIKE); + + if(urand(0,4) == 4) + DoScriptText(RAND(SAY_SARTHARION_SPECIAL_1,SAY_SARTHARION_SPECIAL_2,SAY_SARTHARION_SPECIAL_3), m_creature); + } + m_uiLavaStrikeTimer = urand(5000,20000); + } + else + m_uiLavaStrikeTimer -= uiDiff; + + // call tenebron + if (!m_bHasCalledTenebron && m_uiTenebronTimer <= uiDiff) + { + CallDragon(DATA_TENEBRON); + m_bHasCalledTenebron = true; + } + else + m_uiTenebronTimer -= uiDiff; + + // call shadron + if (!m_bHasCalledShadron && m_uiShadronTimer <= uiDiff) + { + CallDragon(DATA_SHADRON); + m_bHasCalledShadron = true; + } + else + m_uiShadronTimer -= uiDiff; + + // call vesperon + if (!m_bHasCalledVesperon && m_uiVesperonTimer <= uiDiff) + { + CallDragon(DATA_VESPERON); + m_bHasCalledVesperon = true; + } + else + m_uiVesperonTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(uiDiff); + } +}; + +CreatureAI* GetAI_boss_sartharion(Creature* pCreature) +{ + return new boss_sartharionAI(pCreature); +} + +enum TeneText +{ + SAY_TENEBRON_AGGRO = -1615009, + SAY_TENEBRON_SLAY_1 = -1615010, + SAY_TENEBRON_SLAY_2 = -1615011, + SAY_TENEBRON_DEATH = -1615012, + SAY_TENEBRON_BREATH = -1615013, + SAY_TENEBRON_RESPOND = -1615014, + SAY_TENEBRON_SPECIAL_1 = -1615015, + SAY_TENEBRON_SPECIAL_2 = -1615016 +}; + +enum ShadText +{ + SAY_SHADRON_AGGRO = -1615000, + SAY_SHADRON_SLAY_1 = -1615001, + SAY_SHADRON_SLAY_2 = -1615002, + SAY_SHADRON_DEATH = -1615003, + SAY_SHADRON_BREATH = -1615004, + SAY_SHADRON_RESPOND = -1615005, + SAY_SHADRON_SPECIAL_1 = -1615006, + SAY_SHADRON_SPECIAL_2 = -1615007 +}; + +enum VespText +{ + SAY_VESPERON_AGGRO = -1615033, + SAY_VESPERON_SLAY_1 = -1615034, + SAY_VESPERON_SLAY_2 = -1615035, + SAY_VESPERON_DEATH = -1615036, + SAY_VESPERON_BREATH = -1615037, + SAY_VESPERON_RESPOND = -1615038, + SAY_VESPERON_SPECIAL_1 = -1615039, + SAY_VESPERON_SPECIAL_2 = -1615040 +}; + +//to control each dragons common abilities +struct TRINITY_DLL_DECL dummy_dragonAI : public ScriptedAI +{ + dummy_dragonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 m_uiWaypointId; + uint32 m_uiMoveNextTimer; + int32 m_iPortalRespawnTime; + bool m_bCanMoveFree; + + void Reset() + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_uiWaypointId = 0; + m_uiMoveNextTimer = 500; + m_iPortalRespawnTime = 30000; + m_bCanMoveFree = false; + } + + void MovementInform(uint32 uiType, uint32 uiPointId) + { + if (!pInstance || uiType != POINT_MOTION_TYPE) + return; + + debug_log("dummy_dragonAI: %s reached point %u", m_creature->GetName(), uiPointId); + + //if healers messed up the raid and we was already initialized + if (pInstance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) + { + EnterEvadeMode(); + return; + } + + //this is end, if we reach this, don't do much + if (uiPointId == POINT_ID_LAND) + { + m_creature->GetMotionMaster()->Clear(); + m_bCanMoveFree = false; + return; + } + + //get amount of common points + uint32 uiCommonWPCount = sizeof(m_aDragonCommon)/sizeof(Waypoint); + + //increase + m_uiWaypointId = uiPointId+1; + + //if we have reached a point bigger or equal to count, it mean we must reset to point 0 + if (m_uiWaypointId >= uiCommonWPCount) + { + if (!m_bCanMoveFree) + m_bCanMoveFree = true; + + m_uiWaypointId = 0; + } + + m_uiMoveNextTimer = 500; + } + + //used when open portal and spawn mobs in phase + void DoRaidWhisper(int32 iTextId) + { + Map* pMap = m_creature->GetMap(); + + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + + if (!PlayerList.isEmpty()) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + DoScriptText(iTextId, m_creature, i->getSource()); + } + } + } + + //"opens" the portal and does the "opening" whisper + void OpenPortal() + { + int32 iTextId = 0; + + //there are 4 portal spawn locations, each are expected to be spawned with negative spawntimesecs in database + + //using a grid search here seem to be more efficient than caching all four guids + //in instance script and calculate range to each. + GameObject* pPortal = m_creature->FindNearestGameObject(GO_TWILIGHT_PORTAL,50.0f); + + switch(m_creature->GetEntry()) + { + case NPC_TENEBRON: + iTextId = WHISPER_HATCH_EGGS; + break; + case NPC_SHADRON: + case NPC_VESPERON: + iTextId = WHISPER_OPEN_PORTAL; + break; + } + + DoRaidWhisper(iTextId); + + //By using SetRespawnTime() we will actually "spawn" the object with our defined time. + //Once time is up, portal will disappear again. + if (pPortal && !pPortal->isSpawned()) + pPortal->SetRespawnTime(m_iPortalRespawnTime); + + //Unclear what are expected to happen if one drake has a portal open already + //Refresh respawnTime so time again are set to 30secs? + } + + void JustDied(Unit* pKiller) + { + int32 iTextId = 0; + uint32 uiSpellId = 0; + + switch(m_creature->GetEntry()) + { + case NPC_TENEBRON: + iTextId = SAY_TENEBRON_DEATH; + uiSpellId = SPELL_POWER_OF_TENEBRON; + break; + case NPC_SHADRON: + iTextId = SAY_SHADRON_DEATH; + uiSpellId = SPELL_POWER_OF_SHADRON; + break; + case NPC_VESPERON: + iTextId = SAY_VESPERON_DEATH; + uiSpellId = SPELL_POWER_OF_VESPERON; + break; + } + + DoScriptText(iTextId, m_creature); + + m_creature->RemoveOwnedAura(uiSpellId); + + if (pInstance) + { + // not if solo mini-boss fight + if (pInstance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) + return; + + // Twilight Revenge to main boss + if (Unit* pSartharion = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_SARTHARION))) + if (pSartharion->isAlive()) + DoCast(pSartharion, SPELL_TWILIGHT_REVENGE, true); + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (m_bCanMoveFree && m_uiMoveNextTimer) + { + if (m_uiMoveNextTimer <= uiDiff) + { + if(m_uiWaypointId < MAX_WAYPOINT) + m_creature->GetMotionMaster()->MovePoint(m_uiWaypointId, + m_aDragonCommon[m_uiWaypointId].m_fX, m_aDragonCommon[m_uiWaypointId].m_fY, m_aDragonCommon[m_uiWaypointId].m_fZ); + + debug_log("dummy_dragonAI: %s moving to point %u", m_creature->GetName(), m_uiWaypointId); + m_uiMoveNextTimer = 0; + } + else + m_uiMoveNextTimer -= uiDiff; + } + } +}; + +/*###### +## Mob Tenebron +######*/ + +struct TRINITY_DLL_DECL mob_tenebronAI : public dummy_dragonAI +{ + mob_tenebronAI(Creature* pCreature) : dummy_dragonAI(pCreature) {} + + uint32 m_uiShadowBreathTimer; + uint32 m_uiShadowFissureTimer; + uint32 m_uiHatchEggTimer; + + void Reset() + { + m_uiShadowBreathTimer = 20000; + m_uiShadowFissureTimer = 5000; + m_uiHatchEggTimer = 30000; + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_TENEBRON_AGGRO, m_creature); + DoZoneInCombat(); + DoCast(m_creature, SPELL_POWER_OF_TENEBRON); + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_TENEBRON_SLAY_1,SAY_TENEBRON_SLAY_2), m_creature); + } + + void UpdateAI(const uint32 uiDiff) + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(uiDiff); + return; + } + + // shadow fissure + if (m_uiShadowFissureTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE)); + + m_uiShadowFissureTimer = urand(15000,20000); + } + else + m_uiShadowFissureTimer -= uiDiff; + + // shadow breath + if (m_uiShadowBreathTimer <= uiDiff) + { + DoScriptText(SAY_TENEBRON_BREATH, m_creature); + DoCast(m_creature->getVictim(), RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); + m_uiShadowBreathTimer = urand(20000,25000); + } + else + m_uiShadowBreathTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_tenebron(Creature* pCreature) +{ + return new mob_tenebronAI(pCreature); +} + +/*###### +## Mob Shadron +######*/ + +struct TRINITY_DLL_DECL mob_shadronAI : public dummy_dragonAI +{ + mob_shadronAI(Creature* pCreature) : dummy_dragonAI(pCreature) {} + + uint32 m_uiShadowBreathTimer; + uint32 m_uiShadowFissureTimer; + uint32 m_uiAcolyteShadronTimer; + + void Reset() + { + m_uiShadowBreathTimer = 20000; + m_uiShadowFissureTimer = 5000; + m_uiAcolyteShadronTimer = 60000; + + if (m_creature->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) + m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + + if (m_creature->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) + m_creature->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_SHADRON_AGGRO,m_creature); + DoZoneInCombat(); + DoCast(m_creature, SPELL_POWER_OF_SHADRON); + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_SHADRON_SLAY_1,SAY_SHADRON_SLAY_2), m_creature); + } + + void UpdateAI(const uint32 uiDiff) + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(uiDiff); + return; + } + + // shadow fissure + if (m_uiShadowFissureTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE_H)); + + m_uiShadowFissureTimer = urand(15000,20000); + } + else + m_uiShadowFissureTimer -= uiDiff; + + // shadow breath + if (m_uiShadowBreathTimer <= uiDiff) + { + DoScriptText(SAY_SHADRON_BREATH, m_creature); + DoCast(m_creature->getVictim(), RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); + m_uiShadowBreathTimer = urand(20000,25000); + } + else + m_uiShadowBreathTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_shadron(Creature* pCreature) +{ + return new mob_shadronAI(pCreature); +} + +/*###### +## Mob Vesperon +######*/ + +struct TRINITY_DLL_DECL mob_vesperonAI : public dummy_dragonAI +{ + mob_vesperonAI(Creature* pCreature) : dummy_dragonAI(pCreature) {} + + uint32 m_uiShadowBreathTimer; + uint32 m_uiShadowFissureTimer; + uint32 m_uiAcolyteVesperonTimer; + + void Reset() + { + m_uiShadowBreathTimer = 20000; + m_uiShadowFissureTimer = 5000; + m_uiAcolyteVesperonTimer = 60000; + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_VESPERON_AGGRO,m_creature); + DoZoneInCombat(); + DoCast(m_creature, SPELL_POWER_OF_VESPERON); + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_VESPERON_SLAY_1,SAY_VESPERON_SLAY_2), m_creature); + } + + void UpdateAI(const uint32 uiDiff) + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(uiDiff); + return; + } + + // shadow fissure + if (m_uiShadowFissureTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE_H)); + + m_uiShadowFissureTimer = urand(15000,20000); + } + else + m_uiShadowFissureTimer -= uiDiff; + + // shadow breath + if (m_uiShadowBreathTimer <= uiDiff) + { + DoScriptText(SAY_VESPERON_BREATH, m_creature); + DoCast(m_creature->getVictim(), RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); + m_uiShadowBreathTimer = urand(20000,25000); + } + else + m_uiShadowBreathTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_vesperon(Creature* pCreature) +{ + return new mob_vesperonAI(pCreature); +} + +/*###### +## Mob Acolyte of Shadron +######*/ + +struct TRINITY_DLL_DECL mob_acolyte_of_shadronAI : public ScriptedAI +{ + mob_acolyte_of_shadronAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void Reset() + { + if (pInstance) + { + //if not solo figth, buff main boss, else place debuff on mini-boss. both spells TARGET_SCRIPT + if (pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + DoCast(m_creature, SPELL_GIFT_OF_TWILIGTH_SAR); + else + DoCast(m_creature, SPELL_GIFT_OF_TWILIGTH_SHA); + } + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + Creature* pDebuffTarget = NULL; + + if (pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + { + //not solo fight, so main boss has deduff + pDebuffTarget = pInstance->instance->GetCreature(pInstance->GetData64(DATA_SARTHARION)); + + if (pDebuffTarget && pDebuffTarget->isAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SAR)) + pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SAR); + } + else + { + //event not in progress, then solo fight and must remove debuff mini-boss + pDebuffTarget = pInstance->instance->GetCreature(pInstance->GetData64(DATA_SHADRON)); + + if (pDebuffTarget && pDebuffTarget->isAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) + pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_acolyte_of_shadron(Creature* pCreature) +{ + return new mob_acolyte_of_shadronAI(pCreature); +} + +/*###### +## Mob Acolyte of Vesperon +######*/ + +struct TRINITY_DLL_DECL mob_acolyte_of_vesperonAI : public ScriptedAI +{ + mob_acolyte_of_vesperonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void Reset() + { + DoCast(m_creature, SPELL_TWILIGHT_TORMENT_VESP_ACO); + } + + void JustDied(Unit* pKiller) + { + // remove twilight torment on Vesperon + if (pInstance) + { + Creature* pVesperon = pInstance->instance->GetCreature(pInstance->GetData64(DATA_VESPERON)); + + if (pVesperon && pVesperon->isAlive() && pVesperon->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) + pVesperon->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_acolyte_of_vesperon(Creature* pCreature) +{ + return new mob_acolyte_of_vesperonAI(pCreature); +} + +/*###### +## Mob Twilight Eggs +######*/ + +struct TRINITY_DLL_DECL mob_twilight_eggsAI : public ScriptedAI +{ + mob_twilight_eggsAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 m_uiFadeArmorTimer; + + void Reset() + { + m_uiFadeArmorTimer = 1000; + } + + void AttackStart(Unit* pWho) {} + void MoveInLineOfSight(Unit* pWho) {} +}; + +CreatureAI* GetAI_mob_twilight_eggs(Creature* pCreature) +{ + return new mob_twilight_eggsAI(pCreature); +} + +/*###### +## Mob Twilight Whelps +######*/ + +struct TRINITY_DLL_DECL mob_twilight_whelpAI : public ScriptedAI +{ + mob_twilight_whelpAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 m_uiFadeArmorTimer; + + void Reset() + { + m_uiFadeArmorTimer = 1000; + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + // twilight torment + if (m_uiFadeArmorTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_FADE_ARMOR); + m_uiFadeArmorTimer = urand(5000,10000); + } + else + m_uiFadeArmorTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_twilight_whelp(Creature* pCreature) +{ + return new mob_twilight_whelpAI(pCreature); +} + +void AddSC_boss_sartharion() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_sartharion"; + newscript->GetAI = &GetAI_boss_sartharion; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_vesperon"; + newscript->GetAI = &GetAI_mob_vesperon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_shadron"; + newscript->GetAI = &GetAI_mob_shadron; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_tenebron"; + newscript->GetAI = &GetAI_mob_tenebron; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_acolyte_of_shadron"; + newscript->GetAI = &GetAI_mob_acolyte_of_shadron; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_acolyte_of_vesperon"; + newscript->GetAI = &GetAI_mob_acolyte_of_vesperon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_twilight_eggs"; + newscript->GetAI = &GetAI_mob_twilight_eggs; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_twilight_whelp"; + newscript->GetAI = &GetAI_mob_twilight_whelp; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp b/src/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp new file mode 100644 index 00000000000..1d4b38270d9 --- /dev/null +++ b/src/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp @@ -0,0 +1,97 @@ +#include "ScriptedPch.h" +#include "obsidian_sanctum.h" + +#define MAX_ENCOUNTER 1 + +/* Obsidian Sanctum encounters: +0 - Sartharion +*/ + +struct TRINITY_DLL_DECL instance_obsidian_sanctum : public ScriptedInstance +{ + instance_obsidian_sanctum(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + uint64 m_uiSartharionGUID; + uint64 m_uiTenebronGUID; + uint64 m_uiShadronGUID; + uint64 m_uiVesperonGUID; + + void Initialize() + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + m_uiSartharionGUID = 0; + m_uiTenebronGUID = 0; + m_uiShadronGUID = 0; + m_uiVesperonGUID = 0; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case NPC_SARTHARION: + m_uiSartharionGUID = pCreature->GetGUID(); + break; + //three dragons below set to active state once created. + //we must expect bigger raid to encounter main boss, and then three dragons must be active due to grid differences + case NPC_TENEBRON: + m_uiTenebronGUID = pCreature->GetGUID(); + pCreature->setActive(true); + break; + case NPC_SHADRON: + m_uiShadronGUID = pCreature->GetGUID(); + pCreature->setActive(true); + break; + case NPC_VESPERON: + m_uiVesperonGUID = pCreature->GetGUID(); + pCreature->setActive(true); + break; + } + } + + void SetData(uint32 uiType, uint32 uiData) + { + if (uiType == TYPE_SARTHARION_EVENT) + m_auiEncounter[0] = uiData; + } + + uint32 GetData(uint32 uiType) + { + if (uiType == TYPE_SARTHARION_EVENT) + return m_auiEncounter[0]; + + return 0; + } + + uint64 GetData64(uint32 uiData) + { + switch(uiData) + { + case DATA_SARTHARION: + return m_uiSartharionGUID; + case DATA_TENEBRON: + return m_uiTenebronGUID; + case DATA_SHADRON: + return m_uiShadronGUID; + case DATA_VESPERON: + return m_uiVesperonGUID; + } + return 0; + } +}; + +InstanceData* GetInstanceData_instance_obsidian_sanctum(Map* pMap) +{ + return new instance_obsidian_sanctum(pMap); +} + +void AddSC_instance_obsidian_sanctum() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_obsidian_sanctum"; + newscript->GetInstanceData = &GetInstanceData_instance_obsidian_sanctum; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h b/src/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h new file mode 100644 index 00000000000..59013174795 --- /dev/null +++ b/src/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h @@ -0,0 +1,20 @@ +#ifndef DEF_OBSIDIAN_SANCTUM_H +#define DEF_OBSIDIAN_SANCTUM_H + +enum eTypes +{ + TYPE_SARTHARION_EVENT = 1, + + DATA_SARTHARION = 10, + DATA_TENEBRON = 11, + DATA_SHADRON = 12, + DATA_VESPERON = 13, + + NPC_SARTHARION = 28860, + NPC_TENEBRON = 30452, + NPC_SHADRON = 30451, + NPC_VESPERON = 30449, + GO_TWILIGHT_PORTAL = 193988 +}; + +#endif diff --git a/src/scripts/northrend/sholazar_basin.cpp b/src/scripts/northrend/sholazar_basin.cpp new file mode 100644 index 00000000000..38445c4b515 --- /dev/null +++ b/src/scripts/northrend/sholazar_basin.cpp @@ -0,0 +1,328 @@ +/* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Sholazar_Basin +SD%Complete: 100 +SDComment: Quest support: 12570, 12573, 12621. +SDCategory: Sholazar_Basin +EndScriptData */ + +/* ContentData +npc_injured_rainspeaker_oracle +npc_vekjik +avatar_of_freya +EndContentData */ + +#include "ScriptedPch.h" +#include "ScriptedEscortAI.h" + +/*###### +## npc_injured_rainspeaker_oracle +######*/ + +#define GOSSIP_ITEM1 "I am ready to travel to your village now." + +enum eRainspeaker +{ + SAY_START_IRO = -1571000, + SAY_QUEST_ACCEPT_IRO = -1571001, + SAY_END_IRO = -1571002, + + QUEST_FORTUNATE_MISUNDERSTANDINGS = 12570, + FACTION_ESCORTEE_A = 774, + FACTION_ESCORTEE_H = 775 +}; + +struct TRINITY_DLL_DECL npc_injured_rainspeaker_oracleAI : public npc_escortAI +{ + npc_injured_rainspeaker_oracleAI(Creature* c) : npc_escortAI(c) { c_guid = c->GetGUID(); } + + uint64 c_guid; + + void Reset() + { + me->RestoreFaction(); + // if we will have other way to assign this to only one npc remove this part + if (GUID_LOPART(me->GetGUID()) != 101030) + { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + } + + void WaypointReached(uint32 i) + { + Player* pPlayer = GetPlayerForEscort(); + + if (!pPlayer) + return; + + switch(i) + { + case 1: SetRun(); break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_JUMPING); + m_creature->SetSpeed(MOVE_SWIM, 0.85f, true); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_LEVITATING); + break; + case 19: + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_JUMPING); + break; + case 28: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_FORTUNATE_MISUNDERSTANDINGS, m_creature); + // me->RestoreFaction(); + DoScriptText(SAY_END_IRO,m_creature); + SetRun(false); + break; + } + } + + void JustDied(Unit* killer) + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + if (Player* pPlayer = GetPlayerForEscort()) + { + if (pPlayer->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) != QUEST_STATUS_COMPLETE) + pPlayer->FailQuest(QUEST_FORTUNATE_MISUNDERSTANDINGS); + } + } +}; + +bool GossipHello_npc_injured_rainspeaker_oracle(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_injured_rainspeaker_oracle(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + CAST_AI(npc_escortAI, (pCreature->AI()))->Start(true, false, pPlayer->GetGUID()); + CAST_AI(npc_escortAI, (pCreature->AI()))->SetMaxPlayerDistance(35.0f); + pCreature->SetUnitMovementFlags(MOVEMENTFLAG_JUMPING); + DoScriptText(SAY_START_IRO, pCreature); + + switch (pPlayer->GetTeam()){ + case ALLIANCE: + pCreature->setFaction(FACTION_ESCORTEE_A); + break; + case HORDE: + pCreature->setFaction(FACTION_ESCORTEE_H); + break; + } + } + return true; +} + +bool QuestAccept_npc_injured_rainspeaker_oracle(Player* pPlayer, Creature* pCreature, Quest const *_Quest) +{ + DoScriptText(SAY_QUEST_ACCEPT_IRO, pCreature); + return false; +} + +CreatureAI* GetAI_npc_injured_rainspeaker_oracle(Creature* pCreature) +{ + return new npc_injured_rainspeaker_oracleAI(pCreature); +} + +/*###### +## npc_vekjik +######*/ + +#define GOSSIP_VEKJIK_ITEM1 "Shaman Vekjik, I have spoken with the big-tongues and they desire peace. I have brought this offering on their behalf." +#define GOSSIP_VEKJIK_ITEM2 "No no... I had no intentions of betraying your people. I was only defending myself. it was all a misunderstanding." + +enum eVekjik +{ + GOSSIP_TEXTID_VEKJIK1 = 13137, + GOSSIP_TEXTID_VEKJIK2 = 13138, + + SAY_TEXTID_VEKJIK1 = -1000208, + + SPELL_FREANZYHEARTS_FURY = 51469, + + QUEST_MAKING_PEACE = 12573 +}; + +bool GossipHello_npc_vekjik(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_MAKING_PEACE) == QUEST_STATUS_INCOMPLETE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_VEKJIK_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VEKJIK1, pCreature->GetGUID()); + return true; + } + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_vekjik(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_VEKJIK_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VEKJIK2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->CLOSE_GOSSIP_MENU(); + DoScriptText(SAY_TEXTID_VEKJIK1, pCreature, pPlayer); + pPlayer->AreaExploredOrEventHappens(QUEST_MAKING_PEACE); + pCreature->CastSpell(pPlayer, SPELL_FREANZYHEARTS_FURY, false); + break; + } + + return true; +} + +/*###### +## avatar_of_freya +######*/ + +#define GOSSIP_ITEM_AOF1 "I want to stop the Scourge as much as you do. How can I help?" +#define GOSSIP_ITEM_AOF2 "You can trust me. I am no friend of the Lich King." +#define GOSSIP_ITEM_AOF3 "I will not fail." + +enum eFreya +{ + QUEST_FREYA_PACT = 12621, + + SPELL_FREYA_CONVERSATION = 52045, + + GOSSIP_TEXTID_AVATAR1 = 13303, + GOSSIP_TEXTID_AVATAR2 = 13304, + GOSSIP_TEXTID_AVATAR3 = 13305 +}; + +bool GossipHello_npc_avatar_of_freya(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_FREYA_PACT) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AOF1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->PlayerTalkClass->SendGossipMenu(GOSSIP_TEXTID_AVATAR1, pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_avatar_of_freya(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AOF2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->PlayerTalkClass->SendGossipMenu(GOSSIP_TEXTID_AVATAR2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AOF3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->PlayerTalkClass->SendGossipMenu(GOSSIP_TEXTID_AVATAR3, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->CastSpell(pPlayer, SPELL_FREYA_CONVERSATION, true); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + } + return true; +} + +/*###### +## npc_geezle +######*/ + +struct TRINITY_DLL_DECL npc_bushwhackerAI : public ScriptedAI +{ + npc_bushwhackerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + MoveToSummoner(); + } + + void MoveToSummoner() + { + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + if (pSummoner) + m_creature->GetMotionMaster()->MovePoint(0,pSummoner->GetPositionX(),pSummoner->GetPositionY(),pSummoner->GetPositionZ()); + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_bushwhacker(Creature* pCreature) +{ + return new npc_bushwhackerAI(pCreature); +} + +void AddSC_sholazar_basin() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "npc_injured_rainspeaker_oracle"; + newscript->GetAI = &GetAI_npc_injured_rainspeaker_oracle; + newscript->pGossipHello = &GossipHello_npc_injured_rainspeaker_oracle; + newscript->pGossipSelect = &GossipSelect_npc_injured_rainspeaker_oracle; + newscript->pQuestAccept = &QuestAccept_npc_injured_rainspeaker_oracle; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_vekjik"; + newscript->pGossipHello = &GossipHello_npc_vekjik; + newscript->pGossipSelect = &GossipSelect_npc_vekjik; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_avatar_of_freya"; + newscript->pGossipHello = &GossipHello_npc_avatar_of_freya; + newscript->pGossipSelect = &GossipSelect_npc_avatar_of_freya; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_bushwhacker"; + newscript->GetAI = &GetAI_npc_bushwhacker; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/storm_peaks.cpp b/src/scripts/northrend/storm_peaks.cpp new file mode 100644 index 00000000000..9086bfbfc6e --- /dev/null +++ b/src/scripts/northrend/storm_peaks.cpp @@ -0,0 +1,389 @@ +/* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" + +/*###### +## npc_agnetta_tyrsdottar +######*/ + +#define SAY_AGGRO -1571003 +#define GOSSIP_AGNETTA "Skip the warmup, sister... or are you too scared to face soemeone your own size?" + +enum eAgnetta +{ + QUEST_ITS_THAT_YOUR_GOBLIN = 12969, + FACTION_HOSTILE_AT1 = 45 +}; + +struct TRINITY_DLL_DECL npc_agnetta_tyrsdottarAI : public ScriptedAI +{ + npc_agnetta_tyrsdottarAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + void Reset() + { + me->RestoreFaction(); + } +}; + +CreatureAI* GetAI_npc_agnetta_tyrsdottar(Creature* pCreature) +{ + return new npc_agnetta_tyrsdottarAI(pCreature); +} + +bool GossipHello_npc_agnetta_tyrsdottar(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->GetQuestStatus(QUEST_ITS_THAT_YOUR_GOBLIN) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_AGNETTA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(13691, pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_agnetta_tyrsdottar(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction ) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + DoScriptText(SAY_AGGRO, pCreature); + pPlayer->CLOSE_GOSSIP_MENU(); + pCreature->setFaction(FACTION_HOSTILE_AT1); + pCreature->AI()->AttackStart(pPlayer); + } + + return true; +} + +/*###### +## npc_frostborn_scout +######*/ + +#define GOSSIP_ITEM1 "Are you okay? I've come to take you back to Frosthold if you can stand." +#define GOSSIP_ITEM2 "I'm sorry that I didn't get here sooner. What happened?" +#define GOSSIP_ITEM3 "I'll go get some help. Hang in there." + +enum eFrostbornScout +{ + QUEST_MISSING_SCOUTS = 12864 +}; + +bool GossipHello_npc_frostborn_scout(Player* pPlayer, Creature* pCreature) +{ + + if (pPlayer->GetQuestStatus(QUEST_MISSING_SCOUTS) == QUEST_STATUS_INCOMPLETE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->PlayerTalkClass->SendGossipMenu(13611, pCreature->GetGUID()); + } + + return true; +} + +bool GossipSelect_npc_frostborn_scout(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->PlayerTalkClass->SendGossipMenu(13612, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->PlayerTalkClass->SendGossipMenu(13613, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->PlayerTalkClass->SendGossipMenu(13614, pCreature->GetGUID()); + pPlayer->AreaExploredOrEventHappens(QUEST_MISSING_SCOUTS); + break; + } + + return true; +} + +/*###### +## npc_thorim +######*/ + +#define GOSSIP_HN "Thorim?" +#define GOSSIP_SN1 "Can you tell me what became of Sif?" +#define GOSSIP_SN2 "He did more than that, Thorim. He controls Ulduar now." +#define GOSSIP_SN3 "It needn't end this way." + +enum eThorim +{ + QUEST_SIBLING_RIVALRY = 13064, + NPC_THORIM = 29445, + GOSSIP_TEXTID_THORIM1 = 13799, + GOSSIP_TEXTID_THORIM2 = 13801, + GOSSIP_TEXTID_THORIM3 = 13802, + GOSSIP_TEXTID_THORIM4 = 13803 +}; + +bool GossipHello_npc_thorim(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_SIBLING_RIVALRY) == QUEST_STATUS_INCOMPLETE) { + pPlayer->ADD_GOSSIP_ITEM(0, GOSSIP_HN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM1, pCreature->GetGUID()); + return true; + } + return false; +} + +bool GossipSelect_npc_thorim(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(0, GOSSIP_SN1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(0, GOSSIP_SN2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM3, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->ADD_GOSSIP_ITEM(0, GOSSIP_SN3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM4, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->AreaExploredOrEventHappens(QUEST_SIBLING_RIVALRY); + break; + } + return true; +} + +/*###### +## npc_goblin_prisoner +######*/ + +enum eGoblinPrisoner +{ + GO_RUSTY_CAGE = 191544 +}; + +struct TRINITY_DLL_DECL npc_goblin_prisonerAI : public ScriptedAI +{ + npc_goblin_prisonerAI(Creature* pCreature) : ScriptedAI (pCreature){} + + void Reset() + { + m_creature->SetReactState(REACT_PASSIVE); + + if(GameObject* pGO = m_creature->FindNearestGameObject(GO_RUSTY_CAGE,5.0f)) + { + if(pGO->GetGoState() == GO_STATE_ACTIVE) + pGO->SetGoState(GO_STATE_READY); + } + } + +}; + +CreatureAI* GetAI_npc_goblin_prisoner(Creature* pCreature) +{ + return new npc_goblin_prisonerAI(pCreature); +} + +/*###### +## npc_victorious_challenger +######*/ + +#define GOSSIP_CHALLENGER "Let's do this, sister." + +enum eVictoriousChallenger +{ + QUEST_TAKING_ALL_CHALLENGERS = 12971, + QUEST_DEFENDING_YOUR_TITLE = 13423, + + SPELL_SUNDER_ARMOR = 11971, + SPELL_REND_VC = 11977 +}; + +struct TRINITY_DLL_DECL npc_victorious_challengerAI : public ScriptedAI +{ + npc_victorious_challengerAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 SunderArmorTimer; + uint32 RendTimer; + + void Reset() + { + m_creature->RestoreFaction(); + + SunderArmorTimer = 10000; + RendTimer = 15000; + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if(RendTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_REND_VC, true); + RendTimer = 15000; + }else RendTimer -= diff; + + if(SunderArmorTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SUNDER_ARMOR, true); + SunderArmorTimer = 10000; + }else SunderArmorTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void KilledUnit(Unit* victim) + { + m_creature->RestoreFaction(); + } + +}; + +bool GossipHello_npc_victorious_challenger(Player* pPlayer, Creature* pCreature) +{ + if(pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_TAKING_ALL_CHALLENGERS) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_DEFENDING_YOUR_TITLE) == QUEST_STATUS_INCOMPLETE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_CHALLENGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; + } + + return false; +} + +bool GossipSelect_npc_victorious_challenger(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction ) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + pCreature->setFaction(14); + pCreature->AI()->AttackStart(pPlayer); + } + + return true; +} + +CreatureAI* GetAI_npc_victorious_challenger(Creature* pCreature) +{ + return new npc_victorious_challengerAI(pCreature); +} + +/*###### +## npc_loklira_crone +######*/ + +#define GOSSIP_LOKLIRACRONE "Tell me about this proposal" +#define GOSSIP_LOKLIRACRONE1 "What happened then?" +#define GOSSIP_LOKLIRACRONE2 "You want me to take part in the Hyldsmeet to end the war?" +#define GOSSIP_LOKLIRACRONE3 "Very well. I'll take part in this competition." + +enum eLokliraCrone +{ + QUEST_HYLDSMEET = 12970, + + GOSSIP_TEXTID_LOK1 = 13778, + GOSSIP_TEXTID_LOK2 = 13779, + GOSSIP_TEXTID_LOK3 = 13780 +}; + +bool GossipHello_npc_loklira_crone(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_HYLDSMEET) == QUEST_STATUS_INCOMPLETE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOKLIRACRONE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; + } + return false; +} + +bool GossipSelect_npc_loklira_crone(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOKLIRACRONE1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LOK1, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOKLIRACRONE2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LOK2, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOKLIRACRONE3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LOK3, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->CompleteQuest(QUEST_HYLDSMEET); + break; + } + return true; +} + +void AddSC_storm_peaks() +{ + Script* newscript; + + newscript = new Script; + newscript->Name = "npc_agnetta_tyrsdottar"; + newscript->GetAI = &GetAI_npc_agnetta_tyrsdottar; + newscript->pGossipHello = &GossipHello_npc_agnetta_tyrsdottar; + newscript->pGossipSelect = &GossipSelect_npc_agnetta_tyrsdottar; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_frostborn_scout"; + newscript->pGossipHello = &GossipHello_npc_frostborn_scout; + newscript->pGossipSelect = &GossipSelect_npc_frostborn_scout; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_thorim"; + newscript->pGossipHello = &GossipHello_npc_thorim; + newscript->pGossipSelect = &GossipSelect_npc_thorim; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_goblin_prisoner"; + newscript->GetAI = &GetAI_npc_goblin_prisoner; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_victorious_challenger"; + newscript->GetAI = &GetAI_npc_victorious_challenger; + newscript->pGossipHello = &GossipHello_npc_victorious_challenger; + newscript->pGossipSelect = &GossipSelect_npc_victorious_challenger; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_loklira_crone"; + newscript->pGossipHello = &GossipHello_npc_loklira_crone; + newscript->pGossipSelect = &GossipSelect_npc_loklira_crone; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp b/src/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp new file mode 100644 index 00000000000..d1dc90cd6bf --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp @@ -0,0 +1,432 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss General Bjarngrim +SD%Complete: 70% +SDComment: Waypoint needed, we expect boss to always have 2x Stormforged Lieutenant following +SDCategory: Halls of Lightning +EndScriptData */ + +#include "ScriptedPch.h" +#include "halls_of_lightning.h" + +enum eEnums +{ + //Yell + SAY_AGGRO = -1602000, + SAY_SLAY_1 = -1602001, + SAY_SLAY_2 = -1602002, + SAY_SLAY_3 = -1602003, + SAY_DEATH = -1602004, + SAY_BATTLE_STANCE = -1602005, + EMOTE_BATTLE_STANCE = -1602006, + SAY_BERSEKER_STANCE = -1602007, + EMOTE_BERSEKER_STANCE = -1602008, + SAY_DEFENSIVE_STANCE = -1602009, + EMOTE_DEFENSIVE_STANCE = -1602010, + + SPELL_DEFENSIVE_STANCE = 53790, + //SPELL_DEFENSIVE_AURA = 41105, + SPELL_SPELL_REFLECTION = 36096, + SPELL_PUMMEL = 12555, + SPELL_KNOCK_AWAY = 52029, + SPELL_IRONFORM = 52022, + + SPELL_BERSEKER_STANCE = 53791, + //SPELL_BERSEKER_AURA = 41107, + SPELL_INTERCEPT = 58769, + SPELL_WHIRLWIND = 52027, + SPELL_CLEAVE = 15284, + + SPELL_BATTLE_STANCE = 53792, + //SPELL_BATTLE_AURA = 41106, + SPELL_MORTAL_STRIKE = 16856, + SPELL_SLAM = 52026, + + //OTHER SPELLS + //SPELL_CHARGE_UP = 52098, // only used when starting walk from one platform to the other + //SPELL_TEMPORARY_ELECTRICAL_CHARGE = 52092, // triggered part of above + + NPC_STORMFORGED_LIEUTENANT = 29240, + SPELL_ARC_WELD = 59085, + SPELL_RENEW_STEEL_N = 52774, + SPELL_RENEW_STEEL_H = 59160, + + EQUIP_SWORD = 37871, + EQUIP_SHIELD = 35642, + EQUIP_MACE = 43623, + + STANCE_DEFENSIVE = 0, + STANCE_BERSERKER = 1, + STANCE_BATTLE = 2 +}; + +/*###### +## boss_bjarngrim +######*/ + +struct TRINITY_DLL_DECL boss_bjarngrimAI : public ScriptedAI +{ + boss_bjarngrimAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + m_uiStance = STANCE_DEFENSIVE; + memset(&m_auiStormforgedLieutenantGUID, 0, sizeof(m_auiStormforgedLieutenantGUID)); + } + + ScriptedInstance* m_pInstance; + + bool m_bIsChangingStance; + + uint8 m_uiChargingStatus; + uint8 m_uiStance; + + uint32 m_uiCharge_Timer; + uint32 m_uiChangeStance_Timer; + + uint32 m_uiReflection_Timer; + uint32 m_uiKnockAway_Timer; + uint32 m_uiPummel_Timer; + uint32 m_uiIronform_Timer; + + uint32 m_uiIntercept_Timer; + uint32 m_uiWhirlwind_Timer; + uint32 m_uiCleave_Timer; + + uint32 m_uiMortalStrike_Timer; + uint32 m_uiSlam_Timer; + + uint64 m_auiStormforgedLieutenantGUID[2]; + + void Reset() + { + m_bIsChangingStance = false; + + m_uiChargingStatus = 0; + m_uiCharge_Timer = 1000; + + m_uiChangeStance_Timer = 20000 + rand()%5000; + + m_uiReflection_Timer = 8000; + m_uiKnockAway_Timer = 20000; + m_uiPummel_Timer = 10000; + m_uiIronform_Timer = 25000; + + m_uiIntercept_Timer = 5000; + m_uiWhirlwind_Timer = 10000; + m_uiCleave_Timer = 8000; + + m_uiMortalStrike_Timer = 8000; + m_uiSlam_Timer = 10000; + + for (uint8 i = 0; i < 2; ++i) + { + if (Creature* pStormforgedLieutenant = (Unit::GetCreature((*m_creature), m_auiStormforgedLieutenantGUID[i]))) + { + if (!pStormforgedLieutenant->isAlive()) + pStormforgedLieutenant->Respawn(); + } + } + + if (m_uiStance != STANCE_DEFENSIVE) + { + DoRemoveStanceAura(m_uiStance); + DoCast(m_creature, SPELL_DEFENSIVE_STANCE); + m_uiStance = STANCE_DEFENSIVE; + } + + SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SHIELD, EQUIP_NO_CHANGE); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, NOT_STARTED); + } + + void EnterCombat(Unit* pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + + //must get both lieutenants here and make sure they are with him + m_creature->CallForHelp(30.0f); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, IN_PROGRESS); + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void JustDied(Unit* pKiller) + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, DONE); + } + + //TODO: remove when removal is done by mangos + void DoRemoveStanceAura(uint8 uiStance) + { + switch(uiStance) + { + case STANCE_DEFENSIVE: + m_creature->RemoveAurasDueToSpell(SPELL_DEFENSIVE_STANCE); + break; + case STANCE_BERSERKER: + m_creature->RemoveAurasDueToSpell(SPELL_BERSEKER_STANCE); + break; + case STANCE_BATTLE: + m_creature->RemoveAurasDueToSpell(SPELL_BATTLE_STANCE); + break; + } + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + // Change stance + if (m_uiChangeStance_Timer <= uiDiff) + { + //wait for current spell to finish before change stance + if (m_creature->IsNonMeleeSpellCasted(false)) + return; + + DoRemoveStanceAura(m_uiStance); + + int uiTempStance = rand()%(3-1); + + if (uiTempStance >= m_uiStance) + ++uiTempStance; + + m_uiStance = uiTempStance; + + switch(m_uiStance) + { + case STANCE_DEFENSIVE: + DoScriptText(SAY_DEFENSIVE_STANCE, m_creature); + DoScriptText(EMOTE_DEFENSIVE_STANCE, m_creature); + DoCast(m_creature, SPELL_DEFENSIVE_STANCE); + SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SHIELD, EQUIP_NO_CHANGE); + break; + case STANCE_BERSERKER: + DoScriptText(SAY_BERSEKER_STANCE, m_creature); + DoScriptText(EMOTE_BERSEKER_STANCE, m_creature); + DoCast(m_creature, SPELL_BERSEKER_STANCE); + SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SWORD, EQUIP_NO_CHANGE); + break; + case STANCE_BATTLE: + DoScriptText(SAY_BATTLE_STANCE, m_creature); + DoScriptText(EMOTE_BATTLE_STANCE, m_creature); + DoCast(m_creature, SPELL_BATTLE_STANCE); + SetEquipmentSlots(false, EQUIP_MACE, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + break; + } + + m_uiChangeStance_Timer = 20000 + rand()%5000; + return; + } + else + m_uiChangeStance_Timer -= uiDiff; + + switch(m_uiStance) + { + case STANCE_DEFENSIVE: + { + if (m_uiReflection_Timer <= uiDiff) + { + DoCast(m_creature, SPELL_SPELL_REFLECTION); + m_uiReflection_Timer = 8000 + rand()%1000; + } + else + m_uiReflection_Timer -= uiDiff; + + if (m_uiKnockAway_Timer <= uiDiff) + { + DoCast(m_creature, SPELL_KNOCK_AWAY); + m_uiKnockAway_Timer = 20000 + rand()%1000; + } + else + m_uiKnockAway_Timer -= uiDiff; + + if (m_uiPummel_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_PUMMEL); + m_uiPummel_Timer = 10000 + rand()%1000; + } + else + m_uiPummel_Timer -= uiDiff; + + if (m_uiIronform_Timer <= uiDiff) + { + DoCast(m_creature, SPELL_IRONFORM); + m_uiIronform_Timer = 25000 + rand()%1000; + } + else + m_uiIronform_Timer -= uiDiff; + + break; + } + case STANCE_BERSERKER: + { + if (m_uiIntercept_Timer <= uiDiff) + { + //not much point is this, better random target and more often? + DoCast(m_creature->getVictim(), SPELL_INTERCEPT); + m_uiIntercept_Timer = 45000 + rand()%1000; + } + else + m_uiIntercept_Timer -= uiDiff; + + if (m_uiWhirlwind_Timer <= uiDiff) + { + DoCast(m_creature, SPELL_WHIRLWIND); + m_uiWhirlwind_Timer = 10000 + rand()%1000; + } + else + m_uiWhirlwind_Timer -= uiDiff; + + if (m_uiCleave_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + m_uiCleave_Timer = 8000 + rand()%1000; + } + else + m_uiCleave_Timer -= uiDiff; + + break; + } + case STANCE_BATTLE: + { + if (m_uiMortalStrike_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); + m_uiMortalStrike_Timer = 20000 + rand()%1000; + } + else + m_uiMortalStrike_Timer -= uiDiff; + + if (m_uiSlam_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SLAM); + m_uiSlam_Timer = 15000 + rand()%1000; + } + else + m_uiSlam_Timer -= uiDiff; + + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## mob_stormforged_lieutenant +######*/ + +struct TRINITY_DLL_DECL mob_stormforged_lieutenantAI : public ScriptedAI +{ + mob_stormforged_lieutenantAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiArcWeld_Timer; + uint32 m_uiRenewSteel_Timer; + + void Reset() + { + m_uiArcWeld_Timer = 20000 + rand()%1000; + m_uiRenewSteel_Timer = 10000 + rand()%1000; + } + + void EnterCombat(Unit* pWho) + { + if (m_pInstance) + { + if (Creature* pBjarngrim = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_BJARNGRIM))) + { + if (pBjarngrim->isAlive() && !pBjarngrim->getVictim()) + pBjarngrim->AI()->AttackStart(pWho); + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (m_uiArcWeld_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_ARC_WELD); + m_uiArcWeld_Timer = 20000 + rand()%1000; + } + else + m_uiArcWeld_Timer -= uiDiff; + + if (m_uiRenewSteel_Timer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pBjarngrim = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_BJARNGRIM))) + { + if (pBjarngrim->isAlive()) + DoCast(pBjarngrim, DUNGEON_MODE(SPELL_RENEW_STEEL_N, SPELL_RENEW_STEEL_H)); + } + } + m_uiRenewSteel_Timer = 10000 + rand()%4000; + } + else + m_uiRenewSteel_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_bjarngrim(Creature* pCreature) +{ + return new boss_bjarngrimAI(pCreature); +} + +CreatureAI* GetAI_mob_stormforged_lieutenant(Creature* pCreature) +{ + return new mob_stormforged_lieutenantAI(pCreature); +} + +void AddSC_boss_bjarngrim() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_bjarngrim"; + newscript->GetAI = &GetAI_boss_bjarngrim; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_stormforged_lieutenant"; + newscript->GetAI = &GetAI_mob_stormforged_lieutenant; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp b/src/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp new file mode 100644 index 00000000000..7cb2b4ef634 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp @@ -0,0 +1,380 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss Ionar +SD%Complete: 80% +SDComment: Timer check +SDCategory: Halls of Lightning +EndScriptData */ + +#include "ScriptedPch.h" +#include "halls_of_lightning.h" + +enum eEnums +{ + SAY_AGGRO = -1602011, + SAY_SLAY_1 = -1602012, + SAY_SLAY_2 = -1602013, + SAY_SLAY_3 = -1602014, + SAY_DEATH = -1602015, + SAY_SPLIT_1 = -1602016, + SAY_SPLIT_2 = -1602017, + + SPELL_BALL_LIGHTNING_N = 52780, + SPELL_BALL_LIGHTNING_H = 59800, + SPELL_STATIC_OVERLOAD_N = 52658, + SPELL_STATIC_OVERLOAD_H = 59795, + + SPELL_DISPERSE = 52770, + SPELL_SUMMON_SPARK = 52746, + SPELL_SPARK_DESPAWN = 52776, + + //Spark of Ionar + SPELL_SPARK_VISUAL_TRIGGER_N = 52667, + SPELL_SPARK_VISUAL_TRIGGER_H = 59833, + + NPC_SPARK_OF_IONAR = 28926, + + MAX_SPARKS = 5, + POINT_CALLBACK = 0 +}; + +/*###### +## Boss Ionar +######*/ + +struct TRINITY_DLL_DECL boss_ionarAI : public ScriptedAI +{ + boss_ionarAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + std::list<uint64> m_lSparkGUIDList; + + bool m_bIsSplitPhase; + uint32 m_uiSplit_Timer; + uint32 m_uiSparkAtHomeCount; + + uint32 m_uiStaticOverload_Timer; + uint32 m_uiBallLightning_Timer; + + uint32 m_uiHealthAmountModifier; + + void Reset() + { + m_lSparkGUIDList.clear(); + + m_bIsSplitPhase = true; + m_uiSplit_Timer = 25000; + m_uiSparkAtHomeCount = 0; + + m_uiStaticOverload_Timer = 5000 + rand()%1000; + m_uiBallLightning_Timer = 10000 + rand()%1000; + + m_uiHealthAmountModifier = 1; + + if (m_creature->GetVisibility() == VISIBILITY_OFF) + m_creature->SetVisibility(VISIBILITY_ON); + } + + void AttackedBy(Unit* pAttacker) + { + if (m_creature->getVictim()) + return; + + if (m_creature->GetVisibility() == VISIBILITY_OFF) + return; + + AttackStart(pAttacker); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_IONAR, IN_PROGRESS); + } + + void JustReachedHome() + { + if (m_pInstance) + m_pInstance->SetData(TYPE_IONAR, NOT_STARTED); + } + + void AttackStart(Unit* pWho) + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + if (m_creature->GetVisibility() != VISIBILITY_OFF) + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + DespawnSpark(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_IONAR, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void DespawnSpark() + { + if (m_lSparkGUIDList.empty()) + return; + + for (std::list<uint64>::iterator itr = m_lSparkGUIDList.begin(); itr != m_lSparkGUIDList.end(); ++itr) + { + if (Creature* pTemp = Unit::GetCreature(*m_creature, *itr)) + { + if (pTemp->isAlive()) + pTemp->ForcedDespawn(); + } + } + + m_lSparkGUIDList.clear(); + } + + //make sparks come back + void CallBackSparks() + { + //should never be empty here, but check + if (m_lSparkGUIDList.empty()) + return; + + for (std::list<uint64>::iterator itr = m_lSparkGUIDList.begin(); itr != m_lSparkGUIDList.end(); ++itr) + { + if (Creature* pSpark = Unit::GetCreature(*m_creature, *itr)) + { + if (pSpark->isAlive()) + { + if (pSpark->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + pSpark->GetMotionMaster()->MovementExpired(); + + pSpark->SetSpeed(MOVE_RUN, pSpark->GetCreatureInfo()->speed * 2); + pSpark->GetMotionMaster()->MovePoint(POINT_CALLBACK, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + } + } + } + } + + void RegisterSparkAtHome() + { + ++m_uiSparkAtHomeCount; + } + + void JustSummoned(Creature* pSummoned) + { + if (pSummoned->GetEntry() == NPC_SPARK_OF_IONAR) + { + pSummoned->CastSpell(pSummoned, DUNGEON_MODE(SPELL_SPARK_VISUAL_TRIGGER_N,SPELL_SPARK_VISUAL_TRIGGER_H), true); + + Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(pTarget ? pTarget : m_creature->getVictim()); + + m_lSparkGUIDList.push_back(pSummoned->GetGUID()); + } + } + + void UpdateAI(const uint32 uiDiff) + { + // Splitted + if (m_creature->GetVisibility() == VISIBILITY_OFF) + { + /*if (!m_creature->getVictim()) + { + Reset(); + return; + }*/ + + if (m_uiSplit_Timer <= uiDiff) + { + m_uiSplit_Timer = 2500; + + // Return sparks to where Ionar splitted + if (m_bIsSplitPhase) + { + CallBackSparks(); + m_bIsSplitPhase = false; + } + // Lightning effect and restore Ionar + else if (m_uiSparkAtHomeCount == MAX_SPARKS) + { + m_creature->SetVisibility(VISIBILITY_ON); + DoCast(m_creature, SPELL_SPARK_DESPAWN, false); + + DespawnSpark(); + + m_uiSparkAtHomeCount = 0; + m_uiSplit_Timer = 25000; + m_bIsSplitPhase = true; + + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + { + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + } + else + m_uiSplit_Timer -= uiDiff; + + return; + } + + //Return since we have no target + if (!UpdateVictim()) + return; + + if (m_uiStaticOverload_Timer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, DUNGEON_MODE(SPELL_STATIC_OVERLOAD_N, SPELL_STATIC_OVERLOAD_H)); + + m_uiStaticOverload_Timer = 5000 + rand()%1000; + } + else + m_uiStaticOverload_Timer -= uiDiff; + + if (m_uiBallLightning_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_BALL_LIGHTNING_N, SPELL_BALL_LIGHTNING_H)); + m_uiBallLightning_Timer = 10000 + rand()%1000; + } + else + m_uiBallLightning_Timer -= uiDiff; + + // Health check + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < (100-(20*m_uiHealthAmountModifier))) + { + ++m_uiHealthAmountModifier; + + DoScriptText(RAND(SAY_SPLIT_1,SAY_SPLIT_2), m_creature); + + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + + DoCast(m_creature, SPELL_DISPERSE); + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ionar(Creature* pCreature) +{ + return new boss_ionarAI(pCreature); +} + +bool EffectDummyCreature_boss_ionar(Unit* pCaster, uint32 uiSpellId, uint32 uiEffIndex, Creature* pCreatureTarget) +{ + //always check spellid and effectindex + if (uiSpellId == SPELL_DISPERSE && uiEffIndex == 0) + { + if (pCreatureTarget->GetEntry() != NPC_IONAR) + return true; + + for (uint8 i = 0; i < MAX_SPARKS; ++i) + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_SUMMON_SPARK, true); + + pCreatureTarget->AttackStop(); + pCreatureTarget->SetVisibility(VISIBILITY_OFF); + + if (pCreatureTarget->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + pCreatureTarget->GetMotionMaster()->MovementExpired(); + + //always return true when we are handling this spell and effect + return true; + } + return false; +} + +/*###### +## mob_spark_of_ionar +######*/ + +struct TRINITY_DLL_DECL mob_spark_of_ionarAI : public ScriptedAI +{ + mob_spark_of_ionarAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + void Reset() { } + + void MovementInform(uint32 uiType, uint32 uiPointId) + { + if (uiType != POINT_MOTION_TYPE || !m_pInstance) + return; + + if (uiPointId == POINT_CALLBACK) + { + if (Creature* pIonar = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_IONAR))) + { + if (!pIonar->isAlive()) + { + m_creature->ForcedDespawn(); + return; + } + + if (boss_ionarAI* pIonarAI = dynamic_cast<boss_ionarAI*>(pIonar->AI())) + pIonarAI->RegisterSparkAtHome(); + } + else + m_creature->ForcedDespawn(); + } + } +}; + +CreatureAI* GetAI_mob_spark_of_ionar(Creature* pCreature) +{ + return new mob_spark_of_ionarAI(pCreature); +} + +void AddSC_boss_ionar() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_ionar"; + newscript->GetAI = &GetAI_boss_ionar; + newscript->pEffectDummyCreature = &EffectDummyCreature_boss_ionar; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_spark_of_ionar"; + newscript->GetAI = &GetAI_mob_spark_of_ionar; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp b/src/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp new file mode 100644 index 00000000000..b7cc283e2b9 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp @@ -0,0 +1,239 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss Loken +SD%Complete: 60% +SDComment: Missing intro. Remove hack of Pulsing Shockwave when core supports. Aura is not working (59414) +SDCategory: Halls of Lightning +EndScriptData */ + +#include "ScriptedPch.h" +#include "halls_of_lightning.h" + +#define MAX_ENCOUNTER_TIME 2 * 60 * 1000 + +enum eEnums +{ + ACHIEVEMENT_TIMELY_DEATH = 1867, + + SAY_AGGRO = -1602018, + SAY_INTRO_1 = -1602019, + SAY_INTRO_2 = -1602020, + SAY_SLAY_1 = -1602021, + SAY_SLAY_2 = -1602022, + SAY_SLAY_3 = -1602023, + SAY_DEATH = -1602024, + SAY_NOVA_1 = -1602025, + SAY_NOVA_2 = -1602026, + SAY_NOVA_3 = -1602027, + SAY_75HEALTH = -1602028, + SAY_50HEALTH = -1602029, + SAY_25HEALTH = -1602030, + EMOTE_NOVA = -1602031, + + SPELL_ARC_LIGHTNING = 52921, + SPELL_LIGHTNING_NOVA_N = 52960, + SPELL_LIGHTNING_NOVA_H = 59835, + + SPELL_PULSING_SHOCKWAVE_N = 52961, + SPELL_PULSING_SHOCKWAVE_H = 59836, + SPELL_PULSING_SHOCKWAVE_AURA = 59414 +}; + +/*###### +## Boss Loken +######*/ + +struct TRINITY_DLL_DECL boss_lokenAI : public ScriptedAI +{ + boss_lokenAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + bool m_bIsAura; + + uint32 m_uiArcLightning_Timer; + uint32 m_uiLightningNova_Timer; + uint32 m_uiPulsingShockwave_Timer; + uint32 m_uiResumePulsingShockwave_Timer; + + uint32 m_uiHealthAmountModifier; + + uint32 EncounterTime; + + void Reset() + { + m_bIsAura = false; + + m_uiArcLightning_Timer = 15000; + m_uiLightningNova_Timer = 20000; + m_uiPulsingShockwave_Timer = 2000; + m_uiResumePulsingShockwave_Timer = 15000; + + m_uiHealthAmountModifier = 1; + + if (m_pInstance) + m_pInstance->SetData(TYPE_LOKEN, NOT_STARTED); + } + + void EnterCombat(Unit* pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + + EncounterTime = 0; + + if (m_pInstance) + m_pInstance->SetData(TYPE_LOKEN, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) + { + DoScriptText(SAY_DEATH, m_creature); + + if (IsHeroic() && EncounterTime <= MAX_ENCOUNTER_TIME) + { + AchievementEntry const *AchievTimelyDeath = GetAchievementStore()->LookupEntry(ACHIEVEMENT_TIMELY_DEATH); + if (AchievTimelyDeath) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievTimelyDeath); + } + } + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_LOKEN, DONE); + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + EncounterTime += uiDiff; + + if (m_bIsAura) + { + // workaround for PULSING_SHOCKWAVE + if (m_uiPulsingShockwave_Timer <= uiDiff) + { + Map* pMap = m_creature->GetMap(); + if (pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + + if (PlayerList.isEmpty()) + return; + + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (i->getSource() && i->getSource()->isAlive() && i->getSource()->isTargetableForAttack()) + { + int32 dmg; + float m_fDist = m_creature->GetExactDist(i->getSource()->GetPositionX(), i->getSource()->GetPositionY(), i->getSource()->GetPositionZ()); + + dmg = DUNGEON_MODE(100, 150); // need to correct damage + if (m_fDist > 1.0f) // Further from 1 yard + dmg *= m_fDist; + + m_creature->CastCustomSpell(i->getSource(), DUNGEON_MODE(52942, 59837), &dmg, 0, 0, false); + } + } + m_uiPulsingShockwave_Timer = 2000; + } else m_uiPulsingShockwave_Timer -= uiDiff; + } + else + { + if (m_uiResumePulsingShockwave_Timer <= uiDiff) + { + //breaks at movement, can we assume when it's time, this spell is casted and also must stop movement? + DoCast(m_creature, SPELL_PULSING_SHOCKWAVE_AURA, true); + + DoCast(m_creature, DUNGEON_MODE(SPELL_PULSING_SHOCKWAVE_N, SPELL_PULSING_SHOCKWAVE_H)); // need core support + m_bIsAura = true; + m_uiResumePulsingShockwave_Timer = 0; + } + else + m_uiResumePulsingShockwave_Timer -= uiDiff; + } + + if (m_uiArcLightning_Timer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_ARC_LIGHTNING); + + m_uiArcLightning_Timer = 15000 + rand()%1000; + } + else + m_uiArcLightning_Timer -= uiDiff; + + if (m_uiLightningNova_Timer <= uiDiff) + { + DoScriptText(RAND(SAY_NOVA_1,SAY_NOVA_2,SAY_NOVA_3), m_creature); + DoScriptText(EMOTE_NOVA, m_creature); + DoCast(m_creature, DUNGEON_MODE(SPELL_LIGHTNING_NOVA_N, SPELL_LIGHTNING_NOVA_H)); + + m_bIsAura = false; + m_uiResumePulsingShockwave_Timer = DUNGEON_MODE(5000, 4000); // Pause Pulsing Shockwave aura + m_uiLightningNova_Timer = 20000 + rand()%1000; + } + else + m_uiLightningNova_Timer -= uiDiff; + + // Health check + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < (100-(25*m_uiHealthAmountModifier))) + { + switch(m_uiHealthAmountModifier) + { + case 1: DoScriptText(SAY_75HEALTH, m_creature); break; + case 2: DoScriptText(SAY_50HEALTH, m_creature); break; + case 3: DoScriptText(SAY_25HEALTH, m_creature); break; + } + + ++m_uiHealthAmountModifier; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_loken(Creature* pCreature) +{ + return new boss_lokenAI(pCreature); +} + +void AddSC_boss_loken() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_loken"; + newscript->GetAI = &GetAI_boss_loken; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp b/src/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp new file mode 100644 index 00000000000..4dddf375bac --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp @@ -0,0 +1,478 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss Volkhan +SD%Complete: 60% +SDComment: Not considered complete. Some events may fail and need further development +SDCategory: Halls of Lightning +EndScriptData */ + +#include "ScriptedPch.h" +#include "halls_of_lightning.h" + +enum eEnums +{ + SAY_AGGRO = -1602032, + SAY_SLAY_1 = -1602033, + SAY_SLAY_2 = -1602034, + SAY_SLAY_3 = -1602035, + SAY_DEATH = -1602036, + SAY_STOMP_1 = -1602037, + SAY_STOMP_2 = -1602038, + SAY_FORGE_1 = -1602039, + SAY_FORGE_2 = -1602040, + EMOTE_TO_ANVIL = -1602041, + EMOTE_SHATTER = -1602042, + + SPELL_HEAT_N = 52387, + SPELL_HEAT_H = 59528, + SPELL_SHATTERING_STOMP_N = 52237, + SPELL_SHATTERING_STOMP_H = 59529, + + //unclear how "directions" of spells must be. Last, summoning GO, what is it for? Script depend on: + SPELL_TEMPER = 52238, //TARGET_SCRIPT boss->anvil + SPELL_TEMPER_DUMMY = 52654, //TARGET_SCRIPT anvil->boss + + //SPELL_TEMPER_VISUAL = 52661, //summons GO + + SPELL_SUMMON_MOLTEN_GOLEM = 52405, + + //Molten Golem + SPELL_BLAST_WAVE = 23113, + SPELL_IMMOLATION_STRIKE_N = 52433, + SPELL_IMMOLATION_STRIKE_H = 59530, + SPELL_SHATTER_N = 52429, + SPELL_SHATTER_H = 59527, + + NPC_VOLKHAN_ANVIL = 28823, + NPC_MOLTEN_GOLEM = 28695, + NPC_BRITTLE_GOLEM = 28681, + + POINT_ID_ANVIL = 0, + MAX_GOLEM = 2, + + ACHIEVEMENT_SHATTER_RESISTANT = 2042 +}; + +/*###### +## Boss Volkhan +######*/ + +struct TRINITY_DLL_DECL boss_volkhanAI : public ScriptedAI +{ + boss_volkhanAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + std::list<uint64> m_lGolemGUIDList; + + bool m_bHasTemper; + bool m_bIsStriking; + bool m_bCanShatterGolem; + + uint8 GolemsShattered; + uint32 m_uiPause_Timer; + uint32 m_uiShatteringStomp_Timer; + uint32 m_uiShatter_Timer; + + uint32 m_uiHealthAmountModifier; + + void Reset() + { + m_bIsStriking = false; + m_bHasTemper = false; + m_bCanShatterGolem = false; + + m_uiPause_Timer = 3500; + m_uiShatteringStomp_Timer = 0; + m_uiShatter_Timer = 5000; + GolemsShattered = 0; + + m_uiHealthAmountModifier = 1; + + DespawnGolem(); + m_lGolemGUIDList.clear(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLKHAN, NOT_STARTED); + } + + void EnterCombat(Unit* pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLKHAN, IN_PROGRESS); + } + + void AttackStart(Unit* pWho) + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + if (!m_bHasTemper) + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void JustDied(Unit* pKiller) + { + DoScriptText(SAY_DEATH, m_creature); + DespawnGolem(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLKHAN, DONE); + + if (IsHeroic() && GolemsShattered < 5) + { + AchievementEntry const *AchievShatterResistant = GetAchievementStore()->LookupEntry(ACHIEVEMENT_SHATTER_RESISTANT); + if (AchievShatterResistant) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievShatterResistant); + } + } + } + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void DespawnGolem() + { + if (m_lGolemGUIDList.empty()) + return; + + for (std::list<uint64>::iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + { + if (Creature* pTemp = Unit::GetCreature(*m_creature, *itr)) + { + if (pTemp->isAlive()) + pTemp->ForcedDespawn(); + } + } + + m_lGolemGUIDList.clear(); + } + + void ShatterGolem() + { + if (m_lGolemGUIDList.empty()) + return; + + for (std::list<uint64>::iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + { + if (Creature* pTemp = Unit::GetCreature(*m_creature, *itr)) + { + // only shatter brittle golems + if (pTemp->isAlive() && pTemp->GetEntry() == NPC_BRITTLE_GOLEM) + { + pTemp->CastSpell(pTemp, DUNGEON_MODE(SPELL_SHATTER_N, SPELL_SHATTER_H), false); + GolemsShattered += 1; + } + } + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + { + if (pSpell->Id == SPELL_TEMPER_DUMMY) + m_bIsStriking = true; + } + + void JustSummoned(Creature* pSummoned) + { + if (pSummoned->GetEntry() == NPC_MOLTEN_GOLEM) + { + m_lGolemGUIDList.push_back(pSummoned->GetGUID()); + + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + //why healing when just summoned? + pSummoned->CastSpell(pSummoned, DUNGEON_MODE(SPELL_HEAT_N, SPELL_HEAT_H), false, NULL, NULL, m_creature->GetGUID()); + } + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (m_bIsStriking) + { + if (m_uiPause_Timer <= uiDiff) + { + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + { + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + + m_bHasTemper = false; + m_bIsStriking = false; + m_uiPause_Timer = 3500; + } + else + m_uiPause_Timer -= uiDiff; + + return; + } + + // When to start shatter? After 60, 40 or 20% hp? + if (!m_bHasTemper && m_uiHealthAmountModifier >= 3) + { + if (m_uiShatteringStomp_Timer <= uiDiff) + { + //should he stomp even if he has no brittle golem to shatter? + + DoScriptText(RAND(SAY_STOMP_1,SAY_STOMP_2), m_creature); + + DoCast(m_creature, DUNGEON_MODE(SPELL_SHATTERING_STOMP_N, SPELL_SHATTERING_STOMP_H)); + + DoScriptText(EMOTE_SHATTER, m_creature); + + m_uiShatteringStomp_Timer = 30000; + m_bCanShatterGolem = true; + } + else + m_uiShatteringStomp_Timer -= uiDiff; + } + + // Shatter Golems 3 seconds after Shattering Stomp + if (m_bCanShatterGolem) + { + if (m_uiShatter_Timer <= uiDiff) + { + ShatterGolem(); + m_uiShatter_Timer = 3000; + m_bCanShatterGolem = false; + } + else + m_uiShatter_Timer -= uiDiff; + } + + // Health check + if (!m_bCanShatterGolem && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < (100-(20*m_uiHealthAmountModifier))) + { + ++m_uiHealthAmountModifier; + + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + + DoScriptText(RAND(SAY_FORGE_1,SAY_FORGE_2), m_creature); + + m_bHasTemper = true; + + DoCast(m_creature, SPELL_TEMPER, false); + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_volkhan(Creature* pCreature) +{ + return new boss_volkhanAI(pCreature); +} + +bool EffectDummyCreature_boss_volkhan(Unit* pCaster, uint32 uiSpellId, uint32 uiEffIndex, Creature* pCreatureTarget) +{ + //always check spellid and effectindex + if (uiSpellId == SPELL_TEMPER_DUMMY && uiEffIndex == 0) + { + if (pCaster->GetEntry() != NPC_VOLKHAN_ANVIL || pCreatureTarget->GetEntry() != NPC_VOLKHAN) + return true; + + for (uint8 i = 0; i < MAX_GOLEM; ++i) + { + pCreatureTarget->CastSpell(pCaster, SPELL_SUMMON_MOLTEN_GOLEM, true); + } + + //always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_volkhan_anvil +######*/ + +bool EffectDummyCreature_npc_volkhan_anvil(Unit* pCaster, uint32 uiSpellId, uint32 uiEffIndex, Creature* pCreatureTarget) +{ + //always check spellid and effectindex + if (uiSpellId == SPELL_TEMPER && uiEffIndex == 0) + { + if (pCaster->GetEntry() != NPC_VOLKHAN || pCreatureTarget->GetEntry() != NPC_VOLKHAN_ANVIL) + return true; + + Creature *cre = CAST_CRE(pCaster); + + DoScriptText(EMOTE_TO_ANVIL, pCaster); + + float fX, fY, fZ; + pCreatureTarget->GetContactPoint(pCaster, fX, fY, fZ, INTERACTION_DISTANCE); + + pCaster->AttackStop(); + + if (pCaster->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + pCaster->GetMotionMaster()->MovementExpired(); + + cre->GetMap()->CreatureRelocation(cre, fX, fY, fZ, pCreatureTarget->GetOrientation()); + cre->SendMonsterMove(fX, fY, fZ, 0, cre->GetUnitMovementFlags(), 1); + + pCreatureTarget->CastSpell(pCaster, SPELL_TEMPER_DUMMY, false); + + //always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## mob_molten_golem +######*/ + +struct TRINITY_DLL_DECL mob_molten_golemAI : public ScriptedAI +{ + mob_molten_golemAI(Creature *pCreature) : ScriptedAI(pCreature) + { + } + + bool m_bIsFrozen; + + uint32 m_uiBlast_Timer; + uint32 m_uiDeathDelay_Timer; + uint32 m_uiImmolation_Timer; + + void Reset() + { + m_bIsFrozen = false; + + m_uiBlast_Timer = 20000; + m_uiDeathDelay_Timer = 0; + m_uiImmolation_Timer = 5000; + } + + void AttackStart(Unit* pWho) + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + if (!m_bIsFrozen) + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + { + if (uiDamage > m_creature->GetHealth()) + { + m_creature->UpdateEntry(NPC_BRITTLE_GOLEM); + m_creature->SetHealth(1); + uiDamage = 0; + m_creature->RemoveAllAuras(); + m_creature->AttackStop(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + m_creature->GetMotionMaster()->MovementExpired(); + m_bIsFrozen = true; + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + { + //this is the dummy effect of the spells + if (pSpell->Id == SPELL_SHATTER_N || pSpell->Id == SPELL_SHATTER_H) + { + if (m_creature->GetEntry() == NPC_BRITTLE_GOLEM) + m_creature->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target or if we are frozen + if (!UpdateVictim() || m_bIsFrozen) + return; + + if (m_uiBlast_Timer <= uiDiff) + { + DoCast(m_creature, SPELL_BLAST_WAVE); + m_uiBlast_Timer = 20000; + } + else + m_uiBlast_Timer -= uiDiff; + + if (m_uiImmolation_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_IMMOLATION_STRIKE_N, SPELL_IMMOLATION_STRIKE_H)); + m_uiImmolation_Timer = 5000; + } + else + m_uiImmolation_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_molten_golem(Creature* pCreature) +{ + return new mob_molten_golemAI(pCreature); +} + +void AddSC_boss_volkhan() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_volkhan"; + newscript->GetAI = &GetAI_boss_volkhan; + newscript->pEffectDummyCreature = &EffectDummyCreature_boss_volkhan; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_volkhan_anvil"; + newscript->pEffectDummyCreature = &EffectDummyCreature_npc_volkhan_anvil; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_molten_golem"; + newscript->GetAI = &GetAI_mob_molten_golem; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h b/src/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h new file mode 100644 index 00000000000..d9739fdf888 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_HALLS_OF_LIGHTNING_H +#define DEF_HALLS_OF_LIGHTNING_H + +enum eTypes +{ + MAX_ENCOUNTER = 4, + + DATA_BJARNGRIM = 1, + DATA_IONAR = 2, + DATA_LOKEN = 3, + DATA_VOLKHAN = 4, + + TYPE_BJARNGRIM = 10, + TYPE_IONAR = 11, + TYPE_LOKEN = 12, + TYPE_VOLKHAN = 13, + + NPC_BJARNGRIM = 28586, + NPC_VOLKHAN = 28587, + NPC_IONAR = 28546, + NPC_LOKEN = 28923, + + GO_BJARNGRIM_DOOR = 191416, //_doors10 + GO_VOLKHAN_DOOR = 191325, //_doors07 + GO_IONAR_DOOR = 191326, //_doors05 + GO_LOKEN_DOOR = 191324, //_doors02 + GO_LOKEN_THRONE = 192654 +}; + +#endif diff --git a/src/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp b/src/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp new file mode 100644 index 00000000000..fc556d3ddb7 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp @@ -0,0 +1,237 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Instance_Halls_of_Lightning +SD%Complete: 90% +SDComment: All ready. +SDCategory: Halls of Lightning +EndScriptData */ + +#include "ScriptedPch.h" +#include "halls_of_lightning.h" + +/* Halls of Lightning encounters: +0 - General Bjarngrim +1 - Volkhan +2 - Ionar +3 - Loken +*/ + +struct TRINITY_DLL_DECL instance_halls_of_lightning : public ScriptedInstance +{ + instance_halls_of_lightning(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + uint64 m_uiGeneralBjarngrimGUID; + uint64 m_uiIonarGUID; + uint64 m_uiLokenGUID; + uint64 m_uiVolkhanGUID; + + uint64 m_uiBjarngrimDoorGUID; + uint64 m_uiVolkhanDoorGUID; + uint64 m_uiIonarDoorGUID; + uint64 m_uiLokenDoorGUID; + uint64 m_uiLokenGlobeGUID; + + void Initialize() + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + m_uiGeneralBjarngrimGUID = 0; + m_uiVolkhanGUID = 0; + m_uiIonarGUID = 0; + m_uiLokenGUID = 0; + + m_uiBjarngrimDoorGUID = 0; + m_uiVolkhanDoorGUID = 0; + m_uiIonarDoorGUID = 0; + m_uiLokenDoorGUID = 0; + m_uiLokenGlobeGUID = 0; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case NPC_BJARNGRIM: + m_uiGeneralBjarngrimGUID = pCreature->GetGUID(); + break; + case NPC_VOLKHAN: + m_uiVolkhanGUID = pCreature->GetGUID(); + break; + case NPC_IONAR: + m_uiIonarGUID = pCreature->GetGUID(); + break; + case NPC_LOKEN: + m_uiLokenGUID = pCreature->GetGUID(); + break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case GO_BJARNGRIM_DOOR: + m_uiBjarngrimDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[0] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_VOLKHAN_DOOR: + m_uiVolkhanDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_IONAR_DOOR: + m_uiIonarDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_LOKEN_DOOR: + m_uiLokenDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[3] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_LOKEN_THRONE: + m_uiLokenGlobeGUID = pGo->GetGUID(); + break; + } + } + + void SetData(uint32 uiType, uint32 uiData) + { + switch(uiType) + { + case TYPE_BJARNGRIM: + if (uiData == DONE) + DoUseDoorOrButton(m_uiBjarngrimDoorGUID); + m_auiEncounter[0] = uiData; + break; + case TYPE_VOLKHAN: + if (uiData == DONE) + DoUseDoorOrButton(m_uiVolkhanDoorGUID); + m_auiEncounter[1] = uiData; + break; + case TYPE_IONAR: + if (uiData == DONE) + DoUseDoorOrButton(m_uiIonarDoorGUID); + m_auiEncounter[2] = uiData; + break; + case TYPE_LOKEN: + if (uiData == DONE) + { + DoUseDoorOrButton(m_uiLokenDoorGUID); + + //Appears to be type 5 GO with animation. Need to figure out how this work, code below only placeholder + if (GameObject* pGlobe = instance->GetGameObject(m_uiLokenGlobeGUID)) + pGlobe->SetGoState(GO_STATE_ACTIVE); + } + m_auiEncounter[3] = uiData; + break; + } + } + + uint32 GetData(uint32 uiType) + { + switch(uiType) + { + case TYPE_BJARNGRIM: + return m_auiEncounter[0]; + case TYPE_VOLKHAN: + return m_auiEncounter[1]; + case TYPE_IONAR: + return m_auiEncounter[2]; + case TYPE_LOKEN: + return m_auiEncounter[3]; + } + return 0; + } + + uint64 GetData64(uint32 uiData) + { + switch(uiData) + { + case DATA_BJARNGRIM: + return m_uiGeneralBjarngrimGUID; + case DATA_VOLKHAN: + return m_uiVolkhanGUID; + case DATA_IONAR: + return m_uiIonarGUID; + case DATA_LOKEN: + return m_uiLokenGUID; + } + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "H L " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); + } + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3; + + if (dataHead1 == 'H' && dataHead2 == 'L') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + m_auiEncounter[3] = data3; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_halls_of_lightning(Map* pMap) +{ + return new instance_halls_of_lightning(pMap); +} + +void AddSC_instance_halls_of_lightning() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_halls_of_lightning"; + newscript->GetInstanceData = &GetInstanceData_instance_halls_of_lightning; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp b/src/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp new file mode 100644 index 00000000000..f8a88e9fcc7 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp @@ -0,0 +1,148 @@ +/* Script Data Start +SDName: Boss krystallus +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_krystallus' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "halls_of_stone.h" + +enum Spells +{ + SPELL_BOULDER_TOSS = 50843, + H_SPELL_BOULDER_TOSS = 59742, + SPELL_GROUND_SPIKE = 59750, + SPELL_GROUND_SLAM = 50827, + SPELL_SHATTER = 50810, + H_SPELL_SHATTER = 61546, + SPELL_STOMP = 48131, + H_SPELL_STOMP = 59744 +}; + +enum Yells +{ + SAY_AGGRO = -1603007, + SAY_KILL = -1603008, + SAY_DEATH = -1603009, + SAY_SHATTER = -1603010 +}; + +struct TRINITY_DLL_DECL boss_krystallusAI : public ScriptedAI +{ + boss_krystallusAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiBoulderTossTimer; + uint32 uiGroundSpikeTimer; + uint32 uiGroundSlamTimer; + uint32 uiShatterTimer; + uint32 uiStompTimer; + + bool bIsSlam; + + ScriptedInstance* pInstance; + + void Reset() + { + bIsSlam = false; + + uiBoulderTossTimer = 3000 + rand()%6000; + uiGroundSpikeTimer = 9000 + rand()%5000; + uiGroundSlamTimer = 15000 + rand()%3000; + uiStompTimer = 20000 + rand()%9000; + uiShatterTimer = 0; + + if (pInstance) + pInstance->SetData(DATA_KRYSTALLUS_EVENT, NOT_STARTED); + } + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_KRYSTALLUS_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiBoulderTossTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_BOULDER_TOSS, H_SPELL_BOULDER_TOSS)); + uiBoulderTossTimer = 9000 + rand()%6000; + } else uiBoulderTossTimer -= diff; + + if (uiGroundSpikeTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_GROUND_SPIKE); + uiGroundSpikeTimer = 12000 + rand()%5000; + } else uiGroundSpikeTimer -= diff; + + if (uiStompTimer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_STOMP, H_SPELL_STOMP)); + uiStompTimer = 20000 + rand()%9000; + } else uiStompTimer -= diff; + + if (uiGroundSlamTimer <= diff) + { + DoCast(m_creature, SPELL_GROUND_SLAM); + bIsSlam = true; + uiShatterTimer = 10000; + uiGroundSlamTimer = 15000 + rand()%3000; + } else uiGroundSlamTimer -= diff; + + if (bIsSlam) + { + if (uiShatterTimer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_SHATTER, H_SPELL_SHATTER)); + bIsSlam = false; + } else uiShatterTimer -= diff; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_KRYSTALLUS_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(SAY_KILL, m_creature); + } +}; + +CreatureAI* GetAI_boss_krystallus(Creature* pCreature) +{ + return new boss_krystallusAI (pCreature); +} + +void AddSC_boss_krystallus() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_krystallus"; + newscript->GetAI = &GetAI_boss_krystallus; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp b/src/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp new file mode 100644 index 00000000000..615e4c5cc44 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp @@ -0,0 +1,177 @@ +/* Script Data Start +SDName: Boss maiden_of_grief +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_maiden_of_grief' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "halls_of_stone.h" + +enum Spells +{ + SPELL_PARTING_SORROW = 59723, + SPELL_STORM_OF_GRIEF_N = 50752, + SPELL_STORM_OF_GRIEF_H = 59772, + SPELL_SHOCK_OF_SORROW_N = 50760, + SPELL_SHOCK_OF_SORROW_H = 59726, + SPELL_PILLAR_OF_WOE_N = 50761, + SPELL_PILLAR_OF_WOE_H = 59727 +}; + +enum Yells +{ + SAY_AGGRO = -1603000, + SAY_SLAY_1 = -1603001, + SAY_SLAY_2 = -1603002, + SAY_SLAY_3 = -1603003, + SAY_SLAY_4 = -1603004, + SAY_DEATH = -1603005, + SAY_STUN = -1603006 +}; + +enum Achievements +{ + ACHIEVEMENT_GOOD_GRIEF = 1866 +}; + +struct TRINITY_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI +{ + boss_maiden_of_griefAI(Creature *c) : ScriptedAI(c) + { + pInstance = m_creature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 PartingSorrowTimer; + uint32 StormOfGriefTimer; + uint32 ShockOfSorrowTimer; + uint32 PillarOfWoeTimer; + uint32 AchievTimer; + + void Reset() + { + PartingSorrowTimer = 25000 + rand()%5000; + StormOfGriefTimer = 10000; + ShockOfSorrowTimer = 20000+rand()%5000; + PillarOfWoeTimer = 5000 + rand()%10000; + AchievTimer = 0; + + if (pInstance) + pInstance->SetData(DATA_MAIDEN_OF_GRIEF_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + { + if (GameObject *pDoor = pInstance->instance->GetGameObject(pInstance->GetData64(DATA_MAIDEN_DOOR))) + if (pDoor->GetGoState() == GO_STATE_READY) + { + EnterEvadeMode(); + return; + } + + pInstance->SetData(DATA_MAIDEN_OF_GRIEF_EVENT, IN_PROGRESS); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + //Achievement counter + if (pInstance) + if (pInstance->GetData(DATA_MAIDEN_OF_GRIEF_EVENT) == IN_PROGRESS) + AchievTimer += diff; + + if (IsHeroic()) + { + if (PartingSorrowTimer <= diff) + { + Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(pTarget) + DoCast(pTarget, SPELL_PARTING_SORROW); + + PartingSorrowTimer = 30000 + rand()%10000; + } else PartingSorrowTimer -= diff; + } + + if (StormOfGriefTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_STORM_OF_GRIEF_N, SPELL_STORM_OF_GRIEF_H), true); + StormOfGriefTimer = 15000 + rand()%5000; + } else StormOfGriefTimer -= diff; + + if (ShockOfSorrowTimer <= diff) + { + DoResetThreat(); + DoScriptText(SAY_STUN, m_creature); + DoCast(m_creature, DUNGEON_MODE(SPELL_SHOCK_OF_SORROW_N, SPELL_SHOCK_OF_SORROW_H)); + ShockOfSorrowTimer = 20000 + rand()%10000; + } else ShockOfSorrowTimer -= diff; + + if (PillarOfWoeTimer <= diff) + { + Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 1); + + if (pTarget) + DoCast(pTarget, DUNGEON_MODE(SPELL_PILLAR_OF_WOE_N, SPELL_PILLAR_OF_WOE_H)); + else + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_PILLAR_OF_WOE_N, SPELL_PILLAR_OF_WOE_H)); + + PillarOfWoeTimer = 5000 + rand()%20000; + } else PillarOfWoeTimer -= diff; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_MAIDEN_OF_GRIEF_EVENT, DONE); + + AchievementEntry const *AchievGoodGrief = GetAchievementStore()->LookupEntry(ACHIEVEMENT_GOOD_GRIEF); + Map* pMap = m_creature->GetMap(); + + if (IsHeroic() && AchievTimer < 60000 && pMap && pMap->IsDungeon() && AchievGoodGrief) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievGoodGrief); + } + } + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3,SAY_SLAY_4), m_creature); + } +}; + +CreatureAI* GetAI_boss_maiden_of_grief(Creature* pCreature) +{ + return new boss_maiden_of_griefAI (pCreature); +} + +void AddSC_boss_maiden_of_grief() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_maiden_of_grief"; + newscript->GetAI = &GetAI_boss_maiden_of_grief; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp b/src/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp new file mode 100644 index 00000000000..5986748f0c5 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp @@ -0,0 +1,300 @@ +/* Script Data Start +SDName: Boss sjonnir +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_sjonnir' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "halls_of_stone.h" + +enum Spells +{ + SPELL_LIGHTING_RING = 51849, //Periodic Trigger (interval 2s) spell = 50841 + H_SPELL_LIGHTING_RING = 59861, //Periodic Trigger (interval 2s) spell = 59849 + SPELL_LIGHTING_RING_1 = 50840, //Periodic Trigger (interval 2s) spell = 50841 + H_SPELL_LIGHTING_RING_1 = 59848, //Periodic Trigger (interval 2s) spell = 59849 + SPELL_STATIC_CHARGE = 50834, //Periodic Trigger 2s interval, spell =50835 + H_SPELL_STATIC_CHARGE = 59846, //Periodic Trigger 2s interval, spell =50847 + SPELL_CHAIN_LIGHTING = 50830, + H_SPELL_CHAIN_LIGHTING = 59844, + SPELL_LIGHTING_SHIELD = 50831, + H_SPELL_LIGHTING_SHIELD = 59845, + SPELL_FRENZY = 28747 +}; + +enum Yells +{ + SAY_AGGRO = -1603011, + SAY_SLAY_1 = -1603012, + SAY_SLAY_2 = -1603013, + SAY_SLAY_3 = -1603014, + SAY_DEATH = -1603015 +}; + +#define EMOTE_GENERIC_FRENZY -1000002 + +enum SjonnirCreatures +{ + CREATURE_FORGED_IRON_TROGG = 27979, + CREATURE_MALFORMED_OOZE = 27981, + CREATURE_FORGED_IRON_DWARF = 27982, + CREATURE_IRON_SLUDGE = 28165 +}; + +enum Misc +{ + DATA_TIME_BEFORE_OOZE = 150000, //2min 30 secs + ACHIEV_ABUSE_THE_OOZE = 2155 +}; + +struct Locations +{ + float x, y, z; +}; + +static Locations PipeLocations[] = +{ + {1295.44, 734.07, 200.3}, //left + {1297.7, 595.6, 199.9} //right +}; + +static Locations CenterPoint = {1295.21, 667.157, 189.691}; + +struct TRINITY_DLL_DECL boss_sjonnirAI : public ScriptedAI +{ + boss_sjonnirAI(Creature *c) : ScriptedAI(c), lSummons(me) + { + pInstance = c->GetInstanceData(); + } + + bool bIsFrenzy; + + uint32 uiChainLightningTimer; + uint32 uiLightningShieldTimer; + uint32 uiStaticChargeTimer; + uint32 uiLightningRingTimer; + uint32 uiSummonTimer; + uint32 uiFrenzyTimer; + uint32 uiEncounterTimer; + uint32 uiKilledIronSludges; + + SummonList lSummons; + + ScriptedInstance* pInstance; + + void Reset() + { + bIsFrenzy = false; + + uiEncounterTimer = 0; + uiChainLightningTimer = 3000 + rand()%5000; + uiLightningShieldTimer = 20000 + rand()%5000; + uiStaticChargeTimer = 20000 + rand()%5000; + uiLightningRingTimer = 30000 + rand()%5000; + uiSummonTimer = 5000; + uiFrenzyTimer = 300000; //5 minutes + uiKilledIronSludges = 0; + + lSummons.DespawnAll(); + + if (pInstance) + pInstance->SetData(DATA_SJONNIR_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + uiEncounterTimer = 0; + + if (pInstance) + { + if (GameObject *pDoor = pInstance->instance->GetGameObject(pInstance->GetData64(DATA_SJONNIR_DOOR))) + if (pDoor->GetGoState() == GO_STATE_READY) + { + EnterEvadeMode(); + return; + } + + pInstance->SetData(DATA_SJONNIR_EVENT, IN_PROGRESS); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiChainLightningTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_CHAIN_LIGHTING, H_SPELL_CHAIN_LIGHTING)); + uiChainLightningTimer = 10000 + rand()%5000; + } else uiChainLightningTimer -= diff; + + if (uiLightningShieldTimer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_LIGHTING_SHIELD, H_SPELL_LIGHTING_SHIELD)); + uiLightningShieldTimer -= diff; + } + + if (uiStaticChargeTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_STATIC_CHARGE, H_SPELL_STATIC_CHARGE)); + uiStaticChargeTimer = 20000 + rand()%5000; + } uiStaticChargeTimer -= diff; + + if (uiLightningRingTimer <= diff) + { + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, DUNGEON_MODE(SPELL_LIGHTING_RING, H_SPELL_LIGHTING_RING)); + uiLightningRingTimer = 30000 + rand()%5000; + } else uiLightningRingTimer -= diff; + + if (uiSummonTimer <= diff) + { + uint32 uiSummonPipe = rand()%2; + m_creature->SummonCreature(uiEncounterTimer > DATA_TIME_BEFORE_OOZE ? CREATURE_MALFORMED_OOZE : + RAND(CREATURE_FORGED_IRON_DWARF,CREATURE_FORGED_IRON_TROGG), + PipeLocations[uiSummonPipe].x, PipeLocations[uiSummonPipe].y, PipeLocations[uiSummonPipe].z, 0.0f, + TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); + uiSummonTimer = 20000; + } else uiSummonTimer -= diff; + + if (!bIsFrenzy) + { + if (uiFrenzyTimer <= diff) + { + DoCast(m_creature, SPELL_FRENZY); + bIsFrenzy = true; + } + else uiFrenzyTimer -= diff; + } + + uiEncounterTimer +=diff; + + DoMeleeAttackIfReady(); + } + + void JustSummoned(Creature* summon) + { + summon->GetMotionMaster()->MovePoint(0, CenterPoint.x, CenterPoint.y, CenterPoint.z); + /*if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + summon->AI()->AttackStart(pTarget);*/ + lSummons.Summon(summon); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + lSummons.DespawnAll(); + + if (pInstance) + { + pInstance->SetData(DATA_SJONNIR_EVENT, DONE); + if (IsHeroic() && uiKilledIronSludges > 4) + pInstance->DoCompleteAchievement(ACHIEV_ABUSE_THE_OOZE); + } + } + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void KilledIronSludge() + { + ++uiKilledIronSludges; + } +}; + +CreatureAI* GetAI_boss_sjonnir(Creature* pCreature) +{ + return new boss_sjonnirAI (pCreature); +} + +struct TRINITY_DLL_DECL mob_malformed_oozeAI : public ScriptedAI +{ + mob_malformed_oozeAI(Creature *c) : ScriptedAI(c) {} + + uint32 uiMergeTimer; + + void Reset() + { + uiMergeTimer = 10000; + } + + void UpdateAI(const uint32 diff) + { + if (uiMergeTimer <= diff) + { + if (Creature* pTemp = m_creature->FindNearestCreature(CREATURE_MALFORMED_OOZE, 3.0f, true)) + { + DoSpawnCreature(CREATURE_IRON_SLUDGE, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + pTemp->DisappearAndDie(); + m_creature->DisappearAndDie(); + } + uiMergeTimer = 3000; + } else uiMergeTimer -= diff; + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_malformed_ooze(Creature* pCreature) +{ + return new mob_malformed_oozeAI(pCreature); +} + +struct TRINITY_DLL_DECL mob_iron_sludgeAI : public ScriptedAI +{ + mob_iron_sludgeAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void JustDied(Unit* pKiller) + { + if (pInstance) + if(Creature* pSjonnir = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_SJONNIR))) + CAST_AI(boss_sjonnirAI, pSjonnir->AI())->KilledIronSludge(); + } +}; + +CreatureAI* GetAI_mob_iron_sludge(Creature* pCreature) +{ + return new mob_iron_sludgeAI(pCreature); +} + +void AddSC_boss_sjonnir() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_sjonnir"; + newscript->GetAI = &GetAI_boss_sjonnir; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_malformed_ooze"; + newscript->GetAI = &GetAI_mob_malformed_ooze; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_iron_sludge"; + newscript->GetAI = &GetAI_mob_iron_sludge; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp b/src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp new file mode 100644 index 00000000000..1c21f531c96 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp @@ -0,0 +1,690 @@ +#include "ScriptedPch.h" +#include "ScriptedEscortAI.h" +#include "halls_of_stone.h" + +enum Texts +{ + SAY_KILL_1 = -1603016, + SAY_KILL_2 = -1603017, + SAY_KILL_3 = -1603018, + SAY_LOW_HEALTH = -1603019, + SAY_DEATH = -1603020, + SAY_PLAYER_DEATH_1 = -1603021, + SAY_PLAYER_DEATH_2 = -1603022, + SAY_PLAYER_DEATH_3 = -1603023, + SAY_ESCORT_START = -1603024, + + SAY_SPAWN_DWARF = -1603025, + SAY_SPAWN_TROGG = -1603026, + SAY_SPAWN_OOZE = -1603027, + SAY_SPAWN_EARTHEN = -1603028, + + SAY_EVENT_INTRO_1 = -1603029, + SAY_EVENT_INTRO_2 = -1603030, + SAY_EVENT_INTRO_3_ABED = -1603031, + + SAY_EVENT_A_1 = -1603032, + SAY_EVENT_A_2_KADD = -1603033, + SAY_EVENT_A_3 = -1603034, + + SAY_EVENT_B_1 = -1603035, + SAY_EVENT_B_2_MARN = -1603036, + SAY_EVENT_B_3 = -1603037, + + SAY_EVENT_C_1 = -1603038, + SAY_EVENT_C_2_ABED = -1603039, + SAY_EVENT_C_3 = -1603040, + + SAY_EVENT_D_1 = -1603041, + SAY_EVENT_D_2_ABED = -1603042, + SAY_EVENT_D_3 = -1603043, + SAY_EVENT_D_4_ABED = -1603044, + + SAY_EVENT_END_01 = -1603045, + SAY_EVENT_END_02 = -1603046, + SAY_EVENT_END_03_ABED = -1603047, + SAY_EVENT_END_04 = -1603048, + SAY_EVENT_END_05_ABED = -1603049, + SAY_EVENT_END_06 = -1603050, + SAY_EVENT_END_07_ABED = -1603051, + SAY_EVENT_END_08 = -1603052, + SAY_EVENT_END_09_KADD = -1603053, + SAY_EVENT_END_10 = -1603054, + SAY_EVENT_END_11_KADD = -1603055, + SAY_EVENT_END_12 = -1603056, + SAY_EVENT_END_13_KADD = -1603057, + SAY_EVENT_END_14 = -1603058, + SAY_EVENT_END_15_MARN = -1603059, + SAY_EVENT_END_16 = -1603060, + SAY_EVENT_END_17_MARN = -1603061, + SAY_EVENT_END_18 = -1603062, + SAY_EVENT_END_19_MARN = -1603063, + SAY_EVENT_END_20 = -1603064, + SAY_EVENT_END_21_ABED = -1603065, + + SAY_VICTORY_SJONNIR_1 = -1603066, + SAY_VICTORY_SJONNIR_2 = -1603067, + + SAY_ENTRANCE_MEET = -1603068, + + TEXT_ID_START = 13100, + TEXT_ID_PROGRESS = 13101 +}; + +enum BrannCreatures +{ + CREATURE_TRIBUNAL_OF_THE_AGES = 28234, + CREATURE_BRANN_BRONZEBEARD = 28070, + CREATURE_DARK_MATTER_TARGET = 28237, + CREATURE_SEARING_GAZE_TARGET = 28265, + CREATURE_DARK_RUNE_PROTECTOR = 27983, + CREATURE_DARK_RUNE_STORMCALLER = 27984, + CREATURE_IRON_GOLEM_CUSTODIAN = 27985, +}; + +enum Spells +{ + SPELL_STEALTH = 58506, + //Kadrak + SPELL_GLARE_OF_THE_TRIBUNAL = 50988, + H_SPELL_GLARE_OF_THE_TRIBUNAL = 59868, + //Marnak + SPELL_DARK_MATTER = 51012, + H_SPELL_DARK_MATTER = 59868, + //Abedneum + SPELL_SEARING_GAZE = 51136, + H_SPELL_SEARING_GAZE = 59867 +}; + +enum Quests +{ + QUEST_HALLS_OF_STONE = 13207 +}; + +#define GOSSIP_ITEM_START "Brann, it would be our honor!" +#define GOSSIP_ITEM_PROGRESS "Let's move Brann, enough of the history lessons!" + +struct Locations +{ + float x, y, z; +}; + +static Locations SpawnLocations[]= +{ + {946.992, 397.016, 208.374}, + {960.748, 382.944, 208.374}, +}; + +struct TRINITY_DLL_DECL mob_tribuna_controllerAI : public ScriptedAI +{ + mob_tribuna_controllerAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + SetCombatMovement(false); + } + + ScriptedInstance* pInstance; + + uint32 uiKaddrakEncounterTimer; + uint32 uiMarnakEncounterTimer; + uint32 uiAbedneumEncounterTimer; + + bool bKaddrakActivated; + bool bMarnakActivated; + bool bAbedneumActivated; + + std::list<Creature*> lKaddrakGUIDList; + + void Reset() + { + uiKaddrakEncounterTimer = 1500; + uiMarnakEncounterTimer = 10000; + uiAbedneumEncounterTimer = 10000; + + bKaddrakActivated = false; + bMarnakActivated = false; + bAbedneumActivated = false; + + lKaddrakGUIDList.clear(); + } + + void UpdateFacesList() + { + /*GetCreatureListWithEntryInGrid(lKaddrakGUIDList, m_creature, CREATURE_KADDRAK, 50.0f); + if (!lKaddrakGUIDList.empty()) + { + uint32 uiPositionCounter = 0; + for (std::list<Creature*>::iterator itr = lKaddrakGUIDList.begin(); itr != lKaddrakGUIDList.end(); ++itr) + { + if ((*itr)->isAlive()) + { + if (uiPositionCounter == 0) + { + (*itr)->GetMap()->CreatureRelocation((*itr), 927.265, 333.200, 218.780, (*itr)->GetOrientation()); + (*itr)->SendMonsterMove(927.265, 333.200, 218.780, 0, (*itr)->GetMovementFlags(), 1); + } + else + { + (*itr)->GetMap()->CreatureRelocation((*itr), 921.745, 328.076, 218.780, (*itr)->GetOrientation()); + (*itr)->SendMonsterMove(921.745, 328.076, 218.780, 0, (*itr)->GetMovementFlags(), 1); + } + } + ++uiPositionCounter; + } + }*/ + } + + void UpdateAI(const uint32 diff) + { + if(bKaddrakActivated) + { + if (uiKaddrakEncounterTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + if (!lKaddrakGUIDList.empty()) + for (std::list<Creature*>::iterator itr = lKaddrakGUIDList.begin(); itr != lKaddrakGUIDList.end(); ++itr) + if ((*itr)->isAlive()) + (*itr)->CastSpell(pTarget, DUNGEON_MODE(SPELL_GLARE_OF_THE_TRIBUNAL, H_SPELL_GLARE_OF_THE_TRIBUNAL), true); + uiKaddrakEncounterTimer = 1500; + } else uiKaddrakEncounterTimer -= diff; + } + if (bMarnakActivated) + { + if (uiMarnakEncounterTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + if (Creature* pSummon = m_creature->SummonCreature(CREATURE_DARK_MATTER_TARGET, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000)) + { + pSummon->SetDisplayId(11686); + pSummon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pSummon->CastSpell(pTarget, DUNGEON_MODE(SPELL_DARK_MATTER, H_SPELL_DARK_MATTER), true); + } + } + uiMarnakEncounterTimer = 30000 + rand()%1000; + } else uiMarnakEncounterTimer -= diff; + } + if (bAbedneumActivated) + { + if (uiAbedneumEncounterTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + if (Creature* pSummon = m_creature->SummonCreature(CREATURE_SEARING_GAZE_TARGET, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000)) + { + pSummon->SetDisplayId(11686); + pSummon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pSummon->CastSpell(pTarget, DUNGEON_MODE(SPELL_SEARING_GAZE, H_SPELL_SEARING_GAZE), true); + } + } + uiAbedneumEncounterTimer = 30000 + rand()%1000; + } else uiAbedneumEncounterTimer -= diff; + } + } +}; + +struct TRINITY_DLL_DECL npc_brann_hosAI : public npc_escortAI +{ + npc_brann_hosAI(Creature *c) : npc_escortAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiStep; + uint32 uiPhaseTimer; + + uint64 uiControllerGUID; + std::list<uint64> lDwarfGUIDList; + + ScriptedInstance* pInstance; + + bool bIsBattle; + bool bIsLowHP; + + void Reset() + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + bIsLowHP = false; + bIsBattle = false; + uiStep = 0; + uiPhaseTimer = 0; + uiControllerGUID = 0; + + DespawnDwarf(); + + if (pInstance) + pInstance->SetData(DATA_BRANN_EVENT, NOT_STARTED); + } + } + + void DespawnDwarf() + { + if (lDwarfGUIDList.empty()) + return; + for (std::list<uint64>::iterator itr = lDwarfGUIDList.begin(); itr != lDwarfGUIDList.end(); ++itr) + { + Creature* pTemp = Unit::GetCreature(*m_creature, pInstance ? (*itr) : 0); + if (pTemp && pTemp->isAlive()) + pTemp->ForcedDespawn(); + } + lDwarfGUIDList.clear(); + } + + void WaypointReached(uint32 uiPointId) + { + switch(uiPointId) + { + case 7: + if (Creature* pCreature = GetClosestCreatureWithEntry(m_creature, CREATURE_TRIBUNAL_OF_THE_AGES, 100.0f)) + { + if (!pCreature->isAlive()) + pCreature->Respawn(); + CAST_AI(mob_tribuna_controllerAI, pCreature->AI())->UpdateFacesList(); + uiControllerGUID = pCreature->GetGUID(); + } + break; + case 13: + DoScriptText(SAY_EVENT_INTRO_1, m_creature); + SetEscortPaused(true); + SetRun(true); + JumpToNextStep(20000); + break; + case 17: + DoScriptText(SAY_EVENT_INTRO_2, m_creature); + if (pInstance) + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_TRIBUNAL_CONSOLE),true); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + SetEscortPaused(true); + JumpToNextStep(8500); + break; + case 18: + SetEscortPaused(true); + break; + } + } + + void SpawnDwarf(uint32 uiType) + { + switch(uiType) + { + case 1: + { + uint32 uiSpawnNumber = DUNGEON_MODE(2,3); + for (uint8 i = 0; i < uiSpawnNumber; ++i) + m_creature->SummonCreature(CREATURE_DARK_RUNE_PROTECTOR, SpawnLocations[0].x, SpawnLocations[0].y, SpawnLocations[0].z, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); + m_creature->SummonCreature(CREATURE_DARK_RUNE_STORMCALLER, SpawnLocations[0].x, SpawnLocations[0].y, SpawnLocations[0].z, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); + break; + } + case 2: + for (uint8 i = 0; i < 2; ++i) + m_creature->SummonCreature(CREATURE_DARK_RUNE_STORMCALLER, SpawnLocations[1].x, SpawnLocations[1].y, SpawnLocations[1].z, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); + break; + case 3: + m_creature->SummonCreature(CREATURE_IRON_GOLEM_CUSTODIAN, SpawnLocations[1].x, SpawnLocations[1].y, SpawnLocations[1].z, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); + break; + } + } + + void JustSummoned(Creature* pSummoned) + { + lDwarfGUIDList.push_back(pSummoned->GetGUID()); + pSummoned->AddThreat(m_creature, 0.0f); + pSummoned->AI()->AttackStart(m_creature); + } + + void JumpToNextStep(uint32 uiTimer) + { + uiPhaseTimer = uiTimer; + ++uiStep; + } + + void StartWP() + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + SetEscortPaused(false); + uiStep = 1; + Start(); + } + + void UpdateEscortAI(const uint32 uiDiff) + { + if (uiPhaseTimer <= uiDiff) + { + switch(uiStep) + { + case 1: + if (pInstance) + { + if (pInstance->GetData(DATA_BRANN_EVENT) != NOT_STARTED) + return; + pInstance->SetData(DATA_BRANN_EVENT, IN_PROGRESS); + } + bIsBattle = false; + DoScriptText(SAY_ESCORT_START, m_creature); + JumpToNextStep(0); + break; + case 3: + SetEscortPaused(false); + JumpToNextStep(0); + break; + case 5: + if (pInstance) + if (Creature* pTemp = (Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM)))) + DoScriptText(SAY_EVENT_INTRO_3_ABED, pTemp); + JumpToNextStep(8500); + break; + case 6: + DoScriptText(SAY_EVENT_A_1, m_creature); + JumpToNextStep(6500); + break; + case 7: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_KADDRAK))) + DoScriptText(SAY_EVENT_A_2_KADD, pTemp); + JumpToNextStep(12500); + break; + case 8: + DoScriptText(SAY_EVENT_A_3, m_creature); + if (pInstance) + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_KADDRAK),true); + if (Creature* pTemp = Unit::GetCreature(*m_creature, uiControllerGUID)) + CAST_AI(mob_tribuna_controllerAI, pTemp->AI())->bKaddrakActivated = true; + JumpToNextStep(5000); + break; + case 9: + SpawnDwarf(1); + JumpToNextStep(20000); + break; + case 10: + DoScriptText(SAY_EVENT_B_1, m_creature); + JumpToNextStep(6000); + break; + case 11: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_MARNAK))) + DoScriptText(SAY_EVENT_B_2_MARN, pTemp); + SpawnDwarf(1); + JumpToNextStep(20000); + break; + case 12: + DoScriptText(SAY_EVENT_B_3, m_creature); + if (pInstance) + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_MARNAK),true); + if (Creature* pTemp = Unit::GetCreature(*m_creature, uiControllerGUID)) + CAST_AI(mob_tribuna_controllerAI, pTemp->AI())->bMarnakActivated = true; + JumpToNextStep(10000); + break; + case 13: + SpawnDwarf(1); + JumpToNextStep(10000); + break; + case 14: + SpawnDwarf(2); + JumpToNextStep(20000); + break; + case 15: + DoScriptText(SAY_EVENT_C_1, m_creature); + SpawnDwarf(1); + JumpToNextStep(10000); + break; + case 16: + SpawnDwarf(2); + JumpToNextStep(20000); + break; + case 17: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM))) + DoScriptText(SAY_EVENT_C_2_ABED, pTemp); + SpawnDwarf(1); + JumpToNextStep(20000); + break; + case 18: + DoScriptText(SAY_EVENT_C_3, m_creature); + if (pInstance) + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_ABEDNEUM),true); + if (Creature* pTemp = Unit::GetCreature(*m_creature, uiControllerGUID)) + CAST_AI(mob_tribuna_controllerAI, pTemp->AI())->bAbedneumActivated = true; + JumpToNextStep(5000); + break; + case 19: + SpawnDwarf(2); + JumpToNextStep(10000); + break; + case 20: + SpawnDwarf(1); + JumpToNextStep(15000); + break; + case 21: + DoScriptText(SAY_EVENT_D_1, m_creature); + SpawnDwarf(3); + JumpToNextStep(20000); + break; + case 22: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM))) + DoScriptText(SAY_EVENT_D_2_ABED, pTemp); + SpawnDwarf(1); + JumpToNextStep(5000); + break; + case 23: + SpawnDwarf(2); + JumpToNextStep(15000); + break; + case 24: + DoScriptText(SAY_EVENT_D_3, m_creature); + SpawnDwarf(3); + JumpToNextStep(5000); + break; + case 25: + SpawnDwarf(1); + JumpToNextStep(5000); + break; + case 26: + SpawnDwarf(2); + JumpToNextStep(10000); + break; + case 27: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM))) + DoScriptText(SAY_EVENT_D_4_ABED, pTemp); + SpawnDwarf(1); + JumpToNextStep(10000); + break; + case 28: + DoScriptText(SAY_EVENT_END_01, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + if (pInstance) + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_SKY_FLOOR),true); + if (Creature* pTemp = Unit::GetCreature(*m_creature, uiControllerGUID)) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + bIsBattle = true; + SetEscortPaused(false); + JumpToNextStep(6500); + break; + case 29: + DoScriptText(SAY_EVENT_END_02, m_creature); + JumpToNextStep(5500); + break; + case 30: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM))) + DoScriptText(SAY_EVENT_END_03_ABED, pTemp); + JumpToNextStep(8500); + break; + case 31: + DoScriptText(SAY_EVENT_END_04, m_creature); + JumpToNextStep(11500); + break; + case 32: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM))) + DoScriptText(SAY_EVENT_END_05_ABED, pTemp); + JumpToNextStep(11500); + break; + case 33: + DoScriptText(SAY_EVENT_END_06, m_creature); + JumpToNextStep(4500); + break; + case 34: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM))) + DoScriptText(SAY_EVENT_END_07_ABED, pTemp); + JumpToNextStep(22500); + break; + case 35: + DoScriptText(SAY_EVENT_END_08, m_creature); + JumpToNextStep(7500); + break; + case 36: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_KADDRAK))) + DoScriptText(SAY_EVENT_END_09_KADD, pTemp); + JumpToNextStep(18500); + break; + case 37: + DoScriptText(SAY_EVENT_END_10, m_creature); + JumpToNextStep(5500); + break; + case 38: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_KADDRAK))) + DoScriptText(SAY_EVENT_END_11_KADD, pTemp); + JumpToNextStep(20500); + break; + case 39: + DoScriptText(SAY_EVENT_END_12, m_creature); + JumpToNextStep(2500); + break; + case 40: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_KADDRAK))) + DoScriptText(SAY_EVENT_END_13_KADD, pTemp); + JumpToNextStep(19500); + break; + case 41: + DoScriptText(SAY_EVENT_END_14, m_creature); + JumpToNextStep(10500); + break; + case 42: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_MARNAK))) + DoScriptText(SAY_EVENT_END_15_MARN, pTemp); + JumpToNextStep(6500); + break; + case 43: + DoScriptText(SAY_EVENT_END_16, m_creature); + JumpToNextStep(6500); + break; + case 44: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_MARNAK))) + DoScriptText(SAY_EVENT_END_17_MARN, pTemp); + JumpToNextStep(25500); + break; + case 45: + DoScriptText(SAY_EVENT_END_18, m_creature); + JumpToNextStep(23500); + break; + case 46: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_MARNAK))) + DoScriptText(SAY_EVENT_END_19_MARN, pTemp); + JumpToNextStep(3500); + break; + case 47: + DoScriptText(SAY_EVENT_END_20, m_creature); + JumpToNextStep(8500); + break; + case 48: + if (pInstance) + if (Creature* pTemp = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_ABEDNEUM))) + DoScriptText(SAY_EVENT_END_21_ABED, pTemp); + JumpToNextStep(5500); + break; + case 49: + { + if (pInstance) + { + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_KADDRAK),true); + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_MARNAK),true); + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_ABEDNEUM),true); + pInstance->HandleGameObject(pInstance->GetData64(DATA_GO_SKY_FLOOR),true); + pInstance->SetData(DATA_BRANN_EVENT, DONE); + } + Player* pPlayer = GetPlayerForEscort(); + if (pPlayer) + pPlayer->GroupEventHappens(QUEST_HALLS_OF_STONE, m_creature); + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + JumpToNextStep(180000); + break; + } + case 50: + SetEscortPaused(false); + break; + } + } else uiPhaseTimer -= uiDiff; + + if (!bIsLowHP && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 30) + { + DoScriptText(SAY_LOW_HEALTH, m_creature); + bIsLowHP = true; + } else if (bIsLowHP && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) > 30) + bIsLowHP = false; + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +bool GossipHello_npc_brann_hos(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_START, pCreature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_brann_hos(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1 || uiAction == GOSSIP_ACTION_INFO_DEF+2) + { + pPlayer->CLOSE_GOSSIP_MENU(); + CAST_AI(npc_brann_hosAI, pCreature->AI())->StartWP(); + } + + return true; +} + +CreatureAI* GetAI_mob_tribuna_controller(Creature* pCreature) +{ + return new mob_tribuna_controllerAI(pCreature); +} + +CreatureAI* GetAI_npc_brann_hos(Creature* pCreature) +{ + return new npc_brann_hosAI(pCreature); +} + +void AddSC_halls_of_stone() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_brann_hos"; + newscript->GetAI = &GetAI_npc_brann_hos; + newscript->pGossipHello = &GossipHello_npc_brann_hos; + newscript->pGossipSelect = &GossipSelect_npc_brann_hos; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_tribuna_controller"; + newscript->GetAI = &GetAI_mob_tribuna_controller; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h b/src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h new file mode 100644 index 00000000000..b61e7057ddc --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h @@ -0,0 +1,48 @@ +#ifndef DEF_HALLS_OF_STONE_H +#define DEF_HALLS_OF_STONE_H +enum Data +{ + DATA_KRYSTALLUS_EVENT, + DATA_MAIDEN_OF_GRIEF_EVENT, + DATA_SJONNIR_EVENT, + DATA_BRANN_EVENT +}; +enum Data64 +{ + DATA_KRYSTALLUS, + DATA_MAIDEN_OF_GRIEF, + DATA_SJONNIR, + DATA_KADDRAK, + DATA_MARNAK, + DATA_ABEDNEUM, + DATA_GO_TRIBUNAL_CONSOLE, + DATA_GO_KADDRAK, + DATA_GO_MARNAK, + DATA_GO_ABEDNEUM, + DATA_GO_SKY_FLOOR, + DATA_SJONNIR_DOOR, + DATA_MAIDEN_DOOR +}; +enum Creatures +{ + CREATURE_MAIDEN = 27975, + CREATURE_KRYSTALLUS = 27977, + CREATURE_SJONNIR = 27978, + CREATURE_MARNAK = 30897, + CREATURE_KADDRAK = 30898, + CREATURE_ABEDNEUM = 30899, + CREATURE_BRANN = 28070 +}; +enum GameObjects +{ + GO_ABEDNEUM = 191669, + GO_MARNAK = 192170, + GO_KADDRAK = 192171, + GO_MAIDEN_DOOR = 191292, + GO_BRANN_DOOR = 191295, + GO_SJONNIR_DOOR = 191296, + GO_TRIBUNAL_CONSOLE = 193907, + GO_TRIBUNAL_CHEST = 190586, + GO_TRIBUNAL_CHEST_HERO = 193996 +}; +#endif diff --git a/src/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp b/src/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp new file mode 100644 index 00000000000..07fece777f5 --- /dev/null +++ b/src/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp @@ -0,0 +1,254 @@ +#include "ScriptedPch.h" +#include "halls_of_stone.h" + +#define MAX_ENCOUNTER 4 + +/* Halls of Stone encounters: +0- Krystallus +1- Maiden of Grief +2- Escort Event +3- Sjonnir The Ironshaper +*/ + +struct TRINITY_DLL_DECL instance_halls_of_stone : public ScriptedInstance +{ + instance_halls_of_stone(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint64 uiMaidenOfGrief; + uint64 uiKrystallus; + uint64 uiSjonnir; + + uint64 uiKaddrak; + uint64 uiAbedneum; + uint64 uiMarnak; + uint64 uiBrann; + + uint64 uiMaidenOfGriefDoor; + uint64 uiSjonnirDoor; + uint64 uiBrannDoor; + uint64 uiTribunalConsole; + uint64 uiTribunalChest; + uint64 uiTribunalSkyFloor; + uint64 uiKaddrakGo; + uint64 uiAbedneumGo; + uint64 uiMarnakGo; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + std::string str_data; + + void Initialize() + { + uiMaidenOfGrief = 0; + uiKrystallus = 0; + uiSjonnir = 0; + + uiKaddrak = 0; + uiMarnak = 0; + uiAbedneum = 0; + uiBrann = 0; + + uiMaidenOfGriefDoor = 0; + uiSjonnirDoor = 0; + uiBrannDoor = 0; + uiKaddrakGo = 0; + uiMarnakGo = 0; + uiAbedneumGo = 0; + uiTribunalConsole = 0; + uiTribunalChest = 0; + uiTribunalSkyFloor = 0; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + m_auiEncounter[i] = NOT_STARTED; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case CREATURE_MAIDEN: uiMaidenOfGrief = pCreature->GetGUID(); break; + case CREATURE_KRYSTALLUS: uiKrystallus = pCreature->GetGUID(); break; + case CREATURE_SJONNIR: uiSjonnir = pCreature->GetGUID(); break; + case CREATURE_MARNAK: uiMarnak = pCreature->GetGUID(); break; + case CREATURE_KADDRAK: uiKaddrak = pCreature->GetGUID(); break; + case CREATURE_ABEDNEUM: uiAbedneum = pCreature->GetGUID(); break; + case CREATURE_BRANN: uiBrann = pCreature->GetGUID(); break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case GO_ABEDNEUM: + uiAbedneumGo = pGo->GetGUID(); + break; + case GO_MARNAK: + uiMarnakGo = pGo->GetGUID(); + break; + case GO_KADDRAK: + uiKaddrakGo = pGo->GetGUID(); + break; + case GO_MAIDEN_DOOR: + uiMaidenOfGriefDoor = pGo->GetGUID(); + if (m_auiEncounter[0] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + else + pGo->SetGoState(GO_STATE_READY); + break; + case GO_BRANN_DOOR: + uiBrannDoor = pGo->GetGUID(); + if (m_auiEncounter[1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + else + pGo->SetGoState(GO_STATE_READY); + break; + case GO_SJONNIR_DOOR: + uiSjonnirDoor = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + else + pGo->SetGoState(GO_STATE_READY); + break; + case GO_TRIBUNAL_CONSOLE: + uiTribunalConsole = pGo->GetGUID(); + break; + case GO_TRIBUNAL_CHEST: + case GO_TRIBUNAL_CHEST_HERO: + uiTribunalChest = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND); + break; + case 191527: + uiTribunalSkyFloor = pGo->GetGUID(); + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_MAIDEN_OF_GRIEF_EVENT: + m_auiEncounter[1] = data; + if (m_auiEncounter[1] == DONE) + HandleGameObject(uiBrannDoor,true); + break; + case DATA_KRYSTALLUS_EVENT: + m_auiEncounter[0] = data; + if (m_auiEncounter[0] == DONE) + HandleGameObject(uiMaidenOfGriefDoor,true); + break; + case DATA_SJONNIR_EVENT: + m_auiEncounter[3] = data; + break; + case DATA_BRANN_EVENT: + m_auiEncounter[2] = data; + if (m_auiEncounter[2] == DONE) + { + HandleGameObject(uiSjonnirDoor,true); + GameObject *pGo = instance->GetGameObject(uiTribunalChest); + if (pGo) + pGo->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND); + } + break; + } + + if (data == DONE) + SaveToDB(); + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_KRYSTALLUS_EVENT: return m_auiEncounter[0]; + case DATA_MAIDEN_OF_GRIEF_EVENT: return m_auiEncounter[1]; + case DATA_SJONNIR_EVENT: return m_auiEncounter[2]; + case DATA_BRANN_EVENT: return m_auiEncounter[3]; + } + + return 0; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_MAIDEN_OF_GRIEF: return uiMaidenOfGrief; + case DATA_KRYSTALLUS: return uiKrystallus; + case DATA_SJONNIR: return uiSjonnir; + case DATA_KADDRAK: return uiKaddrak; + case DATA_MARNAK: return uiMarnak; + case DATA_ABEDNEUM: return uiAbedneum; + case DATA_GO_TRIBUNAL_CONSOLE: return uiTribunalConsole; + case DATA_GO_KADDRAK: return uiKaddrakGo; + case DATA_GO_ABEDNEUM: return uiAbedneumGo; + case DATA_GO_MARNAK: return uiMarnakGo; + case DATA_GO_SKY_FLOOR: return uiTribunalSkyFloor; + case DATA_SJONNIR_DOOR: return uiSjonnirDoor; + case DATA_MAIDEN_DOOR: return uiMaidenOfGriefDoor; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "H S " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3; + + if (dataHead1 == 'H' && dataHead2 == 'S') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + m_auiEncounter[3] = data3; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_halls_of_stone(Map* pMap) +{ + return new instance_halls_of_stone(pMap); +} + +void AddSC_instance_halls_of_stone() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_halls_of_stone"; + newscript->GetInstanceData = &GetInstanceData_instance_halls_of_stone; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_algalon.cpp b/src/scripts/northrend/ulduar/ulduar/boss_algalon.cpp new file mode 100644 index 00000000000..a9f1be65f2d --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_algalon.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" diff --git a/src/scripts/northrend/ulduar/ulduar/boss_assembly_of_iron.cpp b/src/scripts/northrend/ulduar/ulduar/boss_assembly_of_iron.cpp new file mode 100644 index 00000000000..229f912e226 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_assembly_of_iron.cpp @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Assembly of Iron encounter +SD%Complete: 60% +SDComment: Runes need DB support, chain lightning won't cast, supercharge won't cast (pTarget error?) - it worked before during debugging. +SDCategory: Ulduar - Ulduar +EndScriptData */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +// Any boss +#define SPELL_SUPERCHARGE 61920 +#define SPELL_BERSERK 47008 // Hard enrage, don't know the correct ID. + +// Steelbreaker +#define SPELL_HIGH_VOLTAGE 61890 +#define SPELL_HIGH_VOLTAGE_H 63498 +#define SPELL_FUSION_PUNCH 61903 +#define SPELL_FUSION_PUNCH_H 63493 +#define SPELL_STATIC_DISRUPTION 44008 +#define SPELL_STATIC_DISRUPTION_H 63494 +#define SPELL_OVERWHELMING_POWER_H 61888 +#define SPELL_OVERWHELMING_POWER 64637 +#define SPELL_ELECTRICAL_CHARGE 61902 + +// Runemaster Molgeim +#define SPELL_SHIELD_OF_RUNES 62274 +#define SPELL_SHIELD_OF_RUNES_H 63489 +#define SPELL_RUNE_OF_POWER 64320 +#define SPELL_RUNE_OF_DEATH 62269 +#define SPELL_RUNE_OF_SUMMONING 62273 +#define SPELL_LIGHTNING_BLAST 62054 +#define SPELL_LIGHTNING_BLAST_H 63491 +#define CREATURE_RUNE_OF_SUMMONING 33051 + +// Stormcaller Brundir +#define SPELL_CHAIN_LIGHTNING_N 61879 +#define SPELL_CHAIN_LIGHTNING_H 63479 +#define SPELL_OVERLOAD 61869 +#define SPELL_OVERLOAD_H 63481 +#define SPELL_LIGHTNING_WHIRL 61915 +#define SPELL_LIGHTNING_WHIRL_H 63483 +#define SPELL_LIGHTNING_TENDRILS 61887 +#define SPELL_LIGHTNING_TENDRILS_H 63486 +#define SPELL_STORMSHIELD 64187 + +enum eEnums +{ + EVENT_ENRAGE, + // Steelbreaker + EVENT_FUSION_PUNCH, + EVENT_STATIC_DISRUPTION, + EVENT_OVERWHELMING_POWER, + // Molgeim + EVENT_RUNE_OF_POWER, + EVENT_SHIELD_OF_RUNES, + EVENT_RUNE_OF_DEATH, + EVENT_RUNE_OF_SUMMONING, + EVENT_LIGHTNING_BLAST, + // Brundir + EVENT_CHAIN_LIGHTNING, + EVENT_OVERLOAD, + EVENT_LIGHTNING_WHIRL, + EVENT_LIGHTNING_TENDRILS, + EVENT_STORMSHIELD, + MAX_EVENT + +}; + +bool IsEncounterComplete(ScriptedInstance* pInstance, Creature* m_creature) +{ + if (!pInstance || !m_creature) + return false; + + for (uint8 i = 0; i < 3; ++i) + { + uint64 guid = pInstance->GetData64(DATA_STEELBREAKER+i); + if(!guid) + return false; + + if(Creature *boss = (Unit::GetCreature((*m_creature), guid))) + { + if(boss->isAlive()) + return false; + + continue; + } + else + return false; + } + return true; +} + +struct TRINITY_DLL_DECL boss_steelbreakerAI : public ScriptedAI +{ + boss_steelbreakerAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + void Reset() + { + events.Reset(); + phase = 0; + m_creature->RemoveAllAuras(); + if(pInstance) + pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); + } + + EventMap events; + ScriptedInstance* pInstance; + uint32 phase; + + void EnterCombat(Unit *who) + { + DoZoneInCombat(); + DoCast(m_creature, RAID_MODE(SPELL_HIGH_VOLTAGE, SPELL_HIGH_VOLTAGE_H)); + events.ScheduleEvent(EVENT_ENRAGE, 900000); + UpdatePhase(); + } + + void UpdatePhase() + { + ++phase; + 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, rand()%5000); + } + + void DamageTaken(Unit* pKiller, uint32 &damage) + { + if(damage >= m_creature->GetHealth()) + { + if(Creature* Brundir = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_STORMCALLER_BRUNDIR) : 0)) + if(Brundir->isAlive()) + { + Brundir->SetHealth(Brundir->GetMaxHealth()); + } + + if(Creature* Molgeim = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_RUNEMASTER_MOLGEIM) : 0)) + if(Molgeim->isAlive()) + { + Molgeim->SetHealth(Molgeim->GetMaxHealth()); + } + DoCast(SPELL_SUPERCHARGE); + } + } + + void JustDied(Unit* Killer) + { + if(IsEncounterComplete(pInstance, m_creature) && pInstance) + pInstance->SetData(TYPE_ASSEMBLY, DONE); + } + + void KilledUnit(Unit *who) + { + if(phase == 3) + DoCast(m_creature, SPELL_ELECTRICAL_CHARGE); + } + + void SpellHit(Unit *from, const SpellEntry *spell) + { + if(spell->Id == SPELL_SUPERCHARGE) + UpdatePhase(); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_ENRAGE: + DoCast(SPELL_BERSERK); + break; + case EVENT_FUSION_PUNCH: + DoCast(me->getVictim(), RAID_MODE(SPELL_FUSION_PUNCH_H, SPELL_FUSION_PUNCH)); + events.ScheduleEvent(EVENT_FUSION_PUNCH, 13000 + (rand()%9)*1000); + break; + case EVENT_STATIC_DISRUPTION: + { + Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM); + DoCast(pTarget, RAID_MODE(SPELL_STATIC_DISRUPTION_H, SPELL_STATIC_DISRUPTION)); + events.ScheduleEvent(EVENT_STATIC_DISRUPTION, 20000 + (rand()%20)*1000); + } + break; + case EVENT_OVERWHELMING_POWER: + DoCast(me->getVictim(), RAID_MODE(SPELL_OVERWHELMING_POWER, SPELL_OVERWHELMING_POWER_H)); + events.ScheduleEvent(EVENT_OVERWHELMING_POWER, RAID_MODE(60000, 35000)); + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL boss_runemaster_molgeimAI : public ScriptedAI +{ + boss_runemaster_molgeimAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + void Reset() + { + if(pInstance) + pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); + events.Reset(); + m_creature->RemoveAllAuras(); + phase = 0; + } + + ScriptedInstance* pInstance; + EventMap events; + uint32 phase; + + void EnterCombat(Unit* who) + { + DoZoneInCombat(); + events.ScheduleEvent(EVENT_ENRAGE, 900000); + UpdatePhase(); + } + + void UpdatePhase() + { + ++phase; + events.SetPhase(phase); + events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 27000); + events.RescheduleEvent(EVENT_RUNE_OF_POWER, 60000); + if(phase >= 2) + events.RescheduleEvent(EVENT_RUNE_OF_DEATH, 30000); + if(phase >= 3) + events.RescheduleEvent(EVENT_RUNE_OF_SUMMONING, 20000+(rand()%10)*1000); + } + + void DamageTaken(Unit* pKiller, uint32 &damage) + { + if(damage >= m_creature->GetHealth()) + { + if(Creature* Steelbreaker = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_STEELBREAKER) : 0)) + if(Steelbreaker->isAlive()) + { + Steelbreaker->SetHealth(Steelbreaker->GetMaxHealth()); + } + + if(Creature* Brundir = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_STORMCALLER_BRUNDIR) : 0)) + if(Brundir->isAlive()) + { + Brundir->SetHealth(Brundir->GetMaxHealth()); + } + DoCast(m_creature, SPELL_SUPERCHARGE); + } + } + + void JustDied(Unit* Killer) + { + if(IsEncounterComplete(pInstance, m_creature) && pInstance) + pInstance->SetData(TYPE_ASSEMBLY, DONE); + } + + void SpellHit(Unit *from, const SpellEntry *spell) + { + if(spell->Id == SPELL_SUPERCHARGE) + UpdatePhase(); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_ENRAGE: + DoCast(SPELL_BERSERK); + break; + case EVENT_RUNE_OF_POWER: // Improve target selection; random alive friendly + { + Unit *Target = DoSelectLowestHpFriendly(60); + if(!Target || (Target && !Target->isAlive())) + Target = m_creature; + DoCast(Target, SPELL_RUNE_OF_POWER); + events.ScheduleEvent(EVENT_RUNE_OF_POWER, 60000); + } + break; + case EVENT_SHIELD_OF_RUNES: + DoCast(m_creature, RAID_MODE(SPELL_SHIELD_OF_RUNES, SPELL_SHIELD_OF_RUNES_H)); + events.ScheduleEvent(EVENT_SHIELD_OF_RUNES, 27000+ (rand()%7)*1000); + break; + case EVENT_RUNE_OF_DEATH: + { + Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM); + DoCast(pTarget, SPELL_RUNE_OF_DEATH); + events.ScheduleEvent(EVENT_RUNE_OF_DEATH, 30000+ (rand()%10)*1000); + } + break; + case EVENT_RUNE_OF_SUMMONING: + { + Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM); + DoCast(pTarget, SPELL_RUNE_OF_SUMMONING); + events.ScheduleEvent(EVENT_RUNE_OF_SUMMONING, 20000+(rand()%10)*1000); + } + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL mob_lightning_elementalAI : public ScriptedAI +{ + mob_lightning_elementalAI(Creature *c) : ScriptedAI(c) + { + Charge(); + } + + Unit* Target; + + void Charge() + { + Target = m_creature->SelectNearestTarget(); + m_creature->AddThreat(Target, 5000000.0f); + AttackStart(Target); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->isInCombat()) + return; + + if(m_creature->IsWithinMeleeRange(Target)) + { + DoCast(Target, RAID_MODE(SPELL_LIGHTNING_BLAST, SPELL_LIGHTNING_BLAST_H)); + m_creature->Kill(m_creature); // hack until spell works + } + + m_creature->GetMotionMaster()->MoveChase(Target); // needed at every update? + } + +}; + +struct TRINITY_DLL_DECL mob_rune_of_summoningAI : public ScriptedAI +{ + mob_rune_of_summoningAI(Creature *c) : ScriptedAI(c) + { + SummonLightningElemental(); + } + + void SummonLightningElemental() + { + m_creature->SummonCreature(CREATURE_RUNE_OF_SUMMONING, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN ); + m_creature->DealDamage(m_creature, m_creature->GetHealth()); + } +}; + +struct TRINITY_DLL_DECL boss_stormcaller_brundirAI : public ScriptedAI +{ + boss_stormcaller_brundirAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + void Reset() + { + if(pInstance) + pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); + m_creature->RemoveAllAuras(); + events.Reset(); + phase = 0; + } + + EventMap events; + ScriptedInstance* pInstance; + uint32 phase; + + void EnterCombat(Unit* who) + { + DoZoneInCombat(); + events.ScheduleEvent(EVENT_ENRAGE, 900000); + UpdatePhase(); + } + + void UpdatePhase() + { + ++phase; + events.SetPhase(phase); + events.RescheduleEvent(EVENT_CHAIN_LIGHTNING, 9000+ (rand()%8)*1000); + events.RescheduleEvent(EVENT_OVERLOAD, 60000+ (rand()%65)*1000); + if(phase >= 2) + events.RescheduleEvent(EVENT_LIGHTNING_WHIRL, 20000+ (rand()%20)*1000); + if(phase >= 3) + { + DoCast(m_creature, SPELL_STORMSHIELD); + events.RescheduleEvent(EVENT_LIGHTNING_TENDRILS, 40000+ (rand()%40)*1000); + } + + } + + void DamageTaken(Unit* pKiller, uint32 &damage) + { + if(damage >= m_creature->GetHealth()) + { + if(Creature* Steelbreaker = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_STEELBREAKER) : 0)) + if(Steelbreaker->isAlive()) + { + Steelbreaker->SetHealth(Steelbreaker->GetMaxHealth()); + } + + if(Creature* Molgeim = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_RUNEMASTER_MOLGEIM) : 0)) + if(Molgeim->isAlive()) + { + Molgeim->SetHealth(Molgeim->GetMaxHealth()); + } + + DoCast(SPELL_SUPERCHARGE); + } + } + + void JustDied(Unit* Killer) + { + if(IsEncounterComplete(pInstance, m_creature) && pInstance) + pInstance->SetData(TYPE_ASSEMBLY, DONE); + } + + void SpellHit(Unit *from, const SpellEntry *spell) + { + if(spell->Id == SPELL_SUPERCHARGE) + { + UpdatePhase(); + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_ENRAGE: + DoCast(SPELL_BERSERK); + break; + case EVENT_CHAIN_LIGHTNING: + { + Unit* Target = SelectUnit(SELECT_TARGET_RANDOM,0); + DoCast(Target, RAID_MODE(SPELL_CHAIN_LIGHTNING_N , SPELL_CHAIN_LIGHTNING_H)); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 9000+ (rand()%8)*1000); + } + break; + case EVENT_OVERLOAD: + DoCast(RAID_MODE(SPELL_OVERLOAD , SPELL_OVERLOAD_H)); + events.ScheduleEvent(EVENT_OVERLOAD, 60000+ (rand()%65)*1000); + break; + case EVENT_LIGHTNING_WHIRL: + DoCast(RAID_MODE(SPELL_LIGHTNING_WHIRL , SPELL_LIGHTNING_WHIRL_H)); + events.ScheduleEvent(EVENT_LIGHTNING_WHIRL, 20000+ (rand()%20)*1000); + break; + case EVENT_LIGHTNING_TENDRILS: + DoCast(RAID_MODE(SPELL_LIGHTNING_TENDRILS, SPELL_LIGHTNING_TENDRILS_H)); + events.DelayEvents(15000, 5000); + DoResetThreat(); + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_steelbreaker(Creature* pCreature) +{ + return new boss_steelbreakerAI (pCreature); +} + +CreatureAI* GetAI_boss_runemaster_molgeim(Creature* pCreature) +{ + return new boss_runemaster_molgeimAI (pCreature); +} + +CreatureAI* GetAI_boss_stormcaller_brundir(Creature* pCreature) +{ + return new boss_stormcaller_brundirAI (pCreature); +} + +CreatureAI* GetAI_mob_lightning_elemental(Creature* pCreature) +{ + return new mob_lightning_elementalAI (pCreature); +} + +CreatureAI* GetAI_mob_rune_of_summoning(Creature* pCreature) +{ + return new mob_rune_of_summoningAI (pCreature); +} + +void AddSC_boss_assembly_of_iron() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_steelbreaker"; + newscript->GetAI = &GetAI_boss_steelbreaker; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_runemaster_molgeim"; + newscript->GetAI = &GetAI_boss_runemaster_molgeim; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_stormcaller_brundir"; + newscript->GetAI = &GetAI_boss_stormcaller_brundir; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_lightning_elemental"; + newscript->GetAI = &GetAI_mob_lightning_elemental; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_rune_of_summoning"; + newscript->GetAI = &GetAI_mob_rune_of_summoning; + newscript->RegisterSelf(); + +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp b/src/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp new file mode 100644 index 00000000000..c3ae8c01f59 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +//boss_auriaya +#define SPELL_TERRIFYING_SCREECH 64386 +#define SPELL_SETINEL_BLAST 64679 +#define SPELL_SONIC_SCREECH 64422 +#define SPELL_SUMMON_SWARMING_GUARDIAN 64397 +//wrong text ids. correct are beetwen -1000000 AND -1999999 +//beetwen -2000000 and -2999999 are custom texts so wtf? +#define SAY_AGGRO -2615016 +#define SAY_SLAY_1 -2615017 + +struct TRINITY_DLL_DECL boss_auriaya_AI : public BossAI +{ + boss_auriaya_AI(Creature *pCreature) : BossAI(pCreature, TYPE_AURIAYA) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 TERRIFYING_SCREECH_Timer; + uint32 SONIC_SCREECH_Timer; + + void Reset() + { + TERRIFYING_SCREECH_Timer = 180000; + SONIC_SCREECH_Timer = 30000; + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO,m_creature); + } + void KilledUnit(Unit* victim) + { + DoScriptText(SAY_SLAY_1, m_creature); + } + + void JustDied(Unit *victim) + { + DoScriptText(SAY_SLAY_1, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_AURIAYA, DONE); + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (TERRIFYING_SCREECH_Timer <= diff) + { + DoCast(SPELL_TERRIFYING_SCREECH); + DoScriptText(SAY_SLAY_1, m_creature); + TERRIFYING_SCREECH_Timer = 180000; + } else TERRIFYING_SCREECH_Timer -= diff; + + if (SONIC_SCREECH_Timer <= diff) + { + DoCastVictim(SPELL_SONIC_SCREECH); + SONIC_SCREECH_Timer = 30000; + } else SONIC_SCREECH_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_auriaya(Creature* pCreature) +{ + return new boss_auriaya_AI (pCreature); +} +void AddSC_boss_auriaya() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_auriaya"; + newscript->GetAI = &GetAI_boss_auriaya; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp b/src/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp new file mode 100644 index 00000000000..b05e59cad20 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" +#include "Vehicle.h" + +#define SPELL_PURSUED 62374 +#define SPELL_GATHERING_SPEED 62375 +#define SPELL_BATTERING_RAM 62376 +#define SPELL_FLAME_VENTS 62396 +#define SPELL_MISSILE_BARRAGE 62400 +#define SPELL_SYSTEMS_SHUTDOWN 62475 + +#define SPELL_FLAME_CANNON 62395 +//#define SPELL_FLAME_CANNON 64692 trigger the same spell + +#define SPELL_OVERLOAD_CIRCUIT 62399 + +#define SPELL_SEARING_FLAME 62402 + +#define SPELL_BLAZE 62292 + +#define SPELL_SMOKE_TRAIL 63575 + +#define SPELL_MIMIRON_INFERNO 62910 + +#define SPELL_HODIR_FURY 62297 + +#define SPELL_ELECTROSHOCK 62522 + +enum Mobs +{ + MOB_MECHANOLIFT = 33214, + MOB_LIQUID = 33189, + MOB_CONTAINER = 33218, +}; + +enum Events +{ + EVENT_PURSUE = 1, + EVENT_MISSILE, + EVENT_VENT, + EVENT_SPEED, + EVENT_SUMMON, + EVENT_MIMIRON_INFERNO, // Not Blizzlike + EVENT_HODIR_FURY, // Not Blizzlike +}; + +enum Seats +{ + SEAT_PLAYER = 0, + SEAT_TURRET = 1, + SEAT_DEVICE = 2, +}; + +struct TRINITY_DLL_DECL boss_flame_leviathanAI : public BossAI +{ + boss_flame_leviathanAI(Creature *pCreature) : BossAI(pCreature, TYPE_LEVIATHAN), vehicle(me->GetVehicleKit()) + { + m_pInstance = pCreature->GetInstanceData(); + assert(vehicle); + } + + ScriptedInstance* m_pInstance; + + Vehicle *vehicle; + + void Reset() + { + _Reset(); + me->SetReactState(REACT_AGGRESSIVE); + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + me->SetReactState(REACT_DEFENSIVE); + events.ScheduleEvent(EVENT_PURSUE, 0); + events.ScheduleEvent(EVENT_MISSILE, 1500); + events.ScheduleEvent(EVENT_VENT, 20000); + events.ScheduleEvent(EVENT_SPEED, 15000); + events.ScheduleEvent(EVENT_SUMMON, 0); + //events.ScheduleEvent(EVENT_MIMIRON_INFERNO, 60000 + (rand()%60000)); // Not Blizzlike + //events.ScheduleEvent(EVENT_HODIR_FURY, 60000 + (rand()%60000)); // Not Blizzlike + if (Creature *turret = CAST_CRE(vehicle->GetPassenger(7))) + turret->AI()->DoZoneInCombat(); + } + + // TODO: effect 0 and effect 1 may be on different target + void SpellHitTarget(Unit *pTarget, const SpellEntry *spell) + { + if (spell->Id == SPELL_PURSUED) + AttackStart(pTarget); + } + + void JustDied(Unit *victim) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LEVIATHAN, DONE); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if(spell->Id == 62472) + vehicle->InstallAllAccessories(); + else if(spell->Id == SPELL_ELECTROSHOCK) + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + } + + void UpdateAI(const uint32 diff) + { + if (!me->isInCombat()) + return; + + if (me->getThreatManager().isThreatListEmpty()) + { + EnterEvadeMode(); + return; + } + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + uint32 eventId = events.GetEvent(); + if (!me->getVictim()) + eventId = EVENT_PURSUE; + + switch(eventId) + { + case 0: break; // this is a must + case EVENT_PURSUE: + DoCastAOE(SPELL_PURSUED, true); + //events.RepeatEvent(35000); // this should not be used because eventId may be overriden + events.RescheduleEvent(EVENT_PURSUE, 35000); + if(!me->getVictim()) // all siege engines and demolishers are dead + UpdateVictim(); // begin to kill other things + return; + case EVENT_MISSILE: + //TODO: without target no visual effect + //DoCastAOE(SPELL_MISSILE_BARRAGE); + DoCast(me->getVictim(), SPELL_MISSILE_BARRAGE); + events.RepeatEvent(1500); + return; + case EVENT_VENT: + DoCastAOE(SPELL_FLAME_VENTS); + events.RepeatEvent(20000); + return; + case EVENT_SPEED: + DoCastAOE(SPELL_GATHERING_SPEED); + events.RepeatEvent(15000); + return; + case EVENT_SUMMON: + if(summons.size() < 15) // 4seat+1turret+10lift + if(Creature *lift = DoSummonFlyer(MOB_MECHANOLIFT, me, rand()%20 + 20, 50, 0)) + lift->GetMotionMaster()->MoveRandom(100); + events.RepeatEvent(2000); + return; + case EVENT_MIMIRON_INFERNO: // Not Blizzlike + DoCast(me->getVictim(), SPELL_MIMIRON_INFERNO); + events.RepeatEvent(60000 + (rand()%60000)); + return; + case EVENT_HODIR_FURY: // Not Blizzlike + DoCast(me->getVictim(), SPELL_HODIR_FURY); + events.RepeatEvent(60000 + (rand()%60000)); + default: + events.PopEvent(); + break; + } + + DoSpellAttackIfReady(SPELL_BATTERING_RAM); + } +}; + +//#define BOSS_DEBUG + +struct TRINITY_DLL_DECL boss_flame_leviathan_seatAI : public PassiveAI +{ + boss_flame_leviathan_seatAI(Creature *c) : PassiveAI(c), vehicle(c->GetVehicleKit()) + { + assert(vehicle); +#ifdef BOSS_DEBUG + me->SetReactState(REACT_AGGRESSIVE); +#endif + } + + Vehicle *vehicle; + +#ifdef BOSS_DEBUG + void MoveInLineOfSight(Unit *who) + { + if(who->GetTypeId() == TYPEID_PLAYER && CAST_PLR(who)->isGameMaster() + && !who->GetVehicle() && vehicle->GetPassenger(SEAT_TURRET)) + who->EnterVehicle(vehicle, SEAT_PLAYER); + } +#endif + + void PassengerBoarded(Unit *who, int8 seatId, bool apply) + { + if(!me->GetVehicle()) + return; + + if(seatId == SEAT_PLAYER) + { + if(!apply) + return; + + if(Creature *turret = CAST_CRE(vehicle->GetPassenger(SEAT_TURRET))) + { + turret->setFaction(me->GetVehicleBase()->getFaction()); + turret->SetUInt32Value(UNIT_FIELD_FLAGS, 0); // unselectable + turret->AI()->AttackStart(who); + } + if(Unit *device = vehicle->GetPassenger(SEAT_DEVICE)) + { + device->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + device->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 + } + } + } +}; + +struct TRINITY_DLL_DECL boss_flame_leviathan_defense_turretAI : public TurretAI +{ + boss_flame_leviathan_defense_turretAI(Creature *c) : TurretAI(c) {} + + void DamageTaken(Unit *who, uint32 &damage) + { + if(!CanAIAttack(who)) + damage = 0; + } + + bool CanAIAttack(const Unit *who) const + { + if (who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() != 33114) + return false; + return true; + } +}; + +struct TRINITY_DLL_DECL boss_flame_leviathan_overload_deviceAI : public PassiveAI +{ + boss_flame_leviathan_overload_deviceAI(Creature *c) : PassiveAI(c) {} + + void DoAction(const int32 param) + { + if(param == EVENT_SPELLCLICK) + { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if(me->GetVehicle()) + { + if(Unit *player = me->GetVehicle()->GetPassenger(SEAT_PLAYER)) + { + player->ExitVehicle(); + me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true); + if(Unit *leviathan = me->GetVehicleBase()->GetVehicleBase()) + player->GetMotionMaster()->MoveKnockbackFrom(leviathan->GetPositionX(), leviathan->GetPositionY(), 30, 30); + } + } + } + } +}; + +struct TRINITY_DLL_DECL boss_flame_leviathan_safety_containerAI : public PassiveAI +{ + boss_flame_leviathan_safety_containerAI(Creature *c) : PassiveAI(c) {} + + void MovementInform(uint32 type, uint32 id) + { + if(id == me->GetEntry()) + { + if(Creature *liquid = DoSummon(MOB_LIQUID, me, 0)) + liquid->CastSpell(liquid, 62494, true); + me->DisappearAndDie(); // this will relocate creature to sky + } + } + + void UpdateAI(const uint32 diff) + { + if(!me->GetVehicle() && me->isSummon() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) + me->GetMotionMaster()->MoveFall(409.8f, me->GetEntry()); + } +}; + +struct TRINITY_DLL_DECL spell_pool_of_tarAI : public TriggerAI +{ + spell_pool_of_tarAI(Creature *c) : TriggerAI(c) + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void DamageTaken(Unit *who, uint32 &damage) + { + damage = 0; + } + + void SpellHit(Unit* caster, const SpellEntry *spell) + { + if(spell->SchoolMask & SPELL_SCHOOL_MASK_FIRE && !me->HasAura(SPELL_BLAZE)) + me->CastSpell(me, SPELL_BLAZE, true); + } +}; + +CreatureAI* GetAI_boss_flame_leviathan(Creature* pCreature) +{ + return new boss_flame_leviathanAI (pCreature); +} + +CreatureAI* GetAI_boss_flame_leviathan_seat(Creature* pCreature) +{ + return new boss_flame_leviathan_seatAI (pCreature); +} + +CreatureAI* GetAI_boss_flame_leviathan_defense_turret(Creature* pCreature) +{ + return new boss_flame_leviathan_defense_turretAI (pCreature); +} + +CreatureAI* GetAI_boss_flame_leviathan_overload_device(Creature* pCreature) +{ + return new boss_flame_leviathan_overload_deviceAI (pCreature); +} + +CreatureAI* GetAI_boss_flame_leviathan_safety_containerAI(Creature* pCreature) +{ + return new boss_flame_leviathan_safety_containerAI(pCreature); +} + +CreatureAI* GetAI_spell_pool_of_tar(Creature* pCreature) +{ + return new spell_pool_of_tarAI (pCreature); +} + +void AddSC_boss_flame_leviathan() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_flame_leviathan"; + newscript->GetAI = &GetAI_boss_flame_leviathan; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_flame_leviathan_seat"; + newscript->GetAI = &GetAI_boss_flame_leviathan_seat; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_flame_leviathan_defense_turret"; + newscript->GetAI = &GetAI_boss_flame_leviathan_defense_turret; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_flame_leviathan_overload_device"; + newscript->GetAI = &GetAI_boss_flame_leviathan_overload_device; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_flame_leviathan_safety_container"; + newscript->GetAI = &GetAI_boss_flame_leviathan_safety_containerAI; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "spell_pool_of_tar"; + newscript->GetAI = &GetAI_spell_pool_of_tar; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_freya.cpp b/src/scripts/northrend/ulduar/ulduar/boss_freya.cpp new file mode 100644 index 00000000000..22f53c3a2e8 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_freya.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +/* +#define SAY_AGGRO -1 +#define SAY_SLAY -1 +*/ + +struct TRINITY_DLL_DECL boss_freyaAI : public BossAI +{ + boss_freyaAI(Creature* pCreature) : BossAI(pCreature, TYPE_FREYA) + { + m_pInstance = pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + } + + void KilledUnit(Unit *victim) + { + } + + void JustDied(Unit *victim) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FREYA, DONE); + } + + void Aggro(Unit* pWho) + { +// DoScriptText(SAY_AGGRO, m_creature); + m_creature->SetInCombatWithZone(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FREYA, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; +//SPELLS TODO: + +// + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(diff); + } +}; + +CreatureAI* GetAI_boss_freya(Creature* pCreature) +{ + return new boss_freyaAI(pCreature); +} + +void AddSC_boss_freya() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_freya"; + newscript->GetAI = &GetAI_boss_freya; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp b/src/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp new file mode 100644 index 00000000000..a9f1be65f2d --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" diff --git a/src/scripts/northrend/ulduar/ulduar/boss_hodir.cpp b/src/scripts/northrend/ulduar/ulduar/boss_hodir.cpp new file mode 100644 index 00000000000..8603d287b99 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_hodir.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +/* +#define SAY_AGGRO -1 +#define SAY_SLAY -1 +*/ + +struct TRINITY_DLL_DECL boss_hodirAI : public BossAI +{ + boss_hodirAI(Creature *pCreature) : BossAI(pCreature, TYPE_HODIR) + { + m_pInstance = pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + } + + void KilledUnit(Unit *victim) + { + } + + void JustDied(Unit *victim) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HODIR, DONE); + } + + void Aggro(Unit* pWho) + { +// DoScriptText(SAY_AGGRO, m_creature); + m_creature->SetInCombatWithZone(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_HODIR, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; +//SPELLS TODO: + +// + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(diff); + + } + +}; + +CreatureAI* GetAI_boss_hodir(Creature* pCreature) +{ + return new boss_hodirAI(pCreature); +} + +void AddSC_boss_hodir() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_hodir"; + newscript->GetAI = &GetAI_boss_hodir; + newscript->RegisterSelf(); + +} + diff --git a/src/scripts/northrend/ulduar/ulduar/boss_ignis.cpp b/src/scripts/northrend/ulduar/ulduar/boss_ignis.cpp new file mode 100644 index 00000000000..3c924b07289 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_ignis.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +#define SPELL_FLAME_JETS 62680 +#define SPELL_SCORCH 62546 +#define SPELL_SLAG_POT 62717 + +//wrong ids. not in db +#define SAY_AGGRO -10000002 +#define SAY_SLAY -1000003 + +struct TRINITY_DLL_DECL boss_ignis_AI : public BossAI +{ + boss_ignis_AI(Creature *pCreature) : BossAI(pCreature, TYPE_IGNIS) {} + + uint32 FLAME_JETS_Timer; + uint32 SCORCH_Timer; + uint32 SLAG_POT_Timer; + + void Reset() + { + FLAME_JETS_Timer = 32000; + SCORCH_Timer = 100; + SLAG_POT_Timer = 100; + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO,m_creature); + } + void KilledUnit(Unit* victim) + { + DoScriptText(SAY_SLAY, m_creature); + } + + void JustDied(Unit *victim) + { + DoScriptText(SAY_SLAY, m_creature); + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if(m_creature->GetPositionY() < 150 || m_creature->GetPositionX() < 450) // Not Blizzlike, anti-exploit to prevent players from pulling bosses to vehicles. + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(false); + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + + if (FLAME_JETS_Timer <= diff) + { + DoCast(SPELL_FLAME_JETS); + DoScriptText(SAY_SLAY, m_creature); + FLAME_JETS_Timer = 25000; + } else FLAME_JETS_Timer -= diff; + + if (SCORCH_Timer <= diff) + { + DoCast(SPELL_SCORCH); + SCORCH_Timer = 20000; + } else SCORCH_Timer -= diff; + + if (SLAG_POT_Timer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_SLAG_POT); + DoScriptText(SAY_SLAY, m_creature); + SLAG_POT_Timer = 30000; + } else SLAG_POT_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ignis(Creature* pCreature) +{ + return new boss_ignis_AI (pCreature); +} +void AddSC_boss_ignis() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_ignis"; + newscript->GetAI = &GetAI_boss_ignis; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp b/src/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp new file mode 100644 index 00000000000..4701a63fca1 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" +#include "Vehicle.h" + +#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_STONE_SHOUT RAID_MODE(63716,64005) +#define SPELL_PETRIFY_BREATH RAID_MODE(62030,63980) + +#define SPELL_STONE_GRIP RAID_MODE(62166,63981) +#define SPELL_ARM_SWEEP RAID_MODE(63766,63983) + +enum Events +{ + EVENT_NONE = 0, + EVENT_SMASH, + EVENT_GRIP, + EVENT_SWEEP, +}; + +struct TRINITY_DLL_DECL boss_kologarnAI : public BossAI +{ + boss_kologarnAI(Creature *pCreature) : BossAI(pCreature, TYPE_KOLOGARN), vehicle(me->GetVehicleKit()), + left(false), right(false) + { + m_pInstance = me->GetInstanceData(); + assert(vehicle); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); // i think this is a hack, but there is no other way to disable his rotation + } + + ScriptedInstance* m_pInstance; + + Vehicle *vehicle; + bool left, right; + + void AttackStart(Unit *who) + { + me->Attack(who, true); + } + + void JustDied(Unit *victim) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KOLOGARN, DONE); + } + + void PassengerBoarded(Unit *who, int8 seatId, bool apply) + { + if(who->GetTypeId() == TYPEID_UNIT) + { + if(who->GetEntry() == 32933) + left = apply; + else if(who->GetEntry() == 32934) + right = apply; + who->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + CAST_CRE(who)->SetReactState(REACT_PASSIVE); + } + } + + void EnterCombat(Unit *who) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_SMASH, 5000); + events.ScheduleEvent(EVENT_SWEEP, 10000); + events.ScheduleEvent(EVENT_GRIP, 15000); + } + + void UpdateAI(const uint32 diff) + { + if(!UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + // TODO: because we are using hack, he is stunned and cannot cast, so we use triggered for every spell + switch(events.GetEvent()) + { + case EVENT_NONE: break; + case EVENT_SMASH: + if(left && right) + DoCastVictim(SPELL_TWO_ARM_SMASH, true); + else if(left || right) + DoCastVictim(SPELL_ONE_ARM_SMASH, true); + events.RepeatEvent(15000); + break; + case EVENT_SWEEP: + if(left) + DoCastAOE(SPELL_ARM_SWEEP, true); + events.RepeatEvent(15000); + break; + case EVENT_GRIP: + if(right) + DoCastAOE(SPELL_STONE_GRIP, true); + events.RepeatEvent(15000); + break; + default: + events.PopEvent(); + break; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_kologarn(Creature* pCreature) +{ + return new boss_kologarnAI (pCreature); +} + +void AddSC_boss_kologarn() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_kologarn"; + newscript->GetAI = &GetAI_boss_kologarn; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp b/src/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp new file mode 100644 index 00000000000..a9f1be65f2d --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" diff --git a/src/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp b/src/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp new file mode 100644 index 00000000000..cf114e00897 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: razorscale +SDAuthor: MaXiMiUS +SD%Complete: 65 +EndScriptData */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +//not in db +#define SAY_AGGRO -2000000 +#define SAY_KILL -2000001 +#define SAY_PHASE_2_TRANS -2000002 +#define SAY_PHASE_3_TRANS -2000003 +#define EMOTE_BREATH -2000004 + +enum Spells +{ + SPELL_FLAMEBUFFET = 64016, + SPELL_FIREBALL = 62796, + + SPELL_WINGBUFFET = 62666, + SPELL_FLAMEBREATH = 63317, + SPELL_FUSEARMOR = 64771, + SPELL_DEVOURINGFLAME = 63014 +}; + +enum Mobs +{ + NPC_DARK_RUNE_SENTINEL = 33846 +}; + +struct TRINITY_DLL_DECL boss_razorscaleAI : public BossAI +{ + boss_razorscaleAI(Creature *pCreature) : BossAI(pCreature, TYPE_RAZORSCALE) {} + + uint8 Phase; + + uint32 FlameBreathTimer; + uint32 FuseArmorTimer; + uint32 DevouringFlameTimer; + uint32 FlameBuffetTimer; + uint32 SummonAddsTimer; + uint32 WingBuffetTimer; + uint32 FireballTimer; + //uint32 StunTimer; + //uint32 CastSpellsTimer; + + bool InitialSpawn; + bool IsFlying; + + void Reset() + { + Phase = 1; + + FlyPhase(Phase, 0); + + FlameBreathTimer = 20000; + DevouringFlameTimer = 2000; + FuseArmorTimer = 15000; + FlameBuffetTimer = 3000; + SummonAddsTimer = 45000; + WingBuffetTimer = 17000; + FireballTimer = 18000; + //StunTimer = 30000; + //CastSpellsTimer = 0; + + InitialSpawn = true; + IsFlying = true; + + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + DoZoneInCombat(); + } + + void JustDied(Unit* Killer) + { + } + + void KilledUnit(Unit *victim) + { + DoScriptText(SAY_KILL, m_creature); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if(m_creature->GetPositionY() > -60 || m_creature->GetPositionX() < 450) // Not Blizzlike, anti-exploit to prevent players from pulling bosses to vehicles. + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(false); + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + + // Victim is not controlled by a player (should never happen) + if (m_creature->getVictim() && !m_creature->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()) + m_creature->Kill(m_creature->getVictim()); + + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 99 && Phase == 1) // TODO: Only land (exit Phase 1) if brought down with harpoon guns! This is important! + { + Phase = 2; + DoScriptText(SAY_PHASE_2_TRANS, m_creature); // Audio: "Move quickly! She won't remain grounded for long!" + } + + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 33 && Phase == 2) // Health under 33%, Razorscale can't fly anymore. + { + Phase = 3; + DoScriptText(SAY_PHASE_3_TRANS, m_creature); // "Razorscale lands permanently!" + // TODO: Cast Devouring Flame on all harpoon guns simultaneously, briefly after Phase 3 starts (lasts until the harpoon guns are destroyed) + } + + /* + if (Phase == 2 && CastSpellsTimer > 0) // 5 seconds of spell casting, after stun breaks, during Phase 2 + { + if (CastSpellsTimer <= diff) // 5 seconds are up + Phase = 1; // Return to phase 1 + else + CastSpellsTimer -= diff; + }*/ + + FlyPhase(Phase, diff); + + if (Phase >= 2) // Ground Phase (Phase 3 = permanent ground phase) + { + if (FuseArmorTimer <= diff) + { + DoCastVictim(SPELL_FUSEARMOR); + FuseArmorTimer = 10000; + } else FuseArmorTimer -= diff; + + if (WingBuffetTimer <= diff) + { + DoCast(SPELL_WINGBUFFET); + WingBuffetTimer = urand(7000,14000); + } else WingBuffetTimer -= diff; + + if (FireballTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true)) + { + m_creature->SetInFront(pTarget); + DoCast(pTarget, SPELL_FIREBALL); + } + + FireballTimer = 18000; + } else FireballTimer -= diff; + + if (FlameBreathTimer <= diff) + { + DoScriptText(EMOTE_BREATH, m_creature); // TODO: "Razorscale takes a deep breath..." + DoCastVictim(SPELL_FLAMEBREATH); + FlameBreathTimer = 15000; + WingBuffetTimer = 0; + } else FlameBreathTimer -= diff; + + if (Phase == 3) + { + if (FlameBuffetTimer <= diff) + { + DoScriptText(EMOTE_BREATH, m_creature); + std::list<Unit*> pTargets; + SelectTargetList(pTargets, RAID_MODE(3,9), SELECT_TARGET_RANDOM, 100, true); + uint8 i = 0; + for (std::list<Unit*>::iterator itr = pTargets.begin(); itr != pTargets.end();) + { + if (m_creature->HasInArc(M_PI, *itr)) + { + DoCast(*itr, SPELL_FLAMEBUFFET, true); + ++i; + } + if (++itr == pTargets.end() || i == RAID_MODE(3,9)) + { + AttackStart(*--itr); // seems to attack targets randomly during perma-ground phase.. + break; + } + } + FlameBuffetTimer = 25000; + } else FlameBuffetTimer -= diff; + } + + DoMeleeAttackIfReady(); + } + else if (Phase == 1) //Flying Phase + { + if (InitialSpawn) + SummonAdds(); + + InitialSpawn = false; + + if (FireballTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true)) + { + m_creature->SetInFront(pTarget); + DoCast(pTarget, SPELL_FIREBALL); + } + + FireballTimer = 18000; + } else FireballTimer -= diff; + + if (DevouringFlameTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true)) + { + m_creature->SetInFront(pTarget); + DoCast(pTarget, SPELL_DEVOURINGFLAME); + } + + DevouringFlameTimer = 10000; + } else DevouringFlameTimer -= diff; + + if (SummonAddsTimer <= diff) + SummonAdds(); + else SummonAddsTimer -= diff; + } + } + + void SummonAdds() + { + // TODO: 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(1,4); + for (uint8 i = 0; i < random; ++i) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true)) + { + float x = std::max(500.0f, std::min(650.0f, pTarget->GetPositionX() + irand(-20,20))); // Safe range is between 500 and 650 + float y = std::max(-235.0f, std::min(-145.0f, pTarget->GetPositionY() + irand(-20,20))); // Safe range is between -235 and -145 + float z = m_creature->GetBaseMap()->GetHeight(x, y, MAX_HEIGHT); // Ground level + // TODO: Spawn drillers, then spawn adds 5 seconds later + if (Creature *pAdd = m_creature->SummonCreature(NPC_DARK_RUNE_SENTINEL, x, y, z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000)) + pAdd->AI()->AttackStart(pTarget); + } + } + SummonAddsTimer = 45000; + } + + void FlyPhase(uint8 Phase, const uint32 diff) + { + const float x = 587.54; + const float y = -174.92; + const float GroundLevel = m_creature->GetBaseMap()->GetHeight(x, y, MAX_HEIGHT); + const float FlightHeight = GroundLevel + 4.0f; // TODO: Fly out of range of attacks (442 is sufficient height for this), minus ~(10*number of harpoon gun chains attached to Razorscale) + + if (Phase == 1) // Always flying during Phase 1 + IsFlying = true; + + m_creature->SetFlying(IsFlying); + m_creature->SendMovementFlagUpdate(); + m_creature->SetSpeed(MOVE_WALK, IsFlying ? 7.0f : 2.5f, IsFlying); + + if (Phase == 1) // Flying Phase + { + if (m_creature->GetPositionZ() > FlightHeight) // Correct height, stop moving + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + else // Incorrect height + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + m_creature->GetMotionMaster()->MovePoint(0, x, y, FlightHeight + 0.5f); // Fly to slightly above (x, y, FlightHeight) + } + } + else // Ground Phases + { + const float CurrentGroundLevel = m_creature->GetBaseMap()->GetHeight(m_creature->GetPositionX(), m_creature->GetPositionY(), MAX_HEIGHT); + //if (StunTimer == 30000) // Only fly around if not stunned. + //{ + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + if (IsFlying && m_creature->GetPositionZ() > CurrentGroundLevel) // Fly towards the ground + m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), CurrentGroundLevel); + // TODO: Swoop up just before landing + else + IsFlying = false; // Landed, no longer flying + //} + + //if (!IsFlying &&Phase == 2 && CastSpellsTimer == 0 && StunTimer >= diff) // No longer flying, non-permanent ground phase, and not casting spells + //{ + // TODO: Add stun here. 30 second stun after Razorscale is grounded by harpoon guns + //StunTimer -= diff; + //} + //else if (StunTimer != 30000 && (StunTimer < 0 || Phase == 3)) // Stun is active, and needs to end. Note: Stun breaks instantly if Phase 3 starts + //{ + // TODO: Remove stun here. + //DoCast(SPELL_WINGBUFFET); // "Used in the beginning of the phase." + //WingBuffetTimer = urand(7000,14000); + //StunTimer = 30000; // Reinitialize the stun timer + //if (Phase == 2) // Non-permanent ground phase + // CastSpellsTimer = 5000; // Five seconds of casting before returning to Phase 1 + //} + } + } +}; + +CreatureAI* GetAI_boss_razorscale(Creature* pCreature) +{ + return new boss_razorscaleAI (pCreature); +} + +void AddSC_boss_razorscale() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_razorscale"; + newscript->GetAI = &GetAI_boss_razorscale; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_thorim.cpp b/src/scripts/northrend/ulduar/ulduar/boss_thorim.cpp new file mode 100644 index 00000000000..2eececb76a8 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_thorim.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +/* +#define SAY_AGGRO -1 +#define SAY_SLAY -1 +*/ + +struct TRINITY_DLL_DECL boss_thorimAI : public BossAI +{ + boss_thorimAI(Creature* pCreature) : BossAI(pCreature, TYPE_THORIM) + { + m_pInstance = pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + } + + void KilledUnit(Unit *victim) + { + } + + void JustDied(Unit *victim) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_THORIM, DONE); + } + + void Aggro(Unit* pWho) + { +// DoScriptText(SAY_AGGRO, m_creature); + m_creature->SetInCombatWithZone(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; +//SPELLS TODO: + +// + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(diff); + + } + +}; + +CreatureAI* GetAI_boss_thorim(Creature* pCreature) +{ + return new boss_thorimAI(pCreature); +} + +void AddSC_boss_thorim() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_thorim"; + newscript->GetAI = &GetAI_boss_thorim; + newscript->RegisterSelf(); + +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_xt002.cpp b/src/scripts/northrend/ulduar/ulduar/boss_xt002.cpp new file mode 100644 index 00000000000..66be50292cb --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_xt002.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +#define SPELL_SEARING_LIGHT 63018 +#define SPELL_SONIC_BOOM 38897 + +#define SAY_AGGRO -1000000 +#define SAY_SLAY -1000001 + +struct TRINITY_DLL_DECL boss_xt002_AI : public BossAI +{ + boss_xt002_AI(Creature *pCreature) : BossAI(pCreature, TYPE_XT002) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + uint32 SEARING_LIGHT_Timer; + uint32 SONIC_BOOM_Timer; + + void Reset() + { + SEARING_LIGHT_Timer = 100; + SONIC_BOOM_Timer = 20; + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO,m_creature); + } + void KilledUnit(Unit* victim) + { + DoScriptText(SAY_SLAY, m_creature); + } + + void JustDied(Unit *victim) + { + DoScriptText(SAY_SLAY, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_XT002, DONE); + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if(m_creature->GetPositionX() < 700) // Not Blizzlike, anti-exploit to prevent players from pulling bosses to vehicles. + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(false); + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + + if (SEARING_LIGHT_Timer <= diff) + { + DoCast(m_creature, SPELL_SEARING_LIGHT); + DoScriptText(SAY_SLAY, m_creature); + SEARING_LIGHT_Timer = 50000; + } else SEARING_LIGHT_Timer -= diff; + + if (SONIC_BOOM_Timer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_SONIC_BOOM); + SONIC_BOOM_Timer = 20000; + } else SONIC_BOOM_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_xt002(Creature* pCreature) +{ + return new boss_xt002_AI (pCreature); +} +void AddSC_boss_xt002() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_xt002"; + newscript->GetAI = &GetAI_boss_xt002; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/boss_yoggsaron.cpp b/src/scripts/northrend/ulduar/ulduar/boss_yoggsaron.cpp new file mode 100644 index 00000000000..a9f1be65f2d --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/boss_yoggsaron.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" diff --git a/src/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp b/src/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp new file mode 100644 index 00000000000..2c961073d89 --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ulduar.h" + +enum eGameObjects +{ + GO_Kologarn_CHEST_HERO = 195047, + GO_Kologarn_CHEST = 195046, + GO_Thorim_CHEST_HERO = 194315, + GO_Thorim_CHEST = 194314, + GO_Hodir_CHEST_HERO = 194308, + GO_Hodir_CHEST = 194307, + GO_Freya_CHEST_HERO = 194325, + GO_Freya_CHEST = 194324, +}; + +struct TRINITY_DLL_DECL instance_ulduar : public ScriptedInstance +{ + instance_ulduar(Map* pMap) : ScriptedInstance(pMap), KologarnChest(NULL), ThorimChest(NULL), HodirChest(NULL), FreyaChest(NULL) { Initialize(); }; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint64 m_uiLeviathanGUID; + uint64 m_uiIgnisGUID; + uint64 m_uiRazorscaleGUID; + uint64 m_uiXT002GUID; + uint64 m_auiAssemblyGUIDs[3]; + uint64 m_uiKologarnGUID; + uint64 m_uiAuriayaGUID; + uint64 m_uiMimironGUID; + uint64 m_uiHodirGUID; + uint64 m_uiThorimGUID; + uint64 m_uiFreyaGUID; + uint64 m_uiVezaxGUID; + uint64 m_uiYoggSaronGUID; + uint64 m_uiAlgalonGUID; + + GameObject* KologarnChest, *ThorimChest, *HodirChest, *FreyaChest; + + void Initialize() + { + m_uiLeviathanGUID = 0; + m_uiIgnisGUID = 0; + m_uiRazorscaleGUID = 0; + m_uiXT002GUID = 0; + m_uiKologarnGUID = 0; + m_uiAuriayaGUID = 0; + m_uiMimironGUID = 0; + m_uiHodirGUID = 0; + m_uiThorimGUID = 0; + m_uiFreyaGUID = 0; + m_uiVezaxGUID = 0; + m_uiYoggSaronGUID = 0; + m_uiAlgalonGUID = 0; + KologarnChest = 0; + ThorimChest = 0; + HodirChest = 0; + FreyaChest = 0; + + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + memset(&m_auiAssemblyGUIDs, 0, sizeof(m_auiAssemblyGUIDs)); + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } + + return false; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case NPC_LEVIATHAN: + m_uiLeviathanGUID = pCreature->GetGUID(); + break; + case NPC_IGNIS: + m_uiIgnisGUID = pCreature->GetGUID(); + break; + case NPC_RAZORSCALE: + m_uiRazorscaleGUID = pCreature->GetGUID(); + break; + case NPC_XT002: + m_uiXT002GUID = pCreature->GetGUID(); + break; + + // Assembly of Iron + case NPC_STEELBREAKER: + m_auiAssemblyGUIDs[0] = pCreature->GetGUID(); + break; + case NPC_MOLGEIM: + m_auiAssemblyGUIDs[1] = pCreature->GetGUID(); + break; + case NPC_BRUNDIR: + m_auiAssemblyGUIDs[2] = pCreature->GetGUID(); + break; + + case NPC_KOLOGARN: + m_uiKologarnGUID = pCreature->GetGUID(); + break; + case NPC_AURIAYA: + m_uiAuriayaGUID = pCreature->GetGUID(); + break; + case NPC_MIMIRON: + m_uiMimironGUID = pCreature->GetGUID(); + break; + case NPC_HODIR: + m_uiHodirGUID = pCreature->GetGUID(); + break; + case NPC_THORIM: + m_uiThorimGUID = pCreature->GetGUID(); + break; + case NPC_FREYA: + m_uiFreyaGUID = pCreature->GetGUID(); + break; + case NPC_VEZAX: + m_uiVezaxGUID = pCreature->GetGUID(); + break; + case NPC_YOGGSARON: + m_uiYoggSaronGUID = pCreature->GetGUID(); + break; + case NPC_ALGALON: + m_uiAlgalonGUID = pCreature->GetGUID(); + break; + } + + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case GO_Kologarn_CHEST_HERO: KologarnChest = add ? pGo : NULL; break; + case GO_Kologarn_CHEST: KologarnChest = add ? pGo : NULL; break; + case GO_Thorim_CHEST_HERO: ThorimChest = add ? pGo : NULL; break; + case GO_Thorim_CHEST: ThorimChest = add ? pGo : NULL; break; + case GO_Hodir_CHEST_HERO: HodirChest = add ? pGo : NULL; break; + case GO_Hodir_CHEST: HodirChest = add ? pGo : NULL; break; + case GO_Freya_CHEST_HERO: FreyaChest = add ? pGo : NULL; break; + case GO_Freya_CHEST: FreyaChest = add ? pGo : NULL; break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case TYPE_LEVIATHAN: + case TYPE_IGNIS: + case TYPE_RAZORSCALE: + case TYPE_XT002: + case TYPE_ASSEMBLY: + case TYPE_KOLOGARN: + m_auiEncounter[TYPE_KOLOGARN] = data; + if (data == DONE && KologarnChest) + KologarnChest->SetRespawnTime(KologarnChest->GetRespawnDelay()); + case TYPE_AURIAYA: + case TYPE_MIMIRON: + case TYPE_HODIR: + m_auiEncounter[TYPE_HODIR] = data; + if (data == DONE && HodirChest) + HodirChest->SetRespawnTime(HodirChest->GetRespawnDelay()); + case TYPE_THORIM: + m_auiEncounter[TYPE_THORIM] = data; + if (data == DONE && ThorimChest) + ThorimChest->SetRespawnTime(ThorimChest->GetRespawnDelay()); + case TYPE_FREYA: + m_auiEncounter[TYPE_FREYA] = data; + if (data == DONE && FreyaChest) + FreyaChest->SetRespawnTime(FreyaChest->GetRespawnDelay()); + case TYPE_VEZAX: + case TYPE_YOGGSARON: + case TYPE_ALGALON: + m_auiEncounter[type] = data; + break; + } + + if (data == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + saveStream << m_auiEncounter[i] << " "; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + uint64 GetData64(uint32 data) + { + switch(data) + { + case TYPE_LEVIATHAN: + return m_uiLeviathanGUID; + case TYPE_IGNIS: + return m_uiIgnisGUID; + case TYPE_RAZORSCALE: + return m_uiRazorscaleGUID; + case TYPE_XT002: + return m_uiXT002GUID; + case TYPE_KOLOGARN: + return m_uiKologarnGUID; + case TYPE_AURIAYA: + return m_uiAuriayaGUID; + case TYPE_MIMIRON: + return m_uiMimironGUID; + case TYPE_HODIR: + return m_uiMimironGUID; + case TYPE_THORIM: + return m_uiThorimGUID; + case TYPE_FREYA: + return m_uiFreyaGUID; + case TYPE_VEZAX: + return m_uiVezaxGUID; + case TYPE_YOGGSARON: + return m_uiYoggSaronGUID; + case TYPE_ALGALON: + return m_uiAlgalonGUID; + + // Assembly of Iron + case DATA_STEELBREAKER: + return m_auiAssemblyGUIDs[0]; + case DATA_MOLGEIM: + return m_auiAssemblyGUIDs[1]; + case DATA_BRUNDIR: + return m_auiAssemblyGUIDs[2]; + } + + return 0; + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case TYPE_LEVIATHAN: + case TYPE_IGNIS: + case TYPE_RAZORSCALE: + case TYPE_XT002: + case TYPE_ASSEMBLY: + case TYPE_KOLOGARN: + case TYPE_AURIAYA: + case TYPE_MIMIRON: + case TYPE_HODIR: + case TYPE_THORIM: + case TYPE_FREYA: + case TYPE_VEZAX: + case TYPE_YOGGSARON: + case TYPE_ALGALON: + return m_auiEncounter[type]; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "U U " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] + << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6] << " " << m_auiEncounter[7] + << m_auiEncounter[8] << " " << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11] + << m_auiEncounter[12] << " " << m_auiEncounter[13]; + + m_strInstData = saveStream.str(); + + OUT_SAVE_INST_DATA_COMPLETE; + return m_strInstData; + } + + void Load(const char* strIn) + { + if (!strIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(strIn); + + char dataHead1, dataHead2; + uint32 data0, data1, data2, data3, data4, data5, data6, + data7, data8, data9, data10, data11, data12, data13; + + std::istringstream loadStream(strIn); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4 >> data5 >> data6 + >> data7 >> data8 >> data9 >> data10 >> data11 >> data12 >> data13; + + if (dataHead1 == 'U' && dataHead2 == 'U') + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + loadStream >> m_auiEncounter[i]; + + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + } + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_ulduar(Map* pMap) +{ + return new instance_ulduar(pMap); +} + +void AddSC_instance_ulduar() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_ulduar"; + newscript->GetInstanceData = &GetInstanceData_instance_ulduar; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/ulduar/ulduar/ulduar.h b/src/scripts/northrend/ulduar/ulduar/ulduar.h new file mode 100644 index 00000000000..ed7686343fb --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/ulduar.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DEF_ULDUAR_H +#define DEF_ULDUAR_H + +enum eTypes +{ + MAX_ENCOUNTER = 14, + + TYPE_LEVIATHAN = 0, + TYPE_IGNIS = 1, + TYPE_RAZORSCALE = 2, + TYPE_XT002 = 3, + TYPE_ASSEMBLY = 4, + TYPE_KOLOGARN = 5, + TYPE_AURIAYA = 6, + TYPE_MIMIRON = 7, + TYPE_HODIR = 8, + TYPE_THORIM = 9, + TYPE_FREYA = 10, + TYPE_VEZAX = 11, + TYPE_YOGGSARON = 12, + TYPE_ALGALON = 13, + + DATA_STEELBREAKER = 20, + DATA_MOLGEIM = 21, + DATA_BRUNDIR = 22, + DATA_RUNEMASTER_MOLGEIM = 23, + DATA_STORMCALLER_BRUNDIR = 24, + + NPC_LEVIATHAN = 33113, + NPC_IGNIS = 33118, + NPC_RAZORSCALE = 33186, + NPC_XT002 = 33293, + NPC_STEELBREAKER = 32867, + NPC_MOLGEIM = 32927, + NPC_BRUNDIR = 32857, + NPC_KOLOGARN = 32930, + NPC_AURIAYA = 33515, + NPC_MIMIRON = 33350, + NPC_HODIR = 32845, + NPC_THORIM = 32865, + NPC_FREYA = 32906, + NPC_VEZAX = 33271, + NPC_YOGGSARON = 33288, + NPC_ALGALON = 32871 +}; + +#endif diff --git a/src/scripts/northrend/ulduar/ulduar/ulduar_teleporter.cpp b/src/scripts/northrend/ulduar/ulduar/ulduar_teleporter.cpp new file mode 100644 index 00000000000..8489bf4272b --- /dev/null +++ b/src/scripts/northrend/ulduar/ulduar/ulduar_teleporter.cpp @@ -0,0 +1,92 @@ +#include "ScriptedPch.h" +#include "ulduar.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 +*/ + +#define BASE_CAMP 200 +#define GROUNDS 201 +#define FORGE 202 +#define SCRAPYARD 203 +#define ANTECHAMBER 204 +#define WALKWAY 205 +#define CONSERVATORY 206 + +bool GoHello_ulduar_teleporter( Player *pPlayer, GameObject *pGO ) +{ + ScriptedInstance *pInstance = (ScriptedInstance *) pGO->GetInstanceData(); + if(!pInstance) return true; + + pPlayer->ADD_GOSSIP_ITEM(0, "Teleport to the Expedition Base Camp", GOSSIP_SENDER_MAIN, BASE_CAMP); + pPlayer->ADD_GOSSIP_ITEM(0, "Teleport to the Formation Grounds", GOSSIP_SENDER_MAIN, GROUNDS); + if(pInstance->GetData(TYPE_LEVIATHAN) == DONE) + { + pPlayer->ADD_GOSSIP_ITEM(0, "Teleport to the Colossal Forge", GOSSIP_SENDER_MAIN, FORGE); + if(pInstance->GetData(TYPE_XT002) == DONE) + { + pPlayer->ADD_GOSSIP_ITEM(0, "Teleport to the Scrapyard", GOSSIP_SENDER_MAIN, SCRAPYARD); + pPlayer->ADD_GOSSIP_ITEM(0, "Teleport to the Antechamber of Ulduar", GOSSIP_SENDER_MAIN, ANTECHAMBER); + if(pInstance->GetData(TYPE_KOLOGARN) == DONE) + { + pPlayer->ADD_GOSSIP_ITEM(0, "Teleport to the Shattered Walkway", GOSSIP_SENDER_MAIN, WALKWAY); + if(pInstance->GetData(TYPE_AURIAYA) == DONE) + pPlayer->ADD_GOSSIP_ITEM(0, "Teleport to the Conservatory of Life", GOSSIP_SENDER_MAIN, CONSERVATORY); + } + } + } + pPlayer->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pGO->GetGUID()); + + return true; +} + +bool GOSelect_ulduar_teleporter( Player *pPlayer, GameObject *pGO, uint32 sender, uint32 action ) +{ + if(sender != GOSSIP_SENDER_MAIN) return true; + if(!pPlayer->getAttackers().empty()) return true; + + switch(action) + { + case BASE_CAMP: + pPlayer->TeleportTo(603, -706.122, -92.6024, 429.876, 0); + pPlayer->CLOSE_GOSSIP_MENU(); break; + case GROUNDS: + pPlayer->TeleportTo(603, 131.248, -35.3802, 409.804, 0); + pPlayer->CLOSE_GOSSIP_MENU(); break; + case FORGE: + pPlayer->TeleportTo(603, 553.233, -12.3247, 409.679, 0); + pPlayer->CLOSE_GOSSIP_MENU(); break; + case SCRAPYARD: + pPlayer->TeleportTo(603, 926.292, -11.4635, 418.595, 0); + pPlayer->CLOSE_GOSSIP_MENU(); break; + case ANTECHAMBER: + pPlayer->TeleportTo(603, 1498.09, -24.246, 420.967, 0); + pPlayer->CLOSE_GOSSIP_MENU(); break; + case WALKWAY: + pPlayer->TeleportTo(603, 1859.45, -24.1, 448.9, 0); + pPlayer->CLOSE_GOSSIP_MENU(); break; + case CONSERVATORY: + pPlayer->TeleportTo(603, 2086.27, -24.3134, 421.239, 0); + pPlayer->CLOSE_GOSSIP_MENU(); break; + } + + return true; +} + +void AddSC_ulduar_teleporter() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "ulduar_teleporter"; + newscript->pGOHello = &GoHello_ulduar_teleporter; + newscript->pGOSelect = &GOSelect_ulduar_teleporter; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp b/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp new file mode 100644 index 00000000000..f9f503177b2 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Ingvar_The_Plunderer +SD%Complete: 95 +SDComment: Some Problems with Annhylde Movement, Blizzlike Timers +SDCategory: Udgarde Keep +EndScriptData */ + +#include "ScriptedPch.h" +#include "utgarde_keep.h" + +enum eEnums +{ + //Yells Ingvar + YELL_AGGRO_1 = -1574005, + YELL_AGGRO_2 = -1574006, + + YELL_DEAD_1 = -1574007, + YELL_DEAD_2 = -1574008, + + YELL_KILL_1 = -1574009, + YELL_KILL_2 = -1574010, + +//Ingvar Spells human form + MOB_INGVAR_HUMAN = 23954, + SPELL_CLEAVE = 42724, + SPELL_SMASH = 42669, + H_SPELL_SMASH = 59706, + SPELL_STAGGERING_ROAR = 42708, + H_SPELL_STAGGERING_ROAR = 59708, + SPELL_ENRAGE = 42705, + H_SPELL_ENRAGE = 59707, + + MOB_ANNHYLDE_THE_CALLER = 24068, + SPELL_INGVAR_FEIGN_DEATH = 42795, + SPELL_SUMMON_BANSHEE = 42912, + SPELL_SCOURG_RESURRECTION_EFFEKTSPAWN = 42863, //Spawn resurrecteffekt around Ingvar + + MODEL_INGVAR_UNDEAD = 26351, + MODEL_INGVAR_HUMAN = 21953, + +//Ingvar Spells undead form + MOB_INGVAR_UNDEAD = 23980, + SPELL_DARK_SMASH = 42723, + SPELL_DREADFUL_ROAR = 42729, + H_SPELL_DREADFUL_ROAR = 59734, + SPELL_WOE_STRIKE = 42730, + H_SPELL_WOE_STRIKE = 59735, + + ENTRY_THROW_TARGET = 23996, + SPELL_SHADOW_AXE_SUMMON = 42749 +}; + +struct TRINITY_DLL_DECL boss_ingvar_the_plundererAI : public ScriptedAI +{ + boss_ingvar_the_plundererAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + bool undead; + bool event_inProgress; + + uint32 Cleave_Timer; + uint32 Smash_Timer; + uint32 Enrage_Timer; + uint32 Roar_Timer; + uint32 SpawnResTimer; + uint32 wait_Timer; + + void Reset() + { + if (undead) // Visual Hack + m_creature->SetDisplayId(MODEL_INGVAR_HUMAN); + + undead = false; + event_inProgress = false; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + Cleave_Timer = 2000; + Smash_Timer = 5000; + Enrage_Timer = 10000; + Roar_Timer = 15000; + + SpawnResTimer = 3000; + + wait_Timer = 0; + + if (pInstance) + pInstance->SetData(DATA_INGVAR_EVENT, NOT_STARTED); + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if (damage >= m_creature->GetHealth() && !undead) + { + //DoCast(m_creature, SPELL_INGVAR_FEIGN_DEATH, true); // Dont work ??? + // visuel hack + m_creature->SetHealth(0); + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveAllAuras(); + m_creature->SetDisplayId(MODEL_INGVAR_UNDEAD); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + // visuel hack end + + event_inProgress = true; + undead = true; + + DoScriptText(YELL_DEAD_1,m_creature); + } + + if (event_inProgress) + { + damage = 0; + } + } + + void StartZombiePhase() + { + undead = true; + event_inProgress = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_creature->AI()->AttackStart(m_creature->getVictim()); + + DoScriptText(YELL_AGGRO_2,m_creature); + } + + void EnterCombat(Unit *who) + { + DoScriptText(YELL_AGGRO_1,m_creature); + + if (pInstance) + pInstance->SetData(DATA_INGVAR_EVENT, IN_PROGRESS); + } + + void JustDied(Unit* killer) + { + DoScriptText(YELL_DEAD_2,m_creature); + + if (pInstance) + pInstance->SetData(DATA_INGVAR_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + if (undead) { DoScriptText(YELL_KILL_1,m_creature); } + else { DoScriptText(YELL_KILL_2,m_creature); } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (event_inProgress) + { + if (SpawnResTimer) + if (SpawnResTimer <= diff) + { + DoCast(m_creature, SPELL_SUMMON_BANSHEE); // Summons direktly on caster position + //DoCast(m_creature, SPELL_SCOURG_RESURRECTION_EFFEKTSPAWN); // Dont needet ? + SpawnResTimer = 0; + } else SpawnResTimer -= diff; + + return; + } + + // This is used for a spell queue ... the spells should not castet if one spell is already casting + if (wait_Timer) + if (wait_Timer <= diff) + { + wait_Timer = 0; + } else wait_Timer -= diff; + + if (Cleave_Timer <= diff) + { + if (!wait_Timer) + { + if (undead) + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_WOE_STRIKE, H_SPELL_WOE_STRIKE)); + else + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + Cleave_Timer = rand()%5000 + 2000; + + wait_Timer = 1000; + } + } else Cleave_Timer -= diff; + + if (Smash_Timer <= diff) + { + if (!wait_Timer) + { + if (undead) + DoCast(m_creature->getVictim(), SPELL_DARK_SMASH); + else + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_SMASH, H_SPELL_SMASH)); + Smash_Timer = 10000; + + wait_Timer = 5000; + } + } else Smash_Timer -= diff; + + if (!undead) + { + if (Enrage_Timer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_ENRAGE, H_SPELL_ENRAGE)); + Enrage_Timer = 10000; + } else Enrage_Timer -= diff; + } else // In Undead form used to summon weapon + { + if (Enrage_Timer <= diff) + { + if (!wait_Timer) + { + // Spawn target for Axe + Unit *pTarget = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); + if (pTarget) + { + Creature* temp = m_creature->SummonCreature(ENTRY_THROW_TARGET,pTarget->GetPositionX(),pTarget->GetPositionY(),pTarget->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN,2000); + + DoCast(m_creature, SPELL_SHADOW_AXE_SUMMON); + } + Enrage_Timer = 30000; + } + } else Enrage_Timer -= diff; + } + + if (Roar_Timer <= diff) + { + if (!wait_Timer) + { + if (undead) + DoCast(m_creature, DUNGEON_MODE(SPELL_DREADFUL_ROAR, H_SPELL_DREADFUL_ROAR)); + else + DoCast(m_creature, DUNGEON_MODE(SPELL_STAGGERING_ROAR, H_SPELL_STAGGERING_ROAR)); + Roar_Timer = 10000; + + wait_Timer = 5000; + } + } else Roar_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ingvar_the_plunderer(Creature* pCreature) +{ + return new boss_ingvar_the_plundererAI (pCreature); +} + +enum eSpells +{ +//we don't have that text in db so comment it until we get this text +// YELL_RESSURECT = -1574025, + +//Spells for Annhylde + SPELL_SCOURG_RESURRECTION_HEAL = 42704, //Heal Max + DummyAura + SPELL_SCOURG_RESURRECTION_BEAM = 42857, //Channeling Beam of Annhylde + SPELL_SCOURG_RESURRECTION_DUMMY = 42862, //Some Emote Dummy? + SPELL_INGVAR_TRANSFORM = 42796 +}; + +struct TRINITY_DLL_DECL mob_annhylde_the_callerAI : public ScriptedAI +{ + mob_annhylde_the_callerAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + float x,y,z; + ScriptedInstance* pInstance; + uint32 Resurect_Timer; + uint32 Resurect_Phase; + + void Reset() + { + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_HOVER); + m_creature->SetSpeed(MOVE_SWIM , 1.0f); + m_creature->SetSpeed(MOVE_RUN , 1.0f); + m_creature->SetSpeed(MOVE_WALK , 1.0f); + //m_creature->SetSpeed(MOVE_FLIGHT , 1.0f); + + m_creature->GetPosition(x,y,z); + DoTeleportTo(x+1,y,z+30); + + Unit* ingvar = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_INGVAR) : 0); + if (ingvar) + { + m_creature->GetMotionMaster()->MovePoint(1,x,y,z+15); + +// DoScriptText(YELL_RESSURECT,m_creature); + } + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + Unit* ingvar = Unit::GetUnit((*m_creature), pInstance ? pInstance->GetData64(DATA_INGVAR) : 0); + if (ingvar) + { + switch (id) + { + case 1: + ingvar->RemoveAura(SPELL_SUMMON_BANSHEE); + ingvar->CastSpell(ingvar,SPELL_SCOURG_RESURRECTION_DUMMY,true); + DoCast(ingvar, SPELL_SCOURG_RESURRECTION_BEAM); + Resurect_Timer = 8000; + Resurect_Phase = 1; + break; + case 2: + m_creature->DealDamage(m_creature,m_creature->GetHealth()); + m_creature->RemoveCorpse(); + break; + } + } + } + + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void EnterCombat(Unit *who) {} + void UpdateAI(const uint32 diff) + { + if (Resurect_Timer) + if (Resurect_Timer <= diff) + { + if (Resurect_Phase == 1) + { + Unit* ingvar = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_INGVAR) : 0); + if (ingvar) + { + ingvar->SetStandState(UNIT_STAND_STATE_STAND); + ingvar->CastSpell(ingvar,SPELL_SCOURG_RESURRECTION_HEAL,false); + } + Resurect_Timer = 3000; + Resurect_Phase = 2; + } else if (Resurect_Phase == 2) + { + Creature* ingvar = Unit::GetCreature(*m_creature, pInstance ? pInstance->GetData64(DATA_INGVAR) : 0); + if (ingvar) + { + ingvar->RemoveAurasDueToSpell(SPELL_SCOURG_RESURRECTION_DUMMY); + //ingvar->CastSpell(ingvar,SPELL_INGVAR_TRANSFORM,false); + //ingvar->SetDisplayId(MODEL_INGVAR_UNDEAD); // Visual Hack - when he dies he becomes human model -> wrong + Creature* c_ingvar = ingvar; + + CAST_AI(boss_ingvar_the_plundererAI, (c_ingvar->AI()))->StartZombiePhase(); + + m_creature->GetMotionMaster()->MovePoint(2,x+1,y,z+30); + ++Resurect_Phase; + } + } + + } else Resurect_Timer -= diff; + } +}; + +CreatureAI* GetAI_mob_annhylde_the_caller(Creature* pCreature) +{ + return new mob_annhylde_the_callerAI (pCreature); +} + +enum eShadowAxe +{ + SPELL_SHADOW_AXE_DAMAGE = 42750, + H_SPELL_SHADOW_AXE_DAMAGE = 59719 +}; + +struct TRINITY_DLL_DECL mob_ingvar_throw_dummyAI : public ScriptedAI +{ + mob_ingvar_throw_dummyAI(Creature *c) : ScriptedAI(c) + { + } + + uint32 Despawn_Timer; + + void Reset() + { + Unit *pTarget = m_creature->FindNearestCreature(ENTRY_THROW_TARGET,50); + if (pTarget) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_SHADOW_AXE_DAMAGE, H_SPELL_SHADOW_AXE_DAMAGE)); + float x,y,z; + pTarget->GetPosition(x,y,z); + m_creature->GetMotionMaster()->MovePoint(0,x,y,z); + } + Despawn_Timer = 7000; + } + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void EnterCombat(Unit *who) {} + void UpdateAI(const uint32 diff) + { + if (Despawn_Timer <= diff) + { + m_creature->DealDamage(m_creature,m_creature->GetHealth()); + m_creature->RemoveCorpse(); + Despawn_Timer = 0; + } else Despawn_Timer -= diff; + } +}; + +CreatureAI* GetAI_mob_ingvar_throw_dummy(Creature* pCreature) +{ + return new mob_ingvar_throw_dummyAI (pCreature); +} + +void AddSC_boss_ingvar_the_plunderer() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_ingvar_the_plunderer"; + newscript->GetAI = &GetAI_boss_ingvar_the_plunderer; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_annhylde_the_caller"; + newscript->GetAI = &GetAI_mob_annhylde_the_caller; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ingvar_throw_dummy"; + newscript->GetAI = &GetAI_mob_ingvar_throw_dummy; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp b/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp new file mode 100644 index 00000000000..4af56fdbad8 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Prince_Keleseth +SD%Complete: 90 +SDComment: Needs Prince Movements, Needs adjustments to blizzlike timers, Needs Shadowbolt castbar, Needs right Ressurect Visual, Needs Some Heroic Spells +SDCategory: Utgarde Keep +EndScriptData */ + +#include "ScriptedPch.h" +#include "utgarde_keep.h" + +enum eEnums +{ + ACHIEVEMENT_ON_THE_ROCKS = 1919, + + SPELL_SHADOWBOLT = 43667, + SPELL_SHADOWBOLT_HEROIC = 59389, + SPELL_FROST_TOMB = 48400, + SPELL_FROST_TOMB_SUMMON = 42714, + SPELL_DECREPIFY = 42702, + SPELL_SCOURGE_RESSURRECTION = 42704, + CREATURE_FROSTTOMB = 23965, + CREATURE_SKELETON = 23970, + + SAY_AGGRO = -1574000, + SAY_FROST_TOMB = -1574001, + SAY_SKELETONS = -1574002, + SAY_KILL = -1574003, + SAY_DEATH = -1574004 +}; + +#define SKELETONSPAWN_Z 42.8668 + +float SkeletonSpawnPoint[5][5]= +{ + {156.2559, 259.2093}, + {156.2559, 259.2093}, + {156.2559, 259.2093}, + {156.2559, 259.2093}, + {156.2559, 259.2093}, +}; + +float AttackLoc[3]={197.636, 194.046, 40.8164}; + +bool ShatterFrostTomb; // needed for achievement: On The Rocks(1919) + +struct TRINITY_DLL_DECL mob_frost_tombAI : public ScriptedAI +{ + mob_frost_tombAI(Creature *c) : ScriptedAI(c) + { + FrostTombGUID = 0; + } + + uint64 FrostTombGUID; + + void SetPrisoner(Unit* uPrisoner) + { + FrostTombGUID = uPrisoner->GetGUID(); + } + + void Reset(){ FrostTombGUID = 0; } + void EnterCombat(Unit* who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + + void JustDied(Unit *killer) + { + if (killer->GetGUID() != m_creature->GetGUID()) + ShatterFrostTomb = true; + + if (FrostTombGUID) + { + Unit* FrostTomb = Unit::GetUnit((*m_creature),FrostTombGUID); + if (FrostTomb) + FrostTomb->RemoveAurasDueToSpell(SPELL_FROST_TOMB); + } + } + + void UpdateAI(const uint32 diff) + { + Unit* temp = Unit::GetUnit((*m_creature),FrostTombGUID); + if ((temp && temp->isAlive() && !temp->HasAura(SPELL_FROST_TOMB)) || !temp) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } +}; + +struct TRINITY_DLL_DECL boss_kelesethAI : public ScriptedAI +{ + boss_kelesethAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 FrostTombTimer; + uint32 SummonSkeletonsTimer; + uint32 RespawnSkeletonsTimer; + uint32 ShadowboltTimer; + uint64 SkeletonGUID[5]; + bool Skeletons; + bool RespawnSkeletons; + + void Reset() + { + ShadowboltTimer = 0; + Skeletons = false; + + ShatterFrostTomb = false; + + ResetTimer(); + + if (pInstance) + pInstance->SetData(DATA_PRINCEKELESETH_EVENT, NOT_STARTED); + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + + DoScriptText(SAY_KILL, m_creature); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (IsHeroic() && !ShatterFrostTomb) + { + AchievementEntry const *AchievOnTheRocks = GetAchievementStore()->LookupEntry(ACHIEVEMENT_ON_THE_ROCKS); + if (AchievOnTheRocks) + { + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievOnTheRocks); + } + } + } + + if (pInstance) + pInstance->SetData(DATA_PRINCEKELESETH_EVENT, DONE); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + DoZoneInCombat(); + + if (pInstance) + pInstance->SetData(DATA_PRINCEKELESETH_EVENT, IN_PROGRESS); + } + + void ResetTimer(uint32 inc = 0) + { + SummonSkeletonsTimer = 5000 + inc; + FrostTombTimer = 28000 + inc; + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (ShadowboltTimer <= diff) + { + Unit *pTarget = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); + if (pTarget && pTarget->isAlive() && pTarget->GetTypeId() == TYPEID_PLAYER) + m_creature->CastSpell(pTarget, DUNGEON_MODE(SPELL_SHADOWBOLT, SPELL_SHADOWBOLT_HEROIC), true); + ShadowboltTimer = 10000; + } else ShadowboltTimer -= diff; + + if (!Skeletons) + if ((SummonSkeletonsTimer <= diff)) + { + Creature* Skeleton; + DoScriptText(SAY_SKELETONS, m_creature); + for (uint8 i = 0; i < 5; ++i) + { + if (Skeleton = m_creature->SummonCreature(CREATURE_SKELETON, SkeletonSpawnPoint[i][0], SkeletonSpawnPoint[i][1] , SKELETONSPAWN_Z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000)) + { + Skeleton->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + Skeleton->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY() , m_creature->GetPositionZ()); + Skeleton->AddThreat(m_creature->getVictim(), 0.0f); + DoZoneInCombat(Skeleton); + } + } + Skeletons = true; + } else SummonSkeletonsTimer -= diff; + + if (FrostTombTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + if (pTarget->isAlive()) + { + //DoCast(pTarget, SPELL_FROST_TOMB_SUMMON, true); + if (Creature *pChains = m_creature->SummonCreature(CREATURE_FROSTTOMB, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 20000)) + { + CAST_AI(mob_frost_tombAI, pChains->AI())->SetPrisoner(pTarget); + pChains->CastSpell(pTarget, SPELL_FROST_TOMB, true); + + DoScriptText(SAY_FROST_TOMB, m_creature); + } + } + FrostTombTimer = 15000; + } else FrostTombTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI +{ + mob_vrykul_skeletonAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance *pInstance; + uint32 Respawn_Time; + uint64 Target_Guid; + uint32 Decrepify_Timer; + + bool isDead; + + void Reset() + { + Respawn_Time = 12000; + Decrepify_Timer = urand(10000,20000); + isDead = false; + } + + void EnterCombat(Unit *who){} + void DamageTaken(Unit *done_by, uint32 &damage) + { + if (done_by->GetGUID() == m_creature->GetGUID()) + return; + + if (damage >= m_creature->GetHealth()) + { + PretendToDie(); + damage = 0; + } + } + + void PretendToDie() + { + isDead = true; + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveAllAuras(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + }; + + void Resurrect() + { + isDead = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(m_creature, SPELL_SCOURGE_RESSURRECTION, true); + + if (m_creature->getVictim()) + { + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_creature->AI()->AttackStart(m_creature->getVictim()); + } + else + m_creature->GetMotionMaster()->Initialize(); + }; + + void UpdateAI(const uint32 diff) + { + if (pInstance && pInstance->GetData(DATA_PRINCEKELESETH_EVENT) == IN_PROGRESS) + { + if (isDead) + { + if (Respawn_Time <= diff) + { + Resurrect(); + Respawn_Time = 12000; + } else Respawn_Time -= diff; + } + else + { + if (!UpdateVictim()) + return; + + if (Decrepify_Timer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_DECREPIFY); + Decrepify_Timer = 30000; + } else Decrepify_Timer -= diff; + + DoMeleeAttackIfReady(); + } + }else + { + if (m_creature->isAlive()) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + } +}; + +CreatureAI* GetAI_mob_frost_tomb(Creature* pCreature) +{ + return new mob_frost_tombAI(pCreature); +} + +CreatureAI* GetAI_boss_keleseth(Creature* pCreature) +{ + return new boss_kelesethAI (pCreature); +} + +CreatureAI* GetAI_mob_vrykul_skeleton(Creature* pCreature) +{ + return new mob_vrykul_skeletonAI (pCreature); +} + +void AddSC_boss_keleseth() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_keleseth"; + newscript->GetAI = &GetAI_boss_keleseth; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_frost_tomb"; + newscript->GetAI = &GetAI_mob_frost_tomb; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_vrykul_skeleton"; + newscript->GetAI = &GetAI_mob_vrykul_skeleton; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp b/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp new file mode 100644 index 00000000000..2b6c9c9a855 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Skarvald_Dalronn +SD%Complete: 95 +SDComment: Needs adjustments to blizzlike timers, Yell Text + Sound to DB +SDCategory: Utgarde Keep +EndScriptData */ + +#include "ScriptedPch.h" +#include "utgarde_keep.h" + +enum eEnums +{ + //signed for 24200, but used by 24200,27390 + YELL_SKARVALD_AGGRO = -1574011, + YELL_SKARVALD_DAL_DIED = -1574012, + YELL_SKARVALD_SKA_DIEDFIRST = -1574013, + YELL_SKARVALD_KILL = -1574014, + YELL_SKARVALD_DAL_DIEDFIRST = -1574015, + + //signed for 24201, but used by 24201,27389 + YELL_DALRONN_AGGRO = -1574016, + YELL_DALRONN_SKA_DIED = -1574017, + YELL_DALRONN_DAL_DIEDFIRST = -1574018, + YELL_DALRONN_KILL = -1574019, + YELL_DALRONN_SKA_DIEDFIRST = -1574020, + +//Spells of Skarvald and his Ghost + MOB_SKARVALD_THE_CONSTRUCTOR = 24200, + SPELL_CHARGE = 43651, + SPELL_STONE_STRIKE = 48583, + SPELL_SUMMON_SKARVALD_GHOST = 48613, + MOB_SKARVALD_GHOST = 27390, +//Spells of Dalronn and his Ghost + MOB_DALRONN_THE_CONTROLLER = 24201, + SPELL_SHADOW_BOLT = 43649, + H_SPELL_SHADOW_BOLT = 59575, + H_SPELL_SUMMON_SKELETONS = 52611, + SPELL_DEBILITATE = 43650, + SPELL_SUMMON_DALRONN_GHOST = 48612, + MOB_DALRONN_GHOST = 27389 +}; + +struct TRINITY_DLL_DECL boss_skarvald_the_constructorAI : public ScriptedAI +{ + boss_skarvald_the_constructorAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + bool ghost; + uint32 Charge_Timer; + uint32 StoneStrike_Timer; + uint32 Response_Timer; + uint32 Check_Timer; + bool Dalronn_isDead; + + void Reset() + { + Charge_Timer = 5000; + StoneStrike_Timer = 10000; + Dalronn_isDead = false; + Check_Timer = 5000; + + ghost = (m_creature->GetEntry() == MOB_SKARVALD_GHOST); + if (!ghost && pInstance) + { + Unit* dalronn = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_DALRONN)); + if (dalronn && dalronn->isDead()) + CAST_CRE(dalronn)->Respawn(); + + pInstance->SetData(DATA_SKARVALD_DALRONN_EVENT, NOT_STARTED); + } + } + + void EnterCombat(Unit *who) + { + if (!ghost && pInstance) + { + DoScriptText(YELL_SKARVALD_AGGRO,m_creature); + + Unit* dalronn = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_DALRONN)); + if (dalronn && dalronn->isAlive() && !dalronn->getVictim()) + dalronn->getThreatManager().addThreat(who,0.0f); + + pInstance->SetData(DATA_SKARVALD_DALRONN_EVENT, IN_PROGRESS); + } + } + + void JustDied(Unit* Killer) + { + if (!ghost && pInstance) + { + Unit* dalronn = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_DALRONN)); + if (dalronn) + { + if (dalronn->isDead()) + { + DoScriptText(YELL_SKARVALD_DAL_DIED,m_creature); + + pInstance->SetData(DATA_SKARVALD_DALRONN_EVENT, DONE); + } + else + { + DoScriptText(YELL_SKARVALD_SKA_DIEDFIRST,m_creature); + + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + //DoCast(m_creature, SPELL_SUMMON_SKARVALD_GHOST, true); + Creature* temp = m_creature->SummonCreature(MOB_SKARVALD_GHOST,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),0,TEMPSUMMON_CORPSE_DESPAWN,5000); + if (temp) + { + temp->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NON_ATTACKABLE); + temp->AI()->AttackStart(Killer); + } + } + } + } + } + + void KilledUnit(Unit *victim) + { + if (!ghost) + { + DoScriptText(YELL_SKARVALD_KILL,m_creature); + } + } + + void UpdateAI(const uint32 diff) + { + if (ghost) + { + if (pInstance && pInstance->GetData(DATA_SKARVALD_DALRONN_EVENT) != IN_PROGRESS) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + if (!UpdateVictim()) + return; + + if (!ghost) + { + if (Check_Timer) + if (Check_Timer <= diff) + { + Check_Timer = 5000; + Unit* dalronn = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_DALRONN) : 0); + if (dalronn && dalronn->isDead()) + { + Dalronn_isDead = true; + Response_Timer = 2000; + Check_Timer = 0; + } + } else Check_Timer -= diff; + + if (Response_Timer) + if (Dalronn_isDead) + if (Response_Timer <= diff) + { + DoScriptText(YELL_SKARVALD_DAL_DIEDFIRST,m_creature); + + Response_Timer = 0; + } else Response_Timer -= diff; + } + + if (Charge_Timer <= diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 1), SPELL_CHARGE); + Charge_Timer = 5000+rand()%5000; + } else Charge_Timer -= diff; + + if (StoneStrike_Timer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_STONE_STRIKE); + StoneStrike_Timer = 5000+rand()%5000; + } else StoneStrike_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_skarvald_the_constructor(Creature* pCreature) +{ + return new boss_skarvald_the_constructorAI (pCreature); +} + +struct TRINITY_DLL_DECL boss_dalronn_the_controllerAI : public ScriptedAI +{ + boss_dalronn_the_controllerAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + bool ghost; + uint32 ShadowBolt_Timer; + uint32 Debilitate_Timer; + uint32 Summon_Timer; + + uint32 Response_Timer; + uint32 Check_Timer; + uint32 AggroYell_Timer; + bool Skarvald_isDead; + + void Reset() + { + ShadowBolt_Timer = 1000; + Debilitate_Timer = 5000; + Summon_Timer = 10000; + Check_Timer = 5000; + Skarvald_isDead = false; + AggroYell_Timer = 0; + + ghost = m_creature->GetEntry() == MOB_DALRONN_GHOST; + if (!ghost && pInstance) + { + Unit* skarvald = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_SKARVALD)); + if (skarvald && skarvald->isDead()) + CAST_CRE(skarvald)->Respawn(); + + pInstance->SetData(DATA_SKARVALD_DALRONN_EVENT, NOT_STARTED); + } + } + + void EnterCombat(Unit *who) + { + if (!ghost && pInstance) + { + Unit* skarvald = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_SKARVALD)); + if (skarvald && skarvald->isAlive() && !skarvald->getVictim()) + skarvald->getThreatManager().addThreat(who,0.0f); + + AggroYell_Timer = 5000; + + if (pInstance) + pInstance->SetData(DATA_SKARVALD_DALRONN_EVENT, IN_PROGRESS); + } + } + + void JustDied(Unit* Killer) + { + if (!ghost && pInstance) + { + Unit* skarvald = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_SKARVALD)); + if (skarvald) + if (skarvald->isDead()) + { + DoScriptText(YELL_DALRONN_SKA_DIED,m_creature); + + if (pInstance) + pInstance->SetData(DATA_SKARVALD_DALRONN_EVENT, DONE); + } + else + { + DoScriptText(YELL_DALRONN_DAL_DIEDFIRST,m_creature); + + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + //DoCast(m_creature, SPELL_SUMMON_DALRONN_GHOST, true); + Creature* temp = m_creature->SummonCreature(MOB_DALRONN_GHOST,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),0,TEMPSUMMON_CORPSE_DESPAWN,5000); + if (temp) + { + temp->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NON_ATTACKABLE); + temp->AI()->AttackStart(Killer); + } + } + } + } + + void KilledUnit(Unit *victim) + { + if (!ghost) + { + DoScriptText(YELL_DALRONN_KILL,m_creature); + } + } + + void UpdateAI(const uint32 diff) + { + if (ghost) + { + if (pInstance && pInstance->GetData(DATA_SKARVALD_DALRONN_EVENT) != IN_PROGRESS) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + if (!UpdateVictim()) + return; + + if (AggroYell_Timer) + if (AggroYell_Timer <= diff) + { + DoScriptText(YELL_DALRONN_AGGRO,m_creature); + + AggroYell_Timer = 0; + } else AggroYell_Timer -= diff; + + if (!ghost) + { + if (Check_Timer) + if (Check_Timer <= diff) + { + Check_Timer = 5000; + Unit* skarvald = Unit::GetUnit(*m_creature, pInstance ? pInstance->GetData64(DATA_SKARVALD) : 0); + if (skarvald && skarvald->isDead()) + { + Skarvald_isDead = true; + Response_Timer = 2000; + Check_Timer = 0; + } + } else Check_Timer -= diff; + + if (Response_Timer) + if (Skarvald_isDead) + if (Response_Timer <= diff) + { + DoScriptText(YELL_DALRONN_SKA_DIEDFIRST,m_creature); + + Response_Timer = 0; + } else Response_Timer -= diff; + } + + if (ShadowBolt_Timer <= diff) + { + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), DUNGEON_MODE(SPELL_SHADOW_BOLT, H_SPELL_SHADOW_BOLT)); + ShadowBolt_Timer = 1000; + } + } else ShadowBolt_Timer -= diff; + + if (Debilitate_Timer <= diff) + { + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DEBILITATE); + Debilitate_Timer = 5000+rand()%5000; + } + } else Debilitate_Timer -= diff; + + if (IsHeroic()) + if (Summon_Timer <= diff) + { + DoCast(m_creature, H_SPELL_SUMMON_SKELETONS); + Summon_Timer = (rand()%10000) + 20000; + } else Summon_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_dalronn_the_controller(Creature* pCreature) +{ + return new boss_dalronn_the_controllerAI (pCreature); +} + +void AddSC_boss_skarvald_dalronn() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_skarvald_the_constructor"; + newscript->GetAI = &GetAI_boss_skarvald_the_constructor; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_dalronn_the_controller"; + newscript->GetAI = &GetAI_boss_dalronn_the_controller; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp b/src/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp new file mode 100644 index 00000000000..2a3bafc811a --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Instance_Utgarde_Keep +SD%Complete: 90 +SDComment: Instance Data Scripts and functions to acquire mobs and set encounter status for use in various Utgarde Keep Scripts +SDCategory: Utgarde Keep +EndScriptData */ + +#include "ScriptedPch.h" +#include "utgarde_keep.h" + +#define MAX_ENCOUNTER 3 + +#define ENTRY_BELLOW_1 186688 +#define ENTRY_BELLOW_2 186689 +#define ENTRY_BELLOW_3 186690 + +#define ENTRY_FORGEFIRE_1 186692 +#define ENTRY_FORGEFIRE_2 186693 +#define ENTRY_FORGEFIRE_3 186691 + +#define ENTRY_GLOWING_ANVIL_1 186609 +#define ENTRY_GLOWING_ANVIL_2 186610 +#define ENTRY_GLOWING_ANVIL_3 186611 + +#define ENTRY_GIANT_PORTCULLIS_1 186756 +#define ENTRY_GIANT_PORTCULLIS_2 186694 + +/* Utgarde Keep encounters: +0 - Prince Keleseth +1 - Skarvald Dalronn +2 - Ingvar the Plunderer +*/ + +struct TRINITY_DLL_DECL instance_utgarde_keep : public ScriptedInstance +{ + instance_utgarde_keep(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint64 Keleseth; + uint64 Skarvald; + uint64 Dalronn; + uint64 Ingvar; + + uint64 forge_bellow[3]; + uint64 forge_fire[3]; + uint64 forge_anvil[3]; + uint64 portcullis[2]; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + uint32 forge_event[3]; + std::string str_data; + + void Initialize() + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + Keleseth = 0; + Skarvald = 0; + Dalronn = 0; + Ingvar = 0; + + for (uint8 i = 0; i < 3; ++i) + { + forge_bellow[i] = 0; + forge_fire[i] = 0; + forge_anvil[i] = 0; + forge_event[i] = NOT_STARTED; + } + + portcullis[0] = 0; + portcullis[1] = 0; + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) return true; + + return false; + } + + Player* GetPlayerInMap() + { + Map::PlayerList const& players = instance->GetPlayers(); + + if (!players.isEmpty()) + { + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* plr = itr->getSource()) + return plr; + } + } + + debug_log("TSCR: Instance Utgarde Keep: GetPlayerInMap, but PlayerList is empty!"); + return NULL; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case 23953: Keleseth = pCreature->GetGUID(); break; + case 24201: Dalronn = pCreature->GetGUID(); break; + case 24200: Skarvald = pCreature->GetGUID(); break; + case 23954: Ingvar = pCreature->GetGUID(); break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + //door and object id + case ENTRY_BELLOW_1: forge_bellow[0] = pGo->GetGUID(); + if (forge_event[0] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_BELLOW_2: forge_bellow[1] = pGo->GetGUID(); + if (forge_event[1] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_BELLOW_3: forge_bellow[2] = pGo->GetGUID(); + if (forge_event[2] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_FORGEFIRE_1: forge_fire[0] = pGo->GetGUID(); + if (forge_event[0] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_FORGEFIRE_2: forge_fire[1] = pGo->GetGUID(); + if (forge_event[1] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_FORGEFIRE_3: forge_fire[2] = pGo->GetGUID(); + if (forge_event[2] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_GLOWING_ANVIL_1: forge_anvil[0] = pGo->GetGUID(); + if (forge_event[0] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_GLOWING_ANVIL_2: forge_anvil[1] = pGo->GetGUID(); + if (forge_event[1] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_GLOWING_ANVIL_3: forge_anvil[2] = pGo->GetGUID(); + if (forge_event[2] != NOT_STARTED)HandleGameObject(NULL,true,pGo);break; + case ENTRY_GIANT_PORTCULLIS_1: portcullis[0] = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE)HandleGameObject(NULL,true,pGo);break; + case ENTRY_GIANT_PORTCULLIS_2: portcullis[1] = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE)HandleGameObject(NULL,true,pGo);break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_PRINCEKELESETH: return Keleseth; + case DATA_DALRONN: return Dalronn; + case DATA_SKARVALD: return Skarvald; + case DATA_INGVAR: return Ingvar; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_PRINCEKELESETH_EVENT: + m_auiEncounter[0] = data; + break; + case DATA_SKARVALD_DALRONN_EVENT: + m_auiEncounter[1] = data; + break; + case DATA_INGVAR_EVENT: + if (data == DONE) + { + HandleGameObject(portcullis[0], true); + HandleGameObject(portcullis[1], true); + } + m_auiEncounter[2] = data; + break; + case EVENT_FORGE_1: + if (data == NOT_STARTED) + { + HandleGameObject(forge_bellow[0],false); + HandleGameObject(forge_fire[0],false); + HandleGameObject(forge_anvil[0],false); + }else + { + HandleGameObject(forge_bellow[0],true); + HandleGameObject(forge_fire[0],true); + HandleGameObject(forge_anvil[0],true); + } + forge_event[0] = data; + break; + case EVENT_FORGE_2: + if (data == NOT_STARTED) + { + HandleGameObject(forge_bellow[1],false); + HandleGameObject(forge_fire[1],false); + HandleGameObject(forge_anvil[1],false); + }else + { + HandleGameObject(forge_bellow[1],true); + HandleGameObject(forge_fire[1],true); + HandleGameObject(forge_anvil[1],true); + } + forge_event[1] = data; + break; + case EVENT_FORGE_3: + if (data == NOT_STARTED) + { + HandleGameObject(forge_bellow[2],false); + HandleGameObject(forge_fire[2],false); + HandleGameObject(forge_anvil[2],false); + }else + { + HandleGameObject(forge_bellow[2],true); + HandleGameObject(forge_fire[2],true); + HandleGameObject(forge_anvil[2],true); + } + forge_event[2] = data; + break; + } + + if (data == DONE) + { + SaveToDB(); + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_PRINCEKELESETH_EVENT: return m_auiEncounter[0]; + case DATA_SKARVALD_DALRONN_EVENT: return m_auiEncounter[1]; + case DATA_INGVAR_EVENT: return m_auiEncounter[2]; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "U K " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2] << " " << forge_event[0] << " " << forge_event[1] << " " << forge_event[2]; + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4 >> data5; + + if (dataHead1 == 'U' && dataHead2 == 'K') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + forge_event[0] = data3; + forge_event[1] = data4; + forge_event[2] = data5; + + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_utgarde_keep(Map* pMap) +{ + return new instance_utgarde_keep(pMap); +} + +void AddSC_instance_utgarde_keep() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_utgarde_keep"; + newscript->GetInstanceData = &GetInstanceData_instance_utgarde_keep; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp b/src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp new file mode 100644 index 00000000000..a7d1d91ac1f --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "utgarde_keep.h" + +uint32 entry_search[3] = +{ + 186609, + 186610, + 186611 +}; + +struct TRINITY_DLL_DECL npc_dragonflayer_forge_masterAI : public ScriptedAI +{ + npc_dragonflayer_forge_masterAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + fm_Type = 0; + } + + ScriptedInstance* pInstance; + uint8 fm_Type; + + void Reset() + { + if (fm_Type == 0) fm_Type = GetForgeMasterType(); + CheckForge(); + } + + void CheckForge() + { + if (pInstance) + { + switch(fm_Type) + { + case 1: + pInstance->SetData(EVENT_FORGE_1,m_creature->isAlive() ? NOT_STARTED : DONE); + break; + case 2: + pInstance->SetData(EVENT_FORGE_2,m_creature->isAlive() ? NOT_STARTED : DONE); + break; + case 3: + pInstance->SetData(EVENT_FORGE_3,m_creature->isAlive() ? NOT_STARTED : DONE); + break; + } + } + } + + void JustDied(Unit *killer) + { + if (fm_Type == 0) fm_Type = GetForgeMasterType(); + if (pInstance) + { + switch(fm_Type) + { + case 1: + pInstance->SetData(EVENT_FORGE_1,DONE); + break; + case 2: + pInstance->SetData(EVENT_FORGE_2,DONE); + break; + case 3: + pInstance->SetData(EVENT_FORGE_3,DONE); + break; + } + } + } + + void EnterCombat(Unit *who) + { + if (fm_Type == 0) fm_Type = GetForgeMasterType(); + if (pInstance) + { + switch(fm_Type) + { + case 1: + pInstance->SetData(EVENT_FORGE_1,IN_PROGRESS); + break; + case 2: + pInstance->SetData(EVENT_FORGE_2,IN_PROGRESS); + break; + case 3: + pInstance->SetData(EVENT_FORGE_3,IN_PROGRESS); + break; + } + } + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE ,EMOTE_ONESHOT_NONE); + } + + uint8 GetForgeMasterType() + { + float diff = 30.0f; + int near_f = 0; + + for (uint8 i = 0; i < 3 ; ++i) + { + GameObject* temp; + temp = m_creature->FindNearestGameObject(entry_search[i],30); + if (temp) + { + if (m_creature->IsWithinDist(temp,diff,false)) + { + near_f = i + 1; + diff = m_creature->GetDistance2d(temp); + + } + } + } + + switch (near_f) + { + case 1: return 1; + case 2: return 2; + case 3: return 3; + default: return 0; + } + } + + void UpdateAI(const uint32 diff) + { + if (fm_Type == 0) + fm_Type = GetForgeMasterType(); + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_dragonflayer_forge_master(Creature* pCreature) +{ + return new npc_dragonflayer_forge_masterAI(pCreature); +} + +void AddSC_utgarde_keep() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_dragonflayer_forge_master"; + newscript->GetAI = &GetAI_npc_dragonflayer_forge_master; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h b/src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h new file mode 100644 index 00000000000..b630e156564 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DEF_UTGARDE_KEEP_H +#define DEF_UTGARDE_KEEP_H + +#define DATA_PRINCEKELESETH 1 +#define DATA_SKARVALD 3 +#define DATA_DALRONN 4 +#define DATA_INGVAR 6 + +#define DATA_PRINCEKELESETH_EVENT 2 +#define DATA_SKARVALD_DALRONN_EVENT 5 +#define DATA_INGVAR_EVENT 7 + +#define EVENT_FORGE_1 8 +#define EVENT_FORGE_2 9 +#define EVENT_FORGE_3 10 + +#endif diff --git a/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_palehoof.cpp b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_palehoof.cpp new file mode 100644 index 00000000000..5637e157fc3 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_palehoof.cpp @@ -0,0 +1,823 @@ +/* Script Data Start +SDName: Boss palehoof +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_palehoof' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "utgarde_pinnacle.h" + +enum Spells +{ + SPELL_ARCING_SMASH = 48260, + SPELL_IMPALE = 48261, + H_SPELL_IMPALE = 59268, + SPELL_WITHERING_ROAR = 48256, + H_SPELL_WITHERING_ROAR = 59267, + SPELL_FREEZE = 16245 +}; + +//Orb spells +enum OrbSpells +{ + SPELL_ORB_VISUAL = 48044, + SPELL_ORB_CHANNEL = 48048 +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1575000, + SAY_SLAY_1 = -1575001, + SAY_SLAY_2 = -1575002, + SAY_DEATH = -1575003 +}; + +enum Creatures +{ + MOB_STASIS_CONTROLLER = 26688 +}; + +struct Locations +{ + float x, y, z; +}; + +struct Locations moveLocs[]= +{ + {261.6,-449.3,109.5}, + {263.3,-454.0,109.5}, + {291.5,-450.4,109.5}, + {291.5,-454.0,109.5}, + {310.0,-453.4,109.5}, + {238.6,-460.7,109.5} +}; + +enum Phase +{ + PHASE_FRENZIED_WORGEN, + PHASE_RAVENOUS_FURLBORG, + PHASE_MASSIVE_JORMUNGAR, + PHASE_FEROCIOUS_RHINO, + PHASE_GORTOK_PALEHOOF, + PHASE_NONE +}; + +struct TRINITY_DLL_DECL boss_palehoofAI : public ScriptedAI +{ + boss_palehoofAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiArcingSmashTimer; + uint32 uiImpaleTimer; + uint32 uiWhiteringRoarTimer; + uint32 uiWaitingTimer; + Phase currentPhase; + uint8 AddCount; + bool DoneAdds[4]; + + ScriptedInstance *pInstance; + + void Reset() + { + uiArcingSmashTimer = 15000; + uiImpaleTimer = 12000; + uiWhiteringRoarTimer = 10000; + + m_creature->GetMotionMaster()->MoveTargetedHome(); + + for(uint32 i=0;i<4;i++) + DoneAdds[i]=false; + AddCount=0; + + currentPhase=PHASE_NONE; + + if (pInstance) + { + pInstance->SetData(DATA_GORTOK_PALEHOOF_EVENT, NOT_STARTED); + + Creature* pTemp; + if ((pTemp = Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_MOB_FRENZIED_WORGEN))) && !pTemp->isAlive()) + pTemp->Respawn(); + if ((pTemp = Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_MOB_FEROCIOUS_RHINO))) && !pTemp->isAlive()) + pTemp->Respawn(); + if ((pTemp = Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_MOB_MASSIVE_JORMUNGAR))) && !pTemp->isAlive()) + pTemp->Respawn(); + if ((pTemp = Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_MOB_RAVENOUS_FURBOLG))) && !pTemp->isAlive()) + pTemp->Respawn(); + + if (GameObject* pGo = pInstance->instance->GetGameObject(pInstance->GetData64(DATA_GORTOK_PALEHOOF_SPHERE))) + { + pGo->SetGoState(GO_STATE_READY); + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + } + } + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(who, true)) + { + m_creature->AddThreat(who, 0.0f); + m_creature->SetInCombatWith(who); + who->SetInCombatWith(m_creature); + DoStartMovement(who); + } + } + + void UpdateAI(const uint32 diff) + { + if(currentPhase!=PHASE_GORTOK_PALEHOOF) + return; + //Return since we have no target + if (!UpdateVictim()) + return; + + Creature* pTemp = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_ORB) : 0); + if (pTemp && pTemp->isAlive()) + pTemp->DisappearAndDie(); + + if (uiArcingSmashTimer <= diff) + { + DoCast(m_creature, SPELL_ARCING_SMASH); + uiArcingSmashTimer = urand(13000,17000); + } else uiArcingSmashTimer -= diff; + + if (uiImpaleTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_IMPALE, H_SPELL_IMPALE)); + uiImpaleTimer = urand(8000,12000); + } else uiImpaleTimer -= diff; + + if (uiWhiteringRoarTimer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_WITHERING_ROAR, H_SPELL_WITHERING_ROAR)); + uiWhiteringRoarTimer = urand(8000,12000); + } else uiWhiteringRoarTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + if (pInstance) + pInstance->SetData(DATA_GORTOK_PALEHOOF_EVENT, DONE); + Creature* pTemp = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_ORB) : 0); + if (pTemp && pTemp->isAlive()) + pTemp->DisappearAndDie(); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), m_creature); + } + + void NextPhase() + { + if(currentPhase == PHASE_NONE) + { + pInstance->SetData(DATA_GORTOK_PALEHOOF_EVENT, IN_PROGRESS); + m_creature->SummonCreature(MOB_STASIS_CONTROLLER,moveLocs[5].x,moveLocs[5].y,moveLocs[5].z,0,TEMPSUMMON_CORPSE_DESPAWN); + } + Phase move = PHASE_NONE; + if (AddCount >= DUNGEON_MODE(2,4)) + move = PHASE_GORTOK_PALEHOOF; + else + { + //select random not yet defeated add + uint8 next = urand(0,3); + for(uint8 i=0; i < 16; i++) + { + if(!DoneAdds[i%4] && next == 0) + { + move = (Phase)(i%4); + break; + } else if (!DoneAdds[i%4] && next > 0) + --next; + } + ++AddCount; + DoneAdds[move] = true; + move = (Phase)(move%4); + } + //send orb to summon spot + Creature *pOrb = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_ORB) : 0); + if (pOrb && pOrb->isAlive()) + { + if(currentPhase == PHASE_NONE) + pOrb->CastSpell(m_creature,SPELL_ORB_VISUAL,true); + pOrb->GetMotionMaster()->MovePoint(move,moveLocs[move].x,moveLocs[move].y,moveLocs[move].z); + } + currentPhase = move; + } + + void JustReachedHome() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NOT_ATTACKABLE_1|UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(m_creature, SPELL_FREEZE); + } +}; + +CreatureAI* GetAI_boss_palehoof(Creature* pCreature) +{ + return new boss_palehoofAI (pCreature); +} + +//ravenous furbolg's spells +enum RavenousSpells +{ + SPELL_CHAIN_LIGHTING = 48140, + H_SPELL_CHAIN_LIGHTING = 59273, + SPELL_CRAZED = 48139, + SPELL_TERRIFYING_ROAR = 48144 +}; + +struct TRINITY_DLL_DECL mob_ravenous_furbolgAI : public ScriptedAI +{ + mob_ravenous_furbolgAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiChainLightingTimer; + uint32 uiCrazedTimer; + uint32 uiTerrifyingRoarTimer; + + ScriptedInstance *pInstance; + + void Reset() + { + uiChainLightingTimer = 5000; + uiCrazedTimer = 10000; + uiTerrifyingRoarTimer = 15000; + + m_creature->GetMotionMaster()->MoveTargetedHome(); + + if (pInstance) + if(pInstance->GetData(DATA_GORTOK_PALEHOOF_EVENT)==IN_PROGRESS) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof && pPalehoof->isAlive()) + CAST_AI(boss_palehoofAI, pPalehoof->AI())->Reset(); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiChainLightingTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_CHAIN_LIGHTING, H_SPELL_CHAIN_LIGHTING)); + uiChainLightingTimer = 5000 + rand()%5000; + } else uiChainLightingTimer -= diff; + + if (uiCrazedTimer <= diff) + { + DoCast(m_creature, SPELL_CRAZED); + uiCrazedTimer = 8000 + rand()%4000; + } else uiCrazedTimer -= diff; + + if (uiTerrifyingRoarTimer <= diff) + { + DoCast(m_creature, SPELL_TERRIFYING_ROAR); + uiTerrifyingRoarTimer = 10000 + rand()%10000; + } else uiTerrifyingRoarTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(who, true)) + { + m_creature->AddThreat(who, 0.0f); + m_creature->SetInCombatWith(who); + who->SetInCombatWith(m_creature); + DoStartMovement(who); + } + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof) + CAST_AI(boss_palehoofAI, pPalehoof->AI())->NextPhase(); + } + } + + void JustReachedHome() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NOT_ATTACKABLE_1|UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(m_creature, SPELL_FREEZE); + } +}; + +CreatureAI* GetAI_mob_ravenous_furbolg(Creature* pCreature) +{ + return new mob_ravenous_furbolgAI (pCreature); +} + +//frenzied worgen's spells +enum FrenziedSpells +{ + SPELL_MORTAL_WOUND = 48137, + H_SPELL_MORTAL_WOUND = 59265, + SPELL_ENRAGE_1 = 48138, + SPELL_ENRAGE_2 = 48142 +}; + +struct TRINITY_DLL_DECL mob_frenzied_worgenAI : public ScriptedAI +{ + mob_frenzied_worgenAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiMortalWoundTimer; + uint32 uiEnrage1Timer; + uint32 uiEnrage2Timer; + + ScriptedInstance *pInstance; + + void Reset() + { + uint32 uiMortalWoundTimer = 5000; + uint32 uiEnrage1Timer = 15000; + uint32 uiEnrage2Timer = 10000; + + m_creature->GetMotionMaster()->MoveTargetedHome(); + + if (pInstance) + if(pInstance->GetData(DATA_GORTOK_PALEHOOF_EVENT)==IN_PROGRESS) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof && pPalehoof->isAlive()) + CAST_AI(boss_palehoofAI, pPalehoof->AI())->Reset(); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiMortalWoundTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_MORTAL_WOUND, H_SPELL_MORTAL_WOUND)); + uiMortalWoundTimer = 3000 + rand()%4000; + } else uiMortalWoundTimer -= diff; + + if (uiEnrage1Timer <= diff) + { + DoCast(m_creature, SPELL_ENRAGE_1); + uiEnrage1Timer = 15000; + } else uiEnrage1Timer -= diff; + + if (uiEnrage2Timer <= diff) + { + DoCast(m_creature, SPELL_ENRAGE_2); + uiEnrage2Timer = 10000; + } else uiEnrage2Timer -= diff; + + DoMeleeAttackIfReady(); + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(who, true)) + { + m_creature->AddThreat(who, 0.0f); + m_creature->SetInCombatWith(who); + who->SetInCombatWith(m_creature); + DoStartMovement(who); + } + if (pInstance) + pInstance->SetData(DATA_GORTOK_PALEHOOF_EVENT, IN_PROGRESS); + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_GORTOK_PALEHOOF)); + if (pPalehoof) + CAST_AI(boss_palehoofAI, pPalehoof->AI())->NextPhase(); + } + } + + void JustReachedHome() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NOT_ATTACKABLE_1|UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(m_creature, SPELL_FREEZE); + } +}; + +CreatureAI* GetAI_mob_frenzied_worgen(Creature* pCreature) +{ + return new mob_frenzied_worgenAI (pCreature); +} + +//ferocious rhino's spells +enum FerociousSpells +{ + SPELL_GORE = 48130, + H_SPELL_GORE = 59264, + SPELL_GRIEVOUS_WOUND = 48105, + H_SPELL_GRIEVOUS_WOUND = 59263, + SPELL_STOMP = 48131 +}; + +struct TRINITY_DLL_DECL mob_ferocious_rhinoAI : public ScriptedAI +{ + mob_ferocious_rhinoAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiStompTimer; + uint32 uiGoreTimer; + uint32 uiGrievousWoundTimer; + + ScriptedInstance *pInstance; + + void Reset() + { + uiStompTimer = 10000; + uiGoreTimer = 15000; + uiGrievousWoundTimer = 20000; + + m_creature->GetMotionMaster()->MoveTargetedHome(); + + if (pInstance) + if(pInstance->GetData(DATA_GORTOK_PALEHOOF_EVENT)==IN_PROGRESS) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof && pPalehoof->isAlive()) + CAST_AI(boss_palehoofAI, pPalehoof->AI())->Reset(); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiStompTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_STOMP); + uiStompTimer = 8000 + rand()%4000; + } else uiStompTimer -= diff; + + if (uiGoreTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_GORE, H_SPELL_GORE)); + uiGoreTimer = 13000 + rand()%4000; + } else uiGoreTimer -= diff; + + if (uiGrievousWoundTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_GRIEVOUS_WOUND, H_SPELL_GRIEVOUS_WOUND)); + uiGrievousWoundTimer = 18000 + rand()%4000; + } else uiGrievousWoundTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(who, true)) + { + m_creature->AddThreat(who, 0.0f); + m_creature->SetInCombatWith(who); + who->SetInCombatWith(m_creature); + DoStartMovement(who); + } + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof) + CAST_AI(boss_palehoofAI, pPalehoof->AI())->NextPhase(); + } + } + + void JustReachedHome() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NOT_ATTACKABLE_1|UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(m_creature, SPELL_FREEZE); + } +}; + +CreatureAI* GetAI_mob_ferocious_rhino(Creature* pCreature) +{ + return new mob_ferocious_rhinoAI (pCreature); +} + +//massive jormungar's spells +enum MassiveSpells +{ + SPELL_ACID_SPIT = 48132, + SPELL_ACID_SPLATTER = 48136, + H_SPELL_ACID_SPLATTER = 59272, + SPELL_POISON_BREATH = 48133, + H_SPELL_POISON_BREATH = 59271 +}; + +enum MassiveAdds +{ + CREATURE_JORMUNGAR_WORM = 27228 +}; + +struct TRINITY_DLL_DECL mob_massive_jormungarAI : public ScriptedAI +{ + mob_massive_jormungarAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiAcidSpitTimer; + uint32 uiAcidSplatterTimer; + uint32 uiPoisonBreathTimer; + + ScriptedInstance *pInstance; + + void Reset() + { + uiAcidSpitTimer = 3000; + uiAcidSplatterTimer = 12000; + uiPoisonBreathTimer = 10000; + + m_creature->GetMotionMaster()->MoveTargetedHome(); + + if (pInstance) + if(pInstance->GetData(DATA_GORTOK_PALEHOOF_EVENT) == IN_PROGRESS) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof && pPalehoof->isAlive()) + CAST_AI(boss_palehoofAI, pPalehoof->AI())->Reset(); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiAcidSpitTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_ACID_SPIT); + uiAcidSpitTimer = 2000 + rand()%2000; + } else uiAcidSpitTimer -= diff; + + if (uiAcidSplatterTimer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_POISON_BREATH, H_SPELL_POISON_BREATH)); + uiAcidSplatterTimer = 10000 + rand()%4000; + } else uiAcidSplatterTimer -= diff; + + if (uiPoisonBreathTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_POISON_BREATH, H_SPELL_POISON_BREATH)); + uiPoisonBreathTimer = 8000 + rand()%4000; + } else uiPoisonBreathTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(who, true)) + { + m_creature->AddThreat(who, 0.0f); + m_creature->SetInCombatWith(who); + who->SetInCombatWith(m_creature); + DoStartMovement(who); + } + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + Creature *pPalehoof = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof) + CAST_AI(boss_palehoofAI,pPalehoof->AI())->NextPhase(); + } + } + + void JustReachedHome() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NOT_ATTACKABLE_1|UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(m_creature, SPELL_FREEZE); + } +}; + +CreatureAI* GetAI_mob_massive_jormungar(Creature* pCreature) +{ + return new mob_massive_jormungarAI (pCreature); +} + + +struct TRINITY_DLL_DECL mob_palehoof_orbAI : public ScriptedAI +{ + mob_palehoof_orbAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance *pInstance; + uint32 SummonTimer; + Phase currentPhase; + + void Reset() + { + currentPhase=PHASE_NONE; + SummonTimer=5000; + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); + m_creature->RemoveAurasDueToSpell(SPELL_ORB_VISUAL); + m_creature->SetSpeed(MOVE_FLIGHT , 0.5f); + } + + void UpdateAI(const uint32 diff) + { + if(currentPhase==PHASE_NONE) + return; + + if(SummonTimer<=diff) + { + if(currentPhase<5&¤tPhase>=0) + { + Creature *pNext; + switch(currentPhase) + { + case PHASE_FRENZIED_WORGEN: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_FRENZIED_WORGEN) : 0); break; + case PHASE_RAVENOUS_FURLBORG: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_RAVENOUS_FURBOLG) : 0); break; + case PHASE_MASSIVE_JORMUNGAR: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_MASSIVE_JORMUNGAR) : 0); break; + case PHASE_FEROCIOUS_RHINO: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_FEROCIOUS_RHINO) : 0); break; + case PHASE_GORTOK_PALEHOOF: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); break; + } + + if (pNext) + { + pNext->RemoveAurasDueToSpell(SPELL_FREEZE); + pNext->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_ATTACKABLE_1|UNIT_FLAG_OOC_NOT_ATTACKABLE); + ((Unit*)pNext)->SetStandState(UNIT_STAND_STATE_STAND); + pNext->SetInCombatWithZone(); + pNext->Attack(pNext->SelectNearestTarget(100),true); + + } + currentPhase=PHASE_NONE; + } + } else SummonTimer-=diff; + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + if(id<0 || id>4) + return; + Creature *pNext; + switch(id) + { + case PHASE_FRENZIED_WORGEN: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_FRENZIED_WORGEN) : 0); break; + case PHASE_RAVENOUS_FURLBORG: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_RAVENOUS_FURBOLG) : 0); break; + case PHASE_MASSIVE_JORMUNGAR: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_MASSIVE_JORMUNGAR) : 0); break; + case PHASE_FEROCIOUS_RHINO: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_MOB_FEROCIOUS_RHINO) : 0); break; + case PHASE_GORTOK_PALEHOOF: pNext = Unit::GetCreature((*m_creature), pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); break; + } + if(pNext) + DoCast(pNext, SPELL_ORB_CHANNEL, false); + currentPhase=(Phase)id; + SummonTimer=5000; + } +}; + +CreatureAI* GetAI_mob_palehoof_orb(Creature* pCreature) +{ + return new mob_palehoof_orbAI (pCreature); +} + + + +bool GOHello_palehoof_sphere(Player *pPlayer, GameObject *pGO) +{ + ScriptedInstance *pInstance = pGO->GetInstanceData(); + + Creature *pPalehoof = Unit::GetCreature(*pGO, pInstance ? pInstance->GetData64(DATA_GORTOK_PALEHOOF) : 0); + if (pPalehoof && pPalehoof->isAlive()) + { + // maybe these are hacks :( + pGO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGO->SetGoState(GO_STATE_ACTIVE); + + CAST_AI(boss_palehoofAI, pPalehoof->AI())->NextPhase(); + } + return true; +} + + + +void AddSC_boss_palehoof() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_palehoof"; + newscript->GetAI = &GetAI_boss_palehoof; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ravenous_furbolg"; + newscript->GetAI = &GetAI_mob_ravenous_furbolg; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_frenzied_worgen"; + newscript->GetAI = &GetAI_mob_frenzied_worgen; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ferocious_rhino"; + newscript->GetAI = &GetAI_mob_ferocious_rhino; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_massive_jormungar"; + newscript->GetAI = &GetAI_mob_massive_jormungar; + newscript->RegisterSelf(); + + + newscript = new Script; + newscript->Name = "mob_palehoof_orb"; + newscript->GetAI = &GetAI_mob_palehoof_orb; + newscript->RegisterSelf(); + + + newscript = new Script; + newscript->Name = "go_palehoof_sphere"; + newscript->pGOHello=&GOHello_palehoof_sphere; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp new file mode 100644 index 00000000000..efb943aa6f9 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp @@ -0,0 +1,252 @@ +/* Script Data Start +SDName: Boss skadi +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_skadi' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "utgarde_pinnacle.h" + +//Phase 0 "gauntlet even" Skadi on a flying mount, waves of adds charging to the group periodicaly carrying harpoons +//Phase 1 Kill the Skadi drake mount with harppons launcher +//Phase 2 Kill the Skadi + +//Skadi Spells +#define SPELL_CRUSH 50234 +#define H_SPELL_CRUSH 59330 +#define SPELL_POISONED_SPEAR 50225 +#define H_SPELL_POISONED_SPEAR 59331 +#define SPELL_WHIRLWIND 50228 //random target, but not the tank approx. every 20s +#define H_SPELL_WHIRLWIND 59332 + +//Spawned creatures +#define CREATURE_YMIRJAR_WARRIOR 26690 +#define CREATURE_YMIRJAR_WITCH_DOCTOR 26691 +#define CREATURE_YMIRJAR_HARPOONER 26692 + +#define DATA_MOUNT 27043 + +//not in db +//Yell +#define SAY_AGGRO -1575004 +#define SAY_KILL_1 -1575005 +#define SAY_KILL_2 -1575006 +#define SAY_KILL_3 -1575007 +#define SAY_DEATH -1575008 +#define SAY_DRAKE_DEATH -1575009 +#define SAY_DRAKE_HIT_1 -1575010 +#define SAY_DRAKE_HIT_2 -1575011 +#define SAY_DRAKE_BREATH_1 -1575012 +#define SAY_DRAKE_BREATH_2 -1575013 +#define SAY_DRAKE_BREATH_3 -1575014 + +//Spawn locations +struct Locations +{ + float x, y, z; + uint32 id; +}; + +static Locations SpawnLoc[]= +{ + {340.556, -511.493, 104.352}, + {367.741, -512.865, 104.828}, + {399.546, -512.755, 104.834}, + {430.551, -514.320, 105.055}, + {468.931, -513.555, 104.723} +}; + +enum CombatPhase +{ + FLYING, + SKADI +}; + +struct TRINITY_DLL_DECL boss_skadiAI : public ScriptedAI +{ + boss_skadiAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiCrushTimer; + uint32 uiPoisonedSpearTimer; + uint32 uiWhirlwindTimer; + uint32 uiMovementTimer; + uint32 uiWaypointId; + uint32 uiSpawnCounter; + + CombatPhase Phase; + + ScriptedInstance* pInstance; + + void Reset() + { + uiCrushTimer = 8000; + uiPoisonedSpearTimer = 10000; + uiWhirlwindTimer = 20000; + uiSpawnCounter = 0; + + uiWaypointId = 0; + + Phase = SKADI; + + m_creature->Unmount(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (pInstance) + pInstance->SetData(DATA_SKADI_THE_RUTHLESS_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + m_creature->Mount(DATA_MOUNT); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->MovePoint(uiWaypointId, 340.259, -510.541, 120.869); + + Phase = FLYING; + + if (pInstance) + pInstance->SetData(DATA_SKADI_THE_RUTHLESS_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + switch(Phase) + { + case FLYING: + if (uiMovementTimer <= diff) + { + switch(uiWaypointId) + { + case 0: m_creature->GetMotionMaster()->MovePoint(uiWaypointId, 340.259, -510.541, 120.869); break; + case 1: m_creature->GetMotionMaster()->MovePoint(uiWaypointId, 472.977, -513.636, 120.869); break; + case 200: + m_creature->GetMotionMaster()->Clear(); + m_creature->Unmount(); + Phase = SKADI; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + AttackStart(pTarget); + break; + } + } else uiMovementTimer -= diff; + break; + case SKADI: + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiCrushTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_CRUSH, H_SPELL_CRUSH)); + uiCrushTimer = 8000; + } else uiCrushTimer -= diff; + + if (uiPoisonedSpearTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_POISONED_SPEAR, H_SPELL_POISONED_SPEAR)); + uiPoisonedSpearTimer = 10000; + } else uiPoisonedSpearTimer -= diff; + + if (uiWhirlwindTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + m_creature->CastSpell(pTarget, DUNGEON_MODE(SPELL_WHIRLWIND, H_SPELL_WHIRLWIND), false); + } else uiWhirlwindTimer = 20000; + + DoMeleeAttackIfReady(); + break; + } + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_SKADI_THE_RUTHLESS_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(RAND(SAY_KILL_1,SAY_KILL_2,SAY_KILL_3), m_creature); + } + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE) + return; + + if (uiSpawnCounter >= DUNGEON_MODE(4, 5)) + { + uiWaypointId = 200; + uiMovementTimer = 3000; + } + else + { + switch(id) + { + case 0: + SpawnMobs(uiSpawnCounter); + uiWaypointId = 1; + ++uiSpawnCounter; + uiMovementTimer = 3000; + break; + case 1: + SpawnMobs(uiSpawnCounter); + uiWaypointId = 0; + ++uiSpawnCounter; + uiMovementTimer = 3000; + break; + } + } + } + + void SpawnMobs(uint32 spot) + { + uint8 uiMaxSpawn = DUNGEON_MODE(5, 6); + for (uint8 i = 0; i < uiMaxSpawn; ++i) + { + Creature* pTemp; + switch (urand(0,2)) + { + case 0: pTemp = m_creature->SummonCreature(CREATURE_YMIRJAR_WARRIOR, SpawnLoc[spot].x+rand()%5, SpawnLoc[spot].y+rand()%5, SpawnLoc[spot].z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); break; + case 1: pTemp = m_creature->SummonCreature(CREATURE_YMIRJAR_WITCH_DOCTOR, SpawnLoc[spot].x+rand()%5, SpawnLoc[spot].y+rand()%5, SpawnLoc[spot].z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); break; + case 2: pTemp = m_creature->SummonCreature(CREATURE_YMIRJAR_HARPOONER, SpawnLoc[spot].x+rand()%5, SpawnLoc[spot].y+rand()%5, SpawnLoc[spot].z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); break; + } + if (pTemp) + { + pTemp->SetInCombatWithZone(); + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + pTemp->AI()->AttackStart(pTarget); + } + } + } +}; + +CreatureAI* GetAI_boss_skadi(Creature* pCreature) +{ + return new boss_skadiAI (pCreature); +} + +void AddSC_boss_skadi() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_skadi"; + newscript->GetAI = &GetAI_boss_skadi; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp new file mode 100644 index 00000000000..4fb5d273312 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp @@ -0,0 +1,384 @@ +/* Script Data Start +SDName: Boss svala +SDAuthor: Tartalo +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_svala' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "utgarde_pinnacle.h" + +enum Spells +{ + SPELL_CALL_FLAMES = 48258, + SPELL_RITUAL_OF_THE_SWORD = 48276, //Effect #1 Teleport, Effect #2 Dummy + SPELL_SINSTER_STRIKE = 15667, + H_SPELL_SINSTER_STRIKE = 59409, + SPELL_SVALA_TRANSFORMING1 = 54140, + SPELL_SVALA_TRANSFORMING2 = 54205 +}; +//not in db +enum Yells +{ + SAY_DIALOG_WITH_ARTHAS_1 = -1575015, + SAY_DIALOG_WITH_ARTHAS_2 = -1575016, + SAY_DIALOG_WITH_ARTHAS_3 = -1575017, + SAY_AGGRO = -1575018, + SAY_SLAY_1 = -1575019, + SAY_SLAY_2 = -1575020, + SAY_SLAY_3 = -1575021, + SAY_DEATH = -1575022, + SAY_SACRIFICE_PLAYER_1 = -1575023, + SAY_SACRIFICE_PLAYER_2 = -1575024, + SAY_SACRIFICE_PLAYER_3 = -1575025, + SAY_SACRIFICE_PLAYER_4 = -1575026, + SAY_SACRIFICE_PLAYER_5 = -1575027, + SAY_DIALOG_OF_ARTHAS_1 = -1575028, + SAY_DIALOG_OF_ARTHAS_2 = -1575029 +}; +enum Creatures +{ + CREATURE_ARTHAS = 24266, // Image of Arthas + CREATURE_SVALA_SORROWGRAVE = 26668, // Svala after transformation + CREATURE_SVALA = 29281, // Svala before transformation + CREATURE_RITUAL_CHANNELER = 27281 +}; +enum ChannelerSpells +{ + //ritual channeler's spells + SPELL_PARALYZE = 48278, + SPELL_SHADOWS_IN_THE_DARK = 59407 +}; +enum Misc +{ + DATA_SVALA_DISPLAY_ID = 25944 +}; +enum IntroPhase +{ + IDLE, + INTRO, + FINISHED +}; +enum CombatPhase +{ + NORMAL, + SACRIFICING +}; +struct Locations +{ + float x, y, z; +}; +static Locations RitualChannelerLocations[]= +{ + {296.42, -355.01, 90.94}, + {302.36, -352.01, 90.54}, + {291.39, -350.89, 90.54} +}; + +struct TRINITY_DLL_DECL boss_svalaAI : public ScriptedAI +{ + boss_svalaAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiIntroTimer; + + uint8 uiIntroPhase; + + IntroPhase Phase; + + Creature* pArthas; + + ScriptedInstance* pInstance; + + void Reset() + { + Phase = IDLE; + uiIntroTimer = 1000; + uiIntroPhase = 0; + pArthas = NULL; + + if (pInstance) + pInstance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, NOT_STARTED); + } + + void MoveInLineOfSight(Unit* pWho) + { + if (!pWho) + return; + if (Phase == IDLE && pWho->isTargetableForAttack() && m_creature->IsHostileTo(pWho) && Phase == IDLE && m_creature->IsWithinDistInMap(pWho, 40)) + { + Phase = INTRO; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (pArthas = m_creature->SummonCreature(CREATURE_ARTHAS, 295.81, -366.16, 92.57, 1.58, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 20000)) + { + pArthas->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + pArthas->SetFloatValue(OBJECT_FIELD_SCALE_X, 5); + } + } + } + + void AttackStart(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (Phase != INTRO) + return; + + if (uiIntroTimer <= diff) + { + if(!pArthas) + return; + + switch (uiIntroPhase) + { + case 0: + DoScriptText(SAY_DIALOG_WITH_ARTHAS_1, m_creature); + ++uiIntroPhase; + uiIntroTimer = 3500; + break; + case 1: + DoScriptText(SAY_DIALOG_OF_ARTHAS_1, pArthas); + ++uiIntroPhase; + uiIntroTimer = 3500; + break; + case 2: + DoScriptText(SAY_DIALOG_WITH_ARTHAS_2, m_creature); + ++uiIntroPhase; + uiIntroTimer = 3500; + break; + case 3: + DoScriptText(SAY_DIALOG_OF_ARTHAS_2, pArthas); + ++uiIntroPhase; + uiIntroTimer = 3500; + break; + case 4: + DoScriptText(SAY_DIALOG_WITH_ARTHAS_3, m_creature); + DoCast(m_creature, SPELL_SVALA_TRANSFORMING1); + ++uiIntroPhase; + uiIntroTimer = 2800; + break; + case 5: + DoCast(m_creature, SPELL_SVALA_TRANSFORMING2); + ++uiIntroPhase; + uiIntroTimer = 200; + break; + case 6: + if (Creature* pSvalaSorrowgrave = m_creature->SummonCreature(CREATURE_SVALA_SORROWGRAVE, 296.632, -346.075, 90.6307, 1.58, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000)) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetDisplayId(DATA_SVALA_DISPLAY_ID); + pArthas->DisappearAndDie(); + Phase = FINISHED; + } + else Reset(); + return; + } + } else uiIntroTimer -= diff; + } +}; + +struct TRINITY_DLL_DECL mob_ritual_channelerAI : public Scripted_NoMovementAI +{ + mob_ritual_channelerAI(Creature *c) :Scripted_NoMovementAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + void Reset() + { + DoCast(m_creature, SPELL_SHADOWS_IN_THE_DARK); + } + + void EnterCombat(Unit* who) + { + if (who && !who->HasAura(SPELL_PARALYZE,0)) + DoCast(who, SPELL_PARALYZE); + return; + } +}; + +struct TRINITY_DLL_DECL boss_svala_sorrowgraveAI : public ScriptedAI +{ + boss_svala_sorrowgraveAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiSinsterStrikeTimer; + uint32 uiCallFlamesTimer; + uint32 uiRitualOfSwordTimer; + uint32 uiSacrificeTimer; + + CombatPhase Phase; + + Creature* pRitualChanneler[3]; + Unit* pSacrificeTarget; + + ScriptedInstance* pInstance; + + void Reset() + { + uiSinsterStrikeTimer = 7000; + uiCallFlamesTimer = 10000; + uiRitualOfSwordTimer = 20000; + uiSacrificeTimer = 8000; + + Phase = NORMAL; + + DoTeleportTo(296.632, -346.075, 90.6307); + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); + + for (uint8 i = 0; i < 3; ++i) + pRitualChanneler[i] = NULL; + pSacrificeTarget = NULL; + + if (pInstance) + pInstance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (Phase == NORMAL) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiSinsterStrikeTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_SINSTER_STRIKE, H_SPELL_SINSTER_STRIKE)); + uiSinsterStrikeTimer = urand(5000,9000); + } else uiSinsterStrikeTimer -= diff; + + if (uiCallFlamesTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + DoCast(pTarget, SPELL_CALL_FLAMES); + uiCallFlamesTimer = urand(8000,12000); + } + } else uiCallFlamesTimer -= diff; + + if (uiRitualOfSwordTimer <= diff) + { + pSacrificeTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); + if (pSacrificeTarget) + { + DoScriptText(RAND(SAY_SACRIFICE_PLAYER_1,SAY_SACRIFICE_PLAYER_2,SAY_SACRIFICE_PLAYER_3,SAY_SACRIFICE_PLAYER_4,SAY_SACRIFICE_PLAYER_5),m_creature); + DoCast(pSacrificeTarget, SPELL_RITUAL_OF_THE_SWORD); + //Spell doesn't teleport + DoTeleportPlayer(pSacrificeTarget, 296.632, -346.075, 90.63, 4.6); + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_FLY_MODE); + DoTeleportTo(296.632, -346.075, 120.85); + Phase = SACRIFICING; + + for (uint8 i = 0; i < 3; ++i) + if (pRitualChanneler[i] = m_creature->SummonCreature(CREATURE_RITUAL_CHANNELER, RitualChannelerLocations[i].x, RitualChannelerLocations[i].y, RitualChannelerLocations[i].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000)) + if (mob_ritual_channelerAI *pChannelerAI = CAST_AI(mob_ritual_channelerAI,pRitualChanneler[i]->AI())) + pChannelerAI->AttackStartNoMove(pSacrificeTarget); + + uiRitualOfSwordTimer = urand(18000,22000); + } + } else uiRitualOfSwordTimer -= diff; + + DoMeleeAttackIfReady(); + } + else //SACRIFICING + { + if (uiSacrificeTimer <= diff) + { + bool bSacrificed = false; + for (uint8 i = 0; i < 3; ++i) + { + if (pRitualChanneler[i] && pRitualChanneler[i]->isAlive()) + { + bSacrificed = true; + break; + } + } + if (bSacrificed && pSacrificeTarget && pSacrificeTarget->isAlive()) + m_creature->Kill(pSacrificeTarget, false); // durability damage? + + //go down + Phase = NORMAL; + pSacrificeTarget = NULL; + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + m_creature->GetMotionMaster()->MoveChase(pTarget); + + uiSacrificeTimer = 8000; + } + else uiSacrificeTimer -= diff; + } + } + + void KilledUnit(Unit* pVictim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void JustDied(Unit* pKiller) + { + if (pInstance) + { + Creature* pSvala = Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_SVALA)); + if (pSvala && pSvala->isAlive()) + pKiller->Kill(pSvala); + + pInstance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, IN_PROGRESS); + } + DoScriptText(SAY_DEATH, m_creature); + } +}; + +CreatureAI* GetAI_boss_svala(Creature* pCreature) +{ + return new boss_svalaAI (pCreature); +} + +CreatureAI* GetAI_mob_ritual_channeler(Creature* pCreature) +{ + return new mob_ritual_channelerAI(pCreature); +} + +CreatureAI* GetAI_boss_svala_sorrowgrave(Creature* pCreature) +{ + return new boss_svala_sorrowgraveAI(pCreature); +} + +void AddSC_boss_svala() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_svala"; + newscript->GetAI = &GetAI_boss_svala; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ritual_channeler"; + newscript->GetAI = &GetAI_mob_ritual_channeler; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_svala_sorrowgrave"; + newscript->GetAI = &GetAI_boss_svala_sorrowgrave; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp new file mode 100644 index 00000000000..6f1d8d7196f --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp @@ -0,0 +1,367 @@ +/* Script Data Start +SDName: Boss ymiron +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = 'boss_ymiron' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "utgarde_pinnacle.h" + +enum Spells +{ + SPELL_BANE = 48294, + H_SPELL_BANE = 59301, + SPELL_DARK_SLASH = 48292, + SPELL_FETID_ROT = 48291, + H_SPELL_FETID_ROT = 59300, + SPELL_SCREAMS_OF_THE_DEAD = 51750, + SPELL_SPIRIT_BURST = 48529, + H_SPELL_SPIRIT_BURST = 59305, + SPELL_SPIRIT_STRIKE = 48423, + H_SPELL_SPIRIT_STRIKE = 59304, + SPELL_ANCESTORS_VENGEANCE = 16939, + + SPELL_SUMMON_AVENGING_SPIRIT = 48592, + SPELL_SUMMON_SPIRIT_FOUNT = 48386, + + SPELL_CHANNEL_SPIRIT_TO_YMIRON = 48316, + SPELL_CHANNEL_YMIRON_TO_SPIRIT = 48307, + + SPELL_SPIRIT_FOUNT = 48380, + H_SPELL_SPIRIT_FOUNT = 59320 +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1575028, + SAY_SLAY_1 = -1575029, + SAY_SLAY_2 = -1575030, + SAY_SLAY_3 = -1575031, + SAY_SLAY_4 = -1575032, + SAY_DEATH = -1575033, + SAY_SUMMON_BJORN = -1575034, + SAY_SUMMON_HALDOR = -1575035, + SAY_SUMMON_RANULF = -1575036, + SAY_SUMMON_TORGYN = -1575037 +}; + +enum Creatures +{ + CREATURE_BJORN = 27303, + CREATURE_BJORN_VISUAL = 27304, + CREATURE_HALDOR = 27307, + CREATURE_HALDOR_VISUAL = 27310, + CREATURE_RANULF = 27308, + CREATURE_RANULF_VISUAL = 27311, + CREATURE_TORGYN = 27309, + CREATURE_TORGYN_VISUAL = 27312, + CREATURE_SPIRIT_FOUNT = 27339, + CREATURE_AVENGING_SPIRIT = 27386 +}; + +struct ActiveBoatStruct +{ + uint32 npc; + uint32 say; + float MoveX,MoveY,MoveZ,SpawnX,SpawnY,SpawnZ,SpawnO; +}; + +static ActiveBoatStruct ActiveBot[4] = +{ + {CREATURE_BJORN_VISUAL, SAY_SUMMON_BJORN, 404.379, -335.335, 104.756, 413.594, -335.408, 107.995, 3.157}, + {CREATURE_HALDOR_VISUAL, SAY_SUMMON_HALDOR, 380.813, -335.069, 104.756, 369.994, -334.771, 107.995, 6.232}, + {CREATURE_RANULF_VISUAL, SAY_SUMMON_RANULF, 381.546, -314.362, 104.756, 370.841, -314.426, 107.995, 6.232}, + {CREATURE_TORGYN_VISUAL, SAY_SUMMON_TORGYN, 404.310, -314.761, 104.756, 413.992, -314.703, 107.995, 3.157} +}; + +struct TRINITY_DLL_DECL boss_ymironAI : public ScriptedAI +{ + boss_ymironAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + srand(time(NULL)); + for (int i = 0; i < 4; ++i) + m_uiActiveOrder[i] = i; + for (int i = 0; i < 3; ++i) + { + int r = i + (rand()%(4-i)); + int temp = m_uiActiveOrder[i]; + m_uiActiveOrder[i] = m_uiActiveOrder[r]; + m_uiActiveOrder[r] = temp; + } + } + + bool m_bIsWalking; + bool m_bIsPause; + bool m_bIsActiveWithBJORN; + bool m_bIsActiveWithHALDOR; + bool m_bIsActiveWithRANULF; + bool m_bIsActiveWithTORGYN; + + uint8 m_uiActiveOrder[4]; + uint8 m_uiActivedNumber; + + uint32 m_uiFetidRot_Timer; + uint32 m_uiBane_Timer; + uint32 m_uiDarkSlash_Timer; + uint32 m_uiAncestors_Vengeance_Timer; + + uint32 m_uiAbility_BJORN_Timer; + uint32 m_uiAbility_HALDOR_Timer; + uint32 m_uiAbility_RANULF_Timer; + uint32 m_uiAbility_TORGYN_Timer; + + uint32 m_uiPause_Timer; + uint32 m_uiHealthAmountModifier; + uint32 m_uiHealthAmountMultipler; + + uint64 m_uiActivedCreatureGUID; + uint64 m_uiOrbGUID; + + ScriptedInstance *pInstance; + + void Reset() + { + m_bIsPause = false; + m_bIsActiveWithBJORN = false; + m_bIsActiveWithHALDOR = false; + m_bIsActiveWithRANULF = false; + m_bIsActiveWithTORGYN = false; + + m_uiFetidRot_Timer = urand(8000,13000); + m_uiBane_Timer = urand(18000,23000); + m_uiDarkSlash_Timer = urand(28000,33000); + m_uiAncestors_Vengeance_Timer = DUNGEON_MODE(60000,45000); + m_uiPause_Timer = 0; + + m_uiAbility_BJORN_Timer = 0; + m_uiAbility_HALDOR_Timer = 0; + m_uiAbility_RANULF_Timer = 0; + m_uiAbility_TORGYN_Timer = 0; + + m_uiActivedNumber = 0; + m_uiHealthAmountModifier = 1; + m_uiHealthAmountMultipler = DUNGEON_MODE(20,25); + + DespawnBoatGhosts(m_uiActivedCreatureGUID); + DespawnBoatGhosts(m_uiOrbGUID); + + if (pInstance) + pInstance->SetData(DATA_KING_YMIRON_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (pInstance) + pInstance->SetData(DATA_KING_YMIRON_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (m_bIsWalking) + { + if (m_uiPause_Timer <= diff) + { + DoScriptText(ActiveBot[m_uiActiveOrder[m_uiActivedNumber]].say, m_creature); + DoCast(m_creature, SPELL_CHANNEL_YMIRON_TO_SPIRIT); // should be on spirit + if (Creature* pTemp = m_creature->SummonCreature(ActiveBot[m_uiActiveOrder[m_uiActivedNumber]].npc, ActiveBot[m_uiActiveOrder[m_uiActivedNumber]].SpawnX, ActiveBot[m_uiActiveOrder[m_uiActivedNumber]].SpawnY, ActiveBot[m_uiActiveOrder[m_uiActivedNumber]].SpawnZ, ActiveBot[m_uiActiveOrder[m_uiActivedNumber]].SpawnO, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + m_uiActivedCreatureGUID = pTemp->GetGUID(); + pTemp->CastSpell(m_creature, SPELL_CHANNEL_SPIRIT_TO_YMIRON, true); + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pTemp->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + switch(m_uiActiveOrder[m_uiActivedNumber]) + { + case 0: m_bIsActiveWithBJORN = true; break; + case 1: m_bIsActiveWithHALDOR = true; break; + case 2: m_bIsActiveWithRANULF = true; break; + case 3: m_bIsActiveWithTORGYN = true; break; + } + } + + m_bIsPause = true; + m_bIsWalking = false; + m_uiPause_Timer = 3000; + } else m_uiPause_Timer -= diff; + return; + } + else if (m_bIsPause) + { + if (m_uiPause_Timer <= diff) + { + m_uiAbility_BJORN_Timer = 5000; + m_uiAbility_HALDOR_Timer = 5000; + m_uiAbility_RANULF_Timer = 5000; + m_uiAbility_TORGYN_Timer = 5000; + + m_bIsPause = false; + m_uiPause_Timer = 0; + } else m_uiPause_Timer -= diff; + return; + } + + //Return since we have no target + if (!UpdateVictim()) + return; + + if (!m_bIsPause) + { + // Normal spells ------------------------------------------------------------------------ + if (m_uiBane_Timer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_BANE, H_SPELL_BANE)); + m_uiBane_Timer = urand(20000,25000); + } else m_uiBane_Timer -= diff; + + if (m_uiFetidRot_Timer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_FETID_ROT, H_SPELL_FETID_ROT)); + m_uiFetidRot_Timer = urand(10000,15000); + } else m_uiFetidRot_Timer -= diff; + + if (m_uiDarkSlash_Timer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_DARK_SLASH); + m_uiDarkSlash_Timer = urand(30000,35000); + } else m_uiDarkSlash_Timer -= diff; + + if (m_uiAncestors_Vengeance_Timer <= diff) + { + DoCast(m_creature, SPELL_ANCESTORS_VENGEANCE); + m_uiAncestors_Vengeance_Timer = DUNGEON_MODE(urand(60000,65000),urand(45000,50000)); + } else m_uiAncestors_Vengeance_Timer -= diff; + + // Abilities ------------------------------------------------------------------------------ + if (m_bIsActiveWithBJORN && m_uiAbility_BJORN_Timer <= diff) + { + //DoCast(m_creature, SPELL_SUMMON_SPIRIT_FOUNT); // works fine, but using summon has better control + if (Creature* pTemp = m_creature->SummonCreature(CREATURE_SPIRIT_FOUNT, 385+rand()%10, -330+rand()%10, 104.756, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 180000)) + { + pTemp->SetSpeed(MOVE_RUN, 0.4f); + pTemp->CastSpell(pTemp, DUNGEON_MODE(SPELL_SPIRIT_FOUNT, H_SPELL_SPIRIT_FOUNT), true); + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pTemp->SetDisplayId(11686); + //pTemp->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiOrbGUID = pTemp->GetGUID(); + } + m_bIsActiveWithBJORN = false; // only one orb + } else m_uiAbility_BJORN_Timer -= diff; + + if (m_bIsActiveWithHALDOR && m_uiAbility_HALDOR_Timer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_SPIRIT_STRIKE, H_SPELL_SPIRIT_STRIKE)); + m_uiAbility_HALDOR_Timer = 5000; // overtime + } else m_uiAbility_HALDOR_Timer -= diff; + + if (m_bIsActiveWithRANULF && m_uiAbility_RANULF_Timer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_SPIRIT_BURST, H_SPELL_SPIRIT_BURST)); + m_uiAbility_RANULF_Timer = 10000; // overtime + } else m_uiAbility_RANULF_Timer -= diff; + + if (m_bIsActiveWithTORGYN && m_uiAbility_TORGYN_Timer <= diff) + { + float x,y,z; + x = m_creature->GetPositionX()-5; + y = m_creature->GetPositionY()-5; + z = m_creature->GetPositionZ(); + for (uint8 i = 0; i < 4; ++i) + { + //DoCast(m_creature, SPELL_SUMMON_AVENGING_SPIRIT); // works fine, but using summon has better control + if (Creature* pTemp = m_creature->SummonCreature(CREATURE_AVENGING_SPIRIT, x+rand()%10, y+rand()%10, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + pTemp->AddThreat(pTarget, 0.0f); + pTemp->AI()->AttackStart(pTarget); + } + } + } + m_uiAbility_TORGYN_Timer = 15000; // overtime + } else m_uiAbility_TORGYN_Timer -= diff; + + // Health check ----------------------------------------------------------------------------- + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < (100-(m_uiHealthAmountMultipler * m_uiHealthAmountModifier))) + { + uint8 m_uiOrder = m_uiHealthAmountModifier - 1; + ++m_uiHealthAmountModifier; + + m_creature->InterruptNonMeleeSpells(true); + DoCast(m_creature, SPELL_SCREAMS_OF_THE_DEAD); + m_creature->GetMotionMaster()->Clear(); + m_creature->StopMoving(); + m_creature->AttackStop(); + m_creature->GetMotionMaster()->MovePoint(0, ActiveBot[m_uiActiveOrder[m_uiOrder]].MoveX, ActiveBot[m_uiActiveOrder[m_uiOrder]].MoveY, ActiveBot[m_uiActiveOrder[m_uiOrder]].MoveZ); + + DespawnBoatGhosts(m_uiActivedCreatureGUID); + DespawnBoatGhosts(m_uiOrbGUID); + + m_bIsActiveWithBJORN = false; + m_bIsActiveWithHALDOR = false; + m_bIsActiveWithRANULF = false; + m_bIsActiveWithTORGYN = false; + + m_uiBane_Timer += 8000; + m_uiFetidRot_Timer += 8000; + m_uiDarkSlash_Timer += 8000; + m_uiAncestors_Vengeance_Timer += 8000; + + m_uiActivedNumber = m_uiOrder; + m_bIsWalking = true; + m_uiPause_Timer = 2000; + return; + } + DoMeleeAttackIfReady(); + } + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + DespawnBoatGhosts(m_uiActivedCreatureGUID); + DespawnBoatGhosts(m_uiOrbGUID); + + if (pInstance) + pInstance->SetData(DATA_KING_YMIRON_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3,SAY_SLAY_4), m_creature); + } + + void DespawnBoatGhosts(uint64& m_uiCreatureGUID) + { + if (m_uiCreatureGUID) + if (Creature* pTemp = (Creature*)Unit::GetUnit(*m_creature, m_uiCreatureGUID)) + pTemp->DisappearAndDie(); + + m_uiCreatureGUID = 0; + } +}; + +CreatureAI* GetAI_boss_ymiron(Creature* pCreature) +{ + return new boss_ymironAI(pCreature); +} + +void AddSC_boss_ymiron() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_ymiron"; + newscript->GetAI = &GetAI_boss_ymiron; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_pinnacle.cpp b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_pinnacle.cpp new file mode 100644 index 00000000000..5c4a53156d2 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_pinnacle.cpp @@ -0,0 +1,213 @@ +#include "ScriptedPch.h" +#include "utgarde_pinnacle.h" + +#define MAX_ENCOUNTER 4 + +/* Utgarde Pinnacle encounters: +0 - Svala Sorrowgrave +1 - Gortok Palehoof +2 - Skadi the Ruthless +3 - King Ymiron +*/ + +#define ENTRY_SKADI_THE_RUTHLESS_DOOR 192173 +#define ENTRY_KING_YMIRON_DOOR 192174 +#define ENTRY_GORK_PALEHOOF_SPHERE 188593 + +struct TRINITY_DLL_DECL instance_pinnacle : public ScriptedInstance +{ + instance_pinnacle(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint64 uiSvalaSorrowgrave; + uint64 uiGortokPalehoof; + uint64 uiSkadiTheRuthless; + uint64 uiKingYmiron; + + uint64 uiSkadiTheRuthlessDoor; + uint64 uiKingYmironDoor; + uint64 uiGortokPalehoofSphere; + + uint64 uiFrenziedWorgen; + uint64 uiRavenousFurbolg; + uint64 uiFerociousRhino; + uint64 uiMassiveJormungar; + uint64 uiPalehoofOrb; + + uint64 uiSvala; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + std::string str_data; + + void Initialize() + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + m_auiEncounter[i] = NOT_STARTED; + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case 26668: uiSvalaSorrowgrave = pCreature->GetGUID(); break; + case 26687: uiGortokPalehoof = pCreature->GetGUID(); break; + case 26693: uiSkadiTheRuthless = pCreature->GetGUID(); break; + case 26861: uiKingYmiron = pCreature->GetGUID(); break; + case 26683: uiFrenziedWorgen = pCreature->GetGUID(); break; + case 26684: uiRavenousFurbolg = pCreature->GetGUID(); break; + case 26685: uiMassiveJormungar = pCreature->GetGUID(); break; + case 26686: uiFerociousRhino = pCreature->GetGUID(); break; + case 29281: uiSvala = pCreature->GetGUID(); break; + case 26688: uiPalehoofOrb = pCreature->GetGUID(); break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case ENTRY_SKADI_THE_RUTHLESS_DOOR: + uiSkadiTheRuthlessDoor = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE) HandleGameObject(NULL,true,pGo); + break; + case ENTRY_KING_YMIRON_DOOR: + uiKingYmironDoor = pGo->GetGUID(); + if (m_auiEncounter[3] == DONE) HandleGameObject(NULL,true,pGo); + break; + case ENTRY_GORK_PALEHOOF_SPHERE: + uiGortokPalehoofSphere = pGo->GetGUID(); + if (m_auiEncounter[1] == DONE) + { + HandleGameObject(NULL,true,pGo); + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + } + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_SVALA_SORROWGRAVE_EVENT: + m_auiEncounter[0] = data; + break; + case DATA_GORTOK_PALEHOOF_EVENT: + m_auiEncounter[1] = data; + break; + case DATA_SKADI_THE_RUTHLESS_EVENT: + if (data == DONE) + HandleGameObject(uiSkadiTheRuthlessDoor,true); + m_auiEncounter[2] = data; + break; + case DATA_KING_YMIRON_EVENT: + if (data == DONE) + HandleGameObject(uiKingYmironDoor,true); + m_auiEncounter[3] = data; + break; + } + + if (data == DONE) + SaveToDB(); + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_SVALA_SORROWGRAVE_EVENT: return m_auiEncounter[0]; + case DATA_GORTOK_PALEHOOF_EVENT: return m_auiEncounter[1]; + case DATA_SKADI_THE_RUTHLESS_EVENT: return m_auiEncounter[2]; + case DATA_KING_YMIRON_EVENT: return m_auiEncounter[3]; + } + return 0; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_SVALA_SORROWGRAVE: return uiSvalaSorrowgrave; + case DATA_GORTOK_PALEHOOF: return uiGortokPalehoof; + case DATA_SKADI_THE_RUTHLESS: return uiSkadiTheRuthless; + case DATA_KING_YMIRON: return uiKingYmiron; + case DATA_MOB_FRENZIED_WORGEN: return uiFrenziedWorgen; + case DATA_MOB_RAVENOUS_FURBOLG: return uiRavenousFurbolg; + case DATA_MOB_MASSIVE_JORMUNGAR: return uiMassiveJormungar; + case DATA_MOB_FEROCIOUS_RHINO: return uiFerociousRhino; + case DATA_MOB_ORB: return uiPalehoofOrb; + case DATA_SVALA: return uiSvala; + case DATA_GORTOK_PALEHOOF_SPHERE: return uiGortokPalehoofSphere; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "U P " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3; + + if (dataHead1 == 'U' && dataHead2 == 'K') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + m_auiEncounter[3] = data3; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_utgarde_pinnacle(Map* pMap) +{ + return new instance_pinnacle(pMap); +} + +void AddSC_instance_utgarde_pinnacle() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_utgarde_pinnacle"; + newscript->GetInstanceData = &GetInstanceData_instance_utgarde_pinnacle; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h new file mode 100644 index 00000000000..550e9c28694 --- /dev/null +++ b/src/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h @@ -0,0 +1,26 @@ +#ifndef DEF_PINNACLE_H +#define DEF_PINNACLE_H + +enum Data +{ + DATA_SVALA_SORROWGRAVE_EVENT, + DATA_GORTOK_PALEHOOF_EVENT, + DATA_SKADI_THE_RUTHLESS_EVENT, + DATA_KING_YMIRON_EVENT +}; +enum Data64 +{ + DATA_SVALA, + DATA_SVALA_SORROWGRAVE, + DATA_GORTOK_PALEHOOF, + DATA_SKADI_THE_RUTHLESS, + DATA_KING_YMIRON, + DATA_MOB_FRENZIED_WORGEN, + DATA_MOB_RAVENOUS_FURBOLG, + DATA_MOB_MASSIVE_JORMUNGAR, + DATA_MOB_FEROCIOUS_RHINO, + DATA_MOB_ORB, + DATA_GORTOK_PALEHOOF_SPHERE +}; + +#endif diff --git a/src/scripts/northrend/vault_of_archavon/boss_archavon.cpp b/src/scripts/northrend/vault_of_archavon/boss_archavon.cpp new file mode 100644 index 00000000000..08817affdfb --- /dev/null +++ b/src/scripts/northrend/vault_of_archavon/boss_archavon.cpp @@ -0,0 +1,199 @@ +/*** SQL START *** +UPDATE `creature_template` SET `ScriptName`='boss_archavon' WHERE `entry`='31125'; +UPDATE `creature_template` SET `ScriptName`='mob_archavon_warder' WHERE `entry`='32353'; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "vault_of_archavon.h" + +#define EMOTE_BERSERK -1590002 + +//Spells Archavon +#define SPELL_ROCK_SHARDS 58678 +#define SPELL_CRUSHING_LEAP RAID_MODE(58960,60894)//Instant (10-80yr range) -- Leaps at an enemy, inflicting 8000 Physical damage, knocking all nearby enemies away, and creating a cloud of choking debris. +#define SPELL_STOMP RAID_MODE(58663,60880) +#define SPELL_IMPALE RAID_MODE(58666,60882) //Lifts an enemy off the ground with a spiked fist, inflicting 47125 to 52875 Physical damage and 9425 to 10575 additional damage each second for 8 sec. +#define SPELL_BERSERK 47008 +//Spells Archavon Warders +#define SPELL_ROCK_SHOWER RAID_MODE(60919,60923) +#define SPELL_SHIELD_CRUSH RAID_MODE(60897,60899) +#define SPELL_WHIRL RAID_MODE(60902,60916) + +//4 Warders spawned +#define ARCHAVON_WARDER 32353 //npc 32353 + +//Yell +#define SAY_LEAP "Archavon the Stone Watcher lunges for $N!" //$N should be the target + +#define EVENT_ROCK_SHARDS 1 //15s cd +#define EVENT_CHOKING_CLOUD 2 //30s cd +#define EVENT_STOMP 3 //45s cd +#define EVENT_IMPALE 4 +#define EVENT_BERSERK 5 //300s cd + +//mob +#define EVENT_ROCK_SHOWER 5 //set = 20s cd,unkown cd +#define EVENT_SHIELD_CRUSH 6 //set = 30s cd +#define EVENT_WHIRL 8 //set= 10s cd + +struct TRINITY_DLL_DECL boss_archavonAI : public ScriptedAI +{ + boss_archavonAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + EventMap events; + + void Reset() + { + events.Reset(); + + if (pInstance) + pInstance->SetData(DATA_ARCHAVON_EVENT, NOT_STARTED); + } + + void KilledUnit(Unit* Victim){} + + void JustDied(Unit* Killer) + { + if (pInstance) + pInstance->SetData(DATA_ARCHAVON_EVENT, DONE); + } + + void EnterCombat(Unit *who) + { + DoZoneInCombat(); + events.ScheduleEvent(EVENT_ROCK_SHARDS, 15000); + events.ScheduleEvent(EVENT_CHOKING_CLOUD, 30000); + events.ScheduleEvent(EVENT_STOMP, 45000); + events.ScheduleEvent(EVENT_BERSERK, 300000); + + if (pInstance) + pInstance->SetData(DATA_ARCHAVON_EVENT, IN_PROGRESS); + } + + // Below UpdateAI may need review/debug. + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_ROCK_SHARDS: + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_ROCK_SHARDS); + events.ScheduleEvent(EVENT_ROCK_SHARDS, 15000); + return; + case EVENT_CHOKING_CLOUD: + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_CRUSHING_LEAP, true); //10y~80y, ignore range + events.ScheduleEvent(EVENT_CHOKING_CLOUD, 30000); + return; + case EVENT_STOMP: + DoCast(me->getVictim(), SPELL_STOMP); + events.ScheduleEvent(EVENT_IMPALE, 3000); + events.ScheduleEvent(EVENT_STOMP, 45000); + return; + case EVENT_IMPALE: + DoCast(me->getVictim(), SPELL_IMPALE); + return; + case EVENT_BERSERK: + DoCast(m_creature, SPELL_BERSERK); + DoScriptText(EMOTE_BERSERK, m_creature); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## Mob Archavon Warder +######*/ +struct TRINITY_DLL_DECL mob_warderAI : public ScriptedAI //npc 32353 +{ + mob_warderAI(Creature *c) : ScriptedAI(c) {} + + EventMap events; + + void Reset() + { + events.Reset(); + } + + void EnterCombat(Unit *who) + { + DoZoneInCombat(); + events.ScheduleEvent(EVENT_ROCK_SHOWER, 2000); + events.ScheduleEvent(EVENT_SHIELD_CRUSH, 20000); + events.ScheduleEvent(EVENT_WHIRL, 7500); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + events.Update(diff); + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_ROCK_SHOWER: + { + if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_ROCK_SHOWER); + events.ScheduleEvent(EVENT_ROCK_SHARDS, 6000); + return; + } + case EVENT_SHIELD_CRUSH: + DoCast(m_creature->getVictim(), SPELL_SHIELD_CRUSH); + events.ScheduleEvent(EVENT_SHIELD_CRUSH, 20000); + return; + case EVENT_WHIRL: + DoCast(m_creature->getVictim(), SPELL_WHIRL); + events.ScheduleEvent(EVENT_WHIRL, 8000); + return; + } + } + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_warder(Creature* pCreature) +{ + return new mob_warderAI (pCreature); +} + +CreatureAI* GetAI_boss_archavon(Creature* pCreature) +{ + return new boss_archavonAI (pCreature); +} + +void AddSC_boss_archavon() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_archavon"; + newscript->GetAI = &GetAI_boss_archavon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_archavon_warder"; + newscript->GetAI = &GetAI_mob_warder; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/vault_of_archavon/boss_emalon.cpp b/src/scripts/northrend/vault_of_archavon/boss_emalon.cpp new file mode 100644 index 00000000000..f7f4a085c06 --- /dev/null +++ b/src/scripts/northrend/vault_of_archavon/boss_emalon.cpp @@ -0,0 +1,287 @@ +#include "ScriptedPch.h" +#include "vault_of_archavon.h" + +//Emalon spells +#define SPELL_CHAIN_LIGHTNING RAID_MODE(64213, 64215) +#define SPELL_LIGHTNING_NOVA RAID_MODE(64216, 65279) +#define SPELL_OVERCHARGE 64218 //Casted every 45 sec on a random Tempest Minion +#define SPELL_BERSERK 26662 + +//Tempest Minion spells +#define SPELL_SHOCK 64363 +#define SPELL_OVERCHARGED 64217 +#define SPELL_OVERCHARGED_BLAST 64219 //Casted when Overcharged reaches 10 stacks. Mob dies after that + +//Emotes +#define EMOTE_OVERCHARGE -1590000 +#define EMOTE_MINION_RESPAWN -1590001 +#define EMOTE_BERSERK -1590002 + +//Events +#define EVENT_CHAIN_LIGHTNING 1 +#define EVENT_LIGHTNING_NOVA 2 +#define EVENT_OVERCHARGE 3 +#define EVENT_BERSERK 4 +#define EVENT_SHOCK 5 + +//Creatures +#define MOB_TEMPEST_MINION 33998 + +#define MAX_TEMPEST_MINIONS 4 + +float TempestMinions[4][4] = +{ + {-203.980103, -281.287720, 91.650223, 1.598807}, + {-233.489410, -281.139282, 91.652412, 1.598807}, + {-233.267578, -297.104645, 91.681915, 1.598807}, + {-203.842529, -297.097015, 91.745163, 1.598807} +}; + +/*###### +## Emalon the Storm Watcher +######*/ +struct TRINITY_DLL_DECL boss_emalonAI : public ScriptedAI +{ + boss_emalonAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + EventMap events; + + std::list<uint64> MinionList; + + void Reset() + { + events.Reset(); + + DespawnAllMinions(); + + for (uint8 i = 0; i < MAX_TEMPEST_MINIONS; ++i) + m_creature->SummonCreature(MOB_TEMPEST_MINION, TempestMinions[i][0], TempestMinions[i][1], TempestMinions[i][2], TempestMinions[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); + + if (pInstance) + pInstance->SetData(DATA_EMALON_EVENT, NOT_STARTED); + } + + void DespawnAllMinions() + { + if(!MinionList.empty()) + { + for (std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); itr++) + { + Creature *Minion = Unit::GetCreature(*m_creature, *itr); + if(Minion && Minion->isAlive()) + Minion->ForcedDespawn(); + } + } + MinionList.clear(); + } + + void JustSummoned(Creature *summoned) + { + MinionList.push_back(summoned->GetGUID()); + + if(m_creature->getVictim()) + summoned->AI()->AttackStart(m_creature->getVictim()); + } + + void JustDied(Unit* Killer) + { + DespawnAllMinions(); + + if (pInstance) + pInstance->SetData(DATA_EMALON_EVENT, DONE); + } + + void EnterCombat(Unit *who) + { + if(!MinionList.empty()) + { + for (std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) + { + Creature *Minion = Unit::GetCreature(*m_creature, *itr); + if(Minion && Minion->isAlive() && !Minion->getVictim()) + Minion->AI()->AttackStart(who); + } + } + + DoZoneInCombat(); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 5000); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 40000); + events.ScheduleEvent(EVENT_BERSERK, 360000); + events.ScheduleEvent(EVENT_OVERCHARGE, 45000); + + if (pInstance) + pInstance->SetData(DATA_EMALON_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if(!UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_CHAIN_LIGHTNING: + if(Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_CHAIN_LIGHTNING); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 25000); + return; + case EVENT_LIGHTNING_NOVA: + DoCastAOE(SPELL_LIGHTNING_NOVA, false); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 40000); + return; + case EVENT_OVERCHARGE: + if(!MinionList.empty()) + { + std::list<uint64>::const_iterator itr = MinionList.begin(); + std::advance(itr, rand() % MinionList.size()); + Creature *Minion = Unit::GetCreature(*m_creature, *itr); + if(Minion && Minion->isAlive()) + { + Minion->CastSpell(me, SPELL_OVERCHARGED, true); + Minion->SetHealth(Minion->GetMaxHealth()); + DoScriptText(EMOTE_OVERCHARGE, m_creature); + events.ScheduleEvent(EVENT_OVERCHARGE, 45000); + } + } + return; + case EVENT_BERSERK: + DoCast(m_creature, SPELL_BERSERK); + DoScriptText(EMOTE_BERSERK, m_creature); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## Tempest Minion +######*/ +struct TRINITY_DLL_DECL mob_tempest_minionAI : public ScriptedAI +{ + mob_tempest_minionAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + EmalonGUID = pInstance ? pInstance->GetData64(DATA_EMALON) : 0; + Emalon = Unit::GetCreature(*m_creature, EmalonGUID); + } + + ScriptedInstance* pInstance; + + EventMap events; + + uint64 EmalonGUID; + Creature* Emalon; + + uint32 OverchargedTimer; + + void Reset() + { + events.Reset(); + + OverchargedTimer = 0; + } + + void JustDied(Unit* Killer) + { + if(Emalon && Emalon->isAlive()) + { + Emalon->SummonCreature(MOB_TEMPEST_MINION, Emalon->GetPositionX(), Emalon->GetPositionY(), Emalon->GetPositionZ(), Emalon->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0); + DoScriptText(EMOTE_MINION_RESPAWN, m_creature); + } + } + + void EnterCombat(Unit *who) + { + DoZoneInCombat(); + events.ScheduleEvent(EVENT_SHOCK, 20000); + + if(Emalon && !Emalon->getVictim()) + Emalon->AI()->AttackStart(who); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if(!UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(Aura * OverchargedAura = m_creature->GetAura(SPELL_OVERCHARGED)) + { + if(OverchargedAura->GetStackAmount() < 10) + { + if (OverchargedTimer <= diff) + { + DoCast(me, SPELL_OVERCHARGED); + OverchargedTimer = 2000; + } else OverchargedTimer -=diff; + } + else + { + if(OverchargedAura->GetStackAmount() == 10) + { + DoCast(me, SPELL_OVERCHARGED_BLAST); + m_creature->ForcedDespawn(); + DoScriptText(EMOTE_MINION_RESPAWN, m_creature); + } + } + } + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_SHOCK: + DoCast(me->getVictim(), SPELL_SHOCK); + events.ScheduleEvent(EVENT_SHOCK, 20000); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_tempest_minion(Creature *_Creature) +{ + return new mob_tempest_minionAI (_Creature); +} + +CreatureAI* GetAI_boss_emalon(Creature *_Creature) +{ + return new boss_emalonAI (_Creature); +} + +void AddSC_boss_emalon() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_emalon"; + newscript->GetAI = &GetAI_boss_emalon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_tempest_minion"; + newscript->GetAI = &GetAI_mob_tempest_minion; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp b/src/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp new file mode 100644 index 00000000000..d1f0f280edb --- /dev/null +++ b/src/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp @@ -0,0 +1,124 @@ +#include "ScriptedPch.h" +#include "vault_of_archavon.h" + +#define ENCOUNTERS 2 + +/* Vault of Archavon encounters: +1 - Archavon the Stone Watcher event +2 - Emalon the Storm Watcher event +*/ + +struct TRINITY_DLL_DECL instance_archavon : public ScriptedInstance +{ + instance_archavon(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounters[ENCOUNTERS]; + + uint64 Archavon; + uint64 Emalon; + + void Initialize() + { + Archavon = 0; + Emalon = 0; + + for (uint8 i = 0; i < ENCOUNTERS; i++) + Encounters[i] = NOT_STARTED; + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounters[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, bool add) + { + switch(creature->GetEntry()) + { + case 31125: Archavon = creature->GetGUID(); break; + case 33993: Emalon = creature->GetGUID(); break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_ARCHAVON_EVENT: return Encounters[0]; + case DATA_EMALON_EVENT: return Encounters[1]; + } + return 0; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_ARCHAVON: return Archavon; + case DATA_EMALON: return Emalon; + } + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_ARCHAVON_EVENT: Encounters[0] = data; break; + case DATA_EMALON_EVENT: Encounters[1] = data; break; + } + + if(data == DONE) + SaveToDB(); + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + std::ostringstream stream; + stream << Encounters[0] << " " << Encounters[1]; + char* out = new char[stream.str().length() + 1]; + strcpy(out, stream.str().c_str()); + if(out) + { + OUT_SAVE_INST_DATA_COMPLETE; + return out; + } + + return NULL; + } + + void Load(const char* in) + { + if(!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(in); + std::istringstream stream(in); + stream >> Encounters[0] >> Encounters[1]; + for (uint8 i = 0; i < ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) + Encounters[i] = NOT_STARTED; + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_archavon(Map* map) +{ + return new instance_archavon(map); +} + +void AddSC_instance_archavon() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_archavon"; + newscript->GetInstanceData = &GetInstanceData_instance_archavon; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/vault_of_archavon/vault_of_archavon.h b/src/scripts/northrend/vault_of_archavon/vault_of_archavon.h new file mode 100644 index 00000000000..95c44035184 --- /dev/null +++ b/src/scripts/northrend/vault_of_archavon/vault_of_archavon.h @@ -0,0 +1,8 @@ +#ifndef DEF_ARCHAVON_H +#define DEF_ARCHAVON_H + +#define DATA_ARCHAVON_EVENT 1 +#define DATA_EMALON_EVENT 2 +#define DATA_EMALON 3 +#define DATA_ARCHAVON 4 +#endif diff --git a/src/scripts/northrend/violet_hold/boss_cyanigosa.cpp b/src/scripts/northrend/violet_hold/boss_cyanigosa.cpp new file mode 100644 index 00000000000..770c38ddaca --- /dev/null +++ b/src/scripts/northrend/violet_hold/boss_cyanigosa.cpp @@ -0,0 +1,156 @@ +/* Script Data Start +SDName: Boss cyanigosa +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "violet_hold.h" + +enum Spells +{ + SPELL_ARCANE_VACUUM = 58694, + SPELL_BLIZZARD = 58693, + H_SPELL_BLIZZARD = 59369, + SPELL_MANA_DESTRUCTION = 59374, + SPELL_TAIL_SWEEP = 58690, + H_SPELL_TAIL_SWEEP = 59283, + SPELL_UNCONTROLLABLE_ENERGY = 58688, + H_SPELL_UNCONTROLLABLE_ENERGY = 59281, + SPELL_TRANSFORM = 58668 +}; + +enum Yells +{ + SAY_AGGRO = -1608000, + SAY_SLAY_1 = -1608001, + SAY_SLAY_2 = -1608002, + SAY_SLAY_3 = -1608003, + SAY_DEATH = -1608004, + SAY_SPAWN = -1608005, + SAY_DISRUPTION = -1608006, + SAY_BREATH_ATTACK = -1608007, + SAY_SPECIAL_ATTACK_1 = -1608008, + SAY_SPECIAL_ATTACK_2 = -1608009 +}; + +struct TRINITY_DLL_DECL boss_cyanigosaAI : public ScriptedAI +{ + boss_cyanigosaAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiArcaneVacuumTimer; + uint32 uiBlizzardTimer; + uint32 uiManaDestructionTimer; + uint32 uiTailSweepTimer; + uint32 uiUncontrollableEnergyTimer; + + ScriptedInstance* pInstance; + + void Reset() + { + uiArcaneVacuumTimer = 10000; + uiBlizzardTimer = 15000; + uiManaDestructionTimer = 30000; + uiTailSweepTimer = 20000; + uiUncontrollableEnergyTimer = 25000; + if (pInstance) + pInstance->SetData(DATA_CYANIGOSA_EVENT, NOT_STARTED); + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + DoCast(m_creature, SPELL_TRANSFORM); + + if (pInstance) + pInstance->SetData(DATA_CYANIGOSA_EVENT, IN_PROGRESS); + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (pInstance && pInstance->GetData(DATA_REMOVE_NPC) == 1) + { + m_creature->ForcedDespawn(); + pInstance->SetData(DATA_REMOVE_NPC, 0); + } + + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiArcaneVacuumTimer <= diff) + { + DoCast(SPELL_ARCANE_VACUUM); + uiArcaneVacuumTimer = 10000; + } else uiArcaneVacuumTimer -= diff; + + if (uiBlizzardTimer <= diff) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, DUNGEON_MODE(SPELL_BLIZZARD, H_SPELL_BLIZZARD)); + uiBlizzardTimer = 15000; + } else uiBlizzardTimer -= diff; + + if (uiTailSweepTimer <= diff) + { + DoCast(DUNGEON_MODE(SPELL_TAIL_SWEEP, H_SPELL_TAIL_SWEEP)); + uiTailSweepTimer = 20000; + } else uiTailSweepTimer -= diff; + + if (uiUncontrollableEnergyTimer <= diff) + { + DoCastVictim(DUNGEON_MODE(SPELL_UNCONTROLLABLE_ENERGY,H_SPELL_UNCONTROLLABLE_ENERGY)); + uiUncontrollableEnergyTimer = 25000; + } else uiUncontrollableEnergyTimer -= diff; + + if (IsHeroic()) + if (uiManaDestructionTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_MANA_DESTRUCTION); + uiManaDestructionTimer = 30000; + } else uiManaDestructionTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + pInstance->SetData(DATA_CYANIGOSA_EVENT, DONE); + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_cyanigosa(Creature* pCreature) +{ + return new boss_cyanigosaAI (pCreature); +} + +void AddSC_boss_cyanigosa() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_cyanigosa"; + newscript->GetAI = &GetAI_boss_cyanigosa; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/boss_erekem.cpp b/src/scripts/northrend/violet_hold/boss_erekem.cpp new file mode 100644 index 00000000000..5f99c7ef6ec --- /dev/null +++ b/src/scripts/northrend/violet_hold/boss_erekem.cpp @@ -0,0 +1,291 @@ +/* Script Data Start +SDName: Boss erekem +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "violet_hold.h" + +enum Spells +{ + SPELL_BLOODLUST = 54516, + SPELL_BREAK_BONDS = 59463, + SPELL_CHAIN_HEAL = 54481, + H_SPELL_CHAIN_HEAL = 59473, + SPELL_EARTH_SHIELD = 54479, + H_SPELL_EARTH_SHIELD = 59471, + SPELL_EARTH_SHOCK = 54511, + SPELL_LIGHTNING_BOLT = 53044, + SPELL_STORMSTRIKE = 51876 +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1608010, + SAY_SLAY_1 = -1608011, + SAY_SLAY_2 = -1608012, + SAY_SLAY_3 = -1608013, + SAY_DEATH = -1608014, + SAY_SPAWN = -1608015, + SAY_ADD_KILLED = -1608016, + SAY_BOTH_ADDS_KILLED = -1608017 +}; + +struct TRINITY_DLL_DECL boss_erekemAI : public ScriptedAI +{ + boss_erekemAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiBloodlustTimer; + uint32 uiChainHealTimer; + uint32 uiEarthShockTimer; + uint32 uiLightningBoltTimer; + uint32 uiEarthShieldTimer; + + Creature* pGuard1; + Creature* pGuard2; + + ScriptedInstance* pInstance; + + void Reset() + { + uiBloodlustTimer = 15000; + uiChainHealTimer = 0; + uiEarthShockTimer = urand(2000,8000); + uiLightningBoltTimer = urand(5000,10000); + uiEarthShieldTimer = 20000; + if (pInstance) + { + pGuard1 = pInstance->instance->GetCreature(pInstance->GetData(DATA_EREKEM_GUARD_1)); + pGuard2 = pInstance->instance->GetCreature(pInstance->GetData(DATA_EREKEM_GUARD_2)); + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + } + } + + void AttackStart(Unit* pWho) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + DoCast(m_creature, DUNGEON_MODE(SPELL_EARTH_SHIELD, H_SPELL_EARTH_SHIELD)); + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + } + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + //spam stormstrike in hc mode if spawns are dead + if (IsHeroic()) + { + if (pGuard1 && !pGuard1->isAlive() && pGuard2 && !pGuard2->isAlive()) + { + DoCast(m_creature->getVictim(), SPELL_STORMSTRIKE); + } + } + + if (uiEarthShieldTimer <= diff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_EARTH_SHIELD, H_SPELL_EARTH_SHIELD)); + uiEarthShieldTimer = 20000; + } else uiEarthShieldTimer -= diff; + + if (uiChainHealTimer <= diff) + { + if (Creature *pTarget = GetChainHealTarget()) + { + DoCast(pTarget, DUNGEON_MODE(SPELL_CHAIN_HEAL, H_SPELL_CHAIN_HEAL)); + //If one of the adds is dead spawn heals faster + uiChainHealTimer = ((pGuard1 && !pGuard1->isAlive()) || (pGuard2 && !pGuard2->isAlive()) ? 3000 : 8000) + rand()%3000; + } + } else uiChainHealTimer -= diff; + + if (uiBloodlustTimer <= diff) + { + DoCast(m_creature, SPELL_BLOODLUST); + uiBloodlustTimer = urand(35000,45000); + } else uiBloodlustTimer -= diff; + + if (uiEarthShockTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_EARTH_SHOCK); + uiEarthShockTimer = urand(8000,13000); + } else uiEarthShockTimer -= diff; + + if (uiLightningBoltTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_LIGHTNING_BOLT); + uiLightningBoltTimer = urand(18000,24000); + } else uiLightningBoltTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + { + pInstance->SetData(DATA_1ST_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 7); + } + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + { + pInstance->SetData(DATA_2ND_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 13); + } + } + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + Creature* GetChainHealTarget() + { + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 85) + return m_creature; + if (pGuard1 && pGuard1->isAlive() && (pGuard1->GetHealth()*100 / pGuard1->GetMaxHealth() <= 75)) + return pGuard1; + if (pGuard2 && pGuard2->isAlive() && (pGuard2->GetHealth()*100 / pGuard2->GetMaxHealth() <= 75)) + return pGuard2; + return NULL; + } +}; + +CreatureAI* GetAI_boss_erekem(Creature* pCreature) +{ + return new boss_erekemAI (pCreature); +} + +enum GuardSpells +{ + SPELL_GUSHING_WOUND = 39215, + SPELL_HOWLING_SCREECH = 54462, + SPELL_STRIKE = 14516 +}; + +struct TRINITY_DLL_DECL mob_erekem_guardAI : public ScriptedAI +{ + mob_erekem_guardAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiGushingWoundTimer; + uint32 uiHowlingScreechTimer; + uint32 uiStrikeTimer; + + ScriptedInstance* pInstance; + + void Reset() + { + uiStrikeTimer = urand(4000,8000); + uiHowlingScreechTimer = urand(8000,13000); + uiGushingWoundTimer = urand(1000,3000); + } + + void AttackStart(Unit* pWho) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + + if (uiStrikeTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_STRIKE); + uiStrikeTimer = urand(4000,8000); + } else uiStrikeTimer -= diff; + + if (uiHowlingScreechTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_HOWLING_SCREECH); + uiHowlingScreechTimer = urand(8000,13000); + } else uiHowlingScreechTimer -= diff; + + if (uiGushingWoundTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_GUSHING_WOUND); + uiGushingWoundTimer = urand(7000,12000); + } else uiGushingWoundTimer -= diff; + } +}; + +CreatureAI* GetAI_mob_erekem_guard(Creature* pCreature) +{ + return new mob_erekem_guardAI (pCreature); +} + +void AddSC_boss_erekem() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_erekem"; + newscript->GetAI = &GetAI_boss_erekem; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_erekem_guard"; + newscript->GetAI = &GetAI_mob_erekem_guard; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/boss_ichoron.cpp b/src/scripts/northrend/violet_hold/boss_ichoron.cpp new file mode 100644 index 00000000000..78cac6b455c --- /dev/null +++ b/src/scripts/northrend/violet_hold/boss_ichoron.cpp @@ -0,0 +1,354 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: Boss ichoron +SDAuthor: ckegg +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +#include "ScriptedPch.h" +#include "violet_hold.h" + +enum Spells +{ + SPELL_DRAINED = 59820, + SPELL_FRENZY = 54312, + SPELL_FRENZY_H = 59522, + SPELL_PROTECTIVE_BUBBLE = 54306, + SPELL_WATER_BLAST = 54237, + SPELL_WATER_BLAST_H = 59520, + SPELL_WATER_BOLT_VOLLEY = 54241, + SPELL_WATER_BOLT_VOLLEY_H = 59521, + SPELL_SPLASH = 59516, +}; + +enum IchoronCreatures +{ + NPC_ICHOR_GLOBULE = 29321, +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1608018, + SAY_SLAY_1 = -1608019, + SAY_SLAY_2 = -1608020, + SAY_SLAY_3 = -1608021, + SAY_DEATH = -1608022, + SAY_SPAWN = -1608023, + SAY_ENRAGE = -1608024, + SAY_SHATTER = -1608025, + SAY_BUBBLE = -1608026 +}; + +struct Locations +{ + float x, y, z; + uint32 id; +}; + +static Locations PortalLoc[]= +{ + {1857.125, 763.295, 38.654}, + {1925.480, 849.981, 47.174}, + {1892.737, 744.589, 47.666}, + {1878.198, 850.005, 43.333}, + {1909.381, 806.796, 38.645}, + {1936.101, 802.950, 52.417}, +}; + +struct TRINITY_DLL_DECL boss_ichoronAI : public ScriptedAI +{ + boss_ichoronAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + bool bIsExploded; + bool bIsFrenzy; + + uint32 uiBuubleChecker_Timer; + uint32 uiWaterBoltVolley_Timer; + uint32 uiShowup_Counter; + + ScriptedInstance* pInstance; + + std::list<uint64> m_lWaterElementsGUIDList; + + void Reset() + { + bIsExploded = false; + bIsFrenzy = false; + uiBuubleChecker_Timer = 1000; + uiWaterBoltVolley_Timer = urand(10000, 15000); + uiShowup_Counter = 0; + + m_creature->SetVisibility(VISIBILITY_ON); + DespawnWaterElements(); + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + } + } + + void EnterCombat(Unit* pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + + DoCast(m_creature, SPELL_PROTECTIVE_BUBBLE); + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + } + } + + void AttackStart(Unit* pWho) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void WaterElementHit() + { + m_creature->SetHealth(m_creature->GetHealth() + m_creature->GetMaxHealth() * 0.01); + if (bIsExploded) + { + DoCast(m_creature, SPELL_PROTECTIVE_BUBBLE); + bIsExploded = false; + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + + void DespawnWaterElements() + { + if (m_lWaterElementsGUIDList.empty()) + return; + + for(std::list<uint64>::iterator itr = m_lWaterElementsGUIDList.begin(); itr != m_lWaterElementsGUIDList.end(); ++itr) + { + if (Creature* pTemp = (Creature*)Unit::GetUnit(*m_creature, *itr)) + { + if (pTemp->isAlive()) + pTemp->Kill(pTemp, false); + } + } + m_lWaterElementsGUIDList.clear(); + } + + void MoveInLineOfSight(Unit* pWho) {} + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (!bIsFrenzy) + { + if (uiBuubleChecker_Timer < uiDiff) + { + if (!bIsExploded) + { + if (!m_creature->HasAura(SPELL_PROTECTIVE_BUBBLE, 0)) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_WATER_BLAST, SPELL_WATER_BLAST_H)); + //DoCast(m_creature, SPELL_DRAINED); + bIsExploded = true; + uiShowup_Counter = 0; + m_creature->AttackStop(); + m_creature->SetVisibility(VISIBILITY_OFF); + for(uint8 i = 0; i < 10; i++) + { + //int tmp = urand(0, 5); + //m_creature->SummonCreature(NPC_ICHOR_GLOBULE, PortalLoc[tmp].x, PortalLoc[tmp].y, PortalLoc[tmp].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_ICHOR_GLOBULE, m_creature->GetPositionX()-10+rand()%20, m_creature->GetPositionY()-10+rand()%20, m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + } + uiBuubleChecker_Timer = 3000; + } + else + { + bool bIsWaterElementsAlive = false; + ++uiShowup_Counter; + if (!m_lWaterElementsGUIDList.empty()) + { + for(std::list<uint64>::iterator itr = m_lWaterElementsGUIDList.begin(); itr != m_lWaterElementsGUIDList.end(); ++itr) + if (Creature* pTemp = (Creature*)Unit::GetUnit(*m_creature, *itr)) + if (pTemp->isAlive()) + bIsWaterElementsAlive = true; + } + if (!bIsWaterElementsAlive || uiShowup_Counter > 20) + { + DoCast(m_creature, SPELL_PROTECTIVE_BUBBLE); + bIsExploded = false; + uiShowup_Counter = 0; + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + uiBuubleChecker_Timer = 1000; + } + } + else uiBuubleChecker_Timer -= uiDiff; + } + + if (!bIsExploded) + { + if (uiWaterBoltVolley_Timer < uiDiff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_WATER_BOLT_VOLLEY, SPELL_WATER_BOLT_VOLLEY_H)); + uiWaterBoltVolley_Timer = urand(10000, 15000); + } + else uiWaterBoltVolley_Timer -= uiDiff; + + if (!bIsFrenzy && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_FRENZY, SPELL_FRENZY_H)); + bIsFrenzy = true; + } + + DoMeleeAttackIfReady(); + } + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + DespawnWaterElements(); + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + { + pInstance->SetData(DATA_1ST_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 7); + } + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + { + pInstance->SetData(DATA_2ND_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 13); + } + } + } + + void JustSummoned(Creature* pSummoned) + { + pSummoned->SetSpeed(MOVE_RUN, 0.2f); + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); + m_lWaterElementsGUIDList.push_back(pSummoned->GetGUID()); + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_ichoron(Creature* pCreature) +{ + return new boss_ichoronAI (pCreature); +} + +struct TRINITY_DLL_DECL mob_ichor_globuleAI : public ScriptedAI +{ + mob_ichor_globuleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 uiRangeCheck_Timer; + + void Reset() + { + uiRangeCheck_Timer = 1000; + } + + void AttackStart(Unit* pWho) + { + return; + } + + void UpdateAI(const uint32 uiDiff) + { + if (uiRangeCheck_Timer < uiDiff) + { + if (pInstance) + { + if (Creature* pIchoron = ((Creature*)Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ICHORON)))) + { + //maybe 12.0f is not offlike, maybe 2.00f ? + float fDistance = m_creature->GetDistance(pIchoron); + if (m_creature->IsWithinDist(pIchoron, fDistance <= 12.0f , false)) + { + ((boss_ichoronAI*)pIchoron->AI())->WaterElementHit(); + m_creature->Kill(m_creature, false); + } + } + } + uiRangeCheck_Timer = 1000; + } + else uiRangeCheck_Timer -= uiDiff; + } + + void JustDied(Unit* pKiller) + { + DoCast(m_creature, SPELL_SPLASH); + } +}; + +CreatureAI* GetAI_mob_ichor_globule(Creature* pCreature) +{ + return new mob_ichor_globuleAI (pCreature); +} + +void AddSC_boss_ichoron() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_ichoron"; + newscript->GetAI = &GetAI_boss_ichoron; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ichor_globule"; + newscript->GetAI = &GetAI_mob_ichor_globule; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/boss_lavanthor.cpp b/src/scripts/northrend/violet_hold/boss_lavanthor.cpp new file mode 100644 index 00000000000..8743614675f --- /dev/null +++ b/src/scripts/northrend/violet_hold/boss_lavanthor.cpp @@ -0,0 +1,149 @@ +/* Script Data Start +SDName: Boss lavanthor +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "violet_hold.h" + +enum Spells +{ + SPELL_CAUTERIZING_FLAMES = 59466, //Only in heroic + SPELL_FIREBOLT = 54235, + H_SPELL_FIREBOLT = 59468, + SPELL_FLAME_BREATH = 54282, + H_SPELL_FLAME_BREATH = 59469, + SPELL_LAVA_BURN = 54249, + H_SPELL_LAVA_BURN = 59594 +}; + +struct TRINITY_DLL_DECL boss_lavanthorAI : public ScriptedAI +{ + boss_lavanthorAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiFireboltTimer; + uint32 uiFlameBreathTimer; + uint32 uiLavaBurnTimer; + uint32 uiCauterizingFlamesTimer; + + ScriptedInstance* pInstance; + + void Reset() + { + uiFireboltTimer = 1000; + uiFlameBreathTimer = 5000; + uiLavaBurnTimer = 10000; + uiCauterizingFlamesTimer = 3000; + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + } + } + + void EnterCombat(Unit* who) + { + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + } + } + + void AttackStart(Unit* pWho) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiFireboltTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_FIREBOLT, H_SPELL_FIREBOLT)); + uiFireboltTimer = urand(5000,13000); + } else uiFireboltTimer -= diff; + + if (uiFlameBreathTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_FLAME_BREATH, H_SPELL_FLAME_BREATH)); + uiFlameBreathTimer = urand(10000,15000); + } else uiFlameBreathTimer -= diff; + + if (uiLavaBurnTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_LAVA_BURN, H_SPELL_LAVA_BURN)); + uiLavaBurnTimer = urand(15000,23000); + } + + if (IsHeroic()) + { + if (uiCauterizingFlamesTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_CAUTERIZING_FLAMES); + uiCauterizingFlamesTimer = urand(10000,16000); + } else uiCauterizingFlamesTimer -= diff; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + { + pInstance->SetData(DATA_1ST_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 7); + } + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + { + pInstance->SetData(DATA_2ND_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 13); + } + } + } +}; + +CreatureAI* GetAI_boss_lavanthor(Creature* pCreature) +{ + return new boss_lavanthorAI (pCreature); +} + +void AddSC_boss_lavanthor() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_lavanthor"; + newscript->GetAI = &GetAI_boss_lavanthor; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/boss_moragg.cpp b/src/scripts/northrend/violet_hold/boss_moragg.cpp new file mode 100644 index 00000000000..f76a31403c1 --- /dev/null +++ b/src/scripts/northrend/violet_hold/boss_moragg.cpp @@ -0,0 +1,127 @@ +/* Script Data Start +SDName: Boss moragg +SDAuthor: LordVanMartin +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +/*** SQL START *** +update creature_template set scriptname = '' where entry = ''; +*** SQL END ***/ +#include "ScriptedPch.h" +#include "violet_hold.h" + +//Spells +enum Spells +{ + SPELL_CORROSIVE_SALIVA = 54527, + SPELL_OPTIC_LINK = 54396 +}; + +struct TRINITY_DLL_DECL boss_moraggAI : public ScriptedAI +{ + boss_moraggAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiOpticLinkTimer; + uint32 uiCorrosiveSalivaTimer; + + ScriptedInstance* pInstance; + + void Reset() + { + uiOpticLinkTimer = 10000; + uiCorrosiveSalivaTimer = 5000; + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + } + } + + void EnterCombat(Unit* who) + { + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + } + } + + void AttackStart(Unit* pWho) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiOpticLinkTimer <= diff) + { + if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(pTarget, SPELL_OPTIC_LINK); + uiOpticLinkTimer = 15000; + } else uiOpticLinkTimer -= diff; + + if (uiCorrosiveSalivaTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_CORROSIVE_SALIVA); + uiCorrosiveSalivaTimer = 10000; + } else uiCorrosiveSalivaTimer -= diff; + + DoMeleeAttackIfReady(); + } + void JustDied(Unit* killer) + { + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + { + pInstance->SetData(DATA_1ST_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 7); + } + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + { + pInstance->SetData(DATA_2ND_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT,13); + } + } + } +}; + +CreatureAI* GetAI_boss_moragg(Creature* pCreature) +{ + return new boss_moraggAI (pCreature); +} + +void AddSC_boss_moragg() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_moragg"; + newscript->GetAI = &GetAI_boss_moragg; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/boss_xevozz.cpp b/src/scripts/northrend/violet_hold/boss_xevozz.cpp new file mode 100644 index 00000000000..d02adee1280 --- /dev/null +++ b/src/scripts/northrend/violet_hold/boss_xevozz.cpp @@ -0,0 +1,302 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Script Data Start +SDName: Boss xevozz +SD%Complete: +SDComment: +SDCategory: +Script Data End */ + +#include "ScriptedPch.h" +#include "violet_hold.h" + +enum Spells +{ + SPELL_ARCANE_BARRAGE_VOLLEY = 54202, + SPELL_ARCANE_BARRAGE_VOLLEY_H = 59483, + SPELL_ARCANE_BUFFET = 54226, + SPELL_ARCANE_BUFFET_H = 59485, + SPELL_SUMMON_ETHEREAL_SPHERE_1 = 54102, + SPELL_SUMMON_ETHEREAL_SPHERE_2 = 54137, + SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138, +}; + +enum NPCs +{ + NPC_ETHEREAL_SPHERE = 29271, + //NPC_ETHEREAL_SPHERE2 = 32582, // heroic only? +}; + +enum CreatureSpells +{ + SPELL_ARCANE_POWER = 54160, + H_SPELL_ARCANE_POWER = 59474, + SPELL_SUMMON_PLAYERS = 54164, + SPELL_POWER_BALL_VISUAL = 54141, +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1608027, + SAY_SLAY_1 = -1608028, + SAY_SLAY_2 = -1608029, + SAY_SLAY_3 = -1608030, + SAY_DEATH = -1608031, + SAY_SPAWN = -1608032, + SAY_CHARGED = -1608033, + SAY_REPEAT_SUMMON_1 = -1608034, + SAY_REPEAT_SUMMON_2 = -1608035, + SAY_SUMMON_ENERGY = -1608036 +}; + +struct TRINITY_DLL_DECL boss_xevozzAI : public ScriptedAI +{ + boss_xevozzAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 uiSummonEtherealSphere_Timer; + uint32 uiArcaneBarrageVolley_Timer; + uint32 uiArcaneBuffet_Timer; + + void Reset() + { + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + } + + uiSummonEtherealSphere_Timer = urand(10000, 12000); + uiArcaneBarrageVolley_Timer = urand(20000, 22000); + uiArcaneBuffet_Timer = uiSummonEtherealSphere_Timer + urand(5000, 6000); + DespawnSphere(); + } + + void DespawnSphere() + { + std::list<Creature*> assistList; + GetCreatureListWithEntryInGrid(assistList,m_creature, NPC_ETHEREAL_SPHERE ,150.0f); + + if (assistList.empty()) + return; + + for(std::list<Creature*>::iterator iter = assistList.begin(); iter != assistList.end(); ++iter) + { + if (Creature* pSphere = *iter) + pSphere->Kill(pSphere, false); + } + } + + void JustSummoned(Creature* pSummoned) + { + pSummoned->SetSpeed(MOVE_RUN, 0.5f); + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + pSummoned->AddThreat(pTarget, 0.00f); + pSummoned->AI()->AttackStart(pTarget); + } + } + + void AttackStart(Unit* pWho) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void EnterCombat(Unit* pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + } + } + + void MoveInLineOfSight(Unit* pWho) {} + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (uiArcaneBarrageVolley_Timer < uiDiff) + { + DoCast(m_creature, DUNGEON_MODE(SPELL_ARCANE_BARRAGE_VOLLEY, SPELL_ARCANE_BARRAGE_VOLLEY_H)); + uiArcaneBarrageVolley_Timer = urand(20000, 22000); + } + else uiArcaneBarrageVolley_Timer -= uiDiff; + + if (uiArcaneBuffet_Timer) + if (uiArcaneBuffet_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_ARCANE_BUFFET, SPELL_ARCANE_BUFFET_H)); + uiArcaneBuffet_Timer = 0; + } + else uiArcaneBuffet_Timer -= uiDiff; + + if (uiSummonEtherealSphere_Timer < uiDiff) + { + DoScriptText(SAY_SPAWN, m_creature); + DoCast(m_creature, SPELL_SUMMON_ETHEREAL_SPHERE_1); + if (IsHeroic()) // extra one for heroic + m_creature->SummonCreature(NPC_ETHEREAL_SPHERE, m_creature->GetPositionX()-5+rand()%10, m_creature->GetPositionY()-5+rand()%10, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 40000); + + uiSummonEtherealSphere_Timer = urand(45000, 47000); + uiArcaneBuffet_Timer = urand(5000, 6000); + } + else uiSummonEtherealSphere_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + DoScriptText(SAY_DEATH, m_creature); + + DespawnSphere(); + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + { + pInstance->SetData(DATA_1ST_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 7); + } + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + { + pInstance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + pInstance->SetData(DATA_WAVE_COUNT, 13); + } + } + } + void KilledUnit(Unit* pVictim) + { + if (pVictim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } +}; + +CreatureAI* GetAI_boss_xevozz(Creature* pCreature) +{ + return new boss_xevozzAI (pCreature); +} + +struct TRINITY_DLL_DECL mob_ethereal_sphereAI : public ScriptedAI +{ + mob_ethereal_sphereAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 uiSummonPlayers_Timer; + uint32 uiRangeCheck_Timer; + + void Reset() + { + uiSummonPlayers_Timer = urand(33000, 35000); + uiRangeCheck_Timer = 1000; + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (!m_creature->HasAura(SPELL_POWER_BALL_VISUAL)) + DoCast(m_creature, SPELL_POWER_BALL_VISUAL); + + if (uiRangeCheck_Timer < uiDiff) + { + if (pInstance) + { + if (Creature* pXevozz = ((Creature*)Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_XEVOZZ)))) + { + float fDistance = m_creature->GetDistance2d(pXevozz); + if (fDistance <= 3) + DoCast(pXevozz, DUNGEON_MODE(SPELL_ARCANE_POWER, H_SPELL_ARCANE_POWER)); + else + DoCast(m_creature, 35845); //Is it blizzlike? + } + } + uiRangeCheck_Timer = 1000; + } + else uiRangeCheck_Timer -= uiDiff; + + if (uiSummonPlayers_Timer < uiDiff) + { + DoCast(m_creature, SPELL_SUMMON_PLAYERS); // not working right + + Map* pMap = m_creature->GetMap(); + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + + if (!PlayerList.isEmpty()) + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (i->getSource()->isAlive()) + DoTeleportPlayer(i->getSource(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), i->getSource()->GetOrientation()); + } + + uiSummonPlayers_Timer = urand(33000, 35000); + } + else uiSummonPlayers_Timer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_ethereal_sphere(Creature* pCreature) +{ + return new mob_ethereal_sphereAI (pCreature); +} + +void AddSC_boss_xevozz() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_xevozz"; + newscript->GetAI = &GetAI_boss_xevozz; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ethereal_sphere"; + newscript->GetAI = &GetAI_mob_ethereal_sphere; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/boss_zuramat.cpp b/src/scripts/northrend/violet_hold/boss_zuramat.cpp new file mode 100644 index 00000000000..4a6ef848575 --- /dev/null +++ b/src/scripts/northrend/violet_hold/boss_zuramat.cpp @@ -0,0 +1,173 @@ +/* Script Data Start +SDName: Boss zuramat +SD%Complete: +SDComment: The phasemask for the voids dosen't work. +SDCategory: +Script Data End */ + +#include "ScriptedPch.h" +#include "violet_hold.h" + +enum Spells +{ + SPELL_SHROUD_OF_DARKNESS = 54524, + H_SPELL_SHROUD_OF_DARKNESS = 59745, + SPELL_SUMMON_VOID_SENTRY = 54369, + SPELL_VOID_SHIFT = 54361, + H_SPELL_VOID_SHIFT = 59743, + + SPELL_ZUMARAT_ADD_2 = 59747, + H_SPELL_ZUMARAT_ADD_2 = 59747 +}; + +enum ZuramatCreatures +{ + CREATURE_VOID_SENTRY = 29364 +}; + +//not in db +enum Yells +{ + SAY_AGGRO = -1608037, + SAY_SLAY_1 = -1608038, + SAY_SLAY_2 = -1608039, + SAY_SLAY_3 = -1608040, + SAY_DEATH = -1608041, + SAY_SPAWN = -1608042, + SAY_SHIELD = -1608043, + SAY_WHISPER = -1608044 +}; + +struct TRINITY_DLL_DECL boss_zuramatAI : public ScriptedAI +{ + boss_zuramatAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint32 SpellVoidShiftTimer; + uint32 SpellSummonVoidTimer; + uint32 SpellShroudOfDarknessTimer; + + void Reset() + { + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + } + + SpellShroudOfDarknessTimer = 22000; + SpellVoidShiftTimer = 15000; + SpellSummonVoidTimer = 12000; + } + + void AttackStart(Unit* pWho) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void EnterCombat(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + pInstance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + pInstance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + } + } + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (SpellSummonVoidTimer <= diff) + { + DoCast(m_creature->getVictim(), SPELL_SUMMON_VOID_SENTRY, false); + SpellSummonVoidTimer = 20000; + } else SpellSummonVoidTimer -=diff; + + if (SpellVoidShiftTimer <= diff) + { + if (Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pUnit, DUNGEON_MODE(SPELL_VOID_SHIFT, H_SPELL_VOID_SHIFT)); + SpellVoidShiftTimer = 20000; + } else SpellVoidShiftTimer -=diff; + + if (SpellShroudOfDarknessTimer <= diff) + { + DoCast(m_creature->getVictim(), DUNGEON_MODE(SPELL_SHROUD_OF_DARKNESS, H_SPELL_SHROUD_OF_DARKNESS)); + SpellShroudOfDarknessTimer = 20000; + } else SpellShroudOfDarknessTimer -=diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (pInstance) + { + if (pInstance->GetData(DATA_WAVE_COUNT) == 6) + { + pInstance->SetData(DATA_1ST_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 7); + } + else if (pInstance->GetData(DATA_WAVE_COUNT) == 12) + { + pInstance->SetData(DATA_2ND_BOSS_EVENT, DONE); + pInstance->SetData(DATA_WAVE_COUNT, 13); + } + } + } + + void KilledUnit(Unit *victim) + { + if (victim == m_creature) + return; + + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2,SAY_SLAY_3), m_creature); + } + + void JustSummoned(Creature* summon) + { + summon->AI()->AttackStart(m_creature->getVictim()); + summon->AI()->DoCastAOE(DUNGEON_MODE(SPELL_ZUMARAT_ADD_2, H_SPELL_ZUMARAT_ADD_2)); + summon->SetPhaseMask(17,true); + } +}; + +CreatureAI* GetAI_boss_zuramat(Creature* pCreature) +{ + return new boss_zuramatAI (pCreature); +} + +void AddSC_boss_zuramat() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_zuramat"; + newscript->GetAI = &GetAI_boss_zuramat; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/instance_violet_hold.cpp b/src/scripts/northrend/violet_hold/instance_violet_hold.cpp new file mode 100644 index 00000000000..602ad682eda --- /dev/null +++ b/src/scripts/northrend/violet_hold/instance_violet_hold.cpp @@ -0,0 +1,544 @@ +#include "ScriptedPch.h" +#include "violet_hold.h" + +#define MAX_ENCOUNTER 3 + +/* Violet Hold encounters: +0 - First boss +1 - Second boss +2 - Cyanigosa*/ + +/* Violet hold bosses: +0 - Moragg +1 - Erekem +2 - Ichoron +3 - Lavanthor +4 - Xevozz +5 - Zuramat +6 - Cyanigosa */ +enum GameObjects +{ + GO_MAIN_DOOR = 191723, + GO_XEVOZZ_DOOR = 191556, + GO_LAVANTHOR_DOOR = 191566, + GO_ICHORON_DOOR = 191722, + GO_ZURAMAT_DOOR = 191565, + GO_EREKEM_DOOR = 191564, + GO_EREKEM_GUARD_1_DOOR = 191563, + GO_EREKEM_GUARD_2_DOOR = 191562, + GO_MORAGG_DOOR = 191606, + GO_INTRO_ACTIVATION_CRYSTAL = 193615, + GO_ACTIVATION_CRYSTAL = 193611 +}; +enum Spells +{ + SPELL_PORTAL_CHANNEL = 58012 +}; +struct Location +{ + float x,y,z,orientation; +}; +const Location PortalLocation[] = +{ + {1936.07, 803.198, 53.3749, 3.12414}, + {1877.51, 850.104, 44.6599, 4.7822 }, + {1890.64, 753.471, 48.7224, 1.71042} +}; +struct TRINITY_DLL_DECL instance_violet_hold : public ScriptedInstance +{ + instance_violet_hold(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint64 uiMoragg; + uint64 uiErekem; + uint64 uiErekemGuard[2]; + uint64 uiIchoron; + uint64 uiLavanthor; + uint64 uiXevozz; + uint64 uiZuramat; + uint64 uiCyanigosa; + uint64 uiSinclari; + + uint64 uiMoraggCell; + uint64 uiErekemCell; + uint64 uiErekemLeftGuardCell; + uint64 uiErekemRightGuardCell; + uint64 uiIchoronCell; + uint64 uiLavanthorCell; + uint64 uiXevozzCell; + uint64 uiZuramatCell; + uint64 uiMainDoor; + + uint64 uiActivationCrystal[3]; + + uint32 uiActivationTimer; + + uint8 uiWaveCount; + uint8 uiLocation; + uint8 uiFirstBoss; + uint8 uiSecondBoss; + uint8 uiRemoveNpc; + + uint8 m_auiEncounter[MAX_ENCOUNTER]; + uint8 uiCountErekemGuards; + uint8 uiCountActivationCrystals; + uint8 uiPlayersDead; + uint8 uiMaxPlayerCount; + + bool bActive; + bool bWiped; + + std::string str_data; + + void Initialize() + { + uiMoragg = 0; + uiErekem = 0; + uiIchoron = 0; + uiLavanthor = 0; + uiXevozz = 0; + uiZuramat = 0; + uiCyanigosa = 0; + uiSinclari = 0; + + uiMoraggCell = 0; + uiErekemCell = 0; + uiErekemGuard[0] = 0; + uiErekemGuard[1] = 0; + uiIchoronCell = 0; + uiLavanthorCell = 0; + uiXevozzCell = 0; + uiZuramatCell = 0; + uiMainDoor = 0; + uiRemoveNpc = 0; + + uiWaveCount = 0; + uiLocation = 0; + uiFirstBoss = 0; + uiSecondBoss = 0; + uiCountErekemGuards = 0; + uiCountActivationCrystals = 0; + uiPlayersDead = 0; + uiMaxPlayerCount = 0; + + uiActivationTimer = 5000; + + bActive = false; + bWiped = false; + + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case CREATURE_XEVOZZ: + uiXevozz = pCreature->GetGUID(); + break; + case CREATURE_LAVANTHOR: + uiLavanthor = pCreature->GetGUID(); + break; + case CREATURE_ICHORON: + uiIchoron = pCreature->GetGUID(); + break; + case CREATURE_ZURAMAT: + uiZuramat = pCreature->GetGUID(); + break; + case CREATURE_EREKEM: + uiErekem = pCreature->GetGUID(); + break; + case CREATURE_EREKEM_GUARD: + if (uiCountErekemGuards < 2) + uiErekemGuard[uiCountErekemGuards++] = pCreature->GetGUID(); + break; + case CREATURE_MORAGG: + uiMoragg = pCreature->GetGUID(); + break; + case CREATURE_CYANIGOSA: + uiCyanigosa = pCreature->GetGUID(); + break; + case CREATURE_SINCLARI: + uiSinclari = pCreature->GetGUID(); + break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case GO_EREKEM_GUARD_1_DOOR: + uiErekemLeftGuardCell = pGo->GetGUID(); + break; + case GO_EREKEM_GUARD_2_DOOR: + uiErekemRightGuardCell = pGo->GetGUID(); + break; + case GO_EREKEM_DOOR: + uiErekemCell = pGo->GetGUID(); + break; + case GO_ZURAMAT_DOOR: + uiZuramatCell = pGo->GetGUID(); + break; + case GO_LAVANTHOR_DOOR: + uiLavanthorCell = pGo->GetGUID(); + break; + case GO_MORAGG_DOOR: + uiMoraggCell = pGo->GetGUID(); + break; + case GO_ICHORON_DOOR: + uiIchoronCell = pGo->GetGUID(); + break; + case GO_XEVOZZ_DOOR: + uiXevozzCell = pGo->GetGUID(); + break; + case GO_MAIN_DOOR: + uiMainDoor = pGo->GetGUID(); + break; + case GO_ACTIVATION_CRYSTAL: + if (uiCountActivationCrystals < 3) + uiActivationCrystal[uiCountActivationCrystals++] = pGo->GetGUID(); + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_1ST_BOSS_EVENT: + m_auiEncounter[0] = data; + if (data == DONE) + SaveToDB(); + break; + case DATA_2ND_BOSS_EVENT: + m_auiEncounter[1] = data; + if (data == DONE) + SaveToDB(); + break; + case DATA_CYANIGOSA_EVENT: + m_auiEncounter[2] = data; + if (data == DONE) + { + SaveToDB(); + if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor)) + pMainDoor->SetGoState(GO_STATE_ACTIVE); + } + break; + case DATA_WAVE_COUNT: + uiWaveCount = data; + bActive = true; + break; + case DATA_REMOVE_NPC: + uiRemoveNpc = data; + break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_1ST_BOSS_EVENT: return m_auiEncounter[0]; + case DATA_2ND_BOSS_EVENT: return m_auiEncounter[1]; + case DATA_CYANIGOSA_EVENT: return m_auiEncounter[2]; + case DATA_WAVE_COUNT: return uiWaveCount; + case DATA_REMOVE_NPC: return uiRemoveNpc; + } + + return 0; + } + + void SpawnPortal() + { + Creature *pSinclari = instance->GetCreature(uiSinclari); + if (pSinclari) + { + if (Creature *pPortal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL,PortalLocation[uiLocation].x,PortalLocation[uiLocation].y, + PortalLocation[uiLocation].z,PortalLocation[uiLocation].orientation, + TEMPSUMMON_CORPSE_DESPAWN,900000)) + { + uint32 entry = urand(0, 1) ? CREATURE_PORTAL_GUARDIAN : CREATURE_PORTAL_KEEPER; + if (Creature *pPortalKeeper = pPortal->SummonCreature(entry,PortalLocation[uiLocation].x, PortalLocation[uiLocation].y, + PortalLocation[uiLocation].z, PortalLocation[uiLocation].orientation, + TEMPSUMMON_DEAD_DESPAWN,900000)) + pPortal->CastSpell(pPortalKeeper, SPELL_PORTAL_CHANNEL,false); + uiLocation = (++uiLocation)%3; + } + } + } + + void StartBossEncounter(uint8 uiBoss, bool bForceRespawn = true) + { + Creature* pBoss = NULL; + switch(uiBoss) + { + case 0: //Moragg + HandleGameObject(uiMoraggCell,bForceRespawn); + + if (pBoss = instance->GetCreature(uiMoragg)) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + } + break; + case 1: //Erekem + HandleGameObject(uiErekemCell,bForceRespawn); + HandleGameObject(uiErekemRightGuardCell,bForceRespawn); + HandleGameObject(uiErekemLeftGuardCell,bForceRespawn); + + if (pBoss = instance->GetCreature(uiErekem)) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + if (pBoss = instance->GetCreature(uiErekemGuard[0])) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + if (pBoss = instance->GetCreature(uiErekemGuard[1])) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + break; + case 2: //Ichoron + HandleGameObject(uiIchoronCell,bForceRespawn); + if (pBoss = instance->GetCreature(uiIchoron)) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + break; + case 3: //Lavanthor + HandleGameObject(uiLavanthorCell,bForceRespawn); + if (pBoss = instance->GetCreature(uiLavanthor)) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + break; + case 4: //Xevozz + HandleGameObject(uiXevozzCell,bForceRespawn); + if (pBoss = instance->GetCreature(uiXevozz)) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + break; + case 5: //Zuramat + HandleGameObject(uiZuramatCell,bForceRespawn); + if (pBoss = instance->GetCreature(uiZuramat)) + { + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + break; + } + if (!bForceRespawn && pBoss) + { + pBoss->AllLootRemovedFromCorpse(); + pBoss->Respawn(); + pBoss->RemoveLootMode(1); + pBoss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pBoss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + SetData(DATA_WAVE_COUNT,0); + uiWaveCount = 0; + } + } + + void AddWave() + { + DoUpdateWorldState(WORLD_STATE_VH, uiWaveCount); + switch(uiWaveCount) + { + case 6: + uiFirstBoss = rand()%6; + StartBossEncounter(uiFirstBoss); + break; + case 12: + uiSecondBoss = rand()%6; + while (uiSecondBoss == uiFirstBoss) + uiSecondBoss = rand()%6; + StartBossEncounter(uiSecondBoss); + break; + case 18: + { + Creature *pSinclari = instance->GetCreature(uiSinclari); + if (pSinclari) + pSinclari->SummonCreature(CREATURE_CYANIGOSA,PortalLocation[0].x,PortalLocation[0].y, + PortalLocation[0].z,PortalLocation[0].orientation,TEMPSUMMON_DEAD_DESPAWN,0); + break; + } + case 1: + { + if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor)) + pMainDoor->SetGoState(GO_STATE_READY); + } + default: + if (!bWiped) + SpawnPortal(); + bWiped = false; + } + bActive = true; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_MORAGG: return uiMoragg; + case DATA_EREKEM: return uiErekem; + case DATA_EREKEM_GUARD_1: return uiErekemGuard[0]; + case DATA_EREKEM_GUARD_2: return uiErekemGuard[1]; + case DATA_ICHORON: return uiIchoron; + case DATA_LAVANTHOR: return uiLavanthor; + case DATA_XEVOZZ: return uiXevozz; + case DATA_ZURAMAT: return uiZuramat; + case DATA_CYANIGOSA: return uiCyanigosa; + case DATA_MORAGG_CELL: return uiMoraggCell; + case DATA_EREKEM_CELL: return uiErekemCell; + case DATA_EREKEM_RIGHT_GUARD_CELL: return uiErekemRightGuardCell; + case DATA_EREKEM_LEFT_GUARD_CELL: return uiErekemLeftGuardCell; + case DATA_ICHORON_CELL: return uiIchoronCell; + case DATA_LAVANTHOR_CELL: return uiLavanthorCell; + case DATA_XEVOZZ_CELL: return uiXevozzCell; + case DATA_ZURAMAT_CELL: return uiZuramatCell; + case DATA_MAIN_DOOR: return uiMainDoor; + case DATA_SINCLARI: return uiSinclari; + } + + return 0; + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "V H " << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2] << " " << uiFirstBoss << " " << uiSecondBoss; + + 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; + + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4; + + if (dataHead1 == 'V' && dataHead2 == 'H') + { + m_auiEncounter[0] = data0; + m_auiEncounter[1] = data1; + m_auiEncounter[2] = data2; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + + uiFirstBoss = data3; + uiSecondBoss = data4; + } else OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } + + void CountPlayers(bool bCheckState = false) + { + if (!bCheckState) + { + uiMaxPlayerCount = 0; + Map::PlayerList const &players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + ++uiMaxPlayerCount; + }else + { + Map::PlayerList const &players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + Player* pPlayer = itr->getSource(); + + if (pPlayer->isDead() && !pPlayer->isGameMaster()) + ++uiPlayersDead; + else if (pPlayer->isAlive() && !pPlayer->isGameMaster()) + uiPlayersDead = 0; + } + + } + } + + void Update(uint32 diff) + { + if (!instance->HavePlayers()) + return; + + if (bActive) + { + if (uiActivationTimer < diff) + { + AddWave(); + bActive = false; + uiActivationTimer = 5000; + } else uiActivationTimer -= diff; + } + + CountPlayers(true); + CountPlayers(false); + + if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor)) + if (pMainDoor->GetGoState() != GO_STATE_ACTIVE && uiPlayersDead >= uiMaxPlayerCount) + { + SetData(DATA_REMOVE_NPC, 1); + StartBossEncounter(uiFirstBoss, false); + StartBossEncounter(uiSecondBoss, false); + bWiped = true; + if (Creature* pSinclari = instance->GetCreature(uiSinclari)) + { + pSinclari->DisappearAndDie(); + pSinclari->Respawn(true); + } + + if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor)) + pMainDoor->SetGoState(GO_STATE_ACTIVE); + SetData(DATA_WAVE_COUNT, 0); + } + } +}; + +InstanceData* GetInstanceData_instance_violet_hold(Map* pMap) +{ + return new instance_violet_hold(pMap); +} + +void AddSC_instance_violet_hold() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_violet_hold"; + newscript->GetInstanceData = &GetInstanceData_instance_violet_hold; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/violet_hold.cpp b/src/scripts/northrend/violet_hold/violet_hold.cpp new file mode 100644 index 00000000000..b9f7b010615 --- /dev/null +++ b/src/scripts/northrend/violet_hold/violet_hold.cpp @@ -0,0 +1,249 @@ +#include "ScriptedPch.h" +#include "violet_hold.h" + +#define GOSSIP_START_EVENT "Get your people to safety, we'll keep the Blue Dragonflight's forces at bay." +#define GOSSIP_ITEM_1 "Activate the crystals when we get in trouble, right" +#define SPAWN_TIME 15000 + +enum PortalCreatures +{ + CREATURE_AZURE_INVADER = 30661, + CREATURE_AZURE_SPELLBREAKER = 30662, + CREATURE_AZURE_BINDER = 30663, + CREATURE_AZURE_MAGE_SLAYER = 30664, + CREATURE_AZURE_CAPTAIN = 30666, + CREATURE_AZURE_SORCEROR = 30667, + CREATURE_AZURE_RAIDER = 30668, + CREATURE_AZURE_STALKER = 32191 +}; + +enum eSinclari +{ + NPC_VIOLET_HOLD_GUARD = 30659, + + SAY_SINCLARI_1 = -1608000, +}; + +const Position DoorPosition = { 1828.300049, 797.309021, 46.135502, 1.48353}; +const Position MovePosition = { 1806.955566, 803.851807, 44.363323}; + +struct TRINITY_DLL_DECL npc_sinclariAI : public ScriptedAI +{ + npc_sinclariAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* pInstance; + + uint8 uiPhase; + uint32 uiTimer; + + std::list<Creature*> GuardList; + + void Reset() + { + uiPhase = 0; + uiTimer = 0; + + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->SetReactState(REACT_AGGRESSIVE); + + m_creature->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); + if (!GuardList.empty()) + for (std::list<Creature*>::iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) + { + if (Creature* pGuard = *itr) + { + pGuard->DisappearAndDie(); + pGuard->Respawn(); + pGuard->SetVisibility(VISIBILITY_ON); + pGuard->SetReactState(REACT_AGGRESSIVE); + } + } + } + + void MovementInform(uint32 uiType, uint32 uiId) + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (pInstance) + pInstance->SetData(DATA_WAVE_COUNT,1); + + //She should not be despawned, she will be used by the instance to summon some npcs + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetReactState(REACT_PASSIVE); + } + + void UpdateAI(const uint32 uiDiff) + { + ScriptedAI::UpdateAI(uiDiff); + + if (uiPhase) + { + if (uiTimer <= uiDiff) + { + switch(uiPhase) + { + case 1: + DoScriptText(SAY_SINCLARI_1, m_creature); + uiTimer = 4000; + uiPhase = 2; + break; + case 2: + m_creature->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); + if (!GuardList.empty()) + for (std::list<Creature*>::iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) + { + if (Creature* pGuard = *itr) + { + pGuard->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + pGuard->GetMotionMaster()->MovePoint(0, MovePosition); + } + } + uiTimer = 6000; + uiPhase = 3; + break; + case 3: + m_creature->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); + if (!GuardList.empty()) + for (std::list<Creature*>::iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) + { + if (Creature* pGuard = *itr) + { + pGuard->SetVisibility(VISIBILITY_OFF); + pGuard->SetReactState(REACT_PASSIVE); + } + } + uiTimer = 2000; + uiPhase = 4; + break; + case 4: + m_creature->GetMotionMaster()->MovePoint(0, MovePosition); + uiTimer = 0; + uiPhase = 0; + break; + } + } + else uiTimer -= uiDiff; + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_sinclari(Creature* pCreature) +{ + return new npc_sinclariAI(pCreature); +} + +bool GossipHello_npc_sinclari(Player* pPlayer, Creature* pCreature) +{ + ScriptedInstance* pInstance = pCreature->GetInstanceData(); + if (pInstance && pInstance->GetData(DATA_CYANIGOSA_EVENT) != DONE && pInstance->GetData(DATA_WAVE_COUNT) == 0 && pPlayer) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT,GOSSIP_ITEM_1,GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT,GOSSIP_START_EVENT,GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(13853, pCreature->GetGUID()); + }else + pPlayer->SEND_GOSSIP_MENU(13910, pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + if (pPlayer) + pPlayer->CLOSE_GOSSIP_MENU(); + CAST_AI(npc_sinclariAI, (pCreature->AI()))->uiPhase = 1; + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->SEND_GOSSIP_MENU(13854, pCreature->GetGUID()); + break; + } + return true; +} + +struct TRINITY_DLL_DECL npc_teleportation_portalAI : public ScriptedAI +{ + npc_teleportation_portalAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + uint32 uiSpawnTimer; + + ScriptedInstance *pInstance; + + void Reset() + { + uiSpawnTimer = 3000; + } + + void EnterCombat(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if (pInstance && pInstance->GetData(DATA_REMOVE_NPC) == 1) + { + m_creature->ForcedDespawn(); + pInstance->SetData(DATA_REMOVE_NPC, 0); + } + + if (uiSpawnTimer <= diff) + { + uint8 k = pInstance->GetData(DATA_WAVE_COUNT) < 12 ? 3 : 4; + for (uint8 i = 0; i < k; ++i) + { + if (Creature* pSummon = m_creature->SummonCreature(RAND(CREATURE_AZURE_CAPTAIN,CREATURE_AZURE_RAIDER,CREATURE_AZURE_STALKER,CREATURE_AZURE_SORCEROR), + m_creature->GetPositionX()+urand(0,2), m_creature->GetPositionY()+urand(0,2), + m_creature->GetPositionZ(),m_creature->GetOrientation(), + TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + pSummon->GetMotionMaster()->MovePoint(0, DoorPosition); + } + uiSpawnTimer = SPAWN_TIME; + } else uiSpawnTimer -= diff; + + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + m_creature->Kill(m_creature, false); + m_creature->RemoveCorpse(); + return; + } + } + + void JustDied(Unit* killer) + { + if (pInstance) + pInstance->SetData(DATA_WAVE_COUNT,pInstance->GetData(DATA_WAVE_COUNT)+1); + } +}; + +CreatureAI* GetAI_npc_teleportation_portal(Creature *pCreature) +{ + return new npc_teleportation_portalAI(pCreature); +} + +void AddSC_violet_hold() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_sinclari_vh"; + newscript->GetAI = &GetAI_npc_sinclari; + newscript->pGossipHello = &GossipHello_npc_sinclari; + newscript->pGossipSelect = &GossipSelect_npc_sinclari; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_teleportation_portal_vh"; + newscript->GetAI = &GetAI_npc_teleportation_portal; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/violet_hold/violet_hold.h b/src/scripts/northrend/violet_hold/violet_hold.h new file mode 100644 index 00000000000..187ab28036b --- /dev/null +++ b/src/scripts/northrend/violet_hold/violet_hold.h @@ -0,0 +1,57 @@ +#ifndef DEF_VIOLET_HOLD_H +#define DEF_VIOLET_HOLD_H + +enum Creatures +{ + CREATURE_TELEPORTATION_PORTAL = 31011, + CREATURE_PORTAL_GUARDIAN = 30660, + CREATURE_PORTAL_KEEPER = 30695, + CREATURE_XEVOZZ = 29266, + CREATURE_LAVANTHOR = 29312, + CREATURE_ICHORON = 29313, + CREATURE_ZURAMAT = 29314, + CREATURE_EREKEM = 29315, + CREATURE_EREKEM_GUARD = 29395, + CREATURE_MORAGG = 29316, + CREATURE_CYANIGOSA = 31134, + CREATURE_SINCLARI = 30658 +}; + +enum Data +{ + DATA_1ST_BOSS_EVENT, + DATA_2ND_BOSS_EVENT, + DATA_CYANIGOSA_EVENT, + DATA_WAVE_COUNT, + DATA_REMOVE_NPC +}; + +enum Data64 +{ + DATA_MORAGG, + DATA_EREKEM, + DATA_EREKEM_GUARD_1, + DATA_EREKEM_GUARD_2, + DATA_ICHORON, + DATA_LAVANTHOR, + DATA_XEVOZZ, + DATA_ZURAMAT, + DATA_CYANIGOSA, + DATA_MORAGG_CELL, + DATA_EREKEM_CELL, + DATA_EREKEM_LEFT_GUARD_CELL, + DATA_EREKEM_RIGHT_GUARD_CELL, + DATA_ICHORON_CELL, + DATA_LAVANTHOR_CELL, + DATA_XEVOZZ_CELL, + DATA_ZURAMAT_CELL, + DATA_MAIN_DOOR, + DATA_SINCLARI +}; + +enum WorldStates +{ + WORLD_STATE_VH = 3816 +}; + +#endif diff --git a/src/scripts/northrend/wintergrasp.cpp b/src/scripts/northrend/wintergrasp.cpp new file mode 100644 index 00000000000..af8e54319d9 --- /dev/null +++ b/src/scripts/northrend/wintergrasp.cpp @@ -0,0 +1,95 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "OutdoorPvPWG.h" + +#define GOSSIP_HELLO_DEMO1 "Build catapult." +#define GOSSIP_HELLO_DEMO2 "Build demolisher." +#define GOSSIP_HELLO_DEMO3 "Build siege engine." +#define GOSSIP_HELLO_DEMO4 "I cannot build more!" + +struct TRINITY_DLL_DECL npc_demolisher_engineererAI : public ScriptedAI +{ + npc_demolisher_engineererAI(Creature* pCreature) : ScriptedAI(pCreature) + { + me->SetReactState(REACT_PASSIVE); + } + + /* + void JustDied(Unit *killer) + { + if(me->GetZoneScript()) + me->GetZoneScript()->SetData(DATA_ENGINEER_DIE, me->GetDBTableGUIDLow()); + } + */ +}; + +CreatureAI* GetAI_npc_demolisher_engineerer(Creature* pCreature) +{ + return new npc_demolisher_engineererAI (pCreature); +} + +bool GossipHello_npc_demolisher_engineerer(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + if(pPlayer->isGameMaster() || pCreature->GetZoneScript() && pCreature->GetZoneScript()->GetData(pCreature->GetDBTableGUIDLow())) + { + if (pPlayer->HasAura(SPELL_CORPORAL)) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + else if (pPlayer->HasAura(SPELL_LIEUTENANT)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + } + } + else + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; +} + +bool GossipSelect_npc_demolisher_engineerer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + pPlayer->CLOSE_GOSSIP_MENU(); + if(pPlayer->isGameMaster() || pCreature->GetZoneScript() && pCreature->GetZoneScript()->GetData(pCreature->GetDBTableGUIDLow())) + { + switch(uiAction - GOSSIP_ACTION_INFO_DEF) + { + case 0: pPlayer->CastSpell(pPlayer, 56663, false, NULL, NULL, pCreature->GetGUID()); break; + case 1: pPlayer->CastSpell(pPlayer, 56575, false, NULL, NULL, pCreature->GetGUID()); break; + case 2: pPlayer->CastSpell(pPlayer, pPlayer->GetTeamId() ? 61408 : 56661, false, NULL, NULL, pCreature->GetGUID()); break; + } + } + + return true; +} + +void AddSC_wintergrasp() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_demolisher_engineerer"; + newscript->GetAI = &GetAI_npc_demolisher_engineerer; + newscript->pGossipHello = &GossipHello_npc_demolisher_engineerer; + newscript->pGossipSelect = &GossipSelect_npc_demolisher_engineerer; + newscript->RegisterSelf(); +} diff --git a/src/scripts/northrend/zuldrak.cpp b/src/scripts/northrend/zuldrak.cpp new file mode 100644 index 00000000000..d971c86a336 --- /dev/null +++ b/src/scripts/northrend/zuldrak.cpp @@ -0,0 +1,932 @@ +/* + * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ScriptedEscortAI.h" + +/*#### +## npc_drakuru_shackles +####*/ + +enum eDrakuruShackles +{ + SPELL_LEFT_CHAIN = 59951, + SPELL_RIGHT_CHAIN = 59952, + SPELL_UNLOCK_SHACKLE = 55083, + SPELL_FREE_RAGECLAW = 55223, + + NPC_RAGECLAW = 29686 +}; + +struct TRINITY_DLL_DECL npc_drakuru_shacklesAI : public ScriptedAI +{ + npc_drakuru_shacklesAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + Unit* Rageclaw; + + void Reset() + { + Rageclaw = NULL; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + float x, y, z; + m_creature->GetClosePoint(x, y, z, m_creature->GetObjectSize() / 3, 0.1f); + + if (Unit* summon = m_creature->SummonCreature(NPC_RAGECLAW, x, y, z, + 0, TEMPSUMMON_DEAD_DESPAWN, 1000)) + { + Rageclaw = summon; + LockRageclaw(); + } + } + + void LockRageclaw() + { + m_creature->SetInFront(Rageclaw); + Rageclaw->SetInFront(m_creature); + + DoCast(Rageclaw, SPELL_LEFT_CHAIN, true); + DoCast(Rageclaw, SPELL_RIGHT_CHAIN, true); + } + + void UnlockRageclaw(Unit* pWho) + { + if (!pWho) + return; + + DoCast(Rageclaw, SPELL_FREE_RAGECLAW, true); + + m_creature->setDeathState(DEAD); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + { + if (pSpell->Id == SPELL_UNLOCK_SHACKLE) + { + if (Rageclaw) + UnlockRageclaw(pCaster); + else + m_creature->setDeathState(JUST_DIED); + } + } +}; + + +CreatureAI* GetAI_npc_drakuru_shackles(Creature* pCreature) +{ + return new npc_drakuru_shacklesAI (pCreature); +} + +/*#### +## npc_captured_rageclaw +####*/ + +enum eRageclaw +{ + SPELL_UNSHACKLED = 55085, + SPELL_KNEEL = 39656 +}; + +const char * SAY_RAGECLAW_1 = "I poop on you, trollses!"; +const char * SAY_RAGECLAW_2 = "ARRRROOOOGGGGAAAA!"; +const char * SAY_RAGECLAW_3 = "No more mister nice wolvar!"; + +#define SAY_RAGECLAW RAND(SAY_RAGECLAW_1,SAY_RAGECLAW_2,SAY_RAGECLAW_3) + +struct TRINITY_DLL_DECL npc_captured_rageclawAI : public ScriptedAI +{ + npc_captured_rageclawAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 DespawnTimer; + bool Despawn; + + void Reset() + { + Despawn = false; + DespawnTimer = 0; + m_creature->setFaction(35); + DoCast(m_creature, SPELL_KNEEL, true); // Little Hack for kneel - Thanks Illy :P + } + + void MoveInLineOfSight(Unit *who){} + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + { + if (pSpell->Id == SPELL_FREE_RAGECLAW) + { + m_creature->RemoveAurasDueToSpell(SPELL_LEFT_CHAIN); + + m_creature->RemoveAurasDueToSpell(SPELL_RIGHT_CHAIN); + + m_creature->RemoveAurasDueToSpell(SPELL_KNEEL); + + m_creature->setFaction(m_creature->GetCreatureInfo()->faction_H); + + DoCast(m_creature, SPELL_UNSHACKLED, true); + m_creature->MonsterSay(SAY_RAGECLAW, LANG_UNIVERSAL, NULL); + m_creature->GetMotionMaster()->MoveRandom(10); + + DespawnTimer = 10000; + Despawn = true; + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (UpdateVictim()) + { + DoMeleeAttackIfReady(); + return; + } + + if (!Despawn) + return; + + if (DespawnTimer <= uiDiff) + m_creature->DisappearAndDie(); + else DespawnTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_captured_rageclaw(Creature* pCreature) +{ + return new npc_captured_rageclawAI (pCreature); +} + +/*#### +## npc_gymer +####*/ + +#define GOSSIP_ITEM_G "I'm ready, Gymer. Let's go!" + +enum eGymer +{ + QUEST_STORM_KING_VENGEANCE = 12919, + SPELL_GYMER = 55568 +}; + +bool GossipHello_npc_gymer(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + + if (pPlayer->GetQuestStatus(QUEST_STORM_KING_VENGEANCE) == QUEST_STATUS_INCOMPLETE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_G, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(13640, pCreature->GetGUID()); + } + + return true; +} + +bool GossipSelect_npc_gymer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->CastSpell(pPlayer, SPELL_GYMER, true); + } + + return true; +} + +/*#### +## npc_gurgthock +####*/ + +enum eGurgthock +{ + QUEST_AMPHITHEATER_ANGUISH_TUSKARRMAGEDDON = 12935, + QUEST_AMPHITHEATER_ANGUISH_KORRAK_BLOODRAGER = 12936, + QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_2 = 12954, + QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_1 = 12932, + QUEST_AMPHITHEATER_ANGUISH_MAGNATAUR = 12933, + + NPC_ORINOKO_TUSKBREAKER = 30020, + NPC_KORRAK_BLOODRAGER = 30023, + NPC_YGGDRAS = 30014, + NPC_STINKBEARD = 30017, + + SAY_QUEST_ACCEPT_TUSKARRMAGEDON = -1571031, + SAY_QUEST_ACCEPT_KORRAK_1 = -1571033, + SAY_QUEST_ACCEPT_KORRAK_2 = -1571034, + SAY_QUEST_ACCEPT_MAGNATAUR = -1571035 +}; + +const Position SpawnPosition[] = +{ + {5757.765137, -2945.161133, 286.276672, 5.156380}, + {5762.054199, -2954.385010, 273.826955, 5.108289} //yggdras +}; + +struct TRINITY_DLL_DECL npc_gurgthockAI : public ScriptedAI +{ + npc_gurgthockAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pSummon = NULL; + } + + Unit* pSummon; + + std::list<uint64> SummonList; + + uint32 uiTimer; + uint32 uiPhase; + uint32 uiRemoveFlagTimer; + uint32 uiQuest; + + bool bEventInProgress; + bool bRemoveFlag; + + void Reset() + { + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + uiTimer = 0; + uiPhase = 0; + uiQuest = 0; + uiRemoveFlagTimer = 5000; + bEventInProgress = false; + bRemoveFlag = false; + } + + void RemoveSummons() + { + if (SummonList.empty()) + return; + + bEventInProgress = false; + + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + for(std::list<uint64>::iterator itr = SummonList.begin(); itr != SummonList.end(); ++itr) + { + if (Creature* pTemp = (Creature*)Unit::GetUnit(*m_creature, *itr)) + if (pTemp) + pTemp->RemoveFromWorld(); + } + SummonList.clear(); + } + + void SetData(uint32 uiId, uint32 uiValue) + { + if (!bEventInProgress) + { + bEventInProgress = true; + bRemoveFlag = true; + switch(uiId) + { + case 1: + switch(uiValue) + { + case QUEST_AMPHITHEATER_ANGUISH_TUSKARRMAGEDDON: + DoScriptText(SAY_QUEST_ACCEPT_TUSKARRMAGEDON, m_creature); + uiPhase = 1; + uiTimer = 4000; + break; + case QUEST_AMPHITHEATER_ANGUISH_KORRAK_BLOODRAGER: + DoScriptText(SAY_QUEST_ACCEPT_KORRAK_1, m_creature); + uiPhase = 3; + uiTimer = 3000; + break; + case QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_2: + case QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_1: + uiPhase = 6; + uiTimer = 3000; + break; + case QUEST_AMPHITHEATER_ANGUISH_MAGNATAUR: + uiTimer = 5000; + uiPhase = 7; + break; + } + break; + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (!bEventInProgress) + return; + + ScriptedAI::UpdateAI(uiDiff); + + if (bRemoveFlag) + { + if (uiRemoveFlagTimer <= uiDiff) + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + bRemoveFlag = false; + uiRemoveFlagTimer = 5000; + } else uiRemoveFlagTimer -= uiDiff; + } + + if (uiPhase) + { + if (uiTimer <= uiDiff) + { + switch(uiPhase) + { + case 1: + pSummon = m_creature->SummonCreature(NPC_ORINOKO_TUSKBREAKER, SpawnPosition[0], TEMPSUMMON_CORPSE_DESPAWN, 1000); + uiPhase = 2; + uiTimer = 4000; + break; + case 2: + if (pSummon) + pSummon->GetMotionMaster()->MoveJump(5776.319824, -2981.005371, 273.100037, 10.0f, 20.0f); + uiPhase = 0; + pSummon = NULL; + break; + case 3: + DoScriptText(SAY_QUEST_ACCEPT_KORRAK_2, m_creature); + uiTimer = 3000; + uiPhase = 4; + break; + case 4: + pSummon = m_creature->SummonCreature(NPC_KORRAK_BLOODRAGER, SpawnPosition[0], TEMPSUMMON_CORPSE_DESPAWN, 1000); + uiTimer = 3000; + uiPhase = 0; + break; + case 6: + m_creature->SummonCreature(NPC_YGGDRAS, SpawnPosition[1], TEMPSUMMON_CORPSE_DESPAWN, 1000); + uiPhase = 0; + break; + case 7: + DoScriptText(SAY_QUEST_ACCEPT_MAGNATAUR, m_creature); + uiTimer = 3000; + uiPhase = 8; + break; + case 8: + m_creature->SummonCreature(NPC_STINKBEARD, SpawnPosition[0], TEMPSUMMON_CORPSE_DESPAWN, 1000); + uiPhase = 0; + break; + } + } else uiTimer -= uiDiff; + } + } + + void JustSummoned(Creature* pSummon) + { + SummonList.push_back(pSummon->GetGUID()); + } + + void SummonedCreatureDespawn(Creature* pSummon) + { + if (bEventInProgress) + bEventInProgress = false; + + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + } +}; + +bool QuestAccept_npc_gurgthock(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + switch (pQuest->GetQuestId()) + { + case QUEST_AMPHITHEATER_ANGUISH_TUSKARRMAGEDDON: + pCreature->AI()->SetData(1, pQuest->GetQuestId()); + break; + case QUEST_AMPHITHEATER_ANGUISH_KORRAK_BLOODRAGER: + pCreature->AI()->SetData(1, pQuest->GetQuestId()); + break; + case QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_2: + case QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_1: + pCreature->AI()->SetData(1, pQuest->GetQuestId()); + break; + case QUEST_AMPHITHEATER_ANGUISH_MAGNATAUR: + pCreature->AI()->SetData(1, pQuest->GetQuestId()); + break; + } + return false; +} + +CreatureAI* GetAI_npc_gurgthock(Creature* pCreature) +{ + return new npc_gurgthockAI(pCreature); +} + +/*#### +## npc_orinoko_tuskbreaker +####*/ + +enum eOrinokoTuskbreaker +{ + SPELL_BATTLE_SHOUT = 32064, + SPELL_FISHY_SCENT = 55937, + SPELL_IMPALE = 55929, + SPELL_SUMMON_WHISKER = 55946, + + NPC_WHISKER = 30113, + NPC_HUNGRY_PENGUIN = 30110, + + SAY_CALL_FOR_HELP = -1571032 +}; + +struct TRINITY_DLL_DECL npc_orinoko_tuskbreakerAI : public ScriptedAI +{ + npc_orinoko_tuskbreakerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetReactState(REACT_PASSIVE); + pAffected = NULL; + pWhisker = NULL; + } + + bool bSummoned; + bool bBattleShout; + bool bFishyScent; + + uint32 uiBattleShoutTimer; + uint32 uiFishyScentTimer; + + Unit* pAffected; + Creature* pWhisker; + + void Reset() + { + bSummoned = false; + bBattleShout = false; + bFishyScent = false; + uiBattleShoutTimer = 0; + uiFishyScentTimer = 20000; + } + + void EnterEvadeMode() + { + if (pWhisker) + pWhisker->RemoveFromWorld(); + + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->RemoveSummons(); + } + + void MovementInform(uint32 uiType, uint32 uiId) + { + if (uiType != POINT_MOTION_TYPE) + return; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetReactState(REACT_AGGRESSIVE); + m_creature->SetHomePosition(m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(), 0); + uiBattleShoutTimer = 7000; + } + + void EnterCombat(Unit* pWho) + { + DoCast(pWho, SPELL_IMPALE); + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + if (!bBattleShout && uiBattleShoutTimer <= uiDiff) + { + DoCast(m_creature, SPELL_BATTLE_SHOUT); + bBattleShout = true; + } else uiBattleShoutTimer -= uiDiff; + + if (uiFishyScentTimer <= uiDiff) + { + if (pAffected = SelectUnit(SELECT_TARGET_RANDOM,0)) + DoCast(pAffected, SPELL_FISHY_SCENT); + uiFishyScentTimer = 20000; + } else uiFishyScentTimer -= uiDiff; + + if (!bSummoned && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50) + { + DoScriptText(SAY_CALL_FOR_HELP ,m_creature); + //DoCast(m_creature->getVictim(), SPELL_SUMMON_WHISKER); petai is not working correctly??? + pWhisker = m_creature->SummonCreature(NPC_WHISKER, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); + bSummoned = true; + } + + DoMeleeAttackIfReady(); + } + + void JustSummoned(Creature* pSummon) + { + switch(pSummon->GetEntry()) + { + case NPC_WHISKER: + pSummon->AI()->AttackStart(m_creature->getVictim()); + break; + case NPC_HUNGRY_PENGUIN: + if (pAffected && pAffected->isAlive()) + pSummon->AI()->AttackStart(pAffected); + break; + } + } + + void JustDied(Unit* pKiller) + { + if (pWhisker) + pWhisker->RemoveFromWorld(); + + if (pKiller->GetTypeId() == TYPEID_PLAYER) + CAST_PLR(pKiller)->GroupEventHappens(QUEST_AMPHITHEATER_ANGUISH_TUSKARRMAGEDDON, CAST_PLR(pKiller)); + + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->bEventInProgress = false; + } +}; + +CreatureAI* GetAI_npc_orinoko_tuskbreaker(Creature* pCreature) +{ + return new npc_orinoko_tuskbreakerAI(pCreature); +} + +/*#### +## npc_korrak_bloodrager +####*/ + +enum eKorrakBloodrager +{ + SPELL_GROW = 55948, + SPELL_CHARGE = 24193, + SPELL_UPPERCUT = 30471, + SPELL_ENRAGE = 42745 +}; + +struct TRINITY_DLL_DECL npc_korrak_bloodragerAI : public npc_escortAI +{ + npc_korrak_bloodragerAI(Creature* pCreature) : npc_escortAI(pCreature) + { + Start(true,true, 0, NULL); + SetDespawnAtEnd(false); + } + + uint32 uiChargeTimer; + uint32 uiUppercutTimer; + + bool bEnrage; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetReactState(REACT_PASSIVE); + uiChargeTimer = 15000; + uiUppercutTimer = 12000; + bEnrage = false; + } + + void EnterEvadeMode() + { + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->RemoveSummons(); + } + + void WaypointReached(uint32 uiI) + { + switch(uiI) + { + case 6: + m_creature->SetHomePosition(m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(), 0); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetReactState(REACT_AGGRESSIVE); + break; + } + } + + void EnterCombat(Unit* pWho) + { + DoCast(m_creature, SPELL_GROW); + } + + void UpdateAI(const uint32 uiDiff) + { + npc_escortAI::UpdateAI(uiDiff); + + if (!UpdateVictim()) + return; + + if (uiUppercutTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_NEAREST, 0)) + DoCast(pTarget, SPELL_UPPERCUT); + uiUppercutTimer = 12000; + } else uiUppercutTimer -= uiDiff; + + if (uiChargeTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_FARTHEST, 0)) + DoCast(pTarget, SPELL_CHARGE); + uiChargeTimer = 15000; + } else uiChargeTimer -= uiDiff; + + if (!bEnrage && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 20) + { + DoCast(m_creature, SPELL_ENRAGE); + bEnrage = true; + } + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + if (pKiller->GetTypeId() == TYPEID_PLAYER) + CAST_PLR(pKiller)->GroupEventHappens(QUEST_AMPHITHEATER_ANGUISH_KORRAK_BLOODRAGER, CAST_PLR(pKiller)); + + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->bEventInProgress = false; + } +}; + +CreatureAI* GetAI_npc_korrak_bloodrager(Creature* pCreature) +{ + return new npc_korrak_bloodragerAI(pCreature); +} + +/*#### +## npc_yggdras +####*/ + +enum eYggdras +{ + SPELL_CLEAVE = 40504, + SPELL_CORRODE_FLESH = 57076, + SPELL_JORMUNGAR_SPAWN = 55859 +}; + +struct TRINITY_DLL_DECL npc_yggdrasAI : public ScriptedAI +{ + npc_yggdrasAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + uint32 uiCleaveTimer; + uint32 uiCorrodeFleshTimer; + + void Reset() + { + uiCleaveTimer = 12000; + uiCorrodeFleshTimer = 18000; + } + + void EnterEvadeMode() //If you lose the combat, then the npc go away + { + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->RemoveSummons(); + } + + void EnterCombat(Unit* pWho) + { + DoCast(m_creature, SPELL_GROW); + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + if (uiCleaveTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + uiCleaveTimer = 12000; + } else uiCleaveTimer -= uiDiff; + + if (uiCorrodeFleshTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CHARGE); + uiCorrodeFleshTimer = 18000; + } else uiCorrodeFleshTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + if (pKiller->GetTypeId() == TYPEID_PLAYER) + { + CAST_PLR(pKiller)->GroupEventHappens(QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_1, CAST_PLR(pKiller)); + CAST_PLR(pKiller)->GroupEventHappens(QUEST_AMPHITHEATER_ANGUISH_YGGDRAS_2, CAST_PLR(pKiller)); + } + + for (uint8 i = 0; i < 2; ++i) + DoCast(pKiller, SPELL_JORMUNGAR_SPAWN, true); + + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->bEventInProgress = false; + } +}; + +CreatureAI* GetAI_npc_yggdras(Creature* pCreature) +{ + return new npc_yggdrasAI(pCreature); +} + +enum eStinkbeard +{ + SPELL_ENRAGE_STINKBEARD = 50420, + SPELL_KNOCK_AWAY = 31389, + SPELL_STINKY_BEARD = 55867, + SPELL_THUNDERBLADE = 55866, + SPELL_THUNDERCLAP = 15588 +}; + +/*#### +## npc_stinkbeard +####*/ + +struct TRINITY_DLL_DECL npc_stinkbeardAI : public npc_escortAI +{ + npc_stinkbeardAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetReactState(REACT_PASSIVE); + Start(true,true, 0, NULL); + SetDespawnAtEnd(false); + } + + uint32 uiThunderclapTimer; + uint32 uiKnockAwayTimer; + uint32 uiStinkyBeardTimer; + + bool bEnrage; + + void Reset() + { + DoCast(m_creature, SPELL_THUNDERBLADE); + uiThunderclapTimer = 5000; + uiKnockAwayTimer = 10000; + uiStinkyBeardTimer = 15000; + bEnrage = false; + } + + void EnterEvadeMode() + { + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->RemoveSummons(); + } + + void WaypointReached(uint32 uiI) + { + switch(uiI) + { + case 7: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetReactState(REACT_AGGRESSIVE); + m_creature->SetHomePosition(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation()); + break; + } + } + + void UpdateAI(const uint32 uiDiff) + { + npc_escortAI::UpdateAI(uiDiff); + + if (!UpdateVictim()) + return; + + if (uiThunderclapTimer <= uiDiff) + { + DoCastAOE(SPELL_THUNDERCLAP); + uiThunderclapTimer = 5000; + } else uiThunderclapTimer -= uiDiff; + + if (uiKnockAwayTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget, SPELL_KNOCK_AWAY); + } + uiKnockAwayTimer = 10000; + } else uiKnockAwayTimer -= uiDiff; + + if (uiStinkyBeardTimer <= uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + if (pTarget && pTarget->isAlive()) + DoCast(pTarget, SPELL_STINKY_BEARD); + } + uiStinkyBeardTimer = 15000; + } else uiStinkyBeardTimer -= uiDiff; + + if (!bEnrage && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 20) + { + DoCast(m_creature, SPELL_ENRAGE_STINKBEARD); + bEnrage = true; + } + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) + { + if (m_creature->isSummon()) + if (Unit* pSummoner = CAST_SUM(m_creature)->GetSummoner()) + CAST_AI(npc_gurgthockAI,CAST_CRE(pSummoner)->AI())->bEventInProgress = false; + + if (pKiller->GetTypeId() == TYPEID_PLAYER) + CAST_PLR(pKiller)->GroupEventHappens(QUEST_AMPHITHEATER_ANGUISH_MAGNATAUR, CAST_PLR(pKiller)); + } +}; + +CreatureAI* GetAI_npc_stinkbeard(Creature* pCreature) +{ + return new npc_stinkbeardAI(pCreature); +} + +/*#### +## npc_released_offspring_harkoa +####*/ + +struct TRINITY_DLL_DECL npc_released_offspring_harkoaAI : public ScriptedAI +{ + npc_released_offspring_harkoaAI(Creature* pCreature) : ScriptedAI(pCreature) {} + + void Reset() + { + float x, y, z; + m_creature->GetClosePoint(x, y, z, m_creature->GetObjectSize() / 3, 25.0f); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z); + } + + void MovementInform(uint32 uiType, uint32 uiId) + { + if (uiType != POINT_MOTION_TYPE) + return; + m_creature->DisappearAndDie(); + } +}; + +CreatureAI* GetAI_npc_released_offspring_harkoa(Creature* pCreature) +{ + return new npc_released_offspring_harkoaAI(pCreature); +} + +void AddSC_zuldrak() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_drakuru_shackles"; + newscript->GetAI = &GetAI_npc_drakuru_shackles; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_captured_rageclaw"; + newscript->GetAI = &GetAI_npc_captured_rageclaw; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_gymer"; + newscript->pGossipHello = &GossipHello_npc_gymer; + newscript->pGossipSelect = &GossipSelect_npc_gymer; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_gurgthock"; + newscript->GetAI = &GetAI_npc_gurgthock; + newscript->pQuestAccept = &QuestAccept_npc_gurgthock; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_orinoko_tuskbreaker"; + newscript->GetAI = &GetAI_npc_orinoko_tuskbreaker; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_korrak_bloodrager"; + newscript->GetAI = &GetAI_npc_korrak_bloodrager; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_yggdras"; + newscript->GetAI = &GetAI_npc_yggdras; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_stinkbeard"; + newscript->GetAI = &GetAI_npc_stinkbeard; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_released_offspring_harkoa"; + newscript->GetAI = &GetAI_npc_released_offspring_harkoa; + newscript->RegisterSelf(); +} |
