* chore(Apps/Codestyle): add new codestyle checks for pointers and range loops * revert a typo
1100 lines
41 KiB
C++
1100 lines
41 KiB
C++
/*
|
|
* 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 "AreaTriggerScript.h"
|
|
#include "Cell.h"
|
|
#include "CellImpl.h"
|
|
#include "CreatureScript.h"
|
|
#include "GameObjectScript.h"
|
|
#include "GridNotifiers.h"
|
|
#include "InstanceMapScript.h"
|
|
#include "InstanceScript.h"
|
|
#include "ObjectMgr.h"
|
|
#include "ScriptedCreature.h"
|
|
#include "SpellScript.h"
|
|
#include "SpellScriptLoader.h"
|
|
#include "blackrock_spire.h"
|
|
|
|
uint32 const DragonspireMobs[3] = { NPC_BLACKHAND_DREADWEAVER, NPC_BLACKHAND_SUMMONER, NPC_BLACKHAND_VETERAN };
|
|
|
|
enum EventIds
|
|
{
|
|
EVENT_DRAGONSPIRE_ROOM_STORE = 1,
|
|
EVENT_DRAGONSPIRE_ROOM_CHECK = 2,
|
|
|
|
EVENT_SOLAKAR_WAVE = 3
|
|
};
|
|
|
|
enum Timers
|
|
{
|
|
TIMER_SOLAKAR_WAVE = 30000
|
|
};
|
|
|
|
enum SolakarWaves
|
|
{
|
|
MAX_WAVE_COUNT = 5
|
|
};
|
|
|
|
Position SolakarPosLeft = Position(78.0f, -280.0f, 93.0f, 3.0f * M_PI / 2.0);
|
|
Position SolakarPosRight = Position(84.0f, -280.0f, 93.0f, 3.0f * M_PI / 2.0);
|
|
Position SolakarPosBoss = Position(80.0f, -280.0f, 93.0f, 3.0f * M_PI / 2.0);
|
|
|
|
enum Texts
|
|
{
|
|
SAY_NEFARIUS_REND_WIPE = 11,
|
|
SAY_SOLAKAR_FIRST_HATCHER = 0,
|
|
SAY_SCARSHIELD_INF_WHISPER = 0
|
|
};
|
|
|
|
MinionData const minionData[] =
|
|
{
|
|
{ NPC_CHROMATIC_ELITE_GUARD, DATA_GENERAL_DRAKKISATH }
|
|
};
|
|
|
|
DoorData const doorData[] =
|
|
{
|
|
{ GO_GYTH_EXIT_DOOR, DATA_WARCHIEF_REND_BLACKHAND, DOOR_TYPE_PASSAGE },
|
|
{ GO_DRAKKISATH_DOOR_1, DATA_GENERAL_DRAKKISATH, DOOR_TYPE_PASSAGE },
|
|
{ GO_DRAKKISATH_DOOR_2, DATA_GENERAL_DRAKKISATH, DOOR_TYPE_PASSAGE },
|
|
{ 0, 0, DOOR_TYPE_ROOM, } // END
|
|
};
|
|
|
|
class instance_blackrock_spire : public InstanceMapScript
|
|
{
|
|
public:
|
|
instance_blackrock_spire() : InstanceMapScript(BRSScriptName, 229) { }
|
|
|
|
struct instance_blackrock_spireMapScript : public InstanceScript
|
|
{
|
|
uint32 CurrentSolakarWave = 0;
|
|
uint32 SolakarState = NOT_STARTED; // there should be a global instance encounter state, where is it?
|
|
GuidVector SolakarSummons;
|
|
uint32 VaelastraszState = NOT_STARTED;
|
|
|
|
instance_blackrock_spireMapScript(InstanceMap* map) : InstanceScript(map)
|
|
{
|
|
SetHeaders(DataHeader);
|
|
SetBossNumber(EncounterCount);
|
|
LoadMinionData(minionData);
|
|
LoadDoorData(doorData);
|
|
CurrentSolakarWave = 0;
|
|
SolakarState = NOT_STARTED;
|
|
SolakarSummons.clear();
|
|
VaelastraszState = NOT_STARTED;
|
|
}
|
|
|
|
void CreatureLooted(Creature* creature, LootType loot) override
|
|
{
|
|
switch (creature->GetEntry())
|
|
{
|
|
case NPC_THE_BEAST:
|
|
if (loot == LOOT_SKINNING)
|
|
{
|
|
creature->CastSpell(creature, SPELL_FINKLE_IS_EINHORN, true);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OnCreatureCreate(Creature* creature) override
|
|
{
|
|
switch (creature->GetEntry())
|
|
{
|
|
case NPC_UROK_MAGUS:
|
|
[[fallthrough]];
|
|
case NPC_UROK_ENFORCER:
|
|
UrokMobs.push_back(creature->GetGUID());
|
|
break;
|
|
case NPC_HIGHLORD_OMOKK:
|
|
HighlordOmokk = creature->GetGUID();
|
|
break;
|
|
case NPC_SHADOW_HUNTER_VOSHGAJIN:
|
|
ShadowHunterVoshgajin = creature->GetGUID();
|
|
break;
|
|
case NPC_WARMASTER_VOONE:
|
|
WarMasterVoone = creature->GetGUID();
|
|
break;
|
|
case NPC_MOTHER_SMOLDERWEB:
|
|
MotherSmolderweb = creature->GetGUID();
|
|
break;
|
|
case NPC_UROK_DOOMHOWL:
|
|
UrokDoomhowl = creature->GetGUID();
|
|
break;
|
|
case NPC_QUARTERMASTER_ZIGRIS:
|
|
QuartermasterZigris = creature->GetGUID();
|
|
break;
|
|
case NPC_GIZRUL_THE_SLAVENER:
|
|
GizrultheSlavener = creature->GetGUID();
|
|
break;
|
|
case NPC_HALYCON:
|
|
Halycon = creature->GetGUID();
|
|
break;
|
|
case NPC_OVERLORD_WYRMTHALAK:
|
|
OverlordWyrmthalak = creature->GetGUID();
|
|
break;
|
|
case NPC_PYROGAURD_EMBERSEER:
|
|
PyroguardEmberseer = creature->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
creature->DisappearAndDie();
|
|
break;
|
|
case NPC_WARCHIEF_REND_BLACKHAND:
|
|
if (GetBossState(DATA_GYTH) != IN_PROGRESS)
|
|
{
|
|
WarchiefRendBlackhand = creature->GetGUID();
|
|
}
|
|
|
|
if (GetBossState(DATA_GYTH) == DONE)
|
|
creature->DisappearAndDie();
|
|
break;
|
|
case NPC_GYTH:
|
|
Gyth = creature->GetGUID();
|
|
break;
|
|
case NPC_THE_BEAST:
|
|
TheBeast = creature->GetGUID();
|
|
break;
|
|
case NPC_GENERAL_DRAKKISATH:
|
|
GeneralDrakkisath = creature->GetGUID();
|
|
break;
|
|
case NPC_LORD_VICTOR_NEFARIUS:
|
|
LordVictorNefarius = creature->GetGUID();
|
|
if (GetBossState(DATA_GYTH) == DONE)
|
|
creature->DisappearAndDie();
|
|
break;
|
|
case NPC_FINKLE_EINHORN:
|
|
creature->AI()->Talk(SAY_FINKLE_GANG);
|
|
break;
|
|
case NPC_CHROMATIC_ELITE_GUARD:
|
|
AddMinion(creature);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OnGameObjectCreate(GameObject* go) override
|
|
{
|
|
switch (go->GetEntry())
|
|
{
|
|
case GO_EMBERSEER_IN:
|
|
go_emberseerin = go->GetGUID();
|
|
HandleGameObject(ObjectGuid::Empty, GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE, go);
|
|
break;
|
|
case GO_DOORS:
|
|
go_doors = go->GetGUID();
|
|
if (GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, true, go);
|
|
break;
|
|
case GO_EMBERSEER_OUT:
|
|
go_emberseerout = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, true, go);
|
|
break;
|
|
case GO_HALL_RUNE_1:
|
|
go_roomrunes[0] = go->GetGUID();
|
|
if (GetBossState(DATA_HALL_RUNE_1) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_HALL_RUNE_2:
|
|
go_roomrunes[1] = go->GetGUID();
|
|
if (GetBossState(DATA_HALL_RUNE_2) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_HALL_RUNE_3:
|
|
go_roomrunes[2] = go->GetGUID();
|
|
if (GetBossState(DATA_HALL_RUNE_3) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_HALL_RUNE_4:
|
|
go_roomrunes[3] = go->GetGUID();
|
|
if (GetBossState(DATA_HALL_RUNE_4) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_HALL_RUNE_5:
|
|
go_roomrunes[4] = go->GetGUID();
|
|
if (GetBossState(DATA_HALL_RUNE_5) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_HALL_RUNE_6:
|
|
go_roomrunes[5] = go->GetGUID();
|
|
if (GetBossState(DATA_HALL_RUNE_6) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_HALL_RUNE_7:
|
|
go_roomrunes[6] = go->GetGUID();
|
|
if (GetBossState(DATA_HALL_RUNE_7) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_EMBERSEER_RUNE_1:
|
|
go_emberseerrunes[0] = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_EMBERSEER_RUNE_2:
|
|
go_emberseerrunes[1] = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_EMBERSEER_RUNE_3:
|
|
go_emberseerrunes[2] = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_EMBERSEER_RUNE_4:
|
|
go_emberseerrunes[3] = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_EMBERSEER_RUNE_5:
|
|
go_emberseerrunes[4] = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_EMBERSEER_RUNE_6:
|
|
go_emberseerrunes[5] = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_EMBERSEER_RUNE_7:
|
|
go_emberseerrunes[6] = go->GetGUID();
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, false, go);
|
|
break;
|
|
case GO_PORTCULLIS_ACTIVE:
|
|
go_portcullis_active = go->GetGUID();
|
|
if (GetBossState(DATA_GYTH) == DONE)
|
|
HandleGameObject(ObjectGuid::Empty, true, go);
|
|
break;
|
|
case GO_UROK_PILE:
|
|
go_urokPile = go->GetGUID();
|
|
break;
|
|
case GO_UROK_CIRCLE:
|
|
go_urokOgreCirles.push_back(go->GetGUID());
|
|
break;
|
|
case GO_UROK_CHALLENGE:
|
|
go_urokChallenge = go->GetGUID();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
InstanceScript::OnGameObjectCreate(go);
|
|
}
|
|
|
|
bool SetBossState(uint32 type, EncounterState state) override
|
|
{
|
|
if (!InstanceScript::SetBossState(type, state))
|
|
return false;
|
|
|
|
switch (type)
|
|
{
|
|
case DATA_WARCHIEF_REND_BLACKHAND:
|
|
if (state == FAIL)
|
|
{
|
|
if (Creature* rend = instance->GetCreature(WarchiefRendBlackhand))
|
|
{
|
|
rend->Respawn(true);
|
|
}
|
|
|
|
if (Creature* nefarius = instance->GetCreature(LordVictorNefarius))
|
|
{
|
|
nefarius->AI()->Talk(SAY_NEFARIUS_REND_WIPE);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_PYROGUARD_EMBERSEER:
|
|
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == NOT_STARTED)
|
|
{
|
|
if (Creature* Emberseer = instance->GetCreature(PyroguardEmberseer))
|
|
Emberseer->AI()->SetData(1, 1);
|
|
}
|
|
break;
|
|
case EVENT_UROK_DOOMHOWL:
|
|
if (GetBossState(DATA_UROK_DOOMHOWL) == NOT_STARTED)
|
|
{
|
|
SetBossState(DATA_UROK_DOOMHOWL, IN_PROGRESS);
|
|
if (GameObject* pile = instance->GetGameObject(go_urokPile))
|
|
{
|
|
pile->SetLootState(GO_JUST_DEACTIVATED);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SetData(uint32 type, uint32 data) override
|
|
{
|
|
switch (type)
|
|
{
|
|
case AREATRIGGER:
|
|
if (data == AREATRIGGER_DRAGONSPIRE_HALL)
|
|
{
|
|
if (GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE)
|
|
Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_STORE, 1s);
|
|
}
|
|
break;
|
|
case DATA_SOLAKAR_FLAMEWREATH:
|
|
switch(data)
|
|
{
|
|
case IN_PROGRESS:
|
|
if (SolakarState == NOT_STARTED)
|
|
{
|
|
Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, 500ms);
|
|
}
|
|
break;
|
|
case FAIL:
|
|
for (ObjectGuid const& guid : SolakarSummons)
|
|
{
|
|
if (Creature* creature = instance->GetCreature(guid))
|
|
{
|
|
creature->DespawnOrUnsummon();
|
|
}
|
|
}
|
|
SolakarSummons.clear();
|
|
CurrentSolakarWave = 0;
|
|
SetData(DATA_SOLAKAR_FLAMEWREATH, NOT_STARTED);
|
|
break;
|
|
case DONE:
|
|
break;
|
|
}
|
|
SolakarState = data;
|
|
break;
|
|
case DATA_VAELASTRASZ:
|
|
VaelastraszState = data;
|
|
break;
|
|
case DATA_UROK_DOOMHOWL:
|
|
if (data == FAIL)
|
|
{
|
|
if (GetBossState(DATA_UROK_DOOMHOWL) != NOT_STARTED)
|
|
{
|
|
SetBossState(DATA_UROK_DOOMHOWL, NOT_STARTED);
|
|
if (GameObject* challenge = instance->GetGameObject(go_urokChallenge))
|
|
{
|
|
challenge->Delete();
|
|
}
|
|
if (GameObject* pile = instance->GetGameObject(go_urokPile))
|
|
{
|
|
pile->SetLootState(GO_READY);
|
|
pile->Respawn();
|
|
}
|
|
for (auto const& circleGUID : go_urokOgreCirles)
|
|
{
|
|
if (GameObject* circle = instance->GetGameObject(circleGUID))
|
|
{
|
|
circle->Delete();
|
|
}
|
|
}
|
|
for (auto const& mobGUID : UrokMobs)
|
|
{
|
|
if (Creature* mob = instance->GetCreature(mobGUID))
|
|
{
|
|
mob->DespawnOrUnsummon();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32 GetData(uint32 type) const override
|
|
{
|
|
if (type == DATA_SOLAKAR_FLAMEWREATH)
|
|
{
|
|
return SolakarState;
|
|
}
|
|
else if (type == DATA_VAELASTRASZ)
|
|
{
|
|
return VaelastraszState;
|
|
}
|
|
else
|
|
{
|
|
return InstanceScript::GetData(type);
|
|
}
|
|
}
|
|
|
|
void SummonSolakarWave(uint8 number)
|
|
{
|
|
if (number < MAX_WAVE_COUNT)
|
|
{
|
|
if (Creature* summon = instance->SummonCreature(NPC_ROOKERY_GUARDIAN, SolakarPosLeft))
|
|
{
|
|
SolakarSummons.push_back(summon->GetGUID());
|
|
}
|
|
|
|
if (Creature* summon = instance->SummonCreature(NPC_ROOKERY_HATCHER, SolakarPosRight))
|
|
{
|
|
SolakarSummons.push_back(summon->GetGUID());
|
|
}
|
|
|
|
if (number == 0)
|
|
{
|
|
if (Creature* FirstHatcher = instance->GetCreature(SolakarSummons.back())) // works because we spawned a hatcher second
|
|
{
|
|
FirstHatcher->AI()->Talk(SAY_SOLAKAR_FIRST_HATCHER);
|
|
}
|
|
}
|
|
}
|
|
else if (number == MAX_WAVE_COUNT)
|
|
{
|
|
if (Creature* summon = instance->SummonCreature(NPC_SOLAKAR, SolakarPosBoss))
|
|
{
|
|
SolakarSummons.push_back(summon->GetGUID());
|
|
}
|
|
}
|
|
}
|
|
|
|
ObjectGuid GetGuidData(uint32 type) const override
|
|
{
|
|
switch (type)
|
|
{
|
|
case DATA_HIGHLORD_OMOKK:
|
|
return HighlordOmokk;
|
|
case DATA_SHADOW_HUNTER_VOSHGAJIN:
|
|
return ShadowHunterVoshgajin;
|
|
case DATA_WARMASTER_VOONE:
|
|
return WarMasterVoone;
|
|
case DATA_MOTHER_SMOLDERWEB:
|
|
return MotherSmolderweb;
|
|
case DATA_UROK_DOOMHOWL:
|
|
return UrokDoomhowl;
|
|
case DATA_QUARTERMASTER_ZIGRIS:
|
|
return QuartermasterZigris;
|
|
case DATA_GIZRUL_THE_SLAVENER:
|
|
return GizrultheSlavener;
|
|
case DATA_HALYCON:
|
|
return Halycon;
|
|
case DATA_OVERLORD_WYRMTHALAK:
|
|
return OverlordWyrmthalak;
|
|
case DATA_PYROGAURD_EMBERSEER:
|
|
return PyroguardEmberseer;
|
|
case DATA_WARCHIEF_REND_BLACKHAND:
|
|
return WarchiefRendBlackhand;
|
|
case DATA_GYTH:
|
|
return Gyth;
|
|
case DATA_THE_BEAST:
|
|
return TheBeast;
|
|
case DATA_GENERAL_DRAKKISATH:
|
|
return GeneralDrakkisath;
|
|
case GO_EMBERSEER_IN:
|
|
return go_emberseerin;
|
|
case GO_DOORS:
|
|
return go_doors;
|
|
case GO_EMBERSEER_OUT:
|
|
return go_emberseerout;
|
|
case GO_HALL_RUNE_1:
|
|
return go_roomrunes[0];
|
|
case GO_HALL_RUNE_2:
|
|
return go_roomrunes[1];
|
|
case GO_HALL_RUNE_3:
|
|
return go_roomrunes[2];
|
|
case GO_HALL_RUNE_4:
|
|
return go_roomrunes[3];
|
|
case GO_HALL_RUNE_5:
|
|
return go_roomrunes[4];
|
|
case GO_HALL_RUNE_6:
|
|
return go_roomrunes[5];
|
|
case GO_HALL_RUNE_7:
|
|
return go_roomrunes[6];
|
|
case GO_EMBERSEER_RUNE_1:
|
|
return go_emberseerrunes[0];
|
|
case GO_EMBERSEER_RUNE_2:
|
|
return go_emberseerrunes[1];
|
|
case GO_EMBERSEER_RUNE_3:
|
|
return go_emberseerrunes[2];
|
|
case GO_EMBERSEER_RUNE_4:
|
|
return go_emberseerrunes[3];
|
|
case GO_EMBERSEER_RUNE_5:
|
|
return go_emberseerrunes[4];
|
|
case GO_EMBERSEER_RUNE_6:
|
|
return go_emberseerrunes[5];
|
|
case GO_EMBERSEER_RUNE_7:
|
|
return go_emberseerrunes[6];
|
|
case GO_PORTCULLIS_ACTIVE:
|
|
return go_portcullis_active;
|
|
case GO_UROK_PILE:
|
|
return go_urokPile;
|
|
case GO_UROK_CHALLENGE:
|
|
return go_urokChallenge;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ObjectGuid::Empty;
|
|
}
|
|
|
|
void Update(uint32 diff) override
|
|
{
|
|
Events.Update(diff);
|
|
|
|
while (uint32 eventId = Events.ExecuteEvent())
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_DRAGONSPIRE_ROOM_STORE:
|
|
Dragonspireroomstore();
|
|
Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s);
|
|
break;
|
|
case EVENT_DRAGONSPIRE_ROOM_CHECK:
|
|
Dragonspireroomcheck();
|
|
if ((GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE))
|
|
Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s);
|
|
break;
|
|
case EVENT_SOLAKAR_WAVE:
|
|
SummonSolakarWave(CurrentSolakarWave);
|
|
if (CurrentSolakarWave < MAX_WAVE_COUNT)
|
|
{
|
|
Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, TIMER_SOLAKAR_WAVE);
|
|
CurrentSolakarWave++;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Dragonspireroomstore()
|
|
{
|
|
|
|
for (uint8 i = 0; i < 7; ++i)
|
|
{
|
|
// Refresh the creature list
|
|
runecreaturelist[i].clear();
|
|
|
|
if (GameObject* rune = instance->GetGameObject(go_roomrunes[i]))
|
|
{
|
|
for (uint8 j = 0; j < 3; ++j)
|
|
{
|
|
std::list<Creature*> creatureList;
|
|
GetCreatureListWithEntryInGrid(creatureList, rune, DragonspireMobs[j], 15.0f);
|
|
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
|
|
{
|
|
if (Creature* creature = *itr)
|
|
{
|
|
runecreaturelist[i].push_back(creature->GetGUID());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Dragonspireroomcheck()
|
|
{
|
|
Creature* mob = nullptr;
|
|
GameObject* rune = nullptr;
|
|
|
|
for (uint8 i = 0; i < 7; ++i)
|
|
{
|
|
bool _mobAlive = false;
|
|
rune = instance->GetGameObject(go_roomrunes[i]);
|
|
if (!rune)
|
|
continue;
|
|
|
|
if (rune->GetGoState() == GO_STATE_ACTIVE)
|
|
{
|
|
for (ObjectGuid const& guid : runecreaturelist[i])
|
|
{
|
|
mob = instance->GetCreature(guid);
|
|
if (mob && mob->IsAlive())
|
|
_mobAlive = true;
|
|
}
|
|
}
|
|
|
|
if (!_mobAlive && rune->GetGoState() == GO_STATE_ACTIVE)
|
|
{
|
|
HandleGameObject(ObjectGuid::Empty, false, rune);
|
|
|
|
switch (rune->GetEntry())
|
|
{
|
|
case GO_HALL_RUNE_1:
|
|
SetBossState(DATA_HALL_RUNE_1, DONE);
|
|
break;
|
|
case GO_HALL_RUNE_2:
|
|
SetBossState(DATA_HALL_RUNE_2, DONE);
|
|
break;
|
|
case GO_HALL_RUNE_3:
|
|
SetBossState(DATA_HALL_RUNE_3, DONE);
|
|
break;
|
|
case GO_HALL_RUNE_4:
|
|
SetBossState(DATA_HALL_RUNE_4, DONE);
|
|
break;
|
|
case GO_HALL_RUNE_5:
|
|
SetBossState(DATA_HALL_RUNE_5, DONE);
|
|
break;
|
|
case GO_HALL_RUNE_6:
|
|
SetBossState(DATA_HALL_RUNE_6, DONE);
|
|
break;
|
|
case GO_HALL_RUNE_7:
|
|
SetBossState(DATA_HALL_RUNE_7, DONE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetBossState(DATA_HALL_RUNE_1) == DONE && GetBossState(DATA_HALL_RUNE_2) == DONE && GetBossState(DATA_HALL_RUNE_3) == DONE &&
|
|
GetBossState(DATA_HALL_RUNE_4) == DONE && GetBossState(DATA_HALL_RUNE_5) == DONE && GetBossState(DATA_HALL_RUNE_6) == DONE &&
|
|
GetBossState(DATA_HALL_RUNE_7) == DONE)
|
|
{
|
|
SetBossState(DATA_DRAGONSPIRE_ROOM, DONE);
|
|
if (GameObject* door1 = instance->GetGameObject(go_emberseerin))
|
|
HandleGameObject(ObjectGuid::Empty, true, door1);
|
|
if (GameObject* door2 = instance->GetGameObject(go_doors))
|
|
HandleGameObject(ObjectGuid::Empty, true, door2);
|
|
if (GameObject* door3 = instance->GetGameObject(go_emberseerin))
|
|
HandleGameObject(ObjectGuid::Empty, true, door3);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
EventMap Events;
|
|
ObjectGuid HighlordOmokk;
|
|
ObjectGuid ShadowHunterVoshgajin;
|
|
ObjectGuid WarMasterVoone;
|
|
ObjectGuid MotherSmolderweb;
|
|
ObjectGuid UrokDoomhowl;
|
|
ObjectGuid QuartermasterZigris;
|
|
ObjectGuid GizrultheSlavener;
|
|
ObjectGuid Halycon;
|
|
ObjectGuid OverlordWyrmthalak;
|
|
ObjectGuid PyroguardEmberseer;
|
|
ObjectGuid WarchiefRendBlackhand;
|
|
ObjectGuid Gyth;
|
|
ObjectGuid LordVictorNefarius;
|
|
ObjectGuid TheBeast;
|
|
ObjectGuid GeneralDrakkisath;
|
|
ObjectGuid go_emberseerin;
|
|
ObjectGuid go_doors;
|
|
ObjectGuid go_emberseerout;
|
|
ObjectGuid go_blackrockaltar;
|
|
ObjectGuid go_roomrunes[7];
|
|
ObjectGuid go_emberseerrunes[7];
|
|
GuidVector runecreaturelist[7];
|
|
ObjectGuid go_portcullis_active;
|
|
ObjectGuid go_urokPile;
|
|
ObjectGuid go_urokChallenge;
|
|
std::vector<ObjectGuid> go_urokOgreCirles;
|
|
std::vector<ObjectGuid> UrokMobs;
|
|
};
|
|
|
|
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
|
{
|
|
return new instance_blackrock_spireMapScript(map);
|
|
}
|
|
};
|
|
|
|
/*#####
|
|
# at_dragonspire_hall
|
|
#####*/
|
|
|
|
class at_dragonspire_hall : public AreaTriggerScript
|
|
{
|
|
public:
|
|
at_dragonspire_hall() : AreaTriggerScript("at_dragonspire_hall") { }
|
|
|
|
bool OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
|
{
|
|
if (player && player->IsAlive())
|
|
{
|
|
if (InstanceScript* instance = player->GetInstanceScript())
|
|
{
|
|
instance->SetData(AREATRIGGER, AREATRIGGER_DRAGONSPIRE_HALL);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/*#####
|
|
# at_blackrock_stadium
|
|
#####*/
|
|
|
|
class at_blackrock_stadium : public AreaTriggerScript
|
|
{
|
|
public:
|
|
at_blackrock_stadium() : AreaTriggerScript("at_blackrock_stadium") { }
|
|
|
|
bool OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
|
{
|
|
if (player && player->IsAlive())
|
|
{
|
|
InstanceScript* instance = player->GetInstanceScript();
|
|
if (!instance)
|
|
return false;
|
|
|
|
Creature* rend;
|
|
if (instance->GetBossState(DATA_WARCHIEF_REND_BLACKHAND) == NOT_STARTED)
|
|
{
|
|
if ((rend = player->FindNearestCreature(NPC_WARCHIEF_REND_BLACKHAND, 100.0f, false)))
|
|
rend->Respawn(true);
|
|
}
|
|
|
|
if ((rend = player->FindNearestCreature(NPC_WARCHIEF_REND_BLACKHAND, 100.0f)))
|
|
{
|
|
rend->AI()->SetData(AREATRIGGER, AREATRIGGER_BLACKROCK_STADIUM);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class go_father_flame : public GameObjectScript
|
|
{
|
|
public:
|
|
go_father_flame() : GameObjectScript("go_father_flame") {}
|
|
|
|
void OnLootStateChanged(GameObject* go, uint32 state, Unit* /*unit*/) override
|
|
{
|
|
if (InstanceScript* instance = go->GetInstanceScript())
|
|
{
|
|
if (state == GO_ACTIVATED)
|
|
{
|
|
if (instance->GetData(DATA_SOLAKAR_FLAMEWREATH) == IN_PROGRESS || instance->GetData(DATA_SOLAKAR_FLAMEWREATH) == DONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
instance->SetData(DATA_SOLAKAR_FLAMEWREATH, IN_PROGRESS);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
class near_scarshield_infiltrator : public AreaTriggerScript
|
|
{
|
|
public:
|
|
near_scarshield_infiltrator() : AreaTriggerScript("near_scarshield_infiltrator") { }
|
|
|
|
bool OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
|
{
|
|
if (player && player->IsAlive())
|
|
{
|
|
if (Creature* creature = player->FindNearestCreature(NPC_SCARSHIELD_INFILTRATOR, 100.0f, true))
|
|
{
|
|
bool transformHasStarted = creature->AI()->GetData(0) == 1;
|
|
if ((player->GetLevel() < 57 || !player->HasItemCount(ITEM_UNADORNED_SEAL)) && !transformHasStarted)
|
|
{
|
|
// Send whisper if not already sent
|
|
std::list<ObjectGuid>::iterator itr = std::find(whisperedTargets.begin(), whisperedTargets.end(), player->GetGUID());
|
|
if (itr == whisperedTargets.end())
|
|
{
|
|
creature->AI()->Talk(SAY_SCARSHIELD_INF_WHISPER, player);
|
|
whisperedTargets.push_back(player->GetGUID());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
private:
|
|
GuidList whisperedTargets;
|
|
};
|
|
|
|
class at_scarshield_infiltrator : public AreaTriggerScript
|
|
{
|
|
public:
|
|
at_scarshield_infiltrator() : AreaTriggerScript("at_scarshield_infiltrator") { }
|
|
|
|
bool OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
|
{
|
|
if (player && player->IsAlive())
|
|
{
|
|
if (Creature* creature = player->FindNearestCreature(NPC_SCARSHIELD_INFILTRATOR, 100.0f, true))
|
|
{
|
|
if (player->GetLevel() >= 57 && player->HasItemCount(ITEM_UNADORNED_SEAL))
|
|
{
|
|
creature->AI()->SetData(0, 1); // Start transform into Vaelan
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/*#####
|
|
# npc_vaelastrasz_the_red and Seal of Ascension event
|
|
#####*/
|
|
|
|
// Set fixed spawn points so there's enough room for the dragon model
|
|
Position VaelastraszTheRedPosNorth = Position(168.815506f, -420.311066f, 110.472298f, 3.141593f);
|
|
Position VaelastraszTheRedPosSouth = Position(134.369049f, -420.311066f, 110.472298f, 6.283184f);
|
|
|
|
// 16349 - Call of Vaelastrasz
|
|
|
|
class spell_blackrock_spire_call_of_vaelastrasz : public SpellScript
|
|
{
|
|
PrepareSpellScript(spell_blackrock_spire_call_of_vaelastrasz);
|
|
|
|
void OnEffect(SpellEffIndex /*effIndex*/)
|
|
{
|
|
if (Unit* caster = GetCaster())
|
|
{
|
|
if (InstanceScript* instance = caster->GetInstanceScript())
|
|
{
|
|
instance->SetData(DATA_VAELASTRASZ, IN_PROGRESS);
|
|
float distanceToNorthSpawn = caster->GetDistance2d(VaelastraszTheRedPosNorth.m_positionX, VaelastraszTheRedPosNorth.m_positionY);
|
|
float distanceToSouthSpawn = caster->GetDistance2d(VaelastraszTheRedPosSouth.m_positionX, VaelastraszTheRedPosSouth.m_positionY);
|
|
Position spawnPosition = distanceToNorthSpawn < distanceToSouthSpawn ? VaelastraszTheRedPosNorth : VaelastraszTheRedPosSouth;
|
|
// despawn is called by the CreatureAI
|
|
caster->SummonCreature(NPC_VAELASTRASZ_THE_RED, spawnPosition, TEMPSUMMON_TIMED_DESPAWN, 60 * IN_MILLISECONDS);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Register() override
|
|
{
|
|
OnEffectLaunch += SpellEffectFn(spell_blackrock_spire_call_of_vaelastrasz::OnEffect, EFFECT_0, SPELL_EFFECT_SEND_EVENT);
|
|
}
|
|
};
|
|
|
|
enum Spells
|
|
{
|
|
// Vaelastrasz the Red
|
|
SPELL_VAELAN_SPAWNS = 16634, // Lightning Effect (Self cast)
|
|
SPELL_TOUCH_OF_VAELASTRASZ = 16319, // AoE heal (Self cast)
|
|
// Vaelastrasz
|
|
SPELL_FLAMEBREATH = 16396, // Combat (Self cast)
|
|
SPELL_VAELASTRASZ_SPAWN = 16354, // Self Cast Despawn (Self cast)
|
|
// Victor Nefarius
|
|
SPELL_NEFARIUS_CORRUPTION = 23642,
|
|
};
|
|
|
|
enum ModelIds
|
|
{
|
|
MODEL_VAELASTRASZ_UBRS = 9909,
|
|
MODEL_VAELASTRASZ_THE_RED = 9912,
|
|
};
|
|
|
|
enum Says
|
|
{
|
|
// Vaelastrasz the Red
|
|
SAY_RED_SUMMONED = 0,
|
|
SAY_RED_BEFORE_TRANSFORM = 1,
|
|
// Vaelastrasz
|
|
SAY_VAEL_SUMMONED = 0,
|
|
SAY_VAEL_STOP_COMBAT = 1,
|
|
// Victor Nefarius
|
|
SAY_NEFARIUS_15 = 15,
|
|
SAY_NEFARIUS_16 = 16,
|
|
SAY_NEFARIUS_17 = 17,
|
|
};
|
|
|
|
enum Events
|
|
{
|
|
// Vaelastrasz the Red
|
|
EVENT_RED_1_TALK_BEFORE_TRANSFORM = 1,
|
|
EVENT_RED_2_TRANSFORM,
|
|
// Vaelastrasz
|
|
EVENT_VAEL_TALK_SUMMON,
|
|
EVENT_VAEL_1_START_COMBAT,
|
|
EVENT_NEFARIUS_TALK_1,
|
|
EVENT_NEFARIUS_TALK_2,
|
|
EVENT_NEFARIUS_TALK_3,
|
|
EVENT_NEFARIUS_CORRUPTION,
|
|
EVENT_VAEL_2_TRANSFORM,
|
|
EVENT_VAEL_3_DESPAWN,
|
|
EVENT_FLAME_BREATH,
|
|
};
|
|
|
|
class npc_vaelastrasz_the_red : public CreatureScript
|
|
{
|
|
public:
|
|
npc_vaelastrasz_the_red() : CreatureScript("npc_vaelastrasz_the_red") { }
|
|
|
|
struct npc_vaelastrasz_the_redAI : public CreatureAI
|
|
{
|
|
npc_vaelastrasz_the_redAI(Creature* creature) : CreatureAI(creature) { }
|
|
|
|
void IsSummonedBy(WorldObject* summoner) override
|
|
{
|
|
if (!summoner)
|
|
{
|
|
return;
|
|
}
|
|
_combatEnabled = false;
|
|
me->CastSpell(me, SPELL_VAELAN_SPAWNS, false);
|
|
me->SetFacingToObject(summoner);
|
|
Talk(SAY_RED_SUMMONED);
|
|
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 100.0f))
|
|
{
|
|
_victorGUID = victor->GetGUID();
|
|
}
|
|
events.ScheduleEvent(EVENT_RED_1_TALK_BEFORE_TRANSFORM, 3s);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
events.Update(diff);
|
|
|
|
while (uint32 eventId = events.ExecuteEvent())
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_RED_1_TALK_BEFORE_TRANSFORM:
|
|
Talk(SAY_RED_BEFORE_TRANSFORM);
|
|
events.ScheduleEvent(EVENT_RED_2_TRANSFORM, 2s);
|
|
break;
|
|
case EVENT_RED_2_TRANSFORM:
|
|
me->CastSpell(me, SPELL_TOUCH_OF_VAELASTRASZ, false);
|
|
me->SetEntry(NPC_VAELASTRASZ_UBRS);
|
|
me->SetDisplayId(MODEL_VAELASTRASZ_UBRS);
|
|
events.ScheduleEvent(EVENT_VAEL_TALK_SUMMON, 1s);
|
|
events.ScheduleEvent(EVENT_VAEL_1_START_COMBAT, 5s);
|
|
break;
|
|
case EVENT_VAEL_TALK_SUMMON:
|
|
Talk(SAY_VAEL_SUMMONED);
|
|
break;
|
|
case EVENT_VAEL_1_START_COMBAT:
|
|
_combatEnabled = true;
|
|
me->SetImmuneToNPC(false);
|
|
if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 100.0f, true))
|
|
{
|
|
me->AddThreat(gyth, 1000000.f);
|
|
me->AI()->AttackStart(gyth);
|
|
}
|
|
if (Creature* rend = me->FindNearestCreature(NPC_WARCHIEF_REND_BLACKHAND, 100.0f, true))
|
|
{
|
|
if (!rend->IsImmuneToNPC() && rend->isTargetableForAttack())
|
|
{
|
|
me->AddThreat(rend, 100000.f);
|
|
if (!me->FindNearestCreature(NPC_GYTH, 100.0f, true))
|
|
{
|
|
me->AI()->AttackStart(rend);
|
|
}
|
|
}
|
|
}
|
|
_events2.ScheduleEvent(EVENT_FLAME_BREATH, 5s);
|
|
events.ScheduleEvent(EVENT_NEFARIUS_TALK_1, 500ms);
|
|
break;
|
|
case EVENT_NEFARIUS_TALK_1:
|
|
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
|
|
{
|
|
victor->GetMotionMaster()->Clear(); // stop pacing
|
|
victor->GetMotionMaster()->MoveIdle();
|
|
victor->StopMovingOnCurrentPos();
|
|
victor->SetFacingToObject(me);
|
|
victor->AI()->Talk(SAY_NEFARIUS_15);
|
|
}
|
|
events.ScheduleEvent(EVENT_NEFARIUS_TALK_2, 6s);
|
|
break;
|
|
case EVENT_NEFARIUS_TALK_2:
|
|
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
|
|
{
|
|
victor->SetFacingToObject(me);
|
|
victor->AI()->Talk(SAY_NEFARIUS_16);
|
|
}
|
|
events.ScheduleEvent(EVENT_NEFARIUS_TALK_3, 5s);
|
|
break;
|
|
case EVENT_NEFARIUS_TALK_3:
|
|
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
|
|
{
|
|
victor->SetFacingToObject(me);
|
|
victor->AI()->Talk(SAY_NEFARIUS_17);
|
|
}
|
|
events.ScheduleEvent(EVENT_NEFARIUS_CORRUPTION, 5s);
|
|
break;
|
|
case EVENT_NEFARIUS_CORRUPTION:
|
|
_combatEnabled = false;
|
|
me->AttackStop();
|
|
me->RemoveAllAuras();
|
|
me->StopMovingOnCurrentPos();
|
|
me->SetFaction(FACTION_FRIENDLY);
|
|
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
|
|
{
|
|
victor->SetFacingToObject(me);
|
|
victor->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY);
|
|
}
|
|
events.ScheduleEvent(EVENT_VAEL_2_TRANSFORM, 1s);
|
|
break;
|
|
case EVENT_VAEL_2_TRANSFORM:
|
|
Talk(SAY_VAEL_STOP_COMBAT);
|
|
me->SetDisplayId(MODEL_VAELASTRASZ_THE_RED);
|
|
events.ScheduleEvent(EVENT_VAEL_3_DESPAWN, 500ms);
|
|
break;
|
|
case EVENT_VAEL_3_DESPAWN:
|
|
DoCast(me, SPELL_VAELASTRASZ_SPAWN);
|
|
me->DespawnOrUnsummon(1500);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!_combatEnabled || !UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_events2.Update(diff);
|
|
|
|
switch (_events2.ExecuteEvent())
|
|
{
|
|
case EVENT_FLAME_BREATH:
|
|
me->CastSpell(me, SPELL_FLAMEBREATH, false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
return;
|
|
}
|
|
|
|
private:
|
|
ObjectGuid _victorGUID;
|
|
bool _combatEnabled;
|
|
EventMap _events2;
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return GetBlackrockSpireAI<npc_vaelastrasz_the_redAI>(creature);
|
|
}
|
|
};
|
|
|
|
void AddSC_instance_blackrock_spire()
|
|
{
|
|
new instance_blackrock_spire();
|
|
new at_dragonspire_hall();
|
|
new at_blackrock_stadium();
|
|
new go_father_flame();
|
|
new near_scarshield_infiltrator();
|
|
new at_scarshield_infiltrator();
|
|
RegisterSpellScript(spell_blackrock_spire_call_of_vaelastrasz);
|
|
new npc_vaelastrasz_the_red();
|
|
}
|