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/ulduar | |
| 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/ulduar')
29 files changed, 6007 insertions, 0 deletions
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(); +} |
