aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_ionar.cpp417
-rw-r--r--src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_volkhan.cpp520
2 files changed, 793 insertions, 144 deletions
diff --git a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_ionar.cpp b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_ionar.cpp
index edbf1e58522..6ac58c4aefd 100644
--- a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_ionar.cpp
+++ b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_ionar.cpp
@@ -1,101 +1,385 @@
-/* Script Data Start
-SDName: Boss ionar
-SDAuthor: LordVanMartin
-SD%Complete:
-SDComment:
-SDCategory:
-Script Data End */
-
-/*** SQL START ***
-update creature_template set scriptname = 'boss_ionar' where entry = '';
-*** SQL END ***/
+/* 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 "precompiled.h"
+#include "def_halls_of_lightning.h"
+
+enum
+{
+ 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,
-//Spells
-#define SPELL_BALL_LIGHTNING 52780
-#define SPELL_BALL_LIGHTNING_2 59800
-#define SPELL_DISPERSE 52770 //Disperse into Sparks of Ionar.
-#define SPELL_STATIC_OVERLOAD 52658 //Effect Apply Aura: Periodic Trigger Interval: 2 seconds Spell 52659
-#define SPELL_STATIC_OVERLOAD_2 52658 //Effect Apply Aura: Periodic Trigger Interval: 2 seconds Spell 59796
-
-//Spark of Ionar spells
-#define NPC_SPARK_OF_IONAR 28962 //invulnerable
-#define SPELL_ARCING_BURN 52617
-#define SPELL_ARCING_BURN_2 59834
-
-//Yell
-#define SAY_AGGRO -1602008
-#define SAY_SLAY_1 -1602009
-#define SAY_SLAY_2 -1602010
-#define SAY_SLAY_3 -1602011
-#define SAY_DEATH -1602012
-#define SAY_SPLIT_1 -1602013
-#define SAY_SPLIT_2 -1602014
-
-//he does "morph" every about 25% into 4 sparks of ionar that chase people around, they r slow and easily avoidable.
+ MAX_SPARKS = 5,
+ POINT_CALLBACK = 0
+};
+
+/*######
+## Boss Ionar
+######*/
struct TRINITY_DLL_DECL boss_ionarAI : public ScriptedAI
{
- boss_ionarAI(Creature *c) : ScriptedAI(c) {}
+ boss_ionarAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
+ m_bIsHeroic = pCreature->GetMap()->IsHeroic();
+ Reset();
+ }
+
+ ScriptedInstance* m_pInstance;
+
+ std::list<uint64> m_lSparkGUIDList;
+
+ bool m_bIsHeroic;
+
+ bool m_bIsSplitPhase;
+ uint32 m_uiSplit_Timer;
+ uint32 m_uiSparkAtHomeCount;
- void Reset() {}
- void EnterCombat(Unit* who)
+ uint32 m_uiStaticOverload_Timer;
+ uint32 m_uiBallLightning_Timer;
+
+ uint32 m_uiHealthAmountModifier;
+
+ void Reset()
{
- DoScriptText(SAY_AGGRO, m_creature);
+ 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 AttackStart(Unit* who) {}
- void MoveInLineOfSight(Unit* who) {}
- void UpdateAI(const uint32 diff)
+
+ void AttackedBy(Unit* pAttacker)
{
- //Return since we have no target
- if(!UpdateVictim())
+ if (m_creature->getVictim())
return;
- DoMeleeAttackIfReady();
+ if (m_creature->GetVisibility() == VISIBILITY_OFF)
+ return;
+
+ AttackStart(pAttacker);
}
+
+ void Aggro(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)
{
- if(victim == m_creature)
- return;
switch(rand()%3)
{
- case 0: DoScriptText(SAY_SLAY_1, m_creature);break;
- case 1: DoScriptText(SAY_SLAY_2, m_creature);break;
- case 2: DoScriptText(SAY_SLAY_3, m_creature);break;
+ case 0: DoScriptText(SAY_SLAY_1, m_creature); break;
+ case 1: DoScriptText(SAY_SLAY_2, m_creature); break;
+ case 2: DoScriptText(SAY_SLAY_3, m_creature); break;
}
}
-};
-struct TRINITY_DLL_DECL npc_spark_of_ionarAI : public ScriptedAI
-{
- npc_spark_of_ionarAI(Creature *c) : ScriptedAI(c) {}
+ void DespawnSpark()
+ {
+ if (m_lSparkGUIDList.empty())
+ return;
+
+ for(std::list<uint64>::iterator itr = m_lSparkGUIDList.begin(); itr != m_lSparkGUIDList.end(); ++itr)
+ {
+ if (Creature* pTemp = (Creature*)Unit::GetUnit(*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 = (Creature*)Unit::GetUnit(*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 Reset() {}
- void EnterCombat(Unit* who) {}
- void AttackStart(Unit* who) {}
- void MoveInLineOfSight(Unit* who) {}
- void UpdateAI(const uint32 diff)
+ void RegisterSparkAtHome()
{
+ ++m_uiSparkAtHomeCount;
+ }
+
+ void JustSummoned(Creature* pSummoned)
+ {
+ if (pSummoned->GetEntry() == NPC_SPARK_OF_IONAR)
+ {
+ pSummoned->CastSpell(pSummoned, m_bIsHeroic ? SPELL_SPARK_VISUAL_TRIGGER_H : SPELL_SPARK_VISUAL_TRIGGER_N, 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);
+ m_creature->CastSpell(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())
+ if (!UpdateVictim())
return;
+ if (m_uiStaticOverload_Timer < uiDiff)
+ {
+ if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0))
+ DoCast(pTarget, m_bIsHeroic ? SPELL_STATIC_OVERLOAD_H : SPELL_STATIC_OVERLOAD_N);
+
+ m_uiStaticOverload_Timer = 5000 + rand()%1000;
+ }
+ else
+ m_uiStaticOverload_Timer -= uiDiff;
+
+ if (m_uiBallLightning_Timer < uiDiff)
+ {
+ DoCast(m_creature->getVictim(), m_bIsHeroic ? SPELL_BALL_LIGHTNING_H : SPELL_BALL_LIGHTNING_N);
+ 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;
+
+ switch(rand()%2)
+ {
+ case 0: DoScriptText(SAY_SPLIT_1, m_creature); break;
+ case 1: DoScriptText(SAY_SPLIT_2, m_creature); break;
+ }
+
+ if (m_creature->IsNonMeleeSpellCasted(false))
+ m_creature->InterruptNonMeleeSpells(false);
+
+ DoCast(m_creature, SPELL_DISPERSE);
+ }
+
DoMeleeAttackIfReady();
}
- void JustDied(Unit* killer) {}
};
-CreatureAI* GetAI_npc_spark_of_ionar(Creature *_Creature)
+CreatureAI* GetAI_boss_ionar(Creature* pCreature)
+{
+ return new boss_ionarAI(pCreature);
+}
+
+bool EffectDummyCreature_boss_ionar(Unit* pCaster, uint32 uiSpellId, uint32 uiEffIndex, Creature* pCreatureTarget)
{
- return new npc_spark_of_ionarAI (_Creature);
+ //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);
+
+ //TODO: remove this line of hack when summon implemented
+ pCreatureTarget->SummonCreature(NPC_SPARK_OF_IONAR, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000);
+ }
+
+ 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;
}
-CreatureAI* GetAI_boss_ionar(Creature *_Creature)
+
+/*######
+## mob_spark_of_ionar
+######*/
+
+struct TRINITY_DLL_DECL mob_spark_of_ionarAI : public ScriptedAI
+{
+ mob_spark_of_ionarAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
+ Reset();
+ }
+
+ 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 boss_ionarAI (_Creature);
+ return new mob_spark_of_ionarAI(pCreature);
}
void AddSC_boss_ionar()
@@ -103,12 +387,13 @@ void AddSC_boss_ionar()
Script *newscript;
newscript = new Script;
- newscript->Name="boss_ionar";
+ newscript->Name = "boss_ionar";
newscript->GetAI = &GetAI_boss_ionar;
+ newscript->pEffectDummyCreature = &EffectDummyCreature_boss_ionar;
newscript->RegisterSelf();
newscript = new Script;
- newscript->Name="spark_of_ionar";
- newscript->GetAI = &GetAI_npc_spark_of_ionar;
+ newscript->Name = "mob_spark_of_ionar";
+ newscript->GetAI = &GetAI_mob_spark_of_ionar;
newscript->RegisterSelf();
}
diff --git a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_volkhan.cpp b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_volkhan.cpp
index 7c76164a63e..c3d07e42043 100644
--- a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_volkhan.cpp
+++ b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_volkhan.cpp
@@ -1,115 +1,473 @@
-/* Script Data Start
-SDName: Boss volkhan
-SDAuthor: LordVanMartin
-SD%Complete:
-SDComment:
-SDCategory:
-Script Data End */
-
-/*** SQL START ***
-update creature_template set scriptname = 'boss_volkhan' where entry = '';
-*** SQL END ***/
+/* 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 "precompiled.h"
+#include "def_halls_of_lightning.h"
+
+enum
+{
+ 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
+};
-//Spells
-#define SPELL_HEAT 52387
-#define SPELL_HEAT_2 59528
-#define SPELL_SHATTERING_STOMP 52237
-#define SPELL_SHATTERING_STOMP_2 59529
-#define SPELL_TEMPER 52238 //Dummy ---> Strikes Volkhan's Anvil, creating a number of Molten Golems.
-
-#define NPC_VOLKHANS_ANVIL 28823
-#define MOB_MOLTEN_GOLEM 28695
-
-//Yells
-#define SAY_AGGRO -1602028
-#define SAY_SLAY_1 -1602029
-#define SAY_SLAY_2 -1602030
-#define SAY_SLAY_3 -1602031
-#define SAY_DEATH -1602032
-#define SAY_STOMP_1 -1602033
-#define SAY_STOMP_2 -1602034
-#define SAY_FORGE_1 -1602035
-#define SAY_FORGE_2 -1602036
+/*######
+## Boss Volkhan
+######*/
struct TRINITY_DLL_DECL boss_volkhanAI : public ScriptedAI
{
- boss_volkhanAI(Creature *c) : ScriptedAI(c) {}
+ boss_volkhanAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
+ m_bIsHeroic = pCreature->GetMap()->IsHeroic();
+ Reset();
+ }
+
+ ScriptedInstance* m_pInstance;
- void Reset() {}
- void EnterCombat(Unit* who)
+ std::list<uint64> m_lGolemGUIDList;
+
+ bool m_bIsHeroic;
+ bool m_bHasTemper;
+ bool m_bIsStriking;
+ bool m_bCanShatterGolem;
+
+ 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;
+
+ m_uiHealthAmountModifier = 1;
+
+ DespawnGolem();
+ m_lGolemGUIDList.clear();
+
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_VOLKHAN, NOT_STARTED);
+ }
+
+ void Aggro(Unit* pWho)
{
DoScriptText(SAY_AGGRO, m_creature);
+
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_VOLKHAN, IN_PROGRESS);
}
- void AttackStart(Unit* who) {}
- void MoveInLineOfSight(Unit* who) {}
- void UpdateAI(const uint32 diff)
+
+ void AttackStart(Unit* pWho)
{
- //Return since we have no target
- if(!UpdateVictim())
- return;
+ if (m_creature->Attack(pWho, true))
+ {
+ m_creature->AddThreat(pWho, 0.0f);
+ m_creature->SetInCombatWith(pWho);
+ pWho->SetInCombatWith(m_creature);
- DoMeleeAttackIfReady();
+ if (!m_bHasTemper)
+ m_creature->GetMotionMaster()->MoveChase(pWho);
+ }
}
- void JustDied(Unit* killer)
+
+ void JustDied(Unit* pKiller)
{
DoScriptText(SAY_DEATH, m_creature);
+ DespawnGolem();
+
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_VOLKHAN, DONE);
}
- void KilledUnit(Unit *victim)
+
+ void KilledUnit(Unit* pVictim)
{
- if(victim == m_creature)
- return;
switch(rand()%3)
{
- case 0: DoScriptText(SAY_SLAY_1, m_creature);break;
- case 1: DoScriptText(SAY_SLAY_2, m_creature);break;
- case 2: DoScriptText(SAY_SLAY_3, m_creature);break;
+ case 0: DoScriptText(SAY_SLAY_1, m_creature); break;
+ case 1: DoScriptText(SAY_SLAY_2, m_creature); break;
+ case 2: DoScriptText(SAY_SLAY_3, m_creature); break;
+ }
+ }
+
+ void DespawnGolem()
+ {
+ if (m_lGolemGUIDList.empty())
+ return;
+
+ for(std::list<uint64>::iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr)
+ {
+ if (Creature* pTemp = (Creature*)Unit::GetUnit(*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 = (Creature*)Unit::GetUnit(*m_creature, *itr))
+ {
+ // only shatter brittle golems
+ if (pTemp->isAlive() && pTemp->GetEntry() == NPC_BRITTLE_GOLEM)
+ pTemp->CastSpell(pTemp, m_bIsHeroic ? SPELL_SHATTER_H : SPELL_SHATTER_N, false);
+ }
}
}
+
+ 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, m_bIsHeroic ? SPELL_HEAT_H : SPELL_HEAT_N, 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?
+
+ switch(rand()%2)
+ {
+ case 0: DoScriptText(SAY_STOMP_1, m_creature); break;
+ case 1: DoScriptText(SAY_STOMP_2, m_creature); break;
+ }
+
+ DoCast(m_creature, m_bIsHeroic ? SPELL_SHATTERING_STOMP_H : SPELL_SHATTERING_STOMP_N);
+
+ 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);
+
+ switch(rand()%2)
+ {
+ case 0: DoScriptText(SAY_FORGE_1, m_creature); break;
+ case 1: DoScriptText(SAY_FORGE_2, m_creature); break;
+ }
+
+ m_bHasTemper = true;
+
+ m_creature->CastSpell(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);
+
+ //TODO: remove this line of hack when summon effect implemented
+ pCreatureTarget->SummonCreature(NPC_MOLTEN_GOLEM,
+ pCaster->GetPositionX(), pCaster->GetPositionY(), pCaster->GetPositionZ(), 0.0f,
+ TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
+ }
+
+ //always return true when we are handling this spell and effect
+ return true;
+ }
+
+ return false;
+}
+
/*######
-## Mob Molten Golem
+## 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;
+
+ 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();
+
+ ((Creature*)pCaster)->GetMap()->CreatureRelocation((Creature*)pCaster, fX, fY, fZ, pCreatureTarget->GetOrientation());
+ ((Creature*)pCaster)->SendMonsterMove(fX, fY, fZ, 0, ((Creature*)pCaster)->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
######*/
-//Molten Golem Spells
-#define SPELL_BLAST_WAVE 23113
-#define SPELL_IMMOLATION_STRIKE 52433
-#define SPELL_IMMOLATION_STRIKE_2 59530
-//Effect #1 Apply Aura: Periodic Damage, value: 900 every 3 seconds
-//Effect #2 School Damage (Fire), value: 900
-//Effect #3 Script Effect
-#define SPELL_SHATTER 52429
-//Effect #1 School Damage (Physical), value: 9250 to 10750, radius: 10 yards
-//Effect #2 Dummy, Server-side script
-#define SPELL_SHATTER_2
struct TRINITY_DLL_DECL mob_molten_golemAI : public ScriptedAI
{
- mob_molten_golemAI(Creature *c) : ScriptedAI(c) {}
+ mob_molten_golemAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
+ m_bIsHeroic = pCreature->GetMap()->IsHeroic();
+ Reset();
+ }
+
+ ScriptedInstance* m_pInstance;
+
+ bool m_bIsHeroic;
+ bool m_bIsFrozen;
+
+ uint32 m_uiBlast_Timer;
+ uint32 m_uiDeathDelay_Timer;
+ uint32 m_uiImmolation_Timer;
- void Reset() {}
- void EnterCombat(Unit* who) {}
- void AttackStart(Unit* who) {}
- void MoveInLineOfSight(Unit* who) {}
- void UpdateAI(const uint32 diff)
+ void Reset()
{
- //Return since we have no target
- if(!UpdateVictim())
+ 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 (m_bIsFrozen)
+ {
+ //workaround for now, brittled should be immune to any kind of attacks
+ uiDamage = 0;
+ return;
+ }
+
+ if (uiDamage > m_creature->GetHealth())
+ {
+ m_bIsFrozen = true;
+
+ if (m_creature->IsNonMeleeSpellCasted(false))
+ m_creature->InterruptNonMeleeSpells(false);
+
+ m_creature->RemoveAllAuras();
+ m_creature->AttackStop();
+
+ if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ m_creature->GetMotionMaster()->MovementExpired();
+
+ uiDamage = m_creature->GetHealth()-1;
+
+ m_creature->UpdateEntry(NPC_BRITTLE_GOLEM);
+ m_creature->SetHealth(1);
+ }
+ }
+
+ 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(), m_bIsHeroic ? SPELL_IMMOLATION_STRIKE_H : SPELL_IMMOLATION_STRIKE_N);
+ m_uiImmolation_Timer = 5000;
+ }
+ else
+ m_uiImmolation_Timer -= uiDiff;
+
DoMeleeAttackIfReady();
}
- void JustDied(Unit* killer) {}
};
-CreatureAI* GetAI_mob_molten_golem(Creature *_Creature)
-{
- return new mob_molten_golemAI (_Creature);
-}
-
-CreatureAI* GetAI_boss_volkhan(Creature *_Creature)
+CreatureAI* GetAI_mob_molten_golem(Creature* pCreature)
{
- return new boss_volkhanAI (_Creature);
+ return new mob_molten_golemAI(pCreature);
}
void AddSC_boss_volkhan()
@@ -117,12 +475,18 @@ void AddSC_boss_volkhan()
Script *newscript;
newscript = new Script;
- newscript->Name="boss_volkhan";
+ 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->Name = "mob_molten_golem";
newscript->GetAI = &GetAI_mob_molten_golem;
newscript->RegisterSelf();
}