mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-19 08:55:32 +01:00
Scripts/HoO: ported master scripts. Need to rework and fix them.
This commit is contained in:
235
src/server/scripts/Kalimdor/HallsOfOrigination/boss_ammunae.cpp
Normal file
235
src/server/scripts/Kalimdor/HallsOfOrigination/boss_ammunae.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2018 TrinityCore <https://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 "halls_of_origination.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Ammunae
|
||||
SPELL_ZERO_ENERGY = 72242,
|
||||
SPELL_WITHER = 76043,
|
||||
SPELL_CONSUME_LIFE_ENERGY = 75725,
|
||||
SPELL_RAMPANT_GROWTH = 75790,
|
||||
SPELL_SUMMON_SEEDLING_POD = 75621, // summons 40550 (normal) or 51329 (heroic)
|
||||
SPELL_SUMMON_SPORE = 75695, // summons 40585
|
||||
|
||||
// Consume Life Energy spell
|
||||
SPELL_CONSUME_LIFE_ENERGY_LEECH = 79768,
|
||||
SPELL_CONSUME_LIFE_ENERGY_ENERGIZE = 75665,
|
||||
|
||||
// Seedling Pod npc
|
||||
SPELL_SEEDLING_POD_ENERGIZE = 75708,
|
||||
SPELL_FORCECAST_SUMMON_BLOSSOM = 75774, // forces Seedling Pods to cast 75771
|
||||
SPELL_SUMMON_BLOODPETAL_BLOSSOM = 75771 // summons 40620
|
||||
};
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_DEATH = 0,
|
||||
SAY_AGGRO = 1,
|
||||
SAY_SPECIAL = 2,
|
||||
SAY_PLAYER_KILL = 3
|
||||
};
|
||||
|
||||
|
||||
enum Events
|
||||
{
|
||||
// Ammunae
|
||||
EVENT_WITHER = 1,
|
||||
EVENT_APPLY_IMMUNITY,
|
||||
EVENT_CONSUME_LIFE_ENERGY,
|
||||
EVENT_SEEDLING_POD,
|
||||
EVENT_SUMMON_BLOODPETAL_BLOSSOM,
|
||||
EVENT_SUMMON_SPORE,
|
||||
|
||||
// Blossom
|
||||
EVENT_TRANSFORM,
|
||||
EVENT_EMERGE,
|
||||
EVENT_THORN_SLASH
|
||||
};
|
||||
|
||||
// 39731 Ammunae <Construct of Life>
|
||||
class boss_ammunae : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_ammunae() : CreatureScript("boss_ammunae") { }
|
||||
|
||||
struct boss_ammunaeAI : public BossAI
|
||||
{
|
||||
boss_ammunaeAI(Creature* creature) : BossAI(creature, DATA_AMMUNAE) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
me->MakeInterruptable(false);
|
||||
me->AddAura(SPELL_ZERO_ENERGY, me);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
Talk(SAY_AGGRO);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
|
||||
|
||||
events.ScheduleEvent(EVENT_WITHER, !IsHeroic() ? Seconds(7) : Seconds(5));
|
||||
events.ScheduleEvent(EVENT_SEEDLING_POD, Seconds(7));
|
||||
events.ScheduleEvent(EVENT_CONSUME_LIFE_ENERGY, Seconds(20));
|
||||
events.ScheduleEvent(EVENT_SUMMON_SPORE, Seconds(47));
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
{
|
||||
me->AddAura(SPELL_ZERO_ENERGY, me);
|
||||
me->SetPower(POWER_ENERGY, 0);
|
||||
instance->SetBossState(DATA_AMMUNAE, NOT_STARTED);
|
||||
_JustReachedHome();
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_PLAYER_KILL);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
instance->SetBossState(DATA_AMMUNAE, FAIL);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
|
||||
me->MakeInterruptable(false);
|
||||
events.Reset();
|
||||
_EnterEvadeMode();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || !CheckInRoom())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while(uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_WITHER:
|
||||
me->MakeInterruptable(true);
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
|
||||
DoCast(target, SPELL_WITHER);
|
||||
events.ScheduleEvent(EVENT_APPLY_IMMUNITY, 1500);
|
||||
events.Repeat(Seconds(20));
|
||||
break;
|
||||
case EVENT_APPLY_IMMUNITY:
|
||||
me->MakeInterruptable(false);
|
||||
break;
|
||||
case EVENT_SEEDLING_POD:
|
||||
// If 100 energy, cast Rampant Growth
|
||||
if (me->GetPower(POWER_ENERGY) >= 100)
|
||||
{
|
||||
Talk(SAY_SPECIAL);
|
||||
me->SetPower(POWER_ENERGY, 0);
|
||||
DoCast(SPELL_RAMPANT_GROWTH);
|
||||
}
|
||||
DoCast(SPELL_SUMMON_SEEDLING_POD);
|
||||
events.Repeat(Seconds(7));
|
||||
break;
|
||||
case EVENT_CONSUME_LIFE_ENERGY:
|
||||
DoCast(SPELL_CONSUME_LIFE_ENERGY);
|
||||
events.Repeat(Seconds(15));
|
||||
break;
|
||||
case EVENT_SUMMON_SPORE:
|
||||
DoCast(SPELL_SUMMON_SPORE);
|
||||
events.Repeat(Seconds(47));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_ammunaeAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 75725 Consume Life Energy
|
||||
class spell_ammunae_consume_life_energy : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_ammunae_consume_life_energy() : SpellScriptLoader("spell_ammunae_consume_life_energy") { }
|
||||
|
||||
class spell_ammunae_consume_life_energy_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_ammunae_consume_life_energy_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_CONSUME_LIFE_ENERGY_LEECH, SPELL_CONSUME_LIFE_ENERGY_ENERGIZE });
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
if (targets.empty())
|
||||
return;
|
||||
|
||||
Trinity::Containers::RandomResize(targets, 1);
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetCaster()->CastSpell(GetHitUnit(), SPELL_CONSUME_LIFE_ENERGY_LEECH);
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_CONSUME_LIFE_ENERGY_ENERGIZE);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ammunae_consume_life_energy_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_ammunae_consume_life_energy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_ammunae_consume_life_energy_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_ammunae()
|
||||
{
|
||||
new boss_ammunae();
|
||||
new spell_ammunae_consume_life_energy();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,80 +15,72 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
// To-do:
|
||||
// - Script "Sand Vortex", heroic mode ability.
|
||||
|
||||
#include "halls_of_origination.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Map.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Weather.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_DEATH = 1,
|
||||
SAY_DEATH = 0,
|
||||
SAY_AGGRO = 1,
|
||||
SAY_PLAYER_KILL = 2,
|
||||
SAY_SPECIAL = 3
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_RAGING_SMASH = 1,
|
||||
EVENT_FLAME_BOLT = 2,
|
||||
EVENT_EARTH_SPIKE = 3,
|
||||
EVENT_PTAH_EXPLODE = 4,
|
||||
EVENT_QUICKSAND = 5,
|
||||
// Earthrager Ptah
|
||||
EVENT_RAGING_SMASH = 1,
|
||||
EVENT_FLAME_BOLT,
|
||||
EVENT_EARTH_SPIKE,
|
||||
EVENT_PTAH_EXPLODE,
|
||||
EVENT_QUICKSAND,
|
||||
|
||||
// Beetle Stalker
|
||||
EVENT_SUMMON_JEWELED_SCARAB
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Fight
|
||||
SPELL_RAGING_SMASH = 83650,
|
||||
SPELL_FLAME_BOLT = 77370,
|
||||
SPELL_EARTH_SPIKE_WARN = 94974,
|
||||
|
||||
SPELL_PTAH_EXPLOSION = 75519,
|
||||
// Disperse
|
||||
SPELL_SANDSTORM = 75491,
|
||||
// SPELL_TUMULTUOUS_EARTHSTORM = 75517, // Server-side spell
|
||||
SPELL_PTAH_EXPLOSION = 75519,
|
||||
SPELL_SUMMON_QUICKSAND = 75550, // Server-side spell + hidden client-side flag!
|
||||
|
||||
SPELL_SUMMON_QUICKSAND = 75550, // Spell not in DBC, no SMSG_SPELL_START/GO for it
|
||||
|
||||
SPELL_BEETLE_BURROW = 75463,
|
||||
|
||||
// Beetle Stalker
|
||||
SPELL_BEETLE_BURROW = 75463, // Visual
|
||||
SPELL_SUMMON_JEWELED_SCARAB = 75462,
|
||||
SPELL_SUMMON_DUSTBONE_HORROR = 75521,
|
||||
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),
|
||||
PHASE_FIGHT = 1,
|
||||
PHASE_EARTHSTORM = 2
|
||||
};
|
||||
|
||||
enum PtahData
|
||||
enum Sounds
|
||||
{
|
||||
DATA_SUMMON_DEATHS = 0
|
||||
};
|
||||
|
||||
class SummonScarab : public BasicEvent
|
||||
{
|
||||
public:
|
||||
SummonScarab(Unit* owner, InstanceScript* instance) : _owner(owner), _instance(instance) { }
|
||||
|
||||
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
|
||||
{
|
||||
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:
|
||||
Unit* _owner;
|
||||
InstanceScript* _instance;
|
||||
SOUND_PTAH_EARTHQUAKE = 18908
|
||||
};
|
||||
|
||||
// 39428 Earthrager Ptah
|
||||
class boss_earthrager_ptah : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -96,82 +88,35 @@ public:
|
||||
|
||||
struct boss_earthrager_ptahAI : public BossAI
|
||||
{
|
||||
boss_earthrager_ptahAI(Creature* creature) : BossAI(creature, DATA_EARTHRAGER_PTAH), _summonDeaths(0), _hasDispersed(false) { }
|
||||
boss_earthrager_ptahAI(Creature* creature) : BossAI(creature, DATA_EARTHRAGER_PTAH)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
void Initialize()
|
||||
{
|
||||
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();
|
||||
_hasDispersed = false;
|
||||
_summonsMaxCount = 0;
|
||||
_summonsDeadCount = 0;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_summonDeaths = 0;
|
||||
_hasDispersed = false;
|
||||
Initialize();
|
||||
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);
|
||||
events.SetPhase(PHASE_FIGHT);
|
||||
ScheduleEvents();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (me->HealthBelowPctDamaged(50, damage) && (events.GetPhaseMask() & PHASE_MASK_NORMAL) && !_hasDispersed)
|
||||
{
|
||||
events.SetPhase(PHASE_DISPERSE);
|
||||
_hasDispersed = true;
|
||||
if (action != ACTION_PTAH_ADD_DIED)
|
||||
return;
|
||||
|
||||
me->AttackStop();
|
||||
DoCast(me, SPELL_SANDSTORM);
|
||||
me->GetMap()->SetZoneWeather(AREA_TOMB_OF_THE_EARTHRAGER, WEATHER_STATE_LIGHT_SANDSTORM, 1.0f);
|
||||
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::RandomResize(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::RandomResize(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*/) override
|
||||
{
|
||||
if (index == DATA_SUMMON_DEATHS)
|
||||
{
|
||||
++_summonDeaths;
|
||||
if (_summonDeaths == 11) // All summons died
|
||||
{
|
||||
me->GetMap()->SetZoneWeather(AREA_TOMB_OF_THE_EARTHRAGER, WEATHER_STATE_FOG, 0.0f);
|
||||
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);
|
||||
}
|
||||
}
|
||||
// Increase _summonsDeadCount and check if max reached.
|
||||
if (++_summonsDeadCount == _summonsMaxCount)
|
||||
ExitDispersePhase();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
@@ -181,6 +126,23 @@ public:
|
||||
_JustEngagedWith();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
|
||||
{
|
||||
// About to die? One-hit cases...
|
||||
if (int64(me->GetHealth()) - int64(damage) <= 0)
|
||||
return;
|
||||
|
||||
// Earthquake phase happens at 50% health remaining.
|
||||
if (me->HealthBelowPctDamaged(50, damage) && !_hasDispersed)
|
||||
EnterDispersePhase();
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_PLAYER_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
|
||||
@@ -193,7 +155,6 @@ public:
|
||||
{
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
|
||||
_JustReachedHome();
|
||||
instance->SetBossState(DATA_EARTHRAGER_PTAH, FAIL);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -212,37 +173,109 @@ public:
|
||||
{
|
||||
case EVENT_RAGING_SMASH:
|
||||
DoCastVictim(SPELL_RAGING_SMASH);
|
||||
events.ScheduleEvent(EVENT_RAGING_SMASH, urand(7000, 12000), 0, PHASE_NORMAL);
|
||||
events.Repeat(Seconds(19));
|
||||
break;
|
||||
case EVENT_FLAME_BOLT:
|
||||
DoCast(me, SPELL_FLAME_BOLT);
|
||||
events.ScheduleEvent(EVENT_FLAME_BOLT, 15000, 0, PHASE_NORMAL);
|
||||
events.Repeat(Seconds(21));
|
||||
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);
|
||||
events.Repeat(Seconds(15));
|
||||
break;
|
||||
case EVENT_PTAH_EXPLODE:
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_UPDATE_PRIORITY, me, 0);
|
||||
Talk(SAY_SPECIAL);
|
||||
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);
|
||||
DoCast(target, SPELL_SUMMON_QUICKSAND);
|
||||
events.Repeat(Seconds(21)); //Seconds(10)
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
if (events.GetPhaseMask() & PHASE_MASK_NORMAL) // Do not melee in the disperse phase
|
||||
if (!events.IsInPhase(PHASE_EARTHSTORM)) // Do not melee in the disperse phase
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8 _summonDeaths;
|
||||
private:
|
||||
void ScheduleEvents()
|
||||
{
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_RAGING_SMASH, Seconds(7), 0, PHASE_FIGHT); // Seconds(12)
|
||||
events.ScheduleEvent(EVENT_FLAME_BOLT, Seconds(8), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_EARTH_SPIKE, Seconds(15), 0, PHASE_FIGHT); // Seconds(21)
|
||||
}
|
||||
|
||||
void EnterDispersePhase()
|
||||
{
|
||||
events.SetPhase(PHASE_EARTHSTORM);
|
||||
_hasDispersed = true;
|
||||
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
me->AttackStop();
|
||||
me->GetMap()->SetZoneWeather(AREA_TOMB_OF_THE_EARTHRAGER, WEATHER_STATE_LIGHT_SANDSTORM, 1.0f);
|
||||
DoCast(me, SPELL_SANDSTORM);
|
||||
|
||||
std::list<Creature*> stalkers;
|
||||
GetCreatureListWithEntryInGrid(stalkers, me, NPC_BEETLE_STALKER, 100.0f);
|
||||
for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr)
|
||||
{
|
||||
++_summonsMaxCount;
|
||||
if (-400.f < (*itr)->GetPositionY() && (*itr)->GetPositionY() < -390.f) // 2 stalkers in the middle
|
||||
(*itr)->CastSpell((*itr), SPELL_SUMMON_DUSTBONE_HORROR);
|
||||
else
|
||||
(*itr)->CastSpell((*itr), SPELL_BEETLE_BURROW);
|
||||
}
|
||||
|
||||
events.ScheduleEvent(EVENT_PTAH_EXPLODE, Seconds(6), 0, PHASE_EARTHSTORM);
|
||||
events.ScheduleEvent(EVENT_QUICKSAND, Seconds(10), 0, PHASE_EARTHSTORM);
|
||||
}
|
||||
|
||||
void ExitDispersePhase()
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_PTAH_EXPLOSION);
|
||||
me->GetMap()->SetZoneWeather(AREA_TOMB_OF_THE_EARTHRAGER, WEATHER_STATE_FOG, 0.0f);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_UPDATE_PRIORITY, me, 2);
|
||||
events.SetPhase(PHASE_FIGHT);
|
||||
ScheduleEvents();
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
std::list<Creature*> units;
|
||||
|
||||
GetCreatureListWithEntryInGrid(units, me, NPC_BEETLE_STALKER, 100.0f);
|
||||
for (std::list<Creature*>::iterator itr = units.begin(); itr != units.end(); ++itr)
|
||||
{
|
||||
++_summonsMaxCount;
|
||||
if (-400.f < (*itr)->GetPositionY() && (*itr)->GetPositionY() < -390.f) // 2 stalkers in the middle
|
||||
(*itr)->RemoveAurasDueToSpell(SPELL_SUMMON_DUSTBONE_HORROR);
|
||||
else
|
||||
(*itr)->RemoveAurasDueToSpell(SPELL_BEETLE_BURROW);
|
||||
}
|
||||
|
||||
units.clear();
|
||||
GetCreatureListWithEntryInGrid(units, me, NPC_DUSTBONE_HORROR, 100.0f);
|
||||
for (std::list<Creature*>::iterator itr = units.begin(); itr != units.end(); ++itr)
|
||||
(*itr)->DespawnOrUnsummon();
|
||||
|
||||
units.clear();
|
||||
GetCreatureListWithEntryInGrid(units, me, NPC_JEWELED_SCARAB, 100.0f);
|
||||
for (std::list<Creature*>::iterator itr = units.begin(); itr != units.end(); ++itr)
|
||||
(*itr)->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
bool _hasDispersed;
|
||||
uint8 _summonsMaxCount;
|
||||
uint8 _summonsDeadCount;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -251,6 +284,62 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// 15989 (criteria ID) Straw That Broke the Camel's Back
|
||||
class achievement_straw_broke_camels_back : public AchievementCriteriaScript
|
||||
{
|
||||
public:
|
||||
achievement_straw_broke_camels_back() : AchievementCriteriaScript("achievement_straw_broke_camels_back") { }
|
||||
|
||||
bool OnCheck(Player* player, Unit* /*target*/) override
|
||||
{
|
||||
if (Unit* vehicle = player->GetVehicleBase())
|
||||
return vehicle->GetEntry() == NPC_HOO_CAMEL;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 40459 Beetle Stalker
|
||||
class npc_ptah_beetle_stalker : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_ptah_beetle_stalker() : CreatureScript("npc_ptah_beetle_stalker") { }
|
||||
|
||||
struct npc_ptah_beetle_stalkerAI : public ScriptedAI
|
||||
{
|
||||
npc_ptah_beetle_stalkerAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void SpellHit(Unit* /*caster*/, const SpellInfo* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_BEETLE_BURROW)
|
||||
events.ScheduleEvent(EVENT_SUMMON_JEWELED_SCARAB, Seconds(5), Seconds(6));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (events.Empty())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (events.ExecuteEvent() == EVENT_SUMMON_JEWELED_SCARAB)
|
||||
{
|
||||
DoCastAOE(SPELL_SUMMON_JEWELED_SCARAB);
|
||||
me->RemoveAurasDueToSpell(SPELL_BEETLE_BURROW);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_ptah_beetle_stalkerAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_earthrager_ptah_flame_bolt : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
@@ -277,6 +366,34 @@ class spell_earthrager_ptah_flame_bolt : public SpellScriptLoader
|
||||
}
|
||||
};
|
||||
|
||||
// 75491 Sandstorm spell_earthrager_ptah_sandstorm
|
||||
class spell_earthrager_ptah_sandstorm : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_earthrager_ptah_sandstorm() : SpellScriptLoader("spell_earthrager_ptah_sandstorm") { }
|
||||
|
||||
class spell_earthrager_ptah_sandstorm_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_earthrager_ptah_sandstorm_SpellScript);
|
||||
|
||||
void PlaySound(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Player* player = GetHitUnit()->ToPlayer())
|
||||
GetCaster()->PlayDirectSound(SOUND_PTAH_EARTHQUAKE, player);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_earthrager_ptah_sandstorm_SpellScript::PlaySound, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_earthrager_ptah_sandstorm_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
class spell_earthrager_ptah_explosion : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
@@ -304,14 +421,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void Register()
|
||||
void Register() override
|
||||
{
|
||||
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
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_earthrager_ptah_explosion_AuraScript();
|
||||
}
|
||||
@@ -320,6 +437,9 @@ public:
|
||||
void AddSC_boss_earthrager_ptah()
|
||||
{
|
||||
new boss_earthrager_ptah();
|
||||
new achievement_straw_broke_camels_back();
|
||||
new npc_ptah_beetle_stalker();
|
||||
new spell_earthrager_ptah_flame_bolt();
|
||||
new spell_earthrager_ptah_sandstorm();
|
||||
new spell_earthrager_ptah_explosion();
|
||||
}
|
||||
|
||||
859
src/server/scripts/Kalimdor/HallsOfOrigination/boss_isiset.cpp
Normal file
859
src/server/scripts/Kalimdor/HallsOfOrigination/boss_isiset.cpp
Normal file
@@ -0,0 +1,859 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2018 TrinityCore <https://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 "GridNotifiers.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "halls_of_origination.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SUPERNOVA = 74136,
|
||||
SPELL_SUPERNOVA_EFFECT = 74137,
|
||||
|
||||
// Startfall / Astral Rain ability
|
||||
SPELL_ASTRAL_RAIN_CONTROLLER = 74381,
|
||||
SPELL_ASTRAL_RAIN_1 = 74134,
|
||||
SPELL_ASTRAL_RAIN_2 = 74365,
|
||||
SPELL_ASTRAL_RAIN_3 = 74371,
|
||||
|
||||
// Adds / Celestial Call ability
|
||||
SPELL_ASTRAL_FAMILIAR_CONTROLLER = 74383,
|
||||
SPELL_CELESTIAL_CALL_1 = 74362,
|
||||
SPELL_CELESTIAL_CALL_2 = 74355,
|
||||
SPELL_CELESTIAL_CALL_3 = 74364,
|
||||
|
||||
// Mana shield / Veil of Sky ability
|
||||
SPELL_MANA_SHIELD_CONTROLLER = 74382,
|
||||
SPELL_VEIL_OF_SKY_1 = 74133,
|
||||
SPELL_VEIL_OF_SKY_2 = 74372,
|
||||
SPELL_VEIL_OF_SKY_3 = 74373,
|
||||
SPELL_VEIL_OF_SKY_DAMAGE = 79370,
|
||||
|
||||
// Mirror Images (at 66% and 33%)
|
||||
SPELL_MIRROR_IMAGE_STARRY_SKY_SPAWNER = 69941,
|
||||
SPELL_MIRROR_IMAGE_STARRY_SKY_N = 69936,
|
||||
SPELL_MIRROR_IMAGE_STARRY_SKY_E = 69939,
|
||||
SPELL_MIRROR_IMAGE_STARRY_SKY_W = 69940,
|
||||
SPELL_ASTRAL_SHIFT = 74312,
|
||||
SPELL_ASTRAL_SHIFT_EXPLOSION = 74333,
|
||||
SPELL_MIRROR_IMAGE_SPAWNER = 74264,
|
||||
SPELL_MIRROR_IMAGE_N = 74263,
|
||||
SPELL_MIRROR_IMAGE_E = 74262,
|
||||
SPELL_MIRROR_IMAGE_W = 74261,
|
||||
SPELL_ADDS_STATE_VISUAL = 74289,
|
||||
SPELL_STARFALL_STATE_VISUAL = 74265,
|
||||
SPELL_MANA_SHIELD_STATE_VISUAL = 74266,
|
||||
SPELL_IMAGE_EXPLOSION = 74301,
|
||||
|
||||
// Celestial Familiar npc
|
||||
SPELL_ORB_VISUAL = 74356,
|
||||
SPELL_ARCANE_BARRAGE = 74374,
|
||||
|
||||
// Starry Sky npc
|
||||
SPELL_STARRY_SKY_VISUAL = 74149,
|
||||
|
||||
// Astral Shift Explosion Visual npc
|
||||
SPELL_ASTRAL_SHIFT_EXPLOSION_VISUAL = 74331,
|
||||
|
||||
// Spatial Flux & Energy Flux (heroic only)
|
||||
SPELL_CALL_OF_SKY = 90750 // Summons Spatial Flux (npc script in halls_of_oriignation.cpp)
|
||||
};
|
||||
|
||||
enum NPCs
|
||||
{
|
||||
NPC_CELESTIAL_FAMILIAR = 39795,
|
||||
NPC_ASTRAL_RAIN = 39720, // N
|
||||
NPC_CELESTIAL_CALL = 39721, // E
|
||||
NPC_VEIL_OF_SKY = 39722, // W
|
||||
NPC_ISISET_SPATIAL_FLUX = 48707 // heroic only
|
||||
};
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SUPERNOVA = 1,
|
||||
SAY_SUPERNOVA_WARNING = 2,
|
||||
SAY_PLAYER_KILL = 3,
|
||||
SAY_DEATH = 4
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SUPERNOVA = 1,
|
||||
EVENT_ASTRAL_RAIN,
|
||||
EVENT_ASTRAL_FAMILIAR,
|
||||
EVENT_VEIL_OF_SKY,
|
||||
EVENT_IMAGES_ATTACK,
|
||||
EVENT_DESPAWN_IMAGES,
|
||||
|
||||
EVENT_ORB_ADD_VISUAL,
|
||||
EVENT_ORB_SET_AGGRESSIVE,
|
||||
EVENT_ORB_ARCANE_BARRAGE,
|
||||
|
||||
EVENT_IMAGE_ASTRAL_RAIN_ABILITY,
|
||||
EVENT_IMAGE_ARCANE_BARRAGE_ABILITY,
|
||||
EVENT_IMAGE_VEIL_OF_SKY_ABILITY,
|
||||
|
||||
EVENT_STARRY_SKY_ADD_VISUAL,
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_IMAGES_SET_AGGRESSIVE,
|
||||
ACTION_MIRROR_IMAGE_DIED,
|
||||
ACTION_IMAGES_SET_PASSIVE,
|
||||
ACTION_IMAGES_DESPAWN
|
||||
};
|
||||
|
||||
class boss_isiset : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_isiset() : CreatureScript("boss_isiset") { }
|
||||
|
||||
struct boss_isisetAI : public BossAI
|
||||
{
|
||||
boss_isisetAI(Creature* creature) : BossAI(creature, DATA_ISISET) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
_transitionPhase = false;
|
||||
instance->SetData(DATA_ISISET_PHASE, 1);
|
||||
instance->SetData(DATA_ISISET_ASTRAL_RAIN_ALIVE, 1);
|
||||
instance->SetData(DATA_ISISET_CELESTIAL_CALL_ALIVE, 1);
|
||||
instance->SetData(DATA_ISISET_VEIL_OF_SKY_ALIVE, 1);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
if (IsHeroic())
|
||||
DoCastSelf(SPELL_CALL_OF_SKY);
|
||||
RescheduleEvents();
|
||||
_JustEngagedWith();
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_SET_COMBAT_RES_LIMIT, 0);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
|
||||
{
|
||||
if (_transitionPhase)
|
||||
return;
|
||||
|
||||
// Second transition
|
||||
if (instance->GetData(DATA_ISISET_PHASE) == 2 && me->HealthBelowPctDamaged(33, damage))
|
||||
MirrorImage();
|
||||
|
||||
// First transition
|
||||
if (instance->GetData(DATA_ISISET_PHASE) == 1 && me->HealthBelowPctDamaged(66, damage))
|
||||
MirrorImage();
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
// We only accept action from the first dying image
|
||||
if (_mirrorImageDied || action != ACTION_MIRROR_IMAGE_DIED)
|
||||
return;
|
||||
|
||||
_mirrorImageDied = true;
|
||||
|
||||
// Handle despawning
|
||||
DummyEntryCheckPredicate pred;
|
||||
summons.DoAction(ACTION_IMAGES_SET_PASSIVE, pred);
|
||||
events.ScheduleEvent(EVENT_DESPAWN_IMAGES, Seconds(2));
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
if (who->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_PLAYER_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
//instance->SendEncounterUnit(ENCOUNTER_FRAME_SET_COMBAT_RES_LIMIT, ?me?, 1); //from sniff, not sure what it does
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me, 0);
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ASTRAL_RAIN:
|
||||
DoCastSelf(SPELL_ASTRAL_RAIN_CONTROLLER);
|
||||
events.Repeat(Seconds(15), Seconds(19));
|
||||
break;
|
||||
case EVENT_ASTRAL_FAMILIAR:
|
||||
DoCastSelf(SPELL_ASTRAL_FAMILIAR_CONTROLLER);
|
||||
events.Repeat(Seconds(26), Seconds(30));
|
||||
break;
|
||||
case EVENT_VEIL_OF_SKY:
|
||||
DoCastSelf(SPELL_MANA_SHIELD_CONTROLLER);
|
||||
events.Repeat(Seconds(20), Seconds(25));
|
||||
break;
|
||||
case EVENT_SUPERNOVA:
|
||||
DoCastSelf(SPELL_SUPERNOVA);
|
||||
Talk(SAY_SUPERNOVA);
|
||||
Talk(SAY_SUPERNOVA_WARNING);
|
||||
events.Repeat(Seconds(45), Seconds(50));
|
||||
break;
|
||||
case EVENT_IMAGES_ATTACK:
|
||||
{
|
||||
DummyEntryCheckPredicate pred;
|
||||
summons.DoAction(ACTION_IMAGES_SET_AGGRESSIVE, pred);
|
||||
break;
|
||||
}
|
||||
case EVENT_DESPAWN_IMAGES:
|
||||
{
|
||||
DummyEntryCheckPredicate pred;
|
||||
summons.DoAction(ACTION_IMAGES_DESPAWN, pred);
|
||||
instance->SetData(DATA_ISISET_PHASE, instance->GetData(DATA_ISISET_PHASE) + 1);
|
||||
_transitionPhase = false;
|
||||
me->RemoveAurasDueToSpell(SPELL_ASTRAL_SHIFT);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_UPDATE_PRIORITY, me, 1);
|
||||
RescheduleEvents();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
void RescheduleEvents()
|
||||
{
|
||||
events.Reset();
|
||||
if (instance->GetData(DATA_ISISET_ASTRAL_RAIN_ALIVE))
|
||||
events.ScheduleEvent(EVENT_ASTRAL_RAIN, Seconds(4), Seconds(6));
|
||||
if (instance->GetData(DATA_ISISET_CELESTIAL_CALL_ALIVE))
|
||||
events.ScheduleEvent(EVENT_ASTRAL_FAMILIAR, Seconds(7));
|
||||
if (instance->GetData(DATA_ISISET_VEIL_OF_SKY_ALIVE))
|
||||
events.ScheduleEvent(EVENT_VEIL_OF_SKY, Seconds(8), Seconds(10));
|
||||
events.ScheduleEvent(EVENT_SUPERNOVA, Seconds(12), Seconds(17));
|
||||
}
|
||||
|
||||
// Mirror Image transition phase
|
||||
void MirrorImage()
|
||||
{
|
||||
_transitionPhase = true;
|
||||
|
||||
events.Reset();
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_UPDATE_PRIORITY, me, 0);
|
||||
_mirrorImageDied = false;
|
||||
|
||||
DoCastSelf(SPELL_ASTRAL_SHIFT);
|
||||
DoCastSelf(SPELL_ASTRAL_SHIFT_EXPLOSION);
|
||||
DoCastSelf(SPELL_MIRROR_IMAGE_STARRY_SKY_SPAWNER);
|
||||
DoCastSelf(SPELL_MIRROR_IMAGE_SPAWNER);
|
||||
|
||||
events.ScheduleEvent(EVENT_IMAGES_ATTACK, Seconds(2));
|
||||
}
|
||||
|
||||
bool _transitionPhase;
|
||||
bool _mirrorImageDied;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<boss_isisetAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 39795 - Celestial Familiar
|
||||
class npc_celestial_familiar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_celestial_familiar() : CreatureScript("npc_celestial_familiar") { }
|
||||
|
||||
struct npc_celestial_familiarAI : public ScriptedAI
|
||||
{
|
||||
npc_celestial_familiarAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetInCombatWithZone();
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_ORB_ADD_VISUAL, Seconds(1));
|
||||
events.ScheduleEvent(EVENT_ORB_SET_AGGRESSIVE, Seconds(2));
|
||||
events.ScheduleEvent(EVENT_ORB_ARCANE_BARRAGE, Seconds(4), Seconds(6));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ORB_ADD_VISUAL:
|
||||
DoCastSelf(SPELL_ORB_VISUAL);
|
||||
break;
|
||||
case EVENT_ORB_SET_AGGRESSIVE:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
break;
|
||||
case EVENT_ORB_ARCANE_BARRAGE:
|
||||
DoCastSelf(SPELL_ARCANE_BARRAGE);
|
||||
events.Repeat(Seconds(6), Seconds(7));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_celestial_familiarAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 39720 - Astral Rain
|
||||
// 39721 - Celestial Call
|
||||
// 39722 - Veil of Sky
|
||||
class npc_isiset_mirror_image : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_isiset_mirror_image() : CreatureScript("npc_isiset_mirror_image") { }
|
||||
|
||||
struct npc_isiset_mirror_imageAI : public ScriptedAI
|
||||
{
|
||||
npc_isiset_mirror_imageAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
_instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
|
||||
|
||||
switch (me->GetEntry()) {
|
||||
case NPC_ASTRAL_RAIN:
|
||||
_events.ScheduleEvent(EVENT_IMAGE_ASTRAL_RAIN_ABILITY, Seconds(3), Seconds(5));
|
||||
DoCastSelf(SPELL_STARFALL_STATE_VISUAL);
|
||||
break;
|
||||
case NPC_CELESTIAL_CALL:
|
||||
_events.ScheduleEvent(EVENT_IMAGE_ARCANE_BARRAGE_ABILITY, Seconds(6));
|
||||
DoCastSelf(SPELL_ADDS_STATE_VISUAL);
|
||||
break;
|
||||
case NPC_VEIL_OF_SKY:
|
||||
_events.ScheduleEvent(EVENT_IMAGE_VEIL_OF_SKY_ABILITY, Seconds(8), Seconds(9));
|
||||
//DoCastSelf(SPELL_MANA_SHIELD_STATE_VISUAL); // Disabled in sniffs/on retail, too shiny.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
|
||||
{
|
||||
// Because only one image explodes, others become passive
|
||||
if (me->GetReactState() != REACT_AGGRESSIVE || me->GetHealth() > damage)
|
||||
return;
|
||||
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
damage = me->GetHealth() - 1;
|
||||
DoCastSelf(SPELL_IMAGE_EXPLOSION);
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_IMAGES_SET_AGGRESSIVE:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetInCombatWithZone();
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
|
||||
AttackStart(target);
|
||||
break;
|
||||
case ACTION_IMAGES_SET_PASSIVE:
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
break;
|
||||
case ACTION_IMAGES_DESPAWN:
|
||||
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
|
||||
me->DespawnOrUnsummon();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_IMAGE_ASTRAL_RAIN_ABILITY:
|
||||
DoCastSelf(SPELL_ASTRAL_RAIN_CONTROLLER);
|
||||
_events.Repeat(Seconds(16), Seconds(19));
|
||||
break;
|
||||
case EVENT_IMAGE_ARCANE_BARRAGE_ABILITY:
|
||||
DoCastSelf(SPELL_ARCANE_BARRAGE);
|
||||
_events.Repeat(Seconds(8), Seconds(10));
|
||||
break;
|
||||
case EVENT_IMAGE_VEIL_OF_SKY_ABILITY:
|
||||
DoCastSelf(SPELL_VEIL_OF_SKY_1); // Veil of Sky npc does not cast controller spell!
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_isiset_mirror_imageAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 74381 - Astral Rain Controller Spell
|
||||
class spell_isiset_astral_rain_controller : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_astral_rain_controller() : SpellScriptLoader("spell_isiset_astral_rain_controller") { }
|
||||
|
||||
class spell_isiset_astral_rain_controller_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_astral_rain_controller_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({
|
||||
SPELL_ASTRAL_RAIN_1,
|
||||
SPELL_ASTRAL_RAIN_2,
|
||||
SPELL_ASTRAL_RAIN_3
|
||||
});
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
InstanceScript* instance = GetCaster()->GetInstanceScript();
|
||||
if (!instance || !instance->GetData(DATA_ISISET_ASTRAL_RAIN_ALIVE))
|
||||
return;
|
||||
|
||||
uint32 phase = instance->GetData(DATA_ISISET_PHASE);
|
||||
if (phase == 1)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_ASTRAL_RAIN_1, true);
|
||||
else if (phase == 2)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_ASTRAL_RAIN_2, true);
|
||||
else if (phase == 3)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_ASTRAL_RAIN_3, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunch += SpellEffectFn(spell_isiset_astral_rain_controller_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_astral_rain_controller_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74382 - Mana Shield Controller Spell
|
||||
class spell_isiset_mana_shield_controller : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_mana_shield_controller() : SpellScriptLoader("spell_isiset_mana_shield_controller") { }
|
||||
|
||||
class spell_isiset_mana_shield_controller_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_mana_shield_controller_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({
|
||||
SPELL_VEIL_OF_SKY_1,
|
||||
SPELL_VEIL_OF_SKY_2,
|
||||
SPELL_VEIL_OF_SKY_3
|
||||
});
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
InstanceScript* instance = GetCaster()->GetInstanceScript();
|
||||
if (!instance || !instance->GetData(DATA_ISISET_VEIL_OF_SKY_ALIVE))
|
||||
return;
|
||||
|
||||
uint32 phase = instance->GetData(DATA_ISISET_PHASE);
|
||||
if (phase == 1)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_VEIL_OF_SKY_1);
|
||||
else if (phase == 2)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_VEIL_OF_SKY_2);
|
||||
else if (phase == 3)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_VEIL_OF_SKY_3);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunch += SpellEffectFn(spell_isiset_mana_shield_controller_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_mana_shield_controller_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74383 - Astral Familiar Controller Spell
|
||||
class spell_isiset_astral_familiar_controller : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_astral_familiar_controller() : SpellScriptLoader("spell_isiset_astral_familiar_controller") { }
|
||||
|
||||
class spell_isiset_astral_familiar_controller_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_astral_familiar_controller_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({
|
||||
SPELL_CELESTIAL_CALL_1,
|
||||
SPELL_CELESTIAL_CALL_2,
|
||||
SPELL_CELESTIAL_CALL_3
|
||||
});
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
InstanceScript* instance = GetCaster()->GetInstanceScript();
|
||||
if (!instance || !instance->GetData(DATA_ISISET_CELESTIAL_CALL_ALIVE))
|
||||
return;
|
||||
|
||||
uint32 phase = instance->GetData(DATA_ISISET_PHASE);
|
||||
if (phase == 1)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_CELESTIAL_CALL_1, true);
|
||||
else if (phase == 2)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_CELESTIAL_CALL_2, true);
|
||||
else if (phase == 3)
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_CELESTIAL_CALL_3, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunch += SpellEffectFn(spell_isiset_astral_familiar_controller_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_astral_familiar_controller_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74133, 74372, 74373 - Veil of Sky (mana shield)
|
||||
class spell_isiset_veil_of_sky : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_veil_of_sky() : SpellScriptLoader("spell_isiset_veil_of_sky") { }
|
||||
|
||||
class spell_isiset_veil_of_sky_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_isiset_veil_of_sky_AuraScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_VEIL_OF_SKY_DAMAGE });
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
reflectPct = GetSpellInfo()->Effects[EFFECT_1].BasePoints;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Trigger(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount)
|
||||
{
|
||||
if (dmgInfo.GetDamageType() != SPELL_DIRECT_DAMAGE)
|
||||
return;
|
||||
|
||||
int32 damage = CalculatePct(absorbAmount, reflectPct);
|
||||
GetCaster()->CastCustomSpell(SPELL_VEIL_OF_SKY_DAMAGE, SPELLVALUE_BASE_POINT0, damage, dmgInfo.GetAttacker(), true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectManaShield += AuraEffectManaShieldFn(spell_isiset_veil_of_sky_AuraScript::Trigger, EFFECT_0);
|
||||
}
|
||||
|
||||
private:
|
||||
int32 reflectPct;
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_isiset_veil_of_sky_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74137 - Supernova (disorient + triggers 76670) (are pets also affected?)
|
||||
// 76670 - Supernova (damage)
|
||||
class spell_isiset_supernova_filter : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_supernova_filter() : SpellScriptLoader("spell_isiset_supernova_filter") { }
|
||||
|
||||
class spell_isiset_supernova_filter_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_supernova_filter_SpellScript);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
targets.remove_if([caster](WorldObject* object) { return !object->ToUnit() || !object->ToUnit()->IsCharmedOwnedByPlayerOrPlayer() || !object->isInFront(caster, 2.5f); });
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_isiset_supernova_filter_SpellScript::FilterTargets, m_scriptSpellId == SPELL_SUPERNOVA_EFFECT ? EFFECT_1 : EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_supernova_filter_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 69941 - Mirror Image
|
||||
class spell_isiset_mirror_image_starry_sky_spawner : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_mirror_image_starry_sky_spawner() : SpellScriptLoader("spell_isiset_mirror_image_starry_sky_spawner") { }
|
||||
|
||||
class spell_isiset_mirror_image_starry_sky_spawner_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_mirror_image_starry_sky_spawner_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_MIRROR_IMAGE_STARRY_SKY_N, SPELL_MIRROR_IMAGE_STARRY_SKY_E, SPELL_MIRROR_IMAGE_STARRY_SKY_W });
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
InstanceScript* instance = GetCaster()->GetInstanceScript();
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
if (instance->GetData(DATA_ISISET_CELESTIAL_CALL_ALIVE))
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_MIRROR_IMAGE_STARRY_SKY_N, true);
|
||||
if (instance->GetData(DATA_ISISET_ASTRAL_RAIN_ALIVE))
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_MIRROR_IMAGE_STARRY_SKY_E, true);
|
||||
if (instance->GetData(DATA_ISISET_VEIL_OF_SKY_ALIVE))
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_MIRROR_IMAGE_STARRY_SKY_W, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunch += SpellEffectFn(spell_isiset_mirror_image_starry_sky_spawner_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_mirror_image_starry_sky_spawner_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74264 - Mirror Image
|
||||
class spell_isiset_mirror_image_spawner : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_mirror_image_spawner() : SpellScriptLoader("spell_isiset_mirror_image_spawner") { }
|
||||
|
||||
class spell_isiset_mirror_image_spawner_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_mirror_image_spawner_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_MIRROR_IMAGE_N, SPELL_MIRROR_IMAGE_E, SPELL_MIRROR_IMAGE_W });
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
InstanceScript* const instance = GetCaster()->GetInstanceScript();
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
if (instance->GetData(DATA_ISISET_CELESTIAL_CALL_ALIVE))
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_MIRROR_IMAGE_N, true);
|
||||
if (instance->GetData(DATA_ISISET_ASTRAL_RAIN_ALIVE))
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_MIRROR_IMAGE_E, true);
|
||||
if (instance->GetData(DATA_ISISET_VEIL_OF_SKY_ALIVE))
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_MIRROR_IMAGE_W, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunch += SpellEffectFn(spell_isiset_mirror_image_spawner_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_mirror_image_spawner_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74301 - Image Explosion
|
||||
class spell_isiset_image_explosion : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_image_explosion() : SpellScriptLoader("spell_isiset_image_explosion") { }
|
||||
|
||||
class spell_isiset_image_explosion_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_image_explosion_SpellScript);
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
InstanceScript* const instance = GetCaster()->GetInstanceScript();
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
switch (GetCaster()->GetEntry())
|
||||
{
|
||||
case NPC_ASTRAL_RAIN:
|
||||
instance->SetData(DATA_ISISET_ASTRAL_RAIN_ALIVE, 0);
|
||||
break;
|
||||
case NPC_CELESTIAL_CALL:
|
||||
instance->SetData(DATA_ISISET_CELESTIAL_CALL_ALIVE, 0);
|
||||
break;
|
||||
case NPC_VEIL_OF_SKY:
|
||||
instance->SetData(DATA_ISISET_VEIL_OF_SKY_ALIVE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Creature* Isiset = instance->GetCreature(DATA_ISISET))
|
||||
Isiset->AI()->DoAction(ACTION_MIRROR_IMAGE_DIED);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunch += SpellEffectFn(spell_isiset_image_explosion_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_image_explosion_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 90755 Call of Sky (heroic only)
|
||||
class spell_isiset_call_of_sky : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_isiset_call_of_sky() : SpellScriptLoader("spell_isiset_call_of_sky") { }
|
||||
|
||||
class spell_isiset_call_of_sky_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_isiset_call_of_sky_SpellScript);
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
|
||||
if (Creature* Isiset = instance->GetCreature(DATA_ISISET))
|
||||
Isiset->SummonCreature(NPC_ISISET_SPATIAL_FLUX, GetHitDest()->GetPositionX(), GetHitDest()->GetPositionY(), GetHitDest()->GetPositionZ(), 2.775074f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunch += SpellEffectFn(spell_isiset_call_of_sky_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_isiset_call_of_sky_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_isiset()
|
||||
{
|
||||
new boss_isiset();
|
||||
new npc_celestial_familiar();
|
||||
new npc_isiset_mirror_image();
|
||||
new spell_isiset_astral_rain_controller();
|
||||
new spell_isiset_mana_shield_controller();
|
||||
new spell_isiset_astral_familiar_controller();
|
||||
new spell_isiset_veil_of_sky();
|
||||
new spell_isiset_supernova_filter();
|
||||
new spell_isiset_mirror_image_starry_sky_spawner();
|
||||
new spell_isiset_mirror_image_spawner();
|
||||
new spell_isiset_image_explosion();
|
||||
new spell_isiset_call_of_sky();
|
||||
}
|
||||
530
src/server/scripts/Kalimdor/HallsOfOrigination/boss_setesh.cpp
Normal file
530
src/server/scripts/Kalimdor/HallsOfOrigination/boss_setesh.cpp
Normal file
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2018 TrinityCore <https://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 "halls_of_origination.h"
|
||||
#include "Map.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CHAOS_BOLT = 77069,
|
||||
SPELL_CHAOS_BLAST = 76674, // Forcecast player to summon npc that Setesh fires missle at.
|
||||
SPELL_SEED_OF_CHAOS = 76888,
|
||||
SPELL_REIGN_OF_CHAOS = 77023,
|
||||
SPELL_CHANNEL_CHAOS_PORTAL = 76784,
|
||||
|
||||
// Chaos Blast
|
||||
SPELL_CHAOS_BLAST_ME = 76737, // Tells Setesh to launch missle at it.
|
||||
SPELL_CHAOS_BLAST_MISSLE = 76676,
|
||||
SPELL_CHAOS_BLAST_AURA = 76681,
|
||||
|
||||
// Seed of Chaos
|
||||
SPELL_SEED_OF_CHAOS_DUMMY = 76865,
|
||||
SPELL_SEED_OF_CHAOS_EXPLOSION = 76870,
|
||||
|
||||
// Void Rift
|
||||
SPELL_VOID_RIFT = 73699,
|
||||
|
||||
// Chaos Portal
|
||||
SPELL_DUMMY_AURA = 94562, // Using random dummy aura without effect - for Setesh to target the correct portal.
|
||||
SPELL_NIGHTMARE_PORTAL_VISUAL = 76714,
|
||||
SPELL_SUMMON_VOID_SENTINEL = 77242, // summons 41208
|
||||
SPELL_SUMMON_VOID_SEEKER = 77271, // summons 41148
|
||||
SPELL_SUMMON_VOID_WYRM_1 = 77272, // summons 41212
|
||||
SPELL_SUMMON_VOID_WYRM_2 = 79439, // summons 41212
|
||||
|
||||
// Add Stalker
|
||||
SPELL_CHANNEL_SUMMON_ADDS = 77607
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
// Ammunae
|
||||
EVENT_CHAOS_PORTAL = 1,
|
||||
EVENT_CONTINUE_FIGHT,
|
||||
EVENT_CHAOS_BLAST,
|
||||
EVENT_SEED_OF_CHAOS,
|
||||
EVENT_REIGN_OF_CHAOS,
|
||||
|
||||
// Chaos Portal
|
||||
EVENT_CAST_VISUAL,
|
||||
EVENT_SUMMON_WAVE_1,
|
||||
EVENT_SUMMON_WAVE_2,
|
||||
EVENT_SUMMON_WAVE_3,
|
||||
EVENT_SUMMON_WAVE_RANDOM
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_SETESH_ATTACK
|
||||
};
|
||||
enum Faction
|
||||
{
|
||||
FACTION_ENEMY_14 = 14,
|
||||
FACTION_ENEMY_16 = 16
|
||||
};
|
||||
|
||||
enum Phases
|
||||
{
|
||||
PHASE_FIGHT = 1,
|
||||
PHASE_CHAOS_PORTAL = 2
|
||||
};
|
||||
|
||||
enum Points
|
||||
{
|
||||
POINT_CHANNEL_CHAOS_PORTAL,
|
||||
POINT_GROUND
|
||||
};
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_DEATH = 0,
|
||||
SAY_AGGRO = 1,
|
||||
SAY_SPECIAL = 2,
|
||||
SAY_PLAYER_KILL = 3
|
||||
};
|
||||
|
||||
class NPCEntryPred : public std::unary_function<Unit*, bool>
|
||||
{
|
||||
public:
|
||||
NPCEntryPred(uint32 entry) : _entry(entry) { }
|
||||
|
||||
bool operator()(Unit* unit) const { return unit->GetEntry() == _entry; }
|
||||
|
||||
private:
|
||||
uint32 _entry;
|
||||
};
|
||||
|
||||
// 39732 Setesh <Construct of Destruction>
|
||||
class boss_setesh : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_setesh() : CreatureScript("boss_setesh") { }
|
||||
|
||||
struct boss_seteshAI : public BossAI
|
||||
{
|
||||
boss_seteshAI(Creature* creature) : BossAI(creature, DATA_SETESH) { }
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
Talk(SAY_AGGRO);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
|
||||
|
||||
events.ScheduleEvent(EVENT_CHAOS_PORTAL, Seconds(5));
|
||||
events.ScheduleEvent(EVENT_CHAOS_BLAST, Seconds(15));
|
||||
events.ScheduleEvent(EVENT_SEED_OF_CHAOS, Seconds(20));
|
||||
events.ScheduleEvent(EVENT_REIGN_OF_CHAOS, Seconds(30));
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_PLAYER_KILL);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
_EnterEvadeMode();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*who*/) override
|
||||
{
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
BossAI::JustSummoned(summon);
|
||||
|
||||
switch (summon->GetEntry())
|
||||
{
|
||||
case NPC_SETESH_VOID_RIFT:
|
||||
summon->CastSpell((Unit*)nullptr, SPELL_VOID_RIFT, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 pointId) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
switch (pointId)
|
||||
{
|
||||
case POINT_CHANNEL_CHAOS_PORTAL:
|
||||
if (Unit* npcChaosPortal = SelectTarget(SELECT_TARGET_NEAREST, 0, 0.0f, false, SPELL_DUMMY_AURA))
|
||||
DoCast(npcChaosPortal, SPELL_CHANNEL_CHAOS_PORTAL);
|
||||
events.ScheduleEvent(EVENT_CONTINUE_FIGHT, Seconds(5));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action != ACTION_SETESH_ATTACK)
|
||||
return;
|
||||
|
||||
// Start attacking
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
events.SetPhase(PHASE_FIGHT);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || !CheckInRoom())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING) || events.IsInPhase(PHASE_CHAOS_PORTAL))
|
||||
return;
|
||||
|
||||
while(uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CHAOS_PORTAL:
|
||||
StartChaosPortalPhase();
|
||||
events.Repeat(Seconds(45));
|
||||
break;
|
||||
case EVENT_CHAOS_BLAST:
|
||||
DoCast(SPELL_CHAOS_BLAST);
|
||||
events.Repeat(Seconds(20));
|
||||
break;
|
||||
case EVENT_SEED_OF_CHAOS:
|
||||
DoCast(SPELL_SEED_OF_CHAOS);
|
||||
events.Repeat(Seconds(40));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
// Journal: Setesh casts Chaos Bolt at random players instead of performing a melee attack.
|
||||
if (events.IsInPhase(PHASE_CHAOS_PORTAL) || !me->isAttackReady())
|
||||
return;
|
||||
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
|
||||
{
|
||||
me->SetTarget(target->GetGUID());
|
||||
DoCast(target, SPELL_CHAOS_BOLT);
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void StartChaosPortalPhase()
|
||||
{
|
||||
Unit* npcChaosPortal = SelectTarget(SELECT_TARGET_FARTHEST, 0, NPCEntryPred(NPC_SETESH_CHAOS_PORTAL));
|
||||
if (!npcChaosPortal)
|
||||
return;
|
||||
|
||||
events.SetPhase(PHASE_CHAOS_PORTAL);
|
||||
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
me->AttackStop();
|
||||
|
||||
Talk(SAY_SPECIAL);
|
||||
|
||||
// Walk towards chaos portal.
|
||||
npcChaosPortal->CastSpell((Unit*)nullptr, SPELL_DUMMY_AURA, true);
|
||||
me->GetMotionMaster()->MoveCloserAndStop(POINT_CHANNEL_CHAOS_PORTAL, npcChaosPortal, 18.0f);
|
||||
}
|
||||
|
||||
void CleanUp()
|
||||
{
|
||||
std::list<Creature*> units;
|
||||
GetCreatureListWithEntryInGrid(units, me, NPC_SETESH_CHAOS_BLAST, 200.0f);
|
||||
for (std::list<Creature*>::iterator itr = units.begin(); itr != units.end(); ++itr)
|
||||
(*itr)->DespawnOrUnsummon();
|
||||
|
||||
units.clear();
|
||||
GetCreatureListWithEntryInGrid(units, me, NPC_SETESH_CHAOS_SEED, 200.0f);
|
||||
for (std::list<Creature*>::iterator itr = units.begin(); itr != units.end(); ++itr)
|
||||
(*itr)->DespawnOrUnsummon();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_seteshAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 41041 Chaos Blast
|
||||
class npc_setesh_chaos_blast : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_setesh_chaos_blast() : CreatureScript("npc_setesh_chaos_blast") { }
|
||||
|
||||
struct npc_setesh_chaos_blastAI : public ScriptedAI
|
||||
{
|
||||
npc_setesh_chaos_blastAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* setesh = instance->GetCreature(DATA_SETESH))
|
||||
setesh->CastSpell(me, SPELL_CHAOS_BLAST_MISSLE, true);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, const SpellInfo* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id != SPELL_CHAOS_BLAST_MISSLE)
|
||||
return;
|
||||
|
||||
DoCastSelf(SPELL_CHAOS_BLAST_AURA);
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_setesh_chaos_blastAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 41126 Chaos Seed
|
||||
class npc_setesh_chaos_seed : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_setesh_chaos_seed() : CreatureScript("npc_setesh_chaos_seed") { }
|
||||
|
||||
struct npc_setesh_chaos_seedAI : public ScriptedAI
|
||||
{
|
||||
npc_setesh_chaos_seedAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
me->SetDisableGravity(true);
|
||||
me->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 7.0f);
|
||||
me->SetFloatValue(UNIT_FIELD_COMBATREACH, 7.0f);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
|
||||
DoCastSelf(SPELL_SEED_OF_CHAOS_DUMMY);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
// Simulate slow fall
|
||||
float x = me->GetPositionX();
|
||||
float y = me->GetPositionY();
|
||||
float z = me->GetPositionZ();
|
||||
Position dest = { x, y, me->GetMap()->GetWaterOrGroundLevel(me->GetPhaseShift(), x, y, z) };
|
||||
const uint32 pathSize = 1;
|
||||
const Position path[pathSize] = { dest };
|
||||
me->GetMotionMaster()->MoveSmoothPath(POINT_GROUND, path, pathSize, true, true);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 pointId) override
|
||||
{
|
||||
if (type != FLIGHT_MOTION_TYPE || pointId != POINT_GROUND)
|
||||
return;
|
||||
|
||||
me->SetDisableGravity(false);
|
||||
me->SetFaction(FACTION_ENEMY_14);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
DoCast(SPELL_SEED_OF_CHAOS_EXPLOSION);
|
||||
|
||||
me->RemoveAurasDueToSpell(SPELL_SEED_OF_CHAOS_DUMMY);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->DespawnOrUnsummon(Seconds(15));
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_setesh_chaos_seedAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 41055 Chaos Portal - add waves:
|
||||
// - Normal: 1) 2x Void Wyrm 2) Void Seeker 3) Void Sentinel
|
||||
// - Heroic: 1) Void Sentinel 2) 2x Void Wyrm 3) Void Seeker 4+) Void Seeker or 2x Void Wyrm
|
||||
class npc_setesh_chaos_portal : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_setesh_chaos_portal() : CreatureScript("npc_setesh_chaos_portal") { }
|
||||
|
||||
struct npc_setesh_chaos_portalAI : public ScriptedAI
|
||||
{
|
||||
npc_setesh_chaos_portalAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
me->SetFaction(FACTION_ENEMY_14);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* caster, const SpellInfo* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id != SPELL_CHANNEL_CHAOS_PORTAL)
|
||||
return;
|
||||
|
||||
caster->InterruptNonMeleeSpells(true, SPELL_CHANNEL_CHAOS_PORTAL);
|
||||
me->RemoveAurasDueToSpell(SPELL_DUMMY_AURA);
|
||||
events.ScheduleEvent(EVENT_CAST_VISUAL, Seconds(1));
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*who*/) override
|
||||
{
|
||||
events.Reset();
|
||||
me->SetRespawnTime(0);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (events.Empty())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CAST_VISUAL:
|
||||
DoCast(SPELL_NIGHTMARE_PORTAL_VISUAL);
|
||||
if (IsHeroic())
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
events.ScheduleEvent(EVENT_SUMMON_WAVE_1, Seconds(4));
|
||||
break;
|
||||
case EVENT_SUMMON_WAVE_1: // Also make Setesh attack.
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* setesh = instance->GetCreature(DATA_SETESH))
|
||||
setesh->GetAI()->DoAction(ACTION_SETESH_ATTACK);
|
||||
if (!IsHeroic()) // Normal
|
||||
SummonVoidWyrms();
|
||||
else // Heroic
|
||||
SummonVoidSentinel();
|
||||
events.ScheduleEvent(EVENT_SUMMON_WAVE_2, !IsHeroic() ? Seconds(12) : Seconds(6));
|
||||
break;
|
||||
case EVENT_SUMMON_WAVE_2:
|
||||
if (!IsHeroic()) // Normal
|
||||
SummonVoidSeeker();
|
||||
else // Heroic
|
||||
SummonVoidWyrms();
|
||||
events.ScheduleEvent(EVENT_SUMMON_WAVE_3, !IsHeroic() ? Seconds(15) : Seconds(10));
|
||||
break;
|
||||
case EVENT_SUMMON_WAVE_3:
|
||||
if (!IsHeroic()) // Normal
|
||||
SummonVoidSentinel();
|
||||
else // Heroic
|
||||
SummonVoidSeeker();
|
||||
// Normal: automatically closes after 3 waves of adds.
|
||||
// Heroic: must be destroyed, summons more adds every 15 seconds after 3 waves.
|
||||
if (!IsHeroic())
|
||||
me->DespawnOrUnsummon(Seconds(5), Seconds(1));
|
||||
else
|
||||
events.ScheduleEvent(EVENT_SUMMON_WAVE_RANDOM, Seconds(15));
|
||||
break;
|
||||
case EVENT_SUMMON_WAVE_RANDOM: // Heroic only.
|
||||
if (urand(0,1)) // 50% chance
|
||||
SummonVoidSeeker();
|
||||
else
|
||||
SummonVoidWyrms();
|
||||
events.Repeat(Seconds(15));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void SummonAreaDamage()
|
||||
{
|
||||
if (Unit* npcSeteshAddStalker = SelectTarget(SELECT_TARGET_RANDOM, 200.0f, NPCEntryPred(NPC_SETESH_ADD_STALKER)))
|
||||
npcSeteshAddStalker->CastSpell(me, SPELL_CHANNEL_SUMMON_ADDS);
|
||||
}
|
||||
|
||||
// Adds
|
||||
void SummonVoidWyrms() { SummonAreaDamage(); DoCast(SPELL_SUMMON_VOID_WYRM_1); DoCast(SPELL_SUMMON_VOID_WYRM_2); }
|
||||
void SummonVoidSeeker() { SummonAreaDamage(); DoCast(SPELL_SUMMON_VOID_SEEKER); }
|
||||
void SummonVoidSentinel() { SummonAreaDamage(); DoCast(SPELL_SUMMON_VOID_SENTINEL); }
|
||||
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_setesh_chaos_portalAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 76674 Chaos Blast
|
||||
class spell_setesh_chaos_blast : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_setesh_chaos_blast() : SpellScriptLoader("spell_setesh_chaos_blast") { }
|
||||
|
||||
class spell_setesh_chaos_blast_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_setesh_chaos_blast_SpellScript);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& unitList)
|
||||
{
|
||||
if (unitList.empty())
|
||||
return;
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
unitList.remove_if([caster](WorldObject* player) { return caster->IsWithinDist(player, 15.0f); });
|
||||
Trinity::Containers::RandomResize(unitList, 1);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_setesh_chaos_blast_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_setesh_chaos_blast_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_setesh()
|
||||
{
|
||||
new boss_setesh();
|
||||
new npc_setesh_chaos_blast();
|
||||
new npc_setesh_chaos_seed();
|
||||
new npc_setesh_chaos_portal();
|
||||
new spell_setesh_chaos_blast();
|
||||
}
|
||||
@@ -15,62 +15,75 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* To-do: */
|
||||
// - AreaTrigger: unknown purpose (id: 1843; pos: front-right stairs) - dust animation, aggro snakes?
|
||||
|
||||
#include "halls_of_origination.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "halls_of_origination.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Map.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "World.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SHIELD = 1,
|
||||
EMOTE_SHIELD = 2,
|
||||
EMOTE_UNSHIELD = 3,
|
||||
SAY_KILL = 4,
|
||||
SAY_DEATH = 5
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SHIELD = 1,
|
||||
EMOTE_SHIELD = 2,
|
||||
EMOTE_UNSHIELD = 3,
|
||||
SAY_KILL = 4,
|
||||
SAY_DEATH = 5
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_DIVINE_RECKONING = 1,
|
||||
EVENT_BURNING_LIGHT,
|
||||
EVENT_SEAR,
|
||||
EVENT_ACHIEVEMENT_FAIL,
|
||||
EVENT_BURNING_LIGHT = 1,
|
||||
EVENT_SEARING_LIGHT = 2,
|
||||
EVENT_DIVINE_RECKONING = 3,
|
||||
EVENT_CAST_SHIELD = 4,
|
||||
EVENT_ACTIVATE_BEACONS = 5,
|
||||
EVENT_CAST_BEAMS = 6,
|
||||
EVENT_ACHIEVEMENT_FAILED = 7
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_DIVINE_RECKONING = 75592,
|
||||
SPELL_BURNING_LIGHT = 75115,
|
||||
SPELL_REVERBERATING_HYMN = 75322,
|
||||
SPELL_SHIELD_OF_LIGHT = 74938,
|
||||
// Fight phase
|
||||
SPELL_DIVINE_RECKONING = 75592,
|
||||
SPELL_BURNING_LIGHT = 75115, // Forces victim to summon Searing Light dummy at its location.
|
||||
|
||||
SPELL_ACTIVATE_BEACONS = 76599,
|
||||
SPELL_TELEPORT = 74969,
|
||||
// Shield phase
|
||||
SPELL_TELEPORT = 74969,
|
||||
SPELL_SHIELD_OF_LIGHT = 74938,
|
||||
SPELL_REVERBERATING_HYMN = 75322,
|
||||
SPELL_ACTIVATE_BEACONS = 76599,
|
||||
SPELL_DEACTIVATE_BEACONS = 76600,
|
||||
|
||||
SPELL_SHIELD_VISUAL_RIGHT = 83698,
|
||||
SPELL_BEAM_OF_LIGHT_RIGHT = 76573,
|
||||
// Cave In Stalker (eyes)
|
||||
SPELL_BURNING_LIGHT_SEAR = 75194,
|
||||
|
||||
SPELL_SHIELD_VISUAL_LEFT = 83697,
|
||||
SPELL_BEAM_OF_LIGHT_LEFT = 74930,
|
||||
// Cave In Stalker (beacons)
|
||||
SPELL_SHIELD_VISUAL_LEFT = 83697,
|
||||
SPELL_SHIELD_VISUAL_RIGHT = 83698,
|
||||
SPELL_BEAM_OF_LIGHT_LEFT = 74930,
|
||||
SPELL_BEAM_OF_LIGHT_RIGHT = 76573
|
||||
};
|
||||
|
||||
SPELL_SEARING_LIGHT = 75194,
|
||||
enum Phases
|
||||
{
|
||||
PHASE_FIGHT = 1,
|
||||
PHASE_SHIELD = 2
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_DISABLE_BEACON = 1,
|
||||
};
|
||||
|
||||
enum AnhuurAchievementData
|
||||
{
|
||||
DATA_I_HATE_THAT_SONG = 1,
|
||||
ACTION_DISABLE_BEACON_L,
|
||||
ACTION_DISABLE_BEACON_R,
|
||||
ACTION_HYMN_EXPIRED
|
||||
};
|
||||
|
||||
class boss_temple_guardian_anhuur : public CreatureScript
|
||||
@@ -82,27 +95,67 @@ public:
|
||||
{
|
||||
boss_temple_guardian_anhuurAI(Creature* creature) : BossAI(creature, DATA_TEMPLE_GUARDIAN_ANHUUR)
|
||||
{
|
||||
_shieldCount = 0;
|
||||
_beacons = 0;
|
||||
_achievement = true;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
uint8 _shieldCount;
|
||||
uint8 _beacons;
|
||||
bool _achievement;
|
||||
void Initialize()
|
||||
{
|
||||
_countShield = 0;
|
||||
_leftBeaconDisabled = false;
|
||||
_rightBeaconDisabled = false;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
_Reset();
|
||||
CleanStalkers();
|
||||
me->MakeInterruptable(false);
|
||||
me->RemoveAurasDueToSpell(SPELL_SHIELD_OF_LIGHT);
|
||||
DoCastAOE(SPELL_DEACTIVATE_BEACONS, true);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
events.SetPhase(PHASE_FIGHT);
|
||||
ScheduleEvents();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
|
||||
{
|
||||
// Already in shield phase? 2 shields are enough.
|
||||
if (events.IsInPhase(PHASE_SHIELD) || _countShield == 2)
|
||||
return;
|
||||
|
||||
// About to die? One-hit cases...
|
||||
if (int64(me->GetHealth()) - int64(damage) <= 0)
|
||||
return;
|
||||
|
||||
// Shield phase happens at 66% and 33% health remaining.
|
||||
if ((me->HealthBelowPctDamaged(66, damage) && _countShield == 0) ||
|
||||
(me->HealthBelowPctDamaged(33, damage) && _countShield == 1))
|
||||
EnterShieldPhase();
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_DISABLE_BEACON_L)
|
||||
_leftBeaconDisabled = true;
|
||||
else if (action == ACTION_DISABLE_BEACON_R)
|
||||
_rightBeaconDisabled = true;
|
||||
else if (action == ACTION_HYMN_EXPIRED) // We manually deactivate beacons.
|
||||
DoCastAOE(SPELL_DEACTIVATE_BEACONS, true);
|
||||
|
||||
// Exit shield phase if both beacons are disabled or channeling Reverberating Hymn finished.
|
||||
if ((_leftBeaconDisabled && _rightBeaconDisabled) || action == ACTION_HYMN_EXPIRED)
|
||||
ExitShieldPhase();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
|
||||
Talk(SAY_AGGRO);
|
||||
_JustEngagedWith();
|
||||
events.ScheduleEvent(EVENT_DIVINE_RECKONING, urand(10000, 12000));
|
||||
events.ScheduleEvent(EVENT_BURNING_LIGHT, 12000);
|
||||
|
||||
instance->DoUpdateWorldState(WS_I_HATE_THIS_SONG, 0);
|
||||
sWorld->setWorldState(WS_I_HATE_THIS_SONG, 0); // To-do: make InstanceScript::DoUpdateWorldState do the World::setWorldState.
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -118,115 +171,26 @@ public:
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
_EnterEvadeMode();
|
||||
CleanStalkers();
|
||||
RespawnPit();
|
||||
_shieldCount = 0;
|
||||
_beacons = 0;
|
||||
_achievement = true;
|
||||
DoCastAOE(SPELL_DEACTIVATE_BEACONS, true);
|
||||
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
events.Reset();
|
||||
_EnterEvadeMode();
|
||||
_DespawnAtEvade();
|
||||
}
|
||||
|
||||
void RespawnPit()
|
||||
void OnSpellCastInterrupt(SpellInfo const* spell) override
|
||||
{
|
||||
std::list<Creature*> snakes;
|
||||
GetCreatureListWithEntryInGrid(snakes, me, NPC_PIT_SNAKE, 500.0f);
|
||||
for (std::list<Creature*>::iterator itr = snakes.begin(); itr != snakes.end(); ++itr)
|
||||
me->MakeInterruptable(false);
|
||||
|
||||
if (spell->Id == SPELL_REVERBERATING_HYMN)
|
||||
{
|
||||
Position const pos = (*itr)->GetHomePosition();
|
||||
(*itr)->Respawn();
|
||||
(*itr)->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
|
||||
events.CancelEvent(EVENT_ACHIEVEMENT_FAILED);
|
||||
DoAction(ACTION_HYMN_EXPIRED);
|
||||
ScheduleEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void CleanStalkers()
|
||||
{
|
||||
std::list<Creature*> stalkers;
|
||||
GetCreatureListWithEntryInGrid(stalkers, me, NPC_CAVE_IN_STALKER, 100.0f);
|
||||
for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr)
|
||||
{
|
||||
(*itr)->RemoveAurasDueToSpell(SPELL_BEAM_OF_LIGHT_RIGHT);
|
||||
(*itr)->RemoveAurasDueToSpell(SPELL_BEAM_OF_LIGHT_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override
|
||||
{
|
||||
if ((me->HealthBelowPct(66) && _shieldCount == 0) ||
|
||||
(me->HealthBelowPct(33) && _shieldCount == 1))
|
||||
{
|
||||
_shieldCount++;
|
||||
_beacons = 2;
|
||||
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
me->AttackStop();
|
||||
DoCast(me, SPELL_TELEPORT);
|
||||
|
||||
DoCastAOE(SPELL_ACTIVATE_BEACONS);
|
||||
DoCast(me, SPELL_REVERBERATING_HYMN);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_31);
|
||||
RespawnPit();
|
||||
|
||||
std::list<Creature*> stalkers;
|
||||
GameObject* door = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_ANHUUR_DOOR));
|
||||
GetCreatureListWithEntryInGrid(stalkers, me, NPC_CAVE_IN_STALKER, 100.0f);
|
||||
|
||||
stalkers.remove_if(Trinity::HeightDifferenceCheck(door, 0.0f, false)); // Target only the bottom ones
|
||||
for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetPositionX() > door->GetPositionX())
|
||||
{
|
||||
(*itr)->CastSpell((*itr), SPELL_SHIELD_VISUAL_LEFT, true);
|
||||
(*itr)->CastSpell((*itr), SPELL_BEAM_OF_LIGHT_LEFT, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*itr)->CastSpell((*itr), SPELL_SHIELD_VISUAL_RIGHT, true);
|
||||
(*itr)->CastSpell((*itr), SPELL_BEAM_OF_LIGHT_RIGHT, true);
|
||||
}
|
||||
}
|
||||
|
||||
Talk(EMOTE_SHIELD);
|
||||
Talk(SAY_SHIELD);
|
||||
events.CancelEvent(EVENT_DIVINE_RECKONING);
|
||||
events.CancelEvent(EVENT_BURNING_LIGHT);
|
||||
events.ScheduleEvent(EVENT_ACHIEVEMENT_FAIL, 15000);
|
||||
}
|
||||
else if (me->HasAura(SPELL_REVERBERATING_HYMN) && !me->HasAura(SPELL_SHIELD_OF_LIGHT))
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_REVERBERATING_HYMN);
|
||||
events.CancelEvent(EVENT_ACHIEVEMENT_FAIL);
|
||||
events.ScheduleEvent(EVENT_DIVINE_RECKONING, urand(10000, 12000));
|
||||
events.ScheduleEvent(EVENT_BURNING_LIGHT, 12000);
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_DISABLE_BEACON)
|
||||
{
|
||||
--_beacons;
|
||||
if (!_beacons)
|
||||
{
|
||||
me->RemoveAura(SPELL_SHIELD_OF_LIGHT);
|
||||
Talk(EMOTE_UNSHIELD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 type) const override
|
||||
{
|
||||
if (type == DATA_I_HATE_THAT_SONG)
|
||||
return _achievement ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || !CheckInRoom())
|
||||
@@ -234,60 +198,157 @@ public:
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_SHIELD))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_DIVINE_RECKONING:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true, 0))
|
||||
DoCast(target, SPELL_DIVINE_RECKONING);
|
||||
events.ScheduleEvent(EVENT_DIVINE_RECKONING, urand(10000, 12000));
|
||||
break;
|
||||
case EVENT_BURNING_LIGHT:
|
||||
{
|
||||
Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me));
|
||||
if (!unit)
|
||||
unit = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true);
|
||||
DoCast(unit, SPELL_BURNING_LIGHT);
|
||||
events.ScheduleEvent(EVENT_SEAR, 2000);
|
||||
events.ScheduleEvent(EVENT_BURNING_LIGHT, 12000);
|
||||
events.ScheduleEvent(EVENT_SEARING_LIGHT, Seconds(2)); // No phase.
|
||||
break;
|
||||
}
|
||||
case EVENT_SEAR:
|
||||
{
|
||||
Unit* target = me->FindNearestCreature(NPC_SEARING_LIGHT, 100.0f);
|
||||
if (!target)
|
||||
break;
|
||||
|
||||
std::list<Creature*> stalkers;
|
||||
GetCreatureListWithEntryInGrid(stalkers, me, NPC_CAVE_IN_STALKER, 100.0f);
|
||||
stalkers.remove_if(Trinity::HeightDifferenceCheck(ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_ANHUUR_DOOR)), 5.0f, true));
|
||||
|
||||
if (stalkers.empty())
|
||||
break;
|
||||
|
||||
stalkers.sort(Trinity::ObjectDistanceOrderPred(target));
|
||||
|
||||
// Get the closest statue face (any of its eyes)
|
||||
Creature* eye1 = stalkers.front();
|
||||
stalkers.remove(eye1); // Remove the eye.
|
||||
stalkers.sort(Trinity::ObjectDistanceOrderPred(eye1)); // Find the second eye.
|
||||
Creature* eye2 = stalkers.front();
|
||||
|
||||
eye1->CastSpell(eye1, SPELL_SEARING_LIGHT, true);
|
||||
eye2->CastSpell(eye2, SPELL_SEARING_LIGHT, true);
|
||||
case EVENT_SEARING_LIGHT:
|
||||
HandleSearingLight();
|
||||
events.ScheduleEvent(EVENT_BURNING_LIGHT, Seconds(10), 0, PHASE_FIGHT);
|
||||
break;
|
||||
}
|
||||
case EVENT_ACHIEVEMENT_FAIL:
|
||||
_achievement = false;
|
||||
case EVENT_DIVINE_RECKONING:
|
||||
DoCastVictim(SPELL_DIVINE_RECKONING);
|
||||
events.ScheduleEvent(EVENT_DIVINE_RECKONING, Seconds(10), 0, PHASE_FIGHT);
|
||||
break;
|
||||
case EVENT_CAST_SHIELD:
|
||||
me->AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
|
||||
me->SetFacingTo(1.5708f); // Sniffs set it again
|
||||
DoCastSelf(SPELL_SHIELD_OF_LIGHT); // Note: stun!
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_31);
|
||||
events.ScheduleEvent(EVENT_ACTIVATE_BEACONS, Seconds(2), 0, PHASE_SHIELD);
|
||||
break;
|
||||
case EVENT_ACTIVATE_BEACONS:
|
||||
Talk(EMOTE_SHIELD);
|
||||
DoCastAOE(SPELL_ACTIVATE_BEACONS, true);
|
||||
DoCastSelf(SPELL_REVERBERATING_HYMN);
|
||||
HandleVisuals(SPELL_SHIELD_VISUAL_LEFT, SPELL_SHIELD_VISUAL_RIGHT, true);
|
||||
events.ScheduleEvent(EVENT_CAST_BEAMS, Seconds(1), 0, PHASE_SHIELD);
|
||||
events.ScheduleEvent(EVENT_ACHIEVEMENT_FAILED, Seconds(15), 0, PHASE_SHIELD);
|
||||
break;
|
||||
case EVENT_CAST_BEAMS:
|
||||
HandleVisuals(SPELL_BEAM_OF_LIGHT_LEFT, SPELL_BEAM_OF_LIGHT_RIGHT, true);
|
||||
break;
|
||||
case EVENT_ACHIEVEMENT_FAILED: // Happens on normal too, heroic check is in dbc.
|
||||
instance->DoUpdateWorldState(WS_I_HATE_THIS_SONG, 1);
|
||||
sWorld->setWorldState(WS_I_HATE_THIS_SONG, 1); // To-do: make InstanceScript::DoUpdateWorldState do the World::setWorldState.
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
if (!events.IsInPhase(PHASE_SHIELD))
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
void ScheduleEvents()
|
||||
{
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_DIVINE_RECKONING, Seconds(10), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_BURNING_LIGHT, Seconds(12), 0, PHASE_FIGHT);
|
||||
}
|
||||
|
||||
// To-do: Ideal for a custom spell.
|
||||
void HandleSearingLight()
|
||||
{
|
||||
Unit* target = me->FindNearestCreature(NPC_SEARING_LIGHT, 100.0f);
|
||||
GameObject* door = instance->GetGameObject(DATA_ANHUUR_DOOR);
|
||||
if (!target || !door)
|
||||
return;
|
||||
|
||||
std::list<Creature*> stalkers;
|
||||
GetCreatureListWithEntryInGrid(stalkers, me, NPC_CAVE_IN_STALKER, 100.0f);
|
||||
stalkers.remove_if(Trinity::HeightDifferenceCheck(door, 5.0f, true));
|
||||
if (stalkers.empty())
|
||||
return;
|
||||
|
||||
stalkers.sort(Trinity::ObjectDistanceOrderPred(target));
|
||||
|
||||
// Get the closest statue face (any of its eyes)
|
||||
Creature* eye1 = stalkers.front();
|
||||
stalkers.remove(eye1); // Remove the eye.
|
||||
stalkers.sort(Trinity::ObjectDistanceOrderPred(eye1)); // Find the second eye.
|
||||
Creature* eye2 = stalkers.front();
|
||||
|
||||
eye1->CastSpell(eye1, SPELL_BURNING_LIGHT_SEAR, true);
|
||||
eye2->CastSpell(eye2, SPELL_BURNING_LIGHT_SEAR, true);
|
||||
return;
|
||||
}
|
||||
|
||||
void EnterShieldPhase()
|
||||
{
|
||||
events.SetPhase(PHASE_SHIELD);
|
||||
++_countShield;
|
||||
_leftBeaconDisabled = false;
|
||||
_rightBeaconDisabled = false;
|
||||
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
me->AttackStop();
|
||||
DoCastSelf(SPELL_TELEPORT);
|
||||
me->SetFacingTo(1.5708f, true); // Note: Wrong orientation in old sniffs - 5.144157f.
|
||||
Talk(SAY_SHIELD);
|
||||
|
||||
events.ScheduleEvent(EVENT_CAST_SHIELD, Seconds(1), 0, PHASE_SHIELD);
|
||||
}
|
||||
|
||||
void ExitShieldPhase()
|
||||
{
|
||||
CleanStalkers();
|
||||
me->MakeInterruptable(true);
|
||||
me->RemoveAurasDueToSpell(SPELL_SHIELD_OF_LIGHT);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
Talk(EMOTE_UNSHIELD);
|
||||
events.SetPhase(PHASE_FIGHT);
|
||||
}
|
||||
|
||||
void CleanStalkers()
|
||||
{
|
||||
HandleVisuals(SPELL_SHIELD_VISUAL_LEFT, SPELL_SHIELD_VISUAL_RIGHT, false);
|
||||
HandleVisuals(SPELL_BEAM_OF_LIGHT_LEFT, SPELL_BEAM_OF_LIGHT_RIGHT, false);
|
||||
}
|
||||
|
||||
void HandleVisuals(uint32 leftSpellId, uint32 rightSpellId, bool apply)
|
||||
{
|
||||
std::list<Creature*> stalkers;
|
||||
GetCreatureListWithEntryInGrid(stalkers, me, NPC_CAVE_IN_STALKER, 100.0f);
|
||||
for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr)
|
||||
{
|
||||
// Target only the bottom stalkers (Y: 65.392f and 64.9004f)
|
||||
if ((*itr)->GetPositionZ() > 70.f)
|
||||
return;
|
||||
|
||||
// Left stalker X: -603.465f; right stalker X: -678.132f
|
||||
uint32 spellId = ((*itr)->GetPositionX() > -640.0f) ? leftSpellId : rightSpellId;
|
||||
if (apply)
|
||||
(*itr)->CastSpell((*itr), spellId, true);
|
||||
else
|
||||
{
|
||||
(*itr)->InterruptNonMeleeSpells(true, spellId);
|
||||
(*itr)->RemoveAurasDueToSpell(spellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 _countShield;
|
||||
bool _leftBeaconDisabled;
|
||||
bool _rightBeaconDisabled;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -296,6 +357,44 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// 75592 - Divine Reckoning
|
||||
class spell_anhuur_divine_reckoning : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_anhuur_divine_reckoning() : SpellScriptLoader("spell_anhuur_divine_reckoning") { }
|
||||
|
||||
class spell_anhuur_divine_reckoning_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_anhuur_divine_reckoning_AuraScript);
|
||||
|
||||
void OnPeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (!caster->isDead())
|
||||
{
|
||||
CustomSpellValues values;
|
||||
values.AddSpellMod(SPELLVALUE_BASE_POINT0, aurEff->GetAmount());
|
||||
caster->CastCustomSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, values, GetTarget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_anhuur_divine_reckoning_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_anhuur_divine_reckoning_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74930 - Shield of Light (left)
|
||||
// 76573 - Shield of Light (right)
|
||||
|
||||
class spell_anhuur_shield_of_light : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
@@ -307,17 +406,14 @@ class spell_anhuur_shield_of_light : public SpellScriptLoader
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
if (InstanceMap* instance = GetCaster()->GetMap()->ToInstanceMap())
|
||||
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
|
||||
{
|
||||
if (InstanceScript* const script = instance->GetInstanceScript())
|
||||
if (GameObject* go = instance->GetGameObject(DATA_ANHUUR_DOOR))
|
||||
{
|
||||
if (GameObject* go = ObjectAccessor::GetGameObject(*GetCaster(), script->GetGuidData(DATA_ANHUUR_DOOR)))
|
||||
{
|
||||
targets.remove_if(Trinity::HeightDifferenceCheck(go, 5.0f, false));
|
||||
targets.remove(GetCaster());
|
||||
targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
|
||||
targets.resize(2);
|
||||
}
|
||||
targets.remove_if(Trinity::HeightDifferenceCheck(go, 5.0f, false));
|
||||
targets.remove(GetCaster());
|
||||
targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
|
||||
targets.resize(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,6 +430,37 @@ class spell_anhuur_shield_of_light : public SpellScriptLoader
|
||||
}
|
||||
};
|
||||
|
||||
// 75322 - Reverberating Hymn
|
||||
class spell_anhuur_reverberating_hymn : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_anhuur_reverberating_hymn() : SpellScriptLoader("spell_anhuur_reverberating_hymn") { }
|
||||
|
||||
class spell_anhuur_reverberating_hymn_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_anhuur_reverberating_hymn_AuraScript);
|
||||
|
||||
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
|
||||
if (Creature* anhuur = GetCaster()->ToCreature())
|
||||
anhuur->AI()->DoAction(ACTION_HYMN_EXPIRED);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_anhuur_reverberating_hymn_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_anhuur_reverberating_hymn_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 76606 - Disable Beacon Beams L
|
||||
// 76608 - Disable Beacon Beams R
|
||||
class spell_anhuur_disable_beacon_beams : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
@@ -345,15 +472,14 @@ class spell_anhuur_disable_beacon_beams : public SpellScriptLoader
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetHitUnit()->RemoveAurasDueToSpell(GetEffectValue());
|
||||
GetHitUnit()->InterruptNonMeleeSpells(true, GetEffectValue());
|
||||
}
|
||||
|
||||
void Notify(SpellEffIndex /*index*/)
|
||||
{
|
||||
if (InstanceMap* instance = GetCaster()->GetMap()->ToInstanceMap())
|
||||
if (InstanceScript* const script = instance->GetInstanceScript())
|
||||
if (Creature* anhuur = instance->GetCreature(script->GetGuidData(DATA_ANHUUR_GUID)))
|
||||
anhuur->AI()->DoAction(ACTION_DISABLE_BEACON);
|
||||
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
|
||||
if (Creature* anhuur = instance->GetCreature(DATA_TEMPLE_GUARDIAN_ANHUUR))
|
||||
anhuur->AI()->DoAction(GetEffectValue() == SPELL_BEAM_OF_LIGHT_LEFT ? ACTION_DISABLE_BEACON_L : ACTION_DISABLE_BEACON_R);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
@@ -369,84 +495,52 @@ class spell_anhuur_disable_beacon_beams : public SpellScriptLoader
|
||||
}
|
||||
};
|
||||
|
||||
class spell_anhuur_activate_beacons : public SpellScriptLoader
|
||||
// 76599 - Activate Beacons
|
||||
// 76600 - Deactivate Beacons
|
||||
// Temporary script until Spell::EffectActivateObject is scripted.
|
||||
class spell_anhuur_handle_beacons : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_anhuur_activate_beacons() : SpellScriptLoader("spell_anhuur_activate_beacons") { }
|
||||
spell_anhuur_handle_beacons() : SpellScriptLoader("spell_anhuur_handle_beacons") { }
|
||||
|
||||
class spell_anhuur_activate_beacons_SpellScript : public SpellScript
|
||||
class spell_anhuur_handle_beacons_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_anhuur_activate_beacons_SpellScript);
|
||||
PrepareSpellScript(spell_anhuur_handle_beacons_SpellScript);
|
||||
|
||||
void Activate(SpellEffIndex index)
|
||||
void HandleEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(index);
|
||||
GetHitGObj()->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
int32 script = GetSpellInfo()->Effects[effIndex].MiscValue;
|
||||
|
||||
GameObject* beacon = GetHitGObj();
|
||||
if (!beacon)
|
||||
return;
|
||||
|
||||
beacon->SetLootState(GO_READY);
|
||||
if (script == 16) // 16 => Disable
|
||||
beacon->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
else if (script == 17) // 17 => Activate
|
||||
beacon->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_anhuur_activate_beacons_SpellScript::Activate, EFFECT_0, SPELL_EFFECT_ACTIVATE_OBJECT);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_anhuur_handle_beacons_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_ACTIVATE_OBJECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_anhuur_activate_beacons_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
class spell_anhuur_divine_reckoning : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_anhuur_divine_reckoning() : SpellScriptLoader("spell_anhuur_divine_reckoning") { }
|
||||
|
||||
class spell_anhuur_divine_reckoning_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_anhuur_divine_reckoning_AuraScript);
|
||||
|
||||
void OnPeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
CustomSpellValues values;
|
||||
values.AddSpellMod(SPELLVALUE_BASE_POINT0, aurEff->GetAmount());
|
||||
caster->CastCustomSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, values, GetTarget());
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_anhuur_divine_reckoning_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_anhuur_divine_reckoning_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
class achievement_hate_that_song : public AchievementCriteriaScript
|
||||
{
|
||||
public:
|
||||
achievement_hate_that_song() : AchievementCriteriaScript("achievement_hate_that_song") { }
|
||||
|
||||
bool OnCheck(Player* /*source*/, Unit* target) override
|
||||
{
|
||||
if (!target || !target->IsAIEnabled)
|
||||
return false;
|
||||
|
||||
return target->GetMap()->IsHeroic() && target->GetAI()->GetData(DATA_I_HATE_THAT_SONG);
|
||||
return new spell_anhuur_handle_beacons_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_temple_guardian_anhuur()
|
||||
{
|
||||
new boss_temple_guardian_anhuur();
|
||||
new spell_anhuur_shield_of_light();
|
||||
new spell_anhuur_disable_beacon_beams();
|
||||
new spell_anhuur_activate_beacons();
|
||||
new spell_anhuur_divine_reckoning();
|
||||
new achievement_hate_that_song();
|
||||
new spell_anhuur_shield_of_light();
|
||||
new spell_anhuur_reverberating_hymn();
|
||||
new spell_anhuur_disable_beacon_beams();
|
||||
new spell_anhuur_handle_beacons();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2018 TrinityCore <https://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/>.
|
||||
*/
|
||||
|
||||
/* To-do: */
|
||||
// - Summoner Enabler dummy npc: unknown purpose (at the entrance)
|
||||
// - AreaTrigger: unknown purpose (id: 2275; pos: hole in the left wall at the entrance)
|
||||
// - Find out what Dummy Nuke (68991) spell does.
|
||||
// - Spatial Flux won't enter combat on second aggro from creature group (but it should).
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "CreatureGroups.h"
|
||||
#include "GameObject.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "PassiveAI.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "halls_of_origination.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SUBMERGE = 76084,
|
||||
|
||||
// Isiset trash and adds
|
||||
SPELL_ARCANE_ENERGY = 74881,
|
||||
SPELL_ARCANE_BURST = 74888, // On retail not working! Should probably be cast at full energy.
|
||||
SPELL_SPAWN_ENERGY_FLUX_TRASH = 82382, // Makes random player cast Summon Energy Flux (82385)
|
||||
SPELL_SPAWN_ENERGY_FLUX_ISISET = 90735, // Makes random player cast Summon Energy Flux (90739)
|
||||
SPELL_ENERGY_FLUX_PERIODIC = 74044,
|
||||
SPELL_ENERGY_FLUX_BEAM_TRASH = 82377, // Makes nearby Spatial Flux cast visual beam
|
||||
SPELL_ENERGY_FLUX_BEAM_ISISET = 90741, // Makes nearby Spatial Flux cast visual beam
|
||||
|
||||
SPELL_DUMMY_NUKE = 68991
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
// Spatial Flux
|
||||
EVENT_SPAWN_ENERGY_FLUX = 1,
|
||||
EVENT_DUMMY_NUKE,
|
||||
|
||||
// Energy Flux
|
||||
EVENT_FOLLOW_SUMMONER,
|
||||
};
|
||||
|
||||
// The Maker's Lift
|
||||
enum ElevatorMisc
|
||||
{
|
||||
GOSSIP_MENU_HOO_LIFT = 12646,
|
||||
GOSSIP_NPC_TEXT_CHOOSE_A_DESTINATION = 17791,
|
||||
GOSSIP_OPTION_FIRST_FLOOR = 0,
|
||||
GOSSIP_OPTION_HOO_LIFT_SECOND_FLOOR = 1,
|
||||
GOSSIP_OPTION_HOO_LIFT_THIRD_FLOOR = 2
|
||||
};
|
||||
|
||||
// 207669 - The Maker's Lift Controller
|
||||
class go_hoo_the_makers_lift_controller : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_hoo_the_makers_lift_controller() : GameObjectScript("go_hoo_the_makers_lift_controller") { }
|
||||
|
||||
struct go_hoo_the_makers_lift_controllerAI : public GameObjectAI
|
||||
{
|
||||
go_hoo_the_makers_lift_controllerAI(GameObject* go) : GameObjectAI(go) { }
|
||||
|
||||
bool GossipHello(Player* player) override
|
||||
{
|
||||
InstanceScript* instance = player->GetInstanceScript();
|
||||
if (!instance)
|
||||
return false;
|
||||
|
||||
// Build menu.
|
||||
// First floor: Option available from start.
|
||||
AddGossipItemFor(player, GOSSIP_MENU_HOO_LIFT, GOSSIP_OPTION_FIRST_FLOOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 0);
|
||||
|
||||
// Second floor: Anraphet must be defeated first.
|
||||
if (instance->GetBossState(DATA_ANRAPHET) == DONE)
|
||||
AddGossipItemFor(player, GOSSIP_MENU_HOO_LIFT, GOSSIP_OPTION_HOO_LIFT_SECOND_FLOOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
|
||||
// Third floor: Constructs of The Four Seats must be defeated first.
|
||||
if (instance->GetBossState(DATA_ISISET) == DONE && instance->GetBossState(DATA_AMMUNAE) == DONE &&
|
||||
instance->GetBossState(DATA_SETESH) == DONE && instance->GetBossState(DATA_RAJH) == DONE)
|
||||
AddGossipItemFor(player, GOSSIP_MENU_HOO_LIFT, GOSSIP_OPTION_HOO_LIFT_THIRD_FLOOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
|
||||
SendGossipMenuFor(player, GOSSIP_NPC_TEXT_CHOOSE_A_DESTINATION, me->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
|
||||
{
|
||||
|
||||
ClearGossipMenuFor(player);
|
||||
player->PlayerTalkClass->SendCloseGossip();
|
||||
|
||||
InstanceScript* instance = player->GetInstanceScript();
|
||||
if (!instance)
|
||||
return true;
|
||||
|
||||
// Handle elevator: gossip item index => stopFrame (floor index).
|
||||
uint32 stopFrame = action - GOSSIP_ACTION_INFO_DEF;
|
||||
GameObject* elevator = instance->GetGameObject(DATA_LIFT_OF_THE_MAKERS);
|
||||
if (!elevator)
|
||||
return true;
|
||||
|
||||
elevator->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
|
||||
elevator->SetTransportState(GO_STATE_TRANSPORT_STOPPED, stopFrame);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
GameObjectAI* GetAI(GameObject* go) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<go_hoo_the_makers_lift_controllerAI>(go);
|
||||
}
|
||||
};
|
||||
|
||||
// 40790 Aggro Stalker
|
||||
class npc_hoo_aggro_stalker : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_hoo_aggro_stalker() : CreatureScript("npc_hoo_aggro_stalker") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_hoo_aggro_stalkerAI(creature);
|
||||
}
|
||||
|
||||
struct npc_hoo_aggro_stalkerAI : public PassiveAI
|
||||
{
|
||||
npc_hoo_aggro_stalkerAI(Creature* creature) : PassiveAI(creature)
|
||||
{
|
||||
me->SearchFormation();
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (who && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 30.f))
|
||||
if (CreatureGroup* formation = me->GetFormation())
|
||||
formation->MemberAttackStart(me, who);
|
||||
|
||||
me->CombatStop();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 39612 - Spatial Flux (trash)
|
||||
// 48707 - Spatial Flux (Isiset)
|
||||
class npc_hoo_spatial_flux : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_hoo_spatial_flux() : CreatureScript("npc_hoo_spatial_flux") { }
|
||||
|
||||
struct npc_hoo_spatial_fluxAI : public ScriptedAI
|
||||
{
|
||||
npc_hoo_spatial_fluxAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_DUMMY_NUKE, Seconds(0));
|
||||
events.ScheduleEvent(EVENT_SPAWN_ENERGY_FLUX, Seconds(3));
|
||||
}
|
||||
|
||||
void IsSummonedBy(Unit* summoner) override
|
||||
{
|
||||
if (summoner->GetEntry() == BOSS_ISISET)
|
||||
me->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
|
||||
case EVENT_SPAWN_ENERGY_FLUX:
|
||||
DoCastSelf(me->GetEntry() == NPC_SPATIAL_FLUX_TRASH ? SPELL_SPAWN_ENERGY_FLUX_TRASH : SPELL_SPAWN_ENERGY_FLUX_ISISET);
|
||||
events.Repeat(Seconds(12));
|
||||
break;
|
||||
case EVENT_DUMMY_NUKE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true))
|
||||
DoCast(target, SPELL_DUMMY_NUKE);
|
||||
events.Repeat(Seconds(1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_hoo_spatial_fluxAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 44015 - Energy flux (trash)
|
||||
// 48709 - Energy flux (Isiset)
|
||||
class npc_hoo_energy_flux : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_hoo_energy_flux() : CreatureScript("npc_hoo_energy_flux") { }
|
||||
|
||||
struct npc_hoo_energy_fluxAI : public ScriptedAI
|
||||
{
|
||||
npc_hoo_energy_fluxAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
DoCastSelf(SPELL_ENERGY_FLUX_PERIODIC);
|
||||
DoCastSelf(me->GetEntry() == NPC_ENERGY_FLUX_TRASH ? SPELL_ENERGY_FLUX_BEAM_TRASH : SPELL_ENERGY_FLUX_BEAM_ISISET);
|
||||
}
|
||||
|
||||
void IsSummonedBy(Unit* /*summoner*/) override
|
||||
{
|
||||
me->SetWalk(true);
|
||||
events.ScheduleEvent(EVENT_FOLLOW_SUMMONER, Seconds(1));
|
||||
me->DespawnOrUnsummon(Seconds(6));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (events.Empty())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FOLLOW_SUMMONER:
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, me->GetCreatorGUID()))
|
||||
me->GetMotionMaster()->MovePoint(0, target->GetPosition(), true);
|
||||
events.Repeat(Seconds(1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHallsOfOriginationAI<npc_hoo_energy_fluxAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 75764 - Emerge
|
||||
class spell_hoo_emerge : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_hoo_emerge() : SpellScriptLoader("spell_hoo_emerge") { }
|
||||
|
||||
class spell_hoo_emerge_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_hoo_emerge_SpellScript);
|
||||
|
||||
void RemoveSubmergeAura(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetHitUnit()->RemoveAurasDueToSpell(SPELL_SUBMERGE);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_hoo_emerge_SpellScript::RemoveSubmergeAura, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_hoo_emerge_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 82382 - Energy Flux (cast by trash Spatial Flux)
|
||||
// 90735 - Energy Flux (cast by Isiset's Spatial Flux)
|
||||
class spell_hoo_energy_flux_target_selector : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_hoo_energy_flux_target_selector() : SpellScriptLoader("spell_hoo_energy_flux_target_selector") { }
|
||||
|
||||
class spell_hoo_energy_flux_target_selector_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_hoo_energy_flux_target_selector_SpellScript);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
// Remove tank
|
||||
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
|
||||
if (Creature* Isiset = instance->GetCreature(DATA_ISISET))
|
||||
if (WorldObject* tank = Isiset->AI()->SelectTarget(SELECT_TARGET_TOPAGGRO))
|
||||
targets.remove(tank);
|
||||
|
||||
targets.remove_if(Trinity::ObjectTypeIdCheck(TYPEID_PLAYER, false));
|
||||
if (targets.empty())
|
||||
return;
|
||||
|
||||
WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
|
||||
targets.clear();
|
||||
targets.push_back(target);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hoo_energy_flux_target_selector_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_hoo_energy_flux_target_selector_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 74880 - Arcane Energy
|
||||
class spell_hoo_arcane_energy_check : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_hoo_arcane_energy_check() : SpellScriptLoader("spell_hoo_arcane_energy_check") { }
|
||||
|
||||
class spell_hoo_arcane_energy_check_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_hoo_arcane_energy_check_AuraScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_ARCANE_BURST, SPELL_ARCANE_ENERGY });
|
||||
}
|
||||
|
||||
void AfterProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
|
||||
{
|
||||
if (GetTarget()->GetPower(POWER_ENERGY) == 100)
|
||||
{
|
||||
GetTarget()->CastSpell((Unit*)nullptr, SPELL_ARCANE_BURST);
|
||||
|
||||
// Stacks should probably be consumed, right? (note: this ability doesn't work on retail)
|
||||
GetTarget()->RemoveAurasDueToSpell(SPELL_ARCANE_ENERGY);
|
||||
GetTarget()->SetPower(POWER_ENERGY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectProc += AuraEffectProcFn(spell_hoo_arcane_energy_check_AuraScript::AfterProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_hoo_arcane_energy_check_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
// 73686 Fixate
|
||||
class spell_hoo_fixate : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_hoo_fixate() : SpellScriptLoader("spell_hoo_fixate") { }
|
||||
|
||||
class spell_hoo_fixate_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_hoo_fixate_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* spellInfo) override
|
||||
{
|
||||
return ValidateSpellInfo({ uint32(spellInfo->Effects[EFFECT_0].BasePoints) });
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetHitUnit()->CastSpell(GetCaster(), uint32(GetEffectValue()));
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_hoo_fixate_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_hoo_fixate_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_halls_of_origination()
|
||||
{
|
||||
new go_hoo_the_makers_lift_controller();
|
||||
new npc_hoo_aggro_stalker();
|
||||
new npc_hoo_spatial_flux();
|
||||
new npc_hoo_energy_flux();
|
||||
new spell_hoo_emerge();
|
||||
new spell_hoo_energy_flux_target_selector();
|
||||
new spell_hoo_arcane_energy_check();
|
||||
new spell_hoo_fixate();
|
||||
}
|
||||
@@ -42,16 +42,37 @@ enum HOOData
|
||||
DATA_RAJH,
|
||||
|
||||
// Temple Guardian Anhuur
|
||||
DATA_ANHUUR_GUID,
|
||||
DATA_ANHUUR_LEFT_BEACON,
|
||||
DATA_ANHUUR_RIGHT_BEACON,
|
||||
DATA_ANHUUR_BRIDGE,
|
||||
DATA_ANHUUR_DOOR,
|
||||
|
||||
// Anraphet
|
||||
DATA_BRANN_0_GUID,
|
||||
DATA_BRANN_0,
|
||||
DATA_VAULT_OF_LIGHTS_DOOR,
|
||||
DATA_DEAD_ELEMENTALS,
|
||||
DATA_ANRAPHET_GUID,
|
||||
DATA_LIGHTMACHINE_EARTH,
|
||||
DATA_LIGHTMACHINE_AIR,
|
||||
DATA_LIGHTMACHINE_FIRE,
|
||||
DATA_LIGHTMACHINE_WATER,
|
||||
DATA_LASERBEAMS_EARTH,
|
||||
DATA_LASERBEAMS_AIR,
|
||||
DATA_LASERBEAMS_FIRE,
|
||||
DATA_LASERBEAMS_WATER,
|
||||
DATA_UPDATE_LASERBEAMS,
|
||||
DATA_ANRAPHET_SUN_MIRROR,
|
||||
DATA_ANRAPHET_DOOR,
|
||||
|
||||
// Isiset
|
||||
DATA_ISISET_PHASE,
|
||||
DATA_ISISET_ASTRAL_RAIN_ALIVE,
|
||||
DATA_ISISET_CELESTIAL_CALL_ALIVE,
|
||||
DATA_ISISET_VEIL_OF_SKY_ALIVE,
|
||||
|
||||
// Ammunae
|
||||
|
||||
// Setesh
|
||||
DATA_SETESH_ADD_STALKER,
|
||||
|
||||
// Misc
|
||||
DATA_LIFT_OF_THE_MAKERS
|
||||
};
|
||||
|
||||
enum HOOCreatures
|
||||
@@ -59,13 +80,13 @@ enum HOOCreatures
|
||||
BOSS_TEMPLE_GUARDIAN_ANHUUR = 39425,
|
||||
NPC_CAVE_IN_STALKER = 40183,
|
||||
NPC_SEARING_LIGHT = 40283,
|
||||
NPC_PIT_SNAKE = 39444,
|
||||
|
||||
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)
|
||||
NPC_JEWELED_SCARAB = 40458, // Summoned by spell: 75462 Summon Jeweled Scarab
|
||||
NPC_DUSTBONE_HORROR = 40450, // Summoned by spell: 75521 Summon Dustbone Horror
|
||||
NPC_QUICKSAND = 40503, // Summoned by spell: 75550 (server-side, not in dbc)
|
||||
NPC_HOO_CAMEL = 39443,
|
||||
|
||||
BOSS_ANRAPHET = 39788,
|
||||
NPC_FIRE_WARDEN = 39800,
|
||||
@@ -73,58 +94,134 @@ enum HOOCreatures
|
||||
NPC_WATER_WARDEN = 39802,
|
||||
NPC_AIR_WARDEN = 39803,
|
||||
|
||||
BOSS_RAJH = 39378,
|
||||
NPC_INFERNO_LEAP = 47040,
|
||||
NPC_BLAZING_INFERNO = 40927,
|
||||
|
||||
WARDEN_ENTRY_MAX_COUNT = 4,
|
||||
WARDEN_ENTRY_DATA_DELTA = NPC_FIRE_WARDEN - DATA_FIRE_WARDEN,
|
||||
|
||||
NPC_BRANN_BRONZEBEARD_0 = 39908,
|
||||
NPC_OMEGA_STANCE = 41194,
|
||||
NPC_ALPHA_BEAM = 41144,
|
||||
NPC_STONE_TROGG_PILLAGER = 39804,
|
||||
NPC_STONE_TROGG_BRUTE = 40251,
|
||||
NPC_STONE_TROGG_ROCK_FLINGER = 40252,
|
||||
|
||||
BOSS_ISISET = 39587,
|
||||
NPC_SPATIAL_FLUX_TRASH = 39612, // Isiset trash
|
||||
NPC_ENERGY_FLUX_TRASH = 44015,
|
||||
NPC_SPATIAL_ANOMALY = 40170,
|
||||
NPC_FLUX_ANIMATOR = 40033,
|
||||
NPC_STAR_SHARD = 40106,
|
||||
|
||||
BOSS_AMMUNAE = 39731,
|
||||
|
||||
BOSS_SETESH = 39732,
|
||||
NPC_SETESH_CHAOS_SEED = 41126,
|
||||
NPC_SETESH_CHAOS_BLAST = 41041,
|
||||
NPC_SETESH_CHAOS_PORTAL = 41055,
|
||||
NPC_SETESH_ADD_STALKER = 41479,
|
||||
NPC_SETESH_VOID_RIFT = 39266, // Setesh trash
|
||||
|
||||
BOSS_RAJH = 39378,
|
||||
NPC_INFERNO_LEAP = 47040,
|
||||
NPC_BLAZING_INFERNO = 40927,
|
||||
};
|
||||
|
||||
enum HOOGameObjects
|
||||
{
|
||||
GO_ANHUURS_BRIDGE = 206506,
|
||||
GO_DOODAD_ULDUM_ELEVATOR_COL01 = 207725,
|
||||
GO_ANHUURS_DOOR = 202307,
|
||||
GO_ANHUURS_RIGHT_BEACON = 203136,
|
||||
GO_ANHUURS_LEFT_BEACON = 203133,
|
||||
GO_DOODAD_ULDUM_DOOR_14 = 202306,
|
||||
GO_DOODAD_ULDUM_DOOR_15 = 202307,
|
||||
|
||||
GO_VAULT_OF_LIGHTS_DOOR = 202313,
|
||||
GO_SUN_MIRROR = 207726,
|
||||
GO_ANRAPHET_DOOR = 202314,
|
||||
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_01 = 207375,
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_02 = 207374,
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_03 = 207377,
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_04 = 207376,
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_02 = 207374, // South-West
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_01 = 207375, // South-East
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_04 = 207376, // North-West
|
||||
GO_DOODAD_ULDUM_LIGHTMACHINE_03 = 207377, // North-East
|
||||
|
||||
GO_DOODAD_ULDUM_LASERBEAMS01 = 207662, // Matches GO_DOODAD_ULDUM_LIGHTMACHINE_02
|
||||
GO_DOODAD_ULDUM_LASERBEAMS_01 = 207663, // Matches GO_DOODAD_ULDUM_LIGHTMACHINE_01
|
||||
GO_DOODAD_ULDUM_LASERBEAMS_02 = 207664, // Matches GO_DOODAD_ULDUM_LIGHTMACHINE_04
|
||||
GO_DOODAD_ULDUM_LASERBEAMS_03 = 207665, // Matches GO_DOODAD_ULDUM_LIGHTMACHINE_03
|
||||
GO_DOODAD_ULDUM_LASERBEAMS01 = 207662, // South-West
|
||||
GO_DOODAD_ULDUM_LASERBEAMS_01 = 207663, // South-East
|
||||
GO_DOODAD_ULDUM_LASERBEAMS_02 = 207664, // North-West
|
||||
GO_DOODAD_ULDUM_LASERBEAMS_03 = 207665, // North-East
|
||||
|
||||
GO_ULDUM_TEMPLE = 207802,
|
||||
GO_REORIGINATION_MECHANISM_1 = 207445,
|
||||
GO_REORIGINATION_MECHANISM_2 = 207449,
|
||||
GO_REORIGINATION_MECHANISM_3 = 207452,
|
||||
GO_REORIGINATION_MECHANISM_4 = 207454,
|
||||
GO_REORIGINATION_MECHANISM_5 = 207456,
|
||||
|
||||
GO_HOO_TRANSIT_DEVICE = 204979, // Spell ID: 82916 - Teleports the caster to the lower floor of Halls of Origination.
|
||||
GO_HOO_TRANSIT_DEVICE_2 = 204972, // Spell ID: 82900 - Teleports the caster to the upper floor of Halls of Origination. (dbc desc is wrong)
|
||||
GO_LIFT_OF_THE_MAKERS = 207547,
|
||||
GO_LIFT_GLASS_STAR = 207673,
|
||||
GO_LIFT_GLASS_STAR_2 = 207674
|
||||
};
|
||||
|
||||
enum Achievements
|
||||
{
|
||||
// I Hate That Song
|
||||
// Achievement.db2 ID 5293: ParentTree 19724
|
||||
// CriteriaTree.db2 ID 19725: ParentTree 19724 - Criteria 15988
|
||||
// Criteria.db2 ID 15988: on Anhuur kill, world state 5638 = value 0
|
||||
//CRITERIA_I_HATE_THAT_SONG = 15988,
|
||||
WS_I_HATE_THIS_SONG = 5638,
|
||||
|
||||
// Straw That Broke the Camel's Back
|
||||
// Achievement.db2 ID 5294: ParentTree 18221
|
||||
// CriteriaTree.db2 ID 18222: ParentTree 18221 - Criteria 15989
|
||||
// Criteria.db2 ID 15989: on Ptah kill, tree 2838?
|
||||
CRITERIA_STRAW_BROKE_CAMELS_BACK = 15989,
|
||||
|
||||
// Faster Than The Speed Of Light
|
||||
// Achievement.db2 ID 5296: ParentTree 17685
|
||||
// CriteriaTree.db2 ID 17686: ParentTree 17685 - Criteria 16008
|
||||
// Criteria.db2 ID 16008: spell 94067, startEvent 24212, tree 2615?, world state 5653 = value 0, type 69
|
||||
ACHIEV_VAULT_OF_LIGHTS_START_EVENT = 24212,
|
||||
SPELL_VAULT_OF_LIGHTS_CREDIT = 94067 // Achievement aura, not in DBC
|
||||
};
|
||||
|
||||
enum HOOMisc
|
||||
{
|
||||
AREA_TOMB_OF_THE_EARTHRAGER = 4945,
|
||||
ACHIEV_VAULT_OF_LIGHTS_EVENT = 24212, // Faster Than The Speed Of Light
|
||||
SPELL_VAULT_OF_LIGHTS_CREDIT = 94067, // Not in DBC
|
||||
AREA_TOMB_OF_THE_EARTHRAGER = 4945,
|
||||
SPELL_ZERO_ENERGY_NO_REGEN_AURA = 72242, // Zero Energy + Zero Regen (used by some npcs in HoO)
|
||||
// SPELL_SHRINK = 59632, // Used by static NPCs, summoned by bosses in The Four Seats (not in DBC!)
|
||||
|
||||
// Hmm... Do elementals use these spells to spawn on a random platform?
|
||||
// Probably also 81796, 81798, 81799, 81800 (all hidden client-side).
|
||||
SPELL_TELEPORT_EARTH = 82329, // South-West
|
||||
SPELL_TELEPORT_AIR = 82330, // South-East
|
||||
SPELL_TELEPORT_FIRE = 82331, // North-West
|
||||
SPELL_TELEPORT_WATER = 82332 // North-East
|
||||
};
|
||||
|
||||
enum HOOGlobalActions
|
||||
{
|
||||
ACTION_PTAH_ADD_DIED,
|
||||
ACTION_ANRAPHET_INTRO,
|
||||
ACTION_ELEMENTAL_DIED,
|
||||
ACTION_ANRAPHET_DIED,
|
||||
ACTION_OMEGA_TRIGGER,
|
||||
ACTION_OMEGA_TRIGGER
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
inline AI* GetHallsOfOriginationAI(T* obj)
|
||||
enum DataStates
|
||||
{
|
||||
return GetInstanceAI<AI>(obj, HoOScriptName);
|
||||
ACTIVATE_SHIELD_OF_LIGHT = 0,
|
||||
DISABLE_SHIELD_OF_LIGHT
|
||||
};
|
||||
|
||||
template<typename AI>
|
||||
inline AI* GetHallsOfOriginationAI(Creature* creature)
|
||||
{
|
||||
return GetInstanceAI<AI>(creature, HoOScriptName);
|
||||
}
|
||||
|
||||
template<typename AI>
|
||||
inline AI* GetHallsOfOriginationAI(GameObject* go)
|
||||
{
|
||||
return GetInstanceAI<AI>(go, HoOScriptName);
|
||||
}
|
||||
|
||||
#endif // HALLS_OF_ORIGINATION_H
|
||||
|
||||
@@ -15,33 +15,65 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "halls_of_origination.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureGroups.h"
|
||||
#include "GameObject.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Map.h"
|
||||
#include "PoolMgr.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "halls_of_origination.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "World.h"
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{GO_ANHUURS_DOOR, DATA_TEMPLE_GUARDIAN_ANHUUR, DOOR_TYPE_PASSAGE },
|
||||
{GO_ANHUURS_BRIDGE, DATA_TEMPLE_GUARDIAN_ANHUUR, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_ELEVATOR_COL01, DATA_TEMPLE_GUARDIAN_ANHUUR, DOOR_TYPE_PASSAGE },
|
||||
{GO_VAULT_OF_LIGHTS_DOOR, DATA_VAULT_OF_LIGHTS, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LIGHTMACHINE_02, DATA_EARTH_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LASERBEAMS01, DATA_EARTH_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LIGHTMACHINE_01, DATA_FIRE_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LASERBEAMS_01, DATA_FIRE_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LIGHTMACHINE_03, DATA_WATER_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LASERBEAMS_03, DATA_WATER_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LIGHTMACHINE_04, DATA_AIR_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{GO_DOODAD_ULDUM_LASERBEAMS_02, DATA_AIR_WARDEN, DOOR_TYPE_PASSAGE },
|
||||
{0, 0, DOOR_TYPE_ROOM, }
|
||||
{ GO_DOODAD_ULDUM_DOOR_14, DATA_TEMPLE_GUARDIAN_ANHUUR, DOOR_TYPE_ROOM },
|
||||
{ GO_DOODAD_ULDUM_DOOR_15, DATA_TEMPLE_GUARDIAN_ANHUUR, DOOR_TYPE_PASSAGE },
|
||||
{ GO_ANHUURS_BRIDGE, DATA_TEMPLE_GUARDIAN_ANHUUR, DOOR_TYPE_PASSAGE },
|
||||
{ GO_DOODAD_ULDUM_ELEVATOR_COL01, DATA_TEMPLE_GUARDIAN_ANHUUR, DOOR_TYPE_PASSAGE },
|
||||
{ GO_LIFT_GLASS_STAR, DATA_ANRAPHET, DOOR_TYPE_PASSAGE },
|
||||
{ GO_LIFT_GLASS_STAR_2, DATA_ANRAPHET, DOOR_TYPE_PASSAGE },
|
||||
{ 0, 0, DOOR_TYPE_ROOM }
|
||||
};
|
||||
|
||||
/*BossBoundaryData const boundaries =
|
||||
{
|
||||
};*/
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ BOSS_TEMPLE_GUARDIAN_ANHUUR, DATA_TEMPLE_GUARDIAN_ANHUUR },
|
||||
{ BOSS_EARTHRAGER_PTAH, DATA_EARTHRAGER_PTAH },
|
||||
{ NPC_BRANN_BRONZEBEARD_0, DATA_BRANN_0 },
|
||||
{ NPC_FIRE_WARDEN, DATA_FIRE_WARDEN },
|
||||
{ NPC_EARTH_WARDEN, DATA_EARTH_WARDEN },
|
||||
{ NPC_WATER_WARDEN, DATA_WATER_WARDEN },
|
||||
{ NPC_AIR_WARDEN, DATA_AIR_WARDEN },
|
||||
{ BOSS_ANRAPHET, DATA_ANRAPHET },
|
||||
{ BOSS_ISISET, DATA_ISISET },
|
||||
{ BOSS_AMMUNAE, DATA_AMMUNAE },
|
||||
{ BOSS_SETESH, DATA_SETESH },
|
||||
{ BOSS_RAJH, DATA_RAJH },
|
||||
{ 0, 0 } // END
|
||||
};
|
||||
|
||||
ObjectData const gameObjectData[] =
|
||||
{
|
||||
{ GO_DOODAD_ULDUM_DOOR_15, DATA_ANHUUR_DOOR },
|
||||
{ GO_VAULT_OF_LIGHTS_DOOR, DATA_VAULT_OF_LIGHTS_DOOR },
|
||||
{ GO_DOODAD_ULDUM_LIGHTMACHINE_02, DATA_LIGHTMACHINE_EARTH },
|
||||
{ GO_DOODAD_ULDUM_LIGHTMACHINE_01, DATA_LIGHTMACHINE_AIR },
|
||||
{ GO_DOODAD_ULDUM_LIGHTMACHINE_04, DATA_LIGHTMACHINE_FIRE },
|
||||
{ GO_DOODAD_ULDUM_LIGHTMACHINE_03, DATA_LIGHTMACHINE_WATER },
|
||||
{ GO_DOODAD_ULDUM_LASERBEAMS01, DATA_LASERBEAMS_EARTH },
|
||||
{ GO_DOODAD_ULDUM_LASERBEAMS_01, DATA_LASERBEAMS_AIR },
|
||||
{ GO_DOODAD_ULDUM_LASERBEAMS_03, DATA_LASERBEAMS_FIRE },
|
||||
{ GO_DOODAD_ULDUM_LASERBEAMS_02, DATA_LASERBEAMS_WATER },
|
||||
{ GO_SUN_MIRROR, DATA_ANRAPHET_SUN_MIRROR },
|
||||
{ GO_ANRAPHET_DOOR, DATA_ANRAPHET_DOOR },
|
||||
{ GO_LIFT_OF_THE_MAKERS, DATA_LIFT_OF_THE_MAKERS },
|
||||
{ 0, 0 } //END
|
||||
};
|
||||
|
||||
class instance_halls_of_origination : public InstanceMapScript
|
||||
@@ -56,82 +88,144 @@ class instance_halls_of_origination : public InstanceMapScript
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(creatureData, gameObjectData);
|
||||
|
||||
_brannIntroStarted = 0;
|
||||
_deadElementals = 0;
|
||||
|
||||
RotateWardenPositions();
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_ANHUURS_BRIDGE:
|
||||
AnhuursBridgeGUID = go->GetGUID();
|
||||
case GO_DOODAD_ULDUM_ELEVATOR_COL01:
|
||||
case GO_HOO_TRANSIT_DEVICE: // 5 spawns
|
||||
case GO_HOO_TRANSIT_DEVICE_2: // 1 spawn: elevator
|
||||
_transitDeviceGUIDs.insert(go->GetGUID());
|
||||
UpdateTransitDevice(go);
|
||||
break;
|
||||
case GO_LIFT_OF_THE_MAKERS:
|
||||
go->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
|
||||
go->SetTransportState(GO_STATE_TRANSPORT_STOPPED, 0);
|
||||
break;
|
||||
case GO_VAULT_OF_LIGHTS_DOOR:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_01:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_02:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_03:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_04:
|
||||
if (_brannIntroStarted || GetBossState(DATA_VAULT_OF_LIGHTS) == DONE)
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS01:
|
||||
if (GetBossState(DATA_EARTH_WARDEN) == DONE)
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS_01:
|
||||
if (GetBossState(DATA_FIRE_WARDEN) == DONE)
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS_02:
|
||||
if (GetBossState(DATA_AIR_WARDEN) == DONE)
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS_03:
|
||||
AddDoor(go, true);
|
||||
break;
|
||||
case GO_ANHUURS_DOOR:
|
||||
AnhuursDoorGUID = go->GetGUID();
|
||||
AddDoor(go, true);
|
||||
break;
|
||||
case GO_ANHUURS_RIGHT_BEACON:
|
||||
AnhuurRightBeaconGUID = go->GetGUID();
|
||||
break;
|
||||
case GO_ANHUURS_LEFT_BEACON:
|
||||
AnhuurLeftBeaconGUID = go->GetGUID();
|
||||
if (GetBossState(DATA_WATER_WARDEN) == DONE)
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
case GO_SUN_MIRROR:
|
||||
SunMirrorGUID = go->GetGUID();
|
||||
break;
|
||||
case GO_ANRAPHET_DOOR:
|
||||
AnraphetDoorGUID = go->GetGUID();
|
||||
if (GetBossState(DATA_VAULT_OF_LIGHTS) == DONE)
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
case GO_ULDUM_TEMPLE: // Research about these objects.
|
||||
case GO_REORIGINATION_MECHANISM_1:
|
||||
case GO_REORIGINATION_MECHANISM_2:
|
||||
case GO_REORIGINATION_MECHANISM_3:
|
||||
case GO_REORIGINATION_MECHANISM_4:
|
||||
case GO_REORIGINATION_MECHANISM_5:
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectRemove(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_ANHUURS_BRIDGE:
|
||||
case GO_DOODAD_ULDUM_ELEVATOR_COL01:
|
||||
case GO_ANHUURS_DOOR:
|
||||
case GO_VAULT_OF_LIGHTS_DOOR:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_01:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_02:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_03:
|
||||
case GO_DOODAD_ULDUM_LIGHTMACHINE_04:
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS01:
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS_01:
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS_02:
|
||||
case GO_DOODAD_ULDUM_LASERBEAMS_03:
|
||||
AddDoor(go, false);
|
||||
if (GetBossState(DATA_VAULT_OF_LIGHTS) == DONE)
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
go->SetFarVisible(true);
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
{
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case BOSS_TEMPLE_GUARDIAN_ANHUUR:
|
||||
TempleGuardianAnhuurGUID = creature->GetGUID();
|
||||
case NPC_HOO_CAMEL:
|
||||
_hooCamelGUIDs.insert(creature->GetGUID());
|
||||
break;
|
||||
case NPC_BEETLE_STALKER: // Must be active (sometimes they fail to summon adds, hopefully not anymore).
|
||||
creature->setActive(true);
|
||||
break;
|
||||
case NPC_DUSTBONE_HORROR:
|
||||
case NPC_JEWELED_SCARAB:
|
||||
creature->SetInCombatWithZone();
|
||||
break;
|
||||
case BOSS_ANRAPHET: // Must be active (their AI runs the event at the Vault of Lights).
|
||||
case NPC_BRANN_BRONZEBEARD_0:
|
||||
BrannBronzebeardGUID = creature->GetGUID();
|
||||
creature->setActive(true);
|
||||
break;
|
||||
case BOSS_ANRAPHET:
|
||||
AnraphetGUID = creature->GetGUID();
|
||||
case NPC_FIRE_WARDEN: // random teleport spell + far-visibility
|
||||
case NPC_EARTH_WARDEN:
|
||||
case NPC_WATER_WARDEN:
|
||||
case NPC_AIR_WARDEN:
|
||||
creature->CastSpell(nullptr, _wardenPositionSpells[creature->GetEntry() - NPC_FIRE_WARDEN]);
|
||||
creature->SetFarVisible(true);
|
||||
break;
|
||||
case BOSS_RAJH:
|
||||
RajhGUID = creature->GetGUID();
|
||||
case NPC_STONE_TROGG_PILLAGER: // far-visibility
|
||||
case NPC_STONE_TROGG_BRUTE:
|
||||
case NPC_STONE_TROGG_ROCK_FLINGER:
|
||||
if (GetBossState(DATA_VAULT_OF_LIGHTS) == DONE)
|
||||
creature->DespawnOrUnsummon(0, Seconds(DAY));
|
||||
creature->SetFarVisible(true);
|
||||
break;
|
||||
case NPC_SPATIAL_FLUX_TRASH:
|
||||
case NPC_SPATIAL_ANOMALY:
|
||||
case NPC_FLUX_ANIMATOR:
|
||||
case NPC_STAR_SHARD:
|
||||
creature->SearchFormation();
|
||||
if (creature->GetFormation())
|
||||
_isisetTrashGUIDs.insert(creature->GetGUID());
|
||||
break;
|
||||
case NPC_ALPHA_BEAM:
|
||||
if (Creature* anraphet = GetCreature(DATA_ANRAPHET))
|
||||
anraphet->AI()->JustSummoned(creature);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 data, uint32 value) override
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case DATA_UPDATE_LASERBEAMS:
|
||||
UpdateAllLaserBeams();
|
||||
break;
|
||||
case DATA_ISISET_PHASE:
|
||||
_isisetPhase = value;
|
||||
break;
|
||||
case DATA_ISISET_ASTRAL_RAIN_ALIVE:
|
||||
_isisetAstralRainAlive = value;
|
||||
break;
|
||||
case DATA_ISISET_CELESTIAL_CALL_ALIVE:
|
||||
_isisetCelestialCallAlive = value;
|
||||
break;
|
||||
case DATA_ISISET_VEIL_OF_SKY_ALIVE:
|
||||
_isisetVeilOfSkyAlive = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -142,6 +236,14 @@ class instance_halls_of_origination : public InstanceMapScript
|
||||
{
|
||||
case DATA_DEAD_ELEMENTALS:
|
||||
return _deadElementals;
|
||||
case DATA_ISISET_PHASE:
|
||||
return _isisetPhase;
|
||||
case DATA_ISISET_ASTRAL_RAIN_ALIVE:
|
||||
return _isisetAstralRainAlive;
|
||||
case DATA_ISISET_CELESTIAL_CALL_ALIVE:
|
||||
return _isisetCelestialCallAlive;
|
||||
case DATA_ISISET_VEIL_OF_SKY_ALIVE:
|
||||
return _isisetVeilOfSkyAlive;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -149,41 +251,62 @@ class instance_halls_of_origination : public InstanceMapScript
|
||||
return 0;
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 index) const override
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
{
|
||||
switch (index)
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
if (state == DONE) // Respawn transit devices if needed.
|
||||
for (ObjectGuid guid : _transitDeviceGUIDs)
|
||||
if (GameObject* transit = instance->GetGameObject(guid))
|
||||
UpdateTransitDevice(transit);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_ANHUUR_BRIDGE:
|
||||
return AnhuursBridgeGUID;
|
||||
case DATA_ANHUUR_DOOR:
|
||||
return AnhuursDoorGUID;
|
||||
case DATA_ANHUUR_LEFT_BEACON:
|
||||
return AnhuurLeftBeaconGUID;
|
||||
case DATA_ANHUUR_RIGHT_BEACON:
|
||||
return AnhuurRightBeaconGUID;
|
||||
case DATA_ANHUUR_GUID:
|
||||
return TempleGuardianAnhuurGUID;
|
||||
case DATA_BRANN_0_GUID:
|
||||
return BrannBronzebeardGUID;
|
||||
case DATA_ANRAPHET_GUID:
|
||||
return AnraphetGUID;
|
||||
case DATA_RAJH:
|
||||
return RajhGUID;
|
||||
case DATA_EARTHRAGER_PTAH:
|
||||
if (state == IN_PROGRESS)
|
||||
{
|
||||
// Camels cannot be mounted during the boss fight.
|
||||
for (ObjectGuid guid : _hooCamelGUIDs)
|
||||
if (Creature* camel = instance->GetCreature(guid))
|
||||
camel->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make camels mountable again.
|
||||
for (ObjectGuid guid : _hooCamelGUIDs)
|
||||
if (Creature* camel = instance->GetCreature(guid))
|
||||
camel->SetFlag(UNIT_FIELD_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
|
||||
}
|
||||
break;
|
||||
case DATA_VAULT_OF_LIGHTS:
|
||||
if (state == IN_PROGRESS)
|
||||
{
|
||||
HandleGameObject(ObjectGuid::Empty, true, GetGameObject(DATA_VAULT_OF_LIGHTS_DOOR));
|
||||
DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_VAULT_OF_LIGHTS_START_EVENT);
|
||||
}
|
||||
else if (state == DONE)
|
||||
{
|
||||
DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_VAULT_OF_LIGHTS_CREDIT);
|
||||
}
|
||||
break;
|
||||
case DATA_FIRE_WARDEN:
|
||||
case DATA_EARTH_WARDEN:
|
||||
case DATA_WATER_WARDEN:
|
||||
case DATA_AIR_WARDEN:
|
||||
if (state == DONE)
|
||||
{
|
||||
UpdateAllLightMachines();
|
||||
++_deadElementals;
|
||||
if (Creature* brann = GetCreature(DATA_BRANN_0))
|
||||
brann->AI()->DoAction(ACTION_ELEMENTAL_DIED);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
void IncreaseDeadElementals(uint32 inc)
|
||||
{
|
||||
_deadElementals += inc;
|
||||
if (_deadElementals == 4)
|
||||
{
|
||||
if (GameObject* mirror = instance->GetGameObject(SunMirrorGUID))
|
||||
mirror->SetGoState(GO_STATE_ACTIVE);
|
||||
if (GameObject* door = instance->GetGameObject(AnraphetDoorGUID))
|
||||
door->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnUnitDeath(Unit* unit) override
|
||||
@@ -194,44 +317,111 @@ class instance_halls_of_origination : public InstanceMapScript
|
||||
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_FIRE_WARDEN:
|
||||
case NPC_EARTH_WARDEN:
|
||||
case NPC_DUSTBONE_HORROR:
|
||||
case NPC_JEWELED_SCARAB:
|
||||
if (Creature* ptah = GetCreature(DATA_EARTHRAGER_PTAH))
|
||||
ptah->GetAI()->DoAction(ACTION_PTAH_ADD_DIED);
|
||||
break;
|
||||
case NPC_FIRE_WARDEN: // We have to set boss states manually (wardens use SmartAI).
|
||||
case NPC_EARTH_WARDEN: // To-do: check if smart scripts can handle this
|
||||
case NPC_WATER_WARDEN:
|
||||
case NPC_AIR_WARDEN:
|
||||
{
|
||||
uint32 data = creature->GetEntry() - WARDEN_ENTRY_DATA_DELTA;
|
||||
SetBossState(data, IN_PROGRESS); // Needs to be set to IN_PROGRESS or else the gameobjects state won't be updated
|
||||
SetBossState(data, DONE);
|
||||
IncreaseDeadElementals(1);
|
||||
if (Creature* brann = instance->GetCreature(BrannBronzebeardGUID))
|
||||
brann->AI()->DoAction(ACTION_ELEMENTAL_DIED);
|
||||
break;
|
||||
}
|
||||
case NPC_SPATIAL_ANOMALY:
|
||||
case NPC_FLUX_ANIMATOR:
|
||||
case NPC_STAR_SHARD:
|
||||
{
|
||||
CreatureGroup* group = creature->GetFormation();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
// Check if whole formation is dead, then despawn its leader
|
||||
for (ObjectGuid guid : _isisetTrashGUIDs)
|
||||
if (Creature* member = instance->GetCreature(guid))
|
||||
if (member->GetEntry() != NPC_SPATIAL_FLUX_TRASH && member->GetFormation()->GetId() == group->GetId() && member->IsAlive())
|
||||
return;
|
||||
|
||||
// Despawn leader (Spatial Flux)
|
||||
if (Creature* leader = group->getLeader())
|
||||
leader->DespawnOrUnsummon();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteSaveDataMore(std::ostringstream& data) override
|
||||
{
|
||||
data << _deadElementals;
|
||||
data << _brannIntroStarted << ' ' << _deadElementals << ' ';
|
||||
|
||||
for (uint8 i = 0; i < WARDEN_ENTRY_MAX_COUNT; i++)
|
||||
data << _wardenPositionSpells[i] << ' ';
|
||||
}
|
||||
|
||||
void ReadSaveDataMore(std::istringstream& data) override
|
||||
{
|
||||
uint32 deadElementals;
|
||||
data >> deadElementals;
|
||||
IncreaseDeadElementals(deadElementals);
|
||||
data >> _brannIntroStarted >> _deadElementals;
|
||||
|
||||
for (uint8 i = 0; i < WARDEN_ENTRY_MAX_COUNT; i++)
|
||||
data >> _wardenPositionSpells[i];
|
||||
}
|
||||
|
||||
protected:
|
||||
ObjectGuid TempleGuardianAnhuurGUID;
|
||||
ObjectGuid AnhuursBridgeGUID;
|
||||
ObjectGuid AnhuursDoorGUID;
|
||||
ObjectGuid AnhuurRightBeaconGUID;
|
||||
ObjectGuid AnhuurLeftBeaconGUID;
|
||||
ObjectGuid BrannBronzebeardGUID;
|
||||
ObjectGuid AnraphetGUID;
|
||||
ObjectGuid AnraphetDoorGUID;
|
||||
ObjectGuid SunMirrorGUID;
|
||||
ObjectGuid RajhGUID;
|
||||
private:
|
||||
void RotateWardenPositions()
|
||||
{
|
||||
uint32 startAt = urand(0, WARDEN_ENTRY_MAX_COUNT - 1);
|
||||
for (uint32 i = 0; i < WARDEN_ENTRY_MAX_COUNT; i++)
|
||||
_wardenPositionSpells[(i + startAt) % WARDEN_ENTRY_MAX_COUNT] = SPELL_TELEPORT_EARTH + i;
|
||||
}
|
||||
|
||||
// Activated when warden dies (on SetBossState DONE).
|
||||
void UpdateAllLightMachines()
|
||||
{
|
||||
for (uint8 i = 0; i < WARDEN_ENTRY_MAX_COUNT; i++)
|
||||
{
|
||||
uint32 positionIndex = _wardenPositionSpells[i] - SPELL_TELEPORT_EARTH;
|
||||
HandleGameObject(ObjectGuid::Empty, GetBossState(DATA_FIRE_WARDEN + i) == DONE, GetGameObject(DATA_LIGHTMACHINE_EARTH + positionIndex));
|
||||
}
|
||||
}
|
||||
|
||||
// Activated 9 seconds after warden dies (on SetData DATA_UPDATE_LASERBEAMS, called by Brann).
|
||||
void UpdateAllLaserBeams()
|
||||
{
|
||||
for (uint8 i = 0; i < WARDEN_ENTRY_MAX_COUNT; i++)
|
||||
{
|
||||
uint32 positionIndex = _wardenPositionSpells[i] - SPELL_TELEPORT_EARTH;
|
||||
HandleGameObject(ObjectGuid::Empty, GetBossState(DATA_FIRE_WARDEN + i) == DONE, GetGameObject(DATA_LIGHTMACHINE_EARTH + positionIndex));
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTransitDevice(GameObject* transit)
|
||||
{
|
||||
if (transit->GetPositionX() < -900.f) // The southernmost transit: x = -934.576
|
||||
transit->SetRespawnTime(GetBossState(DATA_TEMPLE_GUARDIAN_ANHUUR) == DONE ? -1 : DAY);
|
||||
else if (transit->GetPositionY() < -300.f) // The two easternmost transits: y = -337.028, y = -686.826
|
||||
transit->SetRespawnTime(GetBossState(DATA_EARTHRAGER_PTAH) == DONE ? -1 : DAY);
|
||||
else // All other transits.
|
||||
transit->SetRespawnTime(GetBossState(DATA_ANRAPHET) == DONE ? -1 : DAY);
|
||||
}
|
||||
|
||||
GuidSet _transitDeviceGUIDs;
|
||||
GuidSet _hooCamelGUIDs;
|
||||
GuidSet _isisetTrashGUIDs;
|
||||
GuidSet _caveInStalkerGUIDs;
|
||||
uint32 _brannIntroStarted;
|
||||
uint32 _wardenPositionSpells[WARDEN_ENTRY_MAX_COUNT];
|
||||
uint32 _deadElementals;
|
||||
uint32 _isisetPhase;
|
||||
uint32 _isisetAstralRainAlive;
|
||||
uint32 _isisetCelestialCallAlive;
|
||||
uint32 _isisetVeilOfSkyAlive;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
|
||||
@@ -99,9 +99,13 @@ void AddSC_boss_high_prophet_barim();
|
||||
void AddSC_boss_lockmaw_and_augh();
|
||||
void AddSC_boss_siamat();
|
||||
void AddSC_instance_halls_of_origination(); //Halls of Origination
|
||||
void AddSC_halls_of_origination();
|
||||
void AddSC_boss_temple_guardian_anhuur();
|
||||
void AddSC_boss_earthrager_ptah();
|
||||
void AddSC_boss_anraphet();
|
||||
void AddSC_boss_ammunae();
|
||||
void AddSC_boss_isiset();
|
||||
void AddSC_boss_setesh();
|
||||
void AddSC_boss_rajh();
|
||||
void AddSC_vortex_pinnacle(); //Vortex Pinnacle
|
||||
void AddSC_instance_vortex_pinnacle();
|
||||
@@ -214,9 +218,13 @@ void AddKalimdorScripts()
|
||||
AddSC_boss_lockmaw_and_augh();
|
||||
AddSC_boss_siamat();
|
||||
AddSC_instance_halls_of_origination(); //Halls of Origination
|
||||
AddSC_halls_of_origination();
|
||||
AddSC_boss_temple_guardian_anhuur();
|
||||
AddSC_boss_earthrager_ptah();
|
||||
AddSC_boss_anraphet();
|
||||
AddSC_boss_ammunae();
|
||||
AddSC_boss_isiset();
|
||||
AddSC_boss_setesh();
|
||||
AddSC_boss_rajh();
|
||||
AddSC_vortex_pinnacle();
|
||||
AddSC_instance_vortex_pinnacle();
|
||||
|
||||
Reference in New Issue
Block a user