Co-authored-by: Meji <alvaro.megias@outlook.com> Co-authored-by: 天鹿 <18535853+PkllonG@users.noreply.github.com>
2034 lines
94 KiB
C++
2034 lines
94 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 "AccountMgr.h"
|
|
#include "CreatureTextMgr.h"
|
|
#include "Group.h"
|
|
#include "InstanceMapScript.h"
|
|
#include "InstanceScript.h"
|
|
#include "Map.h"
|
|
#include "ObjectMgr.h"
|
|
#include "Player.h"
|
|
#include "ScriptedCreature.h"
|
|
#include "Transport.h"
|
|
#include "WorldPacket.h"
|
|
#include "WorldSession.h"
|
|
#include "icecrown_citadel.h"
|
|
|
|
enum EventIds
|
|
{
|
|
EVENT_PLAYERS_GUNSHIP_SPAWN = 22663,
|
|
EVENT_PLAYERS_GUNSHIP_COMBAT = 22664,
|
|
EVENT_PLAYERS_GUNSHIP_SAURFANG = 22665,
|
|
EVENT_ENEMY_GUNSHIP_COMBAT = 22860,
|
|
EVENT_ENEMY_GUNSHIP_DESPAWN = 22861,
|
|
|
|
EVENT_QUAKE = 23437,
|
|
EVENT_SECOND_REMORSELESS_WINTER = 23507,
|
|
EVENT_TELEPORT_TO_FROSMOURNE = 23617,
|
|
EVENT_FESTERGUT_VALVE_USED = 23438,
|
|
EVENT_ROTFACE_VALVE_USED = 23426,
|
|
};
|
|
|
|
enum TimedEvents
|
|
{
|
|
EVENT_UPDATE_EXECUTION_TIME = 1,
|
|
EVENT_QUAKE_SHATTER = 2,
|
|
EVENT_REBUILD_PLATFORM = 3,
|
|
EVENT_RESPAWN_GUNSHIP = 4,
|
|
EVENT_RESPAWN_SINDRAGOSA = 5
|
|
};
|
|
|
|
enum Spells
|
|
{
|
|
SPELL_GAS_VARIABLE = 74119,
|
|
SPELL_OOZE_VARIABLE = 74118,
|
|
BLOOD_BEAM_VISUAL_RHAND = 72304,
|
|
BLOOD_BEAM_VISUAL_LHAND = 72303,
|
|
BLOOD_BEAM_VISUAL_LLEG = 72302,
|
|
BLOOD_BEAM_VISUAL_RLEG = 72301,
|
|
VOID_ZONE_VISUAL = 69422
|
|
};
|
|
|
|
enum Say
|
|
{
|
|
SAY_SOULS_LICH_KING_RAND_WHISPER = 5
|
|
};
|
|
|
|
BossBoundaryData const boundaries =
|
|
{
|
|
{ DATA_LORD_MARROWGAR, new CircleBoundary(Position(-428.0f,2211.0f), 95.0) },
|
|
{ DATA_LORD_MARROWGAR, new RectangleBoundary(-430.0f, -330.0f, 2110.0f, 2310.0f) },
|
|
{ DATA_LADY_DEATHWHISPER, new RectangleBoundary(-670.0f, -520.0f, 2145.0f, 2280.0f) },
|
|
{ DATA_DEATHBRINGER_SAURFANG, new RectangleBoundary(-565.0f, -465.0f, 2160.0f, 2260.0f) },
|
|
|
|
{ DATA_ROTFACE, new RectangleBoundary(4385.0f, 4505.0f, 3082.0f, 3195.0f) },
|
|
{ DATA_FESTERGUT, new RectangleBoundary(4205.0f, 4325.0f, 3082.0f, 3195.0f) },
|
|
{ DATA_PROFESSOR_PUTRICIDE, new ParallelogramBoundary(Position(4356.0f, 3290.0f), Position(4435.0f, 3194.0f), Position(4280.0f, 3194.0f)) },
|
|
{ DATA_PROFESSOR_PUTRICIDE, new RectangleBoundary(4280.0f, 4435.0f, 3150.0f, 4360.0f) },
|
|
|
|
{ DATA_BLOOD_PRINCE_COUNCIL, new EllipseBoundary(Position(4660.95f, 2769.194f), 85.0, 60.0) },
|
|
{ DATA_BLOOD_QUEEN_LANA_THEL, new CircleBoundary(Position(4595.93f, 2769.365f), 64.0) },
|
|
|
|
{ DATA_SISTER_SVALNA, new RectangleBoundary(4291.0f, 4423.0f, 2438.0f, 2653.0f) },
|
|
{ DATA_VALITHRIA_DREAMWALKER, new RectangleBoundary(4112.5f, 4293.5f, 2385.0f, 2585.0f) },
|
|
{ DATA_SINDRAGOSA, new EllipseBoundary(Position(4418.6f, 2484.0f), 110.0, 75.0) }
|
|
};
|
|
|
|
DoorData const doorData[] =
|
|
{
|
|
{GO_LORD_MARROWGAR_S_ENTRANCE, DATA_LORD_MARROWGAR, DOOR_TYPE_ROOM },
|
|
{GO_SCOURGE_TRANSPORTER_FIRST, DATA_LORD_MARROWGAR, DOOR_TYPE_PASSAGE },
|
|
{GO_ICEWALL, DATA_LORD_MARROWGAR, DOOR_TYPE_PASSAGE },
|
|
{GO_DOODAD_ICECROWN_ICEWALL02, DATA_LORD_MARROWGAR, DOOR_TYPE_PASSAGE },
|
|
{GO_ORATORY_OF_THE_DAMNED_ENTRANCE, DATA_LADY_DEATHWHISPER, DOOR_TYPE_ROOM },
|
|
{GO_SAURFANG_S_DOOR, DATA_DEATHBRINGER_SAURFANG, DOOR_TYPE_PASSAGE },
|
|
{GO_ORANGE_PLAGUE_MONSTER_ENTRANCE, DATA_FESTERGUT, DOOR_TYPE_ROOM },
|
|
{GO_GREEN_PLAGUE_MONSTER_ENTRANCE, DATA_ROTFACE, DOOR_TYPE_ROOM },
|
|
{GO_CRIMSON_HALL_DOOR, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_ROOM },
|
|
{GO_CRIMSON_HALL_DOOR, DATA_BLOOD_PRINCE_TRASH, DOOR_TYPE_PASSAGE },
|
|
{GO_BLOOD_ELF_COUNCIL_DOOR, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_PASSAGE },
|
|
{GO_BLOOD_ELF_COUNCIL_DOOR_RIGHT, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_PASSAGE },
|
|
{GO_DOODAD_ICECROWN_BLOODPRINCE_DOOR_01, DATA_BLOOD_QUEEN_LANA_THEL, DOOR_TYPE_ROOM },
|
|
{GO_DOODAD_ICECROWN_GRATE_01, DATA_BLOOD_QUEEN_LANA_THEL, DOOR_TYPE_PASSAGE },
|
|
{GO_GREEN_DRAGON_BOSS_ENTRANCE, DATA_SISTER_SVALNA, DOOR_TYPE_PASSAGE },
|
|
{GO_GREEN_DRAGON_BOSS_ENTRANCE, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_ROOM },
|
|
{GO_GREEN_DRAGON_BOSS_EXIT, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_PASSAGE },
|
|
{GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE },
|
|
{GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE },
|
|
{GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE },
|
|
{GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE },
|
|
{GO_SINDRAGOSA_ENTRANCE_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_ROOM },
|
|
{GO_SINDRAGOSA_ENTRANCE_DOOR, DATA_SINDRAGOSA_GAUNTLET, DOOR_TYPE_PASSAGE },
|
|
{GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_PASSAGE },
|
|
{GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_PASSAGE },
|
|
{GO_ICE_WALL, DATA_SINDRAGOSA, DOOR_TYPE_ROOM },
|
|
{GO_ICE_WALL, DATA_SINDRAGOSA, DOOR_TYPE_ROOM },
|
|
{0, 0, DOOR_TYPE_ROOM }
|
|
};
|
|
|
|
ObjectData const creatureData[] =
|
|
{
|
|
{ NPC_SINDRAGOSA, DATA_SINDRAGOSA },
|
|
{ NPC_THE_SKYBREAKER, DATA_THE_SKYBREAKER },
|
|
{ NPC_ORGRIMS_HAMMER, DATA_ORGRIMS_HAMMER },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
// this doesnt have to only store questgivers, also can be used for related quest spawns
|
|
struct WeeklyQuest
|
|
{
|
|
uint32 creatureEntry;
|
|
uint32 questId[2]; // 10 and 25 man versions
|
|
};
|
|
|
|
// when changing the content, remember to update SetData, DATA_BLOOD_QUICKENING_STATE case for NPC_ALRIN_THE_AGILE index
|
|
WeeklyQuest const WeeklyQuestData[WeeklyNPCs] =
|
|
{
|
|
{NPC_INFILTRATOR_MINCHAR, {QUEST_DEPROGRAMMING_10, QUEST_DEPROGRAMMING_25 }}, // Deprogramming
|
|
{NPC_KOR_KRON_LIEUTENANT, {QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 }}, // Securing the Ramparts
|
|
{NPC_ROTTING_FROST_GIANT_10, {QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 }}, // Securing the Ramparts
|
|
{NPC_ROTTING_FROST_GIANT_25, {QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 }}, // Securing the Ramparts
|
|
{NPC_ALCHEMIST_ADRIANNA, {QUEST_RESIDUE_RENDEZVOUS_10, QUEST_RESIDUE_RENDEZVOUS_25 }}, // Residue Rendezvous
|
|
{NPC_ALRIN_THE_AGILE, {QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 }}, // Blood Quickening
|
|
{NPC_INFILTRATOR_MINCHAR_BQ, {QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 }}, // Blood Quickening
|
|
{NPC_MINCHAR_BEAM_STALKER, {QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 }}, // Blood Quickening
|
|
{NPC_VALITHRIA_DREAMWALKER_QUEST, {QUEST_RESPITE_FOR_A_TORMENTED_SOUL_10, QUEST_RESPITE_FOR_A_TORMENTED_SOUL_25 }}, // Respite for a Tormented Soul
|
|
};
|
|
|
|
Position const JainaSpawnPos = { -48.65278f, 2211.026f, 27.98586f, 3.124139f };
|
|
Position const MuradinSpawnPos = { -47.34549f, 2208.087f, 27.98586f, 3.106686f };
|
|
Position const UtherSpawnPos = { -26.58507f, 2211.524f, 30.19898f, 3.124139f };
|
|
Position const SylvanasSpawnPos = { -41.45833f, 2222.891f, 27.98586f, 3.647738f };
|
|
Position const SindragosaSpawnPos = { 4818.6997f, 2483.7102f, 287.06497f, 3.286661f };
|
|
|
|
// Set position traps Spirit Alarm
|
|
std::vector<Position> GoSpiritAlarm_1 = { { -160.96f, 2210.46f, 35.24f, 0.0f }, { -176.27f, 2201.93f, 35.24f, 0.0f}, { -207.83f, 2207.38f, 35.24f, 0.0f } };
|
|
std::vector<Position> GoSpiritAlarm_2 = { { -178.41f, 2225.11f, 35.24f, 0.0f }, { -195.23f, 2221.55f, 35.24f, 0.0f}, { -209.94f, 2250.34f, 37.99f, 0.0f } };
|
|
std::vector<Position> GoSpiritAlarm_3 = { { -289.80f, 2216.60f, 42.39f, 0.0f }, { -317.76f, 2216.11f, 42.57f, 0.0f}, { -301.07f, 2216.62f, 42.0f, 0.0f } };
|
|
std::vector<Position> GoSpiritAlarm_4 = { { -276.07f, 2206.76f, 42.57f, 0.0f }, { -304.44f, 2199.11f, 41.99f, 0.0f}, { -292.82f, 2204.61f, 42.02f, 0.0f } };
|
|
|
|
class RespawnEvent : public BasicEvent
|
|
{
|
|
public:
|
|
RespawnEvent(Creature& owner) : _owner(owner) { }
|
|
|
|
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
|
|
{
|
|
_owner.RemoveCorpse(false);
|
|
_owner.Respawn();
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
Creature& _owner;
|
|
};
|
|
|
|
class DelayedCastMincharEvent : public BasicEvent
|
|
{
|
|
public:
|
|
DelayedCastMincharEvent(Creature* trigger, uint32 spellId) : _trigger(trigger), _spellId(spellId) {}
|
|
|
|
bool Execute(uint64 /*time*/, uint32 /*diff*/) override
|
|
{
|
|
if (Creature* minchar = _trigger->FindNearestCreature(NPC_INFILTRATOR_MINCHAR_BQ, 50.0f, true))
|
|
_trigger->CastSpell(minchar, _spellId, true);
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
Creature* _trigger;
|
|
uint32 _spellId;
|
|
};
|
|
|
|
class instance_icecrown_citadel : public InstanceMapScript
|
|
{
|
|
public:
|
|
instance_icecrown_citadel() : InstanceMapScript(ICCScriptName, 631) { }
|
|
|
|
struct instance_icecrown_citadel_InstanceMapScript : public InstanceScript
|
|
{
|
|
instance_icecrown_citadel_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
|
|
{
|
|
// pussywizard:
|
|
IsBuffAvailable = true;
|
|
WeeklyQuestId10 = 0;
|
|
PutricideEventProgress = 0;
|
|
LichKingHeroicAvailable = true;
|
|
LichKingRandomWhisperTimer = 120 * IN_MILLISECONDS;
|
|
DarkwhisperElevatorTimer = 3000;
|
|
|
|
SetHeaders(DataHeader);
|
|
SetBossNumber(MAX_ENCOUNTERS);
|
|
SetPersistentDataCount(MAX_DATA_INDEXES);
|
|
LoadBossBoundaries(boundaries);
|
|
LoadObjectData(creatureData, nullptr);
|
|
LoadDoorData(doorData);
|
|
TeamIdInInstance = TEAM_NEUTRAL;
|
|
HeroicAttempts = MaxHeroicAttempts;
|
|
IsBonedEligible = true;
|
|
IsOozeDanceEligible = true;
|
|
IsNauseaEligible = true;
|
|
IsOrbWhispererEligible = true;
|
|
ColdflameJetsState = NOT_STARTED;
|
|
BloodQuickeningState = NOT_STARTED;
|
|
BloodQuickeningMinutes = 0;
|
|
BloodPrinceTrashCount = 0;
|
|
IsSindragosaIntroDone = false;
|
|
}
|
|
|
|
void FillInitialWorldStates(WorldPacket& data) override
|
|
{
|
|
if (instance->IsHeroic())
|
|
{
|
|
data << uint32(WORLDSTATE_SHOW_TIMER) << uint32(BloodQuickeningState == IN_PROGRESS);
|
|
data << uint32(WORLDSTATE_EXECUTION_TIME) << uint32(BloodQuickeningMinutes);
|
|
data << uint32(WORLDSTATE_SHOW_ATTEMPTS) << uint32(1);
|
|
data << uint32(WORLDSTATE_ATTEMPTS_REMAINING) << uint32(HeroicAttempts);
|
|
data << uint32(WORLDSTATE_ATTEMPTS_MAX) << uint32(MaxHeroicAttempts);
|
|
}
|
|
}
|
|
|
|
void OnPlayerAreaUpdate(Player* player, uint32 /*oldArea*/, uint32 newArea) override
|
|
{
|
|
if (newArea == 4890 /*Putricide's Laboratory of Alchemical Horrors and Fun*/ ||
|
|
newArea == 4891 /*The Sanctum of Blood*/ ||
|
|
newArea == 4889 /*The Frost Queen's Lair*/ ||
|
|
newArea == 4859 /*The Frozen Throne*/ ||
|
|
newArea == 4910 /*Frostmourne*/)
|
|
{
|
|
player->SendInitWorldStates(player->GetZoneId(), player->GetAreaId());
|
|
}
|
|
else
|
|
{
|
|
player->SendUpdateWorldState(WORLDSTATE_SHOW_ATTEMPTS, 0);
|
|
}
|
|
}
|
|
|
|
void OnPlayerEnter(Player* player) override
|
|
{
|
|
if (TeamIdInInstance == TEAM_NEUTRAL)
|
|
TeamIdInInstance = player->GetTeamId();
|
|
|
|
// for professor putricide hc
|
|
DoRemoveAurasDueToSpellOnPlayers(SPELL_GAS_VARIABLE);
|
|
DoRemoveAurasDueToSpellOnPlayers(SPELL_OOZE_VARIABLE);
|
|
|
|
if (GetBossState(DATA_LADY_DEATHWHISPER) == DONE && GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) != DONE)
|
|
SpawnGunship();
|
|
|
|
if (GetBossState(DATA_SINDRAGOSA) != DONE && IsSindragosaIntroDone && !GetCreature(DATA_SINDRAGOSA) && Events.GetTimeUntilEvent(EVENT_RESPAWN_SINDRAGOSA) == Milliseconds::max())
|
|
{
|
|
Events.ScheduleEvent(EVENT_RESPAWN_SINDRAGOSA, 30s);
|
|
}
|
|
|
|
if (IsBuffAvailable)
|
|
{
|
|
SpellAreaForAreaMapBounds saBounds = sSpellMgr->GetSpellAreaForAreaMapBounds(4812);
|
|
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
|
|
if ((itr->second->raceMask & player->getRaceMask()) && !player->HasAura(itr->second->spellId))
|
|
{
|
|
if (SpellInfo const* si = sSpellMgr->GetSpellInfo(itr->second->spellId))
|
|
{
|
|
if (si->HasAura(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT))
|
|
{
|
|
DoCastSpellOnPlayer(player, itr->second->spellId, false, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnCreatureCreate(Creature* creature) override
|
|
{
|
|
if (TeamIdInInstance == TEAM_NEUTRAL)
|
|
{
|
|
Map::PlayerList const& players = instance->GetPlayers();
|
|
if (!players.IsEmpty())
|
|
if (Player* player = players.begin()->GetSource())
|
|
TeamIdInInstance = player->GetTeamId();
|
|
}
|
|
|
|
// apply ICC buff to pets/summons
|
|
if (GetData(DATA_BUFF_AVAILABLE) && creature->GetOwnerGUID().IsPlayer() && creature->HasUnitTypeMask(UNIT_MASK_MINION | UNIT_MASK_GUARDIAN | UNIT_MASK_CONTROLABLE_GUARDIAN) && creature->CanHaveThreatList())
|
|
if (Unit* owner = creature->GetOwner())
|
|
if (Player* plr = owner->ToPlayer())
|
|
{
|
|
SpellAreaForAreaMapBounds saBounds = sSpellMgr->GetSpellAreaForAreaMapBounds(4812);
|
|
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
|
|
if ((itr->second->raceMask & plr->getRaceMask()) && !creature->HasAura(itr->second->spellId))
|
|
if (SpellInfo const* si = sSpellMgr->GetSpellInfo(itr->second->spellId))
|
|
if (si->HasAura(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT))
|
|
creature->AddAura(itr->second->spellId, creature);
|
|
}
|
|
|
|
// fighting npcs in Rampart of Skulls
|
|
std::string name1("Skybreaker ");
|
|
std::string name2("Kor'kron ");
|
|
if (!creature->GetTransport() && creature->GetPositionZ() <= 205.0f && creature->GetExactDist2d(-439.0f, 2210.0f) <= 150.0f && (creature->GetEntry() == 37544 || creature->GetEntry() == 37545 || creature->GetName().compare(0, name1.length(), name1) == 0 || creature->GetName().compare(0, name2.length(), name2) == 0))
|
|
creature->AddToNotify(NOTIFY_AI_RELOCATION);
|
|
|
|
// pussywizard: check weekly here, before possible UpdateEntry
|
|
// allow creating all of them, because after killing Marrowgar some have to appear, so just hide them
|
|
switch (creature->GetEntry())
|
|
{
|
|
case NPC_INFILTRATOR_MINCHAR:
|
|
case NPC_KOR_KRON_LIEUTENANT:
|
|
case NPC_ALCHEMIST_ADRIANNA:
|
|
case NPC_ALRIN_THE_AGILE:
|
|
case NPC_INFILTRATOR_MINCHAR_BQ:
|
|
case NPC_MINCHAR_BEAM_STALKER:
|
|
case NPC_VALITHRIA_DREAMWALKER_QUEST:
|
|
for (uint8 i = 0; i < WeeklyNPCs; ++i)
|
|
if (WeeklyQuestData[i].creatureEntry == creature->GetEntry())
|
|
{
|
|
WeeklyQuestNpcGUID[i] = creature->GetGUID();
|
|
if (WeeklyQuestId10 != WeeklyQuestData[i].questId[0])
|
|
creature->SetVisible(false);
|
|
else if (WeeklyQuestData[i].creatureEntry == NPC_VALITHRIA_DREAMWALKER_QUEST && GetBossState(DATA_VALITHRIA_DREAMWALKER) != DONE)
|
|
creature->SetVisible(false);
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (creature->GetEntry())
|
|
{
|
|
case NPC_KOR_KRON_GENERAL:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_ALLIANCE_COMMANDER);
|
|
break;
|
|
case NPC_KOR_KRON_LIEUTENANT:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_SKYBREAKER_LIEUTENANT);
|
|
break;
|
|
case NPC_TORTUNOK:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_ALANA_MOONSTRIKE);
|
|
break;
|
|
case NPC_GERARDO_THE_SUAVE:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_TALAN_MOONSTRIKE);
|
|
break;
|
|
case NPC_UVLUS_BANEFIRE:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_MALFUS_GRIMFROST);
|
|
break;
|
|
case NPC_IKFIRUS_THE_VILE:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_YILI);
|
|
break;
|
|
case NPC_VOL_GUK:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_JEDEBIA);
|
|
break;
|
|
case NPC_HARAGG_THE_UNSEEN:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_NIBY_THE_ALMIGHTY);
|
|
break;
|
|
case NPC_GARROSH_HELLSCREAM:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_KING_VARIAN_WRYNN);
|
|
|
|
// Xinef: summon in case of instance unload
|
|
if (GetBossState(DATA_THE_LICH_KING) == DONE)
|
|
{
|
|
instance->SummonCreature(NPC_LADY_JAINA_PROUDMOORE_QUEST, JainaSpawnPos);
|
|
instance->SummonCreature(NPC_MURADIN_BRONZEBEARD_QUEST, MuradinSpawnPos);
|
|
instance->SummonCreature(NPC_UTHER_THE_LIGHTBRINGER_QUEST, UtherSpawnPos);
|
|
instance->SummonCreature(NPC_LADY_SYLVANAS_WINDRUNNER_QUEST, SylvanasSpawnPos);
|
|
}
|
|
break;
|
|
case NPC_LADY_DEATHWHISPER:
|
|
LadyDeathwhisperGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_DEATHBRINGER_SAURFANG:
|
|
DeathbringerSaurfangGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_SE_HIGH_OVERLORD_SAURFANG:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
{
|
|
creature->UpdateEntry(NPC_SE_MURADIN_BRONZEBEARD, true);
|
|
creature->LoadEquipment();
|
|
}
|
|
DeathbringerSaurfangEventGUID = creature->GetGUID();
|
|
creature->LastUsedScriptID = creature->GetScriptId();
|
|
break;
|
|
case NPC_SE_MURADIN_BRONZEBEARD:
|
|
DeathbringerSaurfangEventGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_HIGH_OVERLORD_SAURFANG_DUMMY:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
{
|
|
creature->UpdateEntry(NPC_MURADIN_BRONZEBEARD_DUMMY, creature->GetCreatureData());
|
|
creature->LoadEquipment();
|
|
}
|
|
break;
|
|
case NPC_SE_KOR_KRON_REAVER:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
creature->UpdateEntry(NPC_SE_SKYBREAKER_MARINE);
|
|
break;
|
|
case NPC_FESTERGUT:
|
|
FestergutGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_ROTFACE:
|
|
RotfaceGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_PROFESSOR_PUTRICIDE:
|
|
ProfessorPutricideGUID = creature->GetGUID();
|
|
if (GetBossState(DATA_ROTFACE) == DONE && GetBossState(DATA_FESTERGUT) == DONE && !HeroicAttempts && GetData(DATA_HAS_LIMITED_ATTEMPTS) && creature->IsAlive())
|
|
creature->SetVisible(false);
|
|
break;
|
|
case NPC_PRINCE_KELESETH:
|
|
BloodCouncilGUIDs[0] = creature->GetGUID();
|
|
break;
|
|
case NPC_PRINCE_TALDARAM:
|
|
BloodCouncilGUIDs[1] = creature->GetGUID();
|
|
break;
|
|
case NPC_PRINCE_VALANAR:
|
|
BloodCouncilGUIDs[2] = creature->GetGUID();
|
|
break;
|
|
case NPC_BLOOD_ORB_CONTROLLER:
|
|
BloodCouncilControllerGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_BLOOD_QUEEN_LANA_THEL:
|
|
BloodQueenLanaThelGUID = creature->GetGUID();
|
|
if (!HeroicAttempts && GetData(DATA_HAS_LIMITED_ATTEMPTS) && creature->IsAlive())
|
|
creature->SetVisible(false);
|
|
break;
|
|
case NPC_CROK_SCOURGEBANE:
|
|
CrokScourgebaneGUID = creature->GetGUID();
|
|
break;
|
|
// we can only do this because there are no gaps in their entries
|
|
case NPC_CAPTAIN_ARNATH:
|
|
case NPC_CAPTAIN_BRANDON:
|
|
case NPC_CAPTAIN_GRONDEL:
|
|
case NPC_CAPTAIN_RUPERT:
|
|
CrokCaptainGUIDs[creature->GetEntry() - NPC_CAPTAIN_ARNATH] = creature->GetGUID();
|
|
break;
|
|
case NPC_SISTER_SVALNA:
|
|
SisterSvalnaGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_VALITHRIA_DREAMWALKER:
|
|
ValithriaDreamwalkerGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_THE_LICH_KING_VALITHRIA:
|
|
ValithriaLichKingGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_THE_LICH_KING_LH:
|
|
TheLichKingLhGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_GREEN_DRAGON_COMBAT_TRIGGER:
|
|
ValithriaTriggerGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_PUTRICADES_TRAP:
|
|
PutricadeTrapGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_SINDRAGOSA_GAUNTLET:
|
|
SindragosaGauntletGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_SINDRAGOSA:
|
|
SindragosaGUID = creature->GetGUID();
|
|
if (!HeroicAttempts && GetData(DATA_HAS_LIMITED_ATTEMPTS) && creature->IsAlive())
|
|
creature->SetVisible(false);
|
|
break;
|
|
case NPC_SPINESTALKER:
|
|
SpinestalkerGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_RIMEFANG:
|
|
RimefangGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_INVISIBLE_STALKER:
|
|
// Teleporter visual at center
|
|
if (creature->GetExactDist2d(4357.052f, 2769.421f) < 10.0f && GetBossState(DATA_PROFESSOR_PUTRICIDE) == DONE && GetBossState(DATA_BLOOD_QUEEN_LANA_THEL) == DONE && GetBossState(DATA_SINDRAGOSA) == DONE)
|
|
creature->CastSpell(creature, SPELL_ARTHAS_TELEPORTER_CEREMONY, false);
|
|
break;
|
|
case NPC_THE_LICH_KING:
|
|
TheLichKingGUID = creature->GetGUID();
|
|
if (!HeroicAttempts && GetData(DATA_HAS_LIMITED_ATTEMPTS) && creature->IsAlive())
|
|
creature->SetVisible(false);
|
|
break;
|
|
case NPC_HIGHLORD_TIRION_FORDRING_LK:
|
|
HighlordTirionFordringGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_TERENAS_MENETHIL_FROSTMOURNE:
|
|
case NPC_TERENAS_MENETHIL_FROSTMOURNE_H:
|
|
TerenasMenethilGUID = creature->GetGUID();
|
|
break;
|
|
case NPC_INFILTRATOR_MINCHAR_BQ:
|
|
if (BloodQuickeningState == DONE)
|
|
creature->DespawnOrUnsummon(1);
|
|
break;
|
|
case NPC_MINCHAR_BEAM_STALKER:
|
|
if (BloodQuickeningState != DONE)
|
|
{
|
|
uint32 spellId = 0;
|
|
if (creature->GetPositionY() > 2790.0f && creature->GetPositionZ() > 420.0f)
|
|
spellId = BLOOD_BEAM_VISUAL_RHAND;
|
|
else if (creature->GetPositionY() < 2790.0f && creature->GetPositionZ() > 420.0f)
|
|
spellId = BLOOD_BEAM_VISUAL_LHAND;
|
|
else if (creature->GetPositionY() < 2790.0f && creature->GetPositionZ() < 420.0f)
|
|
spellId = BLOOD_BEAM_VISUAL_LLEG;
|
|
else
|
|
spellId = BLOOD_BEAM_VISUAL_RLEG;
|
|
creature->m_Events.AddEvent(new DelayedCastMincharEvent(creature, spellId), creature->m_Events.CalculateTime(1000));
|
|
}
|
|
break;
|
|
case NPC_SKYBREAKER_DECKHAND:
|
|
case NPC_ORGRIMS_HAMMER_CREW:
|
|
if (!creature->IsAlive())
|
|
creature->Respawn();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
InstanceScript::OnCreatureCreate(creature);
|
|
}
|
|
|
|
void OnCreatureRemove(Creature* creature) override
|
|
{
|
|
if (creature->GetEntry() == NPC_SINDRAGOSA)
|
|
SindragosaGUID.Clear();
|
|
|
|
InstanceScript::OnCreatureRemove(creature);
|
|
}
|
|
|
|
uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override
|
|
{
|
|
if (TeamIdInInstance == TEAM_NEUTRAL)
|
|
{
|
|
Map::PlayerList const& players = instance->GetPlayers();
|
|
if (!players.IsEmpty())
|
|
if (Player* player = players.begin()->GetSource())
|
|
TeamIdInInstance = player->GetTeamId();
|
|
}
|
|
|
|
uint32 entry = data->id1;
|
|
switch (entry)
|
|
{
|
|
case NPC_HORDE_GUNSHIP_CANNON:
|
|
case NPC_ORGRIMS_HAMMER_CREW:
|
|
case NPC_SKY_REAVER_KORM_BLACKSCAR:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
return 0;
|
|
break;
|
|
case NPC_ALLIANCE_GUNSHIP_CANNON:
|
|
case NPC_SKYBREAKER_DECKHAND:
|
|
case NPC_HIGH_CAPTAIN_JUSTIN_BARTLETT:
|
|
if (TeamIdInInstance == TEAM_HORDE)
|
|
return 0;
|
|
break;
|
|
case NPC_ZAFOD_BOOMBOX:
|
|
if (GameObjectTemplate const* go = sObjectMgr->GetGameObjectTemplate(GO_THE_SKYBREAKER_A))
|
|
if ((TeamIdInInstance == TEAM_ALLIANCE && data->mapid == go->moTransport.mapID) ||
|
|
(TeamIdInInstance == TEAM_HORDE && data->mapid != go->moTransport.mapID))
|
|
return entry;
|
|
return 0;
|
|
case NPC_IGB_MURADIN_BRONZEBEARD:
|
|
if ((TeamIdInInstance == TEAM_ALLIANCE && data->posX > 10.0f) ||
|
|
(TeamIdInInstance == TEAM_HORDE && data->posX < 10.0f))
|
|
return entry;
|
|
return 0;
|
|
case NPC_SPIRE_FROSTWYRM:
|
|
if ((TeamIdInInstance == TEAM_ALLIANCE && data->posY < 2200.0f) || (TeamIdInInstance == TEAM_HORDE && data->posY > 2200.0f))
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
|
|
{
|
|
if (TeamIdInInstance == TEAM_NEUTRAL)
|
|
{
|
|
Map::PlayerList const& players = instance->GetPlayers();
|
|
if (!players.IsEmpty())
|
|
if (Player* player = players.begin()->GetSource())
|
|
TeamIdInInstance = player->GetTeamId();
|
|
}
|
|
|
|
switch (entry)
|
|
{
|
|
case GO_GUNSHIP_ARMORY_H_10N:
|
|
case GO_GUNSHIP_ARMORY_H_25N:
|
|
case GO_GUNSHIP_ARMORY_H_10H:
|
|
case GO_GUNSHIP_ARMORY_H_25H:
|
|
if (TeamIdInInstance == TEAM_ALLIANCE)
|
|
return 0;
|
|
break;
|
|
case GO_GUNSHIP_ARMORY_A_10N:
|
|
case GO_GUNSHIP_ARMORY_A_25N:
|
|
case GO_GUNSHIP_ARMORY_A_10H:
|
|
case GO_GUNSHIP_ARMORY_A_25H:
|
|
if (TeamIdInInstance == TEAM_HORDE)
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
void OnUnitDeath(Unit* unit) override
|
|
{
|
|
Creature* creature = unit->ToCreature();
|
|
if (!creature)
|
|
return;
|
|
|
|
// fighting npcs in Rampart of Skulls
|
|
std::string name1("Skybreaker ");
|
|
std::string name2("Kor'kron ");
|
|
if (!creature->GetTransport() && creature->GetPositionZ() <= 205.0f && creature->GetExactDist2d(-439.0f, 2210.0f) <= 150.0f && (creature->GetEntry() == 37544 || creature->GetEntry() == 37545 || creature->GetName().compare(0, name1.length(), name1) == 0 || creature->GetName().compare(0, name2.length(), name2) == 0))
|
|
if (!creature->GetLootRecipient())
|
|
creature->m_Events.AddEvent(new RespawnEvent(*creature), creature->m_Events.CalculateTime(3000));
|
|
|
|
switch (creature->GetEntry())
|
|
{
|
|
case NPC_YMIRJAR_BATTLE_MAIDEN:
|
|
case NPC_YMIRJAR_DEATHBRINGER:
|
|
case NPC_YMIRJAR_FROSTBINDER:
|
|
case NPC_YMIRJAR_HUNTRESS:
|
|
case NPC_YMIRJAR_WARLORD:
|
|
if (Creature* crok = instance->GetCreature(CrokScourgebaneGUID))
|
|
crok->AI()->SetGUID(creature->GetGUID(), ACTION_VRYKUL_DEATH);
|
|
break;
|
|
case NPC_FROSTWING_WHELP:
|
|
if (FrostwyrmGUIDs.empty())
|
|
return;
|
|
|
|
if (creature->AI()->GetData(1/*DATA_FROSTWYRM_OWNER*/) == DATA_SPINESTALKER)
|
|
{
|
|
SpinestalkerTrash.erase(creature->GetSpawnId());
|
|
if (SpinestalkerTrash.empty())
|
|
if (Creature* spinestalk = instance->GetCreature(SpinestalkerGUID))
|
|
spinestalk->AI()->DoAction(ACTION_START_FROSTWYRM);
|
|
}
|
|
else
|
|
{
|
|
RimefangTrash.erase(creature->GetSpawnId());
|
|
if (RimefangTrash.empty())
|
|
if (Creature* spinestalk = instance->GetCreature(RimefangGUID))
|
|
spinestalk->AI()->DoAction(ACTION_START_FROSTWYRM);
|
|
}
|
|
break;
|
|
case NPC_RIMEFANG:
|
|
case NPC_SPINESTALKER:
|
|
{
|
|
if (GetData(DATA_HAS_LIMITED_ATTEMPTS) && !HeroicAttempts)
|
|
return;
|
|
|
|
if (GetBossState(DATA_SINDRAGOSA) == DONE)
|
|
return;
|
|
|
|
FrostwyrmGUIDs.erase(creature->GetSpawnId());
|
|
if (FrostwyrmGUIDs.empty())
|
|
{
|
|
instance->LoadGrid(SindragosaSpawnPos.GetPositionX(), SindragosaSpawnPos.GetPositionY());
|
|
if (Creature* boss = instance->SummonCreature(NPC_SINDRAGOSA, SindragosaSpawnPos))
|
|
boss->AI()->DoAction(ACTION_START_FROSTWYRM);
|
|
}
|
|
break;
|
|
}
|
|
case NPC_DEATHSPEAKER_SERVANT:
|
|
if (Creature* c = unit->SummonCreature(WORLD_TRIGGER, *unit, TEMPSUMMON_TIMED_DESPAWN, 10000))
|
|
{
|
|
c->CastSpell(c, VOID_ZONE_VISUAL, true);
|
|
unit->SummonCreature(NPC_RISEN_DEATHSPEAKER_SERVANT, *unit, TEMPSUMMON_MANUAL_DESPAWN);
|
|
unit->ToCreature()->DespawnOrUnsummon(3000);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OnGameObjectCreate(GameObject* go) override
|
|
{
|
|
if (TeamIdInInstance == TEAM_NEUTRAL)
|
|
{
|
|
Map::PlayerList const& players = instance->GetPlayers();
|
|
if (!players.IsEmpty())
|
|
if (Player* player = players.begin()->GetSource())
|
|
TeamIdInInstance = player->GetTeamId();
|
|
}
|
|
|
|
switch (go->GetEntry())
|
|
{
|
|
case GO_SPIRIT_ALARM_1:
|
|
case GO_SPIRIT_ALARM_2:
|
|
case GO_SPIRIT_ALARM_3:
|
|
case GO_SPIRIT_ALARM_4:
|
|
SetPositionTraps(go);
|
|
break;
|
|
case GO_GEIST_ALARM_1:
|
|
case GO_GEIST_ALARM_2:
|
|
go->SetPosition(go->GetPositionX() + urand(0, 2) * 20.0f * (go->GetEntry() == GO_GEIST_ALARM_1 ? -1.0f : 1.0f), go->GetPositionY(), go->GetPositionZ(), go->GetOrientation());
|
|
break;
|
|
case GO_DOODAD_ICECROWN_ICEWALL02:
|
|
case GO_ICEWALL:
|
|
case GO_LORD_MARROWGAR_S_ENTRANCE:
|
|
case GO_ORATORY_OF_THE_DAMNED_ENTRANCE:
|
|
case GO_ORANGE_PLAGUE_MONSTER_ENTRANCE:
|
|
case GO_GREEN_PLAGUE_MONSTER_ENTRANCE:
|
|
case GO_CRIMSON_HALL_DOOR:
|
|
case GO_BLOOD_ELF_COUNCIL_DOOR:
|
|
case GO_BLOOD_ELF_COUNCIL_DOOR_RIGHT:
|
|
case GO_DOODAD_ICECROWN_BLOODPRINCE_DOOR_01:
|
|
case GO_DOODAD_ICECROWN_GRATE_01:
|
|
case GO_GREEN_DRAGON_BOSS_ENTRANCE:
|
|
case GO_GREEN_DRAGON_BOSS_EXIT:
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02:
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03:
|
|
case GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR:
|
|
case GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR:
|
|
case GO_ICE_WALL:
|
|
case GO_SINDRAGOSA_ENTRANCE_DOOR:
|
|
AddDoor(go);
|
|
break;
|
|
case GO_SCIENTIST_ENTRANCE:
|
|
PutricideEnteranceDoorGUID = go->GetGUID();
|
|
HandleGameObject(PutricideEnteranceDoorGUID, PutricideEventProgress & PUTRICIDE_EVENT_FLAG_TRAP_FINISHED, go);
|
|
break;
|
|
// these 2 gates are functional only on 25man modes
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01:
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04:
|
|
if (instance->Is25ManRaid())
|
|
AddDoor(go);
|
|
break;
|
|
case GO_LADY_DEATHWHISPER_ELEVATOR:
|
|
LadyDeathwisperElevatorGUID = go->GetGUID();
|
|
break;
|
|
case GO_THE_SKYBREAKER_H:
|
|
case GO_ORGRIMS_HAMMER_A:
|
|
EnemyGunshipGUID = go->GetGUID();
|
|
break;
|
|
case GO_GUNSHIP_ARMORY_H_10N:
|
|
case GO_GUNSHIP_ARMORY_H_25N:
|
|
case GO_GUNSHIP_ARMORY_H_10H:
|
|
case GO_GUNSHIP_ARMORY_H_25H:
|
|
case GO_GUNSHIP_ARMORY_A_10N:
|
|
case GO_GUNSHIP_ARMORY_A_25N:
|
|
case GO_GUNSHIP_ARMORY_A_10H:
|
|
case GO_GUNSHIP_ARMORY_A_25H:
|
|
GunshipArmoryGUID = go->GetGUID();
|
|
break;
|
|
case GO_SAURFANG_S_DOOR:
|
|
DeathbringerSaurfangDoorGUID = go->GetGUID();
|
|
AddDoor(go);
|
|
break;
|
|
case GO_DEATHBRINGER_S_CACHE_10N:
|
|
case GO_DEATHBRINGER_S_CACHE_25N:
|
|
case GO_DEATHBRINGER_S_CACHE_10H:
|
|
case GO_DEATHBRINGER_S_CACHE_25H:
|
|
DeathbringersCacheGUID = go->GetGUID();
|
|
break;
|
|
case GO_SCOURGE_TRANSPORTER_SAURFANG:
|
|
SaurfangTeleportGUID = go->GetGUID();
|
|
break;
|
|
case GO_PLAGUE_SIGIL:
|
|
PlagueSigilGUID = go->GetGUID();
|
|
if (GetBossState(DATA_PROFESSOR_PUTRICIDE) == DONE)
|
|
HandleGameObject(PlagueSigilGUID, false, go);
|
|
break;
|
|
case GO_BLOODWING_SIGIL:
|
|
BloodwingSigilGUID = go->GetGUID();
|
|
if (GetBossState(DATA_BLOOD_QUEEN_LANA_THEL) == DONE)
|
|
HandleGameObject(BloodwingSigilGUID, false, go);
|
|
break;
|
|
case GO_SIGIL_OF_THE_FROSTWING:
|
|
FrostwingSigilGUID = go->GetGUID();
|
|
if (GetBossState(DATA_SINDRAGOSA) == DONE)
|
|
HandleGameObject(FrostwingSigilGUID, false, go);
|
|
break;
|
|
case GO_SCIENTIST_AIRLOCK_DOOR_COLLISION:
|
|
PutricideCollisionGUID = go->GetGUID();
|
|
HandleGameObject(PutricideCollisionGUID, ((PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE) && (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE)), go);
|
|
break;
|
|
case GO_SCIENTIST_AIRLOCK_DOOR_ORANGE:
|
|
PutricideGateGUIDs[0] = go->GetGUID();
|
|
if ((PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE) && (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE))
|
|
go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
|
|
else
|
|
HandleGameObject(PutricideGateGUIDs[0], !(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE), go);
|
|
break;
|
|
case GO_SCIENTIST_AIRLOCK_DOOR_GREEN:
|
|
PutricideGateGUIDs[1] = go->GetGUID();
|
|
if ((PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE) && (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE))
|
|
go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
|
|
else
|
|
HandleGameObject(PutricideGateGUIDs[1], !(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE), go);
|
|
break;
|
|
case GO_DOODAD_ICECROWN_ORANGETUBES02:
|
|
PutricidePipeGUIDs[0] = go->GetGUID();
|
|
if (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE)
|
|
HandleGameObject(PutricidePipeGUIDs[0], true, go);
|
|
break;
|
|
case GO_DOODAD_ICECROWN_GREENTUBES02:
|
|
PutricidePipeGUIDs[1] = go->GetGUID();
|
|
if (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE)
|
|
HandleGameObject(PutricidePipeGUIDs[1], true, go);
|
|
break;
|
|
case GO_GAS_RELEASE_VALVE:
|
|
GasReleaseValveGUID = go->GetGUID();
|
|
if (GetBossState(DATA_FESTERGUT) != DONE)
|
|
go->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
|
break;
|
|
case GO_OOZE_RELEASE_VALVE:
|
|
OozeReleaseValveGUID = go->GetGUID();
|
|
if (GetBossState(DATA_ROTFACE) != DONE)
|
|
go->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
|
break;
|
|
case GO_DRINK_ME:
|
|
PutricideTableGUID = go->GetGUID();
|
|
break;
|
|
case GO_CACHE_OF_THE_DREAMWALKER_10N:
|
|
case GO_CACHE_OF_THE_DREAMWALKER_25N:
|
|
case GO_CACHE_OF_THE_DREAMWALKER_10H:
|
|
case GO_CACHE_OF_THE_DREAMWALKER_25H:
|
|
if (Creature* valithria = instance->GetCreature(ValithriaDreamwalkerGUID))
|
|
go->SetLootRecipient(valithria);
|
|
go->RemoveGameObjectFlag(GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
|
|
break;
|
|
case GO_SCOURGE_TRANSPORTER_LK:
|
|
TheLichKingTeleportGUID = go->GetGUID();
|
|
if (GetBossState(DATA_PROFESSOR_PUTRICIDE) == DONE && GetBossState(DATA_BLOOD_QUEEN_LANA_THEL) == DONE && GetBossState(DATA_SINDRAGOSA) == DONE)
|
|
go->SetGoState(GO_STATE_ACTIVE);
|
|
break;
|
|
case GO_ARTHAS_PLATFORM:
|
|
// this enables movement at The Frozen Throne, when printed this value is 0.000000f
|
|
// however, when represented as integer client will accept only this value
|
|
go->SetUInt32Value(GAMEOBJECT_PARENTROTATION, 5535469);
|
|
ArthasPlatformGUID = go->GetGUID();
|
|
break;
|
|
case GO_ARTHAS_PRECIPICE:
|
|
go->SetUInt32Value(GAMEOBJECT_PARENTROTATION, 4178312);
|
|
ArthasPrecipiceGUID = go->GetGUID();
|
|
break;
|
|
case GO_DOODAD_ICECROWN_THRONEFROSTYEDGE01:
|
|
FrozenThroneEdgeGUID = go->GetGUID();
|
|
break;
|
|
case GO_DOODAD_ICECROWN_THRONEFROSTYWIND01:
|
|
FrozenThroneWindGUID = go->GetGUID();
|
|
break;
|
|
case GO_DOODAD_ICECROWN_SNOWEDGEWARNING01:
|
|
FrozenThroneWarningGUID = go->GetGUID();
|
|
break;
|
|
case GO_FROZEN_LAVAMAN:
|
|
FrozenBolvarGUID = go->GetGUID();
|
|
if (GetBossState(DATA_THE_LICH_KING) == DONE)
|
|
go->SetRespawnTime(7 * DAY);
|
|
break;
|
|
case GO_LAVAMAN_PILLARS_CHAINED:
|
|
PillarsChainedGUID = go->GetGUID();
|
|
if (GetBossState(DATA_THE_LICH_KING) == DONE)
|
|
go->SetRespawnTime(7 * DAY);
|
|
break;
|
|
case GO_LAVAMAN_PILLARS_UNCHAINED:
|
|
PillarsUnchainedGUID = go->GetGUID();
|
|
if (GetBossState(DATA_THE_LICH_KING) == DONE)
|
|
go->SetRespawnTime(7 * DAY);
|
|
break;
|
|
case GO_SCOURGE_TRANSPORTER_FIRST:
|
|
AddDoor(go);
|
|
ScourgeTransporterFirstGUID = go->GetGUID();
|
|
if (GetBossState(DATA_LORD_MARROWGAR) == DONE)
|
|
go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OnGameObjectRemove(GameObject* go) override
|
|
{
|
|
switch (go->GetEntry())
|
|
{
|
|
case GO_DOODAD_ICECROWN_ICEWALL02:
|
|
case GO_ICEWALL:
|
|
case GO_LORD_MARROWGAR_S_ENTRANCE:
|
|
case GO_ORATORY_OF_THE_DAMNED_ENTRANCE:
|
|
case GO_SAURFANG_S_DOOR:
|
|
case GO_ORANGE_PLAGUE_MONSTER_ENTRANCE:
|
|
case GO_GREEN_PLAGUE_MONSTER_ENTRANCE:
|
|
case GO_SCIENTIST_ENTRANCE:
|
|
case GO_CRIMSON_HALL_DOOR:
|
|
case GO_BLOOD_ELF_COUNCIL_DOOR:
|
|
case GO_BLOOD_ELF_COUNCIL_DOOR_RIGHT:
|
|
case GO_DOODAD_ICECROWN_BLOODPRINCE_DOOR_01:
|
|
case GO_DOODAD_ICECROWN_GRATE_01:
|
|
case GO_GREEN_DRAGON_BOSS_ENTRANCE:
|
|
case GO_GREEN_DRAGON_BOSS_EXIT:
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01:
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02:
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03:
|
|
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04:
|
|
//case GO_SINDRAGOSA_ENTRANCE_DOOR:
|
|
case GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR:
|
|
case GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR:
|
|
case GO_ICE_WALL:
|
|
case GO_SCOURGE_TRANSPORTER_FIRST:
|
|
RemoveDoor(go);
|
|
break;
|
|
case GO_THE_SKYBREAKER_A:
|
|
case GO_ORGRIMS_HAMMER_H:
|
|
GunshipGUID.Clear();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32 GetData(uint32 type) const override
|
|
{
|
|
switch (type)
|
|
{
|
|
case DATA_BUFF_AVAILABLE:
|
|
return (IsBuffAvailable ? 1 : 0);
|
|
case DATA_WEEKLY_QUEST_ID:
|
|
return WeeklyQuestId10;
|
|
case DATA_PUTRICIDE_TRAP_STATE:
|
|
if (!(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE) || !(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE))
|
|
return TO_BE_DECIDED;
|
|
if (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_TRAP_INPROGRESS)
|
|
return IN_PROGRESS;
|
|
if (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_TRAP_FINISHED)
|
|
return DONE;
|
|
return NOT_STARTED;
|
|
case DATA_HAS_LIMITED_ATTEMPTS:
|
|
return (instance->IsHeroic() ? 1 : 0);
|
|
case DATA_LK_HC_AVAILABLE:
|
|
return (LichKingHeroicAvailable ? 1 : 0);
|
|
case DATA_SINDRAGOSA_FROSTWYRMS:
|
|
return FrostwyrmGUIDs.size();
|
|
case DATA_SPINESTALKER:
|
|
return SpinestalkerTrash.size();
|
|
case DATA_RIMEFANG:
|
|
return RimefangTrash.size();
|
|
case DATA_COLDFLAME_JETS:
|
|
return ColdflameJetsState;
|
|
case DATA_TEAMID_IN_INSTANCE:
|
|
return TeamIdInInstance;
|
|
case DATA_BLOOD_QUICKENING_STATE:
|
|
return BloodQuickeningState;
|
|
case DATA_HEROIC_ATTEMPTS:
|
|
return HeroicAttempts;
|
|
case DATA_SINDRAGOSA_INTRO:
|
|
return (IsSindragosaIntroDone ? 1 : 0);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ObjectGuid GetGuidData(uint32 type) const override
|
|
{
|
|
switch (type)
|
|
{
|
|
case DATA_LADY_DEATHWHISPER:
|
|
return LadyDeathwhisperGUID;
|
|
case DATA_ICECROWN_GUNSHIP_BATTLE:
|
|
return GunshipGUID;
|
|
case DATA_ENEMY_GUNSHIP:
|
|
return EnemyGunshipGUID;
|
|
case DATA_DEATHBRINGER_SAURFANG:
|
|
return DeathbringerSaurfangGUID;
|
|
case DATA_SAURFANG_EVENT_NPC:
|
|
return DeathbringerSaurfangEventGUID;
|
|
case GO_SAURFANG_S_DOOR:
|
|
return DeathbringerSaurfangDoorGUID;
|
|
case GO_SCOURGE_TRANSPORTER_SAURFANG:
|
|
return SaurfangTeleportGUID;
|
|
case DATA_FESTERGUT:
|
|
return FestergutGUID;
|
|
case DATA_ROTFACE:
|
|
return RotfaceGUID;
|
|
case DATA_PROFESSOR_PUTRICIDE:
|
|
return ProfessorPutricideGUID;
|
|
case DATA_PUTRICIDE_TABLE:
|
|
return PutricideTableGUID;
|
|
case DATA_PRINCE_KELESETH_GUID:
|
|
return BloodCouncilGUIDs[0];
|
|
case DATA_PRINCE_TALDARAM_GUID:
|
|
return BloodCouncilGUIDs[1];
|
|
case DATA_PRINCE_VALANAR_GUID:
|
|
return BloodCouncilGUIDs[2];
|
|
case DATA_BLOOD_PRINCES_CONTROL:
|
|
return BloodCouncilControllerGUID;
|
|
case DATA_BLOOD_QUEEN_LANA_THEL:
|
|
return BloodQueenLanaThelGUID;
|
|
case DATA_CROK_SCOURGEBANE:
|
|
return CrokScourgebaneGUID;
|
|
case DATA_CAPTAIN_ARNATH:
|
|
case DATA_CAPTAIN_BRANDON:
|
|
case DATA_CAPTAIN_GRONDEL:
|
|
case DATA_CAPTAIN_RUPERT:
|
|
return CrokCaptainGUIDs[type - DATA_CAPTAIN_ARNATH];
|
|
case DATA_SISTER_SVALNA:
|
|
return SisterSvalnaGUID;
|
|
case DATA_VALITHRIA_DREAMWALKER:
|
|
return ValithriaDreamwalkerGUID;
|
|
case DATA_VALITHRIA_LICH_KING:
|
|
return ValithriaLichKingGUID;
|
|
case DATA_VALITHRIA_TRIGGER:
|
|
return ValithriaTriggerGUID;
|
|
case NPC_SINDRAGOSA_GAUNTLET:
|
|
return SindragosaGauntletGUID;
|
|
case NPC_PUTRICADES_TRAP:
|
|
return PutricadeTrapGUID;
|
|
case DATA_SINDRAGOSA:
|
|
return SindragosaGUID;
|
|
case DATA_SPINESTALKER:
|
|
return SpinestalkerGUID;
|
|
case DATA_RIMEFANG:
|
|
return RimefangGUID;
|
|
case DATA_THE_LICH_KING:
|
|
return TheLichKingGUID;
|
|
case DATA_HIGHLORD_TIRION_FORDRING:
|
|
return HighlordTirionFordringGUID;
|
|
case DATA_ARTHAS_PLATFORM:
|
|
return ArthasPlatformGUID;
|
|
case DATA_TERENAS_MENETHIL:
|
|
return TerenasMenethilGUID;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ObjectGuid::Empty;
|
|
}
|
|
|
|
void HandleDropAttempt(bool drop = true)
|
|
{
|
|
if (!GetData(DATA_HAS_LIMITED_ATTEMPTS))
|
|
return;
|
|
if (drop && HeroicAttempts)
|
|
{
|
|
--HeroicAttempts;
|
|
DoUpdateWorldState(WORLDSTATE_ATTEMPTS_REMAINING, HeroicAttempts);
|
|
SaveToDB();
|
|
}
|
|
if (HeroicAttempts)
|
|
return;
|
|
if (GetBossState(DATA_ROTFACE) == DONE && GetBossState(DATA_FESTERGUT) == DONE)
|
|
if (Creature* professor = instance->GetCreature(ProfessorPutricideGUID))
|
|
if (professor->IsAlive())
|
|
professor->SetVisible(false);
|
|
if (Creature* bq = instance->GetCreature(BloodQueenLanaThelGUID))
|
|
if (bq->IsAlive())
|
|
bq->SetVisible(false);
|
|
if (Creature* sindra = instance->GetCreature(SindragosaGUID))
|
|
if (sindra->IsAlive())
|
|
sindra->SetVisible(false);
|
|
if (Creature* theLichKing = instance->GetCreature(TheLichKingGUID))
|
|
if (theLichKing->IsAlive())
|
|
theLichKing->SetVisible(false);
|
|
}
|
|
|
|
void RemoveBackPack()
|
|
{
|
|
for (auto const& itr : instance->GetPlayers())
|
|
if (Player* _player = itr.GetSource())
|
|
_player->DestroyItemCount(ITEM_GOBLIN_ROCKET_PACK, _player->GetItemCount(ITEM_GOBLIN_ROCKET_PACK), true);
|
|
}
|
|
|
|
bool SetBossState(uint32 type, EncounterState state) override
|
|
{
|
|
if (!InstanceScript::SetBossState(type, state))
|
|
return false;
|
|
|
|
switch (type)
|
|
{
|
|
case DATA_LORD_MARROWGAR:
|
|
if (state == DONE)
|
|
{
|
|
WeeklyQuestId10 = RAND(QUEST_BLOOD_QUICKENING_10, QUEST_RESIDUE_RENDEZVOUS_10, QUEST_RESPITE_FOR_A_TORMENTED_SOUL_10, QUEST_DEPROGRAMMING_10, QUEST_SECURING_THE_RAMPARTS_10);
|
|
SetData(DATA_WEEKLY_QUEST_ID, 0); // show required hidden npcs
|
|
if (GameObject* transporter = instance->GetGameObject(ScourgeTransporterFirstGUID))
|
|
transporter->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
|
SaveToDB();
|
|
}
|
|
break;
|
|
case DATA_LADY_DEATHWHISPER:
|
|
if (state == DONE)
|
|
SpawnGunship();
|
|
break;
|
|
case DATA_ICECROWN_GUNSHIP_BATTLE:
|
|
if (state == DONE)
|
|
{
|
|
if (GameObject* loot = instance->GetGameObject(GunshipArmoryGUID))
|
|
{
|
|
loot->SetLootRecipient(instance);
|
|
loot->RemoveGameObjectFlag(GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
|
|
}
|
|
}
|
|
else if (state == FAIL)
|
|
Events.ScheduleEvent(EVENT_RESPAWN_GUNSHIP, 30s);
|
|
break;
|
|
case DATA_DEATHBRINGER_SAURFANG:
|
|
switch (state)
|
|
{
|
|
case DONE:
|
|
if (GameObject* loot = instance->GetGameObject(DeathbringersCacheGUID))
|
|
{
|
|
if (Creature* deathbringer = instance->GetCreature(DeathbringerSaurfangGUID))
|
|
loot->SetLootRecipient(deathbringer);
|
|
loot->RemoveGameObjectFlag(GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
|
|
}
|
|
[[fallthrough]];
|
|
case NOT_STARTED:
|
|
if (GameObject* teleporter = instance->GetGameObject(SaurfangTeleportGUID))
|
|
{
|
|
HandleGameObject(SaurfangTeleportGUID, true, teleporter);
|
|
teleporter->RemoveGameObjectFlag(GO_FLAG_IN_USE);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case DATA_FESTERGUT:
|
|
if (state == DONE)
|
|
{
|
|
if (GameObject* go = instance->GetGameObject(GasReleaseValveGUID))
|
|
go->RemoveGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
|
if (GetBossState(DATA_ROTFACE) == DONE)
|
|
HandleDropAttempt(false);
|
|
}
|
|
break;
|
|
case DATA_ROTFACE:
|
|
if (state == DONE)
|
|
{
|
|
if (GameObject* go = instance->GetGameObject(OozeReleaseValveGUID))
|
|
go->RemoveGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
|
if (GetBossState(DATA_FESTERGUT) == DONE)
|
|
HandleDropAttempt(false);
|
|
}
|
|
break;
|
|
case DATA_PROFESSOR_PUTRICIDE:
|
|
HandleGameObject(PutricideEnteranceDoorGUID, (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_TRAP_FINISHED) && state != IN_PROGRESS);
|
|
HandleGameObject(PlagueSigilGUID, state != DONE);
|
|
if (state == DONE)
|
|
CheckLichKingAvailability();
|
|
else if (state == FAIL)
|
|
HandleDropAttempt();
|
|
if (state == DONE && !instance->IsHeroic() && LichKingHeroicAvailable)
|
|
{
|
|
LichKingHeroicAvailable = false;
|
|
SaveToDB();
|
|
}
|
|
break;
|
|
case DATA_BLOOD_QUEEN_LANA_THEL:
|
|
HandleGameObject(BloodwingSigilGUID, state != DONE);
|
|
if (state == DONE)
|
|
CheckLichKingAvailability();
|
|
else if (state == FAIL)
|
|
HandleDropAttempt();
|
|
if (state == DONE && !instance->IsHeroic() && LichKingHeroicAvailable)
|
|
{
|
|
LichKingHeroicAvailable = false;
|
|
SaveToDB();
|
|
}
|
|
break;
|
|
case DATA_VALITHRIA_DREAMWALKER:
|
|
if (state == DONE)
|
|
SetData(DATA_WEEKLY_QUEST_ID, GetData(DATA_WEEKLY_QUEST_ID)); // will show weekly quest npc if necessary
|
|
break;
|
|
case DATA_SINDRAGOSA:
|
|
HandleGameObject(FrostwingSigilGUID, state != DONE);
|
|
if (state == DONE)
|
|
CheckLichKingAvailability();
|
|
else if (state == FAIL)
|
|
{
|
|
IsSindragosaIntroDone = true;
|
|
HandleDropAttempt();
|
|
if (instance->IsHeroic())
|
|
{
|
|
if (HeroicAttempts)
|
|
{
|
|
Events.ScheduleEvent(EVENT_RESPAWN_SINDRAGOSA, 30s);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Events.ScheduleEvent(EVENT_RESPAWN_SINDRAGOSA, 30s);
|
|
}
|
|
}
|
|
if (state == DONE && !instance->IsHeroic() && LichKingHeroicAvailable)
|
|
{
|
|
LichKingHeroicAvailable = false;
|
|
SaveToDB();
|
|
}
|
|
break;
|
|
case DATA_THE_LICH_KING:
|
|
{
|
|
// dramatically increase visibility range during fight to seeing frostmourne room
|
|
instance->SetVisibilityRange(state == IN_PROGRESS ? 500.0f : 200.0f);
|
|
|
|
if (state == FAIL)
|
|
{
|
|
Events.CancelEvent(EVENT_QUAKE_SHATTER);
|
|
Events.CancelEvent(EVENT_REBUILD_PLATFORM);
|
|
|
|
HandleDropAttempt();
|
|
}
|
|
|
|
if (state == DONE)
|
|
{
|
|
if (GameObject* bolvar = instance->GetGameObject(FrozenBolvarGUID))
|
|
bolvar->SetRespawnTime(7 * DAY);
|
|
if (GameObject* pillars = instance->GetGameObject(PillarsChainedGUID))
|
|
pillars->SetRespawnTime(7 * DAY);
|
|
if (GameObject* pillars = instance->GetGameObject(PillarsUnchainedGUID))
|
|
pillars->SetRespawnTime(7 * DAY);
|
|
|
|
instance->LoadGrid(JainaSpawnPos.GetPositionX(), JainaSpawnPos.GetPositionY());
|
|
instance->SummonCreature(NPC_LADY_JAINA_PROUDMOORE_QUEST, JainaSpawnPos);
|
|
instance->SummonCreature(NPC_MURADIN_BRONZEBEARD_QUEST, MuradinSpawnPos);
|
|
instance->SummonCreature(NPC_UTHER_THE_LIGHTBRINGER_QUEST, UtherSpawnPos);
|
|
instance->SummonCreature(NPC_LADY_SYLVANAS_WINDRUNNER_QUEST, SylvanasSpawnPos);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SpawnGunship()
|
|
{
|
|
if (!GunshipGUID && instance->HavePlayers())
|
|
{
|
|
SetBossState(DATA_ICECROWN_GUNSHIP_BATTLE, NOT_STARTED);
|
|
uint32 gunshipEntry = TeamIdInInstance == TEAM_HORDE ? GO_ORGRIMS_HAMMER_H : GO_THE_SKYBREAKER_A;
|
|
if (MotionTransport* gunship = sTransportMgr->CreateTransport(gunshipEntry, 0, instance))
|
|
{
|
|
GunshipGUID = gunship->GetGUID();
|
|
gunship->setActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetData(uint32 type, uint32 data) override
|
|
{
|
|
switch (type)
|
|
{
|
|
case DATA_BUFF_AVAILABLE:
|
|
IsBuffAvailable = !!data;
|
|
if (!IsBuffAvailable)
|
|
{
|
|
instance->DoForAllPlayers([&](Player* player)
|
|
{
|
|
player->UpdateAreaDependentAuras(player->GetAreaId());
|
|
for (Unit::ControlSet::const_iterator itr = player->m_Controlled.begin(); itr != player->m_Controlled.end(); ++itr)
|
|
{
|
|
Unit::AuraMap& am = (*itr)->GetOwnedAuras();
|
|
for (Unit::AuraMap::iterator itra = am.begin(); itra != am.end();)
|
|
switch (itra->second->GetId())
|
|
{
|
|
// Hellscream's Warsong
|
|
case 73816:
|
|
case 73818:
|
|
case 73819:
|
|
case 73820:
|
|
case 73821:
|
|
case 73822:
|
|
// Strength of Wrynn
|
|
case 73762:
|
|
case 73824:
|
|
case 73825:
|
|
case 73826:
|
|
case 73827:
|
|
case 73828:
|
|
(*itr)->RemoveOwnedAura(itra);
|
|
break;
|
|
default:
|
|
++itra;
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
SaveToDB();
|
|
break;
|
|
case DATA_WEEKLY_QUEST_ID:
|
|
for (uint8 i = 0; i < WeeklyNPCs; ++i)
|
|
if (WeeklyQuestData[i].questId[0] == WeeklyQuestId10 && (WeeklyQuestData[i].creatureEntry != NPC_VALITHRIA_DREAMWALKER_QUEST || GetBossState(DATA_VALITHRIA_DREAMWALKER) == DONE) /*appears after killing valithria*/)
|
|
if (WeeklyQuestNpcGUID[i])
|
|
if (Creature* c = instance->GetCreature(WeeklyQuestNpcGUID[i]))
|
|
c->SetVisible(true);
|
|
break;
|
|
case DATA_PUTRICIDE_TRAP_STATE:
|
|
if (data == NOT_STARTED)
|
|
{
|
|
PutricideEventProgress &= ~PUTRICIDE_EVENT_FLAG_TRAP_INPROGRESS;
|
|
HandleGameObject(PutricideCollisionGUID, ((PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE) && (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE)));
|
|
if ((PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE) && (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE))
|
|
{
|
|
for (uint8 i = 0; i < 2; ++i)
|
|
if (GameObject* go = instance->GetGameObject(PutricideGateGUIDs[i]))
|
|
go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
|
|
}
|
|
else
|
|
{
|
|
HandleGameObject(PutricideGateGUIDs[0], !(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE));
|
|
HandleGameObject(PutricideGateGUIDs[1], !(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE));
|
|
}
|
|
SaveToDB();
|
|
}
|
|
else if (data == IN_PROGRESS)
|
|
{
|
|
PutricideEventProgress |= PUTRICIDE_EVENT_FLAG_TRAP_INPROGRESS;
|
|
HandleGameObject(PutricideCollisionGUID, false);
|
|
HandleGameObject(PutricideGateGUIDs[0], false);
|
|
HandleGameObject(PutricideGateGUIDs[1], false);
|
|
SaveToDB();
|
|
}
|
|
else if (data == DONE)
|
|
{
|
|
PutricideEventProgress &= ~PUTRICIDE_EVENT_FLAG_TRAP_INPROGRESS;
|
|
PutricideEventProgress |= PUTRICIDE_EVENT_FLAG_TRAP_FINISHED;
|
|
HandleGameObject(PutricideEnteranceDoorGUID, true);
|
|
HandleGameObject(PutricideCollisionGUID, ((PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE) && (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE)));
|
|
if ((PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE) && (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE))
|
|
{
|
|
for (uint8 i = 0; i < 2; ++i)
|
|
if (GameObject* go = instance->GetGameObject(PutricideGateGUIDs[i]))
|
|
go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
|
|
}
|
|
else
|
|
{
|
|
HandleGameObject(PutricideGateGUIDs[0], !(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE));
|
|
HandleGameObject(PutricideGateGUIDs[1], !(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE));
|
|
}
|
|
SaveToDB();
|
|
}
|
|
return;
|
|
case DATA_BONED_ACHIEVEMENT:
|
|
IsBonedEligible = !!data;
|
|
break;
|
|
case DATA_OOZE_DANCE_ACHIEVEMENT:
|
|
IsOozeDanceEligible = !!data;
|
|
break;
|
|
case DATA_NAUSEA_ACHIEVEMENT:
|
|
IsNauseaEligible = !!data;
|
|
break;
|
|
case DATA_ORB_WHISPERER_ACHIEVEMENT:
|
|
IsOrbWhispererEligible = !!data;
|
|
break;
|
|
case DATA_SINDRAGOSA_FROSTWYRMS:
|
|
FrostwyrmGUIDs.insert(data);
|
|
break;
|
|
case DATA_SPINESTALKER:
|
|
SpinestalkerTrash.insert(data);
|
|
break;
|
|
case DATA_RIMEFANG:
|
|
RimefangTrash.insert(data);
|
|
break;
|
|
case DATA_COLDFLAME_JETS:
|
|
ColdflameJetsState = data;
|
|
if (ColdflameJetsState == DONE)
|
|
SaveToDB();
|
|
break;
|
|
case DATA_BLOOD_QUICKENING_STATE:
|
|
{
|
|
if (data == IN_PROGRESS && BloodQuickeningState != NOT_STARTED)
|
|
break;
|
|
if (BloodQuickeningState == data)
|
|
break;
|
|
if (WeeklyQuestId10 != QUEST_BLOOD_QUICKENING_10)
|
|
break;
|
|
|
|
switch (data)
|
|
{
|
|
case IN_PROGRESS:
|
|
Events.ScheduleEvent(EVENT_UPDATE_EXECUTION_TIME, 1min);
|
|
BloodQuickeningMinutes = 30;
|
|
DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1);
|
|
DoUpdateWorldState(WORLDSTATE_EXECUTION_TIME, BloodQuickeningMinutes);
|
|
break;
|
|
case DONE:
|
|
Events.CancelEvent(EVENT_UPDATE_EXECUTION_TIME);
|
|
BloodQuickeningMinutes = 0;
|
|
DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
BloodQuickeningState = data;
|
|
SaveToDB();
|
|
break;
|
|
}
|
|
case DATA_BPC_TRASH_DIED:
|
|
{
|
|
if (++BloodPrinceTrashCount >= 4)
|
|
{
|
|
SetBossState(DATA_BLOOD_PRINCE_TRASH, NOT_STARTED);
|
|
SetBossState(DATA_BLOOD_PRINCE_TRASH, DONE);
|
|
}
|
|
SaveToDB();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override
|
|
{
|
|
switch (criteria_id)
|
|
{
|
|
case CRITERIA_BONED_10N:
|
|
case CRITERIA_BONED_25N:
|
|
case CRITERIA_BONED_10H:
|
|
case CRITERIA_BONED_25H:
|
|
return IsBonedEligible;
|
|
case CRITERIA_DANCES_WITH_OOZES_10N:
|
|
case CRITERIA_DANCES_WITH_OOZES_25N:
|
|
case CRITERIA_DANCES_WITH_OOZES_10H:
|
|
case CRITERIA_DANCES_WITH_OOZES_25H:
|
|
return IsOozeDanceEligible;
|
|
case CRITERIA_NAUSEA_10N:
|
|
case CRITERIA_NAUSEA_25N:
|
|
case CRITERIA_NAUSEA_10H:
|
|
case CRITERIA_NAUSEA_25H:
|
|
return IsNauseaEligible;
|
|
case CRITERIA_ORB_WHISPERER_10N:
|
|
case CRITERIA_ORB_WHISPERER_25N:
|
|
case CRITERIA_ORB_WHISPERER_10H:
|
|
case CRITERIA_ORB_WHISPERER_25H:
|
|
return IsOrbWhispererEligible;
|
|
// Only one criteria for both modes, need to do it like this
|
|
case CRITERIA_KILL_LANA_THEL_10M:
|
|
return instance->ToInstanceMap()->GetMaxPlayers() == 10;
|
|
case CRITERIA_KILL_LANA_THEL_25M:
|
|
return instance->ToInstanceMap()->GetMaxPlayers() == 25;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CheckRequiredBosses(uint32 bossId, Player const* player) const override
|
|
{
|
|
if (player && player->GetSession() && player->GetSession()->GetSecurity() >= SEC_MODERATOR)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
switch (bossId)
|
|
{
|
|
case DATA_THE_LICH_KING:
|
|
if (!CheckPlagueworks(bossId))
|
|
return false;
|
|
if (!CheckCrimsonHalls(bossId))
|
|
return false;
|
|
if (!CheckFrostwingHalls(bossId))
|
|
return false;
|
|
break;
|
|
case DATA_SINDRAGOSA:
|
|
case DATA_VALITHRIA_DREAMWALKER:
|
|
if (!CheckFrostwingHalls(bossId))
|
|
return false;
|
|
break;
|
|
case DATA_BLOOD_QUEEN_LANA_THEL:
|
|
case DATA_BLOOD_PRINCE_COUNCIL:
|
|
if (!CheckCrimsonHalls(bossId))
|
|
return false;
|
|
break;
|
|
case DATA_FESTERGUT:
|
|
case DATA_ROTFACE:
|
|
case DATA_PROFESSOR_PUTRICIDE:
|
|
if (!CheckPlagueworks(bossId))
|
|
return false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!CheckLowerSpire(bossId))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CheckPlagueworks(uint32 bossId) const
|
|
{
|
|
switch (bossId)
|
|
{
|
|
case DATA_THE_LICH_KING:
|
|
if (GetBossState(DATA_PROFESSOR_PUTRICIDE) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
[[fallthrough]];
|
|
case DATA_PROFESSOR_PUTRICIDE:
|
|
if (GetBossState(DATA_FESTERGUT) != DONE || GetBossState(DATA_ROTFACE) != DONE)
|
|
return false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CheckCrimsonHalls(uint32 bossId) const
|
|
{
|
|
switch (bossId)
|
|
{
|
|
case DATA_THE_LICH_KING:
|
|
if (GetBossState(DATA_BLOOD_QUEEN_LANA_THEL) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
[[fallthrough]];
|
|
case DATA_BLOOD_QUEEN_LANA_THEL:
|
|
if (GetBossState(DATA_BLOOD_PRINCE_COUNCIL) != DONE)
|
|
return false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CheckFrostwingHalls(uint32 bossId) const
|
|
{
|
|
switch (bossId)
|
|
{
|
|
case DATA_THE_LICH_KING:
|
|
if (GetBossState(DATA_SINDRAGOSA) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
[[fallthrough]];
|
|
case DATA_SINDRAGOSA:
|
|
if (GetBossState(DATA_VALITHRIA_DREAMWALKER) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
if (GetBossState(DATA_SINDRAGOSA_GAUNTLET) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CheckLowerSpire(uint32 bossId) const
|
|
{
|
|
switch (bossId)
|
|
{
|
|
case DATA_THE_LICH_KING:
|
|
case DATA_SINDRAGOSA:
|
|
case DATA_BLOOD_QUEEN_LANA_THEL:
|
|
case DATA_PROFESSOR_PUTRICIDE:
|
|
case DATA_VALITHRIA_DREAMWALKER:
|
|
case DATA_BLOOD_PRINCE_COUNCIL:
|
|
case DATA_ROTFACE:
|
|
case DATA_FESTERGUT:
|
|
if (GetBossState(DATA_DEATHBRINGER_SAURFANG) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
[[fallthrough]];
|
|
case DATA_DEATHBRINGER_SAURFANG:
|
|
if (GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
[[fallthrough]];
|
|
case DATA_ICECROWN_GUNSHIP_BATTLE:
|
|
if (GetBossState(DATA_LADY_DEATHWHISPER) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
[[fallthrough]];
|
|
case DATA_LADY_DEATHWHISPER:
|
|
if (GetBossState(DATA_LORD_MARROWGAR) != DONE)
|
|
{
|
|
return false;
|
|
}
|
|
[[fallthrough]];
|
|
case DATA_LORD_MARROWGAR:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CheckLichKingAvailability()
|
|
{
|
|
if (GetBossState(DATA_PROFESSOR_PUTRICIDE) == DONE && GetBossState(DATA_BLOOD_QUEEN_LANA_THEL) == DONE && GetBossState(DATA_SINDRAGOSA) == DONE)
|
|
{
|
|
if (GameObject* teleporter = instance->GetGameObject(TheLichKingTeleportGUID))
|
|
{
|
|
teleporter->SetGoState(GO_STATE_ACTIVE);
|
|
|
|
std::list<Creature*> stalkers;
|
|
GetCreatureListWithEntryInGrid(stalkers, teleporter, NPC_INVISIBLE_STALKER, 100.0f);
|
|
if (stalkers.empty())
|
|
return;
|
|
|
|
stalkers.sort(Acore::ObjectDistanceOrderPred(teleporter));
|
|
stalkers.front()->CastSpell((Unit*)nullptr, SPELL_ARTHAS_TELEPORTER_CEREMONY, false);
|
|
stalkers.pop_front();
|
|
for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr)
|
|
(*itr)->AI()->Reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReadSaveDataMore(std::istringstream& data) override
|
|
{
|
|
data >> HeroicAttempts;
|
|
|
|
uint32 temp = 0;
|
|
data >> temp;
|
|
|
|
if (temp == IN_PROGRESS)
|
|
{
|
|
ColdflameJetsState = NOT_STARTED;
|
|
}
|
|
else
|
|
{
|
|
ColdflameJetsState = temp ? DONE : NOT_STARTED;
|
|
}
|
|
|
|
data >> BloodQuickeningState;
|
|
data >> BloodQuickeningMinutes;
|
|
|
|
if (BloodQuickeningState == IN_PROGRESS)
|
|
{
|
|
Events.ScheduleEvent(EVENT_UPDATE_EXECUTION_TIME, 1min);
|
|
DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1);
|
|
DoUpdateWorldState(WORLDSTATE_EXECUTION_TIME, BloodQuickeningMinutes);
|
|
}
|
|
|
|
data >> WeeklyQuestId10;
|
|
data >> PutricideEventProgress;
|
|
PutricideEventProgress &= ~PUTRICIDE_EVENT_FLAG_TRAP_INPROGRESS;
|
|
data >> LichKingHeroicAvailable;
|
|
data >> BloodPrinceTrashCount;
|
|
data >> IsBuffAvailable;
|
|
data >> IsSindragosaIntroDone;
|
|
SetData(DATA_BUFF_AVAILABLE, IsBuffAvailable);
|
|
}
|
|
|
|
void WriteSaveDataMore(std::ostringstream& data) override
|
|
{
|
|
data << HeroicAttempts << ' '
|
|
<< ColdflameJetsState << ' '
|
|
<< BloodQuickeningState << ' '
|
|
<< BloodQuickeningMinutes << ' '
|
|
<< WeeklyQuestId10 << ' '
|
|
<< PutricideEventProgress << ' '
|
|
<< uint32(LichKingHeroicAvailable ? 1 : 0) << ' '
|
|
<< BloodPrinceTrashCount << ' '
|
|
<< uint32(IsBuffAvailable ? 1 : 0) << ' '
|
|
<< uint32(IsSindragosaIntroDone ? 1 : 0);
|
|
}
|
|
|
|
void Update(uint32 diff) override
|
|
{
|
|
// Xinef: A Feast of Souls (24547) whispers
|
|
if (LichKingRandomWhisperTimer <= diff)
|
|
{
|
|
LichKingRandomWhisperTimer = urand(100, 300) * IN_MILLISECONDS;
|
|
Map::PlayerList const& players = instance->GetPlayers();
|
|
if (!players.IsEmpty())
|
|
if (Player* player = players.begin()->GetSource())
|
|
if (player->GetQuestStatus(QUEST_A_FEAST_OF_SOULS) == QUEST_STATUS_INCOMPLETE)
|
|
{
|
|
if (Creature* theLichKing = instance->GetCreature(TheLichKingLhGUID))
|
|
{
|
|
theLichKing->AI()->Talk(SAY_SOULS_LICH_KING_RAND_WHISPER, player);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
LichKingRandomWhisperTimer -= diff;
|
|
|
|
if (DarkwhisperElevatorTimer <= diff)
|
|
{
|
|
DarkwhisperElevatorTimer = 3000;
|
|
if (GetBossState(DATA_LADY_DEATHWHISPER) == DONE)
|
|
if (GameObject* elevator = instance->GetGameObject(LadyDeathwisperElevatorGUID))
|
|
if (StaticTransport* trans = elevator->ToStaticTransport())
|
|
{
|
|
if (trans->GetGoState() == GO_STATE_READY && trans->GetPathProgress() == 0)
|
|
trans->SetGoState(GO_STATE_ACTIVE);
|
|
else if (trans->GetGoState() == GO_STATE_ACTIVE && trans->GetPathProgress() == trans->GetPauseTime())
|
|
trans->SetGoState(GO_STATE_READY);
|
|
}
|
|
}
|
|
else
|
|
DarkwhisperElevatorTimer -= diff;
|
|
|
|
if (Events.Empty())
|
|
return;
|
|
|
|
Events.Update(diff);
|
|
|
|
while (uint32 eventId = Events.ExecuteEvent())
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_UPDATE_EXECUTION_TIME:
|
|
{
|
|
--BloodQuickeningMinutes;
|
|
if (BloodQuickeningMinutes)
|
|
{
|
|
Events.ScheduleEvent(EVENT_UPDATE_EXECUTION_TIME, 1min);
|
|
DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1);
|
|
DoUpdateWorldState(WORLDSTATE_EXECUTION_TIME, BloodQuickeningMinutes);
|
|
}
|
|
else
|
|
{
|
|
BloodQuickeningState = DONE;
|
|
DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0);
|
|
if (Creature* bq = instance->GetCreature(BloodQueenLanaThelGUID))
|
|
bq->AI()->DoAction(ACTION_KILL_MINCHAR);
|
|
}
|
|
SaveToDB();
|
|
break;
|
|
}
|
|
case EVENT_QUAKE_SHATTER:
|
|
{
|
|
if (GameObject* platform = instance->GetGameObject(ArthasPlatformGUID))
|
|
platform->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
|
|
if (GameObject* edge = instance->GetGameObject(FrozenThroneEdgeGUID))
|
|
edge->SetGoState(GO_STATE_ACTIVE);
|
|
if (GameObject* wind = instance->GetGameObject(FrozenThroneWindGUID))
|
|
wind->SetGoState(GO_STATE_READY);
|
|
if (GameObject* warning = instance->GetGameObject(FrozenThroneWarningGUID))
|
|
warning->SetGoState(GO_STATE_READY);
|
|
if (Creature* theLichKing = instance->GetCreature(TheLichKingGUID))
|
|
theLichKing->AI()->DoAction(ACTION_RESTORE_LIGHT);
|
|
break;
|
|
}
|
|
case EVENT_REBUILD_PLATFORM:
|
|
if (GameObject* platform = instance->GetGameObject(ArthasPlatformGUID))
|
|
platform->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, nullptr, true);
|
|
if (GameObject* edge = instance->GetGameObject(FrozenThroneEdgeGUID))
|
|
edge->SetGoState(GO_STATE_READY);
|
|
if (GameObject* wind = instance->GetGameObject(FrozenThroneWindGUID))
|
|
wind->SetGoState(GO_STATE_ACTIVE);
|
|
break;
|
|
case EVENT_RESPAWN_GUNSHIP:
|
|
SpawnGunship();
|
|
break;
|
|
case EVENT_RESPAWN_SINDRAGOSA:
|
|
if (!GetCreature(DATA_SINDRAGOSA))
|
|
{
|
|
if (Creature* sindragosa = instance->SummonCreature(NPC_SINDRAGOSA, SindragosaSpawnPos))
|
|
{
|
|
sindragosa->setActive(true);
|
|
sindragosa->SetDisableGravity(true);
|
|
sindragosa->GetMotionMaster()->MovePath(NPC_SINDRAGOSA * 10, true);
|
|
|
|
if (TempSummon* summon = sindragosa->ToTempSummon())
|
|
{
|
|
summon->SetTempSummonType(TEMPSUMMON_DEAD_DESPAWN);
|
|
}
|
|
}
|
|
}
|
|
// Could happen more than once if more than one player enters before she respawns.
|
|
Events.CancelEvent(EVENT_RESPAWN_SINDRAGOSA);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProcessEvent(WorldObject* source, uint32 eventId) override
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_ENEMY_GUNSHIP_DESPAWN:
|
|
if (GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) == DONE)
|
|
{
|
|
if (GameObject* go = source->ToGameObject())
|
|
if (MotionTransport* transport = go->ToMotionTransport())
|
|
transport->UnloadNonStaticPassengers();
|
|
source->AddObjectToRemoveList();
|
|
}
|
|
break;
|
|
case EVENT_ENEMY_GUNSHIP_COMBAT:
|
|
if (Creature* captain = source->FindNearestCreature(TeamIdInInstance == TEAM_HORDE ? NPC_IGB_HIGH_OVERLORD_SAURFANG : NPC_IGB_MURADIN_BRONZEBEARD, 200.0f))
|
|
{
|
|
captain->AI()->DoAction(ACTION_ENEMY_GUNSHIP_TALK);
|
|
}
|
|
[[fallthrough]];
|
|
case EVENT_PLAYERS_GUNSHIP_SPAWN:
|
|
case EVENT_PLAYERS_GUNSHIP_COMBAT:
|
|
if (GameObject* go = source->ToGameObject())
|
|
if (MotionTransport* transport = go->ToMotionTransport())
|
|
transport->EnableMovement(false);
|
|
break;
|
|
case EVENT_PLAYERS_GUNSHIP_SAURFANG:
|
|
if (GameObject* go = source->ToGameObject())
|
|
if (MotionTransport* transport = go->ToMotionTransport())
|
|
{
|
|
transport->setActive(false);
|
|
transport->EnableMovement(false);
|
|
//After movement is stopped remove the backpack
|
|
RemoveBackPack();
|
|
}
|
|
if (Creature* captain = source->FindNearestCreature(TeamIdInInstance == TEAM_HORDE ? NPC_IGB_HIGH_OVERLORD_SAURFANG : NPC_IGB_MURADIN_BRONZEBEARD, 200.0f))
|
|
captain->AI()->DoAction(ACTION_EXIT_SHIP);
|
|
break;
|
|
|
|
case EVENT_QUAKE:
|
|
if (GameObject* warning = instance->GetGameObject(FrozenThroneWarningGUID))
|
|
warning->SetGoState(GO_STATE_ACTIVE);
|
|
Events.ScheduleEvent(EVENT_QUAKE_SHATTER, 5s);
|
|
break;
|
|
case EVENT_SECOND_REMORSELESS_WINTER:
|
|
if (GameObject* platform = instance->GetGameObject(ArthasPlatformGUID))
|
|
{
|
|
platform->SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED);
|
|
Events.ScheduleEvent(EVENT_REBUILD_PLATFORM, 1500ms);
|
|
}
|
|
break;
|
|
case EVENT_TELEPORT_TO_FROSMOURNE: // Harvest Soul (normal mode)
|
|
if (Creature* terenas = instance->SummonCreature(NPC_TERENAS_MENETHIL_FROSTMOURNE, TerenasSpawn, nullptr, 65000))
|
|
{
|
|
terenas->AI()->DoAction(ACTION_FROSTMOURNE_INTRO);
|
|
std::list<Creature*> triggers;
|
|
GetCreatureListWithEntryInGrid(triggers, terenas, NPC_WORLD_TRIGGER_INFINITE_AOI, 100.0f);
|
|
if (!triggers.empty())
|
|
{
|
|
triggers.sort(Acore::ObjectDistanceOrderPred(terenas, false));
|
|
Unit* visual = triggers.front();
|
|
visual->CastSpell(visual, SPELL_FROSTMOURNE_TELEPORT_VISUAL, true);
|
|
}
|
|
|
|
if (Creature* warden = instance->SummonCreature(NPC_SPIRIT_WARDEN, SpiritWardenSpawn, nullptr, 65000))
|
|
{
|
|
terenas->AI()->AttackStart(warden);
|
|
warden->AddThreat(terenas, 300000.0f);
|
|
}
|
|
}
|
|
break;
|
|
case EVENT_FESTERGUT_VALVE_USED:
|
|
if (!(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE))
|
|
{
|
|
if (GameObject* goGas = instance->GetGameObject(GasReleaseValveGUID))
|
|
goGas->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
|
|
|
PutricideEventProgress |= PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE;
|
|
if (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE)
|
|
{
|
|
HandleGameObject(PutricideCollisionGUID, true);
|
|
for (uint8 i = 0; i < 2; ++i)
|
|
if (GameObject* go = instance->GetGameObject(PutricideGateGUIDs[i]))
|
|
go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
|
|
}
|
|
else
|
|
HandleGameObject(PutricideGateGUIDs[0], false);
|
|
HandleGameObject(PutricidePipeGUIDs[0], true);
|
|
SaveToDB();
|
|
}
|
|
break;
|
|
case EVENT_ROTFACE_VALVE_USED:
|
|
if (!(PutricideEventProgress & PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE))
|
|
{
|
|
if (GameObject* goOoze = instance->GetGameObject(OozeReleaseValveGUID))
|
|
goOoze->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
|
|
|
PutricideEventProgress |= PUTRICIDE_EVENT_FLAG_ROTFACE_VALVE;
|
|
if (PutricideEventProgress & PUTRICIDE_EVENT_FLAG_FESTERGUT_VALVE)
|
|
{
|
|
HandleGameObject(PutricideCollisionGUID, true);
|
|
for (uint8 i = 0; i < 2; ++i)
|
|
if (GameObject* go = instance->GetGameObject(PutricideGateGUIDs[i]))
|
|
go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
|
|
}
|
|
else
|
|
HandleGameObject(PutricideGateGUIDs[1], false);
|
|
HandleGameObject(PutricidePipeGUIDs[1], true);
|
|
SaveToDB();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SetPositionTraps(GameObject* go)
|
|
{
|
|
std::vector<Position> trapPositions;
|
|
|
|
switch (go->GetEntry())
|
|
{
|
|
case GO_SPIRIT_ALARM_1:
|
|
trapPositions = GoSpiritAlarm_1;
|
|
break;
|
|
case GO_SPIRIT_ALARM_2:
|
|
trapPositions = GoSpiritAlarm_2;
|
|
break;
|
|
case GO_SPIRIT_ALARM_3:
|
|
trapPositions = GoSpiritAlarm_3;
|
|
break;
|
|
case GO_SPIRIT_ALARM_4:
|
|
trapPositions = GoSpiritAlarm_4;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
go->Relocate(Acore::Containers::SelectRandomContainerElement(trapPositions));
|
|
}
|
|
|
|
protected:
|
|
// pussywizard:
|
|
bool IsBuffAvailable;
|
|
uint32 WeeklyQuestId10; // contains id from 10man for any difficulty (for simplicity)
|
|
ObjectGuid WeeklyQuestNpcGUID[WeeklyNPCs];
|
|
ObjectGuid PutricideEnteranceDoorGUID;
|
|
uint32 PutricideEventProgress;
|
|
ObjectGuid GasReleaseValveGUID;
|
|
ObjectGuid OozeReleaseValveGUID;
|
|
bool LichKingHeroicAvailable;
|
|
uint32 LichKingRandomWhisperTimer;
|
|
uint32 DarkwhisperElevatorTimer;
|
|
ObjectGuid ScourgeTransporterFirstGUID;
|
|
|
|
EventMap Events;
|
|
ObjectGuid LadyDeathwhisperGUID;
|
|
ObjectGuid LadyDeathwisperElevatorGUID;
|
|
ObjectGuid GunshipGUID;
|
|
ObjectGuid EnemyGunshipGUID;
|
|
ObjectGuid GunshipArmoryGUID;
|
|
ObjectGuid DeathbringerSaurfangGUID;
|
|
ObjectGuid DeathbringerSaurfangDoorGUID;
|
|
ObjectGuid DeathbringerSaurfangEventGUID; // Muradin Bronzebeard or High Overlord Saurfang
|
|
ObjectGuid DeathbringersCacheGUID;
|
|
ObjectGuid SaurfangTeleportGUID;
|
|
ObjectGuid PlagueSigilGUID;
|
|
ObjectGuid BloodwingSigilGUID;
|
|
ObjectGuid FrostwingSigilGUID;
|
|
ObjectGuid PutricidePipeGUIDs[2];
|
|
ObjectGuid PutricideGateGUIDs[2];
|
|
ObjectGuid PutricideCollisionGUID;
|
|
ObjectGuid FestergutGUID;
|
|
ObjectGuid RotfaceGUID;
|
|
ObjectGuid ProfessorPutricideGUID;
|
|
ObjectGuid PutricideTableGUID;
|
|
ObjectGuid BloodCouncilGUIDs[3];
|
|
ObjectGuid BloodCouncilControllerGUID;
|
|
ObjectGuid BloodQueenLanaThelGUID;
|
|
ObjectGuid CrokScourgebaneGUID;
|
|
ObjectGuid CrokCaptainGUIDs[4];
|
|
ObjectGuid SisterSvalnaGUID;
|
|
ObjectGuid ValithriaDreamwalkerGUID;
|
|
ObjectGuid ValithriaLichKingGUID;
|
|
ObjectGuid ValithriaTriggerGUID;
|
|
ObjectGuid PutricadeTrapGUID;
|
|
ObjectGuid SindragosaGauntletGUID;
|
|
ObjectGuid SindragosaGUID;
|
|
ObjectGuid SpinestalkerGUID;
|
|
ObjectGuid RimefangGUID;
|
|
ObjectGuid TheLichKingTeleportGUID;
|
|
ObjectGuid TheLichKingGUID;
|
|
ObjectGuid TheLichKingLhGUID;
|
|
ObjectGuid HighlordTirionFordringGUID;
|
|
ObjectGuid TerenasMenethilGUID;
|
|
ObjectGuid ArthasPlatformGUID;
|
|
ObjectGuid ArthasPrecipiceGUID;
|
|
ObjectGuid FrozenThroneEdgeGUID;
|
|
ObjectGuid FrozenThroneWindGUID;
|
|
ObjectGuid FrozenThroneWarningGUID;
|
|
ObjectGuid FrozenBolvarGUID;
|
|
ObjectGuid PillarsChainedGUID;
|
|
ObjectGuid PillarsUnchainedGUID;
|
|
TeamId TeamIdInInstance;
|
|
uint32 ColdflameJetsState;
|
|
std::set<ObjectGuid::LowType> FrostwyrmGUIDs;
|
|
std::set<ObjectGuid::LowType> SpinestalkerTrash;
|
|
std::set<ObjectGuid::LowType> RimefangTrash;
|
|
uint32 BloodQuickeningState;
|
|
uint32 HeroicAttempts;
|
|
uint16 BloodQuickeningMinutes;
|
|
uint32 BloodPrinceTrashCount;
|
|
bool IsBonedEligible;
|
|
bool IsOozeDanceEligible;
|
|
bool IsNauseaEligible;
|
|
bool IsOrbWhispererEligible;
|
|
bool IsSindragosaIntroDone;
|
|
};
|
|
|
|
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
|
{
|
|
return new instance_icecrown_citadel_InstanceMapScript(map);
|
|
}
|
|
};
|
|
|
|
void AddSC_instance_icecrown_citadel()
|
|
{
|
|
new instance_icecrown_citadel();
|
|
}
|