Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-05-24 17:57:30 +08:00
131 changed files with 5656 additions and 2599 deletions

View File

@@ -50,8 +50,9 @@ public:
break;
case GO_FACTORY_DOOR:
gameobject->UpdateSaveToDb(true);
// GoState (Door opened) is restored during GO creation, but we need to set LootState to prevent Lever from closing it again
if (_encounters[TYPE_RHAHK_ZOR] == DONE)
gameobject->SetGoState(GO_STATE_ACTIVE);
gameobject->SetLootState(GO_ACTIVATED);
break;
case GO_IRON_CLAD_DOOR:
gameobject->UpdateSaveToDb(true);

View File

@@ -301,7 +301,7 @@ public:
void JustEngagedWith(Unit*)
{
events.ScheduleEvent(EVENT_POISON, 8ms);
events.ScheduleEvent(EVENT_POISON, 8s);
if (Creature* Venoxis = GetVenoxis())
{
@@ -331,7 +331,7 @@ public:
case EVENT_POISON:
{
me->CastSpell(me->GetVictim(), SPELL_POISON);
events.ScheduleEvent(EVENT_POISON, 15ms);
events.ScheduleEvent(EVENT_POISON, 15s);
break;
}
}

View File

@@ -50,6 +50,7 @@ enum Data
ACTION_STOP_LK_FIGHT,
ACTION_DELETE_ICE_WALL,
DATA_WAVE_NUMBER,
DATA_LK_BATTLE,// in progress
};
enum Creatures
@@ -84,6 +85,7 @@ enum Creatures
NPC_SKY_REAVER_KORM_BLACKSKAR = 30824,
NPC_ALTAR_BUNNY = 37704,
NPC_QUEL_DELAR = 37158,
};
enum GameObjects
@@ -263,8 +265,14 @@ enum hMisc
SPELL_HOR_START_QUEST_ALLY = 71351,
SPELL_HOR_START_QUEST_HORDE = 71542,
SPELL_SHADOWMOURNE_VISUAL = 72523,
SPELL_ARCANE_CAST_VISUAL = 65633,
SPELL_UTHER_DESPAWN = 70693, //Sniffed
SPELL_WELL_OF_SOULS_VISUAL = 72630,
SPELL_SUMMON_SOULS = 72711, //Sniffed Sylvanas
//Battle of LK
SPELL_BLIDING_RETREAT = 70199, //Sniffed LK
SPELL_SOUL_REAPER = 69410, //Sniffed LK
SPELL_EVASION = 70190, //Sniffed Sylvanas
// Frostsworn General
EVENT_ACTIVATE_REFLECTIONS = 1,
@@ -310,18 +318,24 @@ const uint32 allowedCompositions[8][5] =
{NPC_WAVE_MERCENARY, NPC_WAVE_MAGE, NPC_WAVE_PRIEST, NPC_WAVE_FOOTMAN, NPC_WAVE_FOOTMAN}
};
const Position CenterPos = {5309.459473f, 2006.478516f, 711.595459f, 0.0f};
const Position SpawnPos = {5262.540527f, 1949.693726f, 707.695007f, 0.808736f}; // Jaina/Sylvanas Beginning Position
const Position LoralenFollowPos = {5283.234863f, 1990.946777f, 707.695679f, 0.929097f};
const Position MoveThronePos = {5306.952148f, 1998.499023f, 709.341431f, 1.277278f}; // Jaina/Sylvanas walks to throne
const Position UtherSpawnPos = {5308.310059f, 2003.857178f, 709.341431f, 4.650315f};
const Position CenterPos = {5309.459473f, 2006.478516f, 711.595459f, 0.0f};
const Position SpawnPos = {5263.22412f, 1950.95544f, 707.695862f, 0.808736f}; // Jaina/Sylvanas Beginning Position
const Position LoralenMidleFollowPos = {5274.25634f, 1976.04760f, 707.694763f, 0.929097f}; // Sniffed
const Position LoralenFollowPos = {5283.29296f, 1992.43078f, 707.694763f, 0.549238f}; // Sniffed
const Position LoralenFollowLk1 = {5292.94921f, 2008.25451f, 707.695801f, 1.047967f}; // Sniffed
const Position LoralenFollowLk2 = {5298.94335f, 2016.37097f, 707.695801f, 0.694538f}; // Sniffed
const Position LoralenFollowLk3 = {5336.94044f, 2040.21814f, 707.695801f, 0.439284f}; // Sniffed
const Position LoralenFollowLkFinal = {5361.96777f, 2065.68310f, 707.693848f, 0.831989f}; // Sniffed
const Position LoralenDeadPos = {5369.71289f, 2083.6330f, 707.695129f, 0.188739f}; // Sniffed
const Position MoveThronePos = {5306.98535f, 1998.10302f, 709.341187f, 1.277278f}; // Jaina/Sylvanas walks to throne
const Position UtherSpawnPos = {5308.310059f, 2003.857178f, 709.341431f, 4.650315f}; // Uther starting position
const Position LichKingSpawnPos = {5362.917480f, 2062.307129f, 707.695374f, 3.945812f};
const Position LichKingMoveThronePos = {5312.080566f, 2009.172119f, 709.341431f, 3.973301f}; // Lich King walks to throne
const Position LichKingMoveAwayPos = {5400.069824f, 2102.7131689f, 707.69525f, 0.843803f}; // Lich King walks away
const Position LichKingMoveMidlelThronePos = {5333.48437f, 2032.02648f, 707.695679f, 3.973301f}; // Lich King moves and hits Uther [sniff]
const Position LichKingMoveThronePos = {5312.79638f, 2010.07141f, 709.3942183f, 3.973301f}; // Lich King walks to throne [sniff]
const Position LichKingMoveAwayPos = {5400.069824f, 2102.7131689f, 707.69525f, 0.843803f}; // Lich King walks away [sniff]
const Position FalricMovePos = {5284.161133f, 2030.691650f, 709.319336f, 5.489386f};
const Position MarwynMovePos = {5335.330078f, 1982.376221f, 709.319580f, 2.339942f};
const Position SylvanasFightPos = {5557.508301f, 2263.920654f, 733.011230f, 3.624075f};
const Position LeaderEscapePos = {5577.654785f, 2235.347412f, 733.011230f, 2.359576f};
const Position LeaderEscapePos = {5576.80566f, 2235.55004f, 733.012268f, 2.782125f}; //Sniff
const Position ShipMasterSummonPos = {5262.773926f, 1669.980103f, 715.000000f, 0.000000f};
const Position WalkCaveInPos = {5267.594238f, 1678.750000f, 784.302856f, 1.041739f};
const Position AllyPortalPos = {5205.015625f, 1605.680298f, 806.444458f, 0.884375f};

View File

@@ -230,6 +230,7 @@ public:
{
case NPC_SYLVANAS_PART1:
creature->SetVisible(false);
creature->SetSpeed(MOVE_RUN, 1.1);
NPC_LeaderIntroGUID = creature->GetGUID();
if (TeamIdInInstance == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART1);
@@ -296,12 +297,8 @@ public:
creature->SetVisible(false);
if (!(EncounterMask & (1 << DATA_LK_INTRO)))
{
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT);
if (TeamIdInInstance != TEAM_ALLIANCE)
{
creature->StopMoving();
creature->SetFacingTo(creature->GetAngle(&SylvanasFightPos));
}
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT); //the fight cannot be in the form of an emote, it is causing bugs
creature->CastSpell(creature, SPELL_SOUL_REAPER, true);
}
else if (!(EncounterMask & (1 << DATA_LICH_KING)))
creature->AddAura(TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, creature);
@@ -316,22 +313,20 @@ public:
if (!creature->IsAlive())
creature->Respawn();
NPC_LeaderGUID = creature->GetGUID();
creature->SetWalk(false);
creature->SetSheath(SHEATH_STATE_MELEE);
if (TeamIdInInstance == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART2);
creature->SetWalk(false);
creature->SetHealth(creature->GetMaxHealth() / 20);
if (!(EncounterMask & (1 << DATA_FROSTSWORN_GENERAL)))
creature->SetVisible(false);
if (!(EncounterMask & (1 << DATA_LK_INTRO)))
{
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, TeamIdInInstance == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H);
creature->SetSheath(SHEATH_STATE_MELEE);
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, TeamIdInInstance == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H); //the fight cannot be in the form of an emote, it is causing bugs.
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
creature->CastSpell(creature, TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_BARRIER : SPELL_SYLVANAS_CLOAK_OF_DARKNESS, true);
if (TeamIdInInstance != TEAM_ALLIANCE)
{
creature->UpdatePosition(SylvanasFightPos, true);
creature->StopMovingOnCurrentPos();
}
}
else if (!(EncounterMask & (1 << DATA_LICH_KING)))
{
@@ -346,6 +341,7 @@ public:
creature->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true);
creature->StopMovingOnCurrentPos();
}
creature->SetSheath(SHEATH_STATE_MELEE);
creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
break;
case NPC_ICE_WALL_TARGET:
@@ -444,8 +440,13 @@ public:
if (Creature* c = instance->GetCreature(NPC_FrostswornGeneralGUID))
{
c->SetVisible(true);
c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
c->SetReactState(REACT_AGGRESSIVE);
}
if (Creature* c = instance->GetCreature(NPC_FrostswornGeneralGUID))
{
c->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
}
WaveNumber = 0;
DoUpdateWorldState(WORLD_STATE_HOR_COUNTER, 0);
@@ -712,7 +713,6 @@ public:
case GO_FRONT_DOOR:
return GO_FrontDoorGUID;
}
return ObjectGuid::Empty;
}
@@ -772,7 +772,6 @@ public:
++ur;
}
}
if (bFinished5Waves)
{
for (; WaveNumber < 4; ++WaveNumber)
@@ -860,9 +859,7 @@ public:
num_to_activate = 3;
else if (WaveNumber <= 4)
num_to_activate = 4;
reqKillCount += num_to_activate;
for (uint8 i = 0; i < num_to_activate; ++i)
{
uint32 entry = chosenComposition[WaveNumber - (WaveNumber > 5 ? 2 : 1)][i];
@@ -910,7 +907,6 @@ public:
c->StopMovingOnCurrentPos();
}
memset(&TrashActive, 0, sizeof(TrashActive));
if (Creature* falric = instance->GetCreature(NPC_FalricGUID))
falric->AI()->EnterEvadeMode();
if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID))
@@ -1014,7 +1010,6 @@ public:
if (Aura* a = pMarwyn->AddAura(SPELL_SHADOWMOURNE_VISUAL, pMarwyn))
a->SetDuration(8000);
}
pMarwyn->AI()->Talk(EMOTE_MARWYN_INTRO_SPIRIT);
}
++ResumeFirstEventStep;
@@ -1035,7 +1030,6 @@ public:
}
}
}
SetData(ACTION_SHOW_TRASH, 1);
ResumeFirstEventStep = 0;
ResumeFirstEventTimer = 0;
@@ -1057,7 +1051,6 @@ public:
else
ResumeFirstEventTimer -= diff;
}
if (outroStep)
{
if (outroTimer <= diff)
@@ -1153,7 +1146,6 @@ public:
if (StairsPos[index][i].GetPositionX())
if (GameObject* go = leader->SummonGameObject(TeamIdInInstance == TEAM_ALLIANCE ? GO_STAIRS_ALLIANCE : GO_STAIRS_HORDE, StairsPos[index][i].GetPositionX(), StairsPos[index][i].GetPositionY(), StairsPos[index][i].GetPositionZ(), StairsPos[index][i].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400, false))
go->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
//Position pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyPortalPos : HordePortalPos;
//leader->SummonGameObject(GO_PORTAL_TO_DALARAN, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400);
//pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyChestPos : HordeChestPos;
@@ -1169,6 +1161,7 @@ public:
{
c->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
c->GetMotionMaster()->MovePoint(0, WalkCaveInPos);
c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); // need gossip ID 10931
}
++outroStep;
outroTimer = 6000;

View File

@@ -1184,6 +1184,36 @@ public:
}
};
struct npc_violet_hold_defense_system : public ScriptedAI
{
npc_violet_hold_defense_system(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
DoCast(RAND(SPELL_DEFENSE_SYSTEM_SPAWN_EFFECT, SPELL_DEFENSE_SYSTEM_VISUAL));
events.ScheduleEvent(EVENT_ARCANE_LIGHTNING, 4s);
events.ScheduleEvent(EVENT_ARCANE_LIGHTNING_INSTAKILL, 4s);
me->DespawnOrUnsummon(7s, 0s);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_ARCANE_LIGHTNING:
DoCastAOE(RAND(SPELL_ARCANE_LIGHTNING, SPELL_ARCANE_LIGHTNING_VISUAL));
events.RepeatEvent(2000);
break;
case EVENT_ARCANE_LIGHTNING_INSTAKILL:
DoCastAOE(SPELL_ARCANE_LIGHTNING_INSTAKILL);
events.RepeatEvent(1000);
break;
}
}
};
void AddSC_violet_hold()
{
new go_vh_activation_crystal();
@@ -1201,4 +1231,5 @@ void AddSC_violet_hold()
new npc_azure_stalker();
new spell_destroy_door_seal();
RegisterCreatureAI(npc_violet_hold_defense_system);
}

View File

@@ -98,13 +98,16 @@ enum VHWorldStates
enum Spells
{
SPELL_CONTROL_CRYSTAL_ACTIVATION = 57804,
SPELL_ARCANE_LIGHTNING = 57912,
SPELL_ARCANE_LIGHTNING_VISUAL = 57930,
SPELL_PORTAL_CHANNEL = 58012,
SPELL_DESTROY_DOOR_SEAL = 58040,
SPELL_CYANIGOSA_TRANSFORM = 58668,
SPELL_CYANIGOSA_BLUE_AURA = 45870,
SPELL_CONTROL_CRYSTAL_ACTIVATION = 57804,
SPELL_DEFENSE_SYSTEM_SPAWN_EFFECT = 57886,
SPELL_DEFENSE_SYSTEM_VISUAL = 57887,
SPELL_ARCANE_LIGHTNING = 57912,
SPELL_ARCANE_LIGHTNING_VISUAL = 57930,
SPELL_ARCANE_LIGHTNING_INSTAKILL = 58152,
SPELL_PORTAL_CHANNEL = 58012,
SPELL_DESTROY_DOOR_SEAL = 58040,
SPELL_CYANIGOSA_TRANSFORM = 58668,
SPELL_CYANIGOSA_BLUE_AURA = 45870
};
enum Events
@@ -117,6 +120,10 @@ enum Events
EVENT_SUMMON_PORTAL,
EVENT_CYANIGOSSA_TRANSFORM,
EVENT_CYANIGOSA_ATTACK,
// Event defense system
EVENT_ARCANE_LIGHTNING,
EVENT_ARCANE_LIGHTNING_INSTAKILL
};
enum Data

View File

@@ -0,0 +1,77 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "mana_tombs.h"
enum Spells
{
SPELL_EARTHQUAKE = 33919,
SPELL_CRYSTAL_PRISON = 32361,
SPELL_ARCING_SMASH_N = 8374,
SPELL_ARCING_SMASH_H = 38761
};
struct boss_tavarok : public BossAI
{
boss_tavarok(Creature* creature) : BossAI(creature, DATA_TAVAROK)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
scheduler.Schedule(10s, 14200ms, [this](TaskContext context)
{
DoCastSelf(SPELL_EARTHQUAKE);
context.Repeat(20s, 31s);
}).Schedule(12s, 22s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_CRYSTAL_PRISON);
context.Repeat(15s, 22s);
}).Schedule(5900ms, [this](TaskContext context)
{
DoCastVictim(DUNGEON_MODE(SPELL_ARCING_SMASH_N, SPELL_ARCING_SMASH_H));
context.Repeat(8s, 12s);
});
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
}
void KilledUnit(Unit* /*victim*/) override
{
}
};
void AddSC_boss_tavarok()
{
RegisterManaTombsCreatureAI(boss_tavarok);
}

View File

@@ -40,4 +40,6 @@ inline AI* GetManaTombsAI(T* obj)
return GetInstanceAI<AI>(obj, MTScriptName);
}
#define RegisterManaTombsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetManaTombsAI)
#endif // MANA_TOMBS_H_

View File

@@ -0,0 +1,115 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "sethekk_halls.h"
enum Spells
{
SPELL_FLAME_SHOCK_N = 15039,
SPELL_FLAME_SHOCK_H = 15616,
SPELL_ARCANE_SHOCK_N = 33534,
SPELL_ARCANE_SHOCK_H = 38135,
SPELL_FROST_SHOCK_N = 12548,
SPELL_FROST_SHOCK_H = 21401,
SPELL_SHADOW_SHOCK_N = 33620,
SPELL_SHADOW_SHOCK_H = 38137,
SPELL_CHAIN_LIGHTNING_N = 15659,
SPELL_CHAIN_LIGHTNING_H = 15305,
SPELL_SUMMON_ARC_ELE = 33538,
SPELL_SUMMON_FIRE_ELE = 33537,
SPELL_SUMMON_FROST_ELE = 33539,
SPELL_SUMMON_SHADOW_ELE = 33540
};
enum Text
{
SAY_SUMMON = 0,
SAY_AGGRO = 1,
SAY_SLAY = 2,
SAY_DEATH = 3
};
struct boss_darkweaver_syth : public BossAI
{
boss_darkweaver_syth(Creature* creature) : BossAI(creature, DATA_DARKWEAVER_SYTH)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
ScheduleHealthCheckEvent({90, 50, 10}, [&] {
Talk(SAY_SUMMON);
DoCastSelf(SPELL_SUMMON_ARC_ELE);
DoCastSelf(SPELL_SUMMON_FIRE_ELE);
DoCastSelf(SPELL_SUMMON_FROST_ELE);
DoCastSelf(SPELL_SUMMON_SHADOW_ELE);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
Talk(SAY_AGGRO);
scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastRandomTarget(DUNGEON_MODE(SPELL_FLAME_SHOCK_N, SPELL_FLAME_SHOCK_H));
context.Repeat(10s, 15s);
}).Schedule(4s, [this](TaskContext context)
{
DoCastRandomTarget(DUNGEON_MODE(SPELL_ARCANE_SHOCK_N, SPELL_ARCANE_SHOCK_H));
context.Repeat(10s, 15s);
}).Schedule(6s, [this](TaskContext context)
{
DoCastRandomTarget(DUNGEON_MODE(SPELL_FROST_SHOCK_N, SPELL_FROST_SHOCK_H));
context.Repeat(10s, 15s);
}).Schedule(8s, [this](TaskContext context)
{
DoCastRandomTarget(DUNGEON_MODE(SPELL_SHADOW_SHOCK_N, SPELL_SHADOW_SHOCK_H));
context.Repeat(10s, 15s);
}).Schedule(15s, [this](TaskContext context)
{
DoCastRandomTarget(DUNGEON_MODE(SPELL_CHAIN_LIGHTNING_N, SPELL_CHAIN_LIGHTNING_H));
context.Repeat(10s, 15s);
});
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
};
void AddSC_boss_darkweaver_syth()
{
RegisterSethekkHallsCreatureAI(boss_darkweaver_syth);
}

View File

@@ -28,8 +28,7 @@ enum GrandmasterVorpil
SAY_SLAY = 3,
SAY_DEATH = 4,
SPELL_RAIN_OF_FIRE_N = 33617,
SPELL_RAIN_OF_FIRE_H = 39363,
SPELL_RAIN_OF_FIRE = 33617,
SPELL_DRAW_SHADOWS = 33563,
SPELL_SHADOWBOLT_VOLLEY = 33841,
@@ -38,8 +37,7 @@ enum GrandmasterVorpil
NPC_VOID_TRAVELER = 19226,
SPELL_SACRIFICE = 33587,
SPELL_SHADOW_NOVA = 33846,
SPELL_EMPOWERING_SHADOWS_N = 33783,
SPELL_EMPOWERING_SHADOWS_H = 39364,
SPELL_EMPOWERING_SHADOWS = 33783,
NPC_VOID_PORTAL = 19224,
SPELL_VOID_PORTAL_VISUAL = 33569,
@@ -155,22 +153,17 @@ struct boss_grandmaster_vorpil : public BossAI
context.Repeat();
}).Schedule(36400ms, [this](TaskContext context)
{
DoCastSelf(SPELL_DRAW_SHADOWS, true);
DoCastAOE(SPELL_DRAW_SHADOWS, true);
me->GetMap()->DoForAllPlayers([&](Player* player)
{
if (player->IsAlive() && !player->HasAura(SPELL_BANISH))
{
player->TeleportTo(me->GetMapId(), VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0, TELE_TO_NOT_LEAVE_COMBAT);
}
});
me->NearTeleportTo(VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0.0f);
me->GetMotionMaster()->Clear();
scheduler.Schedule(1s, [this](TaskContext /*context*/)
{
DoCastSelf(DUNGEON_MODE(SPELL_RAIN_OF_FIRE_N, SPELL_RAIN_OF_FIRE_H));
DoCastSelf(SPELL_RAIN_OF_FIRE);
me->ResumeChasingVictim();
});
me->NearTeleportTo(VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0.0f);
context.Repeat(36400ms, 44950ms);
}).Schedule(10900ms, [this](TaskContext context)
{
@@ -203,52 +196,59 @@ struct npc_voidtraveler : public ScriptedAI
{
npc_voidtraveler(Creature* creature) : ScriptedAI(creature) {}
ObjectGuid VorpilGUID;
uint32 moveTimer;
bool sacrificed;
void Reset() override
{
moveTimer = 1000;
sacrificed = false;
}
if (TempSummon* summon = me->ToTempSummon())
{
if (Unit* vorpil = summon->GetSummonerUnit())
{
me->GetMotionMaster()->MoveFollow(vorpil, 0.0f, 0.0f);
}
}
void SetGUID(ObjectGuid guid, int32) override
{
VorpilGUID = guid;
_scheduler.Schedule(1s, [this](TaskContext context)
{
if (TempSummon* summon = me->ToTempSummon())
{
if (Unit* vorpil = summon->GetSummonerUnit())
{
if (me->IsWithinMeleeRange(vorpil))
{
DoCastSelf(SPELL_SACRIFICE);
_scheduler.Schedule(1200ms, [this](TaskContext /*context*/)
{
if (TempSummon* summon = me->ToTempSummon())
{
if (Unit* vorpil = summon->GetSummonerUnit())
{
DoCastAOE(SPELL_SHADOW_NOVA, true);
me->CastSpell(vorpil, SPELL_EMPOWERING_SHADOWS, true, nullptr, nullptr, vorpil->GetGUID());
vorpil->ModifyHealth(int32(vorpil->CountPctFromMaxHealth(4)));
}
}
_scheduler.Schedule(100ms, [this](TaskContext /*context*/)
{
me->KillSelf();
});
});
}
else
{
context.Repeat();
}
}
}
});
}
void UpdateAI(uint32 diff) override
{
moveTimer += diff;
if (moveTimer >= 1000)
{
moveTimer = 0;
Creature* Vorpil = ObjectAccessor::GetCreature(*me, VorpilGUID);
if (!Vorpil)
{
me->DespawnOrUnsummon();
return;
}
me->GetMotionMaster()->MoveFollow(Vorpil, 0.0f, 0.0f);
if (sacrificed)
{
Vorpil->AddAura(DUNGEON_MODE(SPELL_EMPOWERING_SHADOWS_N, SPELL_EMPOWERING_SHADOWS_H), Vorpil);
Vorpil->ModifyHealth(int32(Vorpil->CountPctFromMaxHealth(4)));
DoCastAOE(SPELL_SHADOW_NOVA, true);
me->KillSelf();
return;
}
if (me->IsWithinDist(Vorpil, 3.0f))
{
DoCastSelf(SPELL_SACRIFICE);
sacrificed = true;
moveTimer = 500;
}
}
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
void AddSC_boss_grandmaster_vorpil()

View File

@@ -0,0 +1,101 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "the_slave_pens.h"
enum Spells
{
SPELL_LIGHTNING_BOLT = 35010,
SPELL_HEALING_WARD = 34980,
SPELL_EARTHGRAB_TOTEM = 31981,
SPELL_STONESKIN_TOTEM = 31985,
SPELL_NOVA_TOTEM = 31991
};
enum Text
{
SAY_AGGRO = 1,
SAY_KILL = 2,
SAY_JUST_DIED = 3
};
struct boss_mennu_the_betrayer : public BossAI
{
boss_mennu_the_betrayer(Creature* creature) : BossAI(creature, DATA_MENNU_THE_BETRAYER)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
ScheduleHealthCheckEvent(60, [&] {
DoCastSelf(SPELL_HEALING_WARD);
});
}
void JustSummoned(Creature* summon) override
{
summon->GetMotionMaster()->Clear();
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
Talk(SAY_AGGRO);
scheduler.Schedule(5s, 8s, [this](TaskContext context)
{
DoCastVictim(SPELL_LIGHTNING_BOLT);
context.Repeat(7s, 10s);
}).Schedule(20s, [this](TaskContext context)
{
DoCastSelf(SPELL_NOVA_TOTEM);
context.Repeat(26s);
}).Schedule(19200ms, [this](TaskContext context)
{
DoCastSelf(SPELL_EARTHGRAB_TOTEM);
context.Repeat(26s);
}).Schedule(18s, [this](TaskContext context)
{
DoCastSelf(SPELL_STONESKIN_TOTEM);
context.Repeat(26s);
});
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_JUST_DIED);
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_KILL);
}
};
void AddSC_boss_mennu_the_betrayer()
{
RegisterTheSlavePensCreatureAI(boss_mennu_the_betrayer);
}

View File

@@ -0,0 +1,73 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "the_slave_pens.h"
enum Spells
{
SPELL_ACID_SPRAY = 38153,
SPELL_CLEAVE = 40504,
SPELL_POISON_BOLT_VOLLEY_N = 34780,
SPELL_POISON_BOLT_VOLLEY_H = 39340,
SPELL_UPPERCUT = 32055
};
struct boss_quagmirran : public BossAI
{
boss_quagmirran(Creature* creature) : BossAI(creature, DATA_QUAGMIRRAN)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
scheduler.Schedule(9100ms, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE);
context.Repeat(18800ms, 24800ms);
}).Schedule(20300ms, [this](TaskContext context)
{
DoCastVictim(SPELL_UPPERCUT);
context.Repeat(21800ms);
}).Schedule(25200ms, [this](TaskContext context)
{
DoCastVictim(SPELL_ACID_SPRAY);
context.Repeat(25s);
}).Schedule(31800ms, [this](TaskContext context)
{
DoCastSelf(DUNGEON_MODE(SPELL_POISON_BOLT_VOLLEY_N, SPELL_POISON_BOLT_VOLLEY_H));
context.Repeat(24400ms);
});
}
};
void AddSC_boss_quagmirran()
{
RegisterTheSlavePensCreatureAI(boss_quagmirran);
}

View File

@@ -0,0 +1,73 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "the_slave_pens.h"
enum Spells
{
SPELL_ENSNARING_MOSS = 31948,
SPELL_FRENZY = 34970,
SPELL_GRIEVOUS_WOUND_N = 31956,
SPELL_GRIEVOUS_WOUND_H = 38801,
SPELL_WATER_SPIT = 35008
};
struct boss_rokmar_the_crackler : public BossAI
{
boss_rokmar_the_crackler(Creature* creature) : BossAI(creature, DATA_ROKMAR_THE_CRACKLER)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
ScheduleHealthCheckEvent(20, [&] {
DoCastSelf(SPELL_FRENZY);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
scheduler.Schedule(8s, [this] (TaskContext context)
{
DoCastVictim(DUNGEON_MODE(SPELL_GRIEVOUS_WOUND_N, SPELL_GRIEVOUS_WOUND_H));
context.Repeat(20700ms);
}).Schedule(15300ms, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_ENSNARING_MOSS);
context.Repeat(26s);
}).Schedule(10700ms, [this](TaskContext context)
{
DoCastSelf(SPELL_WATER_SPIT);
context.Repeat(19s);
});
}
};
void AddSC_boss_rokmar_the_crackler()
{
RegisterTheSlavePensCreatureAI(boss_rokmar_the_crackler);
}

View File

@@ -27,10 +27,11 @@ uint32 const EncounterCount = 3;
enum SPDataTypes
{
DATA_MENNU_THE_BETRAYER = 1,
DATA_ROKMAR_THE_CRACKLER = 2,
DATA_QUAGMIRRAN = 3,
DATA_AHUNE = 4,
DATA_MENNU_THE_BETRAYER = 0,
DATA_ROKMAR_THE_CRACKLER = 1,
DATA_QUAGMIRRAN = 2,
DATA_AHUNE = 3,
MAX_ENCOUNTER = 4,
DATA_AHUNE_BUNNY = 5,
DATA_FROZEN_CORE = 6,
DATA_FLAMECALLER_000 = 7,
@@ -65,6 +66,8 @@ enum SPCreaturesIds
NPC_SHAMAN_BEAM_BUNNY_002 = 25966,
NPC_WHISP_DEST_BUNNY = 26120,
NPC_WHISP_SOURCE_BUNNY = 26121,
NPC_MENNU_THE_BETRAYER = 17941,
NPC_ROKMAR_THE_CRACKLER = 17991,
NPC_QUAGMIRRAN = 17942
};
@@ -80,4 +83,6 @@ inline AI* GetTheSlavePensAI(T* obj)
return GetInstanceAI<AI>(obj, SPScriptName);
}
#define RegisterTheSlavePensCreatureAI(ai_name) RegisterCreatureAIWithFactory (ai_name, GetTheSlavePensAI)
#endif // SLAVE_PENS_H

View File

@@ -0,0 +1,178 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "the_underbog.h"
enum Spells
{
SPELL_SHOOT = 22907,
SPELL_KNOCKAWAY = 18813,
SPELL_RAPTOR_STRIKE = 31566,
SPELL_MULTISHOT = 34974,
SPELL_THROW_FREEZING_TRAP = 31946,
SPELL_AIMED_SHOT = 31623,
SPELL_HUNTERS_MARK = 31615
};
enum Text
{
SAY_AGGRO = 1,
SAY_KILL = 2,
SAY_JUST_DIED = 3
};
enum Misc
{
RANGED_GROUP = 1,
RANGE_CHECK = 2
};
struct boss_swamplord_muselek : public BossAI
{
boss_swamplord_muselek(Creature* creature) : BossAI(creature, DATA_MUSELEK)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
_canChase = true;
}
void AttackStart(Unit* victim) override
{
if (victim && me->Attack(victim, true) && me->IsWithinMeleeRange(victim))
{
me->GetMotionMaster()->MoveChase(victim);
}
else
{
me->GetMotionMaster()->MoveIdle();
}
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_JUST_DIED);
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_KILL);
}
bool CanShootVictim()
{
return me->GetVictim() && !me->IsWithinRange(me->GetVictim(), 10.0f) && me->IsWithinLOSInMap(me->GetVictim());
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
Talk(SAY_AGGRO);
scheduler.Schedule(3s, [this](TaskContext context)
{
if (CanShootVictim())
{
me->LoadEquipment(1, true);
DoCastVictim(SPELL_SHOOT);
me->GetMotionMaster()->Clear();
}
else if (_canChase)
{
me->GetMotionMaster()->MoveChase(me->GetVictim());
}
context.Repeat();
}).Schedule(15s, 30s, [this](TaskContext context)
{
if (me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
{
DoCastVictim(SPELL_KNOCKAWAY);
}
context.Repeat();
}).Schedule(10s, 15s, [this](TaskContext context)
{
DoCastVictim(SPELL_MULTISHOT);
context.Repeat(20s, 30s);
}).Schedule(30s, 40s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, false, true))
{
_markTarget = target->GetGUID();
_canChase = false;
DoCastVictim(SPELL_THROW_FREEZING_TRAP);
scheduler.Schedule(3s, [this, target](TaskContext)
{
if (target && me->GetVictim())
{
if (me->IsWithinMeleeRange(me->GetVictim()))
{
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveBackwards(me->GetVictim(), 10.0f);
}
me->m_Events.AddEventAtOffset([this]()
{
if (Unit* marktarget = ObjectAccessor::GetUnit(*me, _markTarget))
{
DoCast(marktarget, SPELL_HUNTERS_MARK);
}
}, 3s);
}
});
scheduler.Schedule(5s, [this, target](TaskContext)
{
if (target)
{
me->m_Events.AddEventAtOffset([this]()
{
if (Unit* marktarget = ObjectAccessor::GetUnit(*me, _markTarget))
{
scheduler.DelayAll(5s);
DoCast(marktarget, SPELL_AIMED_SHOT);
_canChase = true;
}
}, 3s);
}
});
}
context.Repeat(12s, 16s);
});
}
private:
ObjectGuid _markTarget;
bool _canChase;
};
void AddSC_boss_swamplord_muselek()
{
RegisterUnderbogCreatureAI(boss_swamplord_muselek);
}

View File

@@ -16,9 +16,55 @@
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "TaskScheduler.h"
#include "the_underbog.h"
enum UnderbatSpells
{
SPELL_TENTACLE_LASH = 34171
};
struct npc_underbat : public ScriptedAI
{
npc_underbat(Creature* c) : ScriptedAI(c) {}
void Reset() override
{
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(2200ms, 6900ms, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u)
{
return u->IsAlive() && !u->IsPet() && me->IsWithinCombatRange(u, 20.f) && !me->HasInArc(M_PI, u);
}))
{
DoCast(target, SPELL_TENTACLE_LASH);
}
context.Repeat(5700ms, 9700ms);
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_scheduler.Update(diff, [this]
{
DoMeleeAttackIfReady();
});
}
private:
TaskScheduler _scheduler;
};
class spell_fungal_decay : public AuraScript
{
PrepareAuraScript(spell_fungal_decay);
@@ -72,6 +118,7 @@ class spell_allergies : public AuraScript
void AddSC_underbog()
{
RegisterUnderbogCreatureAI(npc_underbat);
RegisterSpellScript(spell_fungal_decay);
RegisterSpellScript(spell_allergies);
}

View File

@@ -29,41 +29,41 @@ constexpr uint32 EncounterCount = 4;
enum bloodFurnace
{
DATA_THE_MAKER = 0,
DATA_BROGGOK = 1,
DATA_KELIDAN = 2,
MAX_ENCOUNTER = 3,
DATA_THE_MAKER = 0,
DATA_BROGGOK = 1,
DATA_KELIDAN = 2,
MAX_ENCOUNTER = 3,
DATA_DOOR1 = 10,
DATA_DOOR2 = 11,
DATA_DOOR3 = 12,
DATA_BROGGOK_REAR_DOOR = 13,
DATA_BROGGOK_LEVER = 14,
DATA_DOOR6 = 15,
DATA_DOOR1 = 10,
DATA_DOOR2 = 11,
DATA_DOOR3 = 12,
DATA_BROGGOK_REAR_DOOR = 13,
DATA_BROGGOK_LEVER = 14,
DATA_DOOR6 = 15,
DATA_PRISON_CELL1 = 20,
DATA_PRISON_CELL2 = 21,
DATA_PRISON_CELL3 = 22,
DATA_PRISON_CELL4 = 23,
DATA_PRISON_CELL1 = 20,
DATA_PRISON_CELL2 = 21,
DATA_PRISON_CELL3 = 22,
DATA_PRISON_CELL4 = 23,
ACTION_ACTIVATE_BROGGOK = 30,
ACTION_PREPARE_BROGGOK = 31
ACTION_ACTIVATE_BROGGOK = 30,
ACTION_PREPARE_BROGGOK = 31
};
enum bloodFurnaceNPC
{
NPC_THE_MAKER = 17381,
NPC_BROGGOK = 17380,
NPC_KELIDAN = 17377,
NPC_NASCENT_FEL_ORC = 17398,
NPC_CHANNELER = 17653
NPC_THE_MAKER = 17381,
NPC_BROGGOK = 17380,
NPC_KELIDAN = 17377,
NPC_NASCENT_FEL_ORC = 17398,
NPC_CHANNELER = 17653
};
enum BloodFurnaceGO
{
GO_BROGGOK_DOOR_FRONT = 181822,
GO_BROGGOK_DOOR_REAR = 181819,
GO_BROGGOK_LEVER = 181982
GO_BROGGOK_DOOR_FRONT = 181822,
GO_BROGGOK_DOOR_REAR = 181819,
GO_BROGGOK_LEVER = 181982
};
template <class AI, class T>

View File

@@ -21,14 +21,17 @@
#include "SpellScript.h"
#include "blood_furnace.h"
enum eEnums
enum Say
{
SAY_AGGRO = 0,
SAY_AGGRO = 0
};
enum Spells
{
SPELL_SLIME_SPRAY = 30913,
SPELL_POISON_CLOUD = 30916,
SPELL_POISON_BOLT = 30917,
SPELL_POISON = 30914,
SPELL_POISON = 30914
};
struct boss_broggok : public BossAI
@@ -52,7 +55,6 @@ struct boss_broggok : public BossAI
void JustSummoned(Creature* summoned) override
{
summons.Summon(summoned);
summoned->SetFaction(FACTION_MONSTER_2);
summoned->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
summoned->CastSpell(summoned, SPELL_POISON, true, 0, 0, me->GetGUID());
@@ -80,7 +82,6 @@ struct boss_broggok : public BossAI
DoCastSelf(SPELL_POISON_CLOUD);
context.Repeat(20s);
});
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(false);
@@ -106,7 +107,6 @@ public:
}
}
}
go->UseDoorOrButton();
return false;
}
@@ -121,6 +121,7 @@ class spell_broggok_poison_cloud : public AuraScript
{
if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
return false;
return true;
}
@@ -142,6 +143,6 @@ class spell_broggok_poison_cloud : public AuraScript
void AddSC_boss_broggok()
{
RegisterBloodFurnaceCreatureAI(boss_broggok);
new go_broggok_lever();
RegisterSpellScript(spell_broggok_poison_cloud);
new go_broggok_lever();
}

View File

@@ -20,343 +20,160 @@
#include "SpellAuras.h"
#include "blood_furnace.h"
enum eKelidan
enum Says
{
SAY_WAKE = 0,
SAY_ADD_AGGRO = 1,
SAY_KILL = 2,
SAY_NOVA = 3,
SAY_DIE = 4,
SAY_DIE = 4
};
// Keldian spells
enum Spells
{
SPELL_CORRUPTION = 30938,
SPELL_EVOCATION = 30935,
SPELL_FIRE_NOVA = 33132,
SPELL_SHADOW_BOLT_VOLLEY = 28599,
SPELL_BURNING_NOVA = 30940,
SPELL_VORTEX = 37370,
// Channelers spells
SPELL_SHADOW_BOLT = 12739,
SPELL_SHADOW_BOLT_H = 15472,
SPELL_MARK_OF_SHADOW = 30937,
SPELL_CHANNELING = 39123,
// Events
EVENT_SPELL_VOLLEY = 1,
EVENT_SPELL_CORRUPTION = 2,
EVENT_SPELL_BURNING_NOVA = 3,
EVENT_SPELL_FIRE_NOVA = 4,
EVENT_SPELL_SHADOW_BOLT = 5,
EVENT_SPELL_MARK = 6,
// Actions
ACTION_CHANNELER_ENGAGED = 1,
ACTION_CHANNELER_DIED = 2,
SPELL_VORTEX = 37370
};
const float ShadowmoonChannelers[5][4] =
enum Misc
{
{302.0f, -87.0f, -24.4f, 0.157f},
{321.0f, -63.5f, -24.6f, 4.887f},
{346.0f, -74.5f, -24.6f, 3.595f},
{344.0f, -103.5f, -24.5f, 2.356f},
{316.0f, -109.0f, -24.6f, 1.257f}
NPC_SHADOWMOON_CHANNELER = 17653
};
class boss_kelidan_the_breaker : public CreatureScript
enum Actions
{
public:
boss_kelidan_the_breaker() : CreatureScript("boss_kelidan_the_breaker")
ACTION_CHANNELER_DIED = 1,
ACTION_CHANNELER_AGGRO = 2
};
struct boss_kelidan_the_breaker : public BossAI
{
boss_kelidan_the_breaker(Creature* creature) : BossAI(creature, DATA_KELIDAN)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_kelidan_the_breakerAI : public ScriptedAI
void Reset() override
{
boss_kelidan_the_breakerAI(Creature* creature) : ScriptedAI(creature)
_Reset();
ApplyImmunities(true);
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
DoCastSelf(SPELL_EVOCATION);
if (instance)
{
instance = creature->GetInstanceScript();
instance->SetData(DATA_KELIDAN, NOT_STARTED);
}
}
InstanceScript* instance;
EventMap events;
ObjectGuid channelers[5];
uint32 checkTimer;
bool addYell;
void Reset() override
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_WAKE);
_JustEngagedWith();
me->InterruptNonMeleeSpells(false);
if (instance)
{
addYell = false;
checkTimer = 5000;
events.Reset();
instance->SetData(DATA_KELIDAN, IN_PROGRESS);
}
scheduler.Schedule(1s, [this](TaskContext context)
{
DoCastAOE(SPELL_SHADOW_BOLT_VOLLEY);
context.Repeat(8s, 13s);
}).Schedule(5s, [this](TaskContext context)
{
DoCastAOE(SPELL_CORRUPTION);
context.Repeat(30s, 50s);
}).Schedule(15s, [this](TaskContext context)
{
Talk(SAY_NOVA);
ApplyImmunities(false);
me->AddAura(SPELL_BURNING_NOVA, me);
ApplyImmunities(true);
SummonChannelers();
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(true);
if (instance)
instance->SetData(DATA_KELIDAN, NOT_STARTED);
}
void JustEngagedWith(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_SPELL_VOLLEY, 1000);
events.ScheduleEvent(EVENT_SPELL_CORRUPTION, 5000);
events.ScheduleEvent(EVENT_SPELL_BURNING_NOVA, 15000);
me->InterruptNonMeleeSpells(false);
Talk(SAY_WAKE);
if (instance)
instance->SetData(DATA_KELIDAN, IN_PROGRESS);
}
void KilledUnit(Unit* /*victim*/) override
{
if (urand(0, 1))
Talk(SAY_KILL);
}
void DoAction(int32 param) override
{
if (param == ACTION_CHANNELER_ENGAGED)
if (IsHeroic())
{
if (!addYell)
{
addYell = true;
Talk(SAY_ADD_AGGRO);
for (uint8 i = 0; i < 5; ++i)
{
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
if (channeler && !channeler->IsInCombat())
channeler->SetInCombatWithZone();
}
}
DoCastAOE(SPELL_VORTEX);
}
else if (param == ACTION_CHANNELER_DIED)
scheduler.DelayGroup(0, 6s);
scheduler.Schedule(5s, [this](TaskContext /*context*/)
{
for (uint8 i = 0; i < 5; ++i)
{
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
if (channeler && channeler->IsAlive())
return;
}
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(false);
if (Unit* target = me->SelectNearestPlayer(100.0f))
AttackStart(target);
}
}
void CheckChannelers()
{
if (addYell)
{
if (!SelectTargetFromPlayerList(100.0f))
EnterEvadeMode();
return;
}
SummonChannelers();
for (uint8 i = 0; i < 5; ++i)
{
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
if (channeler && !channeler->HasUnitState(UNIT_STATE_CASTING) && !channeler->IsInCombat())
{
Creature* target = ObjectAccessor::GetCreature(*me, channelers[(i + 2) % 5]);
if (target)
channeler->CastSpell(target, SPELL_CHANNELING, false);
}
}
}
void SummonChannelers()
{
for (uint8 i = 0; i < 5; ++i)
{
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
if (channeler && channeler->isDead())
{
channeler->DespawnOrUnsummon(1);
channeler = nullptr;
}
if (!channeler)
channeler = me->SummonCreature(NPC_CHANNELER, ShadowmoonChannelers[i][0], ShadowmoonChannelers[i][1], ShadowmoonChannelers[i][2], ShadowmoonChannelers[i][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000);
channelers[i] = channeler ? channeler->GetGUID() : ObjectGuid::Empty;
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
if (instance)
{
// Xinef: load grid with start doors
me->GetMap()->LoadGrid(0, -111.0f);
instance->SetData(DATA_KELIDAN, DONE);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR1), true);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR6), true);
}
}
void ApplyImmunities(bool apply)
{
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISTRACT, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
checkTimer += diff;
if (checkTimer >= 5000)
{
checkTimer = 0;
CheckChannelers();
if (!me->HasUnitState(UNIT_STATE_CASTING))
me->CastSpell(me, SPELL_EVOCATION, false);
}
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_VOLLEY:
me->CastSpell(me, SPELL_SHADOW_BOLT_VOLLEY, false);
events.RepeatEvent(urand(8000, 13000));
break;
case EVENT_SPELL_CORRUPTION:
me->CastSpell(me, SPELL_CORRUPTION, false);
events.RepeatEvent(urand(30000, 50000));
break;
case EVENT_SPELL_BURNING_NOVA:
Talk(SAY_NOVA);
ApplyImmunities(false);
me->AddAura(SPELL_BURNING_NOVA, me);
ApplyImmunities(true);
if (IsHeroic())
DoTeleportAll(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
events.DelayEvents(6000, 0);
events.RepeatEvent(urand(25000, 32000));
events.ScheduleEvent(EVENT_SPELL_FIRE_NOVA, 5000);
break;
case EVENT_SPELL_FIRE_NOVA:
me->CastSpell(me, SPELL_FIRE_NOVA, true);
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBloodFurnaceAI<boss_kelidan_the_breakerAI>(creature);
DoCastSelf(SPELL_FIRE_NOVA, true);
});
context.Repeat(25s, 32s);
});
}
};
class npc_shadowmoon_channeler : public CreatureScript
{
public:
npc_shadowmoon_channeler() : CreatureScript("npc_shadowmoon_channeler") {}
struct npc_shadowmoon_channelerAI : public ScriptedAI
void KilledUnit(Unit* /*victim*/) override
{
npc_shadowmoon_channelerAI(Creature* creature) : ScriptedAI(creature) {}
EventMap events;
void Reset() override
if (urand(0, 1))
{
events.Reset();
Talk(SAY_KILL);
}
Creature* GetKelidan()
{
if (InstanceScript* instance = me->GetInstanceScript())
return instance->GetCreature(DATA_KELIDAN);
return nullptr;
}
void JustEngagedWith(Unit* /*who*/) override
{
if (Creature* kelidan = GetKelidan())
kelidan->AI()->DoAction(ACTION_CHANNELER_ENGAGED);
me->InterruptNonMeleeSpells(false);
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, urand(1500, 3500));
events.ScheduleEvent(EVENT_SPELL_MARK, urand(5000, 6500));
}
void JustDied(Unit* /*killer*/) override
{
if (Creature* kelidan = GetKelidan())
kelidan->AI()->DoAction(ACTION_CHANNELER_DIED);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_SHADOW_BOLT:
me->CastSpell(me->GetVictim(), IsHeroic() ? SPELL_SHADOW_BOLT_H : SPELL_SHADOW_BOLT, false);
events.RepeatEvent(urand(6000, 7500));
break;
case EVENT_SPELL_MARK:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_MARK_OF_SHADOW, false);
events.RepeatEvent(urand(16000, 17500));
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBloodFurnaceAI<npc_shadowmoon_channelerAI>(creature);
}
void DoAction(int32 param) override
{
if (param == ACTION_CHANNELER_DIED)
{
if (me->FindNearestCreature(NPC_SHADOWMOON_CHANNELER, 100.0f))
{
return;
}
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
}
else if (param == ACTION_CHANNELER_AGGRO)
{
Talk(SAY_ADD_AGGRO);
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
_JustDied();
if (instance)
{
me->GetMap()->LoadGrid(0, -111.0f);
instance->SetData(DATA_KELIDAN, DONE);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR1), true);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR6), true);
}
}
void ApplyImmunities(bool apply)
{
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISTRACT, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, apply);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
}
};
void AddSC_boss_kelidan_the_breaker()
{
new boss_kelidan_the_breaker();
new npc_shadowmoon_channeler();
RegisterBloodFurnaceCreatureAI(boss_kelidan_the_breaker);
}

View File

@@ -19,111 +19,87 @@
#include "ScriptedCreature.h"
#include "blood_furnace.h"
enum eEnums
enum Says
{
SAY_AGGRO = 0,
SAY_KILL = 1,
SAY_DIE = 2,
SPELL_EXPLODING_BREAKER = 30925,
SPELL_DOMINATION = 30923,
EVENT_SPELL_EXPLODING = 1,
EVENT_SPELL_DOMINATION = 2
SAY_AGGRO = 0,
SAY_KILL = 1,
SAY_DIE = 2
};
class boss_the_maker : public CreatureScript
enum Spells
{
public:
boss_the_maker() : CreatureScript("boss_the_maker")
SPELL_EXPLODING_BEAKER = 30925,
SPELL_DOMINATION = 30923
};
struct boss_the_maker : public BossAI
{
boss_the_maker(Creature* creature) : BossAI(creature, DATA_THE_MAKER)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_the_makerAI : public ScriptedAI
void Reset() override
{
boss_the_makerAI(Creature* creature) : ScriptedAI(creature)
_Reset();
if (instance)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
EventMap events;
void Reset() override
{
events.Reset();
if (!instance)
return;
instance->SetData(DATA_THE_MAKER, NOT_STARTED);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
}
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_EXPLODING, 6000);
events.ScheduleEvent(EVENT_SPELL_DOMINATION, 120000);
if (!instance)
return;
instance->SetData(DATA_THE_MAKER, IN_PROGRESS);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), false);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER && urand(0, 1))
Talk(SAY_KILL);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
if (!instance)
return;
instance->SetData(DATA_THE_MAKER, DONE);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR3), true);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_EXPLODING:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_EXPLODING_BREAKER, false);
events.RepeatEvent(urand(7000, 11000));
break;
case EVENT_SPELL_DOMINATION:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_DOMINATION, false);
events.RepeatEvent(120000);
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
void JustEngagedWith(Unit* /*who*/) override
{
return GetBloodFurnaceAI<boss_the_makerAI>(creature);
Talk(SAY_AGGRO);
_JustEngagedWith();
instance->SetData(DATA_THE_MAKER, IN_PROGRESS);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), false);
scheduler.Schedule(6s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_EXPLODING_BEAKER);
context.Repeat(7s, 11s);
}).Schedule(2min, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_DOMINATION);
context.Repeat(2min);
});
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER && urand(0, 1))
{
Talk(SAY_KILL);
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
_JustDied();
instance->SetData(DATA_THE_MAKER, DONE);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR3), true);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
};
void AddSC_boss_the_maker()
{
new boss_the_maker();
RegisterBloodFurnaceCreatureAI(boss_the_maker);
}

View File

@@ -34,134 +34,114 @@ enum Spells
SPELL_SHADOW_BOLT = 30686,
SPELL_SUMMON_FIENDISH_HOUND = 30707,
SPELL_TREACHEROUS_AURA = 30695,
SPELL_DEMONIC_SHIELD = 31901,
SPELL_DEMONIC_SHIELD = 31901
};
enum Misc
struct boss_omor_the_unscarred : public BossAI
{
EVENT_SUMMON1 = 1,
EVENT_SUMMON2 = 2,
EVENT_TREACHEROUS_AURA = 3,
EVENT_DEMONIC_SHIELD = 4,
EVENT_KILL_TALK = 5
};
class boss_omor_the_unscarred : public CreatureScript
{
public:
boss_omor_the_unscarred() : CreatureScript("boss_omor_the_unscarred") { }
struct boss_omor_the_unscarredAI : public BossAI
boss_omor_the_unscarred(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED)
{
boss_omor_the_unscarredAI(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED)
SetCombatMovement(false);
scheduler.SetValidator([this]
{
SetCombatMovement(false);
}
void Reset() override
{
Talk(SAY_WIPE);
BossAI::Reset();
_targetGUID.Clear();
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SUMMON1, 10000);
events.ScheduleEvent(EVENT_SUMMON2, 25000);
events.ScheduleEvent(EVENT_TREACHEROUS_AURA, 6000);
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 1000);
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
}
}
void JustSummoned(Creature* summon) override
{
Talk(SAY_SUMMON);
summons.Summon(summon);
summon->SetInCombatWithZone();
}
void JustDied(Unit* killer) override
{
Talk(SAY_DIE);
BossAI::JustDied(killer);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SUMMON1:
Talk(SAY_SUMMON);
me->CastSpell(me, SPELL_SUMMON_FIENDISH_HOUND, false);
break;
case EVENT_SUMMON2:
me->CastSpell(me, SPELL_SUMMON_FIENDISH_HOUND, false);
events.ScheduleEvent(EVENT_SUMMON2, 15000);
break;
case EVENT_TREACHEROUS_AURA:
if (roll_chance_i(33))
Talk(SAY_CURSE);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_TREACHEROUS_AURA, false);
events.ScheduleEvent(EVENT_TREACHEROUS_AURA, urand(12000, 18000));
break;
case EVENT_DEMONIC_SHIELD:
if (me->HealthBelowPct(21))
{
me->CastSpell(me, SPELL_DEMONIC_SHIELD, false);
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 15000);
}
else
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 1000);
break;
}
if (!me->GetVictim() || !me->isAttackReady())
return;
if (me->IsWithinMeleeRange(me->GetVictim()))
{
me->GetMotionMaster()->MoveChase(me->GetVictim());
DoMeleeAttackIfReady();
}
else
{
me->GetMotionMaster()->Clear();
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
me->resetAttackTimer();
}
}
private:
ObjectGuid _targetGUID;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetHellfireRampartsAI<boss_omor_the_unscarredAI>(creature);
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
Talk(SAY_WIPE);
_Reset();
_targetGUID.Clear();
ScheduleHealthCheckEvent(21, [&]{
DoCastSelf(SPELL_DEMONIC_SHIELD);
scheduler.Schedule(15s, [this](TaskContext context)
{
DoCastSelf(SPELL_DEMONIC_SHIELD);
context.Repeat(15s);
});
});
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
scheduler.Schedule(6s, [this](TaskContext context)
{
if (roll_chance_i(33))
{
Talk(SAY_CURSE);
}
DoCastRandomTarget(SPELL_TREACHEROUS_AURA);
context.Repeat(12s, 18s);
}).Schedule(10s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND);
}).Schedule(25s, [this](TaskContext context)
{
DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND);
context.Repeat(15s);
});
}
void KilledUnit(Unit*) override
{
if(!_hasSpoken)
{
_hasSpoken = true;
Talk(SAY_KILL);
}
scheduler.Schedule(6s, [this](TaskContext /*context*/)
{
_hasSpoken = false;
});
}
void JustSummoned(Creature* summon) override
{
Talk(SAY_SUMMON);
summons.Summon(summon);
summon->SetInCombatWithZone();
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (!me->GetVictim() || !me->isAttackReady())
return;
if (me->IsWithinMeleeRange(me->GetVictim()))
{
me->GetMotionMaster()->MoveChase(me->GetVictim());
DoMeleeAttackIfReady();
}
else
{
me->GetMotionMaster()->Clear();
DoCastVictim(SPELL_SHADOW_BOLT);
me->resetAttackTimer();
}
}
private:
ObjectGuid _targetGUID;
bool _hasSpoken;
};
void AddSC_boss_omor_the_unscarred()
{
new boss_omor_the_unscarred();
RegisterHellfireRampartsCreatureAI(boss_omor_the_unscarred);
}

View File

@@ -21,40 +21,35 @@
enum Says
{
SAY_INTRO = 0,
SAY_WIPE = 0,
SAY_AGGRO = 1,
SAY_KILL = 2,
SAY_DIE = 3,
EMOTE_NAZAN = 0
SAY_INTRO = 0,
SAY_WIPE = 0,
SAY_AGGRO = 1,
SAY_KILL = 2,
SAY_DIE = 3,
EMOTE_NAZAN = 0
};
enum Spells
{
SPELL_FIREBALL = 33793,
SPELL_SUMMON_LIQUID_FIRE = 31706,
SPELL_REVENGE = 19130,
SPELL_REVENGE_H = 40392,
SPELL_CALL_NAZAN = 30693,
SPELL_BELLOWING_ROAR = 39427,
SPELL_CONE_OF_FIRE = 30926
SPELL_FIREBALL = 33793,
SPELL_SUMMON_LIQUID_FIRE = 31706,
SPELL_REVENGE = 19130,
SPELL_CALL_NAZAN = 30693,
SPELL_BELLOWING_ROAR = 39427,
SPELL_CONE_OF_FIRE = 30926
};
enum Misc
{
ACTION_FLY_DOWN = 0,
ACTION_FLY_DOWN = 0,
POINT_MIDDLE = 0,
POINT_FLIGHT = 1
};
POINT_MIDDLE = 0,
POINT_FLIGHT = 1,
EVENT_SPELL_REVENGE = 1,
EVENT_KILL_TALK = 2,
EVENT_AGGRO_TALK = 3,
EVENT_SPELL_FIREBALL = 4,
EVENT_SPELL_CONE_OF_FIRE = 5,
EVENT_SPELL_BELLOWING_ROAR = 6,
EVENT_CHANGE_POS = 7,
EVENT_RESTORE_COMBAT = 8
enum GroupPhase
{
GROUP_PHASE_1 = 0,
GROUP_PHASE_2 = 1
};
const Position NazanPos[3] =
@@ -64,347 +59,302 @@ const Position NazanPos[3] =
{-1373.84f, 1771.57f, 111.0f, 0.0f}
};
class boss_vazruden_the_herald : public CreatureScript
struct boss_vazruden_the_herald : public BossAI
{
public:
boss_vazruden_the_herald() : CreatureScript("boss_vazruden_the_herald") { }
boss_vazruden_the_herald(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) {}
struct boss_vazruden_the_heraldAI : public BossAI
void Reset() override
{
boss_vazruden_the_heraldAI(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
{
}
BossAI::Reset();
me->SetVisible(true);
me->SetReactState(REACT_PASSIVE);
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1372.56f, 1724.31f, 82.967f, 5.3058f);
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1383.39f, 1711.82f, 82.7961f, 5.67232f);
}
void Reset() override
void AttackStart(Unit*) override {}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
{
BossAI::Reset();
me->SetVisible(true);
summon->SetInCombatWithZone();
}
}
void JustDied(Unit*) override
{
instance->SetBossState(DATA_VAZRUDEN, DONE);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
{
me->SetVisible(false);
me->SummonCreature(NPC_VAZRUDEN, me->GetPositionX(), me->GetPositionY(), 81.2f, 5.46f);
me->SummonCreature(NPC_NAZAN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 5.46f);
}
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
summons.Despawn(summon);
if (summon->GetEntry() == NPC_HELLFIRE_SENTRY && summons.size() == 0)
{
Talk(SAY_INTRO);
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 85.0f, false);
me->setActive(true);
}
else if (summons.size() == 0)
{
me->KillSelf();
}
}
void SummonedCreatureDespawn(Creature* summon) override
{
summons.Despawn(summon);
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
{
BossAI::EnterEvadeMode();
}
}
void SetData(uint32 type, uint32 data) override
{
if (type == 0 && data == 1)
{
summons.DoZoneInCombat(NPC_HELLFIRE_SENTRY);
}
}
void UpdateAI(uint32 /*diff*/) override
{
if (!me->IsVisible() && summons.size() == 0)
{
BossAI::EnterEvadeMode();
}
}
};
struct boss_nazan : public BossAI
{
boss_nazan(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
me->SetCanFly(true);
me->SetDisableGravity(true);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->DespawnOrUnsummon(1);
}
void JustEngagedWith(Unit*) override
{
scheduler.CancelGroup(GROUP_PHASE_2);
scheduler.Schedule(5ms, GROUP_PHASE_1, [this](TaskContext context)
{
me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false);
scheduler.DelayAll(7s);
context.Repeat(30s);
}).Schedule(5s, GROUP_PHASE_1, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_FIREBALL);
context.Repeat(4s, 6s);
});
}
void AttackStart(Unit* who) override
{
if (me->IsLevitating())
{
me->Attack(who, true);
}
else
{
ScriptedAI::AttackStart(who);
}
}
void DoAction(int32 param) override
{
if (param == ACTION_FLY_DOWN)
{
Talk(EMOTE_NAZAN);
me->SetReactState(REACT_PASSIVE);
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1372.56f, 1724.31f, 82.967f, 5.3058f);
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1383.39f, 1711.82f, 82.7961f, 5.67232f);
me->InterruptNonMeleeSpells(true);
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 81.2f, false);
}
void AttackStart(Unit*) override
{
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
summon->SetInCombatWithZone();
}
void JustDied(Unit*) override
{
instance->SetBossState(DATA_VAZRUDEN, DONE);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
{
me->SetVisible(false);
me->SummonCreature(NPC_VAZRUDEN, me->GetPositionX(), me->GetPositionY(), 81.2f, 5.46f);
me->SummonCreature(NPC_NAZAN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 5.46f);
}
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
summons.Despawn(summon);
if (summon->GetEntry() == NPC_HELLFIRE_SENTRY && summons.size() == 0)
{
Talk(SAY_INTRO);
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 85.0f, false);
me->setActive(true);
}
else if (summons.size() == 0)
{
me->KillSelf();
}
}
void SummonedCreatureDespawn(Creature* summon) override
{
summons.Despawn(summon);
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
BossAI::EnterEvadeMode();
}
void SetData(uint32 type, uint32 data) override
{
if (type == 0 && data == 1)
{
summons.DoZoneInCombat(NPC_HELLFIRE_SENTRY);
}
}
void UpdateAI(uint32 /*diff*/) override
{
if (!me->IsVisible() && summons.size() == 0)
BossAI::EnterEvadeMode();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetHellfireRampartsAI<boss_vazruden_the_heraldAI>(creature);
}
};
class boss_nazan : public CreatureScript
{
public:
boss_nazan() : CreatureScript("boss_nazan") { }
struct boss_nazanAI : public ScriptedAI
void MovementInform(uint32 type, uint32 id) override
{
boss_nazanAI(Creature* creature) : ScriptedAI(creature)
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
{
}
void Reset() override
{
me->SetCanFly(true);
me->SetDisableGravity(true);
events.Reset();
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->DespawnOrUnsummon(1);
}
void JustEngagedWith(Unit*) override
{
events.ScheduleEvent(EVENT_CHANGE_POS, 0);
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 5000);
}
void AttackStart(Unit* who) override
{
if (me->IsLevitating())
me->Attack(who, true);
else
ScriptedAI::AttackStart(who);
}
void DoAction(int32 param) override
{
if (param == ACTION_FLY_DOWN)
me->SetCanFly(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_AGGRESSIVE);
scheduler.CancelGroup(GROUP_PHASE_1);
me->GetMotionMaster()->MoveChase(me->GetVictim());
scheduler.Schedule(5s, GROUP_PHASE_2, [this](TaskContext context)
{
Talk(EMOTE_NAZAN);
events.Reset();
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 81.2f, false);
DoCastVictim(SPELL_CONE_OF_FIRE);
context.Repeat(12s);
}).Schedule(6s, GROUP_PHASE_2, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_FIREBALL);
context.Repeat(4s, 6s);
});
if (IsHeroic())
{
scheduler.Schedule(10s, GROUP_PHASE_2, [this](TaskContext context)
{
DoCastSelf(SPELL_BELLOWING_ROAR);
context.Repeat(30s);
});
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
{
me->SetCanFly(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 1);
events.ScheduleEvent(EVENT_SPELL_CONE_OF_FIRE, 5000);
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 6000);
if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 10000);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_FIREBALL:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_FIREBALL, false);
events.ScheduleEvent(EVENT_SPELL_FIREBALL, urand(4000, 6000));
break;
case EVENT_CHANGE_POS:
me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false);
events.DelayEvents(7000);
events.ScheduleEvent(EVENT_CHANGE_POS, 30000);
break;
case EVENT_RESTORE_COMBAT:
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
case EVENT_SPELL_CONE_OF_FIRE:
me->CastSpell(me->GetVictim(), SPELL_CONE_OF_FIRE, false);
events.ScheduleEvent(EVENT_SPELL_CONE_OF_FIRE, 12000);
break;
case EVENT_SPELL_BELLOWING_ROAR:
me->CastSpell(me, SPELL_BELLOWING_ROAR, false);
events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 30000);
break;
}
if (!me->IsLevitating())
DoMeleeAttackIfReady();
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetHellfireRampartsAI<boss_nazanAI>(creature);
}
};
class boss_vazruden : public CreatureScript
{
public:
boss_vazruden() : CreatureScript("boss_vazruden") { }
struct boss_vazrudenAI : public ScriptedAI
void UpdateAI(uint32 /*diff*/) override
{
boss_vazrudenAI(Creature* creature) : ScriptedAI(creature) { }
if (!UpdateVictim())
return;
void Reset() override
{
events.Reset();
_nazanCalled = false;
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
Talk(SAY_WIPE);
me->DespawnOrUnsummon(1);
}
void JustEngagedWith(Unit*) override
{
events.ScheduleEvent(EVENT_AGGRO_TALK, 5000);
events.ScheduleEvent(EVENT_SPELL_REVENGE, 4000);
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (!_nazanCalled && me->HealthBelowPctDamaged(35, damage))
{
_nazanCalled = true;
me->CastSpell(me, SPELL_CALL_NAZAN, true);
}
}
void JustDied(Unit*) override
{
Talk(SAY_DIE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_AGGRO_TALK:
Talk(SAY_AGGRO);
break;
case EVENT_SPELL_REVENGE:
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_REVENGE, SPELL_REVENGE_H), false);
events.ScheduleEvent(EVENT_SPELL_REVENGE, 6000);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (!me->IsLevitating())
DoMeleeAttackIfReady();
}
private:
EventMap events;
bool _nazanCalled;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetHellfireRampartsAI<boss_vazrudenAI>(creature);
}
};
class spell_vazruden_fireball : public SpellScriptLoader
struct boss_vazruden : public BossAI
{
public:
spell_vazruden_fireball() : SpellScriptLoader("spell_vazruden_fireball") { }
class spell_vazruden_fireball_SpellScript : public SpellScript
boss_vazruden(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
{
PrepareSpellScript(spell_vazruden_fireball_SpellScript);
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
scheduler.SetValidator([this]
{
if (Unit* target = GetHitUnit())
target->CastSpell(target, SPELL_SUMMON_LIQUID_FIRE, true);
}
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_vazruden_fireball_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
void Reset() override
{
return new spell_vazruden_fireball_SpellScript();
_nazanCalled = false;
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
Talk(SAY_WIPE);
me->DespawnOrUnsummon(1);
}
void JustEngagedWith(Unit*) override
{
scheduler.Schedule(5s, [this](TaskContext /*context*/)
{
Talk(SAY_AGGRO);
}).Schedule(4s, [this](TaskContext context)
{
DoCastVictim(SPELL_REVENGE);
context.Repeat(6s);
});
}
void KilledUnit(Unit*) override
{
if (!_hasSpoken)
{
_hasSpoken = true;
Talk(SAY_KILL);
}
scheduler.Schedule(6s, [this](TaskContext /*context*/)
{
_hasSpoken = false;
});
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (!_nazanCalled && me->HealthBelowPctDamaged(35, damage))
{
_nazanCalled = true;
DoCastSelf(SPELL_CALL_NAZAN, true);
}
}
void JustDied(Unit*) override
{
Talk(SAY_DIE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
bool _hasSpoken;
bool _nazanCalled;
};
class spell_vazruden_fireball : public SpellScript
{
PrepareSpellScript(spell_vazruden_fireball);
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
{
target->CastSpell(target, SPELL_SUMMON_LIQUID_FIRE, true);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_vazruden_fireball::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_vazruden_call_nazan : public SpellScriptLoader
class spell_vazruden_call_nazan : public SpellScript
{
public:
spell_vazruden_call_nazan() : SpellScriptLoader("spell_vazruden_call_nazan") { }
PrepareSpellScript(spell_vazruden_call_nazan);
class spell_vazruden_call_nazan_SpellScript : public SpellScript
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
PrepareSpellScript(spell_vazruden_call_nazan_SpellScript);
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
if (Unit* target = GetHitUnit())
{
if (Unit* target = GetHitUnit())
target->GetAI()->DoAction(ACTION_FLY_DOWN);
target->GetAI()->DoAction(ACTION_FLY_DOWN);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_vazruden_call_nazan_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_vazruden_call_nazan_SpellScript();
OnEffectHitTarget += SpellEffectFn(spell_vazruden_call_nazan::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_boss_vazruden_the_herald()
{
new boss_vazruden_the_herald();
new boss_vazruden();
new boss_nazan();
new spell_vazruden_fireball();
new spell_vazruden_call_nazan();
RegisterHellfireRampartsCreatureAI(boss_vazruden_the_herald);
RegisterHellfireRampartsCreatureAI(boss_vazruden);
RegisterHellfireRampartsCreatureAI(boss_nazan);
RegisterSpellScript(spell_vazruden_fireball);
RegisterSpellScript(spell_vazruden_call_nazan);
}

View File

@@ -38,129 +38,113 @@ enum Spells
enum Misc
{
NPC_HELLFIRE_WATCHER = 17309,
EVENT_MORTAL_WOUND = 1,
EVENT_SURGE = 2,
EVENT_RETALIATION = 3,
EVENT_KILL_TALK = 4,
EVENT_CHECK_HEALTH = 5
NPC_HELLFIRE_WATCHER = 17309
};
class boss_watchkeeper_gargolmar : public CreatureScript
struct boss_watchkeeper_gargolmar : public BossAI
{
public:
boss_watchkeeper_gargolmar() : CreatureScript("boss_watchkeeper_gargolmar") { }
struct boss_watchkeeper_gargolmarAI : public BossAI
boss_watchkeeper_gargolmar(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR)
{
boss_watchkeeper_gargolmarAI(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR)
_taunted = false;
scheduler.SetValidator([this]
{
_taunted = false;
}
void Reset() override
{
BossAI::Reset();
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_MORTAL_WOUND, 5000);
events.ScheduleEvent(EVENT_SURGE, 3000);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
events.ScheduleEvent(EVENT_RETALIATION, 1000);
}
void MoveInLineOfSight(Unit* who) override
{
if (!_taunted)
{
if (who->GetTypeId() == TYPEID_PLAYER)
{
_taunted = true;
Talk(SAY_TAUNT);
}
}
BossAI::MoveInLineOfSight(who);
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
}
}
void JustDied(Unit* killer) override
{
Talk(SAY_DIE);
BossAI::JustDied(killer);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_MORTAL_WOUND:
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8000);
break;
case EVENT_SURGE:
Talk(SAY_SURGE);
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0))
me->CastSpell(target, SPELL_SURGE, false);
events.ScheduleEvent(EVENT_SURGE, 11000);
break;
case EVENT_RETALIATION:
if (me->HealthBelowPct(20))
{
me->CastSpell(me, SPELL_RETALIATION, false);
events.ScheduleEvent(EVENT_RETALIATION, 30000);
}
else
events.ScheduleEvent(EVENT_RETALIATION, 500);
break;
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(50))
{
Talk(SAY_HEAL);
std::list<Creature*> clist;
me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER);
for (std::list<Creature*>::const_iterator itr = clist.begin(); itr != clist.end(); ++itr)
(*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
break;
}
DoMeleeAttackIfReady();
}
private:
bool _taunted;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetHellfireRampartsAI<boss_watchkeeper_gargolmarAI>(creature);
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
ScheduleHealthCheckEvent(50, [&]{
Talk(SAY_HEAL);
std::list<Creature*> clist;
me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER);
for (std::list<Creature*>::const_iterator itr = clist.begin(); itr != clist.end(); ++itr)
{
(*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0);
}
});
ScheduleHealthCheckEvent(20, [&]{
DoCastSelf(SPELL_RETALIATION);
scheduler.Schedule(30s, [this](TaskContext context)
{
DoCastSelf(SPELL_RETALIATION);
context.Repeat(30s);
});
});
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
scheduler.Schedule(5s, [this] (TaskContext context)
{
DoCastVictim(SPELL_MORTAL_WOUND);
context.Repeat(8s);
}).Schedule(3s, [this](TaskContext context)
{
Talk(SAY_SURGE);
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0))
{
me->CastSpell(target, SPELL_SURGE);
}
context.Repeat(11s);
});
}
void MoveInLineOfSight(Unit* who) override
{
if (!_taunted)
{
if (who->GetTypeId() == TYPEID_PLAYER)
{
_taunted = true;
Talk(SAY_TAUNT);
}
}
BossAI::MoveInLineOfSight(who);
}
void KilledUnit(Unit*) override
{
if (!_hasSpoken)
{
_hasSpoken = true;
Talk(SAY_KILL);
}
scheduler.Schedule(6s, [this](TaskContext /*context*/)
{
_hasSpoken = false;
});
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
private:
bool _taunted;
bool _hasSpoken;
};
void AddSC_boss_watchkeeper_gargolmar()
{
new boss_watchkeeper_gargolmar();
RegisterHellfireRampartsCreatureAI(boss_watchkeeper_gargolmar);
}

View File

@@ -52,4 +52,6 @@ inline AI* GetHellfireRampartsAI(T* obj)
return GetInstanceAI<AI>(obj, HellfireRampartsScriptName);
}
#define RegisterHellfireRampartsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetHellfireRampartsAI)
#endif

View File

@@ -20,292 +20,295 @@
#include "ScriptedCreature.h"
#include "shattered_halls.h"
enum eGrandWarlockNethekurse
enum Texts
{
SAY_INTRO = 0,
SAY_PEON_ATTACKED = 1,
SAY_PEON_DIES = 2,
SAY_TAUNT = 3,
SAY_AGGRO = 4,
SAY_SLAY = 5,
SAY_DIE = 6,
SAY_SKIP_INTRO = 0,
SAY_INTRO_2 = 1,
SAY_PEON_ATTACKED = 2,
SAY_PEON_DIES = 3,
SAY_SHADOW_SEAR = 4,
SAY_SHADOW_FISSURE = 5,
SAY_DEATH_COIL = 6,
SAY_SLAY = 7,
SAY_DIE = 8
};
SPELL_DEATH_COIL_N = 30500,
SPELL_DEATH_COIL_H = 35954,
SPELL_DARK_SPIN = 30502,
SPELL_SHADOW_FISSURE = 30496,
SPELL_SHADOW_CLEAVE_N = 30495,
SPELL_SHADOW_SLAM_H = 35953,
enum Spells
{
SPELL_DEATH_COIL = 30500,
SPELL_DARK_SPIN = 30502,
SPELL_SHADOW_FISSURE = 30496,
SPELL_SHADOW_CLEAVE = 30495,
// Spells used exclusively in RP
SPELL_SHADOW_SEAR = 30735,
SPELL_DEATH_COIL = 30741,
SPELL_SHADOW_SEAR = 30735,
SPELL_DEATH_COIL_RP = 30741,
SPELL_SHADOW_FISSURE_RP = 30745,
SPELL_LESSER_SHADOW_FISSURE = 30744
};
enum Events
{
EVENT_INTRO = 1,
EVENT_SPELL_DEATH_COIL = 2,
EVENT_SPELL_SHADOW_FISSURE = 3,
EVENT_SPELL_CLEAVE = 4,
EVENT_CHECK_HEALTH = 5,
EVENT_START_ATTACK = 6,
EVENT_START_ATTACK = 2,
EVENT_STAGE_NONE = 0,
EVENT_STAGE_INTRO = 1,
EVENT_STAGE_TAUNT = 2,
EVENT_STAGE_MAIN = 3,
EVENT_STAGE_MAIN = 3
};
enum Data
{
SETDATA_DATA = 1,
SETDATA_PEON_AGGRO = 1,
SETDATA_PEON_DEATH = 2
};
// ########################################################
// Grand Warlock Nethekurse
// ########################################################
class boss_grand_warlock_nethekurse : public CreatureScript
enum Groups
{
public:
boss_grand_warlock_nethekurse() : CreatureScript("boss_grand_warlock_nethekurse") { }
GROUP_RP = 0
};
struct boss_grand_warlock_nethekurseAI : public BossAI
enum Actions
{
ACTION_START_INTRO = 0,
ACTION_CANCEL_INTRO = 1,
ACTION_START_COMBAT = 2,
};
enum Creatures
{
NPC_PEON = 17083
};
struct PeonRoleplay
{
uint32 spellId;
uint8 textId;
};
PeonRoleplay PeonRoleplayData[3] =
{
{ SPELL_DEATH_COIL_RP, SAY_DEATH_COIL },
{ SPELL_SHADOW_FISSURE_RP, SAY_SHADOW_FISSURE },
{ SPELL_SHADOW_SEAR, SAY_SHADOW_SEAR }
};
struct boss_grand_warlock_nethekurse : public BossAI
{
boss_grand_warlock_nethekurse(Creature* creature) : BossAI(creature, DATA_NETHEKURSE)
{
boss_grand_warlock_nethekurseAI(Creature* creature) : BossAI(creature, DATA_NETHEKURSE) { }
EventMap events2;
void Reset() override
scheduler.SetValidator([this]
{
EventStage = EVENT_STAGE_NONE;
_Reset();
events2.Reset();
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
ScheduleHealthCheckEvent(25, [&] {
DoCastSelf(SPELL_DARK_SPIN);
});
instance->SetBossState(DATA_NETHEKURSE, NOT_STARTED);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
_JustDied();
}
void SetData(uint32 data, uint32 value) override
{
if (data != SETDATA_DATA)
return;
if (value == SETDATA_PEON_AGGRO && PeonEngagedCount <= 4)
{
Talk(SAY_PEON_ATTACKED);
}
void JustDied(Unit* /*killer*/) override
else if (value == SETDATA_PEON_DEATH && PeonKilledCount <= 4)
{
Talk(SAY_DIE);
_JustDied();
}
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
me->SetFacingTo(4.572762489318847656f);
void SetData(uint32 data, uint32 value) override
{
if (data != SETDATA_DATA)
return;
switch (value)
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/)
{
case SETDATA_PEON_AGGRO:
if (PeonEngagedCount >= 4)
return;
me->HandleEmoteCommand(EMOTE_ONESHOT_APPLAUD);
me->GetMotionMaster()->Initialize();
Talk(SAY_PEON_DIES);
if (EventStage < EVENT_STAGE_TAUNT)
Talk(SAY_PEON_ATTACKED);
break;
case SETDATA_PEON_DEATH:
if (PeonKilledCount >= 4)
return;
if (EventStage < EVENT_STAGE_TAUNT)
Talk(SAY_PEON_DIES);
if (++PeonKilledCount == 4)
events2.ScheduleEvent(EVENT_START_ATTACK, 5000);
break;
}
}
void AttackStart(Unit* who) override
{
if (EventStage < EVENT_STAGE_MAIN)
return;
if (me->Attack(who, true))
{
DoStartMovement(who);
}
}
void MoveInLineOfSight(Unit* who) override
{
if (me->IsWithinDistInMap(who, 30.0f))
{
if (who->GetTypeId() != TYPEID_PLAYER)
return;
if (EventStage == EVENT_STAGE_NONE && PeonKilledCount < 4)
if (++PeonKilledCount == 4)
{
events2.ScheduleEvent(EVENT_INTRO, 90000);
Talk(SAY_INTRO);
EventStage = EVENT_STAGE_INTRO;
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
me->SetInCombatWithZone();
}
else if (PeonKilledCount >= 4)
{
events2.ScheduleEvent(EVENT_START_ATTACK, 1000);
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
me->SetInCombatWithZone();
}
}
if (EventStage < EVENT_STAGE_MAIN)
return;
ScriptedAI::MoveInLineOfSight(who);
}
void JustEngagedWith(Unit* /*who*/) override
{
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
uint32 eventId = events2.ExecuteEvent();
if (EventStage < EVENT_STAGE_MAIN && instance->GetBossState(DATA_NETHEKURSE) == IN_PROGRESS)
{
if (eventId == EVENT_INTRO)
{
Talk(SAY_TAUNT);
EventStage = EVENT_STAGE_TAUNT;
me->CastSpell(me, SPELL_SHADOW_SEAR, false);
}
else if (eventId == EVENT_START_ATTACK)
{
Talk(SAY_AGGRO);
EventStage = EVENT_STAGE_MAIN;
if (Unit* target = me->SelectNearestPlayer(50.0f))
Talk(SAY_INTRO_2);
DoAction(ACTION_CANCEL_INTRO);
if (Unit* target = me->SelectNearestPlayer(80.0f))
{
AttackStart(target);
}
}
});
}
}
events.ScheduleEvent(EVENT_SPELL_DEATH_COIL, 20000);
events.ScheduleEvent(EVENT_SPELL_SHADOW_FISSURE, 8000);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
return;
void IntroRP()
{
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext context)
{
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
me->SetFacingTo(4.572762489318847656f);
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/)
{
scheduler.Schedule(2500ms, GROUP_RP, [this](TaskContext /*context*/)
{
PeonRoleplay roleplayData = Acore::Containers::SelectRandomContainerElement(PeonRoleplayData);
DoCast(me, roleplayData.spellId);
Talk(roleplayData.textId);
me->GetMotionMaster()->Initialize();
});
});
context.Repeat(16400ms, 28500ms);
});
}
void JustEngagedWith(Unit* who) override
{
if (who->GetEntry() == NPC_PEON)
{
return;
}
_JustEngagedWith();
DoAction(ACTION_CANCEL_INTRO);
scheduler.CancelAll();
scheduler.Schedule(12150ms, 19850ms, [this](TaskContext context)
{
if (me->HealthBelowPct(90))
{
DoCastRandomTarget(SPELL_DEATH_COIL, 0, 30.0f, true);
}
context.Repeat();
}).Schedule(8100ms, 17300ms, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_SHADOW_FISSURE, 0, 60.0f, true);
context.Repeat(8450ms, 9450ms);
}).Schedule(10950ms, 21850ms, [this](TaskContext context)
{
DoCastVictim(SPELL_SHADOW_CLEAVE);
context.Repeat(1200ms, 23900ms);
});
if (PeonKilledCount < 4)
{
Talk(SAY_SKIP_INTRO);
}
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
void DoAction(int32 action) override
{
if (action == ACTION_CANCEL_INTRO)
{
scheduler.CancelGroup(GROUP_RP);
me->SetInCombatWithZone();
return;
}
else if (action == ACTION_START_INTRO)
{
IntroRP();
}
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
if (!UpdateVictim())
return;
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (!me->HealthBelowPct(25))
DoMeleeAttackIfReady();
}
private:
uint8 PeonEngagedCount = 0;
uint8 PeonKilledCount = 0;
};
class spell_tsh_shadow_bolt : public SpellScript
{
PrepareSpellScript(spell_tsh_shadow_bolt);
void SelectRandomPlayer(WorldObject*& target)
{
if (Creature* caster = GetCaster()->ToCreature())
{
if (Unit* randomTarget = caster->AI()->SelectTarget(SelectTargetMethod::Random, 0, 100.0f))
{
target = randomTarget;
}
}
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_tsh_shadow_bolt::SelectRandomPlayer, EFFECT_0, TARGET_UNIT_TARGET_ENEMY);
}
};
class spell_target_fissures : public SpellScript
{
PrepareSpellScript(spell_target_fissures);
void HandleEffect(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_LESSER_SHADOW_FISSURE, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_target_fissures::HandleEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class at_rp_nethekurse : public OnlyOnceAreaTriggerScript
{
public:
at_rp_nethekurse() : OnlyOnceAreaTriggerScript("at_rp_nethekurse") { }
bool _OnTrigger(Player* player, AreaTrigger const* /*at*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
{
if (instance->GetBossState(DATA_NETHEKURSE) != DONE && instance->GetBossState(DATA_NETHEKURSE) != IN_PROGRESS)
{
if (Creature* nethekurse = instance->GetCreature(DATA_NETHEKURSE))
{
nethekurse->AI()->DoAction(ACTION_START_INTRO);
}
}
if (!UpdateVictim())
return;
events.Update(diff);
if (EventStage < EVENT_STAGE_MAIN || me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_SHADOW_FISSURE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_SHADOW_FISSURE, false);
events.RescheduleEvent(EVENT_SPELL_SHADOW_FISSURE, urand(7500, 10000));
break;
case EVENT_SPELL_DEATH_COIL:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, DUNGEON_MODE(SPELL_DEATH_COIL_N, SPELL_DEATH_COIL_H), false);
events.RescheduleEvent(EVENT_SPELL_DEATH_COIL, urand(15000, 20000));
break;
case EVENT_SPELL_CLEAVE:
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_SHADOW_CLEAVE_N, SPELL_SHADOW_SLAM_H), false);
events.RescheduleEvent(EVENT_SPELL_CLEAVE, urand(6000, 8000));
break;
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(21))
{
events.Reset();
me->CastSpell(me, SPELL_DARK_SPIN, false);
}
else
{
events.RescheduleEvent(EVENT_CHECK_HEALTH, 1000);
}
break;
}
if (!me->HealthBelowPct(21))
DoMeleeAttackIfReady();
}
private:
uint8 PeonEngagedCount = 0;
uint8 PeonKilledCount = 0;
uint8 EventStage;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShatteredHallsAI<boss_grand_warlock_nethekurseAI>(creature);
}
};
class spell_tsh_shadow_sear : public SpellScriptLoader
{
public:
spell_tsh_shadow_sear() : SpellScriptLoader("spell_tsh_shadow_sear") { }
class spell_tsh_shadow_sear_AuraScript : public AuraScript
{
PrepareAuraScript(spell_tsh_shadow_sear_AuraScript);
void CalculateDamageAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
amount = 1000;
}
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_tsh_shadow_sear_AuraScript::CalculateDamageAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_tsh_shadow_sear_AuraScript();
}
};
class spell_tsh_shadow_bolt : public SpellScriptLoader
{
public:
spell_tsh_shadow_bolt() : SpellScriptLoader("spell_tsh_shadow_bolt") { }
class spell_tsh_shadow_bolt_SpellScript : public SpellScript
{
PrepareSpellScript(spell_tsh_shadow_bolt_SpellScript);
void SelectRandomPlayer(WorldObject*& target)
{
if (Creature* caster = GetCaster()->ToCreature())
{
std::list<Player*> playerList;
Map::PlayerList const& players = caster->GetMap()->GetPlayers();
for (auto itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource()->ToPlayer())
if (player->IsWithinDist(caster, 100.0f) && player->IsAlive())
playerList.push_back(player);
if (!playerList.empty())
target = Acore::Containers::SelectRandomContainerElement(playerList);
}
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_tsh_shadow_bolt_SpellScript::SelectRandomPlayer, EFFECT_0, TARGET_UNIT_TARGET_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_tsh_shadow_bolt_SpellScript();
return false;
}
};
void AddSC_boss_grand_warlock_nethekurse()
{
new boss_grand_warlock_nethekurse();
new spell_tsh_shadow_sear();
new spell_tsh_shadow_bolt();
RegisterShatteredHallsCreatureAI(boss_grand_warlock_nethekurse);
RegisterSpellScript(spell_tsh_shadow_bolt);
RegisterSpellScript(spell_target_fissures);
new at_rp_nethekurse();
}

View File

@@ -17,6 +17,8 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "TaskScheduler.h"
#include "shattered_halls.h"
enum Spells
@@ -24,249 +26,264 @@ enum Spells
SPELL_BLAST_WAVE = 30600,
SPELL_FEAR = 30584,
SPELL_THUNDERCLAP = 30633,
SPELL_BURNING_MAUL_N = 30598,
SPELL_BURNING_MAUL_H = 36056,
SPELL_BEATDOWN = 30618,
SPELL_BURNING_MAUL = 30598
};
enum Creatures
enum Equip
{
NPC_LEFT_HEAD = 19523,
NPC_RIGHT_HEAD = 19524
EQUIP_STANDARD = 1,
EQUIP_BURNING_MAUL = 2
};
enum HeadYells
{
SAY_ON_AGGRO = 0,
SAY_ON_AGGRO_2,
SAY_ON_AGGRO_3,
SAY_ON_BEATDOWN,
SAY_ON_BEATDOWN_2,
SAY_ON_BEATDOWN_3,
SAY_ON_KILL,
SAY_ON_KILL_2,
SAY_ON_DEATH
};
enum Misc
{
EMOTE_ENRAGE = 0,
SETDATA_DATA = 1,
SETDATA_YELL = 1
EMOTE_BURNING_MAUL = 0,
DATA_BURNING_MAUL_END = 1
};
enum Events
enum Phase
{
EVENT_AGGRO_YELL_1 = 1,
EVENT_AGGRO_YELL_2 = 2,
EVENT_AGGRO_YELL_3 = 3,
EVENT_THREAT_YELL_L_1 = 4,
EVENT_THREAT_YELL_L_2 = 5,
EVENT_THREAT_YELL_L_3 = 6,
EVENT_THREAT_YELL_R_1 = 7,
EVENT_KILL_YELL_LEFT = 8,
EVENT_KILL_YELL_RIGHT = 9,
EVENT_DEATH_YELL = 10,
EVENT_SPELL_FEAR = 20,
EVENT_SPELL_BURNING_MAUL = 21,
EVENT_SPELL_THUNDER_CLAP = 22,
EVENT_RESET_THREAT = 23,
EVENT_SPELL_BLAST_WAVE = 24
GROUP_NON_BURNING_PHASE = 0,
GROUP_BURNING_PHASE = 1,
GROUP_FULL_PHASE = 2
};
// ########################################################
// Warbringer_Omrogg
// ########################################################
class boss_warbringer_omrogg : public CreatureScript
struct boss_warbringer_omrogg : public BossAI
{
public:
boss_warbringer_omrogg() : CreatureScript("boss_warbringer_omrogg") { }
struct boss_warbringer_omroggAI : public BossAI
boss_warbringer_omrogg(Creature* creature) : BossAI(creature, DATA_OMROGG)
{
boss_warbringer_omroggAI(Creature* creature) : BossAI(creature, DATA_OMROGG)
scheduler.SetValidator([this]
{
}
EventMap events2;
Creature* GetLeftHead()
{
return summons.GetCreatureWithEntry(NPC_LEFT_HEAD);
}
Creature* GetRightHead()
{
return summons.GetCreatureWithEntry(NPC_RIGHT_HEAD);
}
void JustEngagedWith(Unit* /*who*/) override
{
me->SummonCreature(NPC_LEFT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0);
me->SummonCreature(NPC_RIGHT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0);
if (Creature* LeftHead = GetLeftHead())
{
uint8 aggroYell = urand(EVENT_AGGRO_YELL_1, EVENT_AGGRO_YELL_3);
LeftHead->AI()->Talk(aggroYell - 1);
events2.ScheduleEvent(aggroYell, 3000);
}
_JustEngagedWith();
events.ScheduleEvent(EVENT_SPELL_FEAR, 8000);
events.ScheduleEvent(EVENT_SPELL_BURNING_MAUL, 25000);
events.ScheduleEvent(EVENT_SPELL_THUNDER_CLAP, 15000);
events.ScheduleEvent(EVENT_RESET_THREAT, 30000);
}
void JustSummoned(Creature* summoned) override
{
summons.Summon(summoned);
}
void KilledUnit(Unit* /*victim*/) override
{
Creature* head = nullptr;
uint32 eventId = EVENT_KILL_YELL_LEFT;
if (urand(0, 1))
{
head = GetLeftHead();
eventId = EVENT_KILL_YELL_LEFT;
}
else
{
head = GetRightHead();
eventId = EVENT_KILL_YELL_RIGHT;
}
if (head)
head->AI()->Talk(eventId - 1);
events2.ScheduleEvent(eventId, 3000);
}
void JustDied(Unit* /*killer*/) override
{
Creature* LeftHead = GetLeftHead();
Creature* RightHead = GetRightHead();
if (!LeftHead || !RightHead)
return;
LeftHead->DespawnOrUnsummon(5000);
RightHead->DespawnOrUnsummon(5000);
LeftHead->AI()->Talk(EVENT_DEATH_YELL - 1);
RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL);
instance->SetBossState(DATA_OMROGG, DONE);
}
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
switch (uint32 eventId = events2.ExecuteEvent())
{
case EVENT_AGGRO_YELL_1:
case EVENT_AGGRO_YELL_2:
case EVENT_AGGRO_YELL_3:
case EVENT_KILL_YELL_LEFT:
case EVENT_THREAT_YELL_L_1:
case EVENT_THREAT_YELL_L_2:
case EVENT_THREAT_YELL_L_3:
if (Creature* RightHead = GetRightHead())
RightHead->AI()->Talk(eventId - 1);
break;
case EVENT_KILL_YELL_RIGHT:
case EVENT_THREAT_YELL_R_1:
if (Creature* LeftHead = GetLeftHead())
LeftHead->AI()->Talk(eventId - 1);
break;
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_FEAR:
me->CastSpell(me, SPELL_FEAR, false);
events.ScheduleEvent(EVENT_SPELL_FEAR, 22000);
break;
case EVENT_SPELL_THUNDER_CLAP:
me->CastSpell(me, SPELL_THUNDERCLAP, false);
events.ScheduleEvent(EVENT_SPELL_THUNDER_CLAP, 25000);
break;
case EVENT_RESET_THREAT:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
uint8 threatYell = urand(EVENT_THREAT_YELL_L_1, EVENT_THREAT_YELL_R_1);
if (Creature* head = threatYell == EVENT_THREAT_YELL_R_1 ? GetRightHead() : GetLeftHead())
head->AI()->Talk(threatYell - 1);
events.ScheduleEvent(threatYell, 3000);
DoResetThreatList();
me->AddThreat(target, 10.0f);
}
events.ScheduleEvent(EVENT_RESET_THREAT, 30000);
break;
case EVENT_SPELL_BURNING_MAUL:
Talk(EMOTE_ENRAGE);
me->CastSpell(me, DUNGEON_MODE(SPELL_BURNING_MAUL_N, SPELL_BURNING_MAUL_H), false);
events.ScheduleEvent(EVENT_SPELL_BURNING_MAUL, 40000);
events.ScheduleEvent(EVENT_SPELL_BLAST_WAVE, 15000);
events.ScheduleEvent(EVENT_SPELL_BLAST_WAVE, 20000);
break;
case EVENT_SPELL_BLAST_WAVE:
me->CastSpell(me, SPELL_BLAST_WAVE, false);
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShatteredHallsAI<boss_warbringer_omroggAI>(creature);
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void HandleHeadTalk(HeadYells yell)
{
switch (yell)
{
case SAY_ON_AGGRO:
{
uint8 group = urand(SAY_ON_AGGRO, SAY_ON_AGGRO_3);
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
{
leftHead->AI()->Talk(group);
_headTalk.Schedule(3600ms, [this, group](TaskContext /*context*/)
{
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
rightHead->AI()->Talk(group);
});
}
break;
}
case SAY_ON_BEATDOWN:
{
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
{
leftHead->AI()->Talk(SAY_ON_BEATDOWN);
_headTalk.Schedule(3600ms, [this](TaskContext context)
{
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
rightHead->AI()->Talk(SAY_ON_BEATDOWN);
context.Schedule(3600ms, [this](TaskContext context)
{
uint8 group = urand(SAY_ON_BEATDOWN_2, SAY_ON_BEATDOWN_3);
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
leftHead->AI()->Talk(group);
context.Schedule(3600ms, [this, group](TaskContext /*context*/)
{
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
rightHead->AI()->Talk(group);
});
});
});
}
break;
}
case SAY_ON_KILL:
{
uint8 group = urand(SAY_ON_KILL, SAY_ON_KILL_2);
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
leftHead->AI()->Talk(group);
_headTalk.Schedule(3600ms, [this, group](TaskContext /*context*/)
{
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
rightHead->AI()->Talk(group);
});
break;
}
case SAY_ON_DEATH:
{
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
leftHead->AI()->Talk(SAY_ON_DEATH);
_headTalk.Schedule(3600ms, [this](TaskContext /*context*/)
{
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
rightHead->AI()->Talk(SAY_ON_DEATH);
});
break;
}
default:
break;
}
}
void SetData(uint32 data, uint32) override
{
if (data != DATA_BURNING_MAUL_END)
return;
scheduler.CancelGroup(GROUP_BURNING_PHASE);
ScheduleNonBurningPhase();
ScheduleBurningPhase();
}
void ScheduleNonBurningPhase()
{
scheduler.
Schedule(12100ms, 17300ms, GROUP_NON_BURNING_PHASE, [this](TaskContext context)
{
DoCastAOE(SPELL_THUNDERCLAP);
context.Repeat(17200ms, 24200ms);
})
.Schedule(20s, 30s, GROUP_NON_BURNING_PHASE, [this](TaskContext context)
{
DoCastSelf(SPELL_BEATDOWN);
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
context.Schedule(200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext context)
{
DoResetThreatList();
if (Unit* newTarget = SelectTarget(SelectTargetMethod::Random, 1))
me->AddThreat(newTarget, 2250.f);
HandleHeadTalk(SAY_ON_BEATDOWN);
context.Schedule(1200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/)
{
me->SetReactState(REACT_AGGRESSIVE);
});
});
context.Repeat();
});
}
void ScheduleBurningPhase()
{
scheduler.
Schedule(45s, 60s, GROUP_BURNING_PHASE, [this](TaskContext context)
{
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
context.CancelGroup(GROUP_NON_BURNING_PHASE);
context.Schedule(1200ms, [this](TaskContext context)
{
DoCastAOE(SPELL_FEAR);
DoCast(SPELL_BURNING_MAUL);
context.Schedule(200ms, [this](TaskContext context)
{
Talk(EMOTE_BURNING_MAUL);
context.Schedule(2200ms, [this](TaskContext context)
{
DoResetThreatList();
if (Unit* newTarget = SelectTarget(SelectTargetMethod::Random, 1))
me->AddThreat(newTarget, 2250.f);
me->SetReactState(REACT_AGGRESSIVE);
context.Schedule(4850ms, 8500ms, GROUP_BURNING_PHASE, [this](TaskContext context)
{
DoCastAOE(SPELL_BLAST_WAVE);
context.Repeat();
});
});
});
});
});
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
_headTalk.CancelAll();
HandleHeadTalk(SAY_ON_AGGRO);
ScheduleNonBurningPhase();
ScheduleBurningPhase();
}
void KilledUnit(Unit* victim) override
{
if (victim && victim->GetTypeId() == TYPEID_PLAYER)
HandleHeadTalk(SAY_ON_KILL);
}
void JustDied(Unit* killer) override
{
HandleHeadTalk(SAY_ON_DEATH);
BossAI::JustDied(killer);
}
void UpdateAI(uint32 diff) override
{
_headTalk.Update(diff);
if (!UpdateVictim())
return;
scheduler.Update(diff, [this]
{
DoMeleeAttackIfReady();
});
}
protected:
TaskScheduler _headTalk;
};
class npc_omrogg_heads : public CreatureScript
class spell_burning_maul : public AuraScript
{
public:
npc_omrogg_heads() : CreatureScript("npc_omrogg_heads") { }
PrepareAuraScript(spell_burning_maul);
struct npc_omrogg_headsAI : public NullCreatureAI
void HandleOnRemove(AuraEffect const* /* aurEff */, AuraEffectHandleModes /* mode */)
{
npc_omrogg_headsAI(Creature* creature) : NullCreatureAI(creature) { timer = 0; }
void SetData(uint32 data, uint32 value) override
if (Unit* caster = GetCaster())
{
if (data == SETDATA_DATA && value == SETDATA_YELL)
timer = 1;
}
void UpdateAI(uint32 diff) override
{
if (timer)
if (Creature* omrogg = caster->ToCreature())
{
timer += diff;
if (timer >= 3000)
{
timer = 0;
Talk(EVENT_DEATH_YELL - 1);
}
omrogg->LoadEquipment(EQUIP_STANDARD);
omrogg->AI()->SetData(DATA_BURNING_MAUL_END, 0);
}
}
}
uint32 timer;
};
CreatureAI* GetAI(Creature* creature) const override
void HandleOnApply(AuraEffect const* /* aurEff */, AuraEffectHandleModes /* mode */)
{
return GetShatteredHallsAI<npc_omrogg_headsAI>(creature);
if (Unit* caster = GetCaster())
if (Creature* omrogg = caster->ToCreature())
omrogg->LoadEquipment(EQUIP_BURNING_MAUL);
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_burning_maul::HandleOnRemove, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
OnEffectApply += AuraEffectApplyFn(spell_burning_maul::HandleOnApply, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_warbringer_omrogg()
{
new boss_warbringer_omrogg();
new npc_omrogg_heads();
RegisterShatteredHallsCreatureAI(boss_warbringer_omrogg);
RegisterSpellScript(spell_burning_maul);
}

View File

@@ -17,174 +17,305 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "TaskScheduler.h"
#include "shattered_halls.h"
enum Says
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2,
SAY_EVADE = 5
};
enum Spells
{
SPELL_BLADE_DANCE = 30739,
SPELL_CHARGE = 25821,
SPELL_SPRINT = 32720,
// Blade dance
SPELL_BLADE_DANCE_TARGETING = 30738,
SPELL_BLADE_DANCE_DMG = 30739,
SPELL_BLADE_DANCE_CHARGE = 30751,
// Warchief portal
SPELL_SUMMON_HEATHEN = 30737,
SPELL_SUMMON_REAVER = 30785,
SPELL_SUMMON_SHARPSHOOTER = 30786
};
enum Creatures
{
NPC_SHATTERED_ASSASSIN = 17695,
NPC_HEARTHEN_GUARD = 17621,
NPC_SHARPSHOOTER_GUARD = 17622,
NPC_REAVER_GUARD = 17623
NPC_SHATTERED_ASSASSIN = 17695,
NPC_BLADE_DANCE_TARGET = 20709
};
float AssassEntrance[3] = { 275.136f, -84.29f, 2.3f }; // y -8
float AssassExit[3] = { 184.233f, -84.29f, 2.3f }; // y -8
float AddsEntrance[3] = { 306.036f, -84.29f, 1.93f };
enum Misc
enum PortalData
{
EVENT_CHECK_ROOM = 1,
EVENT_SUMMON_ADDS = 2,
EVENT_SUMMON_ASSASSINS = 3,
EVENT_SPELL_CHARGE = 4,
EVENT_MOVE_TO_NEXT_POINT = 5,
EVENT_BLADE_DANCE = 6,
EVENT_FINISH_BLADE_DANCE = 7
DATA_START_FIGHT = 1,
DATA_RESET_FIGHT = 2
};
class boss_warchief_kargath_bladefist : public CreatureScript
std::array<uint32, 3> const summonSpells = { SPELL_SUMMON_HEATHEN, SPELL_SUMMON_REAVER, SPELL_SUMMON_SHARPSHOOTER };
std::vector<Position> const assassinsPos =
{
{ 172.68164f, -80.65692f, 2.0834563f, 5.4279f },
{ 167.8295f, -86.55783f, 1.9949634f, 0.8118f },
{ 287.0375f, -88.17879f, 2.0663502f, 3.2490f },
{ 292.1491f, -82.25267f, 1.9973913f, 5.8568f }
};
Position const kargathRespawnPos = { 231.25f, -83.6449f, 5.02341f };
struct boss_warchief_kargath_bladefist : public BossAI
{
boss_warchief_kargath_bladefist(Creature* creature) : BossAI(creature, DATA_KARGATH)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void InitializeAI() override
{
BossAI::InitializeAI();
if (instance)
{
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
{
executioner->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
}
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
if (summon)
{
summon->SetVisible(false);
scheduler.Schedule(20s, [summon](TaskContext /*context*/)
{
if (summon)
{
summon->Respawn(true);
summon->SetVisible(true);
}
});
}
}
void RespawnAssassins()
{
for (Position const& summonPos : assassinsPos)
me->SummonCreature(NPC_SHATTERED_ASSASSIN, summonPos);
}
void Reset() override
{
BossAI::Reset();
if (Creature* warchiefPortal = instance->GetCreature(DATA_WARCHIEF_PORTAL))
warchiefPortal->AI()->SetData(DATA_RESET_FIGHT, 0);
_danceCount = 0;
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
if (instance)
{
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
{
executioner->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
}
}
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
if (Creature* warchiefPortal = instance->GetCreature(DATA_WARCHIEF_PORTAL))
warchiefPortal->AI()->SetData(DATA_START_FIGHT, 0);
RespawnAssassins();
scheduler
.Schedule(30s, [this](TaskContext context)
{
me->SetReactState(REACT_PASSIVE);
_danceCount = 0;
DoCastAOE(SPELL_BLADE_DANCE_TARGETING);
context.Repeat(32850ms, 41350ms);
});
}
void KilledUnit(Unit* victim) override
{
if (victim && victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void MovementInform(uint32 type, uint32 /*id*/) override
{
if (type != POINT_MOTION_TYPE)
return;
if (_danceCount < 8)
{
_danceCount++;
scheduler.Schedule(100ms, [this](TaskContext /*context*/)
{
DoCastAOE(SPELL_BLADE_DANCE_TARGETING);
});
}
else
me->SetReactState(REACT_AGGRESSIVE);
}
bool IsInRoom()
{
if (me->GetExactDist2d(kargathRespawnPos) >= 42.f)
return false;
return true;
}
void UpdateAI(uint32 diff) override
{
if (!IsInRoom())
{
Talk(SAY_EVADE);
EnterEvadeMode();
return;
}
if (!UpdateVictim())
return;
scheduler.Update(diff, [this]
{
DoMeleeAttackIfReady();
});
}
protected:
uint8 _danceCount;
};
struct npc_warchief_portal : public ScriptedAI
{
public:
boss_warchief_kargath_bladefist() : CreatureScript("boss_warchief_kargath_bladefist") { }
npc_warchief_portal(Creature* creature) : ScriptedAI(creature) { }
struct boss_warchief_kargath_bladefistAI : public BossAI
void UpdateAI(uint32 diff) override
{
boss_warchief_kargath_bladefistAI(Creature* creature) : BossAI(creature, DATA_KARGATH) { }
_scheduler.Update(diff);
}
void InitializeAI() override
void JustSummoned(Creature* creature) override
{
InstanceScript* instance = me->GetInstanceScript();
if (!instance)
return;
if (Creature* kargath = instance->GetCreature(DATA_KARGATH))
kargath->AI()->JustSummoned(creature);
}
void SetData(uint32 type, uint32 /*data*/) override
{
if (type == DATA_START_FIGHT)
{
BossAI::InitializeAI();
if (instance)
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
executioner->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
_scheduler.Schedule(20600ms, [this](TaskContext context)
{
DoCastSelf(summonSpells[context.GetRepeatCounter() % 3]);
context.Repeat();
});
}
void JustDied(Unit* /*killer*/) override
if (type == DATA_RESET_FIGHT)
{
Talk(SAY_DEATH);
_JustDied();
if (instance)
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
executioner->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
_scheduler.CancelAll();
}
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
protected:
TaskScheduler _scheduler;
};
events.ScheduleEvent(EVENT_CHECK_ROOM, 5000);
events.ScheduleEvent(EVENT_SUMMON_ADDS, 30000);
events.ScheduleEvent(EVENT_SUMMON_ASSASSINS, 5000);
events.ScheduleEvent(EVENT_BLADE_DANCE, 30000);
events.ScheduleEvent(EVENT_SPELL_CHARGE, 0);
}
class spell_blade_dance_targeting : public SpellScript
{
PrepareSpellScript(spell_blade_dance_targeting);
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() != NPC_SHATTERED_ASSASSIN)
summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0));
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BLADE_DANCE_CHARGE, SPELL_BLADE_DANCE_DMG });
}
summons.Summon(summon);
}
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
if (!caster)
return;
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE || id != 1)
return;
me->CastSpell(me, SPELL_BLADE_DANCE, true);
events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
targets.remove_if([&](WorldObject* target) -> bool
{
case EVENT_CHECK_ROOM:
if (me->GetPositionX() > 255 || me->GetPositionX() < 205)
{
EnterEvadeMode();
return;
}
events.ScheduleEvent(EVENT_CHECK_ROOM, 5000);
break;
case EVENT_SUMMON_ASSASSINS:
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] + 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] - 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] + 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] - 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
break;
case EVENT_SUMMON_ADDS:
for (uint8 i = 0; i < 2; ++i)
me->SummonCreature(NPC_HEARTHEN_GUARD + urand(0, 2), AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
float dist = caster->GetDistance2d(target);
// Do not target dummies that are too close or too far away
if (dist < 5.f || dist > 16.f)
return true;
// Do not target anything that is not a target dummy
if (target->GetEntry() != NPC_BLADE_DANCE_TARGET)
return true;
events.ScheduleEvent(EVENT_SUMMON_ADDS, 30000);
break;
case EVENT_BLADE_DANCE:
events.DelayEvents(10001);
events.ScheduleEvent(EVENT_BLADE_DANCE, 40000);
events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0);
events.ScheduleEvent(EVENT_FINISH_BLADE_DANCE, 10000);
events.SetPhase(1);
me->CastSpell(me, SPELL_SPRINT, true);
break;
case EVENT_MOVE_TO_NEXT_POINT:
{
float x = 210 + frand(0.0f, 35.0f);
float y = -65.0f - frand(0.0f, 35.0f);
me->GetMotionMaster()->MovePoint(1, x, y, me->GetPositionZ());
break;
}
case EVENT_FINISH_BLADE_DANCE:
events.SetPhase(0);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveChase(me->GetVictim());
if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_CHARGE, 3000);
break;
case EVENT_SPELL_CHARGE:
me->CastSpell(me->GetVictim(), SPELL_CHARGE, false);
break;
}
return false;
});
if (!events.IsInPhase(1))
DoMeleeAttackIfReady();
std::list<WorldObject*> targets2 = targets;
targets.remove_if([&](WorldObject* target) -> bool
{
if (target->SelectNearestPlayer(15.f))
return false;
return true;
});
Acore::Containers::RandomResize(targets2, 1);
if (urand(0, 2))
{
if (targets.empty())
targets = targets2;
else
Acore::Containers::RandomResize(targets, 1);
}
};
else
targets = targets2;
}
CreatureAI* GetAI(Creature* creature) const override
void HandleOnHit()
{
return GetShatteredHallsAI<boss_warchief_kargath_bladefistAI>(creature);
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
return;
caster->CastSpell(target, SPELL_BLADE_DANCE_CHARGE, true);
caster->CastSpell(target, SPELL_BLADE_DANCE_DMG, true);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_blade_dance_targeting::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
OnHit += SpellHitFn(spell_blade_dance_targeting::HandleOnHit);
}
};
void AddSC_boss_warchief_kargath_bladefist()
{
new boss_warchief_kargath_bladefist();
RegisterShatteredHallsCreatureAI(boss_warchief_kargath_bladefist);
RegisterShatteredHallsCreatureAI(npc_warchief_portal);
RegisterSpellScript(spell_blade_dance_targeting);
}

View File

@@ -20,6 +20,23 @@
#include "ScriptMgr.h"
#include "shattered_halls.h"
ObjectData const creatureData[] =
{
{ NPC_GRAND_WARLOCK_NETHEKURSE , DATA_NETHEKURSE },
{ NPC_WARCHIEF_KARGATH , DATA_KARGATH },
{ NPC_OMROGG_LEFT_HEAD , DATA_OMROGG_LEFT_HEAD },
{ NPC_OMROGG_RIGHT_HEAD , DATA_OMROGG_RIGHT_HEAD },
{ NPC_WARCHIEF_PORTAL , DATA_WARCHIEF_PORTAL },
{ 0 , 0 }
};
DoorData const doorData[] =
{
{ GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE },
{ GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
};
class instance_shattered_halls : public InstanceMapScript
{
public:
@@ -37,6 +54,8 @@ public:
void Initialize() override
{
SetBossNumber(ENCOUNTER_COUNT);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
TeamIdInInstance = TEAM_NEUTRAL;
RescueTimer = 100 * MINUTE * IN_MILLISECONDS;
@@ -48,23 +67,6 @@ public:
TeamIdInInstance = player->GetTeamId();
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
nethekurseDoor1GUID = go->GetGUID();
if (GetBossState(DATA_NETHEKURSE) == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
nethekurseDoor2GUID = go->GetGUID();
if (GetBossState(DATA_NETHEKURSE) == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
}
}
void OnCreatureCreate(Creature* creature) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
@@ -77,9 +79,6 @@ public:
switch (creature->GetEntry())
{
case NPC_WARCHIEF_KARGATH:
warchiefKargathGUID = creature->GetGUID();
break;
case NPC_SHATTERED_EXECUTIONER:
if (RescueTimer > 25 * MINUTE * IN_MILLISECONDS)
creature->AddLootMode(2);
@@ -101,29 +100,7 @@ public:
prisonerGUID[2] = creature->GetGUID();
break;
}
}
bool SetBossState(uint32 type, EncounterState state) override
{
if (!InstanceScript::SetBossState(type, state))
return false;
switch (type)
{
case DATA_NETHEKURSE:
if (state == IN_PROGRESS)
{
HandleGameObject(nethekurseDoor1GUID, false);
HandleGameObject(nethekurseDoor2GUID, false);
}
else
{
HandleGameObject(nethekurseDoor1GUID, true);
HandleGameObject(nethekurseDoor2GUID, true);
}
break;
}
return true;
InstanceScript::OnCreatureCreate(creature);
}
void SetData(uint32 type, uint32 data) override
@@ -133,7 +110,7 @@ public:
DoCastSpellOnPlayers(SPELL_KARGATHS_EXECUTIONER_1);
instance->LoadGrid(230, -80);
if (Creature* kargath = instance->GetCreature(warchiefKargathGUID))
if (Creature* kargath = GetCreature(DATA_KARGATH))
sCreatureTextMgr->SendChat(kargath, TeamIdInInstance == TEAM_ALLIANCE ? 3 : 4, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP);
RescueTimer = 80 * MINUTE * IN_MILLISECONDS;
@@ -197,10 +174,6 @@ public:
}
protected:
ObjectGuid warchiefKargathGUID;
ObjectGuid nethekurseDoor1GUID;
ObjectGuid nethekurseDoor2GUID;
ObjectGuid executionerGUID;
ObjectGuid prisonerGUID[3];
uint32 RescueTimer;

View File

@@ -35,14 +35,23 @@ enum DataTypes
DATA_PRISONER_1 = 11,
DATA_PRISONER_2 = 12,
DATA_PRISONER_3 = 13,
DATA_EXECUTIONER = 14
DATA_EXECUTIONER = 14,
DATA_OMROGG_LEFT_HEAD = 15,
DATA_OMROGG_RIGHT_HEAD = 16,
DATA_WARCHIEF_PORTAL = 17
};
enum CreatureIds
{
NPC_GRAND_WARLOCK_NETHEKURSE = 16807,
NPC_WARCHIEF_KARGATH = 16808,
NPC_FEL_ORC_CONVERT = 17083,
// Warchief Kargath
NPC_WARCHIEF_KARGATH = 16808,
NPC_WARCHIEF_PORTAL = 17611,
// O'MROGG
NPC_OMROGG_LEFT_HEAD = 19523,
NPC_OMROGG_RIGHT_HEAD = 19524,
// Trial of the Naaru: Mercy
NPC_SHATTERED_EXECUTIONER = 17301,
@@ -73,4 +82,6 @@ inline AI* GetShatteredHallsAI(T* obj)
return GetInstanceAI<AI>(obj, ShatteredHallsLairScriptName);
}
#define RegisterShatteredHallsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetShatteredHallsAI)
#endif

View File

@@ -46,11 +46,6 @@ enum Yells
SAY_DEATH = 4
};
enum Creatures
{
NPC_NETHER_CHARGE = 20405
};
struct boss_mechano_lord_capacitus : public BossAI
{
boss_mechano_lord_capacitus(Creature* creature) : BossAI(creature, DATA_MECHANOLORD_CAPACITUS)
@@ -127,7 +122,6 @@ struct boss_mechano_lord_capacitus : public BossAI
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->GetMotionMaster()->MoveRandom(30.0f);
}
};

View File

@@ -21,9 +21,11 @@ void AddSC_instance_auchenai_crypts();
void AddSC_boss_shirrak_the_dead_watcher();
void AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs
void AddSC_boss_pandemonius();
void AddSC_boss_tavarok();
void AddSC_instance_mana_tombs();
void AddSC_boss_talon_king_ikiss(); //Auchindoun Sekketh Halls
void AddSC_boss_anzu();
void AddSC_boss_darkweaver_syth();
void AddSC_instance_sethekk_halls();
void AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth
void AddSC_boss_ambassador_hellmaw();
@@ -54,10 +56,14 @@ void AddSC_instance_steam_vault();
void AddSC_underbog(); //CR Underbog
void AddSC_boss_hungarfen();
void AddSC_boss_ghazan();
void AddSC_boss_swamplord_muselek();
void AddSC_boss_the_black_stalker();
void AddSC_instance_the_underbog();
void AddSC_the_slave_pens(); // The Slave Pens
void AddSC_boss_ahune();
void AddSC_boss_mennu_the_betrayer();
void AddSC_boss_rokmar_the_crackler();
void AddSC_boss_quagmirran();
void AddSC_instance_the_slave_pens();
void AddSC_boss_gruul(); //Gruul's Lair
void AddSC_boss_high_king_maulgar();
@@ -119,9 +125,11 @@ void AddOutlandScripts()
AddSC_boss_shirrak_the_dead_watcher();
AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs
AddSC_boss_pandemonius();
AddSC_boss_tavarok();
AddSC_instance_mana_tombs();
AddSC_boss_talon_king_ikiss(); //Auchindoun Sekketh Halls
AddSC_boss_anzu();
AddSC_boss_darkweaver_syth();
AddSC_instance_sethekk_halls();
AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth
AddSC_boss_ambassador_hellmaw();
@@ -152,10 +160,14 @@ void AddOutlandScripts()
AddSC_underbog(); //CR Underbog
AddSC_boss_hungarfen();
AddSC_boss_ghazan();
AddSC_boss_swamplord_muselek();
AddSC_boss_the_black_stalker();
AddSC_instance_the_underbog();
AddSC_the_slave_pens(); // The Slave Pens
AddSC_the_slave_pens(); //CR The Slave Pens
AddSC_boss_ahune();
AddSC_boss_mennu_the_betrayer();
AddSC_boss_rokmar_the_crackler();
AddSC_boss_quagmirran();
AddSC_instance_the_slave_pens();
AddSC_boss_gruul(); //Gruul's Lair
AddSC_boss_high_king_maulgar();
@@ -207,4 +219,4 @@ void AddOutlandScripts()
AddSC_shattrath_city();
AddSC_terokkar_forest();
//AddSC_zangarmarsh();
}
}

View File

@@ -15,21 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Shattrath_City
SD%Complete: 100
SDComment: Quest support: 10004, 10009, 10211. Flask vendors, Teleport to Caverns of Time
SDCategory: Shattrath City
EndScriptData */
/* ContentData
npc_raliq_the_drunk
npc_salsalabim
npc_shattrathflaskvendors
npc_zephyr
npc_kservant
EndContentData */
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
@@ -37,176 +22,6 @@ EndContentData */
#include "ScriptedGossip.h"
#include "TaskScheduler.h"
/*######
## npc_raliq_the_drunk
######*/
#define GOSSIP_RALIQ "You owe Sim'salabim money. Hand them over or die!"
enum Raliq
{
SPELL_UPPERCUT = 10966,
QUEST_CRACK_SKULLS = 10009,
EMOTE_DRINK = 7,
};
class npc_raliq_the_drunk : public CreatureScript
{
public:
npc_raliq_the_drunk() : CreatureScript("npc_raliq_the_drunk") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
CloseGossipMenuFor(player);
creature->SetFaction(FACTION_OGRE);
creature->AI()->AttackStart(player);
}
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE)
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_RALIQ, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, 9440, creature->GetGUID());
return true;
}
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_raliq_the_drunkAI(creature);
}
struct npc_raliq_the_drunkAI : public ScriptedAI
{
npc_raliq_the_drunkAI(Creature* creature) : ScriptedAI(creature)
{
m_uiNormFaction = creature->GetFaction();
}
uint32 m_uiNormFaction;
void Reset() override
{
me->RestoreFaction();
_scheduler.CancelAll();
_scheduler.Schedule(5s, [this](TaskContext context)
{
me->HandleEmoteCommand(EMOTE_DRINK);
context.Repeat(5s);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler
.Schedule(5s, [this](TaskContext context)
{
DoCastVictim(SPELL_UPPERCUT);
context.Repeat(15s);
});
};
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
};
};
/*######
# npc_salsalabim
######*/
enum Salsalabim
{
// Quests
QUEST_10004 = 10004,
// Spells
SPELL_MAGNETIC_PULL = 31705
};
class npc_salsalabim : public CreatureScript
{
public:
npc_salsalabim() : CreatureScript("npc_salsalabim") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetQuestStatus(QUEST_10004) == QUEST_STATUS_INCOMPLETE)
{
creature->SetFaction(FACTION_DEMON);
creature->AI()->AttackStart(player);
}
else
{
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
}
return true;
}
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_salsalabimAI(creature);
}
struct npc_salsalabimAI : public ScriptedAI
{
npc_salsalabimAI(Creature* creature) : ScriptedAI(creature) { }
uint32 MagneticPull_Timer;
void Reset() override
{
MagneticPull_Timer = 15000;
me->RestoreFaction();
}
void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
// xinef: some corrections
if (done_by)
if (Player* player = done_by->GetCharmerOrOwnerPlayerOrPlayerItself())
if (me->HealthBelowPctDamaged(20, damage))
{
player->GroupEventHappens(QUEST_10004, me);
damage = 0;
EnterEvadeMode();
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (MagneticPull_Timer <= diff)
{
DoCastVictim(SPELL_MAGNETIC_PULL);
MagneticPull_Timer = 15000;
}
else MagneticPull_Timer -= diff;
DoMeleeAttackIfReady();
}
};
};
/*
##################################################
Shattrath City Flask Vendors provides flasks to people exalted with 3 fActions:
@@ -436,8 +251,6 @@ public:
void AddSC_shattrath_city()
{
new npc_raliq_the_drunk();
new npc_salsalabim();
new npc_shattrathflaskvendors();
new npc_zephyr();
new npc_kservant();

View File

@@ -15,22 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Terokkar_Forest
SD%Complete: 85
SDComment: Quest support: 9889, 10009, 10873, 10896, 10898, 11096, 10052, 10051. Skettis->Ogri'la Flight
SDCategory: Terokkar Forest
EndScriptData */
/* ContentData
npc_unkor_the_ruthless
npc_rotting_forest_rager
npc_netherweb_victim
npc_floon
npc_isla_starmane
npc_slim
EndContentData */
#include "Group.h"
#include "Player.h"
#include "ScriptMgr.h"
@@ -477,115 +461,6 @@ public:
};
};
/*######
## npc_floon
######*/
#define GOSSIP_FLOON1 "You owe Sim'salabim money. Hand them over or die!"
#define GOSSIP_FLOON2 "Hand over the money or die...again!"
enum Floon
{
SAY_FLOON_ATTACK = 0,
SPELL_SILENCE = 6726,
SPELL_FROSTBOLT = 9672,
SPELL_FROST_NOVA = 11831,
QUEST_CRACK_SKULLS = 10009
};
class npc_floon : public CreatureScript
{
public:
npc_floon() : CreatureScript("npc_floon") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF)
{
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_FLOON2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, 9443, creature->GetGUID());
}
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
CloseGossipMenuFor(player);
creature->SetFaction(FACTION_ARAKKOA);
creature->AI()->Talk(SAY_FLOON_ATTACK, player);
creature->AI()->AttackStart(player);
}
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE)
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_FLOON1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
SendGossipMenuFor(player, 9442, creature->GetGUID());
return true;
}
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_floonAI(creature);
}
struct npc_floonAI : public ScriptedAI
{
npc_floonAI(Creature* creature) : ScriptedAI(creature)
{
m_uiNormFaction = creature->GetFaction();
}
uint32 m_uiNormFaction;
uint32 Silence_Timer;
uint32 Frostbolt_Timer;
uint32 FrostNova_Timer;
void Reset() override
{
Silence_Timer = 2000;
Frostbolt_Timer = 4000;
FrostNova_Timer = 9000;
if (me->GetFaction() != m_uiNormFaction)
me->SetFaction(m_uiNormFaction);
}
void JustEngagedWith(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (Silence_Timer <= diff)
{
DoCastVictim(SPELL_SILENCE);
Silence_Timer = 30000;
}
else Silence_Timer -= diff;
if (FrostNova_Timer <= diff)
{
DoCast(me, SPELL_FROST_NOVA);
FrostNova_Timer = 20000;
}
else FrostNova_Timer -= diff;
if (Frostbolt_Timer <= diff)
{
DoCastVictim(SPELL_FROSTBOLT);
Frostbolt_Timer = 5000;
}
else Frostbolt_Timer -= diff;
DoMeleeAttackIfReady();
}
};
};
/*######
## npc_isla_starmane
######*/
@@ -840,7 +715,6 @@ void AddSC_terokkar_forest()
// Theirs
new npc_unkor_the_ruthless();
new npc_rotting_forest_rager();
new npc_floon();
new npc_isla_starmane();
new go_skull_pile();
new npc_slim();

View File

@@ -96,24 +96,17 @@ struct npc_pet_hunter_snake_trap : public ScriptedAI
{
_init = true;
CreatureTemplate const* Info = me->GetCreatureTemplate();
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(me->GetLevel(), Info->unit_class);
uint32 health = uint32(107 * (me->GetLevel() - 40) * 0.025f);
me->SetCreateHealth(health);
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
{
me->SetStat(Stats(stat), 0);
me->SetCreateStat(Stats(stat), 0);
}
me->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
me->SetMaxHealth(health);
//Add delta to make them not all hit the same time
uint32 delta = urand(0, 700);
me->SetAttackTime(BASE_ATTACK, Info->BaseAttackTime + delta);
me->SetStatFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER, float(stats->AttackPower));
me->CastSpell(me, SPELL_HUNTER_DEADLY_POISON_PASSIVE, true);
me->SetAttackTime(BASE_ATTACK, me->GetAttackTime(BASE_ATTACK) + delta);
if (me->GetEntry() == NPC_VENOMOUS_SNAKE)
DoCastSelf(SPELL_HUNTER_DEADLY_POISON_PASSIVE, true);
// Glyph of Snake Trap
if (Unit* owner = me->GetOwner())