Merge pull request #14157 from ariel-/shathalls

Shattered Halls: Revamped instance script
This commit is contained in:
MitchesD
2015-04-24 20:59:12 +02:00
6 changed files with 517 additions and 32 deletions

View File

@@ -108,6 +108,7 @@ class boss_grand_warlock_nethekurse : public CreatureScript
void Reset() override
{
_Reset();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
Initialize();
@@ -115,9 +116,8 @@ class boss_grand_warlock_nethekurse : public CreatureScript
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DIE);
instance->SetBossState(DATA_NETHEKURSE, DONE);
}
void SetData(uint32 data, uint32 value) override

View File

@@ -160,6 +160,7 @@ class boss_warbringer_omrogg : public CreatureScript
void Reset() override
{
_Reset();
if (Unit* LeftHead = ObjectAccessor::GetUnit(*me, LeftHeadGUID))
{
LeftHead->setDeathState(JUST_DIED);
@@ -257,14 +258,14 @@ class boss_warbringer_omrogg : public CreatureScript
Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID);
Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID);
_JustDied();
if (!LeftHead || !RightHead)
return;
LeftHead->AI()->Talk(YELL_DIE_L);
RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL);
instance->SetBossState(DATA_OMROGG, DONE);
}
void UpdateAI(uint32 diff) override

View File

@@ -35,7 +35,10 @@ enum Says
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2
SAY_DEATH = 2,
SAY_CALL_EXECUTIONER_A = 3,
SAY_CALL_EXECUTIONER_H = 4
};
enum Spells
@@ -84,10 +87,28 @@ class boss_warchief_kargath_bladefist : public CreatureScript
resetcheck_timer = 5000;
}
void SetData(uint32 type, uint32 data) override
{
if (type == 1)
{
switch (data)
{
case ALLIANCE:
Talk(SAY_CALL_EXECUTIONER_A);
break;
case HORDE:
Talk(SAY_CALL_EXECUTIONER_H);
break;
default:
break;
}
}
}
void Reset() override
{
removeAdds();
_Reset();
me->SetSpeed(MOVE_RUN, 2);
me->SetWalk(false);
@@ -96,10 +117,9 @@ class boss_warchief_kargath_bladefist : public CreatureScript
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
removeAdds();
instance->SetBossState(DATA_KARGATH, DONE);
}
void EnterCombat(Unit* /*who*/) override

View File

@@ -27,6 +27,22 @@ EndScriptData */
#include "InstanceScript.h"
#include "shattered_halls.h"
enum Spells
{
SPELL_CLEAVE = 15284,
SPELL_EXECUTE_1 = 39288,
SPELL_EXECUTE_2,
SPELL_EXECUTE_3
};
DoorData const doorData[] =
{
{GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_S },
{GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_N },
{0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE}
};
class instance_shattered_halls : public InstanceMapScript
{
public:
@@ -43,6 +59,43 @@ class instance_shattered_halls : public InstanceMapScript
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
executionTimer = 0;
executed = 0;
_team = 0;
}
void OnPlayerEnter(Player* player) override
{
Aura* ex = nullptr;
if (!_team)
_team = player->GetTeam();
player->RemoveAurasDueToSpell(SPELL_EXECUTE_1);
player->RemoveAurasDueToSpell(SPELL_EXECUTE_2);
player->RemoveAurasDueToSpell(SPELL_EXECUTE_3);
if (!executionTimer || executionerGUID.IsEmpty())
return;
switch (executed)
{
case 0:
ex = player->AddAura(SPELL_EXECUTE_1, player);
break;
case 1:
ex = player->AddAura(SPELL_EXECUTE_2, player);
break;
case 2:
ex = player->AddAura(SPELL_EXECUTE_3, player);
break;
default:
break;
}
if (ex)
ex->SetDuration(executionTimer);
}
void OnGameObjectCreate(GameObject* go) override
@@ -50,21 +103,53 @@ class instance_shattered_halls : public InstanceMapScript
switch (go->GetEntry())
{
case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
nethekurseDoor1GUID = go->GetGUID();
break;
case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
nethekurseDoor2GUID = go->GetGUID();
AddDoor(go, true);
default:
break;
}
}
void OnGameObjectRemove(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
AddDoor(go, false);
default:
break;
}
}
void OnCreatureCreate(Creature* creature) override
{
if (!_team)
{
Map::PlayerList const &players = instance->GetPlayers();
if (!players.isEmpty())
if (Player* player = players.begin()->GetSource())
_team = player->GetTeam();
}
switch (creature->GetEntry())
{
case NPC_GRAND_WARLOCK_NETHEKURSE:
nethekurseGUID = creature->GetGUID();
break;
case NPC_KARGATH_BLADEFIST:
kargathGUID = creature->GetGUID();
break;
case NPC_RANDY_WHIZZLESPROCKET:
if (_team == HORDE)
creature->UpdateEntry(NPC_DRISELLA);
break;
case NPC_SHATTERED_EXECUTIONER:
executionTimer = 55 * MINUTE * IN_MILLISECONDS;
DoCastSpellOnPlayers(SPELL_EXECUTE_1);
executionerGUID = creature->GetGUID();
SaveToDB();
break;
}
}
@@ -75,18 +160,20 @@ class instance_shattered_halls : public InstanceMapScript
switch (type)
{
case DATA_NETHEKURSE:
if (state == IN_PROGRESS)
case DATA_SHATTERED_EXECUTIONER:
if (state == DONE)
{
HandleGameObject(nethekurseDoor1GUID, false);
HandleGameObject(nethekurseDoor2GUID, false);
}
else
{
HandleGameObject(nethekurseDoor1GUID, true);
HandleGameObject(nethekurseDoor2GUID, true);
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_1);
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_2);
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_3);
executionTimer = 0;
SaveToDB();
}
break;
case DATA_KARGATH:
if (Creature* executioner = instance->GetCreature(executionerGUID))
executioner->AI()->Reset();
break;
case DATA_OMROGG:
break;
}
@@ -100,24 +187,307 @@ class instance_shattered_halls : public InstanceMapScript
case NPC_GRAND_WARLOCK_NETHEKURSE:
return nethekurseGUID;
break;
case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
return nethekurseDoor1GUID;
case NPC_KARGATH_BLADEFIST:
return kargathGUID;
break;
case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
return nethekurseDoor2GUID;
case NPC_SHATTERED_EXECUTIONER:
return executionerGUID;
break;
default:
return ObjectGuid::Empty;
break;
}
return ObjectGuid::Empty;
}
void WriteSaveDataMore(std::ostringstream& data) override
{
if (!instance->IsHeroic())
return;
data << uint32(executed) << ' '
<< executionTimer << ' ';
}
void ReadSaveDataMore(std::istringstream& data) override
{
if (!instance->IsHeroic())
return;
uint32 readbuff;
data >> readbuff;
executed = uint8(readbuff);
data >> readbuff;
if (executed > VictimCount)
{
executed = VictimCount;
executionTimer = 0;
return;
}
if (!readbuff)
return;
Creature* executioner = nullptr;
instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
if (Creature* kargath = instance->GetCreature(kargathGUID))
if (executionerGUID.IsEmpty())
executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
if (executioner)
for (uint8 i = executed; i < VictimCount; ++i)
executioner->SummonCreature(executionerVictims[i](GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
executionTimer = readbuff;
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_PRISONERS_EXECUTED:
return executed;
break;
case DATA_TEAM_IN_INSTANCE:
return _team;
break;
default:
return 0;
break;
}
}
void Update(uint32 diff) override
{
if (!executionTimer)
return;
if (executionTimer <= diff)
{
switch (++executed)
{
case 1:
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_1);
DoCastSpellOnPlayers(SPELL_EXECUTE_2);
executionTimer = 10 * MINUTE * IN_MILLISECONDS;
break;
case 2:
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_2);
DoCastSpellOnPlayers(SPELL_EXECUTE_3);
executionTimer = 15 * MINUTE * IN_MILLISECONDS;
break;
default:
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_3);
executionTimer = 0;
break;
}
if (Creature* executioner = instance->GetCreature(executionerGUID))
executioner->AI()->SetData(1, executed);
SaveToDB();
}
else
executionTimer -= diff;
}
protected:
ObjectGuid nethekurseGUID;
ObjectGuid nethekurseDoor1GUID;
ObjectGuid nethekurseDoor2GUID;
ObjectGuid kargathGUID;
ObjectGuid executionerGUID;
uint8 executed;
uint32 executionTimer;
uint32 _team;
};
};
class at_nethekurse_exit : public AreaTriggerScript
{
public:
at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { };
bool OnTrigger(Player* player, AreaTriggerEntry const*) override
{
if (InstanceScript* is = player->GetInstanceScript())
{
if (is->instance->IsHeroic())
{
Creature* executioner = nullptr;
is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST)))
{
if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty())
{
executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
kargath->AI()->SetData(1, is->GetData(DATA_TEAM_IN_INSTANCE));
}
}
if (executioner)
for (uint8 i = 0; i < VictimCount; ++i)
executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
}
}
return false;
}
};
class boss_shattered_executioner : public CreatureScript
{
public:
boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { }
struct boss_shattered_executionerAI : public BossAI
{
boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
{
Initialize();
};
void Initialize()
{
cleaveTimer = 500;
me->ResetLootMode();
switch (instance->GetData(DATA_PRISONERS_EXECUTED))
{
case 0:
me->AddLootMode(LOOT_MODE_HARD_MODE_3);
case 1:
me->AddLootMode(LOOT_MODE_HARD_MODE_2);
case 2:
me->AddLootMode(LOOT_MODE_HARD_MODE_1);
default:
break;
}
}
void Reset() override
{
_Reset();
if (instance->GetBossState(DATA_KARGATH) == DONE)
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
else
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
Initialize();
}
void JustSummoned(Creature*) override { }
void JustDied(Unit*) override
{
_JustDied();
Map::PlayerList const &players = instance->instance->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
Player* pl = itr->GetSource();
uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
if (pl->GetQuestStatus(qId) != QUEST_STATUS_NONE && pl->GetQuestStatus(qId) != QUEST_STATUS_FAILED)
pl->CompleteQuest(qId);
}
}
void SetData(uint32 type, uint32 data) override
{
if (type == 1)
{
uint32 entry = executionerVictims[data - 1](instance->GetData(DATA_TEAM_IN_INSTANCE));
if (Creature* victim = me->FindNearestCreature(entry, 30.0f, true))
me->Kill(victim);
if (data == 1)
{
Map::PlayerList const &players = instance->instance->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
Player* pl = itr->GetSource();
uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
pl->FailQuest(qId);
}
}
switch (data)
{
case 3:
me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
case 2:
me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
case 1:
me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
default:
break;
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (cleaveTimer <= diff)
{
DoCast(SPELL_CLEAVE);
cleaveTimer = urand(5000, 7000);
}
else
cleaveTimer -= diff;
DoMeleeAttackIfReady();
}
private:
uint32 cleaveTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_shattered_executionerAI>(creature);
}
};
class spell_kargath_executioner : public SpellScriptLoader
{
public:
spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { }
class spell_kargath_executioner_AuraScript : public AuraScript
{
PrepareAuraScript(spell_kargath_executioner_AuraScript);
bool AreaCheck(Unit* target)
{
if (target->GetMap()->GetId() != 540)
return false;
return true;
}
bool Load() override
{
return GetCaster()->GetTypeId() == TYPEID_PLAYER;
}
void Register() override
{
DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_kargath_executioner_AuraScript();
}
};
void AddSC_instance_shattered_halls()
{
new instance_shattered_halls();
new at_nethekurse_exit();
new boss_shattered_executioner();
new spell_kargath_executioner();
}

View File

@@ -21,18 +21,41 @@
#define DataHeader "SH"
uint32 const EncounterCount = 3;
uint32 const EncounterCount = 4;
uint32 const VictimCount = 3;
enum DataTypes
{
DATA_NETHEKURSE = 1,
DATA_OMROGG = 2,
DATA_KARGATH = 3
DATA_NETHEKURSE = 0,
DATA_OMROGG = 1,
DATA_KARGATH = 2,
DATA_SHATTERED_EXECUTIONER = 3,
DATA_PRISONERS_EXECUTED = 4,
DATA_TEAM_IN_INSTANCE = 5
};
enum CreatureIds
{
NPC_GRAND_WARLOCK_NETHEKURSE = 16807
NPC_GRAND_WARLOCK_NETHEKURSE = 16807,
NPC_KARGATH_BLADEFIST = 16808,
NPC_SHATTERED_EXECUTIONER = 17301,
// Alliance Ids
NPC_RANDY_WHIZZLESPROCKET = 17288,
NPC_CAPTAIN_ALINA = 17290,
NPC_ALLIANCE_VICTIM_1 = 17289,
NPC_ALLIANCE_VICTIM_2 = 17292,
// Horde Ids
NPC_DRISELLA = 17294,
NPC_CAPTAIN_BONESHATTER = 17296,
NPC_HORDE_VICTIM_1 = 17295,
NPC_HORDE_VICTIM_2 = 17297
};
enum GameobjectIds
@@ -41,4 +64,33 @@ enum GameobjectIds
GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540
};
enum QuestIds
{
QUEST_IMPRISONED_A = 9524,
QUEST_IMPRISONED_H = 9525
};
const Position Executioner = { 152.8524f, -83.63912f, 2.021005f, 0.06981317f };
struct FactionSpawnerHelper
{
FactionSpawnerHelper(uint32 allianceEntry, uint32 hordeEntry, const Position& pos) : _allianceNPC(allianceEntry), _hordeNPC(hordeEntry), _spawnPos(pos) { }
inline uint32 operator()(uint32 teamID) const { return teamID == ALLIANCE ? _allianceNPC : _hordeNPC; }
inline const Position GetPos() const { return _spawnPos; }
private:
const uint32 _allianceNPC;
const uint32 _hordeNPC;
const Position _spawnPos;
};
const FactionSpawnerHelper executionerVictims[VictimCount] =
{
{ NPC_CAPTAIN_ALINA, NPC_CAPTAIN_BONESHATTER, { 138.8807f, -84.22707f, 1.992269f, 0.06981317f } },
{ NPC_ALLIANCE_VICTIM_1, NPC_HORDE_VICTIM_1, { 151.2411f, -91.02930f, 2.019741f, 1.57079600f } },
{ NPC_ALLIANCE_VICTIM_2, NPC_HORDE_VICTIM_2, { 151.0459f, -77.51981f, 2.021008f, 4.74729500f } }
};
#endif