diff --git a/sql/updates/world/2016_07_03_00_world.sql b/sql/updates/world/2016_07_03_00_world.sql
new file mode 100644
index 00000000000..bb530845055
--- /dev/null
+++ b/sql/updates/world/2016_07_03_00_world.sql
@@ -0,0 +1,39 @@
+--
+DELETE FROM `creature` WHERE `guid` =250021;
+INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`) VALUES
+(250021, 53494, 720, 15, 89.9669, -62.8343, 54.9484, 3.16296, 7200);
+
+DELETE FROM `achievement_criteria_data` WHERE `criteria_id` = 17577;
+INSERT INTO `achievement_criteria_data` VALUES (17577, 11, 0, 0, 'achievement_share_the_pain');
+
+UPDATE `creature_template` SET `ScriptName`='boss_baleroc' WHERE `entry`=53494;
+UPDATE `creature_template` SET `ScriptName`='npc_shard_of_torment' WHERE `entry`=53495;
+
+DELETE FROM `creature_text` WHERE `entry`=53494;
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(53494, 4, 2, 'Behold your weakness.', 14, 0, 100, 0, 0, 24451, 0, 0, 'Baleroc'),
+(53494, 0, 0, 'You are forbidden from my master\'s domain, mortals.', 14, 0, 100, 0, 0, 24441, 0, 0, 'Baleroc'),
+(53494, 1, 0, 'Fool mortals. Hurl yourselves into your own demise!', 14, 0, 100, 0, 0, 24446, 0, 0, 'Baleroc'),
+(53494, 2, 0, 'Burn beneath my molten fury!', 14, 0, 100, 0, 0, 24459, 0, 0, 'Baleroc'),
+(53494, 3, 0, 'By the Firelord\'s command, you, too, shall perish!', 14, 0, 100, 0, 0, 24447, 0, 0, 'Baleroc'),
+(53494, 4, 0, 'None shall pass!', 14, 0, 100, 0, 0, 24452, 0, 0, 'Baleroc'),
+(53494, 4, 1, 'You have been judged.', 14, 0, 100, 0, 0, 24449, 0, 0, 'Baleroc'),
+(53494, 5, 0, 'Your flesh is forfeit to the fires of this realm.', 14, 0, 100, 0, 0, 24450, 0, 0, 'Baleroc'),
+(53494, 7, 0, 'Mortal filth... the master\'s keep is forbidden...', 14, 0, 100, 0, 0, 24444, 0, 0, 'Baleroc'),
+(53494, 6, 0, '%s goes into a berserker rage!', 16, 0, 100, 0, 0, 0, 0, 0, 'Baleroc'),
+(53494, 8, 0, '|TInterface\\Icons\\inv_sword_09.blp:20|t%s readies his |cFFFF0000Inferno Blade|r!', 41, 0, 100, 0, 0, 0, 0, 0, 'Baleroc'),
+(53494, 9, 0, '|TInterface\\Icons\\spell_shadow_curse:20|t%s readies his |cFF551A8BDecimation Blade|r!', 41, 0, 100, 0, 0, 0, 0, 0, 'Baleroc');
+
+DELETE FROM `spell_script_names` WHERE `spell_id` IN (99253,99256,99259,99353,99489,99515,99516,99517,100230,100231,100232);
+INSERT INTO `spell_script_names` VALUES
+(99253, 'spell_baleroc_torment'),
+(99256, 'spell_baleroc_tormented'),
+(99259, 'spell_shards_of_torment'),
+(99353, 'spell_decimating_strike'),
+(99489, 'spell_baleroc_tormented_heroic'),
+(99515, 'spell_countdown_p1'),
+(99516, 'spell_countdown_p2'),
+(99517, 'spell_countdown_p3'),
+(100230, 'spell_baleroc_tormented'),
+(100231, 'spell_baleroc_tormented'),
+(100232, 'spell_baleroc_tormented');
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index b091a790349..3310fb50db7 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -504,7 +504,8 @@ Vehicle* Vehicle::RemovePassenger(Unit* unit)
// only for flyable vehicles
if (unit->IsFlying())
- _me->CastSpell(unit, VEHICLE_SPELL_PARACHUTE, true);
+ if (_me->IsFriendlyTo(unit))
+ _me->CastSpell(unit, VEHICLE_SPELL_PARACHUTE, true);
if (_me->GetTypeId() == TYPEID_UNIT && _me->ToCreature()->IsAIEnabled)
_me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, false);
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 694ecd4c0bb..ce75cb7e2c6 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3817,6 +3817,15 @@ void SpellMgr::LoadSpellInfoCorrections()
break;
// ENDOF ISLE OF CONQUEST SPELLS
//
+ // Firelands Spells
+ //
+ case 99256: // Torment
+ case 100230: //Torment
+ case 100231: //Torment
+ case 100232: //Torment
+ spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1;
+ break;
+ // End of Firelands Spells
default:
break;
}
diff --git a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp
new file mode 100644
index 00000000000..ecd161188bd
--- /dev/null
+++ b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp
@@ -0,0 +1,883 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore
+ *
+ * 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 .
+ */
+
+/*
+***To-do list***
+***
+***Implement Vital Spark - http://www.wowhead.com/spell=99262
+***Implement Vital Flame - http://www.wowhead.com/spell=99263
+***
+***Redesign achievement data storage system
+*/
+
+#include "firelands.h"
+
+enum Spells
+{
+ SPELL_INFERNO_BLADE = 99350,
+ SPELL_INFERNO_STRIKE = 99351,
+ SPELL_DECIMATION_BLADE = 99352,
+ SPELL_DECIMATION_BLADE_2 = 99405,
+ SPELL_DECIMATING_STRIKE = 99353,
+
+ SPELL_BLAZE_OF_GLORY = 99252,
+ SPELL_INCENDIARY_SOUL = 99369,
+
+ SPELL_SHARDS_OF_TORMENT = 99259,
+ SPELL_SHARDS_OF_TORMENT_2 = 99260,
+ SPELL_TORMENT_COSMETIC_1 = 99258,
+ SPELL_TORMENT = 99254,
+ SPELL_TORMENT_PERIODIC = 99255,
+ SPELL_WAVE_OF_TORMENT = 99261,
+ SPELL_TORMENTED_20 = 99257,
+ SPELL_TORMENTED_30 = 99402,
+ SPELL_TORMENTED_40 = 99403,
+ SPELL_TORMENTED_60 = 99404,
+
+ SPELL_COUNTDOWN = 99515,
+ SPELL_COUNTDOWN_2 = 99516,
+ SPELL_COUNTDOWN_3 = 99517,
+ SPELL_COUNTDOWN_4 = 99518,
+ SPELL_COUNTDOWN_5 = 99519,
+
+ SPELL_BERSERK = 26662,
+};
+
+enum Events
+{
+ EVENT_BLADE = 1,
+ EVENT_RESTORE_WEAPONS = 2,
+ EVENT_INCENDIARY_SOUL = 3,
+ EVENT_SHARDS_OF_TORMENT = 4,
+ EVENT_COUNTDOWN = 5,
+ EVENT_BERSERK = 6,
+
+ EVENT_SHARD_SPAWN_EFFECT = 7,
+ EVENT_UNLOCK_YELLSPAM = 8,
+};
+
+enum Emotes
+{
+ EMOTE_AGGRO = 0,
+ EMOTE_SHARDS_OF_TORMENT = 1,
+ EMOTE_INFERNO_BLADE = 2,
+ EMOTE_DECIMATION_BLADE = 3,
+ EMOTE_KILL = 4,
+ EMOTE_ENRAGE = 5,
+ EMOTE_ENRAGE_2 = 6,
+ EMOTE_DEATH = 7,
+ ABILITY_INFERNO_BLADE = 8,
+ ABILITY_DECIMATION_BLADE = 9,
+};
+
+enum Guids
+{
+ GUID_TORMENTED = 1,
+};
+
+enum Misc
+{
+ EQUIP_DECIMATION_BLADE = 71082,
+ EQUIP_INFERNO_BLADE = 71138,
+};
+
+class boss_baleroc : public CreatureScript
+{
+ public:
+ boss_baleroc() : CreatureScript("boss_baleroc") { }
+
+ struct boss_balerocAI : public BossAI
+ {
+ boss_balerocAI(Creature* creature) : BossAI(creature, DATA_BALEROC)
+ {
+ }
+
+ bool _canYellKilledPlayer;
+
+ void Reset() OVERRIDE
+ {
+ _Reset();
+ me->SetMaxPower(POWER_RAGE, 0);
+ SetEquipmentSlots(true);
+ me->SetCanDualWield(true);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) OVERRIDE
+ {
+ switch (spell->Id)
+ {
+ case SPELL_INFERNO_BLADE:
+ SetEquipmentSlots(false, EQUIP_INFERNO_BLADE, EQUIP_UNEQUIP);
+ me->SetCanDualWield(false);
+ events.ScheduleEvent(EVENT_RESTORE_WEAPONS, 15*IN_MILLISECONDS);
+ break;
+ case SPELL_DECIMATION_BLADE:
+ case SPELL_DECIMATION_BLADE_2:
+ SetEquipmentSlots(false, EQUIP_DECIMATION_BLADE, EQUIP_UNEQUIP);
+ me->SetCanDualWield(false);
+ events.ScheduleEvent(EVENT_RESTORE_WEAPONS, 15*IN_MILLISECONDS);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void EnterCombat(Unit* target) OVERRIDE
+ {
+ _EnterCombat();
+ Talk(EMOTE_AGGRO);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
+ events.ScheduleEvent(EVENT_INCENDIARY_SOUL, 8.5*IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SHARDS_OF_TORMENT, 5*IN_MILLISECONDS);
+ if (me->GetMap()->IsHeroic())
+ events.ScheduleEvent(EVENT_COUNTDOWN, 26*IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_BLADE, 30.5*IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_BERSERK, 6*MINUTE*IN_MILLISECONDS);
+
+ //Reset our achievement list. We do this here and not in reset, as the debuff may have been spread after the boss has reset.
+ for (int i = 0; i < 25; i++)
+ {
+ _sharedThePain[i].player = 0;
+ _sharedThePain[i].tormented = 0;
+ }
+ }
+
+ void KilledUnit(Unit* who) OVERRIDE
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER && _canYellKilledPlayer)
+ {
+ _canYellKilledPlayer = false;
+ events.ScheduleEvent(EVENT_UNLOCK_YELLSPAM, 8000);
+ Talk(EMOTE_KILL);
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) OVERRIDE
+ {
+ _JustDied();
+ Talk(EMOTE_DEATH);
+ SetEquipmentSlots(true);
+ me->SetCanDualWield(true);;
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ if (Map* map = me->GetMap())
+ {
+ Map::PlayerList const &PlayerList = map->GetPlayers();
+ if (!PlayerList.isEmpty())
+ for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
+ if (i->GetSource()->ToPlayer()->HasQuestForItem(69848))
+ {
+ DoCast(101093);
+ break;
+ }
+ }
+ }
+
+ void EnterEvadeMode() OVERRIDE
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLAZE_OF_GLORY);
+ me->GetMotionMaster()->MoveTargetedHome();
+ summons.DespawnAll();
+ _DespawnAtEvade();
+ }
+
+ void DoMeleeAttackIfReady() OVERRIDE
+ {
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ Unit* victim = me->GetVictim();
+ if (me->isAttackReady(BASE_ATTACK) && me->IsWithinMeleeRange(victim))
+ {
+ if (me->HasAura(SPELL_DECIMATION_BLADE) || me->HasAura(SPELL_DECIMATION_BLADE_2))
+ {
+ me->CastSpell(me->GetVictim(), SPELL_DECIMATING_STRIKE, false);
+ me->resetAttackTimer(BASE_ATTACK);
+ }
+ else if (me->HasAura(SPELL_INFERNO_BLADE))
+ {
+ me->CastSpell(me->GetVictim(), SPELL_INFERNO_STRIKE, false);
+ me->AttackerStateUpdate(victim);
+ me->resetAttackTimer(BASE_ATTACK);
+ }
+ else
+ {
+ me->AttackerStateUpdate(victim);
+ me->resetAttackTimer(BASE_ATTACK);
+ }
+ }
+ if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK) && me->IsWithinMeleeRange(victim))
+ {
+ me->AttackerStateUpdate(victim, OFF_ATTACK);
+ me->resetAttackTimer(OFF_ATTACK);
+ }
+ }
+
+ void UpdateAI(uint32 diff) OVERRIDE
+ {
+ if (me->IsAlive())
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_BLADE:
+ switch (urand(1, 2))
+ {
+ case 1:
+ DoCast(SPELL_INFERNO_BLADE);
+ Talk(EMOTE_INFERNO_BLADE);
+ Talk(ABILITY_INFERNO_BLADE);
+ break;
+ case 2:
+ DoCast(SPELL_DECIMATION_BLADE);
+ Talk(EMOTE_DECIMATION_BLADE);
+ Talk(ABILITY_DECIMATION_BLADE);
+ break;
+ }
+ events.ScheduleEvent(EVENT_BLADE, 47*IN_MILLISECONDS);
+ break;
+ case EVENT_RESTORE_WEAPONS:
+ SetEquipmentSlots(true);
+ me->SetCanDualWield(true);
+ break;
+ case EVENT_INCENDIARY_SOUL:
+ if (me->GetVictim())
+ {
+ DoCast(me->GetVictim(), SPELL_BLAZE_OF_GLORY, false);
+ DoCast(SPELL_INCENDIARY_SOUL);
+ }
+ events.ScheduleEvent(EVENT_INCENDIARY_SOUL, 11.5*IN_MILLISECONDS);
+ break;
+ case EVENT_SHARDS_OF_TORMENT:
+ Talk(EMOTE_SHARDS_OF_TORMENT);
+ DoCast(SPELL_SHARDS_OF_TORMENT);
+ events.ScheduleEvent(EVENT_SHARDS_OF_TORMENT, 34*IN_MILLISECONDS);
+ break;
+ case EVENT_COUNTDOWN:
+ DoCast(SPELL_COUNTDOWN);
+ events.ScheduleEvent(EVENT_COUNTDOWN, 48*IN_MILLISECONDS);
+ break;
+ case EVENT_BERSERK:
+ DoCast(SPELL_BERSERK);
+ Talk(EMOTE_ENRAGE);
+ Talk(EMOTE_ENRAGE_2);
+ break;
+ case EVENT_UNLOCK_YELLSPAM:
+ _canYellKilledPlayer = true;
+ break;
+ default:
+ break;
+ }
+ }
+ DoMeleeAttackIfReady();
+ }
+
+ void SetGUID(uint64 guid, int32 type = 0) OVERRIDE
+ {
+ switch (type)
+ {
+ case GUID_TORMENTED:
+ for (int i = 0; i < 25; i++)
+ {
+ if (_sharedThePain[i].player == guid)
+ {
+ _sharedThePain[i].tormented++;
+ break;
+ }
+ else if (_sharedThePain[i].player == 0)
+ {
+ _sharedThePain[i].player = guid;
+ _sharedThePain[i].tormented++;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool SharedThePain()
+ {
+ for (int i = 0; _sharedThePain[i].player != 0; i++)
+ if (_sharedThePain[i].tormented > 3)
+ return false;
+ return true;
+ }
+
+ private:
+ struct _sharedThePain
+ {
+ uint64 player;
+ uint32 tormented;
+ }
+ _sharedThePain[25];
+ };
+
+ CreatureAI* GetAI(Creature* creature) const OVERRIDE
+ {
+ return GetFirelandsAI(creature);
+ }
+};
+
+//Used for achievements
+typedef boss_baleroc::boss_balerocAI BalerocAI;
+
+class npc_shard_of_torment : public CreatureScript
+{
+ public:
+ npc_shard_of_torment() : CreatureScript("npc_shard_of_torment") { }
+
+ struct npc_shard_of_tormentAI : public ScriptedAI
+ {
+ npc_shard_of_tormentAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetReactState(REACT_PASSIVE);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN);
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ _instance = creature->GetInstanceScript();
+ }
+
+ void IsSummonedBy(Unit* summoner) OVERRIDE
+ {
+ if (summoner->GetEntry() == NPC_BALEROC)
+ {
+ if (_instance->GetBossState(DATA_BALEROC) != IN_PROGRESS)
+ me->DespawnOrUnsummon();
+ DoCast(SPELL_TORMENT_COSMETIC_1);
+ _events.ScheduleEvent(EVENT_SHARD_SPAWN_EFFECT, 5000);
+ me->SetInCombatWithZone();
+ _baleroc = summoner->ToCreature();
+ }
+ else
+ me->DespawnOrUnsummon();
+ }
+
+ void KilledUnit(Unit* who) OVERRIDE
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ if (_baleroc)
+ _baleroc->AI()->KilledUnit(who);
+ }
+
+ void UpdateAI(uint32 diff)
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SHARD_SPAWN_EFFECT:
+ me->RemoveAurasDueToSpell(SPELL_TORMENT_COSMETIC_1);
+ DoCast(SPELL_TORMENT);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ InstanceScript* _instance;
+ EventMap _events;
+ Creature* _baleroc;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_shard_of_tormentAI(creature);
+ }
+};
+
+class spell_countdown_p1 : public SpellScriptLoader
+{
+ public:
+ spell_countdown_p1() : SpellScriptLoader("spell_countdown_p1") { }
+
+ class spell_countdown_p1_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_countdown_p1_SpellScript);
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_UNIT;
+ }
+
+ void CastSpellLink()
+ {
+ if (target1->ToPlayer() && target2->ToPlayer())
+ target1->ToPlayer()->CastSpell(target2->ToPlayer(), SPELL_COUNTDOWN_5, true);
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ GetCaster()->CastSpell(target, SPELL_COUNTDOWN_2, false);
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+
+ //Remove current tank if we have one
+ if (GetCaster()->GetVictim())
+ targets.remove(GetCaster()->ToCreature()->GetVictim());
+
+ if (targets.size() < 2)
+ {
+ FinishCast(SPELL_FAILED_NO_VALID_TARGETS);
+ return;
+ }
+
+ Trinity::Containers::RandomResizeList(targets, 2);
+
+ std::list::const_iterator itr = targets.begin();
+ target1 = (*itr);
+ itr++;
+ target2 = (*itr);
+ }
+
+ void Register() OVERRIDE
+ {
+ AfterCast += SpellCastFn(spell_countdown_p1_SpellScript::CastSpellLink);
+ OnEffectHitTarget += SpellEffectFn(spell_countdown_p1_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_countdown_p1_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+
+ WorldObject* target1;
+ WorldObject* target2;
+ };
+
+ SpellScript* GetSpellScript() const OVERRIDE
+ {
+ return new spell_countdown_p1_SpellScript();
+ }
+};
+
+class spell_countdown_p2 : public SpellScriptLoader
+{
+ public:
+ spell_countdown_p2() : SpellScriptLoader("spell_countdown_p2") { }
+
+ class spell_countdown_p2_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_countdown_p2_AuraScript);
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
+ GetTarget()->CastSpell((Unit*)NULL, SPELL_COUNTDOWN_4, true);
+ GetTarget()->ToPlayer()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_5);
+ }
+
+ void Register() OVERRIDE
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_countdown_p2_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const OVERRIDE
+ {
+ return new spell_countdown_p2_AuraScript();
+ }
+};
+
+class spell_countdown_p3 : public SpellScriptLoader
+{
+ public:
+ spell_countdown_p3() : SpellScriptLoader("spell_countdown_p3") { }
+
+ class spell_countdown_p3_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_countdown_p3_SpellScript);
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(Trinity::UnitAuraCheck(false, SPELL_COUNTDOWN_2));
+ targets.remove(GetCaster());
+
+ if (targets.empty())
+ return;
+
+ for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
+ (*itr)->ToPlayer()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_2);
+ (*itr)->ToPlayer()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_5);
+ }
+
+ GetCaster()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_2);
+ GetCaster()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_5);
+ }
+
+ void Register() OVERRIDE
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_countdown_p3_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const OVERRIDE
+ {
+ return new spell_countdown_p3_SpellScript();
+ }
+};
+
+class spell_decimating_strike : public SpellScriptLoader
+{
+ public:
+ spell_decimating_strike() : SpellScriptLoader("spell_decimating_strike") { }
+
+ class spell_decimating_strike_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_decimating_strike_SpellScript);
+
+ bool Load()
+ {
+ if (GetCaster()->GetTypeId() != TYPEID_UNIT)
+ return false;
+ return true;
+ }
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DECIMATING_STRIKE))
+ return false;
+ return true;
+ }
+
+ void ChangeDamage()
+ {
+ if (GetCaster()->GetVictim())
+ {
+ uint32 health = GetCaster()->GetVictim()->GetMaxHealth();
+ if (health*0.9 < 250000)
+ SetHitDamage(uint32(250000));
+ else
+ SetHitDamage(uint32(health*0.9));
+ }
+ else
+ SetHitDamage(uint32(250000));
+ }
+
+ void Register()
+ {
+ OnHit += SpellHitFn(spell_decimating_strike_SpellScript::ChangeDamage);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_decimating_strike_SpellScript();
+ }
+};
+
+class spell_shards_of_torment : public SpellScriptLoader
+{
+ public:
+ spell_shards_of_torment() : SpellScriptLoader("spell_shards_of_torment") { }
+
+ class spell_shards_of_torment_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_shards_of_torment_SpellScript);
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_UNIT;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_SHARDS_OF_TORMENT_2, true);
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+ uint8 numtargets;
+ if (GetCaster()->GetMap()->Is25ManRaid())
+ numtargets = 2;
+ else
+ numtargets = 1;
+
+ while(targets.size() < numtargets)
+ numtargets--;
+
+
+ if ((targets.size() > numtargets) && GetCaster()->GetVictim())
+ targets.remove(GetCaster()->ToCreature()->GetVictim()); //Safe to remove tank from list
+
+ Trinity::Containers::RandomResizeList(targets, numtargets);
+ }
+
+ void Register() OVERRIDE
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_shards_of_torment_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_shards_of_torment_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const OVERRIDE
+ {
+ return new spell_shards_of_torment_SpellScript();
+ }
+};
+
+class PlayerCheck
+{
+ public:
+ bool operator()(WorldObject* object) const
+ {
+ if (object->GetTypeId() != TYPEID_PLAYER)
+ if (!object->ToPlayer()->IsAlive())
+ if (object->ToPlayer()->IsGameMaster())
+ return true;
+
+ return false;
+ }
+};
+
+class spell_baleroc_torment : public SpellScriptLoader
+{
+ public:
+ spell_baleroc_torment() : SpellScriptLoader("spell_baleroc_torment") { }
+
+ class spell_baleroc_torment_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_baleroc_torment_SpellScript);
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_UNIT;
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(PlayerCheck());
+
+ if (targets.empty())
+ {
+ //No targets found, start pulsating immediately.
+ GetCaster()->ToCreature()->AI()->DoCast(SPELL_WAVE_OF_TORMENT);
+ return;
+ }
+
+ targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), true));
+ targets.resize(1);
+
+ if ((*targets.begin())->GetDistance2d(GetCaster()) > 15.0f)
+ GetCaster()->ToCreature()->AI()->DoCast(SPELL_WAVE_OF_TORMENT);
+ else
+ {
+ if ((*targets.begin())->ToPlayer()->GetAura(SPELL_TORMENT_PERIODIC))
+ if ((*targets.begin())->ToPlayer()->GetAura(SPELL_TORMENT_PERIODIC)->GetCaster() != GetCaster())
+ GetCaster()->CastSpell((*targets.begin())->ToPlayer(), SPELL_TORMENT_PERIODIC, false);
+ else{
+ }
+ else
+ GetCaster()->CastSpell((*targets.begin())->ToPlayer(), SPELL_TORMENT_PERIODIC, false);
+ }
+ }
+
+ void Register() OVERRIDE
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_baleroc_torment_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const OVERRIDE
+ {
+ return new spell_baleroc_torment_SpellScript();
+ }
+};
+
+class spell_baleroc_tormented : public SpellScriptLoader
+{
+ public:
+ spell_baleroc_tormented() : SpellScriptLoader("spell_baleroc_tormented") { }
+
+ class spell_baleroc_tormented_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_baleroc_tormented_SpellScript);
+
+ void ChangeDamage()
+ {
+ //SetHitDamage(GetHitDamage()*GetHitUnit()->GetAuraCount(m_scriptSpellId));
+
+ //The above example seems wrong, wowhead say the damage is 3000 per tick on normal, and 4250 on heroic,
+ //while logs from retail say its 4000 normal, and 5000 heroic.
+ if (GetHitUnit()->GetMap()->IsHeroic())
+ {
+ float damageMultiplier = 1.0f+((GetHitDamage()-4250)/4250);
+ SetHitDamage((5000*GetHitUnit()->GetAuraCount(m_scriptSpellId))*damageMultiplier);
+ }
+ else
+ {
+ float damageMultiplier = 1.0f+((GetHitDamage()-3000)/3000);
+ SetHitDamage((4000*GetHitUnit()->GetAuraCount(m_scriptSpellId))*damageMultiplier);
+ }
+ }
+
+ void Register()
+ {
+ OnHit += SpellHitFn(spell_baleroc_tormented_SpellScript::ChangeDamage);
+ }
+
+ };
+
+ SpellScript* GetSpellScript() const OVERRIDE
+ {
+ return new spell_baleroc_tormented_SpellScript();
+ }
+
+ class spell_baleroc_tormented_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_baleroc_tormented_AuraScript);
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
+ {
+ if (GetTarget()->GetMap()->IsHeroic())
+ GetTarget()->CastSpell(GetTarget(), SPELL_TORMENTED_40, true);
+ else
+ GetTarget()->CastSpell(GetTarget(), SPELL_TORMENTED_20, true);
+ }
+ }
+
+ void Register() OVERRIDE
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_baleroc_tormented_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const OVERRIDE
+ {
+ return new spell_baleroc_tormented_AuraScript();
+ }
+};
+
+class spell_baleroc_tormented_debuff : public SpellScriptLoader
+{
+ public:
+ spell_baleroc_tormented_debuff() : SpellScriptLoader("spell_baleroc_tormented_debuff") { }
+
+ class spell_baleroc_tormented_debuff_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_baleroc_tormented_debuff_AuraScript);
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (InstanceScript* instance = GetTarget()->GetInstanceScript())
+ if (Creature* baleroc = ObjectAccessor::GetCreature(*GetTarget(), instance->GetData64(DATA_BALEROC)))
+ baleroc->AI()->SetGUID(GetTarget()->GetGUID(), GUID_TORMENTED);
+ }
+
+ void Register() OVERRIDE
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_baleroc_tormented_debuff_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const OVERRIDE
+ {
+ return new spell_baleroc_tormented_debuff_AuraScript();
+ }
+};
+
+class spell_baleroc_tormented_heroic : public SpellScriptLoader
+{
+ public:
+ spell_baleroc_tormented_heroic() : SpellScriptLoader("spell_baleroc_tormented_heroic") { }
+
+ class spell_baleroc_tormented_heroic_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_baleroc_tormented_heroic_SpellScript);
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ if (GetCaster()->GetMap()->IsHeroic())
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_TORMENTED_40, true);
+ }
+
+ void Register() OVERRIDE
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_baleroc_tormented_heroic_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const OVERRIDE
+ {
+ return new spell_baleroc_tormented_heroic_SpellScript();
+ }
+};
+
+class achievement_share_the_pain : public AchievementCriteriaScript
+{
+ public:
+ achievement_share_the_pain() : AchievementCriteriaScript("achievement_share_the_pain") { }
+
+ bool OnCheck(Player* /*source*/, Unit* target) OVERRIDE
+ {
+ if (!target)
+ return false;
+
+ if (BalerocAI* balerocAI = CAST_AI(BalerocAI, target->GetAI()))
+ return balerocAI->SharedThePain();
+
+ return false;
+ }
+};
+
+void AddSC_boss_baleroc()
+{
+ new boss_baleroc();
+
+ new npc_shard_of_torment();
+
+ new spell_countdown_p1();
+ new spell_countdown_p2();
+ new spell_countdown_p3();
+
+ new spell_decimating_strike();
+
+ new spell_shards_of_torment();
+ new spell_baleroc_torment();
+ new spell_baleroc_tormented();
+ new spell_baleroc_tormented_heroic();
+ new spell_baleroc_tormented_debuff();
+
+ new achievement_share_the_pain();
+};
diff --git a/src/server/scripts/Kalimdor/Firelands/firelands.h b/src/server/scripts/Kalimdor/Firelands/firelands.h
index 3e5057ea6f7..4e98ebffd08 100644
--- a/src/server/scripts/Kalimdor/Firelands/firelands.h
+++ b/src/server/scripts/Kalimdor/Firelands/firelands.h
@@ -39,6 +39,16 @@ enum DataTypes
enum CreatureIds
{
+ //Bosses
+ NPC_SHANNOX = 53691,
+ NPC_LORD_RHYOLITH = 52558,
+ NPC_BETH_TILAC = 52498,
+ NPC_ALYSRAZOR = 52530,
+ NPC_BALEROC = 53494,
+ NPC_MAJORDOMO_STAGHELM = 52571,
+ NPC_RAGNAROS = 52409,
+
+ //Alysrazor
NPC_BLAZING_MONSTROSITY_LEFT = 53786,
NPC_BLAZING_MONSTROSITY_RIGHT = 53791,
NPC_EGG_PILE = 53795,
@@ -47,6 +57,15 @@ enum CreatureIds
NPC_SMOULDERING_HATCHLING = 53794,
};
+enum GameobjectIds
+{
+ GO_LORD_RHYOLITH_BRIDGE = 209255,
+ GO_BETH_TILAC_DOOR = 208877,
+ GO_BALEROC_FIREWALL = 209066,
+ GO_MAJORDOMO_FIREWALL = 208906,
+ GO_RAGNAROS_DOOR = 209073,
+};
+
class DelayedAttackStartEvent : public BasicEvent
{
public:
diff --git a/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp
index 34cd2d2982a..f730f49f467 100644
--- a/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp
+++ b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp
@@ -19,6 +19,16 @@
#include "InstanceScript.h"
#include "firelands.h"
+DoorData const doorData[] =
+{
+ {GO_LORD_RHYOLITH_BRIDGE, DATA_LORD_RHYOLITH, DOOR_TYPE_ROOM, BOUNDARY_E },
+ {GO_BETH_TILAC_DOOR, DATA_BETH_TILAC, DOOR_TYPE_ROOM, BOUNDARY_SE },
+ //{GO_BALEROC_FIREWALL, DATA_BALEROC, DOOR_TYPE_ROOM, BOUNDARY_S },
+ {GO_MAJORDOMO_FIREWALL, DATA_MAJORDOMO_STAGHELM, DOOR_TYPE_PASSAGE, BOUNDARY_N },
+ {GO_RAGNAROS_DOOR, DATA_RAGNAROS, DOOR_TYPE_ROOM, BOUNDARY_S },
+ {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }, //END
+}; //Baleroc door is special, it depends on the health status of the other bosses in the instance
+
class instance_firelands : public InstanceMapScript
{
public:
@@ -30,6 +40,9 @@ class instance_firelands : public InstanceMapScript
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
+ LoadDoorData(doorData);
+
+ BalerocGUID = 0;
}
void OnCreatureCreate(Creature* creature) override
@@ -40,8 +53,104 @@ class instance_firelands : public InstanceMapScript
// 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;
+ case NPC_BALEROC:
+ BalerocGUID = creature->GetGUID();
+ break;
}
}
+
+ void OnGameObjectCreate(GameObject* go) OVERRIDE
+ {
+ switch(go->GetEntry())
+ {
+ case GO_LORD_RHYOLITH_BRIDGE:
+ case GO_BETH_TILAC_DOOR:
+ //case GO_BALEROC_FIREWALL:
+ case GO_MAJORDOMO_FIREWALL:
+ case GO_RAGNAROS_DOOR:
+ AddDoor(go, true);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnGameObjectRemove(GameObject* go) OVERRIDE
+ {
+ switch (go->GetEntry())
+ {
+ case GO_LORD_RHYOLITH_BRIDGE:
+ case GO_BETH_TILAC_DOOR:
+ //case GO_BALEROC_FIREWALL:
+ case GO_MAJORDOMO_FIREWALL:
+ case GO_RAGNAROS_DOOR:
+ AddDoor(go, false);
+ break;
+ default:
+ break;
+ }
+ }
+
+ uint64 GetData64(uint32 type) const OVERRIDE
+ {
+ switch (type)
+ {
+ case DATA_BALEROC:
+ return BalerocGUID;
+ }
+
+ return 0;
+ }
+
+ std::string GetSaveData() OVERRIDE
+ {
+ OUT_SAVE_INST_DATA;
+
+ std::ostringstream saveStream;
+ saveStream << "F L " << GetBossSaveData();
+
+ OUT_SAVE_INST_DATA_COMPLETE;
+ return saveStream.str();
+ }
+
+ void Load(const char* str) OVERRIDE
+ {
+ if (!str)
+ {
+ OUT_LOAD_INST_DATA_FAIL;
+ return;
+ }
+
+ OUT_LOAD_INST_DATA(str);
+
+ char dataHead1, dataHead2;
+
+ std::istringstream loadStream(str);
+ loadStream >> dataHead1 >> dataHead2;
+
+ if (dataHead1 == 'F' && dataHead2 == 'L')
+ {
+ for (uint32 i = 0; i < EncounterCount; ++i)
+ {
+ uint32 tmpState;
+ loadStream >> tmpState;
+ if (tmpState == IN_PROGRESS || tmpState > SPECIAL)
+ tmpState = NOT_STARTED;
+ SetBossState(i, EncounterState(tmpState));
+ }
+
+ uint32 temp = 0;
+ loadStream >> temp;
+ }
+ else
+ OUT_LOAD_INST_DATA_FAIL;
+
+ OUT_LOAD_INST_DATA_COMPLETE;
+ }
+
+ private:
+ uint64 BalerocGUID;
+
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
index 1f8258f78a6..fab3fdb2757 100644
--- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
+++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
@@ -96,6 +96,7 @@ void AddSC_boss_altairus();
void AddSC_boss_asaad();
void AddSC_instance_firelands(); //Firelands
void AddSC_boss_alysrazor();
+void AddSC_boss_baleroc();
void AddSC_ashenvale();
void AddSC_azshara();
@@ -201,6 +202,7 @@ void AddKalimdorScripts()
AddSC_boss_asaad();
AddSC_instance_firelands(); //Firelands
AddSC_boss_alysrazor();
+ AddSC_boss_baleroc();
AddSC_ashenvale();
AddSC_azshara();