diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_ionar.cpp | 417 | ||||
| -rw-r--r-- | src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_volkhan.cpp | 520 |
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(); } |
