diff options
| author | Kudlaty <none@none> | 2009-08-13 00:57:55 +0200 |
|---|---|---|
| committer | Kudlaty <none@none> | 2009-08-13 00:57:55 +0200 |
| commit | 57d2f5e7d2cb2475de5fe1d1ee8d31ab5fe80558 (patch) | |
| tree | 6b8e92414295e4f7301bc5f387513abce125c425 /src | |
| parent | ba91c78ceb428129c366d69b0057e68dcfa86fd5 (diff) | |
Merge [SD2]
r1205 Check pointer for NULL before use. - skip
r1206 Remove conflicting MovePoint and let creature fully use MoveChase for summoned in hyjal. - skip
r1207 Add instance bosses for map 602. Scripts can not be considered complete and must be tested further when databases has better values for misc (such as creature factions, health/mana etc)
r1208 Added handling of doors for second last boss in BRD. Apply sd2 code style and clean up last boss(es) scripts and spells. Patch by Turok - skip
r1209 Merge scripts for last bosses in BRD to one source file. Also not store pointers to creatures and create only when needed.
Added creation of portal if Moria survive and Emperor is dead. - skip
r1210 Clean up and add script for second boss in SWP. Patch by paytheo (original by ckegg) - skip
note: in previous merge should be r120x insted of r200x. Sorry for that
--HG--
branch : trunk
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(); } |
