aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp5
-rw-r--r--src/server/scripts/Kalimdor/CMakeLists.txt3
-rw-r--r--src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp703
-rw-r--r--src/server/scripts/Kalimdor/Firelands/firelands.h74
-rw-r--r--src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp59
5 files changed, 844 insertions, 0 deletions
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 570fe23478f..f8e58220a3e 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -332,6 +332,8 @@ void AddSC_instance_halls_of_origination();
void AddSC_boss_temple_guardian_anhuur();
void AddSC_boss_earthrager_ptah();
void AddSC_boss_anraphet();
+void AddSC_instance_firelands();
+void AddSC_boss_alysrazor();
void AddSC_ashenvale();
void AddSC_azshara();
@@ -991,6 +993,9 @@ void AddKalimdorScripts()
AddSC_boss_temple_guardian_anhuur();
AddSC_boss_earthrager_ptah();
AddSC_boss_anraphet();
+
+ AddSC_instance_firelands();
+ AddSC_boss_alysrazor();
#endif
}
diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt
index fc75444bda6..44f48a1c35e 100644
--- a/src/server/scripts/Kalimdor/CMakeLists.txt
+++ b/src/server/scripts/Kalimdor/CMakeLists.txt
@@ -116,6 +116,9 @@ set(scripts_STAT_SRCS
Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp
Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp
Kalimdor/HallsOfOrigination/boss_anraphet.cpp
+ Kalimdor/Firelands/instance_firelands.cpp
+ Kalimdor/Firelands/firelands.h
+ Kalimdor/Firelands/boss_alysrazor.cpp
)
message(" -> Prepared: Kalimdor")
diff --git a/src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp b/src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp
new file mode 100644
index 00000000000..e4ab2265027
--- /dev/null
+++ b/src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ObjectMgr.h"
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "MoveSplineInit.h"
+#include "Cell.h"
+#include "CellImpl.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
+#include "firelands.h"
+
+enum Texts
+{
+ // Egg Pile
+ EMOTE_CRACKING_EGGS = 0, // The Molten Eggs begin to crack and splinter!
+};
+
+enum Spells
+{
+ // Harbinger of Flame
+ SPELL_FIRE_IT_UP = 100093,
+ SPELL_FIEROBLAST_TRASH = 100094,
+ SPELL_FIEROCLAST_BARRAGE = 100095,
+ SPELL_FIRE_CHANNELING = 100109,
+
+ // Blazing Monstrosity
+ SPELL_RIDE_MONSTROSITY = 93970,
+ SPELL_SHARE_HEALTH_LEFT = 101502,
+ SPELL_SHARE_HEALTH_RIGHT = 101503,
+ SPELL_SLEEP_ULTRA_HIGH_PRIORITY = 99480,
+ SPELL_GENERIC_DUMMY_CAST = 100088,
+ SPELL_LEFT_SIDE_SMACK_L = 100076,
+ SPELL_RIGHT_SIDE_SMACK_L = 100078,
+ SPELL_HEAD_BONK_L = 100080,
+ SPELL_TICKLE_L = 100082,
+ SPELL_KNOCKBACK_RIGHT = 100084,
+ SPELL_KNOCKBACK_LEFT = 100085,
+ SPELL_KNOCKBACK_FORWARD = 100086,
+ SPELL_KNOCKBACK_BACK = 100087,
+ SPELL_HEAD_BONK_R = 100089,
+ SPELL_LEFT_SIDE_SMACK_R = 100090,
+ SPELL_RIGHT_SIDE_SMACK_R = 100091,
+ SPELL_TICKLE_R = 100092,
+ SPELL_MOLTEN_BARRAGE_EFFECT_L = 100071,
+ SPELL_MOLTEN_BARRAGE_LEFT = 100072,
+ SPELL_MOLTEN_BARRAGE_RIGHT = 100073,
+ SPELL_MOLTEN_BARRAGE_EFFECT_R = 100074,
+ SPELL_MOLTEN_BARRAGE_VISUAL = 100075,
+ SPELL_AGGRO_CLOSEST = 100462,
+ SPELL_INVISIBILITY_AND_STEALTH_DETECTION = 18950,
+
+ // Egg Pile
+ SPELL_SUMMON_SMOULDERING_HATCHLING = 100096,
+ SPELL_MOLTEN_EGG_TRASH_CALL_L = 100097,
+ SPELL_MOLTEN_EGG_TRASH_CALL_R = 100098,
+ SPELL_ALYSRAZOR_COSMETIC_EGG_XPLOSION = 100099,
+};
+
+#define SPELL_SHARE_HEALTH (me->GetEntry() == NPC_BLAZING_MONSTROSITY_LEFT ? SPELL_SHARE_HEALTH_LEFT : SPELL_SHARE_HEALTH_RIGHT)
+#define SPELL_MOLTEN_BARRAGE (me->GetEntry() == NPC_BLAZING_MONSTROSITY_LEFT ? SPELL_MOLTEN_BARRAGE_LEFT : SPELL_MOLTEN_BARRAGE_RIGHT)
+#define SPELL_MOLTEN_BARRAGE_EFFECT (me->GetEntry() == NPC_BLAZING_MONSTROSITY_LEFT ? SPELL_MOLTEN_BARRAGE_EFFECT_L : SPELL_MOLTEN_BARRAGE_EFFECT_R)
+
+enum Events
+{
+ // Blazing Monstrosity
+ EVENT_START_SPITTING = 1,
+ EVENT_CONTINUE_SPITTING = 2,
+
+ // Harbinger of Flame
+ EVENT_FIEROBLAST = 1,
+ EVENT_FIEROCLAST_BARRAGE = 2,
+
+ // Egg Pile
+ EVENT_SUMMON_SMOULDERING_HATCHLING = 1,
+};
+
+enum MiscData
+{
+ MODEL_INVISIBLE_STALKER = 11686,
+ ANIM_KIT_BIRD_WAKE = 1469,
+ ANIM_KIT_BIRD_TURN = 1473,
+};
+
+class RespawnEggEvent : public BasicEvent
+{
+ public:
+ explicit RespawnEggEvent(Creature* egg) : _egg(egg) { }
+
+ bool Execute(uint64 /*time*/, uint32 /*diff*/)
+ {
+ _egg->RestoreDisplayId();
+ return true;
+ }
+
+ private:
+ Creature* _egg;
+};
+
+class MoltenEggCheck
+{
+ public:
+ explicit MoltenEggCheck(Creature* pile) : _eggPile(pile) { }
+
+ bool operator()(Unit* object) const
+ {
+ if (object->GetEntry() != NPC_MOLTEN_EGG_TRASH)
+ return false;
+
+ if (object->GetDisplayId() != object->GetNativeDisplayId())
+ return false;
+
+ if (_eggPile->GetDistance2d(object) > 20.0f)
+ return false;
+
+ return true;
+ }
+
+ private:
+ Creature* _eggPile;
+};
+
+class TrashRespawnWorker
+{
+ public:
+ void operator()(Creature* creature) const
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_BLAZING_MONSTROSITY_LEFT:
+ case NPC_BLAZING_MONSTROSITY_RIGHT:
+ case NPC_EGG_PILE:
+ case NPC_HARBINGER_OF_FLAME:
+ case NPC_MOLTEN_EGG_TRASH:
+ if (!creature->isAlive())
+ creature->Respawn(true);
+ break;
+ case NPC_SMOULDERING_HATCHLING:
+ creature->DespawnOrUnsummon();
+ break;
+ }
+ }
+};
+
+static void AlysrazorTrashEvaded(Creature* creature)
+{
+ TrashRespawnWorker check;
+ Trinity::CreatureWorker<TrashRespawnWorker> worker(creature, check);
+ creature->VisitNearbyGridObject(SIZE_OF_GRIDS, worker);
+}
+
+class npc_harbinger_of_flame : public CreatureScript
+{
+ public:
+ npc_harbinger_of_flame() : CreatureScript("npc_harbinger_of_flame") { }
+
+ struct npc_harbinger_of_flameAI : public ScriptedAI
+ {
+ npc_harbinger_of_flameAI(Creature* creature) : ScriptedAI(creature)
+ {
+ }
+
+ void EnterCombat(Unit* /*target*/)
+ {
+ if (Creature* bird = ObjectAccessor::GetCreature(*me, me->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT)))
+ DoZoneInCombat(bird, 200.0f);
+
+ me->InterruptSpell(CURRENT_CHANNELED_SPELL);
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_FIEROBLAST, 1);
+ _events.ScheduleEvent(EVENT_FIEROCLAST_BARRAGE, 6000);
+ }
+
+ void JustReachedHome()
+ {
+ AlysrazorTrashEvaded(me);
+ }
+
+ void MoveInLineOfSight(Unit* unit)
+ {
+ if (me->isInCombat())
+ return;
+
+ if (!unit->isCharmedOwnedByPlayerOrPlayer())
+ return;
+
+ ScriptedAI::MoveInLineOfSight(unit);
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!me->isInCombat())
+ if (!me->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
+ if (Creature* fireBird = me->FindNearestCreature((me->GetHomePosition().GetPositionY() > -275.0f ? NPC_BLAZING_MONSTROSITY_LEFT : NPC_BLAZING_MONSTROSITY_RIGHT), 100.0f))
+ DoCast(fireBird, SPELL_FIRE_CHANNELING);
+
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_FIEROBLAST:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, false, -SPELL_RIDE_MONSTROSITY))
+ DoCast(target, SPELL_FIEROBLAST_TRASH);
+ _events.RescheduleEvent(EVENT_FIEROBLAST, 500); // cast time is longer, but thanks to UNIT_STATE_CASTING check it won't trigger more often (need this because this creature gets a stacking haste aura)
+ break;
+ case EVENT_FIEROCLAST_BARRAGE:
+ DoCastAOE(SPELL_FIEROCLAST_BARRAGE);
+ _events.ScheduleEvent(EVENT_FIEROCLAST_BARRAGE, urand(9000, 12000));
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ EventMap _events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_harbinger_of_flameAI(creature);
+ }
+};
+
+class npc_blazing_monstrosity : public CreatureScript
+{
+ public:
+ npc_blazing_monstrosity() : CreatureScript("npc_blazing_monstrosity") { }
+
+ struct npc_blazing_monstrosityAI : public PassiveAI
+ {
+ npc_blazing_monstrosityAI(Creature* creature) : PassiveAI(creature), _summons(creature)
+ {
+ }
+
+ void EnterEvadeMode()
+ {
+ _summons.DespawnAll();
+ _events.Reset();
+ PassiveAI::EnterEvadeMode();
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ _summons.DespawnAll();
+ _events.Reset();
+ }
+
+ void JustReachedHome()
+ {
+ AlysrazorTrashEvaded(me);
+ }
+
+ void EnterCombat(Unit* /*target*/)
+ {
+ DoZoneInCombat();
+ me->RemoveAurasDueToSpell(SPELL_SLEEP_ULTRA_HIGH_PRIORITY);
+ me->PlayOneShotAnimKit(ANIM_KIT_BIRD_WAKE);
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_START_SPITTING, 6000);
+ _events.ScheduleEvent(EVENT_CONTINUE_SPITTING, 9000);
+ }
+
+ void PassengerBoarded(Unit* passenger, int8 /*seat*/, bool apply)
+ {
+ if (!apply)
+ return;
+
+ // Our passenger is another vehicle (boardable by players)
+ DoCast(passenger, SPELL_SHARE_HEALTH, true);
+ passenger->setFaction(35);
+ passenger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+
+ // Hack to relocate vehicle on vehicle so exiting players are not moved under map
+ Movement::MoveSplineInit init(*passenger);
+ init.DisableTransportPathTransformations();
+ init.MoveTo(0.6654003f, 0.0f, 1.9815f);
+ init.SetFacing(0.0f);
+ init.Launch();
+ }
+
+ void JustSummoned(Creature* summon)
+ {
+ _summons.Summon(summon);
+ }
+
+ void SummonedCreatureDespawn(Creature* summon)
+ {
+ _summons.Despawn(summon);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_START_SPITTING:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, false, -SPELL_RIDE_MONSTROSITY))
+ DoCast(target, SPELL_MOLTEN_BARRAGE);
+ break;
+ case EVENT_CONTINUE_SPITTING:
+ DoCastAOE(SPELL_MOLTEN_BARRAGE_EFFECT);
+ if (Creature* egg = me->FindNearestCreature(NPC_EGG_PILE, 100.0f))
+ egg->AI()->DoAction(me->GetEntry());
+ break;
+ }
+ }
+ }
+
+ private:
+ SummonList _summons;
+ EventMap _events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_blazing_monstrosityAI(creature);
+ }
+};
+
+class npc_molten_barrage : public CreatureScript
+{
+ public:
+ npc_molten_barrage() : CreatureScript("npc_molten_barrage") { }
+
+ struct npc_molten_barrageAI : public NullCreatureAI
+ {
+ npc_molten_barrageAI(Creature* creature) : NullCreatureAI(creature)
+ {
+ }
+
+ void AttackStart(Unit* target)
+ {
+ if (target)
+ me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f, MOTION_SLOT_IDLE);
+ }
+
+ void IsSummonedBy(Unit* /*summoner*/)
+ {
+ DoCastAOE(SPELL_AGGRO_CLOSEST, true);
+ DoCast(me, SPELL_MOLTEN_BARRAGE_VISUAL);
+ DoCast(me, SPELL_INVISIBILITY_AND_STEALTH_DETECTION, true);
+ }
+
+ void MovementInform(uint32 movementType, uint32 /*pointId*/)
+ {
+ if (movementType != EFFECT_MOTION_TYPE)
+ return;
+
+ DoCastAOE(SPELL_AGGRO_CLOSEST);
+ me->ClearUnitState(UNIT_STATE_CANNOT_TURN);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_molten_barrageAI(creature);
+ }
+};
+
+class npc_egg_pile : public CreatureScript
+{
+ public:
+ npc_egg_pile() : CreatureScript("npc_egg_pile") { }
+
+ struct npc_egg_pileAI : public CreatureAI
+ {
+ npc_egg_pileAI(Creature* creature) : CreatureAI(creature)
+ {
+ }
+
+ void AttackStart(Unit* /*target*/) { }
+
+ void Reset()
+ {
+ me->SetReactState(REACT_PASSIVE);
+ _events.Reset();
+ _callHatchlingSpell = 0;
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ _events.Reset();
+ std::list<Creature*> eggs;
+ GetCreatureListWithEntryInGrid(eggs, me, NPC_MOLTEN_EGG_TRASH, 20.0f);
+ for (std::list<Creature*>::const_iterator itr = eggs.begin(); itr != eggs.end(); ++itr)
+ (*itr)->CastSpell(*itr, SPELL_ALYSRAZOR_COSMETIC_EGG_XPLOSION, TRIGGERED_FULL_MASK);
+
+ DoCast(me, SPELL_ALYSRAZOR_COSMETIC_EGG_XPLOSION, true);
+ }
+
+ void JustReachedHome()
+ {
+ AlysrazorTrashEvaded(me);
+ }
+
+ void DoAction(int32 const action)
+ {
+ if (action != NPC_BLAZING_MONSTROSITY_LEFT &&
+ action != NPC_BLAZING_MONSTROSITY_RIGHT)
+ return;
+
+ if (action == NPC_BLAZING_MONSTROSITY_LEFT)
+ Talk(EMOTE_CRACKING_EGGS);
+
+ _callHatchlingSpell = (action == NPC_BLAZING_MONSTROSITY_LEFT) ? SPELL_MOLTEN_EGG_TRASH_CALL_L : SPELL_MOLTEN_EGG_TRASH_CALL_R;
+ DoZoneInCombat();
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_SUMMON_SMOULDERING_HATCHLING, 1);
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SUMMON_SMOULDERING_HATCHLING:
+ {
+ std::list<Creature*> eggs;
+ MoltenEggCheck check(me);
+ Trinity::CreatureListSearcher<MoltenEggCheck> searcher(me, eggs, check);
+ me->VisitNearbyGridObject(20.0f, searcher);
+ if (!eggs.empty())
+ {
+ Creature* egg = Trinity::Containers::SelectRandomContainerElement(eggs);
+ egg->CastSpell(egg, SPELL_SUMMON_SMOULDERING_HATCHLING, TRIGGERED_FULL_MASK);
+ egg->SetDisplayId(MODEL_INVISIBLE_STALKER);
+ egg->m_Events.AddEvent(new RespawnEggEvent(egg), egg->m_Events.CalculateTime(5000));
+ }
+
+ if (_callHatchlingSpell)
+ DoCastAOE(_callHatchlingSpell, true);
+ _events.ScheduleEvent(EVENT_SUMMON_SMOULDERING_HATCHLING, urand(6000, 10000));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ EventMap _events;
+ uint32 _callHatchlingSpell;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_egg_pileAI(creature);
+ }
+};
+
+class spell_alysrazor_cosmetic_egg_xplosion : public SpellScriptLoader
+{
+ public:
+ spell_alysrazor_cosmetic_egg_xplosion() : SpellScriptLoader("spell_alysrazor_cosmetic_egg_xplosion") { }
+
+ class spell_alysrazor_cosmetic_egg_xplosion_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_alysrazor_cosmetic_egg_xplosion_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sCreatureDisplayInfoStore.LookupEntry(MODEL_INVISIBLE_STALKER))
+ return false;
+ return true;
+ }
+
+ void HandleExplosion(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ GetHitUnit()->SetDisplayId(MODEL_INVISIBLE_STALKER);
+ if (Creature* creature = GetHitCreature())
+ creature->DespawnOrUnsummon(4000);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_alysrazor_cosmetic_egg_xplosion_SpellScript::HandleExplosion, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_alysrazor_cosmetic_egg_xplosion_SpellScript();
+ }
+};
+
+class spell_alysrazor_turn_monstrosity : public SpellScriptLoader
+{
+ public:
+ spell_alysrazor_turn_monstrosity() : SpellScriptLoader("spell_alysrazor_turn_monstrosity") { }
+
+ class spell_alysrazor_turn_monstrosity_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_alysrazor_turn_monstrosity_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_GENERIC_DUMMY_CAST))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_KNOCKBACK_RIGHT))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_KNOCKBACK_LEFT))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_KNOCKBACK_FORWARD))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_KNOCKBACK_BACK))
+ return false;
+ return true;
+ }
+
+ void KnockBarrage(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ GetHitUnit()->GetMotionMaster()->MoveIdle();
+ if (TempSummon* summ = GetHitUnit()->ToTempSummon())
+ if (Unit* summoner = summ->GetSummoner())
+ GetHitUnit()->CastSpell(summoner, SPELL_GENERIC_DUMMY_CAST, TRIGGERED_FULL_MASK);
+
+ float angle = 0.0f;
+ if (Unit* bird = GetCaster()->GetVehicleBase())
+ {
+ bird->SetInFront(GetHitUnit());
+ angle = bird->GetOrientation();
+ }
+
+ uint32 spellId = 0;
+ switch (GetSpellInfo()->Id)
+ {
+ case SPELL_RIGHT_SIDE_SMACK_R:
+ case SPELL_RIGHT_SIDE_SMACK_L:
+ spellId = SPELL_KNOCKBACK_RIGHT;
+ angle -= M_PI * 0.5f;
+ break;
+ case SPELL_LEFT_SIDE_SMACK_R:
+ case SPELL_LEFT_SIDE_SMACK_L:
+ spellId = SPELL_KNOCKBACK_LEFT;
+ angle += M_PI * 0.5f;
+ break;
+ case SPELL_HEAD_BONK_R:
+ case SPELL_HEAD_BONK_L:
+ spellId = SPELL_KNOCKBACK_FORWARD;
+ break;
+ case SPELL_TICKLE_R:
+ case SPELL_TICKLE_L:
+ spellId = SPELL_KNOCKBACK_BACK;
+ angle -= M_PI;
+ break;
+ }
+
+ // Cannot wait for object update to process facing spline, it's needed in next spell cast
+ GetHitUnit()->SetOrientation(angle);
+ GetHitUnit()->SetFacingTo(angle);
+ GetHitUnit()->AddUnitState(UNIT_STATE_CANNOT_TURN);
+ GetHitUnit()->CastSpell(GetHitUnit(), spellId, TRIGGERED_FULL_MASK);
+ }
+
+ void TurnBird(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ GetHitUnit()->PlayOneShotAnimKit(ANIM_KIT_BIRD_TURN);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_alysrazor_turn_monstrosity_SpellScript::KnockBarrage, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ OnEffectHitTarget += SpellEffectFn(spell_alysrazor_turn_monstrosity_SpellScript::TurnBird, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_alysrazor_turn_monstrosity_SpellScript();
+ }
+};
+
+class spell_alysrazor_aggro_closest : public SpellScriptLoader
+{
+ public:
+ spell_alysrazor_aggro_closest() : SpellScriptLoader("spell_alysrazor_aggro_closest") { }
+
+ class spell_alysrazor_aggro_closest_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_alysrazor_aggro_closest_SpellScript);
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_UNIT;
+ }
+
+ void HandleEffect(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ float curThreat = GetCaster()->getThreatManager().getThreat(GetHitUnit(), true);
+ GetCaster()->getThreatManager().addThreat(GetHitUnit(), -curThreat + 50000.0f / std::min(1.0f, GetCaster()->GetDistance(GetHitUnit())));
+ }
+
+ void UpdateThreat()
+ {
+ GetCaster()->ClearUnitState(UNIT_STATE_CASTING);
+ GetCaster()->GetAI()->AttackStart(GetCaster()->ToCreature()->SelectVictim());
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_alysrazor_aggro_closest_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
+ AfterCast += SpellCastFn(spell_alysrazor_aggro_closest_SpellScript::UpdateThreat);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_alysrazor_aggro_closest_SpellScript();
+ }
+};
+
+class spell_alysrazor_fieroblast : public SpellScriptLoader
+{
+ public:
+ spell_alysrazor_fieroblast() : SpellScriptLoader("spell_alysrazor_fieroblast") { }
+
+ class spell_alysrazor_fieroblast_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_alysrazor_fieroblast_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_FIRE_IT_UP))
+ return false;
+ return true;
+ }
+
+ void FireItUp()
+ {
+ GetCaster()->CastSpell(GetCaster(), SPELL_FIRE_IT_UP, TRIGGERED_FULL_MASK);
+ }
+
+ void Register()
+ {
+ AfterCast += SpellCastFn(spell_alysrazor_fieroblast_SpellScript::FireItUp);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_alysrazor_fieroblast_SpellScript();
+ }
+};
+
+void AddSC_boss_alysrazor()
+{
+ new npc_harbinger_of_flame();
+ new npc_blazing_monstrosity();
+ new npc_molten_barrage();
+ new npc_egg_pile();
+ new spell_alysrazor_cosmetic_egg_xplosion();
+ new spell_alysrazor_turn_monstrosity();
+ new spell_alysrazor_aggro_closest();
+ new spell_alysrazor_fieroblast();
+}
diff --git a/src/server/scripts/Kalimdor/Firelands/firelands.h b/src/server/scripts/Kalimdor/Firelands/firelands.h
new file mode 100644
index 00000000000..f58b6e33c7c
--- /dev/null
+++ b/src/server/scripts/Kalimdor/Firelands/firelands.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FIRELANDS_H_
+#define FIRELANDS_H_
+
+#include "Map.h"
+#include "Creature.h"
+
+#define FirelandsScriptName "instance_firelands"
+
+uint32 const EncounterCount = 7;
+
+enum DataTypes
+{
+ DATA_BETH_TILAC = 0,
+ DATA_LORD_RHYOLITH = 1,
+ DATA_SHANNOX = 2,
+ DATA_ALYSRAZOR = 3,
+ DATA_BALEROC = 4,
+ DATA_MAJORDOMO_STAGHELM = 5,
+ DATA_RAGNAROS = 6,
+};
+
+enum CreatureIds
+{
+ NPC_BLAZING_MONSTROSITY_LEFT = 53786,
+ NPC_BLAZING_MONSTROSITY_RIGHT = 53791,
+ NPC_EGG_PILE = 53795,
+ NPC_HARBINGER_OF_FLAME = 53793,
+ NPC_MOLTEN_EGG_TRASH = 53914,
+ NPC_SMOULDERING_HATCHLING = 53794,
+};
+
+class DelayedAttackStartEvent : public BasicEvent
+{
+ public:
+ DelayedAttackStartEvent(Creature* owner) : _owner(owner) { }
+
+ bool Execute(uint64 /*e_time*/, uint32 /*p_time*/)
+ {
+ _owner->AI()->DoZoneInCombat(_owner, 200.0f);
+ return true;
+ }
+
+ private:
+ Creature* _owner;
+};
+
+template<class AI>
+CreatureAI* GetFirelandsAI(Creature* creature)
+{
+ if (InstanceMap* instance = creature->GetMap()->ToInstanceMap())
+ if (instance->GetInstanceScript())
+ if (instance->GetScriptId() == sObjectMgr->GetScriptId(FirelandsScriptName))
+ return new AI(creature);
+ return NULL;
+}
+
+#endif // FIRELANDS_H_ \ No newline at end of file
diff --git a/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp
new file mode 100644
index 00000000000..dd8b2a76093
--- /dev/null
+++ b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "InstanceScript.h"
+#include "firelands.h"
+
+class instance_firelands : public InstanceMapScript
+{
+ public:
+ instance_firelands() : InstanceMapScript(FirelandsScriptName, 720) { }
+
+ struct instance_firelands_InstanceScript : public InstanceScript
+ {
+ instance_firelands_InstanceScript(InstanceMap* map) : InstanceScript(map)
+ {
+ }
+
+ void Initialize()
+ {
+ SetBossNumber(EncounterCount);
+ }
+
+ void OnCreatureCreate(Creature* creature)
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_SMOULDERING_HATCHLING:
+ // Cannot directly start attacking here as the creature is not yet on map
+ creature->m_Events.AddEvent(new DelayedAttackStartEvent(creature), creature->m_Events.CalculateTime(500));
+ break;
+ }
+ }
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const
+ {
+ return new instance_firelands_InstanceScript(map);
+ }
+};
+
+void AddSC_instance_firelands()
+{
+ new instance_firelands();
+}