aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp2
-rw-r--r--src/server/game/Spells/SpellMgr.cpp5
-rw-r--r--src/server/scripts/Kalimdor/CMakeLists.txt3
-rw-r--r--src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp350
-rw-r--r--src/server/scripts/Kalimdor/HallsOfOrigination/halls_of_origination.h6
-rw-r--r--src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp12
6 files changed, 377 insertions, 1 deletions
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 5faae2bf719..a025f856d79 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -330,6 +330,7 @@ void AddSC_zulfarrak(); //Zul'Farrak generic
void AddSC_instance_zulfarrak(); //Zul'Farrak instance script
void AddSC_instance_halls_of_origination();
void AddSC_boss_temple_guardian_anhuur();
+void AddSC_boss_earthrager_ptah();
void AddSC_ashenvale();
void AddSC_azshara();
@@ -984,6 +985,7 @@ void AddKalimdorScripts()
AddSC_instance_halls_of_origination();
AddSC_boss_temple_guardian_anhuur();
+ AddSC_boss_earthrager_ptah();
#endif
}
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index faca4956d28..d1ec90c2ff3 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3672,6 +3672,11 @@ void SpellMgr::LoadSpellInfoCorrections()
// Aura is refreshed at 3 seconds, and the tick should happen at the fourth.
spellInfo->AttributesEx8 |= SPELL_ATTR8_DONT_RESET_PERIODIC_TIMER;
break;
+ // Earthrager Ptah
+ case 94974:
+ // Hacked as a timed event until SPELL_EFFECT_TRIGGER_MISSILE is correctly fixed.
+ spellInfo->Effects[EFFECT_0].TriggerSpell = 0;
+ break;
default:
break;
}
diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt
index 37e2f86e787..49415506565 100644
--- a/src/server/scripts/Kalimdor/CMakeLists.txt
+++ b/src/server/scripts/Kalimdor/CMakeLists.txt
@@ -111,8 +111,9 @@ set(scripts_STAT_SRCS
Kalimdor/OnyxiasLair/onyxias_lair.h
Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp
Kalimdor/HallsOfOrigination/halls_of_origination.h
- Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp
Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp
+ Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp
+ Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp
)
message(" -> Prepared: Kalimdor")
diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp
new file mode 100644
index 00000000000..1d5b473f09f
--- /dev/null
+++ b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp
@@ -0,0 +1,350 @@
+#include "ObjectMgr.h"
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellAuras.h"
+#include "halls_of_origination.h"
+#include "Player.h"
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_DEATH = 1,
+};
+
+enum Events
+{
+ EVENT_RAGING_SMASH = 1,
+ EVENT_FLAME_BOLT = 2,
+ EVENT_EARTH_SPIKE = 3,
+ EVENT_PTAH_EXPLODE = 4,
+ EVENT_QUICKSAND = 5,
+};
+
+enum Spells
+{
+ SPELL_RAGING_SMASH = 83650,
+ SPELL_FLAME_BOLT = 77370,
+ SPELL_EARTH_SPIKE_WARN = 94974,
+ SPELL_EARTH_SPIKE_ERUPT = 75339,
+
+ SPELL_PTAH_EXPLOSION = 75519,
+ SPELL_SANDSTORM = 75491,
+
+ SPELL_SUMMON_QUICKSAND = 75550, // Spell not in DBC, no SMSG_SPELL_START/GO for it
+
+ SPELL_BEETLE_BURROW = 75463,
+
+ SPELL_SUMMON_JEWELED_SCARAB = 75462,
+ SPELL_SUMMON_DUSTBONE_HORROR = 75521,
+};
+
+enum Phases
+{
+ PHASE_NORMAL = 1,
+ PHASE_DISPERSE = 2,
+
+ PHASE_MASK_DISPERSE = (1 << PHASE_DISPERSE),
+ PHASE_MASK_NORMAL = (1 << PHASE_NORMAL),
+};
+
+enum PtahData
+{
+ DATA_SUMMON_DEATHS = 0
+};
+
+class SummonScarab : public BasicEvent
+{
+public:
+ SummonScarab(Unit* owner, InstanceScript* instance) : _owner(owner), _instance(instance) { }
+
+ bool Execute(uint64 execTime, uint32 /*diff*/)
+ {
+ if (!_instance || _instance->GetBossState(DATA_EARTHRAGER_PTAH) != IN_PROGRESS)
+ return true; // delete event
+
+ _owner->CastSpell(_owner, SPELL_SUMMON_JEWELED_SCARAB);
+ _owner->RemoveAurasDueToSpell(SPELL_BEETLE_BURROW);
+ return true;
+ }
+protected:
+ InstanceScript* _instance;
+ Unit* _owner;
+};
+
+class EruptEarthSpike : public BasicEvent
+{
+public:
+ EruptEarthSpike(Unit* caster, WorldLocation const target) : _caster(caster), _target(target) { }
+
+ bool Execute(uint64 execTime, uint32 /*diff*/)
+ {
+ _caster->CastSpell(_target.GetPositionX(), _target.GetPositionY(), _target.GetPositionZ(), SPELL_EARTH_SPIKE_ERUPT, true);
+ return true;
+ }
+
+protected:
+ Unit* _caster;
+ WorldLocation const _target;
+};
+
+class boss_earthrager_ptah : public CreatureScript
+{
+public:
+ boss_earthrager_ptah() : CreatureScript("boss_earthrager_ptah") { }
+
+ struct boss_earthrager_ptahAI : public BossAI
+ {
+ boss_earthrager_ptahAI(Creature* creature) : BossAI(creature, DATA_EARTHRAGER_PTAH), _summonDeaths(0), _hasDispersed(false) { }
+
+ void Cleanup()
+ {
+ std::list<Creature*> units;
+
+ GetCreatureListWithEntryInGrid(units, me, NPC_DUSTBONE_HORROR, 100.0f);
+ for (std::list<Creature*>::iterator itr = units.begin(); itr != units.end(); ++itr)
+ (*itr)->DespawnOrUnsummon();
+
+ GetCreatureListWithEntryInGrid(units, me, NPC_JEWELED_SCARAB, 100.0f);
+ for (std::list<Creature*>::iterator itr = units.begin(); itr != units.end(); ++itr)
+ (*itr)->DespawnOrUnsummon();
+ }
+
+ void Reset()
+ {
+ _summonDeaths = 0;
+ _hasDispersed = false;
+ Cleanup();
+ _Reset();
+ events.SetPhase(PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_RAGING_SMASH, urand(7000, 12000), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_FLAME_BOLT, 15000, 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_EARTH_SPIKE, urand(16000, 21000), 0, PHASE_NORMAL);
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage)
+ {
+ if (me->HealthBelowPctDamaged(50, damage) && (events.GetPhaseMask() & PHASE_MASK_NORMAL) && !_hasDispersed)
+ {
+ events.SetPhase(PHASE_DISPERSE);
+ _hasDispersed = true;
+
+ me->AttackStop();
+ DoCast(me, SPELL_SANDSTORM);
+ events.ScheduleEvent(EVENT_PTAH_EXPLODE, 6000, 0, PHASE_DISPERSE);
+ events.ScheduleEvent(EVENT_QUICKSAND, 10000, 0, PHASE_DISPERSE);
+
+ std::list<Creature*> stalkers;
+ GetCreatureListWithEntryInGrid(stalkers, me, NPC_BEETLE_STALKER, 100.0f);
+ std::list<Creature*> beetlers = stalkers;
+
+ Trinity::Containers::RandomResizeList(beetlers, 9); // Holds the summoners of Jeweled Scarab
+
+ for (std::list<Creature*>::iterator itr = beetlers.begin(); itr != beetlers.end(); ++itr)
+ {
+ stalkers.remove((*itr)); // Remove it to prevent a single trigger from spawning multiple npcs.
+ (*itr)->CastSpell((*itr), SPELL_BEETLE_BURROW); // Cast visual
+ // Summon after 5 seconds.
+ (*itr)->m_Events.AddEvent(new SummonScarab((*itr), instance), (*itr)->m_Events.CalculateTime(5000));
+ }
+
+ Trinity::Containers::RandomResizeList(stalkers, 2); // Holds the summoners of Dustbone Horror
+
+ for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr)
+ (*itr)->CastSpell((*itr), SPELL_SUMMON_DUSTBONE_HORROR);
+ }
+ }
+
+ void SetData(uint32 index, uint32 value)
+ {
+ if (index == DATA_SUMMON_DEATHS)
+ {
+ ++_summonDeaths;
+ if (_summonDeaths == 11) // All summons died
+ {
+ me->RemoveAurasDueToSpell(SPELL_PTAH_EXPLOSION);
+ events.SetPhase(PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_RAGING_SMASH, urand(7000, 12000), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_FLAME_BOLT, 15000, 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_EARTH_SPIKE, urand(16000, 21000), 0, PHASE_NORMAL);
+ }
+ }
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ Talk(SAY_DEATH);
+ _JustDied();
+ Cleanup();
+ }
+
+ void JustReachedHome()
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ _JustReachedHome();
+ instance->SetBossState(DATA_EARTHRAGER_PTAH, FAIL);
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || !CheckInRoom())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_RAGING_SMASH:
+ DoCastVictim(SPELL_RAGING_SMASH);
+ events.ScheduleEvent(EVENT_RAGING_SMASH, urand(7000, 12000), 0, PHASE_NORMAL);
+ break;
+ case EVENT_FLAME_BOLT:
+ DoCast(me, SPELL_FLAME_BOLT);
+ events.ScheduleEvent(EVENT_FLAME_BOLT, 15000, 0, PHASE_NORMAL);
+ break;
+ case EVENT_EARTH_SPIKE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_EARTH_SPIKE_WARN);
+ events.ScheduleEvent(EVENT_EARTH_SPIKE, urand(16000, 21000), 0, PHASE_NORMAL);
+ break;
+ case EVENT_PTAH_EXPLODE:
+ DoCast(me, SPELL_PTAH_EXPLOSION);
+ break;
+ case EVENT_QUICKSAND:
+ // Spell not in DBC, it is not cast either, according to sniffs
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ if (Creature* quicksand = me->SummonCreature(NPC_QUICKSAND, *target))
+ quicksand->SetUInt32Value(UNIT_CREATED_BY_SPELL, SPELL_SUMMON_QUICKSAND);
+ events.ScheduleEvent(EVENT_QUICKSAND, 10000, 0, PHASE_DISPERSE);
+ break;
+ }
+ }
+
+ if (events.GetPhaseMask() & PHASE_MASK_NORMAL) // Do not melee in the disperse phase
+ DoMeleeAttackIfReady();
+ }
+
+ protected:
+ bool _hasDispersed;
+ uint8 _summonDeaths;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetHallsOfOriginationAI<boss_earthrager_ptahAI>(creature);
+ }
+};
+
+class spell_earthrager_ptah_flame_bolt : public SpellScriptLoader
+{
+ public:
+ spell_earthrager_ptah_flame_bolt() : SpellScriptLoader("spell_earthrager_ptah_flame_bolt") { }
+
+ class spell_earthrager_ptah_flame_bolt_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_earthrager_ptah_flame_bolt_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ Trinity::Containers::RandomResizeList(targets, GetCaster()->GetMap()->IsHeroic() ? 3 : 2);
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_earthrager_ptah_flame_bolt_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_earthrager_ptah_flame_bolt_SpellScript();
+ }
+};
+
+class spell_earthrager_ptah_earth_spike : public SpellScriptLoader
+{
+public:
+ spell_earthrager_ptah_earth_spike() : SpellScriptLoader("spell_earthrager_ptah_earth_spike") { }
+
+ class spell_earthrager_ptah_earth_spike_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_earthrager_ptah_earth_spike_SpellScript);
+
+ void Launch(SpellEffIndex index)
+ {
+ PreventHitDefaultEffect(index);
+ // Erupt the spike in 4 seconds.
+ GetCaster()->m_Events.AddEvent(new EruptEarthSpike(GetCaster(), *GetExplTargetDest()), GetCaster()->m_Events.CalculateTime(4000));
+ }
+
+ void Register()
+ {
+ OnEffectHit += SpellEffectFn(spell_earthrager_ptah_earth_spike_SpellScript::Launch, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_earthrager_ptah_earth_spike_SpellScript();
+ }
+};
+
+class spell_earthrager_ptah_explosion : public SpellScriptLoader
+{
+public:
+ spell_earthrager_ptah_explosion() : SpellScriptLoader("spell_earthrager_ptah_explosion") { }
+
+ class spell_earthrager_ptah_explosion_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_earthrager_ptah_explosion_AuraScript);
+
+ void SetFlags(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* ptah = GetCaster())
+ {
+ ptah->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_UNK_29 | UNIT_FLAG_UNK_31);
+ ptah->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
+ }
+ }
+
+ void RemoveFlags(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* ptah = GetCaster())
+ {
+ ptah->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_UNK_29 | UNIT_FLAG_UNK_31);
+ ptah->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_earthrager_ptah_explosion_AuraScript::SetFlags, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_earthrager_ptah_explosion_AuraScript::RemoveFlags, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_earthrager_ptah_explosion_AuraScript();
+ }
+};
+
+void AddSC_boss_earthrager_ptah()
+{
+ new boss_earthrager_ptah();
+ new spell_earthrager_ptah_flame_bolt();
+ new spell_earthrager_ptah_earth_spike();
+ new spell_earthrager_ptah_explosion();
+} \ No newline at end of file
diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/halls_of_origination.h b/src/server/scripts/Kalimdor/HallsOfOrigination/halls_of_origination.h
index d25272c92ac..1f11b594353 100644
--- a/src/server/scripts/Kalimdor/HallsOfOrigination/halls_of_origination.h
+++ b/src/server/scripts/Kalimdor/HallsOfOrigination/halls_of_origination.h
@@ -46,6 +46,12 @@ enum Creatures
BOSS_TEMPLE_GUARDIAN_ANHUUR = 39425,
NPC_CAVE_IN_STALKER = 40183,
NPC_SEARING_LIGHT = 40283,
+
+ BOSS_EARTHRAGER_PTAH = 39428,
+ NPC_BEETLE_STALKER = 40459, // Summons both Jeweled Scarab and Dustbone Horror
+ NPC_JEWELED_SCARAB = 40458,
+ NPC_DUSTBONE_HORROR = 40450,
+ NPC_QUICKSAND = 40503, // Summoned by a spell not in dbc (75550)
};
enum GameObjects
diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp
index f879f7b3202..726ecbacd2e 100644
--- a/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp
+++ b/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp
@@ -75,6 +75,18 @@ class instance_halls_of_origination : public InstanceMapScript
}
}
+ void OnGameObjectRemove(GameObject* go)
+ {
+ switch (go->GetEntry())
+ {
+ case GO_ANHUURS_BRIDGE:
+ case GO_DOODAD_ULDUM_ELEVATOR_COL01:
+ case GO_ANHUURS_DOOR:
+ AddDoor(go, false);
+ break;
+ }
+ }
+
void OnCreatureCreate(Creature* creature)
{
switch (creature->GetEntry())