Conflicts:
	sql/updates/world/2014_10_30_00_world.sql
This commit is contained in:
Rat
2014-12-30 10:22:55 +01:00
39 changed files with 3414 additions and 359 deletions

View File

@@ -9,6 +9,13 @@
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
Maelstrom/kezan.cpp
Maelstrom/Stonecore/instance_stonecore.cpp
Maelstrom/Stonecore/stonecore.cpp
Maelstrom/Stonecore/stonecore.h
Maelstrom/Stonecore/boss_corborus.cpp
Maelstrom/Stonecore/boss_slabhide.cpp
Maelstrom/Stonecore/boss_ozruk.cpp
Maelstrom/Stonecore/boss_high_priestess_azil.cpp
)
message(" -> Prepared: The Maelstrom")

View File

@@ -0,0 +1,323 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "CreatureGroups.h"
#include "stonecore.h"
// TO-DO:
// Find heroic sniffs and script spawning Crystal Shards on heroic mode.
enum Spells
{
// Corborus intro
SPELL_TWILIGHT_DOCUMENTS = 93167,
SPELL_RING_WYRM_CHARGE = 81237,
SPELL_DOOR_BREAK = 81232, // cast by World Trigger 22515
// Corborus boss
SPELL_DAMPENING_WAVE = 82415,
SPELL_CRYSTAL_BARRAGE = 86881, // 81638 triggers 81637
// SPELL_CRYSTAL_BARRAGE_SHARD = 92012, // heroic only, summons Crystal Shard (TO-DO!)
SPELL_CLEAR_ALL_DEBUFFS = 34098,
SPELL_SUBMERGE = 81629,
SPELL_TRASHING_CHARGE_TELEPORT = 81839, // triggers 81864
// SPELL_TRASHING_CHARGE_TELEPORT_2= 81838, // dummy, targets all players, threat update packet follows
SPELL_SUMMON_TRASHING_CHARGE = 81816,
SPELL_TRASHING_CHARGE_VISUAL = 81801, // cast time 3.5 sec
SPELL_TRASHING_CHARGE_EFFECT = 81828, // 40 yard radius
SPELL_EMERGE = 81948,
// Rock Borer npc (43917)
SPELL_ROCK_BORER_EMERGE = 82185,
SPELL_ROCK_BORE = 80028,
};
enum NPCs
{
NPC_TRASHING_CHARGE = 43743,
// NPC_CRYSTAL_SHARD = 49267, // 49473
};
enum Events
{
EVENT_NONE,
// Corborus intro
EVENT_CORBORUS_CHARGE,
EVENT_CORBORUS_KNOCKBACK,
EVENT_CORBORUS_FACEPLAYERS,
// Corborus boss
EVENT_DAMPENING_WAVE,
EVENT_CRYSTAL_BARRAGE,
EVENT_SUBMERGE,
EVENT_TELEPORT,
EVENT_TRASHING_CHARGE,
EVENT_SUMMON_BEETLE,
EVENT_EMERGE,
EVENT_ATTACK,
// Rock Borer
EVENT_EMERGED,
EVENT_ROCK_BORE,
};
class boss_corborus : public CreatureScript
{
public:
boss_corborus() : CreatureScript("boss_corborus") { }
struct boss_corborusAI : public BossAI
{
boss_corborusAI(Creature* creature) : BossAI(creature, DATA_CORBORUS)
{
stateIntro = NOT_STARTED;
}
void Reset() override
{
_Reset();
countTrashingCharge = 0;
events.ScheduleEvent(EVENT_DAMPENING_WAVE, 10000);
events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 15000);
events.ScheduleEvent(EVENT_SUBMERGE, 36000);
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_CORBORUS_INTRO: // Executes Corborus intro event
{
if (stateIntro != NOT_STARTED)
return;
stateIntro = IN_PROGRESS;
if (Creature* Millhouse = instance->GetCreature(DATA_MILLHOUSE_MANASTORM))
{
Millhouse->InterruptNonMeleeSpells(true);
Millhouse->RemoveAllAuras();
Millhouse->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN);
}
events.ScheduleEvent(EVENT_CORBORUS_CHARGE, 1000);
break;
}
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && stateIntro != IN_PROGRESS)
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CORBORUS_CHARGE:
// Face Millhouse and other mobs
instance->SetData(DATA_MILLHOUSE_EVENT_FACE, 0);
// Open rock gate and cast visual from nearby worldtrigger
instance->SetData(DATA_HANDLE_CORBORUS_ROCKDOOR, 0);
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 60.0f))
worldtrigger->CastSpell(worldtrigger, SPELL_DOOR_BREAK, true);
// Make Corborus charge
DoCast(me, SPELL_RING_WYRM_CHARGE, true);
events.ScheduleEvent(EVENT_CORBORUS_KNOCKBACK, 1000);
break;
case EVENT_CORBORUS_KNOCKBACK:
// Spawn Twilight Documents (quest gameobject)
if (Creature* Millhouse = instance->GetCreature(DATA_MILLHOUSE_MANASTORM))
Millhouse->CastSpell(Millhouse, SPELL_TWILIGHT_DOCUMENTS, true);
// Knockback Millhouse and other mobs
instance->SetData(DATA_MILLHOUSE_EVENT_KNOCKBACK, 0);
events.ScheduleEvent(EVENT_CORBORUS_FACEPLAYERS, 2000);
break;
case EVENT_CORBORUS_FACEPLAYERS:
// Face Corborus to players and set new home position
me->SetFacingTo(3.176499f);
me->SetHomePosition(1154.55f, 878.843f, 284.963f, 3.176499f);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
// Despawn Millhouse and all trash
instance->SetData(DATA_MILLHOUSE_EVENT_DESPAWN, 0);
stateIntro = DONE;
break;
case EVENT_DAMPENING_WAVE:
DoCastVictim(SPELL_DAMPENING_WAVE);
events.ScheduleEvent(EVENT_DAMPENING_WAVE, 15000);
break;
case EVENT_CRYSTAL_BARRAGE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_CRYSTAL_BARRAGE);
events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 10000);
break;
case EVENT_SUBMERGE:
events.RescheduleEvent(EVENT_DAMPENING_WAVE, 35000);
events.RescheduleEvent(EVENT_CRYSTAL_BARRAGE, 30000);
events.RescheduleEvent(EVENT_SUBMERGE, 100000);
me->SetReactState(REACT_PASSIVE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
me->AttackStop();
DoCast(me, SPELL_SUBMERGE);
countTrashingCharge = 0;
events.ScheduleEvent(EVENT_TELEPORT, 500);
break;
case EVENT_TELEPORT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_TRASHING_CHARGE_TELEPORT);
countTrashingCharge += 1;
if (countTrashingCharge <= 4)
events.ScheduleEvent(EVENT_TRASHING_CHARGE, 1000);
else
events.ScheduleEvent(EVENT_EMERGE, 2500);
break;
case EVENT_TRASHING_CHARGE:
DoCast(me, SPELL_SUMMON_TRASHING_CHARGE);
DoCast(me, SPELL_TRASHING_CHARGE_VISUAL);
events.ScheduleEvent(EVENT_TELEPORT, 5000);
break;
case EVENT_EMERGE:
me->RemoveAllAuras();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
DoCast(me, SPELL_EMERGE);
events.ScheduleEvent(EVENT_ATTACK, 2500);
break;
case EVENT_ATTACK:
me->SetReactState(REACT_AGGRESSIVE);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_TRASHING_CHARGE)
{
summon->SetReactState(REACT_PASSIVE);
summon->CastSpell(summon, SPELL_TRASHING_CHARGE_EFFECT);
summon->DespawnOrUnsummon(6000);
}
BossAI::JustSummoned(summon);
}
private:
EncounterState stateIntro;
uint32 countTrashingCharge;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_corborusAI>(creature);
}
};
// 43391 - Rock Borer
class npc_rock_borer : public CreatureScript
{
public:
npc_rock_borer() : CreatureScript("npc_rock_borer") { }
struct npc_rock_borerAI : public ScriptedAI
{
npc_rock_borerAI(Creature* creature) : ScriptedAI(creature)
{
me->SetDisableGravity(true);
me->SetReactState(REACT_PASSIVE);
events.ScheduleEvent(EVENT_EMERGED, 1200);
events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer
}
void IsSummonedBy(Unit* summoner) override
{
me->SetInCombatState(false, summoner);
DoCast(me, SPELL_ROCK_BORER_EMERGE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && me->GetReactState() != REACT_PASSIVE)
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_EMERGED:
me->RemoveAurasDueToSpell(SPELL_ROCK_BORER_EMERGE);
me->SetReactState(REACT_AGGRESSIVE);
break;
case EVENT_ROCK_BORE:
DoCast(me, SPELL_ROCK_BORE);
events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_rock_borerAI>(creature);
}
};
void AddSC_boss_corborus()
{
new boss_corborus();
new npc_rock_borer();
}

View File

@@ -0,0 +1,726 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "Vehicle.h"
#include "stonecore.h"
enum Spells
{
SPELL_ENERGY_SHIELD = 82858,
SPELL_CURSE_OF_BLOOD = 79345,
SPELL_FORCE_GRIP = 79351,
SPELL_SUMMON_GRAVITY_WELL = 79340,
SPELL_EARTH_FURY_ENERGY_SHIELD = 79050,
// Gravity Well
SPELL_GRAVITY_WELL_VISUAL = 79245,
SPELL_GRAVITY_WELL_AURA_DAMAGE = 79244,
SPELL_GRAVITY_WELL_AURA_PULL = 79333,
SPELL_GRAVITY_WELL_DAMAGE = 79249,
SPELL_GRAVITY_WELL_PULL = 79332,
// Fury of Earth phase
SPELL_EARTH_FURY_CASTING_VISUAL = 79002,
SPELL_SEISMIC_SHARD_SUMMON_1 = 86860,
SPELL_SEISMIC_SHARD_SUMMON_2 = 86858,
SPELL_SEISMIC_SHARD_SUMMON_3 = 86856,
SPELL_SEISMIC_SHARD_VISUAL = 79009,
SPELL_SEISMIC_SHARD_PREPARE = 86862,
SPELL_SEISMIC_SHARD_TARGETING = 80511,
SPELL_SEISMIC_SHARD_LAUNCH = 79015,
SPELL_SEISMIC_SHARD_MISSLE = 79014,
SPELL_EJECT_ALL_PASSENGERS = 68576,
// Add wave spells
SPELL_SUMMON_WAVE_SOUTH = 79200,
SPELL_SUMMON_WAVE_WEST = 79196,
SPELL_SUMMON_ADD_SOUTH = 79193,
SPELL_SUMMON_ADD_WEST = 79199,
};
enum NPCs
{
NPC_DEVOUT_FOLLOWER = 42428,
NPC_SEISMIC_SHARD = 42355,
};
enum Texts
{
SAY_AGGRO = 0,
SAY_PHASE_TWO = 1,
SAY_DEATH = 2,
};
enum Events
{
EVENT_NONE,
EVENT_INTRO_MOVE,
EVENT_CURSE_OF_BLOOD,
EVENT_FORCE_GRIP,
EVENT_SUMMON_GRAVITY_WELL,
EVENT_ENERGY_SHIELD,
EVENT_EARTH_FURY,
EVENT_SUMMON_WAVE_SOUTH,
EVENT_SUMMON_WAVE_WEST,
EVENT_GRAVITY_WELL_AURA_DAMAGE,
EVENT_GRAVITY_WELL_AURA_PULL,
// Phase 2: Fury of Earth
EVENT_EARTH_FURY_FLY_UP,
EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM,
EVENT_EARTH_FURY_PREPARE_SHARD,
EVENT_EARTH_FURY_LAUNCH_SHARD,
EVENT_EARTH_FURY_FLY_DOWN,
EVENT_START_ATTACK,
EVENT_LAUNCH,
EVENT_SEISMIC_SHARD_MOUNT
};
enum Points
{
POINT_NONE,
POINT_INTRO_MOVE,
POINT_FLY_UP,
POINT_ABOVE_PLATFORM,
POINT_PLATFORM,
POINT_GROUND,
};
Position const GroundPos = { 1331.82f, 980.314f, 207.542f };
Position const AbovePlatformPos = { 1336.21f, 960.813f, 215.0f };
// TO-DO:
// - Find more sniffs and script Force Grip spell (79351)
class boss_high_priestess_azil : public CreatureScript
{
public:
boss_high_priestess_azil() : CreatureScript("boss_high_priestess_azil") { }
struct boss_high_priestess_azilAI : public BossAI
{
boss_high_priestess_azilAI(Creature* creature) : BossAI(creature, DATA_HIGH_PRIESTESS_AZIL) { }
void Reset() override
{
_Reset();
me->SetCanFly(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_PASSIVE);
events.ScheduleEvent(EVENT_INTRO_MOVE, 2000);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000);
events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000,10000));
events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000);
events.ScheduleEvent(EVENT_ENERGY_SHIELD, urand(35000,36000));
events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 0);
events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 40000);
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
DoCast(me, SPELL_ENERGY_SHIELD);
Talk(SAY_AGGRO);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE && id != POINT_INTRO_MOVE)
return;
switch (id)
{
case POINT_INTRO_MOVE:
me->RemoveAurasDueToSpell(SPELL_ENERGY_SHIELD);
me->SetReactState(REACT_AGGRESSIVE);
DoStartMovement(me->GetVictim());
break;
case POINT_FLY_UP:
me->SetCanFly(true);
me->SetDisableGravity(true);
events.ScheduleEvent(EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, 1000);
break;
case POINT_ABOVE_PLATFORM:
me->SetFacingTo(5.218534f);
DoCast(me, SPELL_EARTH_FURY_CASTING_VISUAL);
DoCast(me, SPELL_SEISMIC_SHARD_SUMMON_1);
DoCast(me, SPELL_SEISMIC_SHARD_SUMMON_2);
DoCast(me, SPELL_SEISMIC_SHARD_SUMMON_3);
events.ScheduleEvent(EVENT_EARTH_FURY_PREPARE_SHARD, 6700);
break;
case POINT_GROUND:
DoCast(me, SPELL_EJECT_ALL_PASSENGERS);
me->SetCanFly(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_AGGRESSIVE);
DoStartMovement(me->GetVictim());
// Find more sniffs to correct these timers, this was copied from Reset() void.
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000);
events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000, 10000));
events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000);
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_INTRO_MOVE:
me->GetMotionMaster()->MoveJump(GroundPos, me->GetSpeed(MOVE_FLIGHT), 1.918408f, POINT_INTRO_MOVE);
break;
case EVENT_CURSE_OF_BLOOD:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_CURSE_OF_BLOOD);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000));
break;
case EVENT_FORCE_GRIP:
DoCastVictim(SPELL_FORCE_GRIP);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000));
break;
case EVENT_SUMMON_GRAVITY_WELL:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_SUMMON_GRAVITY_WELL);
events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, urand(13000, 15000));
break;
case EVENT_ENERGY_SHIELD:
events.Reset();
DoCast(me, SPELL_EARTH_FURY_ENERGY_SHIELD);
events.ScheduleEvent(EVENT_EARTH_FURY, 0);
break;
case EVENT_EARTH_FURY:
countSeismicShard = 3;
me->SetReactState(REACT_PASSIVE);
me->SetFacingTo(5.862942f);
events.ScheduleEvent(EVENT_EARTH_FURY_FLY_UP, 1600);
break;
case EVENT_EARTH_FURY_FLY_UP:
Talk(SAY_PHASE_TWO);
me->GetMotionMaster()->MovePoint(POINT_FLY_UP, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5);
break;
case EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM:
me->GetMotionMaster()->MovePoint(POINT_ABOVE_PLATFORM, AbovePlatformPos);
break;
case EVENT_EARTH_FURY_PREPARE_SHARD:
DoCast(me, SPELL_SEISMIC_SHARD_PREPARE);
events.ScheduleEvent(EVENT_EARTH_FURY_LAUNCH_SHARD, 1800);
break;
case EVENT_EARTH_FURY_LAUNCH_SHARD:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
{
me->SetFacingToObject(target);
DoCast(target, SPELL_SEISMIC_SHARD_TARGETING);
DoCast(me, SPELL_SEISMIC_SHARD_LAUNCH);
countSeismicShard -= 1;
}
events.ScheduleEvent(countSeismicShard > 0 ? EVENT_EARTH_FURY_PREPARE_SHARD : EVENT_EARTH_FURY_FLY_DOWN, 4800);
break;
case EVENT_EARTH_FURY_FLY_DOWN:
{
me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_CASTING_VISUAL);
me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_ENERGY_SHIELD);
Position pos = me->GetPosition();
pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
me->GetMotionMaster()->MovePoint(POINT_GROUND, pos);
break;
}
case EVENT_SUMMON_WAVE_SOUTH:
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_SOUTH);
events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 12000);
break;
case EVENT_SUMMON_WAVE_WEST:
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_WEST);
events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 20000);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 countSeismicShard;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_high_priestess_azilAI>(creature);
}
};
// 42428 - Devout Follower
class npc_devout_follower : public CreatureScript
{
public:
npc_devout_follower() : CreatureScript("npc_devout_follower") { }
struct npc_devout_followerAI : public ScriptedAI
{
npc_devout_followerAI(Creature* creature) : ScriptedAI(creature) { }
void IsSummonedBy(Unit* summoner) override
{
if (summoner->GetEntry() != NPC_WORLDTRIGGER)
return;
if (Unit* target = me->SelectNearestPlayer(200.0f))
{
me->AddThreat(target, 0.0f);
me->SetInCombatWith(target);
target->SetInCombatWith(me);
DoStartMovement(target);
me->Attack(target, true);
}
else
me->GetMotionMaster()->MovePoint(POINT_NONE, summoner->GetPosition());
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_devout_followerAI>(creature);
}
};
// 42499 - Gravity Well
class npc_gravity_well : public CreatureScript
{
public:
npc_gravity_well() : CreatureScript("npc_gravity_well") { }
struct npc_gravity_wellAI : public ScriptedAI
{
npc_gravity_wellAI(Creature* creature) : ScriptedAI(creature)
{
DoCast(me, SPELL_GRAVITY_WELL_VISUAL);
events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_DAMAGE, 3200);
events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_PULL, 4500);
if (!me->GetMap()->IsHeroic())
me->DespawnOrUnsummon(23200);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetEntry() != NPC_DEVOUT_FOLLOWER)
return;
me->SetObjectScale(me->GetObjectScale() - 0.25f);
if (me->GetObjectScale() <= 0.0f)
me->DespawnOrUnsummon(1000);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_GRAVITY_WELL_AURA_DAMAGE:
me->RemoveAurasDueToSpell(SPELL_GRAVITY_WELL_VISUAL);
DoCast(me, SPELL_GRAVITY_WELL_AURA_DAMAGE);
break;
case EVENT_GRAVITY_WELL_AURA_PULL:
DoCast(me, SPELL_GRAVITY_WELL_AURA_PULL);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_gravity_wellAI>(creature);
}
};
// 42355 - Seismic Shard
class npc_seismic_shard : public CreatureScript
{
public:
npc_seismic_shard() : CreatureScript("npc_seismic_shard") { }
struct npc_seismic_shardAI : public ScriptedAI
{
npc_seismic_shardAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
me->SetDisableGravity(true);
DoCast(me, SPELL_SEISMIC_SHARD_VISUAL);
Movement::MoveSplineInit init(me);
FillPath(me->GetPosition(), init.Path());
init.SetFly();
init.Launch();
events.ScheduleEvent(EVENT_SEISMIC_SHARD_MOUNT, 2400);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SEISMIC_SHARD_MOUNT:
if (Creature* highPriestAzil = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL)))
if (Vehicle* vehicle = highPriestAzil->GetVehicleKit())
me->EnterVehicle(highPriestAzil, vehicle->GetNextEmptySeat(0, false)->first);
break;
default:
break;
}
}
}
private:
void FillPath(Position const& pos, Movement::PointsArray& path)
{
G3D::Vector3 point;
point.x = pos.GetPositionX();
point.y = pos.GetPositionY();
point.z = pos.GetPositionZ();
point.x -= 1.0f;
path.push_back(point);
point.x += 1.0f;
path.push_back(point);
point.z += 25.0f;
path.push_back(point);
path.push_back(point);
}
InstanceScript* instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_seismic_shardAI>(creature);
}
};
// 79200 - Summon Follower
class spell_summon_wave_south : public SpellScriptLoader
{
public:
spell_summon_wave_south() : SpellScriptLoader("spell_summon_wave_south") { }
class spell_summon_wave_south_SpellScript : public SpellScript
{
PrepareSpellScript(spell_summon_wave_south_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_SOUTH))
return false;
return true;
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
for (int i = 0; i < 3; i++)
caster->CastSpell(caster, SPELL_SUMMON_ADD_SOUTH, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_summon_wave_south_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_summon_wave_south_SpellScript();
}
};
// 79196 - Summon Follower
class spell_summon_wave_west : public SpellScriptLoader
{
public:
spell_summon_wave_west() : SpellScriptLoader("spell_summon_wave_west") { }
class spell_summon_wave_west_SpellScript : public SpellScript
{
PrepareSpellScript(spell_summon_wave_west_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_WEST))
return false;
return true;
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
for (int i = 0; i < 10; i++)
caster->CastSpell(caster, SPELL_SUMMON_ADD_WEST, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_summon_wave_west_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_summon_wave_west_SpellScript();
}
};
// 79251 - Gravity Well (casts damage spell on units within 10 yards)
class PlayerPetOrDevoutFollowerCheck
{
public:
bool operator()(WorldObject* object) const
{
// Valid targets are players, pets and Devout Followers
if (Creature* creature = object->ToCreature())
return (!creature->ToPet() && object->GetEntry() != NPC_DEVOUT_FOLLOWER);
return (!object->ToPlayer());
}
};
class spell_gravity_well_damage_nearby : public SpellScriptLoader
{
public:
spell_gravity_well_damage_nearby() : SpellScriptLoader("spell_gravity_well_damage_nearby") { }
class spell_gravity_well_damage_nearby_SpellScript : public SpellScript
{
PrepareSpellScript(spell_gravity_well_damage_nearby_SpellScript);
void SetRadiusMod()
{
GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3));
}
void FilterTargets(std::list<WorldObject*>& unitList)
{
unitList.remove_if(PlayerPetOrDevoutFollowerCheck());
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_GRAVITY_WELL_DAMAGE, true);
}
void Register() override
{
BeforeCast += SpellCastFn(spell_gravity_well_damage_nearby_SpellScript::SetRadiusMod);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_damage_nearby_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_nearby_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_gravity_well_damage_nearby_SpellScript();
}
};
// 79249 - Gravity Well (damage)
class spell_gravity_well_damage : public SpellScriptLoader
{
public:
spell_gravity_well_damage() : SpellScriptLoader("spell_gravity_well_damage") { }
class spell_gravity_well_damage_SpellScript : public SpellScript
{
PrepareSpellScript(spell_gravity_well_damage_SpellScript);
void CalculateDamage(SpellEffIndex /*effIndex*/)
{
Unit* target = GetHitUnit();
if (!target)
return;
float distance = GetCaster()->GetDistance2d(target);
if (target->GetEntry() == NPC_DEVOUT_FOLLOWER)
SetHitDamage(int32(200000 - (1000 * distance))); //need more research on this formula, damage values from sniffs: 189264, 190318, 190478, 196134, 197672, 199735
else
SetHitDamage(int32(4000 - (200 * distance)));
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_SpellScript::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_gravity_well_damage_SpellScript();
}
};
// 79332 - Gravity Well (pull units within 10 yards)
class spell_gravity_well_pull : public SpellScriptLoader
{
public:
spell_gravity_well_pull() : SpellScriptLoader("spell_gravity_well_pull") { }
class spell_gravity_well_pull_SpellScript : public SpellScript
{
PrepareSpellScript(spell_gravity_well_pull_SpellScript);
void SetRadiusMod()
{
GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3));
}
void Register() override
{
BeforeCast += SpellCastFn(spell_gravity_well_pull_SpellScript::SetRadiusMod);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_gravity_well_pull_SpellScript();
}
};
// 86863 - Seismic Shard (makes shard reenter Azil)
class spell_seismic_shard_change_seat : public SpellScriptLoader
{
public:
spell_seismic_shard_change_seat() : SpellScriptLoader("spell_seismic_shard_change_seat") { }
class spell_seismic_shard_change_seat_SpellScript : public SpellScript
{
PrepareSpellScript(spell_seismic_shard_change_seat_SpellScript);
void ExitVehicle()
{
GetCaster()->ExitVehicle();
}
void Register() override
{
BeforeCast += SpellCastFn(spell_seismic_shard_change_seat_SpellScript::ExitVehicle);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_seismic_shard_change_seat_SpellScript();
}
};
// 79015 - Seismic Shard (launches shard)
class spell_seismic_shard : public SpellScriptLoader
{
public:
spell_seismic_shard() : SpellScriptLoader("spell_seismic_shard") { }
class spell_seismic_shard_SpellScript : public SpellScript
{
PrepareSpellScript(spell_seismic_shard_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
Creature* target = GetHitUnit()->ToCreature();
if (!target)
return;
target->ExitVehicle();
DynamicObject* dynamicObject = GetCaster()->GetDynObject(SPELL_SEISMIC_SHARD_TARGETING);
target->CastSpell(dynamicObject->GetPositionX(), dynamicObject->GetPositionY(), dynamicObject->GetPositionZ(), SPELL_SEISMIC_SHARD_MISSLE, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_seismic_shard_SpellScript();
}
};
void AddSC_boss_high_priestess_azil()
{
new boss_high_priestess_azil();
new npc_devout_follower();
new npc_gravity_well();
new npc_seismic_shard();
new spell_summon_wave_south();
new spell_summon_wave_west();
new spell_gravity_well_damage_nearby();
new spell_gravity_well_damage();
new spell_gravity_well_pull();
new spell_seismic_shard_change_seat();
new spell_seismic_shard();
}

View File

@@ -0,0 +1,274 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "Vehicle.h"
#include "stonecore.h"
enum Spells
{
SPELL_ELEMENTIUM_BULWARK = 78939,
SPELL_GROUND_SLAM = 78903,
SPELL_ELEMENTIUM_SPIKE_SHIELD = 78835,
SPELL_SHATTER = 78807,
SPELL_ENRAGE = 80467,
// Rupture Controller and Rupture
SPELL_RUPTURE = 92393,
// SPELL_RUPTURE_SUMMON_CENTER? = 95669, // summons rupture 8 yards front
// SPELL_RUPTURE_SUMMON_LEFT? = 95348, // summons rupture 3 yards left?
// SPELL_RUPTURE_SUMMON_RIGHT? = 92383, // summons rupture 3 yards right?
SPELL_RUPTURE_DAMAGE = 92381,
};
enum NPCs
{
NPC_BOUNCER_SPIKE = 42189,
NPC_RUPTURE_CONTROLLER = 49597,
NPC_RUPTURE = 49576,
};
enum Texts
{
SAY_AGGRO = 0,
SAY_ELEMENTIUM_BULWARK = 1,
SAY_ELEMENTIUM_SPIKE_SHIELD = 2,
SAY_ENRAGE = 3,
SAY_DEATH = 4,
};
enum Events
{
EVENT_NONE,
EVENT_ELEMENTIUM_BULWARK,
EVENT_GROUND_SLAM,
EVENT_ELEMENTIUM_SPIKE_SHIELD,
EVENT_SHATTER,
EVENT_ENRAGE,
EVENT_START_ATTACK,
};
// TO-DO:
// - Find heroic sniffs and spawn Ruptures using spells commented above.
// - Make Bouncer Spikes enter ozruk without jump animation.
class boss_ozruk : public CreatureScript
{
public:
boss_ozruk() : CreatureScript("boss_ozruk") { }
struct boss_ozrukAI : public BossAI
{
boss_ozrukAI(Creature* creature) : BossAI(creature, DATA_OZRUK) { }
void Reset() override
{
_Reset();
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, 5000);
events.ScheduleEvent(EVENT_GROUND_SLAM, 10000);
events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, 13000);
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_RUPTURE_CONTROLLER)
{
summon->CastSpell(summon, SPELL_RUPTURE, true);
summon->DespawnOrUnsummon(10000);
}
BossAI::JustSummoned(summon);
}
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
{
if (!me->HealthBelowPctDamaged(25, damage) || me->HasAura(SPELL_ENRAGE))
return;
DoCast(me, SPELL_ENRAGE);
Talk(SAY_ENRAGE);
}
void JustDied(Unit* /*killer*/) override
{
_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_ELEMENTIUM_BULWARK:
DoCast(me, SPELL_ELEMENTIUM_BULWARK);
Talk(SAY_ELEMENTIUM_BULWARK);
break;
case EVENT_GROUND_SLAM:
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
DoCast(me, SPELL_GROUND_SLAM);
events.ScheduleEvent(EVENT_START_ATTACK, 4600);
break;
case EVENT_ELEMENTIUM_SPIKE_SHIELD:
DoCast(me, SPELL_ELEMENTIUM_SPIKE_SHIELD);
Talk(SAY_ELEMENTIUM_SPIKE_SHIELD);
events.ScheduleEvent(EVENT_SHATTER, 10000);
break;
case EVENT_SHATTER:
summons.DespawnEntry(NPC_BOUNCER_SPIKE);
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
DoCast(me, SPELL_SHATTER);
events.ScheduleEvent(EVENT_START_ATTACK, 4600);
// Spells are cast in same order everytime after Shatter, so we schedule them here
events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, urand(3000,4000));
events.ScheduleEvent(EVENT_GROUND_SLAM, urand(7000,9000));
events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, urand(10000,12000));
break;
case EVENT_START_ATTACK:
me->SetReactState(REACT_AGGRESSIVE);
DoStartMovement(me->GetVictim());
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_ozrukAI>(creature);
}
};
// 92393 - Rupture
class spell_rupture : public SpellScriptLoader
{
public:
spell_rupture() : SpellScriptLoader("spell_rupture") { }
class spell_rupture_AuraScript : public AuraScript
{
PrepareAuraScript(spell_rupture_AuraScript);
void HandleEffectPeriodic(AuraEffect const* aurEff)
{
Unit* caster = GetCaster();
float dist = aurEff->GetTickNumber() * 8.0f;
// probably hack, should use spells (see Spells enum above)
Position pos = caster->GetNearPosition(dist, 0.0f);
SummonRupture(caster, pos);
pos = caster->GetNearPosition(dist, 0.2f);
SummonRupture(caster, pos);
pos = caster->GetNearPosition(dist, -0.2f);
SummonRupture(caster, pos);
}
void SummonRupture(Unit* caster, Position pos)
{
Creature* rupture = caster->SummonCreature(NPC_RUPTURE, pos, TEMPSUMMON_TIMED_DESPAWN, 2500);
if (!rupture)
return;
rupture->CastSpell(rupture, SPELL_RUPTURE_DAMAGE, true);
}
void Register()
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_rupture_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const
{
return new spell_rupture_AuraScript();
}
};
// 78835 - Elementium Spike Shield
class spell_elementium_spike_shield : public SpellScriptLoader
{
public:
spell_elementium_spike_shield() : SpellScriptLoader("spell_elementium_spike_shield") { }
class spell_elementium_spike_shield_SpellScript : public SpellScript
{
PrepareSpellScript(spell_elementium_spike_shield_SpellScript);
void HandleBouncerSpikes()
{
Unit* caster = GetCaster();
Vehicle* vehicle = caster->GetVehicleKit();
if (!vehicle)
return;
for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++)
if (Creature* summon = caster->SummonCreature(NPC_BOUNCER_SPIKE, caster->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 10000))
summon->EnterVehicle(caster, i);
}
void Register() override
{
OnCast += SpellCastFn(spell_elementium_spike_shield_SpellScript::HandleBouncerSpikes);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_elementium_spike_shield_SpellScript();
}
};
void AddSC_boss_ozruk()
{
new boss_ozruk();
new spell_rupture();
new spell_elementium_spike_shield();
}

View File

@@ -0,0 +1,586 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "stonecore.h"
enum Spells
{
SPELL_FACE_RANDOM_PLAYER = 82530,
// Stalactite Trigger - Trash, On Ground
SPELL_STALACTITE_SUMMON_TRIGGER = 81028,
// Slabhide
SPELL_LAVA_FISSURE = 80803,
SPELL_SAND_BLAST = 80807,
SPELL_STALACTITE_SUMMON = 80656,
// SPELL_COOLDOWN_5S = 95323, Cooldown: Creature Special 1 (5s)?
SPELL_CRYSTAL_STORM = 92305,
SPELL_CRYSTAL_STORM_TRIGGER = 92265,
// Lava Fissure
SPELL_LAVA_FISSURE_CRACK = 80798,
SPELL_LAVA_FISSURE_ERUPTION = 80800,
// Stalactite Trigger - Boss
SPELL_STALACTITE_SHADE = 80654,
SPELL_STALACTITE_MISSLE = 80643,
SPELL_STALACTITE_CREATE = 80647,
};
enum Entries
{
NPC_LAVA_FISSURE = 43242,
NPC_STALACTITE_TRIGGER_GROUND = 43357,
NPC_STALACTITE_TRIGGER = 43159,
GO_STALACTITE = 204337,
};
enum Actions
{
ACTION_STALACTITE_MISSLE,
};
enum Events
{
EVENT_NONE,
// Intro events
EVENT_ROAR_EMOTE,
// Slabhide combat
EVENT_HANDLE_ROCK_WALLS,
EVENT_LAVA_FISSURE,
EVENT_SAND_BLAST,
EVENT_AIR_PHASE,
EVENT_TAKEOFF,
EVENT_STALACTITE,
EVENT_LAND,
EVENT_ATTACK,
// Lava Fissure
EVENT_LAVA_FISSURE_ERUPTION,
// Stalactite Trigger - Boss
EVENT_STALACTITE_MISSLE,
};
enum MovementPoints
{
POINT_NONE,
POINT_SLABHIDE_INTRO,
POINT_SLABHIDE_INTRO_LAND,
POINT_SLABHIDE_MIDDLE,
POINT_SLABHIDE_IN_AIR,
POINT_SLABHIDE_LAND,
};
Position const SlabhideIntroPos = { 1292.27f, 1226.16f, 265.573f };
Position const SlabhideIntroLandPos = { 1292.352f, 1226.478f, 247.6368f, 3.630285f };
Position const SlabhideMiddlePos = { 1280.73f, 1212.31f, 247.3837f };
Position const SlabhideInAirPos = { 1280.73f, 1212.31f, 257.3837f };
Position const SlabhideLandPos = { 1282.7f, 1229.77f, 247.155f, 3.82227f };
class boss_slabhide : public CreatureScript
{
public:
boss_slabhide() : CreatureScript("boss_slabhide") { }
struct boss_slabhideAI : public BossAI
{
boss_slabhideAI(Creature* creature) : BossAI(creature, DATA_SLABHIDE)
{
me->setActive(true);
me->SetCanFly(true);
me->SetDisableGravity(true);
me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetReactState(REACT_PASSIVE);
instance->SetData(DATA_SLABHIDE_INTRO, NOT_STARTED);
}
void Reset()
{
if (instance->GetData(DATA_SLABHIDE_INTRO) == NOT_STARTED)
return;
_Reset();
DespawnAll();
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetReactState(REACT_AGGRESSIVE);
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_HANDLE_ROCK_WALLS, 4000);
events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000));
events.ScheduleEvent(EVENT_AIR_PHASE, 10000);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
// Despawn related npcs and gameobjects
DespawnAll();
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_SLABHIDE_INTRO:
{
if (instance->GetData(DATA_SLABHIDE_INTRO) != NOT_STARTED)
return;
instance->SetData(DATA_SLABHIDE_INTRO, IN_PROGRESS);
// Execute Slabhide intro event
me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_INTRO, SlabhideIntroPos);
break;
}
default:
break;
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
return;
switch (id)
{
case POINT_SLABHIDE_INTRO:
me->SetFacingTo(SlabhideIntroLandPos.GetOrientation());
me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_INTRO_LAND, SlabhideIntroLandPos);
break;
case POINT_SLABHIDE_INTRO_LAND:
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetHover(false);
me->SetHomePosition(SlabhideIntroLandPos);
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
instance->SetData(DATA_SLABHIDE_INTRO, DONE);
break;
case POINT_SLABHIDE_MIDDLE:
events.ScheduleEvent(EVENT_TAKEOFF, 100);
break;
case POINT_SLABHIDE_IN_AIR:
events.ScheduleEvent(EVENT_STALACTITE, 400);
break;
case POINT_SLABHIDE_LAND:
//DoCast(me, SPELL_COOLDOWN_5S); // unknown purpose
events.ScheduleEvent(EVENT_ATTACK, 1200);
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_HANDLE_ROCK_WALLS: // Close rock walls
instance->SetData(DATA_SLABHIDE_ROCK_WALL, false);
break;
case EVENT_LAVA_FISSURE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
DoCast(target, SPELL_LAVA_FISSURE);
events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
break;
case EVENT_SAND_BLAST:
DoCast(me, SPELL_SAND_BLAST);
events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 11000));
break;
case EVENT_AIR_PHASE:
events.Reset();
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_MIDDLE, SlabhideMiddlePos);
events.ScheduleEvent(EVENT_AIR_PHASE, 60000);
break;
case EVENT_TAKEOFF:
me->GetMotionMaster()->MoveTakeoff(POINT_SLABHIDE_IN_AIR, SlabhideInAirPos);
break;
case EVENT_STALACTITE:
me->SetCanFly(true);
me->SetDisableGravity(true);
me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetHover(true);
DoCast(me, SPELL_STALACTITE_SUMMON);
events.ScheduleEvent(EVENT_LAND, 8000);
break;
case EVENT_LAND:
{
Position pos = me->GetPosition();
pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, pos);
break;
}
case EVENT_ATTACK:
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetHover(false);
events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000));
DoCast(me, SPELL_CRYSTAL_STORM);
me->SetReactState(REACT_AGGRESSIVE);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
void DespawnAll()
{
// Despawn stalactite triggers npcs
std::list<Creature*> listStalactiteTrigger;
me->GetCreatureListWithEntryInGrid(listStalactiteTrigger, NPC_STALACTITE_TRIGGER, 200.0f);
if (!listStalactiteTrigger.empty())
for (std::list<Creature*>::const_iterator itr = listStalactiteTrigger.begin(); itr != listStalactiteTrigger.end(); ++itr)
(*itr)->DespawnOrUnsummon();
// Despawn stalactite objects
std::list<GameObject*> listStalactite;
me->GetGameObjectListWithEntryInGrid(listStalactite, GO_STALACTITE, 200.0f);
if (!listStalactite.empty())
for (std::list<GameObject*>::const_iterator itr = listStalactite.begin(); itr != listStalactite.end(); ++itr)
(*itr)->Delete();
}
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_slabhideAI>(creature);
}
};
// 43242 - Lava Fissure
class npc_lava_fissure : public CreatureScript
{
public:
npc_lava_fissure() : CreatureScript("npc_lava_fissure") { }
struct npc_lava_fissureAI : public ScriptedAI
{
npc_lava_fissureAI(Creature* creature) : ScriptedAI(creature)
{
DoCast(me, SPELL_LAVA_FISSURE_CRACK, true);
events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, 6000);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_LAVA_FISSURE_ERUPTION:
me->RemoveAurasDueToSpell(SPELL_LAVA_FISSURE_CRACK);
DoCast(me, SPELL_LAVA_FISSURE_ERUPTION, true);
me->DespawnOrUnsummon(14000);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_lava_fissureAI>(creature);
}
};
// 43159 - Stalactite Trigger - Boss
class npc_stalactite_trigger : public CreatureScript
{
public:
npc_stalactite_trigger() : CreatureScript("npc_stalactite_trigger") { }
struct npc_stalactite_triggerAI : public ScriptedAI
{
npc_stalactite_triggerAI(Creature* creature) : ScriptedAI(creature)
{
me->SetDisableGravity(true);
DoCast(me, SPELL_STALACTITE_SHADE, true);
events.ScheduleEvent(EVENT_STALACTITE_MISSLE, 5600);
}
void UpdateAI(uint32 diff) override
{
if (events.Empty())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_STALACTITE_MISSLE:
DoCast(me, SPELL_STALACTITE_MISSLE);
me->DespawnOrUnsummon(11000);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_stalactite_triggerAI>(creature);
}
};
// 81035 - Stalactite (check if player is near to summon stalactite)
class spell_s81035_stalactite : public SpellScriptLoader
{
public:
spell_s81035_stalactite() : SpellScriptLoader("spell_s81035_stalactite") { }
class spell_s81035_stalactite_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s81035_stalactite_SpellScript);
void SummonStalactiteTrigger()
{
Unit* caster = GetCaster();
caster->CastSpell(caster, SPELL_STALACTITE_SUMMON_TRIGGER, true);
}
void Register() override
{
OnHit += SpellHitFn(spell_s81035_stalactite_SpellScript::SummonStalactiteTrigger);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s81035_stalactite_SpellScript();
}
};
// 81028 - Stalactite (summons "Stalactite Trigger - Boss", 20 yard radius)
// 80650 - Stalactite (summons "Stalactite Trigger - Boss", 40 yard radius)
class spell_s81028_s80650_stalactite : public SpellScriptLoader
{
public:
spell_s81028_s80650_stalactite() : SpellScriptLoader("spell_s81028_s80650_stalactite") { }
class spell_s81028_s80650_stalactite_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s81028_s80650_stalactite_SpellScript);
void ModDestHeight(SpellDestination& dest)
{
// All stalactite triggers should have Z position 301.3837f, but no way to relocate (not relocateoffset!) height only.
Position offset = { 0.0f, 0.0f, 50.0f, 0.0f };
dest.RelocateOffset(offset);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_s81028_s80650_stalactite_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s81028_s80650_stalactite_SpellScript();
}
};
// 80654 - Stalactite (creates visual shade on ground)
// 80643/92653 - Stalactite (launches missle to the ground)
// 80647/92309 - Stalactite (creates stalactite object)
class spell_stalactite_mod_dest_height : public SpellScriptLoader
{
public:
spell_stalactite_mod_dest_height() : SpellScriptLoader("spell_stalactite_mod_dest_height") { }
class spell_stalactite_mod_dest_height_SpellScript : public SpellScript
{
PrepareSpellScript(spell_stalactite_mod_dest_height_SpellScript);
void ModDestHeight(SpellDestination& dest)
{
Unit* caster = GetCaster();
Position pos = caster->GetPosition();
pos.m_positionZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f);
dest.Relocate(pos);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_stalactite_mod_dest_height_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_stalactite_mod_dest_height_SpellScript();
}
};
// 92306 - Crystal storm (heroic mode check)
class spell_s92306_crystal_storm : public SpellScriptLoader
{
public:
spell_s92306_crystal_storm() : SpellScriptLoader("spell_s92306_crystal_storm") { }
class spell_s92306_crystal_storm_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s92306_crystal_storm_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_CRYSTAL_STORM_TRIGGER))
return false;
return true;
}
void HandleDummyEffect(SpellEffIndex /*eff*/)
{
Unit* caster = GetCaster();
if (caster->GetMap()->IsHeroic())
caster->CastSpell(caster, SPELL_CRYSTAL_STORM_TRIGGER, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_s92306_crystal_storm_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s92306_crystal_storm_SpellScript();
}
};
// 92300 - Crystal Storm (damage)
class BehindObjectCheck
{
public:
BehindObjectCheck(Unit* caster, std::list<GameObject*> objectList) : caster(caster), objectList(objectList) { }
bool operator()(WorldObject* unit)
{
for (std::list<GameObject*>::const_iterator itr = objectList.begin(); itr != objectList.end(); ++itr)
if (!(*itr)->IsInvisibleDueToDespawn() && (*itr)->IsInBetween(caster, unit, 1.5f))
return true;
return false;
}
private:
Unit* caster;
std::list<GameObject*> objectList;
};
class spell_s92300_crystal_storm : public SpellScriptLoader
{
public:
spell_s92300_crystal_storm() : SpellScriptLoader("spell_s92300_crystal_storm") { }
class spell_s92300_crystal_storm_SpellScript : public SpellScript
{
PrepareSpellScript(spell_s92300_crystal_storm_SpellScript);
void FilterTargets(std::list<WorldObject*>& unitList)
{
Unit* caster = GetCaster();
std::list<GameObject*> goList;
caster->GetGameObjectListWithEntryInGrid(goList, GO_STALACTITE, 40.0f);
if (goList.empty())
return;
unitList.remove_if(BehindObjectCheck(caster, goList));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s92300_crystal_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_s92300_crystal_storm_SpellScript();
}
};
void AddSC_boss_slabhide()
{
new boss_slabhide();
new npc_lava_fissure();
new npc_stalactite_trigger();
new spell_s81035_stalactite();
new spell_s81028_s80650_stalactite();
new spell_stalactite_mod_dest_height();
new spell_s92306_crystal_storm();
new spell_s92300_crystal_storm();
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "Player.h"
#include "CreatureGroups.h"
#include "InstanceScript.h"
#include "stonecore.h"
#define MAX_ENCOUNTER 4
/* Stonecore encounters:
0 - Corborus
1 - Slabhide
2 - Ozruk
3 - High Priestess Azil
*/
// TO-DO:
// - Find out spell IDs for both Stonecore Teleporters (spellclick).
ObjectData const creatureData[] =
{
{ NPC_MILLHOUSE_MANASTORM, DATA_MILLHOUSE_MANASTORM },
{ NPC_CORBORUS, DATA_CORBORUS },
{ NPC_SLABHIDE, DATA_SLABHIDE },
{ NPC_HIGH_PRIESTESS_AZIL, DATA_HIGH_PRIESTESS_AZIL },
{ NPC_STONECORE_TELEPORTER, DATA_STONECORE_TELEPORTER },
{ NPC_STONECORE_TELEPORTER_2, DATA_STONECORE_TELEPORTER_2 },
{ 0, 0 } // END
};
class instance_stonecore : public InstanceMapScript
{
public:
instance_stonecore() : InstanceMapScript(SCScriptName, 725) { }
struct instance_stonecore_InstanceScript : public InstanceScript
{
instance_stonecore_InstanceScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTER);
LoadObjectData(creatureData, nullptr);
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GAMEOBJECT_CORBORUS_ROCKDOOR:
corborusRockDoorGUID = go->GetGUID();
go->SetGoState(GetBossState(DATA_CORBORUS) != DONE ? GO_STATE_READY : GO_STATE_ACTIVE);
break;
case GAMEOBJECT_SLABHIDE_ROCK_WALL:
slabhideRockWallGUIDs.push_back(go->GetGUID());
break;
default:
break;
}
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_STONECORE_TELEPORTER:
case NPC_STONECORE_TELEPORTER_2:
if (GetBossState(DATA_SLABHIDE) == DONE)
ActivateTeleporter(creature);
break;
default:
break;
}
// Check if creature is part of Millhouse event
creature->SearchFormation();
if (CreatureGroup* group = creature->GetFormation())
{
switch (group->GetId())
{
case CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH:
millhouseTrashGUIDs.push_back(creature->GetGUID());
break;
case CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP:
millhouseLastGroupGUIDs.push_back(creature->GetGUID());
creature->SetReactState(REACT_PASSIVE);
creature->SetMeleeAnimKitId(ANIM_READY2H);
break;
}
}
InstanceScript::OnCreatureCreate(creature);
}
bool SetBossState(uint32 type, EncounterState state) override
{
switch (type)
{
case DATA_SLABHIDE:
// Open rock walls (Slabhide AI handles closing because it must be delayed)
if (state != IN_PROGRESS)
SetData(DATA_SLABHIDE_ROCK_WALL, true);
// Activate teleporters
if (state == DONE)
{
ActivateTeleporter(GetCreature(DATA_STONECORE_TELEPORTER));
ActivateTeleporter(GetCreature(DATA_STONECORE_TELEPORTER_2));
}
break;
default:
break;
}
return InstanceScript::SetBossState(type, state);
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_SLABHIDE_INTRO:
return slabhideIntro;
default:
break;
}
return 0;
}
void SetData(uint32 type, uint32 data) override
{
switch (type)
{
case DATA_HANDLE_CORBORUS_ROCKDOOR:
HandleGameObject(corborusRockDoorGUID, true);
break;
case DATA_MILLHOUSE_EVENT_FACE:
MillhouseEvent_Face();
break;
case DATA_MILLHOUSE_EVENT_KNOCKBACK:
MillhouseEvent_Knockback();
break;
case DATA_MILLHOUSE_EVENT_DESPAWN:
MillhouseEvent_Despawn();
break;
case DATA_SLABHIDE_INTRO:
slabhideIntro = EncounterState(data);
break;
case DATA_SLABHIDE_ROCK_WALL: // Handles rock walls
for (std::vector<ObjectGuid>::iterator itr = slabhideRockWallGUIDs.begin(); itr != slabhideRockWallGUIDs.end(); ++itr)
HandleGameObject((*itr), data ? true : false);
break;
default:
break;
}
}
private:
// Face Millhouse and other nearby mobs to Corborus
void MillhouseEvent_Face()
{
if (Creature* Millhouse = GetCreature(DATA_MILLHOUSE_MANASTORM))
Millhouse->SetFacingTo(1.570796f);
for (GuidVector::const_iterator i = millhouseLastGroupGUIDs.begin(); i != millhouseLastGroupGUIDs.end(); ++i)
if (Creature* creature = instance->GetCreature(*i))
creature->SetFacingTo(1.570796f);
}
// Knock back Millhouse and other mobs
void MillhouseEvent_Knockback()
{
if (Creature* Millhouse = GetCreature(DATA_MILLHOUSE_MANASTORM))
Millhouse->CastSpell(Millhouse, SPELL_RING_WYRM_KNOCKBACK, true);
for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr)
if (Creature* creature = instance->GetCreature(*itr))
creature->CastSpell(creature, SPELL_RING_WYRM_KNOCKBACK, true);
}
// Despawn all mobs
void MillhouseEvent_Despawn()
{
if (Creature* Millhouse = GetCreature(DATA_MILLHOUSE_MANASTORM))
Millhouse->DespawnOrUnsummon(3000);
for (GuidVector::const_iterator itr = millhouseTrashGUIDs.begin(); itr != millhouseTrashGUIDs.end(); ++itr)
if (Creature* creature = instance->GetCreature(*itr))
creature->DespawnOrUnsummon(3000);
for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr)
if (Creature* creature = instance->GetCreature(*itr))
creature->DespawnOrUnsummon(3000);
}
void ActivateTeleporter(Creature* teleporter)
{
if (!teleporter)
return;
teleporter->CastSpell(teleporter, SPELL_TELEPORTER_ACTIVE_VISUAL, true);
teleporter->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
GuidVector millhouseTrashGUIDs;
GuidVector millhouseLastGroupGUIDs;
ObjectGuid corborusRockDoorGUID;
GuidVector slabhideRockWallGUIDs;
EncounterState slabhideIntro;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_stonecore_InstanceScript(map);
}
};
void AddSC_instance_stonecore()
{
new instance_stonecore();
}

View File

@@ -0,0 +1,433 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "stonecore.h"
enum Texts
{
// Millhouse Manastorm
SAY_MILLHOUSE_EVENT_1 = 0,
SAY_MILLHOUSE_EVENT_2 = 1,
};
enum Spells
{
// Millhouse Manastorm
SPELL_SHADOW_BOLT = 81439,
SPELL_FROSTBOLT_VOLLEY = 81440,
SPELL_SHADOWFURY = 81441,
SPELL_FEAR = 81442,
// SPELL_MILLHOUSE_SAFE_CHECK = 81213, // unknown purpose
SPELL_CLEAR_ALL_DEBUFFS = 34098,
SPELL_BLUR = 81216,
SPELL_ANCHOR_HERE = 45313,
SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND = 81220,
SPELL_IMPENDING_DOOM = 86838,
SPELL_IMPENDING_DOOM_CHANNEL = 86830,
// SPELL_PORTAL_VISUAL = 79754,
};
enum Events
{
EVENT_NONE,
// Millhouse Manastorm
EVENT_FROSTBOLT_VOLLEY,
EVENT_SHADOWFURY,
EVENT_FEAR,
EVENT_READY_FOR_COMBAT,
EVENT_CAST_IMPENDING_DOOM,
EVENT_INTERRUPT_IMPENDING_DOOM,
};
enum Phase
{
PHASE_NONE,
PHASE_MILLHOUSE_GROUP_1,
PHASE_MILLHOUSE_GROUP_2,
PHASE_MILLHOUSE_GROUP_3,
PHASE_MILLHOUSE_GROUP_4,
PHASE_MASK_MILLHOUSE_GROUP_1 = (1 << (PHASE_MILLHOUSE_GROUP_1 - 1)),
PHASE_MASK_MILLHOUSE_GROUP_2 = (1 << (PHASE_MILLHOUSE_GROUP_2 - 1)),
PHASE_MASK_MILLHOUSE_GROUP_3 = (1 << (PHASE_MILLHOUSE_GROUP_3 - 1)),
PHASE_MASK_MILLHOUSE_GROUP_4 = (1 << (PHASE_MILLHOUSE_GROUP_4 - 1)),
};
enum MovementPoints
{
POINT_NONE,
POINT_MILLHOUSE_GROUP_2,
POINT_MILLHOUSE_GROUP_3,
POINT_MILLHOUSE_GROUP_4,
};
// Millhouse trash groups
Position const MillhousePointGroup2 = { 977.3045f, 895.2347f, 306.3298f };
Position const MillhousePointGroup3 = { 1049.823f, 871.4349f, 295.006f };
Position const MillhousePointGroup4 = { 1149.04f, 884.431f, 284.9406f };
// TO-DO:
// - Millhouse Manastorm should face and cast SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, but he won't. :(
// 43391 - Millhouse Manastorm
class npc_sc_millhouse_manastorm : public CreatureScript
{
public:
npc_sc_millhouse_manastorm() : CreatureScript("npc_sc_millhouse_manastorm") { }
struct npc_sc_millhouse_manastormAI : public ScriptedAI
{
npc_sc_millhouse_manastormAI(Creature* creature) : ScriptedAI(creature),
_instance(creature->GetInstanceScript())
{
events.SetPhase(PHASE_MILLHOUSE_GROUP_1);
}
void ScheduleEvents()
{
events.ScheduleEvent(EVENT_SHADOWFURY, 3000);
events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 5000);
events.ScheduleEvent(EVENT_FEAR, 8000);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (damage >= me->GetHealth())
damage = me->GetHealth() - 1;
if (!HealthBelowPct(50) || me->HasAura(SPELL_BLUR))
return;
switch (events.GetPhaseMask())
{
case PHASE_MASK_MILLHOUSE_GROUP_1:
events.Reset();
events.SetPhase(PHASE_MILLHOUSE_GROUP_2);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
DoCast(me, SPELL_BLUR);
Talk(SAY_MILLHOUSE_EVENT_1);
me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_2, MillhousePointGroup2);
break;
case PHASE_MASK_MILLHOUSE_GROUP_2:
events.Reset();
events.SetPhase(PHASE_MILLHOUSE_GROUP_3);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
DoCast(me, SPELL_BLUR);
Talk(SAY_MILLHOUSE_EVENT_1);
me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_3, MillhousePointGroup3);
break;
case PHASE_MASK_MILLHOUSE_GROUP_3:
events.Reset();
events.SetPhase(PHASE_MILLHOUSE_GROUP_4);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
DoCast(me, SPELL_BLUR);
me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_4, MillhousePointGroup4);
break;
default:
break;
}
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != POINT_MOTION_TYPE)
return;
if (pointId < POINT_MILLHOUSE_GROUP_2 || pointId > POINT_MILLHOUSE_GROUP_4)
return;
me->RemoveAllAuras();
me->CombatStop(true);
me->DeleteThreatList();
switch (pointId)
{
case POINT_MILLHOUSE_GROUP_2:
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
me->SetReactState(REACT_AGGRESSIVE);
if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 200.0f))
me->SetFacingToObject(worldtrigger);
DoCast(me, SPELL_ANCHOR_HERE);
DoCast(me, SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND);
events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000);
break;
case POINT_MILLHOUSE_GROUP_3:
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
me->SetReactState(REACT_AGGRESSIVE);
me->SetFacingTo(5.931499f);
DoCast(me, SPELL_ANCHOR_HERE);
DoCast(me, SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND);
events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000);
break;
case POINT_MILLHOUSE_GROUP_4:
me->SetFacingTo(3.455752f);
DoCast(me, SPELL_ANCHOR_HERE);
Talk(SAY_MILLHOUSE_EVENT_2);
events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 1000);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
// Do not update events if Millhouse is aggressive and has no combat.
if (!UpdateVictim() && me->GetReactState() == REACT_AGGRESSIVE)
return;
events.Update(diff);
// Impending Doom is exception because it needs to be interrupted.
if (me->HasUnitState(UNIT_STATE_CASTING) && !me->FindCurrentSpellBySpellId(SPELL_IMPENDING_DOOM))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FROSTBOLT_VOLLEY:
DoCastAOE(SPELL_FROSTBOLT_VOLLEY);
events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 7000);
break;
case EVENT_SHADOWFURY:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_SHADOWFURY);
events.ScheduleEvent(EVENT_SHADOWFURY, 7000);
break;
case EVENT_FEAR:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_FEAR);
events.ScheduleEvent(EVENT_FEAR, 18000);
break;
case EVENT_READY_FOR_COMBAT:
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
me->SetReactState(REACT_AGGRESSIVE);
ScheduleEvents();
break;
case EVENT_CAST_IMPENDING_DOOM:
DoCast(me, SPELL_IMPENDING_DOOM);
DoCast(me, SPELL_IMPENDING_DOOM_CHANNEL);
events.ScheduleEvent(EVENT_INTERRUPT_IMPENDING_DOOM, urand(15000,20000));
break;
case EVENT_INTERRUPT_IMPENDING_DOOM:
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
me->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN);
events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 3000);
break;
default:
break;
}
}
DoSpellAttackIfReady(SPELL_SHADOW_BOLT);
}
private:
InstanceScript* _instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_sc_millhouse_manastormAI>(creature);
}
};
// 81459 - Force of Earth
class spell_force_of_earth : public SpellScriptLoader
{
public:
spell_force_of_earth() : SpellScriptLoader("spell_force_of_earth") { }
class spell_force_of_earth_SpellScript : public SpellScript
{
PrepareSpellScript(spell_force_of_earth_SpellScript);
void DummyEffect(SpellEffIndex /*effIndex*/)
{
GetCaster()->SetDisplayId(26693); // can be moved to SAI part, need sniffs to see what this dummy does (note: npc 43552)
}
void Register()
{
OnEffectLaunch += SpellEffectFn(spell_force_of_earth_SpellScript::DummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_force_of_earth_SpellScript();
}
};
// 45313 - Anchor Here
class spell_sc_anchor_here : public SpellScriptLoader
{
public:
spell_sc_anchor_here() : SpellScriptLoader("spell_sc_anchor_here") { }
class spell_sc_anchor_here_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sc_anchor_here_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Creature* creature = GetHitUnit()->ToCreature())
creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_sc_anchor_here_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sc_anchor_here_SpellScript();
}
};
// 93167 - Twilight Documents
class spell_sc_twilight_documents : public SpellScriptLoader
{
public:
spell_sc_twilight_documents() : SpellScriptLoader("spell_sc_twilight_documents") { }
class spell_sc_twilight_documents_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sc_twilight_documents_SpellScript);
bool Validate(SpellInfo const* /*spell*/) override
{
if (!sObjectMgr->GetGameObjectTemplate(GAMEOBJECT_TWILIGHT_DOCUMENTS))
return false;
return true;
}
void SpawnGameObject(SpellEffIndex /*effIndex*/)
{
if (WorldLocation* loc = GetHitDest())
GetCaster()->SummonGameObject(GAMEOBJECT_TWILIGHT_DOCUMENTS, loc->GetPositionX(), loc->GetPositionY(), loc->GetPositionZ(), loc->GetOrientation(), 0, 0, 0, 0, 7200);
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_sc_twilight_documents_SpellScript::SpawnGameObject, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sc_twilight_documents_SpellScript();
}
};
// 81008 - Quake
class JumpCheck
{
public:
bool operator()(WorldObject* object) const
{
Player* player = object->ToPlayer();
return (player && (player->IsFalling() || player->HasUnitState(UNIT_STATE_JUMPING)));
}
};
class spell_sc_quake : public SpellScriptLoader
{
public:
spell_sc_quake() : SpellScriptLoader("spell_sc_quake") { }
class spell_sc_quake_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sc_quake_SpellScript);
void FilterTargets(std::list<WorldObject*>& unitList)
{
unitList.remove_if(JumpCheck());
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sc_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sc_quake_SpellScript();
}
};
class at_sc_corborus_intro : public AreaTriggerScript
{
public:
at_sc_corborus_intro() : AreaTriggerScript("at_sc_corborus_intro") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
if (Creature* corborus = instance->GetCreature(DATA_CORBORUS))
corborus->AI()->DoAction(ACTION_CORBORUS_INTRO);
return true;
}
};
class at_sc_slabhide_intro : public AreaTriggerScript
{
public:
at_sc_slabhide_intro() : AreaTriggerScript("at_sc_slabhide_intro") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
if (Creature* slabhide = instance->GetCreature(DATA_SLABHIDE))
slabhide->AI()->DoAction(ACTION_SLABHIDE_INTRO);
return true;
}
};
void AddSC_stonecore()
{
new npc_sc_millhouse_manastorm();
new spell_force_of_earth();
new spell_sc_anchor_here();
new spell_sc_twilight_documents();
new spell_sc_quake();
new at_sc_corborus_intro();
new at_sc_slabhide_intro();
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEF_STONECORE_H
#define DEF_STONECORE_H
#define SCScriptName "instance_stonecore"
#define DataHeader "SC"
enum DataTypes
{
// Encounter States/Boss GUIDs
DATA_CORBORUS,
DATA_SLABHIDE,
DATA_OZRUK,
DATA_HIGH_PRIESTESS_AZIL,
// Additional Data
DATA_MILLHOUSE_MANASTORM,
DATA_MILLHOUSE_EVENT_FACE,
DATA_HANDLE_CORBORUS_ROCKDOOR,
DATA_MILLHOUSE_EVENT_KNOCKBACK,
DATA_MILLHOUSE_EVENT_DESPAWN,
DATA_SLABHIDE_INTRO,
DATA_SLABHIDE_ROCK_WALL,
// Teleporters
DATA_STONECORE_TELEPORTER,
DATA_STONECORE_TELEPORTER_2,
};
enum Misc
{
ACTION_CORBORUS_INTRO,
ACTION_SLABHIDE_INTRO,
NPC_WORLDTRIGGER = 22515,
NPC_MILLHOUSE_MANASTORM = 43391,
NPC_CORBORUS = 43438,
NPC_SLABHIDE = 43214,
NPC_OZRUK = 42188,
NPC_HIGH_PRIESTESS_AZIL = 42333,
// Stonecore Teleporter misc
MAX_STONECORE_TELEPORTERS = 2,
NPC_STONECORE_TELEPORTER = 51396, // Entrance teleporter
NPC_STONECORE_TELEPORTER_2 = 51397, // Slabhide teleporter
SPELL_TELEPORTER_ACTIVE_VISUAL = 95298,
GAMEOBJECT_TWILIGHT_DOCUMENTS = 207415,
GAMEOBJECT_CORBORUS_ROCKDOOR = 207343,
GAMEOBJECT_SLABHIDE_ROCK_WALL = 204381,
SPELL_RING_WYRM_KNOCKBACK = 81235,
// Creature Formation IDs
CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH = 340418,
CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP = 340492,
};
#endif // DEF_STONECORE

View File

@@ -205,10 +205,7 @@ class boss_anubarak_trial : public CreatureScript
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_KILL_PLAYER);
instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0);
}
}
void MoveInLineOfSight(Unit* /*who*/) override
@@ -611,9 +608,7 @@ class npc_frost_sphere : public CreatureScript
struct npc_frost_sphereAI : public ScriptedAI
{
npc_frost_sphereAI(Creature* creature) : ScriptedAI(creature)
{
}
npc_frost_sphereAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
@@ -766,7 +761,6 @@ class npc_anubarak_spike : public CreatureScript
}
void MoveInLineOfSight(Unit* pWho) override
{
if (!pWho)
return;

View File

@@ -647,8 +647,6 @@ struct boss_faction_championsAI : public BossAI
if (Creature* temp = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GARROSH)))
temp->AI()->Talk(SAY_KILL_PLAYER);
instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0);
}
}

View File

@@ -97,9 +97,7 @@ class boss_jaraxxus : public CreatureScript
struct boss_jaraxxusAI : public BossAI
{
boss_jaraxxusAI(Creature* creature) : BossAI(creature, BOSS_JARAXXUS)
{
}
boss_jaraxxusAI(Creature* creature) : BossAI(creature, BOSS_JARAXXUS) { }
void Reset() override
{
@@ -124,10 +122,7 @@ class boss_jaraxxus : public CreatureScript
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_KILL_PLAYER);
instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0);
}
}
void JustDied(Unit* /*killer*/) override
@@ -136,11 +131,6 @@ class boss_jaraxxus : public CreatureScript
Talk(SAY_DEATH);
}
void JustSummoned(Creature* summoned) override
{
summons.Summon(summoned);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
@@ -370,9 +360,7 @@ class npc_nether_portal : public CreatureScript
struct npc_nether_portalAI : public ScriptedAI
{
npc_nether_portalAI(Creature* creature) : ScriptedAI(creature), _summons(me)
{
}
npc_nether_portalAI(Creature* creature) : ScriptedAI(creature), _summons(me) { }
void Reset() override
{

View File

@@ -156,9 +156,7 @@ class boss_gormok : public CreatureScript
struct boss_gormokAI : public BossAI
{
boss_gormokAI(Creature* creature) : BossAI(creature, BOSS_BEASTS)
{
}
boss_gormokAI(Creature* creature) : BossAI(creature, BOSS_BEASTS) { }
void Reset() override
{
@@ -542,12 +540,6 @@ struct boss_jormungarAI : public BossAI
me->DespawnOrUnsummon();
}
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
@@ -642,7 +634,6 @@ struct boss_jormungarAI : public BossAI
me->SetDisplayId(ModelMobile);
me->RemoveAurasDueToSpell(SPELL_SUBMERGE_0);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->GetMotionMaster()->Clear();
// if the worm was mobile before submerging, make him stationary now
if (WasMobile)
@@ -723,9 +714,7 @@ class boss_dreadscale : public CreatureScript
struct boss_dreadscaleAI : public boss_jormungarAI
{
boss_dreadscaleAI(Creature* creature) : boss_jormungarAI(creature)
{
}
boss_dreadscaleAI(Creature* creature) : boss_jormungarAI(creature) { }
void Reset() override
{
@@ -948,14 +937,6 @@ class boss_icehowl : public CreatureScript
me->DespawnOrUnsummon();
}
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
{
instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0);
}
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();

View File

@@ -31,14 +31,14 @@
#include "CellImpl.h"
#include "trial_of_the_crusader.h"
enum Yells
enum Texts
{
SAY_AGGRO = 0,
SAY_NIGHT = 1,
SAY_LIGHT = 2,
EMOTE_VORTEX = 3,
EMOTE_TWINK_PACT = 4,
SAY_TWINK_PACT = 5,
EMOTE_TWIN_PACT = 4,
SAY_TWIN_PACT = 5,
SAY_KILL_PLAYER = 6,
SAY_BERSERK = 7,
SAY_DEATH = 8
@@ -91,6 +91,23 @@ enum BossSpells
SPELL_SURGE_OF_SPEED = 65828
};
enum Events
{
EVENT_TWIN_SPIKE = 1,
EVENT_TOUCH = 2,
EVENT_SPECIAL_ABILITY = 3,
EVENT_BERSERK = 4
};
enum Stages
{
STAGE_DARK_VORTEX,
STAGE_DARK_PACT,
STAGE_LIGHT_VORTEX,
STAGE_LIGHT_PACT,
MAX_STAGES
};
#define SPELL_DARK_ESSENCE_HELPER RAID_MODE<uint32>(65684, 67176, 67177, 67178)
#define SPELL_LIGHT_ESSENCE_HELPER RAID_MODE<uint32>(65686, 67222, 67223, 67224)
@@ -101,8 +118,8 @@ enum BossSpells
enum Actions
{
ACTION_VORTEX = 0,
ACTION_PACT = 1
ACTION_VORTEX,
ACTION_PACT
};
#define ESSENCE_REMOVE 0
@@ -143,14 +160,8 @@ struct boss_twin_baseAI : public BossAI
{
boss_twin_baseAI(Creature* creature) : BossAI(creature, BOSS_VALKIRIES)
{
Initialize();
AuraState = AURA_STATE_NONE;
Stage = 0;
Weapon = 0;
VortexEmote = 0;
SisterNpcId = 0;
MyEmphatySpellId = 0;
OtherEssenceSpellId = 0;
@@ -162,16 +173,6 @@ struct boss_twin_baseAI : public BossAI
TouchSpellId = 0;
}
void Initialize()
{
IsBerserk = false;
SpecialAbilityTimer = 1 * MINUTE*IN_MILLISECONDS;
SpikeTimer = 20 * IN_MILLISECONDS;
TouchTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
BerserkTimer = IsHeroic() ? 6 * MINUTE*IN_MILLISECONDS : 10 * MINUTE*IN_MILLISECONDS;
}
void Reset() override
{
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
@@ -180,7 +181,6 @@ struct boss_twin_baseAI : public BossAI
/* Uncomment this once that they are floating above the ground
me->SetLevitate(true);
me->SetFlying(true); */
Initialize();
summons.DespawnAll();
}
@@ -212,15 +212,7 @@ struct boss_twin_baseAI : public BossAI
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_KILL_PLAYER);
instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0);
}
}
void JustSummoned(Creature* summoned) override
{
summons.Summon(summoned);
}
void SummonedCreatureDespawn(Creature* summoned) override
@@ -282,6 +274,11 @@ struct boss_twin_baseAI : public BossAI
Talk(SAY_AGGRO);
DoCast(me, SurgeSpellId);
events.ScheduleEvent(EVENT_TWIN_SPIKE, 20 * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_BERSERK, IsHeroic() ? 6 * MINUTE*IN_MILLISECONDS : 10 * MINUTE*IN_MILLISECONDS);
if (IsHeroic())
events.ScheduleEvent(EVENT_TOUCH, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
}
void DoAction(int32 action) override
@@ -289,10 +286,16 @@ struct boss_twin_baseAI : public BossAI
switch (action)
{
case ACTION_VORTEX:
Stage = me->GetEntry() == NPC_LIGHTBANE ? 2 : 1;
Talk(EMOTE_VORTEX);
DoCastAOE(VortexSpellId);
break;
case ACTION_PACT:
Stage = me->GetEntry() == NPC_LIGHTBANE ? 1 : 2;
Talk(EMOTE_TWIN_PACT);
Talk(SAY_TWIN_PACT);
if (Creature* sister = GetSister())
sister->CastSpell(sister, SPELL_POWER_TWINS, false);
DoCast(me, ShieldSpellId);
DoCast(me, TwinPactSpellId);
break;
default:
break;
@@ -305,95 +308,31 @@ struct boss_twin_baseAI : public BossAI
me->SetCanDualWield(mode);
}
void UpdateAI(uint32 diff) override
void ExecuteEvent(uint32 eventId) override
{
if (!instance || !UpdateVictim())
return;
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (Stage)
switch (eventId)
{
case 0:
case EVENT_TWIN_SPIKE:
DoCastVictim(SpikeSpellId);
events.ScheduleEvent(EVENT_TWIN_SPIKE, 20 * IN_MILLISECONDS);
break;
case 1: // Vortex
if (SpecialAbilityTimer <= diff)
{
if (Creature* pSister = GetSister())
pSister->AI()->DoAction(ACTION_VORTEX);
Talk(VortexEmote);
DoCastAOE(VortexSpellId);
Stage = 0;
SpecialAbilityTimer = 1*MINUTE*IN_MILLISECONDS;
}
else
SpecialAbilityTimer -= diff;
case EVENT_TOUCH:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true, OtherEssenceSpellId))
me->CastCustomSpell(TouchSpellId, SPELLVALUE_MAX_TARGETS, 1, target, false);
events.ScheduleEvent(EVENT_TOUCH, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
break;
case 2: // Shield + Pact
if (SpecialAbilityTimer <= diff)
{
Talk(EMOTE_TWINK_PACT);
Talk(SAY_TWINK_PACT);
if (Creature* pSister = GetSister())
{
pSister->AI()->DoAction(ACTION_PACT);
pSister->CastSpell(pSister, SPELL_POWER_TWINS, false);
}
DoCast(me, ShieldSpellId);
DoCast(me, TwinPactSpellId);
Stage = 0;
SpecialAbilityTimer = 1*MINUTE*IN_MILLISECONDS;
}
else
SpecialAbilityTimer -= diff;
case EVENT_BERSERK:
DoCast(me, SPELL_BERSERK);
Talk(SAY_BERSERK);
break;
default:
break;
}
if (SpikeTimer <= diff)
{
DoCastVictim(SpikeSpellId);
SpikeTimer = 20*IN_MILLISECONDS;
}
else
SpikeTimer -= diff;
if (IsHeroic() && TouchTimer <= diff)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true, OtherEssenceSpellId))
me->CastCustomSpell(TouchSpellId, SPELLVALUE_MAX_TARGETS, 1, target, false);
TouchTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS);
}
else
TouchTimer -= diff;
if (!IsBerserk && BerserkTimer <= diff)
{
DoCast(me, SPELL_BERSERK);
Talk(SAY_BERSERK);
IsBerserk = true;
}
else
BerserkTimer -= diff;
DoMeleeAttackIfReady();
}
protected:
AuraStateType AuraState;
uint8 Stage;
bool IsBerserk;
uint32 Weapon;
uint32 SpecialAbilityTimer;
uint32 SpikeTimer;
uint32 TouchTimer;
uint32 BerserkTimer;
int32 VortexEmote;
uint32 SisterNpcId;
uint32 MyEmphatySpellId;
uint32 OtherEssenceSpellId;
@@ -414,15 +353,14 @@ class boss_fjola : public CreatureScript
{
boss_fjolaAI(Creature* creature) : boss_twin_baseAI(creature)
{
GenerateStageSequence();
}
void Reset() override
{
SetEquipmentSlots(false, EQUIP_MAIN_1, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
Stage = 0;
Weapon = EQUIP_MAIN_1;
AuraState = AURA_STATE_UNKNOWN22;
VortexEmote = EMOTE_VORTEX;
SisterNpcId = NPC_DARKBANE;
MyEmphatySpellId = SPELL_TWIN_EMPATHY_DARK;
OtherEssenceSpellId = SPELL_DARK_ESSENCE_HELPER;
@@ -437,10 +375,43 @@ class boss_fjola : public CreatureScript
boss_twin_baseAI::Reset();
}
void ExecuteEvent(uint32 eventId) override
{
if (eventId == EVENT_SPECIAL_ABILITY)
{
if (CurrentStage == MAX_STAGES)
GenerateStageSequence();
switch (Stage[CurrentStage])
{
case STAGE_DARK_VORTEX:
if (Creature* sister = GetSister())
sister->AI()->DoAction(ACTION_VORTEX);
break;
case STAGE_DARK_PACT:
if (Creature* sister = GetSister())
sister->AI()->DoAction(ACTION_PACT);
break;
case STAGE_LIGHT_VORTEX:
DoAction(ACTION_VORTEX);
break;
case STAGE_LIGHT_PACT:
DoAction(ACTION_PACT);
break;
default:
break;
}
++CurrentStage;
events.ScheduleEvent(EVENT_SPECIAL_ABILITY, 45 * IN_MILLISECONDS);
}
else
boss_twin_baseAI::ExecuteEvent(eventId);
}
void EnterCombat(Unit* who) override
{
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT);
events.ScheduleEvent(EVENT_SPECIAL_ABILITY, 45 * IN_MILLISECONDS);
me->SummonCreature(NPC_BULLET_CONTROLLER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 0.0f, TEMPSUMMON_MANUAL_DESPAWN);
boss_twin_baseAI::EnterCombat(who);
}
@@ -457,6 +428,27 @@ class boss_fjola : public CreatureScript
boss_twin_baseAI::JustReachedHome();
}
void GenerateStageSequence()
{
CurrentStage = 0;
// Initialize and clean up.
for (int i = 0; i < MAX_STAGES; ++i)
Stage[i] = i;
// Allocate an unique random stage to each position in the array.
for (int i = 0; i < MAX_STAGES - 1; ++i)
{
int random = i + (rand32() % (MAX_STAGES - i));
int temp = Stage[i];
Stage[i] = Stage[random];
Stage[random] = temp;
}
}
private:
uint8 Stage[4];
uint8 CurrentStage;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -477,10 +469,8 @@ class boss_eydis : public CreatureScript
void Reset() override
{
SetEquipmentSlots(false, EQUIP_MAIN_2, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
Stage = 1;
Weapon = EQUIP_MAIN_2;
AuraState = AURA_STATE_UNKNOWN19;
VortexEmote = EMOTE_VORTEX;
SisterNpcId = NPC_LIGHTBANE;
MyEmphatySpellId = SPELL_TWIN_EMPATHY_LIGHT;
OtherEssenceSpellId = SPELL_LIGHT_ESSENCE_HELPER;

View File

@@ -190,6 +190,13 @@ class instance_trial_of_the_crusader : public InstanceMapScript
}
}
void OnUnitDeath(Unit* unit) override
{
if (unit->GetTypeId() == TYPEID_PLAYER && IsEncounterInProgress())
TributeToImmortalityEligible = false;
}
bool SetBossState(uint32 type, EncounterState state) override
{
if (!InstanceScript::SetBossState(type, state))
@@ -427,9 +434,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript
else if (data == DECREASE)
--MistressOfPainCount;
break;
case DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE:
TributeToImmortalityEligible = false;
break;
default:
break;
}

View File

@@ -111,9 +111,7 @@ class npc_announcer_toc10 : public CreatureScript
struct npc_announcer_toc10AI : public ScriptedAI
{
npc_announcer_toc10AI(Creature* creature) : ScriptedAI(creature)
{
}
npc_announcer_toc10AI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{

View File

@@ -24,9 +24,8 @@ enum DataTypes
TYPE_EVENT_NPC = 102,
TYPE_NORTHREND_BEASTS = 103,
DATA_SNOBOLD_COUNT = 301,
DATA_MISTRESS_OF_PAIN_COUNT = 302,
DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE = 303,
DATA_SNOBOLD_COUNT = 301,
DATA_MISTRESS_OF_PAIN_COUNT = 302,
INCREASE = 501,
DECREASE = 502,

View File

@@ -50,6 +50,7 @@ enum Spells
SPELL_HEAT = 65667,
SPELL_MOLTEN = 62373,
SPELL_BRITTLE = 62382,
SPELL_BRITTLE_25 = 67114,
SPELL_SHATTER = 62383,
SPELL_GROUND = 62548,
};
@@ -240,7 +241,7 @@ class boss_ignis : public CreatureScript
case EVENT_CHANGE_POT:
if (Unit* slagPotTarget = ObjectAccessor::GetUnit(*me, _slagPotGUID))
{
slagPotTarget->AddAura(SPELL_SLAG_POT, slagPotTarget);
DoCast(slagPotTarget, SPELL_SLAG_POT, true);
slagPotTarget->EnterVehicle(me, 1);
events.CancelEvent(EVENT_CHANGE_POT);
events.ScheduleEvent(EVENT_END_POT, 10000);
@@ -320,7 +321,7 @@ class npc_iron_construct : public CreatureScript
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (me->HasAura(SPELL_BRITTLE) && damage >= 5000)
if (me->HasAura(RAID_MODE(SPELL_BRITTLE, SPELL_BRITTLE_25)) && damage >= 5000)
{
DoCast(SPELL_SHATTER);
if (Creature* ignis = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_IGNIS)))
@@ -457,14 +458,13 @@ class spell_ignis_slag_pot : public SpellScriptLoader
return true;
}
void HandleEffectPeriodic(AuraEffect const* aurEff)
void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
{
Unit* aurEffCaster = aurEff->GetCaster();
if (!aurEffCaster)
return;
Unit* target = GetTarget();
aurEffCaster->CastSpell(target, SPELL_SLAG_POT_DAMAGE, true);
if (Unit* caster = GetCaster())
{
Unit* target = GetTarget();
caster->CastSpell(target, SPELL_SLAG_POT_DAMAGE, true);
}
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)

View File

@@ -166,7 +166,6 @@ class boss_kologarn : public CreatureScript
left = apply;
if (!apply && isEncounterInProgress)
{
who->ToCreature()->DespawnOrUnsummon();
Talk(SAY_LEFT_ARM_GONE);
events.ScheduleEvent(EVENT_RESPAWN_LEFT_ARM, 40000);
}
@@ -177,7 +176,6 @@ class boss_kologarn : public CreatureScript
right = apply;
if (!apply && isEncounterInProgress)
{
who->ToCreature()->DespawnOrUnsummon();
Talk(SAY_RIGHT_ARM_GONE);
events.ScheduleEvent(EVENT_RESPAWN_RIGHT_ARM, 40000);
}
@@ -194,6 +192,7 @@ class boss_kologarn : public CreatureScript
{
rubbleStalker->CastSpell(rubbleStalker, SPELL_FALLING_RUBBLE, true);
rubbleStalker->CastSpell(rubbleStalker, SPELL_SUMMON_RUBBLE, true);
who->ToCreature()->DespawnOrUnsummon();
}
if (!right && !left)