diff options
Diffstat (limited to 'src')
63 files changed, 3245 insertions, 2655 deletions
diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp index bb278dd6653..55517884b8e 100644 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ b/src/server/authserver/Authentication/AuthCodes.cpp @@ -79,4 +79,4 @@ namespace AuthHelper return NULL; } -}; +} diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 5e6522f8981..97b4779da0e 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -92,6 +92,6 @@ namespace AuthHelper bool IsAcceptedClientBuild(int build); bool IsPostBCAcceptedClientBuild(int build); bool IsPreBCAcceptedClientBuild(int build); -}; +} #endif diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 8bf34527769..9631b75fe06 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -28,7 +28,6 @@ void UnitAI::AttackStart(Unit* victim) { - if (victim && me->Attack(victim, true)) me->GetMotionMaster()->MoveChase(victim); } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 36c1d384693..c205dd908c7 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -478,10 +478,7 @@ void BossAI::_JustDied() events.Reset(); summons.DespawnAll(); if (instance) - { instance->SetBossState(_bossId, DONE); - instance->SaveToDB(); - } } void BossAI::_EnterCombat() diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 098f3130fed..e769b7c22a5 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -618,10 +618,7 @@ void SmartAI::DamageTaken(Unit* doneBy, uint32& damage) { GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage); if (mInvincibilityHpLevel && (damage >= me->GetHealth() - mInvincibilityHpLevel)) - { - damage = 0; - me->SetHealth(mInvincibilityHpLevel); - } + damage = me->GetHealth() - mInvincibilityHpLevel; // damage should not be nullified, because of player damage req. } void SmartAI::HealReceived(Unit* doneBy, uint32& addhealth) diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index 52ed50f3948..a4cb972e625 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -17,7 +17,6 @@ #include "CalendarMgr.h" #include "QueryResult.h" -#include "DatabaseEnv.h" #include "Log.h" #include "Player.h" #include "GuildMgr.h" @@ -128,6 +127,12 @@ void CalendarMgr::AddEvent(CalendarEvent* calendarEvent, CalendarSendEventType s void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite) { + SQLTransaction dummy; + AddInvite(calendarEvent, invite, dummy); +} + +void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite, SQLTransaction& trans) +{ if (!calendarEvent->IsGuildAnnouncement()) SendCalendarEventInvite(*invite); @@ -137,7 +142,7 @@ void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite if (!calendarEvent->IsGuildAnnouncement()) { _invites[invite->GetEventId()].push_back(invite); - UpdateInvite(invite); + UpdateInvite(invite, trans); } } @@ -221,7 +226,6 @@ void CalendarMgr::RemoveInvite(uint64 inviteId, uint64 eventId, uint64 /*remover void CalendarMgr::UpdateEvent(CalendarEvent* calendarEvent) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CALENDAR_EVENT); stmt->setUInt64(0, calendarEvent->GetEventId()); stmt->setUInt32(1, GUID_LOPART(calendarEvent->GetCreatorGUID())); @@ -232,13 +236,17 @@ void CalendarMgr::UpdateEvent(CalendarEvent* calendarEvent) stmt->setUInt32(6, uint32(calendarEvent->GetEventTime())); stmt->setUInt32(7, calendarEvent->GetFlags()); stmt->setUInt32(8, calendarEvent->GetTimeZoneTime()); // correct? - trans->Append(stmt); - CharacterDatabase.CommitTransaction(trans); + CharacterDatabase.Execute(stmt); } void CalendarMgr::UpdateInvite(CalendarInvite* invite) { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + SQLTransaction dummy; + UpdateInvite(invite, dummy); +} + +void CalendarMgr::UpdateInvite(CalendarInvite* invite, SQLTransaction& trans) +{ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CALENDAR_INVITE); stmt->setUInt64(0, invite->GetInviteId()); stmt->setUInt64(1, invite->GetEventId()); @@ -248,8 +256,7 @@ void CalendarMgr::UpdateInvite(CalendarInvite* invite) stmt->setUInt32(5, uint32(invite->GetStatusTime())); stmt->setUInt8(6, invite->GetRank()); stmt->setString(7, invite->GetText()); - trans->Append(stmt); - CharacterDatabase.CommitTransaction(trans); + CharacterDatabase.ExecuteOrAppend(trans, stmt); } void CalendarMgr::RemoveAllPlayerEventsAndInvites(uint64 guid) diff --git a/src/server/game/Calendar/CalendarMgr.h b/src/server/game/Calendar/CalendarMgr.h index da185d519d5..8f44b013e5c 100644 --- a/src/server/game/Calendar/CalendarMgr.h +++ b/src/server/game/Calendar/CalendarMgr.h @@ -20,6 +20,7 @@ #include <ace/Singleton.h> #include "Common.h" +#include "DatabaseEnv.h" #include "WorldPacket.h" enum CalendarMailAnswers @@ -305,8 +306,10 @@ class CalendarMgr void UpdateEvent(CalendarEvent* calendarEvent); void AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite); + void AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite, SQLTransaction& trans); void RemoveInvite(uint64 inviteId, uint64 eventId, uint64 remover); void UpdateInvite(CalendarInvite* invite); + void UpdateInvite(CalendarInvite* invite, SQLTransaction& trans); void RemoveAllPlayerEventsAndInvites(uint64 guid); void RemovePlayerGuildEventsAndSignups(uint64 guid, uint32 guildId); diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 9b0465a4536..44f03b6978d 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -139,6 +139,7 @@ DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt); DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore(OverrideSpellDatafmt); +DBCStorage <PowerDisplayEntry> sPowerDisplayStore(PowerDisplayfmt); DBCStorage <PvPDifficultyEntry> sPvPDifficultyStore(PvPDifficultyfmt); DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt); @@ -391,6 +392,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sOverrideSpellDataStore, dbcPath, "OverrideSpellData.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sPowerDisplayStore, dbcPath, "PowerDisplay.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sPvPDifficultyStore, dbcPath, "PvpDifficulty.dbc"); for (uint32 i = 0; i < sPvPDifficultyStore.GetNumRows(); ++i) if (PvPDifficultyEntry const* entry = sPvPDifficultyStore.LookupEntry(i)) diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index b77db950541..fe775dfda19 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -141,6 +141,7 @@ extern DBCStorage <MapEntry> sMapStore; extern MapDifficultyMap sMapDifficultyMap; extern DBCStorage <MovieEntry> sMovieStore; extern DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore; +extern DBCStorage <PowerDisplayEntry> sPowerDisplayStore; extern DBCStorage <QuestSortEntry> sQuestSortStore; extern DBCStorage <QuestXPEntry> sQuestXPStore; extern DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index abe7bde4bf5..5d6c8c7aa89 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1398,6 +1398,16 @@ struct OverrideSpellDataEntry //uint32 unk0; // 11 }; +struct PowerDisplayEntry +{ + uint32 Id; // 0 + uint32 PowerType; // 1 + //char* Name; // 2 + //uint32 R; // 3 + //uint32 G; // 4 + //uint32 B; // 5 +}; + struct PvPDifficultyEntry { //uint32 id; // 0 m_ID @@ -1982,7 +1992,7 @@ struct VehicleEntry uint32 m_uiLocomotionType; // 34 float m_msslTrgtImpactTexRadius; // 35 uint32 m_uiSeatIndicatorType; // 36 - uint32 m_powerType; // 37, new in 3.1 + uint32 m_powerDisplayId; // 37, new in 3.1 // 38, new in 3.1 // 39, new in 3.1 }; diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 35a8eecb708..222353467f4 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -91,6 +91,7 @@ char const OverrideSpellDatafmt[] = "niiiiiiiiiix"; char const QuestFactionRewardfmt[] = "niiiiiiiiii"; char const QuestSortEntryfmt[] = "nxxxxxxxxxxxxxxxxx"; char const QuestXPfmt[] = "niiiiiiiiii"; +char const PowerDisplayfmt[] = "nixxxx"; char const PvPDifficultyfmt[] = "diiiii"; char const RandomPropertiesPointsfmt[] = "niiiiiiiiiiiiiii"; char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiii"; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 36997eb884a..01621637985 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -569,7 +569,7 @@ void Creature::Update(uint32 diff) if (getPowerType() == POWER_ENERGY) { - if (!IsVehicle() || GetVehicleKit()->GetVehicleInfo()->m_powerType != POWER_PYRITE) + if (!IsVehicle() || GetVehicleKit()->GetVehicleInfo()->m_powerDisplayId != POWER_PYRITE) Regenerate(POWER_ENERGY); } else diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 8051c757bf2..306e4209e4d 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -526,7 +526,7 @@ void GameObject::Update(uint32 diff) { case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: - if (GetGOInfo()->GetAutoCloseTime() && (m_cooldownTime < time(NULL))) + if (m_cooldownTime && (m_cooldownTime < time(NULL))) ResetDoorOrButton(); break; case GAMEOBJECT_TYPE_GOOBER: @@ -568,10 +568,12 @@ void GameObject::Update(uint32 diff) CastSpell(target, goInfo->trap.spellId); // Template value or 4 seconds - m_cooldownTime = time(NULL) + (goInfo->trap.cooldown ? goInfo->trap.cooldown : uint32(4)); + m_cooldownTime = time(NULL) + (goInfo->trap.cooldown ? goInfo->trap.cooldown : uint32(4)); if (goInfo->trap.type == 1) SetLootState(GO_JUST_DEACTIVATED); + else if (!goInfo->trap.type) + SetLootState(GO_READY); // Battleground gameobjects have data2 == 0 && data5 == 3 if (!goInfo->trap.diameter && goInfo->trap.cooldown == 3) @@ -1098,7 +1100,7 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = f SwitchDoorOrButton(true, alternative); SetLootState(GO_ACTIVATED, user); - m_cooldownTime = time(NULL) + time_to_restore; + m_cooldownTime = time_to_restore ? (time(NULL) + time_to_restore) : 0; } void GameObject::SetGoArtKit(uint8 kit) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a701e6fc38f..563d7fed107 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -144,6 +144,8 @@ enum CharacterCustomizeFlags static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 }; +uint32 const MAX_MONEY_AMOUNT = static_cast<uint32>(std::numeric_limits<int32>::max()); + // == PlayerTaxi ================================================ PlayerTaxi::PlayerTaxi() @@ -364,6 +366,12 @@ void TradeData::SetMoney(uint32 money) if (m_money == money) return; + if (!m_player->HasEnoughMoney(money)) + { + m_player->GetSession()->SendTradeStatus(TRADE_STATUS_BUSY); + return; + } + m_money = money; SetAccepted(false); @@ -22639,7 +22647,7 @@ bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) SetMoney (GetMoney() > uint32(-amount) ? GetMoney() + amount : 0); else { - if (GetMoney() < uint32(MAX_MONEY_AMOUNT - amount)) + if (GetMoney() < MAX_MONEY_AMOUNT - static_cast<uint32>(amount)) SetMoney(GetMoney() + amount); else { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 92691c3fd45..0826f533df7 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -29,6 +29,7 @@ #include "SpellMgr.h" #include "Unit.h" +#include <limits> #include <string> #include <vector> @@ -824,7 +825,8 @@ enum PlayerDelayedOperations // Player summoning auto-decline time (in secs) #define MAX_PLAYER_SUMMON_DELAY (2*MINUTE) -#define MAX_MONEY_AMOUNT (0x7FFFFFFF-1) +// Maximum money amount : 2^31 - 1 +extern uint32 const MAX_MONEY_AMOUNT; struct InstancePlayerBind { diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index fd45c3fc596..8bc07732bb6 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -85,8 +85,8 @@ bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, floa _triggeredDepartureEvent = false; m_goValue.Transport.PathProgress = 0; - SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); - SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); + SetObjectScale(goinfo->size); + SetFaction(goinfo->faction); SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); SetPeriod(tInfo->pathTime); SetEntry(goinfo->entry); @@ -210,8 +210,14 @@ void Transport::Update(uint32 diff) 3. transport moves from active to inactive grid 4. the grid that transport is currently in unloads */ - if (_staticPassengers.empty() && GetMap()->IsGridLoaded(GetPositionX(), GetPositionY())) // 2. + bool gridActive = GetMap()->IsGridLoaded(GetPositionX(), GetPositionY()); + + if (_staticPassengers.empty() && gridActive) // 2. LoadStaticPassengers(); + else if (!_staticPassengers.empty() && !gridActive) + // 4. - if transports stopped on grid edge, some passengers can remain in active grids + // unload all static passengers otherwise passengers won't load correctly when the grid that transport is currently in becomes active + UnloadStaticPassengers(); } } @@ -450,6 +456,7 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu void Transport::UpdatePosition(float x, float y, float z, float o) { bool newActive = GetMap()->IsGridLoaded(x, y); + Cell oldCell(GetPositionX(), GetPositionY()); Relocate(x, y, z, o); UpdateModelPosition(); @@ -464,7 +471,7 @@ void Transport::UpdatePosition(float x, float y, float z, float o) */ if (_staticPassengers.empty() && newActive) // 1. LoadStaticPassengers(); - else if (!_staticPassengers.empty() && !newActive && Cell(x, y).DiffGrid(Cell(GetPositionX(), GetPositionY()))) // 3. + else if (!_staticPassengers.empty() && !newActive && oldCell.DiffGrid(Cell(GetPositionX(), GetPositionY()))) // 3. UnloadStaticPassengers(); else UpdatePassengerPositions(_staticPassengers); diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index fae4f0c6b6a..4c3724a8860 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -76,42 +76,9 @@ Vehicle::~Vehicle() void Vehicle::Install() { - if (Creature* creature = _me->ToCreature()) - { - switch (_vehicleInfo->m_powerType) - { - case POWER_STEAM: - case POWER_HEAT: - case POWER_BLOOD: - case POWER_OOZE: - case POWER_WRATH: - _me->setPowerType(POWER_ENERGY); - _me->SetMaxPower(POWER_ENERGY, 100); - break; - case POWER_PYRITE: - _me->setPowerType(POWER_ENERGY); - _me->SetMaxPower(POWER_ENERGY, 50); - break; - default: - for (uint32 i = 0; i < MAX_SPELL_VEHICLE; ++i) - { - if (!creature->m_spells[i]) - continue; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(creature->m_spells[i]); - if (!spellInfo) - continue; - - if (spellInfo->PowerType == POWER_ENERGY && spellInfo->CalcPowerCost(_me, spellInfo->GetSchoolMask()) > 0) - { - _me->setPowerType(POWER_ENERGY); - _me->SetMaxPower(POWER_ENERGY, 100); - break; - } - } - break; - } - } + if (_me->GetTypeId() == TYPEID_UNIT) + if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId)) + _me->setPowerType(Powers(powerDisplay->PowerType)); _status = STATUS_INSTALLED; if (GetBase()->GetTypeId() == TYPEID_UNIT) diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 2905b0454c4..207f80eabe7 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3822,8 +3822,8 @@ void ObjectMgr::LoadQuests() "RequiredItemId1, RequiredItemId2, RequiredItemId3, RequiredItemId4, RequiredItemId5, RequiredItemId6, RequiredItemCount1, RequiredItemCount2, RequiredItemCount3, RequiredItemCount4, RequiredItemCount5, RequiredItemCount6, " // 117 118 119 120 121 122 123 124 125 126 127 128 129 "Unknown0, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4, DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4, " - // 130 131 132 133 134 135 136 137 138 139 140 - "EmoteOnIncomplete, EmoteOnComplete, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4, OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4, WDBVerified" + // 130 131 132 133 134 135 136 137 138 139 + "EmoteOnIncomplete, EmoteOnComplete, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4, OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4" " FROM quest_template"); if (!result) { diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 48c9e618a1d..ba5940d7e12 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -432,7 +432,7 @@ struct BroadcastText uint32 SoundId; uint32 Unk1; uint32 Unk2; - // uint32 WDBVerified; + // uint32 VerifiedBuild; std::string const& GetText(LocaleConstant locale = DEFAULT_LOCALE, uint8 gender = GENDER_MALE, bool forceGender = false) const { diff --git a/src/server/game/Grids/GridStates.cpp b/src/server/game/Grids/GridStates.cpp index 8b57c382cd7..3e085f1f381 100644 --- a/src/server/game/Grids/GridStates.cpp +++ b/src/server/game/Grids/GridStates.cpp @@ -20,18 +20,6 @@ #include "GridNotifiers.h" #include "Log.h" -#ifdef TRINITY_DEBUG -bool GridState::checkMagic() -{ - if (i_Magic != MAGIC_TESTVAL) - { - TC_LOG_ERROR("misc", "!!! GridState: Magic value gone !!!"); - return false; - } - return true; -} -#endif - void InvalidState::Update(Map&, NGridType&, GridInfo&, uint32) const { } diff --git a/src/server/game/Grids/GridStates.h b/src/server/game/Grids/GridStates.h index 016df4dc3d4..af11ab08d5e 100644 --- a/src/server/game/Grids/GridStates.h +++ b/src/server/game/Grids/GridStates.h @@ -27,13 +27,6 @@ class Map; class GridState { public: -#ifdef TRINITY_DEBUG -#define MAGIC_TESTVAL 0xFBE823BA - GridState() { i_Magic = MAGIC_TESTVAL; } - bool checkMagic(); - void setMagic() { i_Magic = MAGIC_TESTVAL; } - unsigned int i_Magic; -#endif virtual ~GridState() { }; virtual void Update(Map &, NGridType&, GridInfo &, uint32 t_diff) const = 0; }; diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index f448fbb9f19..db0a196dec6 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -754,7 +754,7 @@ int32 Guild::Member::GetBankWithdrawValue(uint8 tabId) const { // Guild master has unlimited amount. if (IsRank(GR_GUILDMASTER)) - return tabId == GUILD_BANK_MAX_TABS ? GUILD_WITHDRAW_MONEY_UNLIMITED : GUILD_WITHDRAW_SLOT_UNLIMITED; + return static_cast<int32>(tabId == GUILD_BANK_MAX_TABS ? GUILD_WITHDRAW_MONEY_UNLIMITED : GUILD_WITHDRAW_SLOT_UNLIMITED); return m_bankWithdraw[tabId]; } @@ -1760,7 +1760,7 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount) bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair) { //clamp amount to MAX_MONEY_AMOUNT, Players can't hold more than that anyway - amount = std::min(amount, uint32(MAX_MONEY_AMOUNT)); + amount = std::min(amount, MAX_MONEY_AMOUNT); if (m_bankMoney < amount) // Not enough money in bank return false; @@ -2581,7 +2581,7 @@ inline int32 Guild::_GetMemberRemainingSlots(Member const* member, uint8 tabId) { uint8 rankId = member->GetRankId(); if (rankId == GR_GUILDMASTER) - return GUILD_WITHDRAW_SLOT_UNLIMITED; + return static_cast<int32>(GUILD_WITHDRAW_SLOT_UNLIMITED); if ((_GetRankBankTabRights(rankId, tabId) & GUILD_BANK_RIGHT_VIEW_TAB) != 0) { int32 remaining = _GetRankBankTabSlotsPerDay(rankId, tabId) - member->GetBankWithdrawValue(tabId); @@ -2598,7 +2598,7 @@ inline int32 Guild::_GetMemberRemainingMoney(Member const* member) const { uint8 rankId = member->GetRankId(); if (rankId == GR_GUILDMASTER) - return GUILD_WITHDRAW_MONEY_UNLIMITED; + return static_cast<int32>(GUILD_WITHDRAW_MONEY_UNLIMITED); if ((_GetRankRights(rankId) & (GR_RIGHT_WITHDRAW_REPAIR | GR_RIGHT_WITHDRAW_GOLD)) != 0) { diff --git a/src/server/game/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp index 632bd02def0..3bb3edac500 100644 --- a/src/server/game/Handlers/ArenaTeamHandler.cpp +++ b/src/server/game/Handlers/ArenaTeamHandler.cpp @@ -121,6 +121,12 @@ void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket& recvData) return; } + if (GetPlayer()->GetArenaTeamId(arenaTeam->GetSlot()) != arenaTeamId) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); + return; + } + // OK result but don't send invite if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) return; diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 45d4d221d06..278c180c380 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -255,7 +255,14 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) uint32 inviteCount; recvData >> inviteCount; - for (uint32 i = 0; i < inviteCount; ++i) + SQLTransaction trans; + if (inviteCount > 1) + trans = CharacterDatabase.BeginTransaction(); + + // client limits the amount of players to be invited to 100 + const uint32 MaxPlayerInvites = 100; + + for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) { uint64 invitee = 0; uint8 status = 0; @@ -265,8 +272,11 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) // 946684800 is 01/01/2000 00:00:00 - default response time CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent.GetEventId(), invitee, guid, 946684800, CalendarInviteStatus(status), CalendarModerationRank(rank), ""); - sCalendarMgr->AddInvite(&calendarEvent, invite); + sCalendarMgr->AddInvite(&calendarEvent, invite, trans); } + + if (inviteCount > 1) + CharacterDatabase.CommitTransaction(trans); } sCalendarMgr->AddEvent(new CalendarEvent(calendarEvent, calendarEvent.GetEventId()), CALENDAR_SENDTYPE_ADD); @@ -350,10 +360,15 @@ void WorldSession::HandleCalendarCopyEvent(WorldPacket& recvData) sCalendarMgr->AddEvent(newEvent, CALENDAR_SENDTYPE_COPY); CalendarInviteStore invites = sCalendarMgr->GetEventInvites(eventId); + SQLTransaction trans; + if (invites.size() > 1) + trans = CharacterDatabase.BeginTransaction(); for (CalendarInviteStore::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) - sCalendarMgr->AddInvite(newEvent, new CalendarInvite(**itr, sCalendarMgr->GetFreeInviteId(), newEvent->GetEventId())); + sCalendarMgr->AddInvite(newEvent, new CalendarInvite(**itr, sCalendarMgr->GetFreeInviteId(), newEvent->GetEventId()), trans); + if (invites.size() > 1) + CharacterDatabase.CommitTransaction(trans); // should we change owner when somebody makes a copy of event owned by another person? } else diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 4372de9eafe..884c4a83b15 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -299,14 +299,14 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) return; } - if (_player->GetMoney() >= uint32(MAX_MONEY_AMOUNT) - his_trade->GetMoney()) + if (_player->GetMoney() >= MAX_MONEY_AMOUNT - his_trade->GetMoney()) { _player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); my_trade->SetAccepted(false, true); return; } - if (trader->GetMoney() >= uint32(MAX_MONEY_AMOUNT) - my_trade->GetMoney()) + if (trader->GetMoney() >= MAX_MONEY_AMOUNT - my_trade->GetMoney()) { trader->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); his_trade->SetAccepted(false, true); @@ -686,7 +686,6 @@ void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket) if (!my_trade) return; - // gold can be incorrect, but this is checked at trade finished. my_trade->SetMoney(gold); } diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 3050443edc0..9e11c566c22 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -243,7 +243,7 @@ AI* GetInstanceAI(T* obj, char const* scriptName) return new AI(obj); return NULL; -}; +} template<class AI, class T> AI* GetInstanceAI(T* obj) @@ -253,6 +253,6 @@ AI* GetInstanceAI(T* obj) return new AI(obj); return NULL; -}; +} #endif // TRINITY_INSTANCE_DATA_H diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index cd391299785..ba271235330 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -1544,11 +1544,8 @@ void Map::UnloadAll() Transport* transport = *itr; ++itr; - transport->RemoveFromWorld(); - delete transport; + RemoveFromMap<Transport>(transport, true); } - - _transports.clear(); } // ***************************** @@ -2648,24 +2645,27 @@ void Map::RemoveAllObjectsInRemoveList() RemoveFromMap(corpse, true); break; } - case TYPEID_DYNAMICOBJECT: - RemoveFromMap((DynamicObject*)obj, true); - break; - case TYPEID_GAMEOBJECT: - if (Transport* transport = obj->ToGameObject()->ToTransport()) - RemoveFromMap(transport, true); - else - RemoveFromMap(obj->ToGameObject(), true); - break; - case TYPEID_UNIT: - // in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call - // make sure that like sources auras/etc removed before destructor start - obj->ToCreature()->CleanupsBeforeDelete(); - RemoveFromMap(obj->ToCreature(), true); - break; - default: - TC_LOG_ERROR("maps", "Non-grid object (TypeId: %u) is in grid object remove list, ignored.", obj->GetTypeId()); - break; + case TYPEID_DYNAMICOBJECT: + RemoveFromMap(obj->ToDynObject(), true); + break; + case TYPEID_GAMEOBJECT: + { + GameObject* go = obj->ToGameObject(); + if (Transport* transport = go->ToTransport()) + RemoveFromMap(transport, true); + else + RemoveFromMap(go, true); + break; + } + case TYPEID_UNIT: + // in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call + // make sure that like sources auras/etc removed before destructor start + obj->ToCreature()->CleanupsBeforeDelete(); + RemoveFromMap(obj->ToCreature(), true); + break; + default: + TC_LOG_ERROR("maps", "Non-grid object (TypeId: %u) is in grid object remove list, ignored.", obj->GetTypeId()); + break; } i_objectsToRemove.erase(itr); diff --git a/src/server/game/Maps/MapUpdater.cpp b/src/server/game/Maps/MapUpdater.cpp index f3a5a66bf66..dd697719d54 100644 --- a/src/server/game/Maps/MapUpdater.cpp +++ b/src/server/game/Maps/MapUpdater.cpp @@ -6,34 +6,6 @@ #include <ace/Guard_T.h> #include <ace/Method_Request.h> -class WDBThreadStartReq1 : public ACE_Method_Request -{ - public: - - WDBThreadStartReq1() - { - } - - virtual int call() - { - return 0; - } -}; - -class WDBThreadEndReq1 : public ACE_Method_Request -{ - public: - - WDBThreadEndReq1() - { - } - - virtual int call() - { - return 0; - } -}; - class MapUpdateRequest : public ACE_Method_Request { private: @@ -67,7 +39,7 @@ MapUpdater::~MapUpdater() int MapUpdater::activate(size_t num_threads) { - return m_executor.start((int)num_threads, new WDBThreadStartReq1, new WDBThreadEndReq1); + return m_executor.start((int)num_threads); } int MapUpdater::deactivate() diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 9b3732d232b..099275ba8dc 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -137,7 +137,7 @@ Quest::Quest(Field* questRecord) for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) OfferRewardEmoteDelay[i] = questRecord[136+i].GetInt32(); - //int32 WDBVerified = questRecord[140].GetInt32(); + //int32 VerifiedBuild = questRecord[140].GetInt32(); if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) Flags |= QUEST_FLAGS_AUTO_ACCEPT; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 8e7edfc5355..3e1763e6c5b 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1343,17 +1343,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b if (target->HasAura(61988) && !target->HasAura(25771)) target->RemoveAura(61988); break; - case 72368: // Shared Suffering - case 72369: - if (caster) - { - if (AuraEffect* aurEff = GetEffect(0)) - { - int32 remainingDamage = aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber()); - if (remainingDamage > 0) - caster->CastCustomSpell(caster, 72373, NULL, &remainingDamage, NULL, true); - } - } + default: break; } break; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 7c6f2552b44..768c0b7e818 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1251,8 +1251,12 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f); m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dist, angle); - float ground = z; - float liquidLevel = m_caster->GetMap()->GetWaterOrGroundLevel(x, y, z, &ground); + float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), x, y, z, true, 50.0f); + float liquidLevel = VMAP_INVALID_HEIGHT_VALUE; + LiquidData liquidData; + if (m_caster->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData)) + liquidLevel = liquidData.level; + if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level { SendCastResult(SPELL_FAILED_NOT_HERE); @@ -1288,10 +1292,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici dist = objSize + (dist - objSize) * float(rand_norm()); Position pos = dest._position; - if (targetType.GetTarget() == TARGET_DEST_CASTER_FRONT_LEAP) - m_caster->MovePositionToFirstCollision(pos, dist, angle); - else - m_caster->MovePosition(pos, dist, angle); + m_caster->MovePositionToFirstCollision(pos, dist, angle); dest.Relocate(pos); break; @@ -1324,7 +1325,7 @@ void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplici dist = objSize + (dist - objSize) * float(rand_norm()); Position pos = dest._position; - target->MovePosition(pos, dist, angle); + target->MovePositionToFirstCollision(pos, dist, angle); dest.Relocate(pos); break; @@ -1363,7 +1364,7 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT dist *= float(rand_norm()); Position pos = dest._position; - m_caster->MovePosition(pos, dist, angle); + m_caster->MovePositionToFirstCollision(pos, dist, angle); dest.Relocate(pos); break; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index ba5b8856323..501cb1e77f2 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3375,6 +3375,18 @@ void SpellMgr::LoadSpellInfoCorrections() break; // ENDOF TRIAL OF THE CRUSADER SPELLS // + // HALLS OF REFLECTION SPELLS + // + case 72435: // Defiling Horror + case 72452: // Defiling Horror + spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd + spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd + break; + case 72900: // Start Halls of Reflection Quest AE + spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + break; + // ENDOF HALLS OF REFLECTION SPELLS + // // ICECROWN CITADEL SPELLS // // THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 75a191a9801..32b8781fb89 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -249,7 +249,7 @@ class SpellScript : public _SpellScript class HitHandlerFunction : public SpellScript::HitHandler { public: HitHandlerFunction(SpellHitFnType _pHitHandlerScript) : SpellScript::HitHandler((SpellScript::SpellHitFnType)_pHitHandlerScript) { } }; \ class ObjectAreaTargetSelectHandlerFunction : public SpellScript::ObjectAreaTargetSelectHandler { public: ObjectAreaTargetSelectHandlerFunction(SpellObjectAreaTargetSelectFnType _pObjectAreaTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::ObjectAreaTargetSelectHandler((SpellScript::SpellObjectAreaTargetSelectFnType)_pObjectAreaTargetSelectHandlerScript, _effIndex, _targetType) { } }; \ class ObjectTargetSelectHandlerFunction : public SpellScript::ObjectTargetSelectHandler { public: ObjectTargetSelectHandlerFunction(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::ObjectTargetSelectHandler((SpellScript::SpellObjectTargetSelectFnType)_pObjectTargetSelectHandlerScript, _effIndex, _targetType) { } }; \ - class DestinationTargetSelectHandlerFunction : public SpellScript::DestinationTargetSelectHandler { public: DestinationTargetSelectHandlerFunction(SpellDestinationTargetSelectFnType _DestinationTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::DestinationTargetSelectHandler((SpellScript::SpellDestinationTargetSelectFnType)_DestinationTargetSelectHandlerScript, _effIndex, _targetType) { } }; + class DestinationTargetSelectHandlerFunction : public SpellScript::DestinationTargetSelectHandler { public: DestinationTargetSelectHandlerFunction(SpellDestinationTargetSelectFnType _DestinationTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::DestinationTargetSelectHandler((SpellScript::SpellDestinationTargetSelectFnType)_DestinationTargetSelectHandlerScript, _effIndex, _targetType) { } } #define PrepareSpellScript(CLASSNAME) SPELLSCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) public: @@ -623,7 +623,7 @@ class AuraScript : public _SpellScript class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) { } }; \ class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) { } }; \ class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) { } }; \ - class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) { } }; \ + class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) { } } #define PrepareAuraScript(CLASSNAME) AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp index b9ecfffb8c3..71d51153b4c 100644 --- a/src/server/game/Tickets/TicketMgr.cpp +++ b/src/server/game/Tickets/TicketMgr.cpp @@ -233,7 +233,7 @@ void GmTicket::SetChatLog(std::list<uint32> time, std::string const& log) std::stringstream ss(log); std::stringstream newss; std::string line; - while (std::getline(ss, line)) + while (std::getline(ss, line) && !time.empty()) { newss << secsToTimeString(time.front()) << ": " << line << "\n"; time.pop_front(); diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index 42872bba22e..0810295c0cc 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -223,7 +223,7 @@ std::string Warden::Penalty(WardenCheck* check /*= NULL*/) void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData) { - if (!_warden) + if (!_warden || recvData.empty()) return; _warden->DecryptData(recvData.contents(), recvData.size()); diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index f2f11801229..5dbe95b3e54 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1020,7 +1020,7 @@ public: } else { - if (newmoney > MAX_MONEY_AMOUNT) + if (newmoney > static_cast<int32>(MAX_MONEY_AMOUNT)) newmoney = MAX_MONEY_AMOUNT; handler->PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(moneyToAdd), handler->GetNameLink(target).c_str()); @@ -1035,10 +1035,7 @@ public: if (handler->needReportToTarget(target)) ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, handler->GetNameLink().c_str(), moneyToAdd); - if (moneyToAdd >= MAX_MONEY_AMOUNT) - moneyToAdd = MAX_MONEY_AMOUNT; - - if (targetMoney >= uint32(MAX_MONEY_AMOUNT) - moneyToAdd) + if (targetMoney >= MAX_MONEY_AMOUNT - moneyToAdd) moneyToAdd -= targetMoney; target->ModifyMoney(moneyToAdd); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp index 83b716728ea..354e1204a50 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp @@ -212,4 +212,4 @@ void AddSC_boss_balinda() { new boss_balinda; new npc_water_elemental; -}; +} diff --git a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp index 010e06d67cb..870ae370366 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp @@ -109,7 +109,7 @@ void SummonCroneIfReady(InstanceScript* instance, Creature* creature) pCrone->AI()->AttackStart(creature->GetVictim()); } } -}; +} class boss_dorothee : public CreatureScript { diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index 5562559786d..28bb24f49a9 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -679,13 +679,16 @@ public: if (!map->IsDungeon()) return; - Map::PlayerList const &PlayerList = map->GetPlayers(); - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + Map::PlayerList const &playerList = map->GetPlayers(); + Position homePos = me->GetHomePosition(); + for (Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) { - if (i->GetSource()->GetPositionZ() <= DRAGON_REALM_Z-5) + Player* player = itr->GetSource(); + if (player->IsInDist(&homePos, 50.0f) && player->GetPositionZ() <= DEMON_REALM_Z + 10.f) { - i->GetSource()->RemoveAura(AURA_SPECTRAL_REALM); - i->GetSource()->TeleportTo(me->GetMap()->GetId(), i->GetSource()->GetPositionX(), i->GetSource()->GetPositionY(), DRAGON_REALM_Z+5, i->GetSource()->GetOrientation()); + player->RemoveAura(AURA_SPECTRAL_REALM); + player->TeleportTo(me->GetMap()->GetId(), player->GetPositionX(), + player->GetPositionY(), DRAGON_REALM_Z + 5, player->GetOrientation()); } } } diff --git a/src/server/scripts/EasternKingdoms/zone_duskwood.cpp b/src/server/scripts/EasternKingdoms/zone_duskwood.cpp index 236455137dc..4eaf98d0a0e 100644 --- a/src/server/scripts/EasternKingdoms/zone_duskwood.cpp +++ b/src/server/scripts/EasternKingdoms/zone_duskwood.cpp @@ -29,18 +29,19 @@ EndScriptData */ enum TwilightCorrupter { - ITEM_FRAGMENT = 21149, NPC_TWILIGHT_CORRUPTER = 15625, - YELL_TWILIGHTCORRUPTOR_RESPAWN = 0, - YELL_TWILIGHTCORRUPTOR_AGGRO = 1, - YELL_TWILIGHTCORRUPTOR_KILL = 2, + YELL_TWILIGHT_CORRUPTOR_RESPAWN = 0, + YELL_TWILIGHT_CORRUPTOR_AGGRO = 1, + YELL_TWILIGHT_CORRUPTOR_KILL = 2, + SPELL_SOUL_CORRUPTION = 25805, SPELL_CREATURE_OF_NIGHTMARE = 25806, SPELL_LEVEL_UP = 24312, EVENT_SOUL_CORRUPTION = 1, EVENT_CREATURE_OF_NIGHTMARE = 2, - FACTION_HOSTILE = 14 + + QUEST_NIGHTMARES_CORRUPTION = 8735 }; /*###### @@ -58,12 +59,13 @@ public: void Reset() override { - KillCount = 0; + _events.Reset(); + KillCount = 0; } void EnterCombat(Unit* /*who*/) override { - Talk(YELL_TWILIGHTCORRUPTOR_AGGRO); + Talk(YELL_TWILIGHT_CORRUPTOR_AGGRO); _events.ScheduleEvent(EVENT_SOUL_CORRUPTION, 15000); _events.ScheduleEvent(EVENT_CREATURE_OF_NIGHTMARE, 30000); } @@ -73,7 +75,7 @@ public: if (victim->GetTypeId() == TYPEID_PLAYER) { ++KillCount; - Talk(YELL_TWILIGHTCORRUPTOR_KILL, victim); + Talk(YELL_TWILIGHT_CORRUPTOR_KILL, victim); if (KillCount == 3) { @@ -90,22 +92,27 @@ public: _events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_SOUL_CORRUPTION: - DoCastVictim(SPELL_SOUL_CORRUPTION); - _events.ScheduleEvent(EVENT_SOUL_CORRUPTION, rand()%4000+15000); + DoCastAOE(SPELL_SOUL_CORRUPTION); + _events.ScheduleEvent(EVENT_SOUL_CORRUPTION, urand(15000, 19000)); break; case EVENT_CREATURE_OF_NIGHTMARE: - DoCastVictim(SPELL_CREATURE_OF_NIGHTMARE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_CREATURE_OF_NIGHTMARE); _events.ScheduleEvent(EVENT_CREATURE_OF_NIGHTMARE, 45000); break; default: break; } } + DoMeleeAttackIfReady(); } @@ -124,27 +131,22 @@ public: # at_twilight_grove ######*/ +Position const TwillightCorrupter = { -10328.16f, -489.57f, 49.95f, 0.0f }; + class at_twilight_grove : public AreaTriggerScript { -public: - at_twilight_grove() : AreaTriggerScript("at_twilight_grove") { } + public: + at_twilight_grove() : AreaTriggerScript("at_twilight_grove") { } - bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override - { - if (player->HasQuestForItem(ITEM_FRAGMENT)) + bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override { - if (Unit* corrupter = player->SummonCreature(NPC_TWILIGHT_CORRUPTER, -10328.16f, -489.57f, 49.95f, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000)) - corrupter->setFaction(FACTION_HOSTILE); + if (player->GetQuestStatus(QUEST_NIGHTMARES_CORRUPTION) == QUEST_STATUS_INCOMPLETE) + if (!player->FindNearestCreature(NPC_TWILIGHT_CORRUPTER, 500.0f, true)) + if (Creature* corrupter = player->SummonCreature(NPC_TWILIGHT_CORRUPTER, TwillightCorrupter, TEMPSUMMON_MANUAL_DESPAWN, 60000)) + corrupter->AI()->Talk(YELL_TWILIGHT_CORRUPTOR_RESPAWN, player); - if (Creature* CorrupterSpeaker = player->SummonCreature(1, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()-1, 0, TEMPSUMMON_TIMED_DESPAWN, 15000)) - { - CorrupterSpeaker->SetName("Twilight Corrupter"); - CorrupterSpeaker->SetVisible(true); - CorrupterSpeaker->AI()->Talk(YELL_TWILIGHTCORRUPTOR_RESPAWN, player); - } - } - return false; - }; + return false; + }; }; void AddSC_duskwood() diff --git a/src/server/scripts/Kalimdor/zone_durotar.cpp b/src/server/scripts/Kalimdor/zone_durotar.cpp index 8d6ae347b85..358814d440a 100644 --- a/src/server/scripts/Kalimdor/zone_durotar.cpp +++ b/src/server/scripts/Kalimdor/zone_durotar.cpp @@ -447,7 +447,7 @@ class spell_mount_check : public SpellScriptLoader class spell_mount_check_AuraScript : public AuraScript { - PrepareAuraScript(spell_mount_check_AuraScript) + PrepareAuraScript(spell_mount_check_AuraScript); bool Validate(SpellInfo const* /*spellInfo*/) override { @@ -495,7 +495,7 @@ class spell_voljin_war_drums : public SpellScriptLoader class spell_voljin_war_drums_SpellScript : public SpellScript { - PrepareSpellScript(spell_voljin_war_drums_SpellScript) + PrepareSpellScript(spell_voljin_war_drums_SpellScript); bool Validate(SpellInfo const* /*spellInfo*/) override { @@ -552,7 +552,7 @@ class spell_voodoo : public SpellScriptLoader class spell_voodoo_SpellScript : public SpellScript { - PrepareSpellScript(spell_voodoo_SpellScript) + PrepareSpellScript(spell_voodoo_SpellScript); bool Validate(SpellInfo const* /*spellInfo*/) override { diff --git a/src/server/scripts/Kalimdor/zone_silithus.cpp b/src/server/scripts/Kalimdor/zone_silithus.cpp index 3f4fb31a11d..42ab3d8d9cf 100644 --- a/src/server/scripts/Kalimdor/zone_silithus.cpp +++ b/src/server/scripts/Kalimdor/zone_silithus.cpp @@ -1006,7 +1006,7 @@ void npc_qiraj_war_spawn::npc_qiraj_war_spawnAI::JustDied(Unit* /*slayer*/) if (npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI* triggerAI = CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, mob->AI())) triggerAI->LiveCounter(); -}; +} /*##### # go_crystalline_tear diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp index abeafe156ad..c0f7b2f1856 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp @@ -553,7 +553,7 @@ class spell_mistress_kiss_area : public SpellScriptLoader class spell_mistress_kiss_area_SpellScript : public SpellScript { - PrepareSpellScript(spell_mistress_kiss_area_SpellScript) + PrepareSpellScript(spell_mistress_kiss_area_SpellScript); void FilterTargets(std::list<WorldObject*>& targets) { diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index 00eb970b57b..5fa52c1eb53 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -673,8 +673,7 @@ class spell_powering_up : public SpellScriptLoader class spell_powering_up_SpellScript : public SpellScript { - public: - PrepareSpellScript(spell_powering_up_SpellScript) + PrepareSpellScript(spell_powering_up_SpellScript); uint32 spellId; uint32 poweringUp; diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp index 9cf61058bd9..a5577b6a0ea 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp @@ -25,7 +25,7 @@ enum Texts SAY_SLAY = 1, SAY_DEATH = 2, SAY_IMPENDING_DESPAIR = 3, - SAY_DEFILING_HORROR = 4, + SAY_DEFILING_HORROR = 4 }; enum Spells @@ -33,8 +33,9 @@ enum Spells SPELL_QUIVERING_STRIKE = 72422, SPELL_IMPENDING_DESPAIR = 72426, SPELL_DEFILING_HORROR = 72435, - SPELL_HOPELESSNESS = 72395, - H_SPELL_HOPELESSNESS = 72390, /// @todo not in dbc. Add in DB. + SPELL_HOPELESSNESS_1 = 72395, + SPELL_HOPELESSNESS_2 = 72396, + SPELL_HOPELESSNESS_3 = 72397 }; enum Events @@ -42,99 +43,106 @@ enum Events EVENT_NONE, EVENT_QUIVERING_STRIKE, EVENT_IMPENDING_DESPAIR, - EVENT_DEFILING_HORROR, + EVENT_DEFILING_HORROR }; +uint32 const HopelessnessHelper[3] = { SPELL_HOPELESSNESS_1, SPELL_HOPELESSNESS_2, SPELL_HOPELESSNESS_3 }; + class boss_falric : public CreatureScript { -public: - boss_falric() : CreatureScript("boss_falric") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_falricAI>(creature); - } - - struct boss_falricAI : public boss_horAI - { - boss_falricAI(Creature* creature) : boss_horAI(creature) { } - - uint8 uiHopelessnessCount; - - void Reset() override - { - boss_horAI::Reset(); - - uiHopelessnessCount = 0; + public: + boss_falric() : CreatureScript("boss_falric") { } - instance->SetBossState(DATA_FALRIC_EVENT, NOT_STARTED); - } - - void EnterCombat(Unit* /*who*/) override + struct boss_falricAI : public boss_horAI { - Talk(SAY_AGGRO); - instance->SetBossState(DATA_FALRIC_EVENT, IN_PROGRESS); - - events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 23000); - events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 9000); - events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000, 45000)); /// @todo adjust timer. - } + boss_falricAI(Creature* creature) : boss_horAI(creature, DATA_FALRIC) { } - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - - instance->SetBossState(DATA_FALRIC_EVENT, DONE); - } + void Reset() override + { + boss_horAI::Reset(); + _hopelessnessCount = 0; + } - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + DoZoneInCombat(); + instance->SetBossState(DATA_FALRIC, IN_PROGRESS); - void UpdateAI(uint32 diff) override - { - // Return since we have no target - if (!UpdateVictim()) - return; + events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 23000); + events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 9000); + events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(21000, 39000)); + } - events.Update(diff); + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if ((_hopelessnessCount < 1 && me->HealthBelowPctDamaged(66, damage)) + || (_hopelessnessCount < 2 && me->HealthBelowPctDamaged(33, damage)) + || (_hopelessnessCount < 3 && me->HealthBelowPctDamaged(10, damage))) + { + if (_hopelessnessCount) + me->RemoveOwnedAura(sSpellMgr->GetSpellIdForDifficulty(HopelessnessHelper[_hopelessnessCount - 1], me)); + DoCast(me, HopelessnessHelper[_hopelessnessCount]); + ++_hopelessnessCount; + } + } - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + events.Reset(); + instance->SetBossState(DATA_FALRIC, DONE); + } - switch (events.ExecuteEvent()) + void KilledUnit(Unit* who) override { - case EVENT_QUIVERING_STRIKE: - DoCast(SPELL_QUIVERING_STRIKE); - events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 10000); - break; - case EVENT_IMPENDING_DESPAIR: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - { - Talk(SAY_IMPENDING_DESPAIR); - DoCast(target, SPELL_IMPENDING_DESPAIR); - } - events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 13000); - break; - case EVENT_DEFILING_HORROR: - DoCast(SPELL_DEFILING_HORROR); - events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000, 45000)); /// @todo adjust timer. - break; + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); } - if ((uiHopelessnessCount < 1 && HealthBelowPct(66)) - || (uiHopelessnessCount < 2 && HealthBelowPct(33)) - || (uiHopelessnessCount < 3 && HealthBelowPct(10))) + void UpdateAI(uint32 diff) override { - uiHopelessnessCount++; - DoCast(DUNGEON_MODE(SPELL_HOPELESSNESS, H_SPELL_HOPELESSNESS)); + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_QUIVERING_STRIKE: + DoCastVictim(SPELL_QUIVERING_STRIKE); + events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 10000); + break; + case EVENT_IMPENDING_DESPAIR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) + { + Talk(SAY_IMPENDING_DESPAIR); + DoCast(target, SPELL_IMPENDING_DESPAIR); + } + events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 13000); + break; + case EVENT_DEFILING_HORROR: + DoCastAOE(SPELL_DEFILING_HORROR); + events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(21000, 39000)); + break; + default: + break; + } + + DoMeleeAttackIfReady(); } - DoMeleeAttackIfReady(); - } - }; + private: + uint8 _hopelessnessCount; + }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<boss_falricAI>(creature); + } }; void AddSC_boss_falric() diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp index cf267ff1079..902a917c594 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp @@ -17,6 +17,8 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" #include "halls_of_reflection.h" enum Texts @@ -33,6 +35,7 @@ enum Spells SPELL_WELL_OF_CORRUPTION = 72362, SPELL_CORRUPTED_FLESH = 72363, SPELL_SHARED_SUFFERING = 72368, + SPELL_SHARED_SUFFERING_DISPEL = 72373 }; enum Events @@ -41,93 +44,130 @@ enum Events EVENT_OBLITERATE, EVENT_WELL_OF_CORRUPTION, EVENT_CORRUPTED_FLESH, - EVENT_SHARED_SUFFERING, + EVENT_SHARED_SUFFERING }; class boss_marwyn : public CreatureScript { -public: - boss_marwyn() : CreatureScript("boss_marwyn") { } + public: + boss_marwyn() : CreatureScript("boss_marwyn") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_marwynAI>(creature); - } - - struct boss_marwynAI : public boss_horAI - { - boss_marwynAI(Creature* creature) : boss_horAI(creature) { } - - void Reset() override + struct boss_marwynAI : public boss_horAI { - boss_horAI::Reset(); + boss_marwynAI(Creature* creature) : boss_horAI(creature, DATA_MARWYN) { } - instance->SetBossState(DATA_MARWYN_EVENT, NOT_STARTED); - } + void Reset() override + { + boss_horAI::Reset(); + } - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - instance->SetBossState(DATA_MARWYN_EVENT, IN_PROGRESS); + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + DoZoneInCombat(); + instance->SetBossState(DATA_MARWYN, IN_PROGRESS); + + events.ScheduleEvent(EVENT_OBLITERATE, urand(8000, 13000)); + events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000); + events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20000); + events.ScheduleEvent(EVENT_SHARED_SUFFERING, urand(14000, 15000)); + } - events.ScheduleEvent(EVENT_OBLITERATE, 30000); /// @todo Check timer - events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000); - events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20000); - events.ScheduleEvent(EVENT_SHARED_SUFFERING, 20000); /// @todo Check timer - } + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + events.Reset(); + instance->SetBossState(DATA_MARWYN, DONE); + } - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } - instance->SetBossState(DATA_MARWYN_EVENT, DONE); - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_OBLITERATE: + DoCastVictim(SPELL_OBLITERATE); + events.ScheduleEvent(EVENT_OBLITERATE, urand(8000, 13000)); + break; + case EVENT_WELL_OF_CORRUPTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_WELL_OF_CORRUPTION); + events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000); + break; + case EVENT_CORRUPTED_FLESH: + Talk(SAY_CORRUPTED_FLESH); + DoCastAOE(SPELL_CORRUPTED_FLESH); + events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20000); + break; + case EVENT_SHARED_SUFFERING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_SHARED_SUFFERING); + events.ScheduleEvent(EVENT_SHARED_SUFFERING, urand(14000, 15000)); + break; + default: + break; + } + + DoMeleeAttackIfReady(); + } + }; - void KilledUnit(Unit* /*victim*/) override + CreatureAI* GetAI(Creature* creature) const override { - Talk(SAY_SLAY); + return GetHallsOfReflectionAI<boss_marwynAI>(creature); } +}; - void UpdateAI(uint32 diff) override - { - // Return since we have no target - if (!UpdateVictim()) - return; +// 72368, 72369 - Shared Suffering +class spell_marwyn_shared_suffering : public SpellScriptLoader +{ + public: + spell_marwyn_shared_suffering() : SpellScriptLoader("spell_marwyn_shared_suffering") { } - events.Update(diff); + class spell_marwyn_shared_suffering_AuraScript : public AuraScript + { + PrepareAuraScript(spell_marwyn_shared_suffering_AuraScript); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + void HandleEffectRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL) + return; + + if (Unit* caster = GetCaster()) + { + int32 remainingDamage = aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber()); + if (remainingDamage > 0) + caster->CastCustomSpell(SPELL_SHARED_SUFFERING_DISPEL, SPELLVALUE_BASE_POINT1, remainingDamage, GetTarget(), TRIGGERED_FULL_MASK); + } + } - switch (events.ExecuteEvent()) + void Register() override { - case EVENT_OBLITERATE: - DoCast(SPELL_OBLITERATE); - events.ScheduleEvent(EVENT_OBLITERATE, 30000); - break; - case EVENT_WELL_OF_CORRUPTION: - DoCast(SPELL_WELL_OF_CORRUPTION); - events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000); - break; - case EVENT_CORRUPTED_FLESH: - Talk(SAY_CORRUPTED_FLESH); - DoCast(SPELL_CORRUPTED_FLESH); - events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20000); - break; - case EVENT_SHARED_SUFFERING: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHARED_SUFFERING); - events.ScheduleEvent(EVENT_SHARED_SUFFERING, 20000); - break; + AfterEffectRemove += AuraEffectRemoveFn(spell_marwyn_shared_suffering_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); } + }; - DoMeleeAttackIfReady(); + AuraScript* GetAuraScript() const override + { + return new spell_marwyn_shared_suffering_AuraScript(); } - }; - }; void AddSC_boss_marwyn() { new boss_marwyn(); + new spell_marwyn_shared_suffering(); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index ca2a181a48a..0c5514a1c0a 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -18,6 +18,8 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" +#include "SpellScript.h" +#include "Transport.h" #include "Player.h" #include "halls_of_reflection.h" @@ -36,17 +38,6 @@ enum Text SAY_JAINA_INTRO_11 = 10, SAY_JAINA_INTRO_END = 11, - SAY_JAINA_ESCAPE_1 = 0, - SAY_JAINA_ESCAPE_2 = 1, - SAY_JAINA_ESCAPE_3 = 2, - SAY_JAINA_ESCAPE_4 = 3, - SAY_JAINA_ESCAPE_5 = 4, - SAY_JAINA_ESCAPE_6 = 5, - SAY_JAINA_ESCAPE_7 = 6, - SAY_JAINA_ESCAPE_8 = 7, - SAY_JAINA_ESCAPE_9 = 8, - SAY_JAINA_ESCAPE_10 = 9, - SAY_SYLVANAS_INTRO_1 = 0, SAY_SYLVANAS_INTRO_2 = 1, SAY_SYLVANAS_INTRO_3 = 2, @@ -57,16 +48,6 @@ enum Text SAY_SYLVANAS_INTRO_8 = 7, SAY_SYLVANAS_INTRO_END = 8, - SAY_SYLVANAS_ESCAPE_1 = 0, - SAY_SYLVANAS_ESCAPE_2 = 1, - SAY_SYLVANAS_ESCAPE_3 = 2, - SAY_SYLVANAS_ESCAPE_4 = 3, - SAY_SYLVANAS_ESCAPE_5 = 4, - SAY_SYLVANAS_ESCAPE_6 = 5, - SAY_SYLVANAS_ESCAPE_7 = 6, - SAY_SYLVANAS_ESCAPE_8 = 7, - SAY_SYLVANAS_ESCAPE_9 = 8, - SAY_UTHER_INTRO_A2_1 = 0, SAY_UTHER_INTRO_A2_2 = 1, SAY_UTHER_INTRO_A2_3 = 2, @@ -90,27 +71,40 @@ enum Text SAY_LK_JAINA_INTRO_END = 3, SAY_LK_SYLVANAS_INTRO_END = 4, + SAY_JAINA_SYLVANAS_ESCAPE_1 = 0, + SAY_JAINA_SYLVANAS_ESCAPE_2 = 1, + SAY_JAINA_SYLVANAS_ESCAPE_3 = 2, + SAY_JAINA_SYLVANAS_ESCAPE_4 = 3, + SAY_JAINA_SYLVANAS_ESCAPE_5 = 4, + SAY_JAINA_SYLVANAS_ESCAPE_6 = 5, + SAY_JAINA_SYLVANAS_ESCAPE_7 = 6, // unused + SAY_JAINA_SYLVANAS_ESCAPE_8 = 7, + + SAY_JAINA_ESCAPE_9 = 8, + SAY_JAINA_ESCAPE_10 = 9, + + SAY_SYLVANAS_ESCAPE_9 = 8, + SAY_LK_ESCAPE_1 = 0, SAY_LK_ESCAPE_2 = 1, - SAY_LK_ESCAPE_3 = 2, - SAY_LK_ESCAPE_4 = 3, - SAY_LK_ESCAPE_5 = 4, - SAY_LK_ESCAPE_6 = 5, - SAY_LK_ESCAPE_7 = 6, - SAY_LK_ESCAPE_8 = 7, - SAY_LK_ESCAPE_9 = 8, - SAY_LK_ESCAPE_10 = 9, - SAY_LK_ESCAPE_11 = 10, + SAY_LK_ESCAPE_ICEWALL_SUMMONED_1 = 2, + SAY_LK_ESCAPE_ICEWALL_SUMMONED_2 = 3, + SAY_LK_ESCAPE_ICEWALL_SUMMONED_3 = 4, + SAY_LK_ESCAPE_ICEWALL_SUMMONED_4 = 5, + SAY_LK_ESCAPE_GHOULS = 6, + SAY_LK_ESCAPE_ABOMINATION = 7, + SAY_LK_ESCAPE_WINTER = 8, + SAY_LK_ESCAPE_HARVEST_SOUL = 9, SAY_FALRIC_INTRO_1 = 5, SAY_FALRIC_INTRO_2 = 6, - SAY_MARWYN_INTRO_1 = 4, + SAY_MARWYN_INTRO_1 = 4 }; enum Events { - EVENT_WALK_INTRO1 = 1, + EVENT_WALK_INTRO1 = 1, EVENT_WALK_INTRO2, EVENT_START_INTRO, EVENT_SKIP_INTRO, @@ -181,21 +175,17 @@ enum Events EVENT_ESCAPE_13, EVENT_ESCAPE_14, EVENT_ESCAPE_15, - //EVENT_ESCAPE_16, + EVENT_ESCAPE_16, EVENT_ESCAPE_17, - EVENT_ESCAPE_18, - EVENT_ESCAPE_19, - EVENT_ESCAPE_20, - EVENT_ESCAPE_21, - EVENT_ESCAPE_22, - EVENT_ESCAPE_23, - EVENT_ESCAPE_24, - EVENT_ESCAPE_25, - EVENT_ESCAPE_26, - EVENT_ESCAPE_27, - - EVENT_OPEN_FROSTWORN_DOOR, - EVENT_CLOSE_FROSTWORN_DOOR, + + EVENT_REMORSELESS_WINTER, + EVENT_ESCAPE_SUMMON_GHOULS, + EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, + EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION, + + EVENT_OPEN_IMPENETRABLE_DOOR, + EVENT_CLOSE_IMPENETRABLE_DOOR, + EVENT_KORELN_LORALEN_DEATH }; enum Misc @@ -203,907 +193,1151 @@ enum Misc ACTION_START_INTRO, ACTION_SKIP_INTRO, - QUEST_DELIVRANCE_FROM_THE_PIT_A2 = 24710, - QUEST_DELIVRANCE_FROM_THE_PIT_H2 = 24712, - QUEST_WRATH_OF_THE_LICH_KING_A2 = 24500, - QUEST_WRATH_OF_THE_LICH_KING_H2 = 24802, + JAINA_SYLVANAS_MAX_HEALTH = 252000, + + POINT_SHADOW_THRONE_DOOR = 1, + POINT_ATTACK_ICEWALL = 2, + POINT_TRAP = 3, + + SOUND_LK_SLAY_1 = 17214, + SOUND_LK_SLAY_2 = 17215, + SOUND_LK_FURY_OF_FROSTMOURNE = 17224 }; enum Spells { - SPELL_CAST_VISUAL = 65633, // Jaina/Sylavana - SPELL_BOSS_SPAWN_AURA = 72712, // Falric and Marwyn - SPELL_UTHER_DESPAWN = 70693, + // Misc SPELL_TAKE_FROSTMOURNE = 72729, SPELL_FROSTMOURNE_DESPAWN = 72726, SPELL_FROSTMOURNE_VISUAL = 73220, SPELL_FROSTMOURNE_SOUNDS = 70667, - SPELL_JAINA_ICEBARRIER = 69787, // Jaina Ice Barrier - SPELL_JAINA_ICEPRISON = 69708, // Jaina Ice Prison - SPELL_SYLVANAS_CLOAKOFDARKNESS = 70188, // Sylvanas Cloak of Darkness - SPELL_SYLVANAS_DARKBINDING = 70194, // Sylvanas Dark Binding - SPELL_REMORSELESS_WINTER = 69780, // Lich King Remorseless Winter - SPELL_SOUL_REAPER = 69409, // Lich King Soul Reaper - SPELL_FURY_OF_FROSTMOURNE = 70063, // Lich King Fury of FrostMourne + SPELL_BOSS_SPAWN_AURA = 72712, // Falric and Marwyn + SPELL_UTHER_DESPAWN = 70693, + + // Jaina, Sylvanas + SPELL_CAST_VISUAL = 65633, // wrong + SPELL_SUMMON_SOULS = 72711, + SPELL_TAUNT_ARTHAS = 69857, + SPELL_JAINA_ICE_BARRIER = 69787, // Jaina Ice Barrier + SPELL_JAINA_ICE_PRISON = 69708, // Jaina Ice Prison SPELL_JAINA_DESTROY_ICE_WALL = 69784, // Jaina + SPELL_SYLVANAS_CLOAK_OF_DARKNESS = 70188, // Sylvanas Cloak of Darkness + SPELL_SYLVANAS_DARK_BINDING = 70194, // Sylvanas Dark Binding SPELL_SYLVANAS_DESTROY_ICE_WALL = 70224, // Sylvanas - SPELL_SYLVANAS_JUMP = 68339, // Sylvanas Jump + SPELL_SYLVANAS_BLINDING_RETREAT = 70199, // Sylvanas Blinding Retreat + + // Lich King + SPELL_REMORSELESS_WINTER = 69780, // Lich King Remorseless Winter + SPELL_SOUL_REAPER = 69409, // Lich King Soul Reaper + SPELL_FURY_OF_FROSTMOURNE = 70063, // Lich King Fury of Frostmourne SPELL_RAISE_DEAD = 69818, - SPELL_HARVEST_SOUL = 70070, - SPELL_SUMMON_RISE_WITCH_DOCTOR = 69836, + SPELL_SUMMON_RISEN_WITCH_DOCTOR = 69836, SPELL_SUMMON_LUMBERING_ABOMINATION = 69835, SPELL_SUMMON_ICE_WALL = 69768, // Visual effect and icewall summoning + SPELL_PAIN_AND_SUFFERING = 74115, // Lich King Pain and Suffering + SPELL_STUN_BREAK_JAINA = 69764, // Lich King visual spell, another Stun Break is 69763, should remove the stun effect + SPELL_STUN_BREAK_SYLVANAS = 70200, + SPELL_HARVEST_SOUL = 69866, // Lich King Harvest Soul + + // Koreln, Loralen + SPELL_FEIGN_DEATH = 29266, // Raging Ghoul - SPELL_EMERGE_VISUAL = 50142, SPELL_GHOUL_JUMP = 70150, + SPELL_RAGING_GHOUL_SPAWN = 69636, - // Witch Doctor - SPELL_COURSE_OF_DOOM = 70144, + // Risen Witch Doctor + SPELL_CURSE_OF_DOOM = 70144, SPELL_SHADOW_BOLT_VOLLEY = 70145, SPELL_SHADOW_BOLT = 70080, + SPELL_RISEN_WITCH_DOCTOR_SPAWN = 69639, // Lumbering Abomination - SPELL_ABON_STRIKE = 40505, - SPELL_VOMIT_SPRAY = 70176, + SPELL_CLEAVE = 40505, + SPELL_VOMIT_SPRAY = 70176 }; -const Position HallsofReflectionLocs[] = +enum HorGossipMenu { - {5283.234863f, 1990.946777f, 707.695679f, 0.929097f}, // 2 Loralen Follows - {5408.031250f, 2102.918213f, 707.695251f, 0.792756f}, // 9 Sylvanas Follows - {5401.866699f, 2110.837402f, 707.695251f, 0.800610f}, // 10 Loralen follows + GOSSIP_MENU_JAINA_FINAL = 10930, + GOSSIP_MENU_SYLVANAS_FINAL = 10931 }; -const Position NpcJainaOrSylvanasEscapeRoute[] = +Position const NpcJainaOrSylvanasEscapeRoute[] = { - {5601.217285f, 2207.652832f, 731.541931f, 5.223304f}, // leave the throne room - {5607.224375f, 2173.913330f, 731.126038f, 2.608723f}, // adjust route - {5583.427246f, 2138.784180f, 731.150391f, 4.260901f}, // stop for talking - {5560.281738f, 2104.025635f, 731.410889f, 4.058383f}, // attack the first icewall - {5510.990723f, 2000.772217f, 734.716064f, 3.973213f}, // attack the second icewall - {5452.641113f, 1905.762329f, 746.530579f, 4.118834f}, // attack the third icewall - {5338.126953f, 1768.429810f, 767.237244f, 3.855189f}, // attack the fourth icewall - {5257.712402f, 1669.379395f, 784.300110f, 0.908373f}, // face the Lich king - {5261.191895f, 1681.901611f, 784.285278f, 4.410465f}, // final position + { 5601.217285f, 2207.652832f, 731.541931f, 5.223304f }, // leave the throne room + { 5607.224375f, 2173.913330f, 731.126038f, 2.608723f }, // adjust route + { 5583.427246f, 2138.784180f, 731.150391f, 4.260901f }, // stop for talking + { 5560.281738f, 2104.025635f, 731.410889f, 4.058383f }, // attack the first icewall + { 5510.990723f, 2000.772217f, 734.716064f, 3.973213f }, // attack the second icewall + { 5452.641113f, 1905.762329f, 746.530579f, 4.118834f }, // attack the third icewall + { 5338.126953f, 1768.429810f, 767.237244f, 3.855189f }, // attack the fourth icewall + { 5259.06f, 1669.27f, 784.3008f, 0.0f }, // trap (sniffed) + { 5265.53f, 1681.6f, 784.2947f, 4.13643f } // final position (sniffed) }; -const Position IceWalls[] = +Position const LichKingMoveAwayPos = { 5400.069824f, 2102.7131689f, 707.69525f, 0.843803f }; // Lich King walks away +Position const LichKingFirstSummon = { 5600.076172f, 2192.270996f, 731.750488f, 4.330935f }; // Lich King First summons +Position const JainaSylvanasShadowThroneDoor = { 5577.243f, 2235.852f, 733.0128f, 2.209562f }; // Jaina/Sylvanas move to door +Position const LichKingFinalPos = { 5283.742188f, 1706.335693f, 783.293518f, 4.138510f }; // Lich King Final Pos + +// sniffed +Position const KorelnOrLoralenPos[] = { - {5547.833f, 2083.701f,731.4332f,4.24115f}, // first icewall - {5503.213f, 1969.547f,737.0245f,4.293779f},// second icewall - {5439.976f, 1879.005f,752.7048f,4.207591f},// third icewall - {5318.289f, 1749.184f,771.9423f,4.054276f},// fourth icewall + { 5253.061f, 1953.616f, 707.6948f, 0.8377581f }, + { 5283.226f, 1992.300f, 707.7445f, 0.8377581f }, + { 5360.711f, 2064.797f, 707.6948f, 0.0f } }; -const Position IntroPos = {5265.89f, 1952.98f, 707.6978f, 0.0f}; // Jaina/Sylvanas Intro Start Position -const Position MoveThronePos = {5306.952148f, 1998.499023f, 709.341431f, 1.277278f}; // Jaina/Sylvanas walks to throne -const Position UtherSpawnPos = {5308.310059f, 2003.857178f, 709.341431f, 4.650315f}; -const Position LichKingSpawnPos = {5362.917480f, 2062.307129f, 707.695374f, 3.945812f}; -const Position LichKingMoveThronePos = {5312.080566f, 2009.172119f, 709.341431f, 3.973301f}; // Lich King walks to throne -const Position LichKingMoveAwayPos = {5400.069824f, 2102.7131689f, 707.69525f, 0.843803f}; // Lich King walks away -const Position LichKingSpawnPos2 = {5552.733398f, 2262.718506f, 733.011047f, 4.009696f}; // Lich King Spawn Position 2 -const Position LichKingFirstSummon = {5600.076172f, 2192.270996f, 731.750488f, 4.330935f}; // Lich King First summons -const Position JainaShadowThroneDoor = {5577.243f, 2235.852f, 733.0128f, 2.209562f}; // Jaina Spawn Position 2 -const Position SylvanasShadowThroneDoor = {5577.243f, 2235.852f, 733.0128f, 2.209562f}; // Sylvanas Spawn Position 2 -const Position FalricStartPos = {5283.878906f, 2030.459595f, 709.319641f, 5.506670f}; // Falric start position -const Position MarwynStartPos = {5334.979980f, 1982.399536f, 709.320129f, 2.347014f}; // Marwyn start position -const Position LichKingFinalPos = {5283.742188f, 1706.335693f, 783.293518f, 4.138510f}; // Lich King Final Pos -const Position ChestPos = {5246.187500f, 1649.079468f, 784.301758f, 0.901268f}; // Chest position -const Position FinalPortalPos = {5270.634277f ,1639.101196f, 784.303040f, 1.682743f}; // Final portal position - -class npc_jaina_or_sylvanas_hor : public CreatureScript +Position const SylvanasIntroPosition[] = { - public: - npc_jaina_or_sylvanas_hor() : CreatureScript("npc_jaina_or_sylvanas_hor") { } - - // AI of Part1 - struct npc_jaina_or_sylvanas_horAI : public ScriptedAI - { - npc_jaina_or_sylvanas_horAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - } - - InstanceScript* _instance; - uint64 _utherGUID; - uint64 _lichkingGUID; + { 0.0f, 0.0f, 0.0f, 0.0f }, // 0 - Spawn + { 5263.2f, 1950.96f, 707.6948f, 0.8028514f }, // 1 - Move to Door + { 5306.82f, 1998.17f, 709.341f, 1.239184f }, // 2 - Move to Frostmourne +}; - EventMap _events; +Position const JainaIntroPosition[] = +{ + { 0.0f, 0.0f, 0.0f, 0.0f }, // 0 - Spawn + { 5265.89f, 1952.98f, 707.6978f, 0.0f }, // 1 - Move to Door + { 5306.95f, 1998.49f, 709.3414f, 1.277278f } // 2 - Move to Frostmourne +}; - void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case 0: - player->CLOSE_GOSSIP_MENU(); - _events.ScheduleEvent(EVENT_START_INTRO, 1000); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); - break; - case 1: - player->CLOSE_GOSSIP_MENU(); - _events.ScheduleEvent(EVENT_SKIP_INTRO, 1000); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); - break; - } - } +Position const UtherSpawnPos = { 5307.814f, 2003.168f, 709.4244f, 4.537856f }; - void Reset() override - { - _events.Reset(); +Position const LichKingIntroPosition[] = +{ + { 5362.463f, 2062.693f, 707.7781f, 3.944444f }, // 0 - Spawn + { 5332.83f, 2031.24f, 707.6948f, 0.0f }, // 1 - Door + { 5312.93f, 2010.24f, 709.34f, 0.0f }, // 2 - Move to Frostmourne + { 5319.028f, 2016.662f, 707.6948f, 0.0f }, // 3 - Move back + { 5332.285f, 2030.832f, 707.6948f, 0.0f }, // 4 - Move back 2 + { 5355.488f, 2055.149f, 707.6907f, 0.0f } // 5 - Move back 3 +}; - _utherGUID = 0; - _lichkingGUID = 0; +Position const FalricPosition[] = +{ + { 5276.583f, 2037.45f, 709.4025f, 5.532694f }, // 0 - Spawn + { 5283.95f, 2030.53f, 709.3191f, 0.0f } // 1 - Intro +}; - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); - me->SetStandState(UNIT_STAND_STATE_STAND); - _events.ScheduleEvent(EVENT_WALK_INTRO1, 3000); - } +Position const MarwynPosition[] = +{ + { 5342.232f, 1975.696f, 709.4025f, 2.391101f }, // 0 - Spawn + { 5335.01f, 1982.37f, 709.3191f, 0.0f } // 1 - Intro +}; - void UpdateAI(uint32 diff) override - { - _events.Update(diff); +Position const SylvanasShadowThroneDoorPosition = { 5576.79f, 2235.73f, 733.0029f, 2.687807f }; - switch (_events.ExecuteEvent()) - { - case EVENT_WALK_INTRO1: - me->GetMotionMaster()->MovePoint(0, IntroPos); - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - { - Talk(SAY_JAINA_INTRO_1); - _events.ScheduleEvent(EVENT_WALK_INTRO2, 7000); - } - else - { - Talk(SAY_SYLVANAS_INTRO_1); - _events.ScheduleEvent(EVENT_WALK_INTRO2, 9000); - } - break; - case EVENT_WALK_INTRO2: - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - Talk(SAY_JAINA_INTRO_2); - else - Talk(SAY_SYLVANAS_INTRO_2); - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); - break; - case EVENT_START_INTRO: - me->GetMotionMaster()->MovePoint(0, MoveThronePos); - // Begining of intro is differents between fActions as the speech sequence and timers are differents. - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - _events.ScheduleEvent(EVENT_INTRO_A2_1, 0); - else - _events.ScheduleEvent(EVENT_INTRO_H2_1, 0); - break; - // A2 Intro Events - case EVENT_INTRO_A2_1: - Talk(SAY_JAINA_INTRO_3); - _events.ScheduleEvent(EVENT_INTRO_A2_2, 7000); - break; - case EVENT_INTRO_A2_2: - Talk(SAY_JAINA_INTRO_4); - _events.ScheduleEvent(EVENT_INTRO_A2_3, 10000); - break; - case EVENT_INTRO_A2_3: - me->CastSpell(me, SPELL_CAST_VISUAL, false); - me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); - _instance->HandleGameObject(_instance->GetData64(DATA_FROSTMOURNE), true); - _events.ScheduleEvent(EVENT_INTRO_A2_4, 10000); - break; - case EVENT_INTRO_A2_4: - if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) - { - uther->GetMotionMaster()->MoveIdle(); - _utherGUID = uther->GetGUID(); - } - _events.ScheduleEvent(EVENT_INTRO_A2_5, 2000); - break; - case EVENT_INTRO_A2_5: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_1); - _events.ScheduleEvent(EVENT_INTRO_A2_6, 3000); - break; - case EVENT_INTRO_A2_6: - Talk(SAY_JAINA_INTRO_5); - _events.ScheduleEvent(EVENT_INTRO_A2_7, 7000); - break; - case EVENT_INTRO_A2_7: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_2); - _events.ScheduleEvent(EVENT_INTRO_A2_8, 7000); - break; - case EVENT_INTRO_A2_8: - Talk(SAY_JAINA_INTRO_6); - _events.ScheduleEvent(EVENT_INTRO_A2_9, 1200); - break; - case EVENT_INTRO_A2_9: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_3); - _events.ScheduleEvent(EVENT_INTRO_A2_10, 11000); - break; - case EVENT_INTRO_A2_10: - Talk(SAY_JAINA_INTRO_7); - _events.ScheduleEvent(EVENT_INTRO_A2_11, 6000); - break; - case EVENT_INTRO_A2_11: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_4); - _events.ScheduleEvent(EVENT_INTRO_A2_12, 12000); - break; - case EVENT_INTRO_A2_12: - Talk(SAY_JAINA_INTRO_8); - _events.ScheduleEvent(EVENT_INTRO_A2_13, 6000); - break; - case EVENT_INTRO_A2_13: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_5); - _events.ScheduleEvent(EVENT_INTRO_A2_14, 13000); - break; - case EVENT_INTRO_A2_14: - Talk(SAY_JAINA_INTRO_9); - _events.ScheduleEvent(EVENT_INTRO_A2_15, 12000); - break; - case EVENT_INTRO_A2_15: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_6); - _events.ScheduleEvent(EVENT_INTRO_A2_16, 25000); - break; - case EVENT_INTRO_A2_16: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_7); - _events.ScheduleEvent(EVENT_INTRO_A2_17, 6000); - break; - case EVENT_INTRO_A2_17: - Talk(SAY_JAINA_INTRO_10); - _events.ScheduleEvent(EVENT_INTRO_A2_18, 5000); - break; - case EVENT_INTRO_A2_18: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - { - uther->HandleEmoteCommand(EMOTE_ONESHOT_NO); - uther->AI()->Talk(SAY_UTHER_INTRO_A2_8); - } - _events.ScheduleEvent(EVENT_INTRO_A2_19, 12000); - break; - case EVENT_INTRO_A2_19: - Talk(SAY_JAINA_INTRO_11); - _events.ScheduleEvent(EVENT_INTRO_LK_1, 3000); - break; - // H2 Intro Events - case EVENT_INTRO_H2_1: - Talk(SAY_SYLVANAS_INTRO_1); - _events.ScheduleEvent(EVENT_INTRO_H2_2, 8000); - break; - case EVENT_INTRO_H2_2: - Talk(SAY_SYLVANAS_INTRO_2); - _events.ScheduleEvent(EVENT_INTRO_H2_3, 6000); - break; - case EVENT_INTRO_H2_3: - Talk(SAY_SYLVANAS_INTRO_3); - me->CastSpell(me, SPELL_CAST_VISUAL, false); - me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); - _instance->HandleGameObject(_instance->GetData64(DATA_FROSTMOURNE), true); - _events.ScheduleEvent(EVENT_INTRO_H2_4, 6000); - break; - case EVENT_INTRO_H2_4: - // spawn UTHER during speach 2 - if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) - { - uther->GetMotionMaster()->MoveIdle(); - _utherGUID = uther->GetGUID(); - } - _events.ScheduleEvent(EVENT_INTRO_H2_5, 2000); - break; - case EVENT_INTRO_H2_5: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_H2_1); - _events.ScheduleEvent(EVENT_INTRO_H2_6, 11000); - break; - case EVENT_INTRO_H2_6: - Talk(SAY_SYLVANAS_INTRO_4); - _events.ScheduleEvent(EVENT_INTRO_H2_7, 3000); - break; - case EVENT_INTRO_H2_7: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_H2_2); - _events.ScheduleEvent(EVENT_INTRO_H2_8, 6000); - break; - case EVENT_INTRO_H2_8: - Talk(SAY_SYLVANAS_INTRO_5); - _events.ScheduleEvent(EVENT_INTRO_H2_9, 5000); - break; - case EVENT_INTRO_H2_9: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_H2_3); - _events.ScheduleEvent(EVENT_INTRO_H2_10, 19000); - break; - case EVENT_INTRO_H2_10: - Talk(SAY_SYLVANAS_INTRO_6); - _events.ScheduleEvent(EVENT_INTRO_H2_11, 1500); - break; - case EVENT_INTRO_H2_11: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_H2_4); - _events.ScheduleEvent(EVENT_INTRO_H2_12, 19500); - break; - case EVENT_INTRO_H2_12: - Talk(SAY_SYLVANAS_INTRO_7); - _events.ScheduleEvent(EVENT_INTRO_H2_13, 2000); - break; - case EVENT_INTRO_H2_13: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - { - uther->HandleEmoteCommand(EMOTE_ONESHOT_NO); - uther->AI()->Talk(SAY_UTHER_INTRO_H2_5); - } - _events.ScheduleEvent(EVENT_INTRO_H2_14, 12000); - break; - case EVENT_INTRO_H2_14: - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - uther->AI()->Talk(SAY_UTHER_INTRO_H2_6); - _events.ScheduleEvent(EVENT_INTRO_H2_15, 8000); - break; - case EVENT_INTRO_H2_15: - Talk(SAY_SYLVANAS_INTRO_8); - _events.ScheduleEvent(EVENT_INTRO_LK_1, 2000); - break; - // Remaining Intro Events common for both faction - case EVENT_INTRO_LK_1: - // Spawn LK in front of door, and make him move to the sword. - if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART1, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) - { - lichking->SetWalk(true); - lichking->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos); - _lichkingGUID = lichking->GetGUID(); - _events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 0); - _events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 4000); - } - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - { - uther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - uther->AI()->Talk(SAY_UTHER_INTRO_A2_9); - else - uther->AI()->Talk(SAY_UTHER_INTRO_H2_7); - } - _events.ScheduleEvent(EVENT_INTRO_LK_2, 10000); - break; - case EVENT_INTRO_LK_2: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->AI()->Talk(SAY_LK_INTRO_1); - _events.ScheduleEvent(EVENT_INTRO_LK_3, 1000); - break; - case EVENT_INTRO_LK_3: - // The Lich King banishes Uther to the abyss. - if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) - { - uther->CastSpell(uther, SPELL_UTHER_DESPAWN, true); - uther->DespawnOrUnsummon(5000); - _utherGUID = 0; - } - _events.ScheduleEvent(EVENT_INTRO_LK_4, 9000); - break; - case EVENT_INTRO_LK_4: - // He steps forward and removes the runeblade from the heap of skulls. - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - { - if (GameObject* frostmourne = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_FROSTMOURNE))) - frostmourne->SetPhaseMask(2, true); - lichking->CastSpell(lichking, SPELL_TAKE_FROSTMOURNE, true); - lichking->CastSpell(lichking, SPELL_FROSTMOURNE_VISUAL, true); - } - _events.ScheduleEvent(EVENT_INTRO_LK_5, 8000); - break; - case EVENT_INTRO_LK_5: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->AI()->Talk(SAY_LK_INTRO_2); - _events.ScheduleEvent(EVENT_INTRO_LK_6, 10000); - break; - case EVENT_INTRO_LK_6: - // summon Falric and Marwyn. then go back to the door - if (Creature* falric = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_FALRIC_EVENT))) - { - falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); - falric->SetVisible(true); - } - if (Creature* marwyn = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_MARWYN_EVENT))) - { - marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); - marwyn->SetVisible(true); - } - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - { - lichking->AI()->Talk(SAY_LK_INTRO_3); - lichking->SetWalk(true); - lichking->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); - } - _events.ScheduleEvent(EVENT_INTRO_LK_7, 10000); - _events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 5000); - break; - case EVENT_INTRO_LK_7: - if (Creature* marwyn = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_MARWYN_EVENT))) - { - marwyn->AI()->Talk(SAY_MARWYN_INTRO_1); - marwyn->SetWalk(true); - marwyn->GetMotionMaster()->MovePoint(0, MarwynStartPos); - } - _events.ScheduleEvent(EVENT_INTRO_LK_8, 1000); - break; - case EVENT_INTRO_LK_8: - if (Creature* falric = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_FALRIC_EVENT))) - { - falric->AI()->Talk(SAY_FALRIC_INTRO_1); - falric->SetWalk(true); - falric->GetMotionMaster()->MovePoint(0, FalricStartPos); - } - _events.ScheduleEvent(EVENT_INTRO_LK_9, 5000); - break; - case EVENT_INTRO_LK_9: - if (Creature* falric = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_FALRIC_EVENT))) - falric->AI()->Talk(SAY_FALRIC_INTRO_2); - _instance->ProcessEvent(0, EVENT_SPAWN_WAVES); - _events.ScheduleEvent(EVENT_INTRO_LK_10, 4000); - break; - case EVENT_INTRO_LK_10: - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - Talk(SAY_JAINA_INTRO_END); - else - Talk(SAY_SYLVANAS_INTRO_END); - me->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); - /// @todo Loralen/Koreln shall run also - _events.ScheduleEvent(EVENT_INTRO_LK_11, 5000); - break; - case EVENT_INTRO_LK_11: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - { - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - lichking->AI()->Talk(SAY_LK_JAINA_INTRO_END); - else - lichking->AI()->Talk(SAY_LK_SYLVANAS_INTRO_END); - } - _events.ScheduleEvent(EVENT_INTRO_END, 5000); - break; - case EVENT_INTRO_END: - _instance->SetData(DATA_INTRO_EVENT, DONE); - // Loralen or Koreln disappearAndDie() - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - { - lichking->DespawnOrUnsummon(5000); - _lichkingGUID = 0; - } - me->DespawnOrUnsummon(10000); - _events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 7000); - break; - case EVENT_SKIP_INTRO: - me->GetMotionMaster()->MovePoint(0, MoveThronePos); - /// @todo Loralen/Koreln shall run also - if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART1, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) - { - lichking->SetWalk(true); - lichking->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos); - lichking->SetReactState(REACT_PASSIVE); - _lichkingGUID = lichking->GetGUID(); - _events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 0); - _events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 4000); - } - _events.ScheduleEvent(EVENT_INTRO_LK_4, 15000); - break; - case EVENT_OPEN_FROSTWORN_DOOR: - if (GameObject* gate = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_FROSTWORN_DOOR))) - _instance->HandleGameObject(0, true, gate); - break; - case EVENT_CLOSE_FROSTWORN_DOOR: - if (GameObject* gate = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_FROSTWORN_DOOR))) - _instance->HandleGameObject(0, false, gate); - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI<npc_jaina_or_sylvanas_horAI>(creature); - } +Position const IceWallTargetPosition[] = +{ + { 5547.833f, 2083.701f, 731.4332f, 1.029744f }, // 1st Icewall + { 5503.213f, 1969.547f, 737.0245f, 1.27409f }, // 2nd Icewall + { 5439.976f, 1879.005f, 752.7048f, 1.064651f }, // 3rd Icewall + { 5318.289f, 1749.184f, 771.9423f, 0.8726646f } // 4th Icewall }; -class npc_jaina_or_sylvanas_escape_hor : public CreatureScript +class npc_jaina_or_sylvanas_intro_hor : public CreatureScript { public: - npc_jaina_or_sylvanas_escape_hor() : CreatureScript("npc_jaina_or_sylvanas_escape_hor") { } - - // AI of Part2 - struct npc_jaina_or_sylvanas_escape_horAI : public ScriptedAI - { - npc_jaina_or_sylvanas_escape_horAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()), _lichkingGUID(0), _walltargetGUID(0), - _icewallGUID(0), _icewall(0) - { - } - - InstanceScript* _instance; - uint64 _lichkingGUID; - uint64 _walltargetGUID; // dummy - uint64 _icewallGUID; // object - uint32 _icewall; // icewall number - - EventMap _events; + npc_jaina_or_sylvanas_intro_hor() : CreatureScript("npc_jaina_or_sylvanas_intro_hor") { } - void Reset() override + struct npc_jaina_or_sylvanas_intro_horAI : public ScriptedAI { - _events.Reset(); - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->DespawnOrUnsummon(1); - _lichkingGUID = 0; - _walltargetGUID = 0; - _icewallGUID = 0; - _icewall = 0; - _events.ScheduleEvent(EVENT_ESCAPE, 0); - } - - void JustDied(Unit* /*Killer*/) override - { - _instance->SetData(DATA_ESCAPE_EVENT, FAIL); - } - - void DoAction(int32 actionId) override - { - switch (actionId) - { - case ACTION_START_ESCAPING: // called by InstanceScript when we need to start the escaping event - _events.ScheduleEvent(EVENT_ESCAPE_1, 1000); - break; - case ACTION_WALL_BROKEN: - _icewall++; - if (_icewall != 4) - _events.ScheduleEvent(EVENT_ESCAPE_17, 3000); - else - _events.ScheduleEvent(EVENT_ESCAPE_23, 3000); - break; + npc_jaina_or_sylvanas_intro_horAI(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + _utherGUID = 0; + _lichkingGUID = 0; } - } - void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - switch (action) + void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override { - case 0: - player->CLOSE_GOSSIP_MENU(); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); - _events.ScheduleEvent(EVENT_ESCAPE_7, 0); - break; - } - } + player->PlayerTalkClass->ClearMenus(); - void DestroyIceWall() - { - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - me->RemoveAurasDueToSpell(SPELL_JAINA_DESTROY_ICE_WALL); - else - me->RemoveAurasDueToSpell(SPELL_SYLVANAS_DESTROY_ICE_WALL); + switch (gossipListId) + { + case 0: + player->PlayerTalkClass->SendCloseGossip(); + _events.ScheduleEvent(EVENT_START_INTRO, 1000); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + break; + case 1: + player->PlayerTalkClass->SendCloseGossip(); + _events.ScheduleEvent(EVENT_SKIP_INTRO, 1000); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + break; + default: + break; + } + } - _instance->HandleGameObject(_icewallGUID, true); + void Reset() override + { + _events.Reset(); - if (Creature* wallTarget = ObjectAccessor::GetCreature(*me, _walltargetGUID)) - wallTarget->DespawnOrUnsummon(); - } + _utherGUID = 0; + _lichkingGUID = 0; - void UpdateAI(uint32 diff) override - { - _events.Update(diff); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + me->SetStandState(UNIT_STAND_STATE_STAND); + _events.ScheduleEvent(EVENT_WALK_INTRO1, 3000); + } - while (uint32 event = _events.ExecuteEvent()) + void UpdateAI(uint32 diff) override { - switch (event) + _events.Update(diff); + + switch (_events.ExecuteEvent()) { - case EVENT_ESCAPE: - if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART2, LichKingSpawnPos2, TEMPSUMMON_MANUAL_DESPAWN)) + case EVENT_WALK_INTRO1: + if (Creature* korelnOrLoralen = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_KORELN_LORALEN))) + korelnOrLoralen->GetMotionMaster()->MovePoint(0, KorelnOrLoralenPos[0]); + + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) { - me->Attack(lichking, true); - lichking->Attack(me, true); - me->SetReactState(REACT_PASSIVE); - lichking->SetReactState(REACT_PASSIVE); - _lichkingGUID = lichking->GetGUID(); - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - DoCast(me, SPELL_JAINA_ICEBARRIER); - else - DoCast(me, SPELL_SYLVANAS_CLOAKOFDARKNESS); + me->GetMotionMaster()->MovePoint(0, JainaIntroPosition[1]); + Talk(SAY_JAINA_INTRO_1); + _events.ScheduleEvent(EVENT_WALK_INTRO2, 7000); } - me->SetHealth(252000); - break; - case EVENT_ESCAPE_1: - _instance->SetData(DATA_ESCAPE_EVENT, IN_PROGRESS); - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + else { - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - lichking->AI()->Talk(SAY_LK_ESCAPE_1); - else - lichking->AI()->Talk(SAY_LK_ESCAPE_2); - _events.ScheduleEvent(EVENT_ESCAPE_2, 8000); + me->GetMotionMaster()->MovePoint(0, SylvanasIntroPosition[1]); + Talk(SAY_SYLVANAS_INTRO_1); + _events.ScheduleEvent(EVENT_WALK_INTRO2, 9000); } break; - case EVENT_ESCAPE_2: + case EVENT_WALK_INTRO2: if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - DoCast(me, SPELL_CAST_VISUAL, true); + Talk(SAY_JAINA_INTRO_2); else - DoCast(me, SPELL_SYLVANAS_JUMP, true); - _events.ScheduleEvent(EVENT_ESCAPE_3, 1000); + Talk(SAY_SYLVANAS_INTRO_2); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); break; - case EVENT_ESCAPE_3: + case EVENT_START_INTRO: + if (Creature* korelnOrLoralen = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_KORELN_LORALEN))) + korelnOrLoralen->GetMotionMaster()->MovePoint(0, KorelnOrLoralenPos[1]); + // Begining of intro is differents between factions as the speech sequence and timers are differents. if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - DoCastAOE(SPELL_JAINA_ICEPRISON, true); + { + me->GetMotionMaster()->MovePoint(0, JainaIntroPosition[2]); + _events.ScheduleEvent(EVENT_INTRO_A2_1, 0); + } else - DoCastAOE(SPELL_SYLVANAS_DARKBINDING, true); - _events.ScheduleEvent(EVENT_ESCAPE_4, 2000); + { + me->GetMotionMaster()->MovePoint(0, SylvanasIntroPosition[2]); + _events.ScheduleEvent(EVENT_INTRO_H2_1, 0); + } break; - case EVENT_ESCAPE_4: - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - Talk(SAY_JAINA_ESCAPE_1); - else - Talk(SAY_SYLVANAS_ESCAPE_1); - _events.ScheduleEvent(EVENT_ESCAPE_5, 2000); + // A2 Intro Events + case EVENT_INTRO_A2_1: + Talk(SAY_JAINA_INTRO_3); + _events.ScheduleEvent(EVENT_INTRO_A2_2, 7000); break; - case EVENT_ESCAPE_5: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->CombatStop(); - me->GetMotionMaster()->MovePoint(0, JainaShadowThroneDoor); - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - me->RemoveAurasDueToSpell(SPELL_JAINA_ICEBARRIER); - else - me->RemoveAurasDueToSpell(SPELL_SYLVANAS_CLOAKOFDARKNESS); - _events.ScheduleEvent(EVENT_ESCAPE_6, 5000); + case EVENT_INTRO_A2_2: + Talk(SAY_JAINA_INTRO_4); + _events.ScheduleEvent(EVENT_INTRO_A2_3, 10000); break; - case EVENT_ESCAPE_6: - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); + case EVENT_INTRO_A2_3: + me->CastSpell(me, SPELL_CAST_VISUAL, false); + me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); + _instance->HandleGameObject(_instance->GetData64(DATA_FROSTMOURNE), true); + _events.ScheduleEvent(EVENT_INTRO_A2_4, 10000); break; - case EVENT_ESCAPE_7: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - { - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - lichking->RemoveAurasDueToSpell(SPELL_JAINA_ICEPRISON); - else - lichking->RemoveAurasDueToSpell(SPELL_SYLVANAS_DARKBINDING); - } - _events.ScheduleEvent(EVENT_ESCAPE_8, 1000); + case EVENT_INTRO_A2_4: + if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) + _utherGUID = uther->GetGUID(); + _events.ScheduleEvent(EVENT_INTRO_A2_5, 2000); break; - case EVENT_ESCAPE_8: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->HandleEmoteCommand(TEXT_EMOTE_ROAR); - me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[0]); - _events.ScheduleEvent(EVENT_ESCAPE_9, 3000); + case EVENT_INTRO_A2_5: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_1); + _events.ScheduleEvent(EVENT_INTRO_A2_6, 3000); break; - case EVENT_ESCAPE_9: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[0]); - _events.ScheduleEvent(EVENT_ESCAPE_10, 1000); + case EVENT_INTRO_A2_6: + Talk(SAY_JAINA_INTRO_5); + _events.ScheduleEvent(EVENT_INTRO_A2_7, 7000); break; - case EVENT_ESCAPE_10: - me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[1]); - _events.ScheduleEvent(EVENT_ESCAPE_11, 5000); + case EVENT_INTRO_A2_7: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_2); + _events.ScheduleEvent(EVENT_INTRO_A2_8, 7000); break; - case EVENT_ESCAPE_11: - me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[2]); - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->GetMotionMaster()->MovePoint(0, LichKingFirstSummon); - _events.ScheduleEvent(EVENT_ESCAPE_12, 6000); + case EVENT_INTRO_A2_8: + Talk(SAY_JAINA_INTRO_6); + _events.ScheduleEvent(EVENT_INTRO_A2_9, 1200); break; - case EVENT_ESCAPE_12: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + case EVENT_INTRO_A2_9: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_3); + _events.ScheduleEvent(EVENT_INTRO_A2_10, 11000); + break; + case EVENT_INTRO_A2_10: + Talk(SAY_JAINA_INTRO_7); + _events.ScheduleEvent(EVENT_INTRO_A2_11, 6000); + break; + case EVENT_INTRO_A2_11: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_4); + _events.ScheduleEvent(EVENT_INTRO_A2_12, 12000); + break; + case EVENT_INTRO_A2_12: + Talk(SAY_JAINA_INTRO_8); + _events.ScheduleEvent(EVENT_INTRO_A2_13, 6000); + break; + case EVENT_INTRO_A2_13: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_5); + _events.ScheduleEvent(EVENT_INTRO_A2_14, 13000); + break; + case EVENT_INTRO_A2_14: + Talk(SAY_JAINA_INTRO_9); + _events.ScheduleEvent(EVENT_INTRO_A2_15, 12000); + break; + case EVENT_INTRO_A2_15: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_6); + _events.ScheduleEvent(EVENT_INTRO_A2_16, 25000); + break; + case EVENT_INTRO_A2_16: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_7); + _events.ScheduleEvent(EVENT_INTRO_A2_17, 6000); + break; + case EVENT_INTRO_A2_17: + Talk(SAY_JAINA_INTRO_10); + _events.ScheduleEvent(EVENT_INTRO_A2_18, 5000); + break; + case EVENT_INTRO_A2_18: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) { - lichking->AI()->Talk(SAY_LK_ESCAPE_3); - lichking->CastSpell(me, SPELL_RAISE_DEAD); - lichking->Attack(me, true); + uther->HandleEmoteCommand(EMOTE_ONESHOT_NO); + uther->AI()->Talk(SAY_UTHER_INTRO_A2_8); } - _events.ScheduleEvent(EVENT_ESCAPE_13, 4000); + _events.ScheduleEvent(EVENT_INTRO_A2_19, 12000); break; - case EVENT_ESCAPE_13: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + case EVENT_INTRO_A2_19: + Talk(SAY_JAINA_INTRO_11); + _events.ScheduleEvent(EVENT_INTRO_LK_1, 3000); + break; + // H2 Intro Events + case EVENT_INTRO_H2_1: + Talk(SAY_SYLVANAS_INTRO_1); + _events.ScheduleEvent(EVENT_INTRO_H2_2, 8000); + break; + case EVENT_INTRO_H2_2: + Talk(SAY_SYLVANAS_INTRO_2); + _events.ScheduleEvent(EVENT_INTRO_H2_3, 6000); + break; + case EVENT_INTRO_H2_3: + Talk(SAY_SYLVANAS_INTRO_3); + me->CastSpell(me, SPELL_CAST_VISUAL, false); + me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); + _instance->HandleGameObject(_instance->GetData64(DATA_FROSTMOURNE), true); + _events.ScheduleEvent(EVENT_INTRO_H2_4, 6000); + break; + case EVENT_INTRO_H2_4: + // spawn UTHER during speach 2 + if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) + _utherGUID = uther->GetGUID(); + _events.ScheduleEvent(EVENT_INTRO_H2_5, 2000); + break; + case EVENT_INTRO_H2_5: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_H2_1); + _events.ScheduleEvent(EVENT_INTRO_H2_6, 11000); + break; + case EVENT_INTRO_H2_6: + Talk(SAY_SYLVANAS_INTRO_4); + _events.ScheduleEvent(EVENT_INTRO_H2_7, 3000); + break; + case EVENT_INTRO_H2_7: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_H2_2); + _events.ScheduleEvent(EVENT_INTRO_H2_8, 6000); + break; + case EVENT_INTRO_H2_8: + Talk(SAY_SYLVANAS_INTRO_5); + _events.ScheduleEvent(EVENT_INTRO_H2_9, 5000); + break; + case EVENT_INTRO_H2_9: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_H2_3); + _events.ScheduleEvent(EVENT_INTRO_H2_10, 19000); + break; + case EVENT_INTRO_H2_10: + Talk(SAY_SYLVANAS_INTRO_6); + _events.ScheduleEvent(EVENT_INTRO_H2_11, 1500); + break; + case EVENT_INTRO_H2_11: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_H2_4); + _events.ScheduleEvent(EVENT_INTRO_H2_12, 19500); + break; + case EVENT_INTRO_H2_12: + Talk(SAY_SYLVANAS_INTRO_7); + _events.ScheduleEvent(EVENT_INTRO_H2_13, 2000); + break; + case EVENT_INTRO_H2_13: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) { - lichking->CastSpell(lichking, SPELL_REMORSELESS_WINTER, true); - lichking->CastSpell(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR); - lichking->GetMotionMaster()->MoveIdle(); - lichking->GetMotionMaster()->MoveChase(me); + uther->HandleEmoteCommand(EMOTE_ONESHOT_NO); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_5); } - if (Creature* walltarget = me->SummonCreature(NPC_ICE_WALL, IceWalls[0], TEMPSUMMON_MANUAL_DESPAWN, 720000)) + _events.ScheduleEvent(EVENT_INTRO_H2_14, 12000); + break; + case EVENT_INTRO_H2_14: + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) + uther->AI()->Talk(SAY_UTHER_INTRO_H2_6); + _events.ScheduleEvent(EVENT_INTRO_H2_15, 8000); + break; + case EVENT_INTRO_H2_15: + Talk(SAY_SYLVANAS_INTRO_8); + _events.ScheduleEvent(EVENT_INTRO_LK_1, 2000); + break; + // Remaining Intro Events common for both faction + case EVENT_INTRO_LK_1: + // Spawn LK in front of door, and make him move to the sword. + if (Creature* lichking = me->SummonCreature(NPC_THE_LICH_KING_INTRO, LichKingIntroPosition[0], TEMPSUMMON_MANUAL_DESPAWN)) { - _walltargetGUID = walltarget->GetGUID(); - walltarget->CastSpell(walltarget, SPELL_SUMMON_ICE_WALL); - walltarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->Attack(walltarget, false); + lichking->SetWalk(true); + lichking->GetMotionMaster()->MovePoint(0, LichKingIntroPosition[2]); + _lichkingGUID = lichking->GetGUID(); + _events.ScheduleEvent(EVENT_OPEN_IMPENETRABLE_DOOR, 0); + _events.ScheduleEvent(EVENT_CLOSE_IMPENETRABLE_DOOR, 4000); } - me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[3]); - _events.ScheduleEvent(EVENT_ESCAPE_14, 8000); - break; - case EVENT_ESCAPE_14: - if (Creature* walltarget = ObjectAccessor::GetCreature(*me, _walltargetGUID)) + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) { - if (GameObject* icewall = walltarget->FindNearestGameObject(GO_ICE_WALL, 50.00f)) - { - _icewallGUID = icewall->GetGUID(); - icewall->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - _instance->HandleGameObject(0, false, icewall); - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - Talk(SAY_JAINA_ESCAPE_2); - else - Talk(SAY_SYLVANAS_ESCAPE_2); - } + uther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_9); + else + uther->AI()->Talk(SAY_UTHER_INTRO_H2_7); } - _events.ScheduleEvent(EVENT_ESCAPE_15, 1000); + _events.ScheduleEvent(EVENT_INTRO_LK_2, 10000); break; - case EVENT_ESCAPE_15: + case EVENT_INTRO_LK_2: if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + lichking->AI()->Talk(SAY_LK_INTRO_1); + _events.ScheduleEvent(EVENT_INTRO_LK_3, 1000); + break; + case EVENT_INTRO_LK_3: + // The Lich King banishes Uther to the abyss. + if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID)) { - lichking->GetMotionMaster()->MoveIdle(); - lichking->GetMotionMaster()->MoveChase(me); - lichking->SetReactState(REACT_PASSIVE); + uther->CastSpell(uther, SPELL_UTHER_DESPAWN, true); + uther->DespawnOrUnsummon(5000); + _utherGUID = 0; } - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - DoCast(me, SPELL_JAINA_DESTROY_ICE_WALL, true); - else - DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, true); + _events.ScheduleEvent(EVENT_INTRO_LK_4, 9000); break; - case EVENT_ESCAPE_17:// ICEWALL BROKEN - me->GetMotionMaster()->MoveIdle(); + case EVENT_INTRO_LK_4: + // He steps forward and removes the runeblade from the heap of skulls. if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) { - lichking->StopMoving(); - lichking->AI()->Talk(SAY_LK_ESCAPE_3); - lichking->CastSpell(me, SPELL_RAISE_DEAD); + if (GameObject* frostmourne = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_FROSTMOURNE))) + frostmourne->SetPhaseMask(2, true); + lichking->CastSpell(lichking, SPELL_TAKE_FROSTMOURNE, true); + lichking->CastSpell(lichking, SPELL_FROSTMOURNE_VISUAL, true); } - - DestroyIceWall(); - - if (_icewall && _icewall < 4) - me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[_icewall + 3]); - _events.ScheduleEvent(EVENT_ESCAPE_18, 2000); + _events.ScheduleEvent(EVENT_INTRO_LK_5, 8000); break; - case EVENT_ESCAPE_18: + case EVENT_INTRO_LK_5: if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + lichking->AI()->Talk(SAY_LK_INTRO_2); + _events.ScheduleEvent(EVENT_INTRO_LK_6, 10000); + break; + case EVENT_INTRO_LK_6: + // summon Falric and Marwyn. then go back to the door + if (Creature* falric = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_FALRIC))) { - lichking->GetMotionMaster()->MoveIdle(); - lichking->GetMotionMaster()->MoveChase(me); + falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); + falric->SetVisible(true); } - _events.ScheduleEvent(EVENT_ESCAPE_19, 6000); - break; - case EVENT_ESCAPE_19: - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + if (Creature* marwyn = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_MARWYN))) { - if (_icewall && _icewall < 4) - lichking->CastSpell(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR); - lichking->GetMotionMaster()->MoveIdle(); - lichking->GetMotionMaster()->MoveChase(me); - lichking->SetReactState(REACT_PASSIVE); - lichking->Attack(me, true); + marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); + marwyn->SetVisible(true); } - if (_icewall < 4) + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) { - if (Creature* walltarget = me->SummonCreature(NPC_ICE_WALL, IceWalls[_icewall], TEMPSUMMON_MANUAL_DESPAWN, 720000)) - { - _walltargetGUID = walltarget->GetGUID(); - walltarget->CastSpell(walltarget, SPELL_SUMMON_ICE_WALL); - walltarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->Attack(walltarget, false); - } + lichking->AI()->Talk(SAY_LK_INTRO_3); + lichking->SetWalk(true); + lichking->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); } - _events.ScheduleEvent(EVENT_ESCAPE_20, 3000); + _events.ScheduleEvent(EVENT_INTRO_LK_7, 10000); + _events.ScheduleEvent(EVENT_OPEN_IMPENETRABLE_DOOR, 5000); break; - case EVENT_ESCAPE_20: - if (Creature* walltarget = ObjectAccessor::GetCreature(*me, _walltargetGUID)) + case EVENT_INTRO_LK_7: + if (Creature* marwyn = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_MARWYN))) { - if (GameObject* icewall = walltarget->FindNearestGameObject(GO_ICE_WALL, 50.00f)) - { - _icewallGUID = icewall->GetGUID(); - _instance->HandleGameObject(0, false, icewall); - icewall->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - { - if (_icewall == 1) - Talk(SAY_JAINA_ESCAPE_3); - else if (_icewall == 2) - Talk(SAY_JAINA_ESCAPE_4); - else if (_icewall == 3) - Talk(SAY_JAINA_ESCAPE_5); - } - else if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE) - { - if (_icewall == 1) - Talk(SAY_SYLVANAS_ESCAPE_3); - else if (_icewall == 2) - Talk(SAY_SYLVANAS_ESCAPE_4); - else if (_icewall == 3) - Talk(SAY_SYLVANAS_ESCAPE_5); - } - } + marwyn->AI()->Talk(SAY_MARWYN_INTRO_1); + marwyn->SetWalk(true); + marwyn->GetMotionMaster()->MovePoint(0, MarwynPosition[1]); } - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + _events.ScheduleEvent(EVENT_INTRO_LK_8, 1000); + break; + case EVENT_INTRO_LK_8: + if (Creature* falric = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_FALRIC))) { - if (_icewall && _icewall < 3) - lichking->CastSpell(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR); - else - lichking->CastSpell(lichking, SPELL_SUMMON_LUMBERING_ABOMINATION); + falric->AI()->Talk(SAY_FALRIC_INTRO_1); + falric->SetWalk(true); + falric->GetMotionMaster()->MovePoint(0, FalricPosition[1]); } - if (_icewall == 3) - _events.ScheduleEvent(EVENT_ESCAPE_21, 16000); // last wall, really far - else - _events.ScheduleEvent(EVENT_ESCAPE_21, 9000); + _events.ScheduleEvent(EVENT_INTRO_LK_9, 5000); + break; + case EVENT_INTRO_LK_9: + if (Creature* falric = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_FALRIC))) + falric->AI()->Talk(SAY_FALRIC_INTRO_2); + _instance->ProcessEvent(0, EVENT_SPAWN_WAVES); + _events.ScheduleEvent(EVENT_INTRO_LK_10, 4000); break; - case EVENT_ESCAPE_21: + case EVENT_INTRO_LK_10: if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - DoCast(me, SPELL_JAINA_DESTROY_ICE_WALL, true); + Talk(SAY_JAINA_INTRO_END); else - DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, true); - + Talk(SAY_SYLVANAS_INTRO_END); + me->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); + /// @todo: needs some improvements + if (Creature* korelnOrLoralen = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_KORELN_LORALEN))) + korelnOrLoralen->GetMotionMaster()->MovePoint(1, KorelnOrLoralenPos[2]); + _events.ScheduleEvent(EVENT_INTRO_LK_11, 5000); + break; + case EVENT_INTRO_LK_11: if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) { - if (_icewall == 1) - lichking->CastSpell(lichking, SPELL_SUMMON_LUMBERING_ABOMINATION); - else if (_icewall > 1 && _icewall < 4) - { - lichking->CastSpell(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR); - _events.ScheduleEvent(EVENT_ESCAPE_22, 1000); - } + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + lichking->AI()->Talk(SAY_LK_JAINA_INTRO_END); + else + lichking->AI()->Talk(SAY_LK_SYLVANAS_INTRO_END); } + _events.ScheduleEvent(EVENT_INTRO_END, 5000); break; - case EVENT_ESCAPE_22: + case EVENT_INTRO_END: + _instance->SetData(DATA_INTRO_EVENT, DONE); + _events.ScheduleEvent(EVENT_KORELN_LORALEN_DEATH, 8000); if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) { - if (_icewall >= 2 && _icewall < 4) - lichking->CastSpell(lichking, SPELL_SUMMON_LUMBERING_ABOMINATION); + lichking->DespawnOrUnsummon(5000); + _lichkingGUID = 0; } + me->DespawnOrUnsummon(10000); + _events.ScheduleEvent(EVENT_CLOSE_IMPENETRABLE_DOOR, 7000); break; - case EVENT_ESCAPE_23: // FINAL PART - DestroyIceWall(); - + case EVENT_SKIP_INTRO: if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - Talk(SAY_JAINA_ESCAPE_6); + me->GetMotionMaster()->MovePoint(0, JainaIntroPosition[2]); else - Talk(SAY_SYLVANAS_ESCAPE_6); + me->GetMotionMaster()->MovePoint(0, SylvanasIntroPosition[2]); - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) + if (Creature* korelnOrLoralen = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_KORELN_LORALEN))) + korelnOrLoralen->GetMotionMaster()->MovePoint(0, KorelnOrLoralenPos[1]); + + if (Creature* lichking = me->SummonCreature(NPC_THE_LICH_KING_INTRO, LichKingIntroPosition[0], TEMPSUMMON_MANUAL_DESPAWN)) { - lichking->GetMotionMaster()->MovePoint(0, LichKingFinalPos); - lichking->AI()->Talk(SAY_LK_ESCAPE_11); + lichking->SetWalk(true); + lichking->GetMotionMaster()->MovePoint(0, LichKingIntroPosition[2]); + lichking->SetReactState(REACT_PASSIVE); + _lichkingGUID = lichking->GetGUID(); + _events.ScheduleEvent(EVENT_OPEN_IMPENETRABLE_DOOR, 0); + _events.ScheduleEvent(EVENT_CLOSE_IMPENETRABLE_DOOR, 4000); } - me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[8]); - _events.ScheduleEvent(EVENT_ESCAPE_24, 10000); + _events.ScheduleEvent(EVENT_INTRO_LK_4, 15000); break; - case EVENT_ESCAPE_24: - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - Talk(SAY_JAINA_ESCAPE_8); - else - Talk(SAY_SYLVANAS_ESCAPE_8); - _events.ScheduleEvent(EVENT_ESCAPE_25, 5000); + case EVENT_OPEN_IMPENETRABLE_DOOR: + _instance->HandleGameObject(_instance->GetData64(DATA_IMPENETRABLE_DOOR), true); break; - case EVENT_ESCAPE_25: - if (GameObject* cave = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_CAVE_IN))) - cave->SetGoState(GO_STATE_READY); - _events.ScheduleEvent(EVENT_ESCAPE_26, 4000); + case EVENT_CLOSE_IMPENETRABLE_DOOR: + _instance->HandleGameObject(_instance->GetData64(DATA_IMPENETRABLE_DOOR), false); break; - case EVENT_ESCAPE_26: - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - Talk(SAY_JAINA_ESCAPE_10); + case EVENT_KORELN_LORALEN_DEATH: + if (Creature* korelnOrLoralen = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_KORELN_LORALEN))) + korelnOrLoralen->CastSpell(korelnOrLoralen, SPELL_FEIGN_DEATH); + break; + default: + break; + } + } + + private: + InstanceScript* _instance; + EventMap _events; + uint64 _utherGUID; + uint64 _lichkingGUID; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<npc_jaina_or_sylvanas_intro_horAI>(creature); + } +}; + +class npc_jaina_or_sylvanas_escape_hor : public CreatureScript +{ + public: + npc_jaina_or_sylvanas_escape_hor() : CreatureScript("npc_jaina_or_sylvanas_escape_hor") { } + + bool OnGossipHello(Player* player, Creature* creature) override + { + // override default gossip + if (InstanceScript* instance = creature->GetInstanceScript()) + if (instance->GetBossState(DATA_THE_LICH_KING_ESCAPE) == DONE) + { + player->PrepareGossipMenu(creature, creature->GetEntry() == NPC_JAINA_ESCAPE ? GOSSIP_MENU_JAINA_FINAL : GOSSIP_MENU_SYLVANAS_FINAL, true); + player->SendPreparedGossip(creature); + return true; + } + + // load default gossip + return false; + } + + struct npc_jaina_or_sylvanas_escape_horAI : public ScriptedAI + { + npc_jaina_or_sylvanas_escape_horAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()), _icewall(0), _prefight(false), _invincibility(true) { } + + void Reset() override + { + _events.Reset(); + _icewall = 0; + _events.ScheduleEvent(EVENT_ESCAPE, 1000); + _instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + lichking->AI()->EnterEvadeMode(); // event failed + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (damage >= me->GetHealth() && _invincibility) + damage = me->GetHealth() - 1; + } + + void DoAction(int32 actionId) override + { + switch (actionId) + { + case ACTION_START_PREFIGHT: + if (_prefight) + return; + _prefight = true; + _events.ScheduleEvent(EVENT_ESCAPE_1, 1000); + break; + case ACTION_WALL_BROKEN: + ++_icewall; + if (_icewall < 4) + _events.ScheduleEvent(EVENT_ESCAPE_13, 3000); else - Talk(SAY_SYLVANAS_ESCAPE_9); - _events.ScheduleEvent(EVENT_ESCAPE_27, 4000); + _events.ScheduleEvent(EVENT_ESCAPE_15, 3000); break; - case EVENT_ESCAPE_27: - if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) - me->SummonGameObject(IsHeroic() ? GO_CAPTAIN_CHEST_ALLIANCE_HEROIC : GO_CAPTAIN_CHEST_ALLIANCE_NORMAL, ChestPos.GetPositionX(), ChestPos.GetPositionY(), ChestPos.GetPositionZ(), ChestPos.GetOrientation(), 0, 0, 0, 0, 720000); + case ACTION_GUNSHIP_ARRIVAL: + _events.ScheduleEvent(EVENT_ESCAPE_16, 5000); + break; + case ACTION_GUNSHIP_ARRIVAL_2: + _events.ScheduleEvent(EVENT_ESCAPE_17, 5000); + break; + default: + break; + } + } + + void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + { + player->PlayerTalkClass->ClearMenus(); + + switch (gossipListId) + { + case 0: + player->PlayerTalkClass->SendCloseGossip(); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + _events.ScheduleEvent(EVENT_ESCAPE_6, 0); + break; + default: + break; + } + } + + void DestroyIceWall() + { + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + me->RemoveAurasDueToSpell(SPELL_JAINA_DESTROY_ICE_WALL); + else + me->RemoveAurasDueToSpell(SPELL_SYLVANAS_DESTROY_ICE_WALL); + + _instance->HandleGameObject(_instance->GetData64(DATA_ICEWALL), true); + me->m_Events.AddEvent(new GameObjectDeleteDelayEvent(me, _instance->GetData64(DATA_ICEWALL)), me->m_Events.CalculateTime(5000)); + + if (Creature* wallTarget = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ICEWALL_TARGET))) + wallTarget->DespawnOrUnsummon(); + } + + void SummonIceWall() + { + if (_icewall < 4) + { + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + { + lichking->StopMoving(); + if (Creature* wallTarget = me->SummonCreature(NPC_ICE_WALL_TARGET, IceWallTargetPosition[_icewall], TEMPSUMMON_MANUAL_DESPAWN, 720000)) + lichking->CastSpell(wallTarget, SPELL_SUMMON_ICE_WALL); + + lichking->AI()->SetData(DATA_ICEWALL, _icewall); + } + } + } + + void AttackIceWall() + { + if (_icewall < 4) + Talk(SAY_JAINA_SYLVANAS_ESCAPE_2 + _icewall); + + if (Creature* wallTarget = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ICEWALL_TARGET))) + me->SetFacingToObject(wallTarget); + + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + DoCast(me, SPELL_JAINA_DESTROY_ICE_WALL, true); + else + DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, true); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_SHADOW_THRONE_DOOR: + if (me->GetEntry() == NPC_JAINA_ESCAPE) + me->RemoveAurasDueToSpell(SPELL_JAINA_ICE_BARRIER); else - me->SummonGameObject(IsHeroic() ? GO_CAPTAIN_CHEST_HORDE_HEROIC : GO_CAPTAIN_CHEST_HORDE_NORMAL, ChestPos.GetPositionX(), ChestPos.GetPositionY(), ChestPos.GetPositionZ(), ChestPos.GetOrientation(), 0, 0, 0, 0, 720000); - me->SummonGameObject(GO_PORTAL, FinalPortalPos.GetPositionX(), FinalPortalPos.GetPositionY(), FinalPortalPos.GetPositionZ(), FinalPortalPos.GetOrientation(), 0, 0, 0, 0, 720000); - if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID)) - lichking->DespawnOrUnsummon(1); + me->RemoveAurasDueToSpell(SPELL_SYLVANAS_CLOAK_OF_DARKNESS); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->SetHealth(JAINA_SYLVANAS_MAX_HEALTH); + me->SetFacingTo(SylvanasShadowThroneDoorPosition.GetOrientation()); + break; + case POINT_ATTACK_ICEWALL: + AttackIceWall(); + break; + case POINT_TRAP: + Talk(SAY_JAINA_SYLVANAS_ESCAPE_8); + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + me->SetFacingToObject(lichking); break; + default: + break; + } + } + + void DeleteAllFromThreatList(Unit* target, uint64 except) + { + ThreatContainer::StorageType threatlist = target->getThreatManager().getThreatList(); + for (auto i : threatlist) + { + if (i->getUnitGuid() == except) + continue; + + i->removeReference(); + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 event = _events.ExecuteEvent()) + { + switch (event) + { + case EVENT_ESCAPE: + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + DoCast(me, SPELL_JAINA_ICE_BARRIER); + else + DoCast(me, SPELL_SYLVANAS_CLOAK_OF_DARKNESS); + + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + { + AttackStart(lichking); + lichking->AI()->AttackStart(me); + me->CastSpell(lichking, SPELL_TAUNT_ARTHAS, true); + } + me->SetHealth(JAINA_SYLVANAS_MAX_HEALTH); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + break; + case EVENT_ESCAPE_1: + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + { + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + lichking->AI()->Talk(SAY_LK_ESCAPE_1); + else + lichking->AI()->Talk(SAY_LK_ESCAPE_2); + _events.ScheduleEvent(EVENT_ESCAPE_2, 8000); + } + break; + case EVENT_ESCAPE_2: + me->AttackStop(); + me->StopMoving(); + me->SetReactState(REACT_PASSIVE); + + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + DoCast(me, SPELL_JAINA_ICE_PRISON, false); + else + DoCast(me, SPELL_SYLVANAS_BLINDING_RETREAT, true); + + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + { + lichking->SetReactState(REACT_PASSIVE); + lichking->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); + } + + _events.ScheduleEvent(EVENT_ESCAPE_3, 1500); + break; + case EVENT_ESCAPE_3: + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE) + DoCastAOE(SPELL_SYLVANAS_DARK_BINDING, true); + _events.ScheduleEvent(EVENT_ESCAPE_4, 1000); + break; + case EVENT_ESCAPE_4: + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + DoCast(me, SPELL_CREDIT_FINDING_JAINA); + else + DoCast(me, SPELL_CREDIT_FINDING_SYLVANAS); + Talk(SAY_JAINA_SYLVANAS_ESCAPE_1); + + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + { + lichking->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + lichking->RemoveAllAttackers(); + + DeleteAllFromThreatList(lichking, me->GetGUID()); + } + + _events.ScheduleEvent(EVENT_ESCAPE_5, 2000); + break; + case EVENT_ESCAPE_5: + me->GetMotionMaster()->MovePoint(POINT_SHADOW_THRONE_DOOR, SylvanasShadowThroneDoorPosition); + break; + case EVENT_ESCAPE_6: + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + { + lichking->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_PACIFIED); + + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + { + lichking->CastSpell(lichking, SPELL_STUN_BREAK_JAINA); + lichking->RemoveAurasDueToSpell(SPELL_JAINA_ICE_PRISON); + } + else + { + lichking->CastSpell(lichking, SPELL_STUN_BREAK_SYLVANAS); + lichking->RemoveAurasDueToSpell(SPELL_SYLVANAS_DARK_BINDING); + } + } + _invincibility = false; + _instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); + _events.ScheduleEvent(EVENT_ESCAPE_7, 1000); + break; + case EVENT_ESCAPE_7: + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + lichking->HandleEmoteCommand(TEXT_EMOTE_ROAR); + me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[0]); + _events.ScheduleEvent(EVENT_ESCAPE_8, 3000); + break; + case EVENT_ESCAPE_8: + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + lichking->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[0]); + _events.ScheduleEvent(EVENT_ESCAPE_9, 1000); + break; + case EVENT_ESCAPE_9: + me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[1]); + _events.ScheduleEvent(EVENT_ESCAPE_10, 5000); + break; + case EVENT_ESCAPE_10: + me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[2]); + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + lichking->GetMotionMaster()->MovePoint(1, LichKingFirstSummon); + _events.ScheduleEvent(EVENT_ESCAPE_11, 6000); + break; + case EVENT_ESCAPE_11: + SummonIceWall(); + _events.ScheduleEvent(EVENT_ESCAPE_12, 4000); + break; + case EVENT_ESCAPE_12: + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + lichking->CastSpell(lichking, SPELL_PAIN_AND_SUFFERING, true); + + me->GetMotionMaster()->MovePoint(POINT_ATTACK_ICEWALL, NpcJainaOrSylvanasEscapeRoute[3]); + break; + case EVENT_ESCAPE_13: // ICEWALL BROKEN + DestroyIceWall(); + + if (_icewall && _icewall < 4) + me->GetMotionMaster()->MovePoint(POINT_ATTACK_ICEWALL, NpcJainaOrSylvanasEscapeRoute[_icewall + 3]); + _events.ScheduleEvent(EVENT_ESCAPE_14, 8000); + break; + case EVENT_ESCAPE_14: + SummonIceWall(); + break; + case EVENT_ESCAPE_15: // FINAL PART + DestroyIceWall(); + + Talk(SAY_JAINA_SYLVANAS_ESCAPE_6); + + if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) + { + lichking->GetMotionMaster()->MovePoint(2, LichKingFinalPos); + lichking->RemoveAurasDueToSpell(SPELL_REMORSELESS_WINTER); + } + me->GetMotionMaster()->MovePoint(POINT_TRAP, NpcJainaOrSylvanasEscapeRoute[7]); + break; + case EVENT_ESCAPE_16: + me->RemoveAurasDueToSpell(SPELL_HARVEST_SOUL); + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + Talk(SAY_JAINA_ESCAPE_9); + if (Transport* gunship = ObjectAccessor::GetTransport(*me, _instance->GetData64(DATA_GUNSHIP))) + gunship->EnableMovement(true); + _instance->SetBossState(DATA_THE_LICH_KING_ESCAPE, DONE); + break; + case EVENT_ESCAPE_17: + if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + Talk(SAY_JAINA_ESCAPE_10); + else + Talk(SAY_SYLVANAS_ESCAPE_9); + DoCast(me, SPELL_CREDIT_ESCAPING_ARTHAS); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + break; + default: + break; } } + + DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI<npc_jaina_or_sylvanas_escape_horAI>(creature); - } + private: + InstanceScript* _instance; + EventMap _events; + uint32 _icewall; // icewall number + bool _prefight; + bool _invincibility; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<npc_jaina_or_sylvanas_escape_horAI>(creature); + } +}; + +class npc_the_lich_king_escape_hor : public CreatureScript +{ + public: + npc_the_lich_king_escape_hor() : CreatureScript("npc_the_lich_king_escape_hor") { } + + struct npc_the_lich_king_escape_horAI : public ScriptedAI + { + npc_the_lich_king_escape_horAI(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + _instance->SetBossState(DATA_THE_LICH_KING_ESCAPE, NOT_STARTED); + _summonsCount = 0; + _icewall = 0; + _despawn = false; + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == POINT_MOTION_TYPE) + { + switch (pointId) + { + case 1: + if (Creature* target = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ESCAPE_LEADER))) + me->GetMotionMaster()->MoveChase(target); + break; + case 2: + Talk(SAY_LK_ESCAPE_HARVEST_SOUL); + + if (Creature* target = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ESCAPE_LEADER))) + DoCast(target, SPELL_HARVEST_SOUL); + + if (Transport* gunship = ObjectAccessor::GetTransport(*me, _instance->GetData64(DATA_GUNSHIP))) + gunship->EnableMovement(true); + break; + default: + break; + } + } + } + + void JustSummoned(Creature* /*summon*/) override + { + ++_summonsCount; + } + + void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) override + { + // should never happen + if (!_summonsCount) + return; + + --_summonsCount; + + // All summons dead and no summon events scheduled + if (!_summonsCount && _events.Empty()) + { + if (Creature* jainaOrSylvanas = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ESCAPE_LEADER))) + jainaOrSylvanas->AI()->DoAction(ACTION_WALL_BROKEN); + } + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + DoPlaySoundToSet(me, RAND(SOUND_LK_SLAY_1, SOUND_LK_SLAY_2)); + } + + void SetData(uint32 type, uint32 data) override + { + if (type != DATA_ICEWALL) + return; + + _icewall = data; + + switch (_icewall) + { + case 0: // 6 Ghouls, 1 Witch Doctor + DoZoneInCombat(); + _events.ScheduleEvent(EVENT_REMORSELESS_WINTER, 0); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_GHOULS, 8000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 14000); + Talk(SAY_LK_ESCAPE_ICEWALL_SUMMONED_1); + break; + case 1: // 6 Ghouls, 2 Witch Doctor, 1 Lumbering Abomination + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_GHOULS, 8000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION, 13000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 16000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 18000); + Talk(SAY_LK_ESCAPE_ICEWALL_SUMMONED_2); + break; + case 2: // 6 Ghouls, 2 Witch Doctor, 2 Lumbering Abomination + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_GHOULS, 9000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION, 14000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 17000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION, 19000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 39000); + Talk(SAY_LK_ESCAPE_ICEWALL_SUMMONED_3); + break; + case 3: // 12 Ghouls, 4 Witch Doctor, 3 Lumbering Abomination + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_GHOULS, 9000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 17000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 19000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION, 40000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION, 46000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_GHOULS, 55000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 62000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_WITCH_DOCTOR, 66000); + _events.ScheduleEvent(EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION, 14000); + Talk(SAY_LK_ESCAPE_ICEWALL_SUMMONED_4); + break; + default: + break; + } + } + + void EnterEvadeMode() override + { + if (_despawn) + return; + + _instance->SetBossState(DATA_THE_LICH_KING_ESCAPE, FAIL); + me->StopMoving(); + DoPlaySoundToSet(me, SOUND_LK_FURY_OF_FROSTMOURNE); + DoCastAOE(SPELL_FURY_OF_FROSTMOURNE); + me->DespawnOrUnsummon(12000); + _despawn = true; + } + + void UpdateAI(uint32 diff) override + { + if (!SelectVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 event = _events.ExecuteEvent()) + { + switch (event) + { + case EVENT_REMORSELESS_WINTER: + me->StopMoving(); + Talk(SAY_LK_ESCAPE_WINTER); + DoCast(me, SPELL_REMORSELESS_WINTER); + break; + case EVENT_ESCAPE_SUMMON_GHOULS: + me->StopMoving(); + Talk(SAY_LK_ESCAPE_GHOULS); + DoCast(me, SPELL_RAISE_DEAD); + break; + case EVENT_ESCAPE_SUMMON_WITCH_DOCTOR: + DoCast(me, SPELL_SUMMON_RISEN_WITCH_DOCTOR); + break; + case EVENT_ESCAPE_SUMMON_LUMBERING_ABOMINATION: + Talk(SAY_LK_ESCAPE_ABOMINATION); + DoCast(me, SPELL_SUMMON_LUMBERING_ABOMINATION); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + bool SelectVictim() + { + if (!me->IsInCombat()) + return false; + + if (!me->HasReactState(REACT_PASSIVE)) + { + if (Unit* victim = me->SelectVictim()) + AttackStart(victim); + return me->GetVictim(); + } + else if (me->getThreatManager().getThreatList().size() < 2 && me->HasAura(SPELL_REMORSELESS_WINTER)) + { + EnterEvadeMode(); + return false; + } + + return true; + } + + InstanceScript* _instance; + EventMap _events; + uint8 _icewall; + uint32 _summonsCount; + bool _despawn; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<npc_the_lich_king_escape_horAI>(creature); + } }; enum TrashSpells @@ -1140,7 +1374,7 @@ enum TrashSpells SPELL_SHOOT = 72208, SPELL_CURSED_ARROW = 72222, SPELL_FROST_TRAP = 72215, - SPELL_ICE_SHOT = 72268, + SPELL_ICE_SHOT = 72268 }; enum TrashEvents @@ -1175,19 +1409,16 @@ enum TrashEvents EVENT_SHOOT, EVENT_CURSED_ARROW, EVENT_FROST_TRAP, - EVENT_ICE_SHOT, + EVENT_ICE_SHOT }; struct npc_gauntlet_trash : public ScriptedAI { - npc_gauntlet_trash(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) - { - InternalWaveId = 0; - } + npc_gauntlet_trash(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()), InternalWaveId(0) { } void Reset() override { - InternalWaveId = 0; me->CastSpell(me, SPELL_WELL_OF_SOULS, true); _events.Reset(); } @@ -1222,352 +1453,362 @@ protected: class npc_ghostly_priest : public CreatureScript { -public: - npc_ghostly_priest() : CreatureScript("npc_ghostly_priest") { } - - struct npc_ghostly_priestAI : public npc_gauntlet_trash - { - npc_ghostly_priestAI(Creature* creature) : npc_gauntlet_trash(creature) { } + public: + npc_ghostly_priest() : CreatureScript("npc_ghostly_priest") { } - void EnterCombat(Unit* /*who*/) override + struct npc_ghostly_priestAI : public npc_gauntlet_trash { - _events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); /// @todo adjust timers - _events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); - _events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); - _events.ScheduleEvent(EVENT_DARK_MENDING, 20000); - } + npc_ghostly_priestAI(Creature* creature) : npc_gauntlet_trash(creature) { } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (_events.ExecuteEvent()) - { - case EVENT_SHADOW_WORD_PAIN: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHADOW_WORD_PAIN); - _events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); - break; - case EVENT_CIRCLE_OF_DESTRUCTION: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CIRCLE_OF_DESTRUCTION); - _events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); - break; - case EVENT_COWER_IN_FEAR: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_COWER_IN_FEAR); - _events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); - break; - case EVENT_DARK_MENDING: - // find an ally with missing HP - if (Unit* target = DoSelectLowestHpFriendly(40, DUNGEON_MODE(30000, 50000))) - { - DoCast(target, SPELL_DARK_MENDING); - _events.ScheduleEvent(EVENT_DARK_MENDING, 20000); - } - else - { - // no friendly unit with missing hp. re-check in just 5 sec. - _events.ScheduleEvent(EVENT_DARK_MENDING, 5000); - } - break; + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(6000, 15000)); + _events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); + _events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); + _events.ScheduleEvent(EVENT_DARK_MENDING, 20000); } - DoMeleeAttackIfReady(); - } - }; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_ghostly_priestAI>(creature); - } -}; + _events.Update(diff); -class npc_phantom_mage : public CreatureScript -{ -public: - npc_phantom_mage() : CreatureScript("npc_phantom_mage") { } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - struct npc_phantom_mageAI : public npc_gauntlet_trash - { - npc_phantom_mageAI(Creature* creature) : npc_gauntlet_trash(creature) { } + switch (_events.ExecuteEvent()) + { + case EVENT_SHADOW_WORD_PAIN: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_SHADOW_WORD_PAIN); + _events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(6000, 15000)); + break; + case EVENT_CIRCLE_OF_DESTRUCTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 10.0f, true)) + DoCast(target, SPELL_CIRCLE_OF_DESTRUCTION); + _events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); + break; + case EVENT_COWER_IN_FEAR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true)) + DoCast(target, SPELL_COWER_IN_FEAR); + _events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); + break; + case EVENT_DARK_MENDING: + // find an ally with missing HP + if (Unit* target = DoSelectLowestHpFriendly(40, DUNGEON_MODE(30000, 50000))) + { + DoCast(target, SPELL_DARK_MENDING); + _events.ScheduleEvent(EVENT_DARK_MENDING, 20000); + } + else + { + // no friendly unit with missing hp. re-check in just 5 sec. + _events.ScheduleEvent(EVENT_DARK_MENDING, 5000); + } + break; + default: + break; + } + + DoMeleeAttackIfReady(); + } + }; - void EnterEvadeMode() override + CreatureAI* GetAI(Creature* creature) const override { - if (!me->HasAura(AURA_HALLUCINATION)) - npc_gauntlet_trash::EnterEvadeMode(); + return GetHallsOfReflectionAI<npc_ghostly_priestAI>(creature); } +}; - void EnterCombat(Unit* /*who*/) override +class npc_phantom_mage : public CreatureScript +{ + public: + npc_phantom_mage() : CreatureScript("npc_phantom_mage") { } + + struct npc_phantom_mageAI : public npc_gauntlet_trash { - _events.ScheduleEvent(EVENT_FIREBALL, 3000); /// @todo adjust timers - _events.ScheduleEvent(EVENT_FLAMESTRIKE, 6000); - _events.ScheduleEvent(EVENT_FROSTBOLT, 9000); - _events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12000); - _events.ScheduleEvent(EVENT_HALLUCINATION, 40000); - } + npc_phantom_mageAI(Creature* creature) : npc_gauntlet_trash(creature) { } + + void EnterEvadeMode() override + { + if (!me->HasAura(AURA_HALLUCINATION)) + npc_gauntlet_trash::EnterEvadeMode(); + } - void UpdateAI(uint32 diff) override + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_FIREBALL, 3000); + _events.ScheduleEvent(EVENT_FLAMESTRIKE, 6000); + _events.ScheduleEvent(EVENT_FROSTBOLT, 9000); + _events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12000); + _events.ScheduleEvent(EVENT_HALLUCINATION, 40000); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (_events.ExecuteEvent()) + { + case EVENT_FIREBALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_FIREBALL); + _events.ScheduleEvent(EVENT_FIREBALL, 15000); + break; + case EVENT_FLAMESTRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_FLAMESTRIKE); + _events.ScheduleEvent(EVENT_FLAMESTRIKE, 15000); + break; + case EVENT_FROSTBOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_FROSTBOLT); + _events.ScheduleEvent(EVENT_FROSTBOLT, 15000); + break; + case EVENT_CHAINS_OF_ICE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_CHAINS_OF_ICE); + _events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 15000); + break; + case EVENT_HALLUCINATION: + // removing any dots on mage or else the invisibility spell will break duration + me->RemoveAllAuras(); + DoCast(me, SPELL_HALLUCINATION); + break; + default: + break; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (_events.ExecuteEvent()) - { - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_FIREBALL); - _events.ScheduleEvent(EVENT_FIREBALL, 15000); - break; - case EVENT_FLAMESTRIKE: - DoCast(SPELL_FLAMESTRIKE); - _events.ScheduleEvent(EVENT_FLAMESTRIKE, 15000); - break; - case EVENT_FROSTBOLT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_FROSTBOLT); - _events.ScheduleEvent(EVENT_FROSTBOLT, 15000); - break; - case EVENT_CHAINS_OF_ICE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CHAINS_OF_ICE); - _events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 15000); - break; - case EVENT_HALLUCINATION: - // removing any dots on mage or else the invisibility spell will break duration - me->RemoveAllAuras(); - DoCast(SPELL_HALLUCINATION); - break; - } - - DoMeleeAttackIfReady(); + return GetHallsOfReflectionAI<npc_phantom_mageAI>(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_phantom_mageAI>(creature); - } }; class npc_phantom_hallucination : public CreatureScript { -public: - npc_phantom_hallucination() : CreatureScript("npc_phantom_hallucination") { } - - struct npc_phantom_hallucinationAI : public npc_phantom_mage::npc_phantom_mageAI - { - npc_phantom_hallucinationAI(Creature* creature) : npc_phantom_mage::npc_phantom_mageAI(creature) { } + public: + npc_phantom_hallucination() : CreatureScript("npc_phantom_hallucination") { } - void Reset() override + struct npc_phantom_hallucinationAI : public npc_phantom_mage::npc_phantom_mageAI { - if (Unit* unit = me->SelectNearestTarget()) - AttackStart(unit); - DoZoneInCombat(); - } + npc_phantom_hallucinationAI(Creature* creature) : npc_phantom_mage::npc_phantom_mageAI(creature) { } - void EnterEvadeMode() override - { - if (me->GetOwner() && !me->GetOwner()->HasAura(AURA_HALLUCINATION)) - npc_phantom_mage::npc_phantom_mageAI::EnterEvadeMode(); - } + void Reset() override + { + DoZoneInCombat(me, 150.0f); + } + + void EnterEvadeMode() override + { + if (me->GetOwner() && !me->GetOwner()->HasAura(AURA_HALLUCINATION)) + npc_phantom_mage::npc_phantom_mageAI::EnterEvadeMode(); + } + + void JustDied(Unit* /*killer*/) override + { + DoCastAOE(SPELL_HALLUCINATION_2); + } + }; - void JustDied(Unit* /*killer*/) override + CreatureAI* GetAI(Creature* creature) const override { - DoCast(SPELL_HALLUCINATION_2); + return new npc_phantom_hallucinationAI(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_phantom_hallucinationAI(creature); - } }; class npc_shadowy_mercenary : public CreatureScript { -public: - npc_shadowy_mercenary() : CreatureScript("npc_shadowy_mercenary") { } - - struct npc_shadowy_mercenaryAI : public npc_gauntlet_trash - { - npc_shadowy_mercenaryAI(Creature* creature) : npc_gauntlet_trash(creature) { } + public: + npc_shadowy_mercenary() : CreatureScript("npc_shadowy_mercenary") { } - void EnterCombat(Unit* /*who*/) override + struct npc_shadowy_mercenaryAI : public npc_gauntlet_trash { - _events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); /// @todo adjust timers - _events.ScheduleEvent(EVENT_DEADLY_POISON, 5000); - _events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); - _events.ScheduleEvent(EVENT_KIDNEY_SHOT, 12000); - } + npc_shadowy_mercenaryAI(Creature* creature) : npc_gauntlet_trash(creature) { } + + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_SHADOW_STEP, 23000); + _events.ScheduleEvent(EVENT_DEADLY_POISON, 5000); + _events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); + _events.ScheduleEvent(EVENT_KIDNEY_SHOT, 12000); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); - void UpdateAI(uint32 diff) override + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (_events.ExecuteEvent()) + { + case EVENT_SHADOW_STEP: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_SHADOW_STEP); + _events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); + break; + case EVENT_DEADLY_POISON: + DoCastVictim(SPELL_DEADLY_POISON); + _events.ScheduleEvent(EVENT_DEADLY_POISON, 10000); + break; + case EVENT_ENVENOMED_DAGGER_THROW: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_ENVENOMED_DAGGER_THROW); + _events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); + break; + case EVENT_KIDNEY_SHOT: + DoCastVictim(SPELL_KIDNEY_SHOT); + _events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10000); + break; + default: + break; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (_events.ExecuteEvent()) - { - case EVENT_SHADOW_STEP: - DoCast(SPELL_SHADOW_STEP); - _events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); - break; - case EVENT_DEADLY_POISON: - DoCastVictim(SPELL_DEADLY_POISON); - _events.ScheduleEvent(EVENT_DEADLY_POISON, 10000); - break; - case EVENT_ENVENOMED_DAGGER_THROW: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_ENVENOMED_DAGGER_THROW); - _events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); - break; - case EVENT_KIDNEY_SHOT: - DoCastVictim(SPELL_KIDNEY_SHOT); - _events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10000); - break; - } - - DoMeleeAttackIfReady(); + return GetHallsOfReflectionAI<npc_shadowy_mercenaryAI>(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_shadowy_mercenaryAI>(creature); - } }; class npc_spectral_footman : public CreatureScript { -public: - npc_spectral_footman() : CreatureScript("npc_spectral_footman") { } - - struct npc_spectral_footmanAI : public npc_gauntlet_trash - { - npc_spectral_footmanAI(Creature* creature) : npc_gauntlet_trash(creature) { } + public: + npc_spectral_footman() : CreatureScript("npc_spectral_footman") { } - void EnterCombat(Unit* /*who*/) override + struct npc_spectral_footmanAI : public npc_gauntlet_trash { - _events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); /// @todo adjust timers - _events.ScheduleEvent(EVENT_SHIELD_BASH, 10000); - _events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); - } + npc_spectral_footmanAI(Creature* creature) : npc_gauntlet_trash(creature) { } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 14000); + _events.ScheduleEvent(EVENT_SHIELD_BASH, 10000); + _events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - _events.Update(diff); + _events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - switch (_events.ExecuteEvent()) - { - case EVENT_SPECTRAL_STRIKE: - DoCastVictim(SPELL_SPECTRAL_STRIKE); - _events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); - break; - case EVENT_SHIELD_BASH: - DoCastVictim(SPELL_SHIELD_BASH); - _events.ScheduleEvent(EVENT_SHIELD_BASH, 5000); - break; - case EVENT_TORTURED_ENRAGE: - DoCast(SPELL_TORTURED_ENRAGE); - _events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); - break; + switch (_events.ExecuteEvent()) + { + case EVENT_SPECTRAL_STRIKE: + DoCastVictim(SPELL_SPECTRAL_STRIKE); + _events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); + break; + case EVENT_SHIELD_BASH: + DoCastVictim(SPELL_SHIELD_BASH); + _events.ScheduleEvent(EVENT_SHIELD_BASH, 5000); + break; + case EVENT_TORTURED_ENRAGE: + DoCast(me, SPELL_TORTURED_ENRAGE); + _events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); + break; + default: + break; + } + + DoMeleeAttackIfReady(); } + }; - DoMeleeAttackIfReady(); + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<npc_spectral_footmanAI>(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_spectral_footmanAI>(creature); - } }; class npc_tortured_rifleman : public CreatureScript { -public: - npc_tortured_rifleman() : CreatureScript("npc_tortured_rifleman") { } - - struct npc_tortured_riflemanAI : public npc_gauntlet_trash - { - npc_tortured_riflemanAI(Creature* creature) : npc_gauntlet_trash(creature) { } + public: + npc_tortured_rifleman() : CreatureScript("npc_tortured_rifleman") { } - void EnterCombat(Unit* /*who*/) override + struct npc_tortured_riflemanAI : public npc_gauntlet_trash { - _events.ScheduleEvent(EVENT_SHOOT, 1); /// @todo adjust timers - _events.ScheduleEvent(EVENT_CURSED_ARROW, 7000); - _events.ScheduleEvent(EVENT_FROST_TRAP, 10000); - _events.ScheduleEvent(EVENT_ICE_SHOT, 15000); - } + npc_tortured_riflemanAI(Creature* creature) : npc_gauntlet_trash(creature) { } + + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_SHOOT, 1); + _events.ScheduleEvent(EVENT_CURSED_ARROW, 7000); + _events.ScheduleEvent(EVENT_FROST_TRAP, 10000); + _events.ScheduleEvent(EVENT_ICE_SHOT, 15000); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void UpdateAI(uint32 diff) override + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (_events.ExecuteEvent()) + { + case EVENT_SHOOT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_SHOOT); + _events.ScheduleEvent(EVENT_SHOOT, 2000); + break; + case EVENT_CURSED_ARROW: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_CURSED_ARROW); + _events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); + break; + case EVENT_FROST_TRAP: + DoCast(me, SPELL_FROST_TRAP); + _events.ScheduleEvent(EVENT_FROST_TRAP, 30000); + break; + case EVENT_ICE_SHOT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_ICE_SHOT); + _events.ScheduleEvent(EVENT_ICE_SHOT, 15000); + break; + default: + break; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (_events.ExecuteEvent()) - { - case EVENT_SHOOT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHOOT); - _events.ScheduleEvent(EVENT_SHOOT, 2000); - break; - case EVENT_CURSED_ARROW: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CURSED_ARROW); - _events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); - break; - case EVENT_FROST_TRAP: - DoCast(SPELL_FROST_TRAP); - _events.ScheduleEvent(EVENT_FROST_TRAP, 30000); - break; - case EVENT_ICE_SHOT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_ICE_SHOT); - _events.ScheduleEvent(EVENT_ICE_SHOT, 15000); - break; - } - DoMeleeAttackIfReady(); + return GetHallsOfReflectionAI<npc_tortured_riflemanAI>(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_tortured_riflemanAI>(creature); - } }; - -enum GeneralEvents +enum FrostswornGeneral { - //General + // General EVENT_SHIELD = 1, EVENT_SPIKE = 2, EVENT_CLONE = 3, @@ -1575,554 +1816,652 @@ enum GeneralEvents SAY_AGGRO = 0, SAY_DEATH = 1, - SPELL_SHIELD_THROWN = 69222, // 73076 on hc - SPELL_SPIKE = 69184, // 70399 on hc - SPELL_CLONE_NAME = 57507, - SPELL_CLONE_MODEL = 45204, + SPELL_SHIELD_THROWN = 69222, + SPELL_SPIKE = 69184, + SPELL_CLONE = 69828, + SPELL_GHOST_VISUAL = 69861, // Reflection EVENT_BALEFUL_STRIKE = 1, - SPELL_BALEFUL_STRIKE = 69933, // 70400 on hc - SPELL_SPIRIT_BURST = 69900, // 73046 on hc + SPELL_BALEFUL_STRIKE = 69933, + SPELL_SPIRIT_BURST = 69900 }; -class npc_frostworn_general : public CreatureScript +class npc_frostsworn_general : public CreatureScript { -public: - npc_frostworn_general() : CreatureScript("npc_frostworn_general") { } + public: + npc_frostsworn_general() : CreatureScript("npc_frostsworn_general") { } - struct npc_frostworn_generalAI : public ScriptedAI - { - npc_frostworn_generalAI(Creature* creature) : ScriptedAI(creature) + struct npc_frostsworn_generalAI : public ScriptedAI { - _instance = me->GetInstanceScript(); - Reset(); - } + npc_frostsworn_generalAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } - InstanceScript* _instance; - EventMap _events; + void Reset() override + { + _events.Reset(); + _instance->SetData(DATA_FROSTSWORN_GENERAL, NOT_STARTED); + } - void Reset() override - { - _events.Reset(); - _instance->SetData(DATA_FROSWORN_EVENT, NOT_STARTED); - } + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _events.Reset(); + _instance->SetData(DATA_FROSTSWORN_GENERAL, DONE); + } - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - _instance->SetData(DATA_FROSWORN_EVENT, DONE); - } + void EnterCombat(Unit* /*victim*/) override + { + Talk(SAY_AGGRO); + DoZoneInCombat(); + _events.ScheduleEvent(EVENT_SHIELD, 5000); + _events.ScheduleEvent(EVENT_SPIKE, 14000); + _events.ScheduleEvent(EVENT_CLONE, 22000); + _instance->SetData(DATA_FROSTSWORN_GENERAL, IN_PROGRESS); + } - void EnterCombat(Unit* /*victim*/) override - { - Talk(SAY_AGGRO); - _events.ScheduleEvent(EVENT_SHIELD, 5000); - _events.ScheduleEvent(EVENT_SPIKE, 14000); - _events.ScheduleEvent(EVENT_CLONE, 22000); - _instance->SetData(DATA_FROSWORN_EVENT, IN_PROGRESS); - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + _events.Update(diff); - _events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + while (uint32 event = _events.ExecuteEvent()) + { + switch (event) + { + case EVENT_SHIELD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) + DoCast(target, SPELL_SHIELD_THROWN); + _events.ScheduleEvent(EVENT_SHIELD, urand(8000, 12000)); + break; + case EVENT_SPIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) + DoCast(target, SPELL_SPIKE); + _events.ScheduleEvent(EVENT_SPIKE, urand(15000, 20000)); + break; + case EVENT_CLONE: + SummonClones(); + _events.ScheduleEvent(EVENT_CLONE, 60000); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } - while (uint32 event = _events.ExecuteEvent()) + void SummonClones() { - switch (event) + std::list<Unit*> playerList; + SelectTargetList(playerList, 5, SELECT_TARGET_TOPAGGRO, 0.0f, true); + for (Unit* target : playerList) { - case EVENT_SHIELD: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_SHIELD_THROWN); - _events.ScheduleEvent(EVENT_SHIELD, urand(8000, 12000)); - break; - case EVENT_SPIKE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_SPIKE); - _events.ScheduleEvent(EVENT_SPIKE, urand(15000, 20000)); - break; - case EVENT_CLONE: - SummonClones(); - _events.ScheduleEvent(EVENT_CLONE, 60000); - break; + if (Creature* reflection = me->SummonCreature(NPC_REFLECTION, *target, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000)) + { + target->CastSpell(reflection, SPELL_CLONE, true); + target->CastSpell(reflection, SPELL_GHOST_VISUAL, true); + reflection->AI()->AttackStart(target); + } } } - DoMeleeAttackIfReady(); - } - void SummonClones() + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override { - std::list<Unit *> playerList; - SelectTargetList(playerList, 5, SELECT_TARGET_TOPAGGRO, 0, true); - for (std::list<Unit*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) - { - Unit* temp = (*itr); - Creature* reflection = me->SummonCreature(NPC_REFLECTION, temp->GetPositionX(), temp->GetPositionY(), temp->GetPositionZ(), temp->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000); - reflection->SetName(temp->GetName()); - temp->CastSpell(reflection, SPELL_CLONE_NAME, true); - temp->CastSpell(reflection, SPELL_CLONE_MODEL, true); - reflection->setFaction(me->getFaction()); - reflection->AI()->AttackStart(temp); - } + return GetHallsOfReflectionAI<npc_frostsworn_generalAI>(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_frostworn_generalAI>(creature); - } }; class npc_spiritual_reflection : public CreatureScript { -public: - npc_spiritual_reflection() : CreatureScript("npc_spiritual_reflection") { } + public: + npc_spiritual_reflection() : CreatureScript("npc_spiritual_reflection") { } - struct npc_spiritual_reflectionAI : public ScriptedAI - { - npc_spiritual_reflectionAI(Creature *creature) : ScriptedAI(creature) + struct npc_spiritual_reflectionAI : public ScriptedAI { - Reset(); - } + npc_spiritual_reflectionAI(Creature *creature) : ScriptedAI(creature) { } - EventMap _events; + void Reset() override + { + _events.Reset(); + } - void Reset() override - { - _events.Reset(); - } + void EnterCombat(Unit* /*victim*/) override + { + _events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 3000); + } - void EnterCombat(Unit* /*victim*/) override - { - _events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 3000); - } + void JustDied(Unit* /*killer*/) override + { + DoCastAOE(SPELL_SPIRIT_BURST); + } - void JustDied(Unit* killer) override - { - DoCast(killer, SPELL_SPIRIT_BURST); - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + _events.Update(diff); - _events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + switch (_events.ExecuteEvent()) + { + case EVENT_BALEFUL_STRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 8.0f, true)) + DoCast(target, SPELL_BALEFUL_STRIKE); + _events.ScheduleEvent(EVENT_BALEFUL_STRIKE, urand(3000, 8000)); + break; + default: + break; + } - switch (_events.ExecuteEvent()) - { - case EVENT_BALEFUL_STRIKE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_BALEFUL_STRIKE); - _events.ScheduleEvent(EVENT_BALEFUL_STRIKE, urand(3000, 8000)); + DoMeleeAttackIfReady(); } - DoMeleeAttackIfReady(); - } - }; + private: + EventMap _events; + }; - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_spiritual_reflectionAI(creature); - } + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_spiritual_reflectionAI(creature); + } }; +// 5689 class at_hor_intro_start : public AreaTriggerScript { -public: - at_hor_intro_start() : AreaTriggerScript("at_hor_intro_start") { } + public: + at_hor_intro_start() : AreaTriggerScript("at_hor_intro_start") { } - bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override - { - InstanceScript* _instance = player->GetInstanceScript(); + bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override + { + if (player->IsGameMaster()) + return true; - if (player->IsGameMaster()) - return true; + InstanceScript* _instance = player->GetInstanceScript(); - if (_instance->GetData(DATA_INTRO_EVENT) == NOT_STARTED) - _instance->SetData(DATA_INTRO_EVENT, IN_PROGRESS); + if (_instance->GetData(DATA_INTRO_EVENT) == NOT_STARTED) + _instance->SetData(DATA_INTRO_EVENT, IN_PROGRESS); - return true; - } + return true; + } }; class at_hor_waves_restarter : public AreaTriggerScript { -public: - at_hor_waves_restarter() : AreaTriggerScript("at_hor_waves_restarter") { } + public: + at_hor_waves_restarter() : AreaTriggerScript("at_hor_waves_restarter") { } - bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override - { - InstanceScript* _instance = player->GetInstanceScript(); + bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override + { + if (player->IsGameMaster()) + return true; - if (player->IsGameMaster()) - return true; + InstanceScript* _instance = player->GetInstanceScript(); + + if (_instance->GetData(DATA_WAVE_COUNT)) + return true; - if (_instance->GetData(DATA_WAVE_COUNT)) + if (_instance->GetData(DATA_INTRO_EVENT) == DONE && _instance->GetBossState(DATA_MARWYN) != DONE) + { + _instance->ProcessEvent(0, EVENT_SPAWN_WAVES); + + if (Creature* falric = player->GetCreature(*player, _instance->GetData64(DATA_FALRIC))) + { + falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); + falric->SetVisible(true); + } + if (Creature* marwyn = player->GetCreature(*player, _instance->GetData64(DATA_MARWYN))) + { + marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); + marwyn->SetVisible(true); + } + } return true; + } +}; - if (_instance->GetData(DATA_INTRO_EVENT) == DONE && _instance->GetBossState(DATA_MARWYN_EVENT) != DONE) +// 5740 +class at_hor_impenetrable_door : public AreaTriggerScript +{ + public: + at_hor_impenetrable_door() : AreaTriggerScript("at_hor_impenetrable_door") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*at*/) override { - _instance->ProcessEvent(0, EVENT_SPAWN_WAVES); + if (player->IsGameMaster()) + return true; - if (Creature* falric = player->GetCreature(*player, _instance->GetData64(DATA_FALRIC_EVENT))) - { - falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); - falric->SetVisible(true); - } - if (Creature* marwyn = player->GetCreature(*player, _instance->GetData64(DATA_MARWYN_EVENT))) - { - marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); - marwyn->SetVisible(true); - } + InstanceScript* _instance = player->GetInstanceScript(); + if (_instance->GetBossState(DATA_MARWYN) == DONE) + return true; + + /// return false to handle teleport by db + return false; } - return true; - } }; -class at_shadow_throne : public AreaTriggerScript +// 5605 +class at_hor_shadow_throne : public AreaTriggerScript { -public: - at_shadow_throne() : AreaTriggerScript("at_shadow_throne") { } + public: + at_hor_shadow_throne() : AreaTriggerScript("at_hor_shadow_throne") { } - bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override - { - InstanceScript* _instance = player->GetInstanceScript(); + bool OnTrigger(Player* player, AreaTriggerEntry const* /*at*/) override + { + if (player->IsGameMaster()) + return true; + + InstanceScript* _instance = player->GetInstanceScript(); + + if (_instance->GetBossState(DATA_THE_LICH_KING_ESCAPE) == NOT_STARTED) + _instance->SetBossState(DATA_THE_LICH_KING_ESCAPE, IN_PROGRESS); - if (player->IsGameMaster()) return true; + } +}; - if (_instance->GetData(DATA_ESCAPE_EVENT) == NOT_STARTED) - _instance->SetData(DATA_ESCAPE_EVENT, IN_PROGRESS); +enum EscapeEvents +{ + // Raging Ghoul + EVENT_RAGING_GHOUL_JUMP = 1, - return true; - } + // Risen Witch Doctor + EVENT_RISEN_WITCH_DOCTOR_CURSE, + EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT, + EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT_VOLLEY, + + // Lumbering Abomination + EVENT_LUMBERING_ABOMINATION_VOMIT_SPRAY, + EVENT_LUMBERING_ABOMINATION_CLEAVE }; -class npc_raging_ghoul : public CreatureScript +namespace hor { -public: - npc_raging_ghoul() : CreatureScript("npc_raging_ghoul") { } - struct npc_raging_ghoulAI : public ScriptedAI - { - npc_raging_ghoulAI(Creature* creature) : ScriptedAI(creature) +class StartMovementEvent : public BasicEvent +{ + public: + StartMovementEvent(Creature* owner) : _owner(owner) { } + + bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override { - _instance = me->GetInstanceScript(); + _owner->SetReactState(REACT_AGGRESSIVE); + if (Unit* target = _owner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + _owner->AI()->AttackStart(target); + return true; } - InstanceScript* _instance; - uint32 _emergeTimer; - bool _doEmerge; - bool _doJump; - uint64 _leaderGUID; + private: + Creature* _owner; +}; - void Reset() override - { - _emergeTimer = 4000; - _doEmerge = false; - _doJump = false; - if (_instance->GetData(DATA_ESCAPE_EVENT) == IN_PROGRESS) - _instance->SetData(DATA_SUMMONS, 1); +} // namespace hor - } +struct npc_escape_event_trash : public ScriptedAI +{ + npc_escape_event_trash(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - void IsSummonedBy(Unit*) override - { - DoCast(me, SPELL_EMERGE_VISUAL); - } + void Reset() override + { + _events.Reset(); + } - void JustDied(Unit* /*killer*/) override + void UpdateAI(uint32 /*diff*/) override + { + if (_instance->GetBossState(DATA_THE_LICH_KING_ESCAPE) == FAIL || _instance->GetBossState(DATA_THE_LICH_KING_ESCAPE) == NOT_STARTED) + me->DespawnOrUnsummon(); + } + + void IsSummonedBy(Unit* /*summoner*/) override + { + DoZoneInCombat(me, 0.0f); + if (Creature* leader = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ESCAPE_LEADER))) { - _instance->SetData(DATA_SUMMONS, 0); + me->SetInCombatWith(leader); + leader->SetInCombatWith(me); + me->AddThreat(leader, 0.0f); } + } - void AttackStart(Unit* who) override +protected: + EventMap _events; + InstanceScript* _instance; +}; + +class npc_raging_ghoul : public CreatureScript +{ + public: + npc_raging_ghoul() : CreatureScript("npc_raging_ghoul") { } + + struct npc_raging_ghoulAI : public npc_escape_event_trash { - if (!who) - return; + npc_raging_ghoulAI(Creature* creature) : npc_escape_event_trash(creature) { } - if (!_doEmerge) - return; + void Reset() override + { + npc_escape_event_trash::Reset(); + _events.ScheduleEvent(EVENT_RAGING_GHOUL_JUMP, 5000); + } - ScriptedAI::AttackStart(who); - } + void IsSummonedBy(Unit* summoner) override + { + me->CastSpell(me, SPELL_RAGING_GHOUL_SPAWN, true); + me->SetReactState(REACT_PASSIVE); + me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + me->m_Events.AddEvent(new hor::StartMovementEvent(me), me->m_Events.CalculateTime(5000)); - void UpdateAI(uint32 diff) override - { - if (!_instance) - return; + npc_escape_event_trash::IsSummonedBy(summoner); + } - if (_instance->GetData(DATA_ESCAPE_EVENT) == IN_PROGRESS) + void UpdateAI(uint32 diff) override { - _leaderGUID = _instance->GetData64(DATA_ESCAPE_LEADER); - Creature* leader = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ESCAPE_LEADER)); + npc_escape_event_trash::UpdateAI(diff); + + if (!UpdateVictim()) + return; + + _events.Update(diff); - if (_doEmerge != true) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (_events.ExecuteEvent()) { - if (_emergeTimer < diff) - { - _doEmerge = true; - if (leader) + case EVENT_RAGING_GHOUL_JUMP: + if (Unit* victim = me->GetVictim()) { - DoResetThreat(); - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MoveChase(leader); + if (me->IsInRange(victim, 5.0f, 30.0f)) + { + DoCast(victim, SPELL_GHOUL_JUMP); + return; + } } - } - else - _emergeTimer -= diff; + _events.ScheduleEvent(EVENT_RAGING_GHOUL_JUMP, 500); + break; + default: + break; } - if (me->Attack(leader,true))/*(Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f))*/ - { - if (!_doJump && me->IsWithinDistInMap(leader, 30.0f) && !me->IsWithinDistInMap(leader, 5.0f)) - { - _doJump = true; - DoCast(leader, SPELL_GHOUL_JUMP); - } - } + DoMeleeAttackIfReady(); } - else if (_instance->GetData(DATA_ESCAPE_EVENT) == FAIL || _instance->GetData(DATA_ESCAPE_EVENT) == NOT_STARTED) - me->DespawnOrUnsummon(); - DoMeleeAttackIfReady(); - } - }; + }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_raging_ghoulAI>(creature); - } + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<npc_raging_ghoulAI>(creature); + } }; class npc_risen_witch_doctor : public CreatureScript { -public: - npc_risen_witch_doctor() : CreatureScript("npc_risen_witch_doctor") { } + public: + npc_risen_witch_doctor() : CreatureScript("npc_risen_witch_doctor") { } - struct npc_risen_witch_doctorAI : public ScriptedAI - { - npc_risen_witch_doctorAI(Creature* creature) : ScriptedAI(creature) + struct npc_risen_witch_doctorAI : public npc_escape_event_trash { - _instance = me->GetInstanceScript(); - } + npc_risen_witch_doctorAI(Creature* creature) : npc_escape_event_trash(creature) { } - InstanceScript* _instance; - uint32 _emergeTimer; - bool _doEmerge; - uint64 _leaderGUID; - uint32 _boltTimer; - uint32 _boltVolleyTimer; - uint32 _curseTimer; + void Reset() override + { + npc_escape_event_trash::Reset(); + _events.ScheduleEvent(EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT, 6000); + _events.ScheduleEvent(EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT_VOLLEY, 15000); + _events.ScheduleEvent(EVENT_RISEN_WITCH_DOCTOR_CURSE, 7000); + } - void Reset() override - { - _emergeTimer = 5000; - _boltTimer = 6000; - _boltVolleyTimer = 15000; - _curseTimer = 7000; - _doEmerge = false; - if (_instance->GetData(DATA_ESCAPE_EVENT) == IN_PROGRESS) - _instance->SetData(DATA_SUMMONS, 1); - } + void IsSummonedBy(Unit* summoner) override + { + me->CastSpell(me, SPELL_RISEN_WITCH_DOCTOR_SPAWN, true); + me->SetReactState(REACT_PASSIVE); + me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + me->m_Events.AddEvent(new hor::StartMovementEvent(me), me->m_Events.CalculateTime(5000)); - void IsSummonedBy(Unit*) override - { - DoCast(me, SPELL_EMERGE_VISUAL); - DoZoneInCombat(me, 100.00f); - } + npc_escape_event_trash::IsSummonedBy(summoner); + } - void JustDied(Unit* /*killer*/) override - { - _instance->SetData(DATA_SUMMONS, 0); - } + void UpdateAI(uint32 diff) override + { + npc_escape_event_trash::UpdateAI(diff); - void AttackStart(Unit* who) override - { - if (!who) - return; + if (!UpdateVictim()) + return; + + _events.Update(diff); - if (_doEmerge == false) - return; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - ScriptedAI::AttackStart(who); + switch (_events.ExecuteEvent()) + { + case EVENT_RISEN_WITCH_DOCTOR_CURSE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true)) + DoCast(target, SPELL_CURSE_OF_DOOM); + _events.ScheduleEvent(EVENT_RISEN_WITCH_DOCTOR_CURSE, urand(10000, 15000)); + break; + case EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 20.0f, true)) + DoCast(target, SPELL_SHADOW_BOLT); + _events.ScheduleEvent(EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT, urand(2000, 3000)); + break; + case EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT_VOLLEY: + if (SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true)) + DoCastAOE(SPELL_SHADOW_BOLT_VOLLEY); + _events.ScheduleEvent(EVENT_RISEN_WITCH_DOCTOR_SHADOW_BOLT_VOLLEY, urand(15000, 22000)); + break; + default: + break; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<npc_risen_witch_doctorAI>(creature); } +}; + +class npc_lumbering_abomination : public CreatureScript +{ + public: + npc_lumbering_abomination() : CreatureScript("npc_lumbering_abomination") { } - void UpdateAI(uint32 diff) override + struct npc_lumbering_abominationAI : public npc_escape_event_trash { - if (!_instance) - return; + npc_lumbering_abominationAI(Creature* creature) : npc_escape_event_trash(creature) { } - if (_instance->GetData(DATA_ESCAPE_EVENT) == IN_PROGRESS) + void Reset() override { - if (_doEmerge != true) - { - if (_emergeTimer < diff) - { - _doEmerge = true; - _leaderGUID = _instance->GetData64(DATA_ESCAPE_LEADER); + npc_escape_event_trash::Reset(); + _events.ScheduleEvent(EVENT_LUMBERING_ABOMINATION_VOMIT_SPRAY, 15000); + _events.ScheduleEvent(EVENT_LUMBERING_ABOMINATION_CLEAVE, 6000); + } - if (Creature* leader = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ESCAPE_LEADER))) - { - DoResetThreat(); - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MoveChase(leader); - } - } - else - _emergeTimer -= diff; - } + void UpdateAI(uint32 diff) override + { + npc_escape_event_trash::UpdateAI(diff); - if (_curseTimer < diff) - { - if (Unit *target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_COURSE_OF_DOOM); - _curseTimer = urand(10000, 15000); - } - else - _curseTimer -= diff; + if (!UpdateVictim()) + return; - if (_boltTimer < diff) - { - if (Unit *target = SelectTarget(SELECT_TARGET_TOPAGGRO)) - DoCast(target, SPELL_SHADOW_BOLT); - _boltTimer = urand(2000, 3000); - } - else - _boltTimer -= diff; + _events.Update(diff); - if (_boltVolleyTimer < diff) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (_events.ExecuteEvent()) { - if (Unit *target = SelectTarget(SELECT_TARGET_TOPAGGRO)) - DoCast(target, SPELL_SHADOW_BOLT_VOLLEY); - _boltVolleyTimer = urand(15000, 22000); + case EVENT_LUMBERING_ABOMINATION_VOMIT_SPRAY: + DoCastVictim(SPELL_VOMIT_SPRAY); + _events.ScheduleEvent(EVENT_LUMBERING_ABOMINATION_VOMIT_SPRAY, urand(15000, 20000)); + break; + case EVENT_LUMBERING_ABOMINATION_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + _events.ScheduleEvent(EVENT_LUMBERING_ABOMINATION_CLEAVE, urand(7000, 9000)); + break; + default: + break; } - else - _boltVolleyTimer -= diff; + + DoMeleeAttackIfReady(); } - else if (_instance->GetData(DATA_ESCAPE_EVENT) == FAIL || _instance->GetData(DATA_ESCAPE_EVENT) == NOT_STARTED) - me->DespawnOrUnsummon(); - DoMeleeAttackIfReady(); - } - }; + }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_risen_witch_doctorAI>(creature); - } + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfReflectionAI<npc_lumbering_abominationAI>(creature); + } }; - -class npc_lumbering_abomination : public CreatureScript +// 72900 - Start Halls of Reflection Quest AE +class spell_hor_start_halls_of_reflection_quest_ae : public SpellScriptLoader { -public: - npc_lumbering_abomination() : CreatureScript("npc_lumbering_abomination") { } + public: + spell_hor_start_halls_of_reflection_quest_ae() : SpellScriptLoader("spell_hor_start_halls_of_reflection_quest_ae") { } - struct npc_lumbering_abominationAI : public ScriptedAI - { - npc_lumbering_abominationAI(Creature* creature) : ScriptedAI(creature) + class spell_hor_start_halls_of_reflection_quest_ae_SpellScript : public SpellScript { - _instance = me->GetInstanceScript(); - } + PrepareSpellScript(spell_hor_start_halls_of_reflection_quest_ae_SpellScript); + + void StartQuests(SpellEffIndex /*effIndex*/) + { + if (Player* target = GetHitPlayer()) + { + // CanTakeQuest and CanAddQuest checks done in spell effect execution + if (target->GetTeam() == ALLIANCE) + target->CastSpell(target, SPELL_START_HALLS_OF_REFLECTION_QUEST_A, true); + else + target->CastSpell(target, SPELL_START_HALLS_OF_REFLECTION_QUEST_H, true); + } + } - InstanceScript* _instance; - uint64 _leaderGUID; - bool _doWalk; - uint32 _strikeTimer; - uint32 _vomitTimer; + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_hor_start_halls_of_reflection_quest_ae_SpellScript::StartQuests, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; - void Reset() override + SpellScript* GetSpellScript() const override { - _doWalk = false; - _vomitTimer = 15000; - _strikeTimer = 6000; - if (_instance->GetData(DATA_ESCAPE_EVENT) == IN_PROGRESS) - _instance->SetData(DATA_SUMMONS, 1); + return new spell_hor_start_halls_of_reflection_quest_ae_SpellScript(); } +}; + +// 70190 - Evasion +class spell_hor_evasion : public SpellScriptLoader +{ + public: + spell_hor_evasion() : SpellScriptLoader("spell_hor_evasion") { } + + class spell_hor_evasion_SpellScript : public SpellScript + { + PrepareSpellScript(spell_hor_evasion_SpellScript); + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void SetDest(SpellDestination& dest) + { + WorldObject* target = GetExplTargetWorldObject(); + Position pos(*target); + Position home = GetCaster()->ToCreature()->GetHomePosition(); + + // prevent evasion outside the room + if (pos.IsInDist2d(&home, 15.0f)) + return; + + float angle = pos.GetAngle(&home); + float dist = GetSpellInfo()->Effects[EFFECT_0].CalcRadius(GetCaster()); + target->MovePosition(pos, dist, angle); + + dest.Relocate(pos); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_hor_evasion_SpellScript::SetDest, EFFECT_0, TARGET_DEST_TARGET_RADIUS); + } + }; - void IsSummonedBy(Unit*) override + SpellScript* GetSpellScript() const override { - DoCast(me, SPELL_EMERGE_VISUAL); - DoZoneInCombat(me, 100.00f); + return new spell_hor_evasion_SpellScript(); } +}; + +// 70017 - Gunship Cannon Fire +class spell_hor_gunship_cannon_fire : public SpellScriptLoader +{ + public: + spell_hor_gunship_cannon_fire() : SpellScriptLoader("spell_hor_gunship_cannon_fire") { } - void UpdateAI(uint32 diff) override + class spell_hor_gunship_cannon_fire_AuraScript : public AuraScript { - if (_instance->GetData(DATA_ESCAPE_EVENT) == IN_PROGRESS) + PrepareAuraScript(spell_hor_gunship_cannon_fire_AuraScript); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) { - if (_doWalk != true) + if (!urand(0, 2)) { - _doWalk = true; - _leaderGUID = _instance->GetData64(DATA_ESCAPE_LEADER); - if (Creature* leader = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ESCAPE_LEADER))) - { - DoResetThreat(); - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MoveChase(leader); - } - } - if (_strikeTimer < diff) - { - if (Unit *target = SelectTarget(SELECT_TARGET_TOPAGGRO)) - DoCast(target, SPELL_ABON_STRIKE); - _strikeTimer = urand(7000, 9000); + if (GetTarget()->GetEntry() == NPC_GUNSHIP_CANNON_HORDE) + GetTarget()->CastSpell((Unit*)NULL, SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE, true); + else + GetTarget()->CastSpell((Unit*)NULL, SPELL_GUNSHIP_CANNON_FIRE_MISSILE_ALLIANCE, true); } - else - _strikeTimer -= diff; + } - if (_vomitTimer < diff) - { - if (Unit *target = SelectTarget(SELECT_TARGET_TOPAGGRO)) - DoCast(target, SPELL_VOMIT_SPRAY); - _vomitTimer = urand(15000, 20000); - } - else - _vomitTimer -= diff; + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_hor_gunship_cannon_fire_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } - else if (_instance->GetData(DATA_ESCAPE_EVENT) == FAIL || _instance->GetData(DATA_ESCAPE_EVENT) == NOT_STARTED) - me->DespawnOrUnsummon(); - DoMeleeAttackIfReady(); - } + }; - void JustDied(Unit* /*killer*/) override + AuraScript* GetAuraScript() const override { - _instance->SetData(DATA_SUMMONS, 0); + return new spell_hor_gunship_cannon_fire_AuraScript(); } - - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_lumbering_abominationAI>(creature); - } }; void AddSC_halls_of_reflection() { new at_hor_intro_start(); new at_hor_waves_restarter(); - new at_shadow_throne(); - new npc_jaina_or_sylvanas_hor(); + new at_hor_impenetrable_door(); + new at_hor_shadow_throne(); + new npc_jaina_or_sylvanas_intro_hor(); new npc_jaina_or_sylvanas_escape_hor(); + new npc_the_lich_king_escape_hor(); new npc_ghostly_priest(); new npc_phantom_mage(); new npc_phantom_hallucination(); new npc_shadowy_mercenary(); new npc_spectral_footman(); new npc_tortured_rifleman(); + new npc_frostsworn_general(); + new npc_spiritual_reflection(); new npc_raging_ghoul(); new npc_risen_witch_doctor(); new npc_lumbering_abomination(); - new npc_frostworn_general(); - new npc_spiritual_reflection(); + new spell_hor_start_halls_of_reflection_quest_ae(); + new spell_hor_evasion(); + new spell_hor_gunship_cannon_fire(); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h index c4776c3cfcd..a05035f7b44 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h @@ -15,170 +15,231 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef DEF_HALLS_OF_REFLECTION_H -#define DEF_HALLS_OF_REFLECTION_H +#ifndef HALLS_OF_REFLECTION_H_ +#define HALLS_OF_REFLECTION_H_ #define HoRScriptName "instance_halls_of_reflection" -#define MAX_ENCOUNTER 3 + +uint32 const EncounterCount = 3; /* Halls of Reflection encounters: -0- Falric -1- Marwyn -2- The Lich King + 0 - Falric + 1 - Marwyn + 2 - The Lich King */ -enum Data +enum DataTypes { - DATA_FALRIC_EVENT = 0, - DATA_MARWYN_EVENT = 1, - DATA_LICHKING_EVENT = 2, + DATA_FALRIC = 0, + DATA_MARWYN = 1, + DATA_THE_LICH_KING_ESCAPE = 2, + DATA_INTRO_EVENT = 3, - DATA_FROSWORN_EVENT = 4, + DATA_FROSTSWORN_GENERAL = 4, - DATA_WAVE_COUNT = 5, - DATA_TEAM_IN_INSTANCE = 6, - DATA_FROSTMOURNE = 7, - DATA_FROSTWORN_DOOR = 8, - DATA_ESCAPE_EVENT = 9, + DATA_KORELN_LORALEN = 5, + DATA_WAVE_COUNT = 6, + DATA_TEAM_IN_INSTANCE = 7, + DATA_FROSTMOURNE = 8, + DATA_IMPENETRABLE_DOOR = 9, DATA_ESCAPE_LEADER = 10, - DATA_SUMMONS = 11, - DATA_ICEWALL = 12, - DATA_CAVE_IN = 13 + DATA_ICEWALL = 11, + DATA_ICEWALL_TARGET = 12, + DATA_GUNSHIP = 13 }; -enum Creatures +enum CreatureIds { - NPC_JAINA_PART1 = 37221, - NPC_SYLVANAS_PART1 = 37223, - NPC_UTHER = 37225, - NPC_LICH_KING_PART1 = 37226, - NPC_LORALEN = 37779, - NPC_KORELN = 37582, - - NPC_FALRIC = 38112, - NPC_MARWYN = 38113, - NPC_WAVE_MERCENARY = 38177, - NPC_WAVE_FOOTMAN = 38173, - NPC_WAVE_RIFLEMAN = 38176, - NPC_WAVE_PRIEST = 38175, - NPC_WAVE_MAGE = 38172, - - NPC_FROSTWORN_GENERAL = 36723, - NPC_REFLECTION = 37068, // 37107 for tank only? - - NPC_JAINA_PART2 = 36955, - NPC_SYLVANAS_PART2 = 37554, - NPC_LICH_KING_PART2 = 36954, - NPC_BARTLETT = 37182, // High Captain Justin Bartlett - NPC_KORM = 37833, // Sky-Reaver Korm Blackscar - NPC_ICE_WALL = 37014, // Ice Wall Target - - NPC_RAGING_GNOUL = 36940, - NPC_RISEN_WITCH_DOCTOR = 36941, - NPC_ABON = 37069 + NPC_JAINA_INTRO = 37221, + NPC_SYLVANAS_INTRO = 37223, + NPC_UTHER = 37225, + NPC_THE_LICH_KING_INTRO = 37226, + NPC_KORELN = 37582, + NPC_LORALEN = 37779, + NPC_FROSTMOUNRE_ALTAR_BUNNY = 37704, + + NPC_FALRIC = 38112, + NPC_MARWYN = 38113, + NPC_WAVE_MERCENARY = 38177, + NPC_WAVE_FOOTMAN = 38173, + NPC_WAVE_RIFLEMAN = 38176, + NPC_WAVE_PRIEST = 38175, + NPC_WAVE_MAGE = 38172, + + NPC_FROSTSWORN_GENERAL = 36723, + NPC_REFLECTION = 37068, // 37107 for tank only? + + NPC_JAINA_ESCAPE = 36955, + NPC_SYLVANAS_ESCAPE = 37554, + NPC_THE_LICH_KING_ESCAPE = 36954, + NPC_ICE_WALL_TARGET = 37014, + + NPC_RAGING_GHOUL = 36940, + NPC_RISEN_WITCH_DOCTOR = 36941, + NPC_LUMBERING_ABOMINATION = 37069, + + NPC_GUNSHIP_CANNON_HORDE = 37593, + NPC_JUSTIN_BARTLETT = 30344, + NPC_KORM_BLACKSCAR = 30824, + + NPC_WORLD_TRIGGER = 22515 }; -enum GameObjects +enum GameObjectIds { - GO_FROSTMOURNE = 202302, - GO_ENTRANCE_DOOR = 201976, - GO_FROSTWORN_DOOR = 197341, - GO_ARTHAS_DOOR = 197342, - //GO_ESCAPE_DOOR = 197343, // always open ? - - GO_ICE_WALL = 201385, - GO_CAVE = 201596, - - GO_STAIRS_SKYBREAKER = 201709, - GO_SKYBREAKER = 201598, - GO_STAIRS_ORGRIM_HAMMER = 202211, - GO_ORGRIM_HAMMER = 201599, - GO_PORTAL = 202079, - - GO_CAPTAIN_CHEST_HORDE_NORMAL = 202212, //3145 - GO_CAPTAIN_CHEST_ALLIANCE_NORMAL = 201710, //30357 - GO_CAPTAIN_CHEST_HORDE_HEROIC = 202337, //3246 - GO_CAPTAIN_CHEST_ALLIANCE_HEROIC = 202336, //3333 + GO_FROSTMOURNE = 202302, + GO_ENTRANCE_DOOR = 201976, + GO_IMPENETRABLE_DOOR = 197341, + GO_SHADOW_THRONE_DOOR = 197342, + GO_ESCAPE_DOOR = 197343, // always open ? + + GO_ICE_WALL = 201385, + GO_CAVE_IN = 201596, + + GO_THE_SKYBREAKER = 201598, + GO_ORGRIMS_HAMMER = 201599, + GO_THE_SKYBREAKER_STAIRS = 201709, + GO_ORGRIMS_HAMMER_STAIRS = 202211, + GO_PORTAL_TO_DALARAN = 195682, + + GO_THE_CAPTAIN_CHEST_ALLIANCE_NORMAL = 201710, + GO_THE_CAPTAIN_CHEST_HORDE_NORMAL = 202212, + GO_THE_CAPTAIN_CHEST_ALLIANCE_HEROIC = 202336, + GO_THE_CAPTAIN_CHEST_HORDE_HEROIC = 202337 }; -enum HorWorldStates +enum Achievements { - WORLD_STATE_HOR_WAVES_ENABLED = 4884, - WORLD_STATE_HOR_WAVE_COUNT = 4882, + ACHIEV_NOT_RETREATING_EVENT = 22615, + SPELL_ACHIEV_CHECK = 72830 }; // Common actions from Instance Script to Boss Script enum Actions { - ACTION_ENTER_COMBAT, - ACTION_START_ESCAPING, - ACTION_WALL_BROKEN + ACTION_ENTER_COMBAT = -668001, + ACTION_START_PREFIGHT = -668002, + ACTION_WALL_BROKEN = -668003, + ACTION_GUNSHIP_ARRIVAL = -668004, + ACTION_GUNSHIP_ARRIVAL_2 = -668005 }; -enum TrashGeneralSpells +enum InstanceEvents { - // General spells - SPELL_WELL_OF_SOULS = 72630, // cast when spawn(become visible) - SPELL_SPIRIT_ACTIVATE = 72130, // cast when unit activates + EVENT_SPAWN_WAVES = 1, + EVENT_NEXT_WAVE = 2, + EVENT_DO_WIPE = 3, + EVENT_ADD_WAVE = 4, + EVENT_SPAWN_ESCAPE_EVENT = 5 }; -enum InstanceEvents +enum InstanceEventIds { - EVENT_SPAWN_WAVES = 1, - EVENT_NEXT_WAVE = 2, - EVENT_DO_WIPE = 3, - EVENT_ADD_WAVE = 4, + EVENT_GUNSHIP_ARRIVAL = 22709, + EVENT_GUNSHIP_ARRIVAL_2 = 22714, + EVENT_ICE_WALL_SUMMONED = 22795 }; -// Base class for FALRIC and MARWYN -// handled the summonList and the notification events to/from the InstanceScript -struct boss_horAI : ScriptedAI +enum InstanceSpells { - boss_horAI(Creature* creature) : ScriptedAI(creature), summons(creature) - { - instance = me->GetInstanceScript(); - } + // Trash + SPELL_WELL_OF_SOULS = 72630, // cast when spawn (become visible) + SPELL_SPIRIT_ACTIVATE = 72130, // cast when unit activates + + // Start Quests + SPELL_START_HALLS_OF_REFLECTION_QUEST_A = 71351, + SPELL_START_HALLS_OF_REFLECTION_QUEST_H = 71542, + SPELL_START_HALLS_OF_REFLECTION_QUEST_AE = 72900, + + // Quest Credits + SPELL_CREDIT_FINDING_SYLVANAS = 71536, + SPELL_CREDIT_FINDING_JAINA = 71538, + SPELL_CREDIT_ESCAPING_ARTHAS = 71352, + + // Gunship + SPELL_GUNSHIP_CANNON_FIRE = 70017, + SPELL_GUNSHIP_CANNON_FIRE_MISSILE_ALLIANCE = 70021, + SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE = 70246 +}; - InstanceScript* instance; - EventMap events; - SummonList summons; +enum InstanceWorldStates +{ + WORLD_STATE_HOR_WAVES_ENABLED = 4884, + WORLD_STATE_HOR_WAVE_COUNT = 4882 +}; + +enum InstanceYells +{ + SAY_CAPTAIN_FIRE = 0, + SAY_CAPTAIN_FINAL = 1 +}; + +// Base class for FALRIC and MARWYN +struct boss_horAI : BossAI +{ + boss_horAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId) { } - void Reset() + void Reset() override { - events.Reset(); + _Reset(); me->SetVisible(false); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); me->SetReactState(REACT_PASSIVE); if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) - instance->ProcessEvent(0, EVENT_DO_WIPE); + instance->ProcessEvent(NULL, EVENT_DO_WIPE); } - void DoAction(int32 actionID) + void DoAction(int32 actionId) override { - switch (actionID) + switch (actionId) { - case ACTION_ENTER_COMBAT: // called by InstanceScript when boss shall enter in combat. + case ACTION_ENTER_COMBAT: // called by InstanceScript when boss shall enter in combat. me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); me->SetReactState(REACT_AGGRESSIVE); - - if (Unit* unit = me->SelectNearestTarget()) - AttackStart(unit); - - DoZoneInCombat(); + DoZoneInCombat(me, 150.0f); + break; + default: break; } } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* summon) override { - summons.Summon(summoned); + summons.Summon(summon); } }; +class GameObjectDeleteDelayEvent : public BasicEvent +{ + public: + GameObjectDeleteDelayEvent(Unit* owner, uint64 gameObjectGUID) : _owner(owner), _gameObjectGUID(gameObjectGUID) { } + + void DeleteGameObject() + { + if (GameObject* go = ObjectAccessor::GetGameObject(*_owner, _gameObjectGUID)) + go->Delete(); + } + + bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override + { + DeleteGameObject(); + return true; + } + + void Abort(uint64 /*execTime*/) override + { + DeleteGameObject(); + } + + private: + Unit* _owner; + uint64 _gameObjectGUID; +}; + template<class AI> AI* GetHallsOfReflectionAI(Creature* creature) { return GetInstanceAI<AI>(creature, HoRScriptName); } -#endif +#endif // HALLS_OF_REFLECTION_H_ diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index ab5168dd34a..6f33e80b92b 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -19,590 +19,792 @@ #include "ScriptedCreature.h" #include "InstanceScript.h" #include "Player.h" +#include "Transport.h" #include "WorldPacket.h" #include "halls_of_reflection.h" -Position const JainaSpawnPos = {5236.659f, 1929.894f, 707.7781f, 0.8726646f}; // Jaina Spawn Position -Position const SylvanasSpawnPos = {5236.667f, 1929.906f, 707.7781f, 0.8377581f}; // Sylvanas Spawn Position -Position const GeneralSpawnPos = {5415.538f, 2117.842f, 707.7781f, 3.944444f}; // Frostsworn General -Position const JainaSpawnPos2 = {5549.011f, 2257.041f, 733.0120f, 1.153993f}; // Jaina Spawn Position 2 -Position const SylvanasSpawnPos2 = {5549.011f, 2257.041f, 733.0120f, 1.153993f}; // Sylvanas Spawn Position 2 +Position const JainaSpawnPos = { 5236.659f, 1929.894f, 707.7781f, 0.8726646f }; // Jaina Spawn Position +Position const SylvanasSpawnPos = { 5236.667f, 1929.906f, 707.7781f, 0.8377581f }; // Sylvanas Spawn Position (sniffed) +Position const JainaSpawnPos2 = { 5549.011f, 2257.041f, 733.0120f, 1.153993f }; // Jaina Spawn Position 2 +Position const SylvanasSpawnPos2 = { 5549.29f, 2257.353f, 733.0943f, 0.8901179f }; // Sylvanas Spawn Position 2 (sniffed) +Position const KorelnOrLoralenSpawnPos = { 5232.68f, 1931.46f, 707.7781f, 0.8377581f }; + +Position const TheLichKingEscapePosition[] = +{ + { 5557.017f, 2266.103f, 733.0943f, 3.892084f }, // 0 - Spawn (Horde) + { 5552.733f, 2262.718f, 733.0110f, 4.009696f } // 1 - Spawn (Alliance) +}; Position const SpawnPos[] = { - {5309.577f, 2042.668f, 707.7781f, 4.694936f}, - {5295.885f, 2040.342f, 707.7781f, 5.078908f}, - {5340.836f, 1992.458f, 707.7781f, 2.757620f}, - {5325.072f, 1977.597f, 707.7781f, 2.076942f}, - {5277.365f, 1993.229f, 707.7781f, 0.401426f}, - {5275.479f, 2001.135f, 707.7781f, 0.174533f}, - {5302.448f, 2042.222f, 707.7781f, 4.904375f}, - {5343.293f, 1999.384f, 707.7781f, 2.914700f}, - {5295.635f, 1973.757f, 707.7781f, 1.186824f}, - {5311.031f, 1972.229f, 707.7781f, 1.640610f}, - {5275.076f, 2008.724f, 707.7781f, 6.213372f}, - {5316.701f, 2041.550f, 707.7781f, 4.502949f}, - {5344.150f, 2007.168f, 707.7781f, 3.159046f}, - {5319.158f, 1973.998f, 707.7781f, 1.919862f}, - {5302.247f, 1972.415f, 707.7781f, 1.378810f}, - {5277.739f, 2016.882f, 707.7781f, 5.969026f}, - {5322.964f, 2040.288f, 707.7781f, 4.345870f}, - {5343.467f, 2015.951f, 707.7781f, 3.490659f}, - {5313.820f, 1978.146f, 707.7781f, 1.745329f}, - {5279.649f, 2004.656f, 707.7781f, 0.069814f}, - {5306.057f, 2037.002f, 707.7781f, 4.817109f}, - {5337.865f, 2003.403f, 707.7781f, 2.984513f}, - {5299.434f, 1979.009f, 707.7781f, 1.239184f}, - {5312.752f, 2037.122f, 707.7781f, 4.590216f}, - {5335.724f, 1996.859f, 707.7781f, 2.740167f}, - {5280.632f, 2012.156f, 707.7781f, 6.056293f}, - {5320.369f, 1980.125f, 707.7781f, 2.007129f}, - {5306.572f, 1977.474f, 707.7781f, 1.500983f}, - {5336.599f, 2017.278f, 707.7781f, 3.473205f}, - {5282.897f, 2019.597f, 707.7781f, 5.881760f}, - {5318.704f, 2036.108f, 707.7781f, 4.223697f}, - {5280.513f, 1997.842f, 707.7781f, 0.296706f}, - {5337.833f, 2010.057f, 707.7781f, 3.228859f}, - {5299.250f, 2035.998f, 707.7781f, 5.026548f}, + { 5309.577f, 2042.668f, 707.7781f, 4.694936f }, + { 5295.885f, 2040.342f, 707.7781f, 5.078908f }, + { 5340.836f, 1992.458f, 707.7781f, 2.757620f }, + { 5325.072f, 1977.597f, 707.7781f, 2.076942f }, + { 5277.365f, 1993.229f, 707.7781f, 0.401426f }, + { 5275.479f, 2001.135f, 707.7781f, 0.174533f }, + { 5302.448f, 2042.222f, 707.7781f, 4.904375f }, + { 5343.293f, 1999.384f, 707.7781f, 2.914700f }, + { 5295.635f, 1973.757f, 707.7781f, 1.186824f }, + { 5311.031f, 1972.229f, 707.7781f, 1.640610f }, + { 5275.076f, 2008.724f, 707.7781f, 6.213372f }, + { 5316.701f, 2041.550f, 707.7781f, 4.502949f }, + { 5344.150f, 2007.168f, 707.7781f, 3.159046f }, + { 5319.158f, 1973.998f, 707.7781f, 1.919862f }, + { 5302.247f, 1972.415f, 707.7781f, 1.378810f }, + { 5277.739f, 2016.882f, 707.7781f, 5.969026f }, + { 5322.964f, 2040.288f, 707.7781f, 4.345870f }, + { 5343.467f, 2015.951f, 707.7781f, 3.490659f }, + { 5313.820f, 1978.146f, 707.7781f, 1.745329f }, + { 5279.649f, 2004.656f, 707.7781f, 0.069814f }, + { 5306.057f, 2037.002f, 707.7781f, 4.817109f }, + { 5337.865f, 2003.403f, 707.7781f, 2.984513f }, + { 5299.434f, 1979.009f, 707.7781f, 1.239184f }, + { 5312.752f, 2037.122f, 707.7781f, 4.590216f }, + { 5335.724f, 1996.859f, 707.7781f, 2.740167f }, + { 5280.632f, 2012.156f, 707.7781f, 6.056293f }, + { 5320.369f, 1980.125f, 707.7781f, 2.007129f }, + { 5306.572f, 1977.474f, 707.7781f, 1.500983f }, + { 5336.599f, 2017.278f, 707.7781f, 3.473205f }, + { 5282.897f, 2019.597f, 707.7781f, 5.881760f }, + { 5318.704f, 2036.108f, 707.7781f, 4.223697f }, + { 5280.513f, 1997.842f, 707.7781f, 0.296706f }, + { 5337.833f, 2010.057f, 707.7781f, 3.228859f }, + { 5299.250f, 2035.998f, 707.7781f, 5.026548f } }; class instance_halls_of_reflection : public InstanceMapScript { -public: - instance_halls_of_reflection() : InstanceMapScript("instance_halls_of_reflection", 668) { } - - struct instance_halls_of_reflection_InstanceMapScript : public InstanceScript - { - instance_halls_of_reflection_InstanceMapScript(Map* map) : InstanceScript(map) { } + public: + instance_halls_of_reflection() : InstanceMapScript(HoRScriptName, 668) { } - void Initialize() override + struct instance_halls_of_reflection_InstanceMapScript : public InstanceScript { - SetBossNumber(MAX_ENCOUNTER); - events.Reset(); - - _falricGUID = 0; - _marwynGUID = 0; - _jainaOrSylvanasPart1GUID = 0; - _jainaOrSylvanasPart2GUID = 0; - _lichkingPart1GUID = 0; - _frostwornGeneralGUID = 0; - - _frostmourneGUID = 0; - _entranceDoorGUID = 0; - _frostwornDoorGUID = 0; - _arthasDoorGUID = 0; - _escapeDoorGUID = 0; - _caveGUID = 0; - - _teamInInstance = 0; - _waveCount = 0; - _introEvent = NOT_STARTED; - _frostwornGeneral = NOT_STARTED; - _escapeevent = NOT_STARTED; - _mobsaticewall = 0; - } + instance_halls_of_reflection_InstanceMapScript(Map* map) : InstanceScript(map) + { + SetBossNumber(EncounterCount); + + JainaOrSylvanasIntroGUID = 0; + KorelnOrLoralenGUID = 0; + TheLichkingIntroGUID = 0; + FalricGUID = 0; + MarwynGUID = 0; + FrostmourneAltarBunnyGUID = 0; + FrostswornGeneralGUID = 0; + JainaOrSylvanasEscapeGUID = 0; + TheLichKingEscapeGUID = 0; + + FrostmourneGUID = 0; + EntranceDoorGUID = 0; + ImpenetrableDoorGUID = 0; + ShadowThroneDoorGUID = 0; + CaveInGUID = 0; + GunshipGUID = 0; + CaptainsChestGUID = 0; + CaptainGUID = 0; + IcewallGUID = 0; + IcewallTargetGUID = 0; + + _teamInInstance = 0; + _waveCount = 0; + _introState = NOT_STARTED; + _frostswornGeneralState = NOT_STARTED; + + events.Reset(); + } - void OnPlayerEnter(Player* player) override - { - if (!_teamInInstance) - _teamInInstance = player->GetTeam(); - } + void OnPlayerEnter(Player* player) override + { + if (!_teamInInstance) + _teamInInstance = player->GetTeam(); - void OnCreatureCreate(Creature* creature) override - { - if (!_teamInInstance) + if (GetBossState(DATA_MARWYN) == DONE) + { + SpawnGunship(); + + if (!JainaOrSylvanasEscapeGUID && GetBossState(DATA_THE_LICH_KING_ESCAPE) != DONE) + SpawnEscapeEvent(); + } + } + + void OnCreatureCreate(Creature* creature) override { - Map::PlayerList const& players = instance->GetPlayers(); - if (!players.isEmpty()) - if (Player* player = players.begin()->GetSource()) - _teamInInstance = player->GetTeam(); + switch (creature->GetEntry()) + { + case NPC_JAINA_INTRO: + case NPC_SYLVANAS_INTRO: + JainaOrSylvanasIntroGUID = creature->GetGUID(); + break; + case NPC_KORELN: + case NPC_LORALEN: + if (GetBossState(DATA_MARWYN) != DONE) + creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + KorelnOrLoralenGUID = creature->GetGUID(); + break; + case NPC_THE_LICH_KING_INTRO: + TheLichkingIntroGUID = creature->GetGUID(); + break; + case NPC_FALRIC: + FalricGUID = creature->GetGUID(); + break; + case NPC_MARWYN: + MarwynGUID = creature->GetGUID(); + break; + case NPC_FROSTMOUNRE_ALTAR_BUNNY: + FrostmourneAltarBunnyGUID = creature->GetGUID(); + break; + case NPC_FROSTSWORN_GENERAL: + FrostswornGeneralGUID = creature->GetGUID(); + if (GetBossState(DATA_MARWYN) == DONE) + creature->SetPhaseMask(1, true); + break; + case NPC_JAINA_ESCAPE: + case NPC_SYLVANAS_ESCAPE: + JainaOrSylvanasEscapeGUID = creature->GetGUID(); + break; + case NPC_THE_LICH_KING_ESCAPE: + TheLichKingEscapeGUID = creature->GetGUID(); + break; + case NPC_JUSTIN_BARTLETT: + case NPC_KORM_BLACKSCAR: + CaptainGUID = creature->GetGUID(); + break; + case NPC_WORLD_TRIGGER: + if (!creature->GetTransport()) + break; + // no break + case NPC_GUNSHIP_CANNON_HORDE: + GunshipCannonGUIDs.insert(creature->GetGUID()); + break; + case NPC_ICE_WALL_TARGET: + IcewallTargetGUID = creature->GetGUID(); + break; + default: + break; + } } - switch (creature->GetEntry()) + void OnCreatureRemove(Creature* creature) override { - case NPC_JAINA_PART1: - case NPC_SYLVANAS_PART1: - _jainaOrSylvanasPart1GUID = creature->GetGUID(); - break; - case NPC_FALRIC: - _falricGUID = creature->GetGUID(); - break; - case NPC_MARWYN: - _marwynGUID = creature->GetGUID(); - break; - case NPC_FROSTWORN_GENERAL: - _frostwornGeneralGUID = creature->GetGUID(); - if (GetBossState(DATA_MARWYN_EVENT) == DONE) - if (Creature* general = instance->GetCreature(_frostwornGeneralGUID)) - general->SetPhaseMask(1, true); - break; - case NPC_JAINA_PART2: - case NPC_SYLVANAS_PART2: - _jainaOrSylvanasPart2GUID = creature->GetGUID(); - break; + switch (creature->GetEntry()) + { + case NPC_WAVE_MERCENARY: + case NPC_WAVE_FOOTMAN: + case NPC_WAVE_RIFLEMAN: + case NPC_WAVE_PRIEST: + case NPC_WAVE_MAGE: + { + uint32 internalWaveId = creature->AI()->GetData(0); + waveGuidList[internalWaveId].erase(creature->GetGUID()); + break; + } + case NPC_ICE_WALL_TARGET: + IcewallTargetGUID = 0; + break; + case NPC_WORLD_TRIGGER: + case NPC_GUNSHIP_CANNON_HORDE: + GunshipCannonGUIDs.erase(creature->GetGUID()); + break; + default: + break; + } } - } - void OnCreatureRemove(Creature* creature) override - { - switch (creature->GetEntry()) + uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override { - case NPC_WAVE_MERCENARY: - case NPC_WAVE_FOOTMAN: - case NPC_WAVE_RIFLEMAN: - case NPC_WAVE_PRIEST: - case NPC_WAVE_MAGE: + if (!_teamInInstance) + { + Map::PlayerList const& players = instance->GetPlayers(); + if (!players.isEmpty()) + if (Player* player = players.begin()->GetSource()) + _teamInInstance = player->GetTeam(); + } + + switch (entry) { - uint32 internalWaveId = creature->AI()->GetData(0); - waveGuidList[internalWaveId].erase(creature->GetGUID()); - break; + case GO_THE_CAPTAIN_CHEST_ALLIANCE_NORMAL: + case GO_THE_CAPTAIN_CHEST_ALLIANCE_HEROIC: + case GO_THE_SKYBREAKER_STAIRS: + if (_teamInInstance == HORDE) + return 0; + break; + case GO_THE_CAPTAIN_CHEST_HORDE_NORMAL: + case GO_THE_CAPTAIN_CHEST_HORDE_HEROIC: + case GO_ORGRIMS_HAMMER_STAIRS: + if (_teamInInstance == ALLIANCE) + return 0; + break; + default: + break; } + + return entry; } - } - void OnGameObjectCreate(GameObject* go) override - { - switch (go->GetEntry()) + void OnGameObjectCreate(GameObject* go) override { - case GO_FROSTMOURNE: - _frostmourneGUID = go->GetGUID(); - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - HandleGameObject(0, false, go); - if (GetData(DATA_INTRO_EVENT) == DONE) - go->SetPhaseMask(2, true); - break; - case GO_ENTRANCE_DOOR: - _entranceDoorGUID = go->GetGUID(); - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - HandleGameObject(0, true, go); - break; - case GO_FROSTWORN_DOOR: - _frostwornDoorGUID = go->GetGUID(); - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - if (GetBossState(DATA_MARWYN_EVENT) == DONE) - HandleGameObject(0, true, go); - else - HandleGameObject(0, false, go); - break; - case GO_ARTHAS_DOOR: - _arthasDoorGUID = go->GetGUID(); - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - if (GetData(DATA_FROSWORN_EVENT) == DONE) - HandleGameObject(0, true, go); - else + switch (go->GetEntry()) + { + case GO_FROSTMOURNE: + FrostmourneGUID = go->GetGUID(); + if (GetData(DATA_INTRO_EVENT) == DONE) + go->SetPhaseMask(2, true); + break; + case GO_ENTRANCE_DOOR: + EntranceDoorGUID = go->GetGUID(); + break; + case GO_IMPENETRABLE_DOOR: + ImpenetrableDoorGUID = go->GetGUID(); + HandleGameObject(0, GetBossState(DATA_MARWYN) == DONE, go); + break; + case GO_SHADOW_THRONE_DOOR: + ShadowThroneDoorGUID = go->GetGUID(); + HandleGameObject(0, GetData(DATA_FROSTSWORN_GENERAL) == DONE, go); + break; + case GO_CAVE_IN: + CaveInGUID = go->GetGUID(); + break; + case GO_THE_SKYBREAKER: + case GO_ORGRIMS_HAMMER: + GunshipGUID = go->GetGUID(); + break; + case GO_THE_SKYBREAKER_STAIRS: + case GO_ORGRIMS_HAMMER_STAIRS: + if (GetBossState(DATA_THE_LICH_KING_ESCAPE) == DONE) + go->SetRespawnTime(DAY); + GunshipStairGUIDs.insert(go->GetGUID()); + break; + case GO_THE_CAPTAIN_CHEST_ALLIANCE_NORMAL: + case GO_THE_CAPTAIN_CHEST_HORDE_NORMAL: + case GO_THE_CAPTAIN_CHEST_ALLIANCE_HEROIC: + case GO_THE_CAPTAIN_CHEST_HORDE_HEROIC: + CaptainsChestGUID = go->GetGUID(); + break; + case GO_ICE_WALL: HandleGameObject(0, false, go); - break; - case GO_CAVE: - _caveGUID = go->GetGUID(); - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - break; + IcewallGUID = go->GetGUID(); + break; + default: + break; + } } - } - void FillInitialWorldStates(WorldPacket& data) override - { - data << uint32(WORLD_STATE_HOR_WAVES_ENABLED) << uint32(0); - data << uint32(WORLD_STATE_HOR_WAVE_COUNT) << uint32(0); - } - - bool SetBossState(uint32 type, EncounterState state) override - { - if (!InstanceScript::SetBossState(type, state)) - return false; - - switch (type) + void OnGameObjectRemove(GameObject* go) override { - case DATA_FALRIC_EVENT: - if (state == DONE) - { - ++_waveCount; - events.ScheduleEvent(EVENT_NEXT_WAVE, 60000); - } - break; - case DATA_MARWYN_EVENT: - if (state == DONE) - { - HandleGameObject(_entranceDoorGUID, true); - HandleGameObject(_frostwornDoorGUID, true); - DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 0); - if (Creature* general = instance->GetCreature(_frostwornGeneralGUID)) - general->SetPhaseMask(1, true); - } - break; - case DATA_LICHKING_EVENT: - default: - break; + switch (go->GetEntry()) + { + case GO_THE_SKYBREAKER_STAIRS: + case GO_ORGRIMS_HAMMER_STAIRS: + GunshipStairGUIDs.erase(go->GetGUID()); + break; + default: + break; + } } - return true; - } + void FillInitialWorldStates(WorldPacket& data) override + { + data << uint32(WORLD_STATE_HOR_WAVES_ENABLED) << uint32(_introState == DONE && GetBossState(DATA_MARWYN) != DONE); + data << uint32(WORLD_STATE_HOR_WAVE_COUNT) << uint32(_waveCount); + } - void SetData(uint32 type, uint32 data) override - { - switch (type) + bool SetBossState(uint32 type, EncounterState state) override { - case DATA_INTRO_EVENT: - if (data == IN_PROGRESS) - { - if (!_introEvent) + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case DATA_FALRIC: + if (state == DONE) { - if (_teamInInstance == ALLIANCE) - instance->SummonCreature(NPC_JAINA_PART1, JainaSpawnPos); - else - instance->SummonCreature(NPC_SYLVANAS_PART1, SylvanasSpawnPos); + ++_waveCount; + events.ScheduleEvent(EVENT_NEXT_WAVE, 60000); } - } - _introEvent = data; - break; - case DATA_WAVE_COUNT: - if (_waveCount && data == NOT_STARTED) - ProcessEvent(NULL, EVENT_DO_WIPE); - break; - case DATA_FROSWORN_EVENT: - if (data == DONE) - { - HandleGameObject(_arthasDoorGUID, true); - if (_teamInInstance == ALLIANCE) - instance->SummonCreature(NPC_JAINA_PART2, JainaSpawnPos2); - else - instance->SummonCreature(NPC_SYLVANAS_PART2, SylvanasSpawnPos2); - } - _frostwornGeneral = data; - break; - case DATA_ESCAPE_EVENT: - if (data == IN_PROGRESS) - { - if (!_escapeevent) - if (Creature* jaina_or_sylvanas = instance->GetCreature(_jainaOrSylvanasPart2GUID)) - jaina_or_sylvanas->AI()->DoAction(ACTION_START_ESCAPING); - } - else if (data == NOT_STARTED) - { - if (Creature* jaina_or_sylvanas = instance->GetCreature(_jainaOrSylvanasPart2GUID)) - jaina_or_sylvanas->DespawnOrUnsummon(1); - if (_teamInInstance == ALLIANCE) - instance->SummonCreature(NPC_JAINA_PART2, JainaSpawnPos2); - else - instance->SummonCreature(NPC_SYLVANAS_PART2, SylvanasSpawnPos2); - SetData(DATA_ESCAPE_EVENT,IN_PROGRESS); - } - _escapeevent = data; - break; - case DATA_SUMMONS: - if (data == 0) - { - _mobsaticewall--; - if (_mobsaticewall == 0) + break; + case DATA_MARWYN: + if (state == DONE) { - if (Creature* jaina_or_sylvanas = instance->GetCreature(_jainaOrSylvanasPart2GUID)) - jaina_or_sylvanas->AI()->DoAction(ACTION_WALL_BROKEN); + if (Creature* bunny = instance->GetCreature(FrostmourneAltarBunnyGUID)) + bunny->CastSpell(bunny, SPELL_START_HALLS_OF_REFLECTION_QUEST_AE, true); + + if (Creature* korelnOrLoralen = instance->GetCreature(KorelnOrLoralenGUID)) + korelnOrLoralen->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + HandleGameObject(EntranceDoorGUID, true); + HandleGameObject(ImpenetrableDoorGUID, true); + DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 0); + if (Creature* general = instance->GetCreature(FrostswornGeneralGUID)) + general->SetPhaseMask(1, true); + + SpawnGunship(); + SpawnEscapeEvent(); } - } - else if (data == 1) - _mobsaticewall++; - break; + break; + case DATA_THE_LICH_KING_ESCAPE: + switch (state) + { + case NOT_STARTED: + break; + case IN_PROGRESS: + if (Creature* jainaOrSylvanas = instance->GetCreature(JainaOrSylvanasEscapeGUID)) + jainaOrSylvanas->AI()->DoAction(ACTION_START_PREFIGHT); + break; + case DONE: + if (GameObject* chest = instance->GetGameObject(CaptainsChestGUID)) + chest->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN); + + DoUseDoorOrButton(CaveInGUID, 15); + + if (Creature* lichking = instance->GetCreature(TheLichKingEscapeGUID)) + { + lichking->CastSpell((Unit*)NULL, SPELL_ACHIEV_CHECK, true); + lichking->DespawnOrUnsummon(1); + } + break; + case FAIL: + DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); + + if (Creature* jainaOrSylvanas = instance->GetCreature(JainaOrSylvanasEscapeGUID)) + jainaOrSylvanas->DespawnOrUnsummon(10000); + + if (Creature* icewallTarget = instance->GetCreature(IcewallTargetGUID)) + icewallTarget->DespawnOrUnsummon(); + + if (GameObject* icewall = instance->GetGameObject(IcewallGUID)) + icewall->Delete(); + + events.ScheduleEvent(EVENT_SPAWN_ESCAPE_EVENT, 30000); + break; + default: + break; + } + break; + default: + break; + } + + return true; } - SaveToDB(); - } + void SpawnGunship() + { + // don't spawn gunship twice + if (GunshipGUID) + return; + if (!_teamInInstance) + { + Map::PlayerList const& players = instance->GetPlayers(); + if (!players.isEmpty()) + if (Player* player = players.begin()->GetSource()) + _teamInInstance = player->GetTeam(); + } - // wave scheduling,checked when wave npcs die - void OnUnitDeath(Unit* unit) override - { - Creature* creature = unit->ToCreature(); - if (!creature) - return; + if (Transport* gunship = sTransportMgr->CreateTransport(_teamInInstance == HORDE ? GO_ORGRIMS_HAMMER : GO_THE_SKYBREAKER, 0, instance)) + gunship->EnableMovement(GetBossState(DATA_THE_LICH_KING_ESCAPE) == DONE); + } - switch (creature->GetEntry()) + void SpawnEscapeEvent() { - case NPC_WAVE_MERCENARY: - case NPC_WAVE_FOOTMAN: - case NPC_WAVE_RIFLEMAN: - case NPC_WAVE_PRIEST: - case NPC_WAVE_MAGE: + if (!_teamInInstance) { - uint32 deadNpcs = 0; - uint32 waveId = creature->AI()->GetData(0); - for (std::set<uint64>::const_iterator itr = waveGuidList[waveId].begin(); itr != waveGuidList[waveId].end(); ++itr) - { - Creature* npc = instance->GetCreature(*itr); - if (!npc || !npc->IsAlive()) - ++deadNpcs; - } - // because the current npc returns IsAlive when OnUnitDeath happens - // we check if the number of dead npcs is equal to the list-1 - if (deadNpcs == waveGuidList[waveId].size() - 1) + Map::PlayerList const& players = instance->GetPlayers(); + if (!players.isEmpty()) + if (Player* player = players.begin()->GetSource()) + _teamInInstance = player->GetTeam(); + } + + if (_teamInInstance == ALLIANCE) + { + instance->SummonCreature(NPC_JAINA_ESCAPE, JainaSpawnPos2); + instance->SummonCreature(NPC_THE_LICH_KING_ESCAPE, TheLichKingEscapePosition[1]); + } + else + { + instance->SummonCreature(NPC_SYLVANAS_ESCAPE, SylvanasSpawnPos2); + instance->SummonCreature(NPC_THE_LICH_KING_ESCAPE, TheLichKingEscapePosition[0]); + } + } + + void SetData(uint32 type, uint32 data) override + { + switch (type) + { + case DATA_INTRO_EVENT: + if (data == IN_PROGRESS) + { + if (_introState == NOT_STARTED) + { + if (_teamInInstance == ALLIANCE) + { + instance->SummonCreature(NPC_JAINA_INTRO, JainaSpawnPos); + instance->SummonCreature(NPC_KORELN, KorelnOrLoralenSpawnPos); + } + else + { + instance->SummonCreature(NPC_SYLVANAS_INTRO, SylvanasSpawnPos); + instance->SummonCreature(NPC_LORALEN, KorelnOrLoralenSpawnPos); + } + } + } + _introState = data; + break; + case DATA_WAVE_COUNT: + if (_waveCount && data == NOT_STARTED) + ProcessEvent(NULL, EVENT_DO_WIPE); + break; + case DATA_FROSTSWORN_GENERAL: + if (data == DONE) + HandleGameObject(ShadowThroneDoorGUID, true); + _frostswornGeneralState = data; + break; + default: + break; + } + + SaveToDB(); + } + + // wave scheduling, checked when wave npcs die + void OnUnitDeath(Unit* unit) override + { + Creature* creature = unit->ToCreature(); + if (!creature) + return; + + switch (creature->GetEntry()) + { + case NPC_WAVE_MERCENARY: + case NPC_WAVE_FOOTMAN: + case NPC_WAVE_RIFLEMAN: + case NPC_WAVE_PRIEST: + case NPC_WAVE_MAGE: { + uint32 waveId = creature->AI()->GetData(0); + for (uint64 guid : waveGuidList[waveId]) + { + if (Creature* npc = instance->GetCreature(guid)) + if (npc->IsAlive()) + return; + } + ++_waveCount; events.ScheduleEvent(EVENT_NEXT_WAVE, 3000); + break; } - break; } } - } - void Update(uint32 diff) override - { - if (!instance->HavePlayers()) - return; + void Update(uint32 diff) override + { + if (!instance->HavePlayers()) + return; - events.Update(diff); + events.Update(diff); - switch (events.ExecuteEvent()) - { - case EVENT_NEXT_WAVE: - ProcessEvent(NULL, EVENT_ADD_WAVE); - break; + switch (events.ExecuteEvent()) + { + case EVENT_NEXT_WAVE: + ProcessEvent(NULL, EVENT_ADD_WAVE); + break; + case EVENT_SPAWN_ESCAPE_EVENT: + SpawnEscapeEvent(); + break; + } } - } - void ProcessEvent(WorldObject* /*go*/, uint32 eventId) override - { - switch (eventId) + void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override { - // spawning all wave npcs at once - case EVENT_SPAWN_WAVES: - _waveCount = 1; - DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); - DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); - { - std::list<uint32> possibilityList, tempList; - uint32 posIndex = 0; + switch (eventId) + { + // spawning all wave npcs at once + case EVENT_SPAWN_WAVES: + _waveCount = 1; + DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + { + std::list<uint32> possibilityList, tempList; + uint32 posIndex = 0; - possibilityList.push_back(NPC_WAVE_MERCENARY); - possibilityList.push_back(NPC_WAVE_FOOTMAN); - possibilityList.push_back(NPC_WAVE_RIFLEMAN); - possibilityList.push_back(NPC_WAVE_PRIEST); - possibilityList.push_back(NPC_WAVE_MAGE); + possibilityList.push_back(NPC_WAVE_MERCENARY); + possibilityList.push_back(NPC_WAVE_FOOTMAN); + possibilityList.push_back(NPC_WAVE_RIFLEMAN); + possibilityList.push_back(NPC_WAVE_PRIEST); + possibilityList.push_back(NPC_WAVE_MAGE); - // iterate each wave - for (uint8 i = 0; i < 8; ++i) - { - tempList = possibilityList; + // iterate each wave + for (uint8 i = 0; i < 8; ++i) + { + tempList = possibilityList; - uint64 bossGuid = i <= 3 ? _falricGUID : _marwynGUID; + uint64 bossGuid = i <= 3 ? FalricGUID : MarwynGUID; - if (!i) - Trinity::Containers::RandomResizeList(tempList, 3); - else if (i < 6 && i != 3) - Trinity::Containers::RandomResizeList(tempList, 4); + if (!i) + Trinity::Containers::RandomResizeList(tempList, 3); + else if (i < 6 && i != 3) + Trinity::Containers::RandomResizeList(tempList, 4); - for (std::list<uint32>::const_iterator itr = tempList.begin(); itr != tempList.end(); ++itr) - { - if (Creature* boss = instance->GetCreature(bossGuid)) + for (uint32 entry : tempList) { - if (Creature* temp = boss->SummonCreature(*itr, SpawnPos[posIndex], TEMPSUMMON_DEAD_DESPAWN)) + if (Creature* boss = instance->GetCreature(bossGuid)) { - temp->AI()->SetData(0, i); - waveGuidList[i].insert(temp->GetGUID()); + if (Creature* temp = boss->SummonCreature(entry, SpawnPos[posIndex], TEMPSUMMON_DEAD_DESPAWN)) + { + temp->AI()->SetData(0, i); + waveGuidList[i].insert(temp->GetGUID()); + } } - } - ++posIndex; + ++posIndex; + } } } - } - events.ScheduleEvent(EVENT_NEXT_WAVE, 5000); - break; - case EVENT_ADD_WAVE: - DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); - DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); - HandleGameObject(_entranceDoorGUID, false); - - if (_waveCount % 5) - { - uint32 internalWaveId = _waveCount - ((_waveCount < 5) ? 1 : 2); - for (std::set<uint64>::const_iterator itr = waveGuidList[internalWaveId].begin(); itr != waveGuidList[internalWaveId].end(); ++itr) + events.ScheduleEvent(EVENT_NEXT_WAVE, 5000); + break; + case EVENT_ADD_WAVE: + DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + HandleGameObject(EntranceDoorGUID, false); + + if (_waveCount % 5) { - if (Creature* temp = instance->GetCreature(*itr)) + uint32 internalWaveId = _waveCount - ((_waveCount < 5) ? 1 : 2); + for (uint64 guid : waveGuidList[internalWaveId]) { - temp->CastSpell(temp, SPELL_SPIRIT_ACTIVATE, true); - temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC|UNIT_FLAG_NOT_SELECTABLE); - temp->AI()->DoZoneInCombat(temp, 100.00f); + if (Creature* temp = instance->GetCreature(guid)) + { + temp->CastSpell(temp, SPELL_SPIRIT_ACTIVATE, false); + temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NOT_SELECTABLE); + temp->AI()->DoZoneInCombat(temp, 100.00f); + } } } - } - else - { - uint32 bossIndex = (_waveCount / 5) - 1; - if (GetBossState(DATA_FALRIC_EVENT + bossIndex) != DONE) + else + { + uint32 bossIndex = (_waveCount / 5) - 1; + if (GetBossState(DATA_FALRIC + bossIndex) != DONE) + { + if (Creature* boss = instance->GetCreature(bossIndex ? MarwynGUID : FalricGUID)) + boss->AI()->DoAction(ACTION_ENTER_COMBAT); + } + else if (_waveCount != 10) + { + ++_waveCount; + events.ScheduleEvent(EVENT_NEXT_WAVE, 5000); + } + } + break; + case EVENT_DO_WIPE: + _waveCount = 0; + events.Reset(); + DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + HandleGameObject(EntranceDoorGUID, true); + + if (Creature* falric = instance->GetCreature(FalricGUID)) + falric->SetVisible(false); + if (Creature* marwyn = instance->GetCreature(MarwynGUID)) + marwyn->SetVisible(false); + // despawn wave npcs + for (uint8 i = 0; i < 8; ++i) { - if (Creature* boss = instance->GetCreature(bossIndex ? _marwynGUID : _falricGUID)) - boss->AI()->DoAction(ACTION_ENTER_COMBAT); + for (uint64 guid : waveGuidList[i]) + if (Creature* creature = instance->GetCreature(guid)) + creature->DespawnOrUnsummon(1); + waveGuidList[i].clear(); } - else if (_waveCount != 10) + break; + // Gunship Outro + case EVENT_GUNSHIP_ARRIVAL: + if (GetBossState(DATA_THE_LICH_KING_ESCAPE) == DONE) + break; + + if (Transport* gunship = instance->GetTransport(GunshipGUID)) + gunship->EnableMovement(false); + + if (Creature* jainaOrSylvanas = instance->GetCreature(JainaOrSylvanasEscapeGUID)) + jainaOrSylvanas->AI()->DoAction(ACTION_GUNSHIP_ARRIVAL); + + if (Creature* captain = instance->GetCreature(CaptainGUID)) + captain->AI()->Talk(SAY_CAPTAIN_FIRE); + + for (uint64 guid : GunshipCannonGUIDs) { - ++_waveCount; - events.ScheduleEvent(EVENT_NEXT_WAVE, 5000); + uint32 entry = GUID_ENPART(guid); + if ((entry == NPC_WORLD_TRIGGER && _teamInInstance == ALLIANCE) || (entry == NPC_GUNSHIP_CANNON_HORDE && _teamInInstance == HORDE)) + if (Creature* cannon = instance->GetCreature(guid)) + cannon->CastSpell(cannon, SPELL_GUNSHIP_CANNON_FIRE, true); } - } - break; - case EVENT_DO_WIPE: - _waveCount = 0; - events.Reset(); - DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); - DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); - HandleGameObject(_entranceDoorGUID, true); - - if (Creature* falric = instance->GetCreature(_falricGUID)) - falric->SetVisible(false); - if (Creature* marwyn = instance->GetCreature(_marwynGUID)) - marwyn->SetVisible(false); - //despawn wave npcs - for (uint8 i = 0; i < 8; ++i) - { - for (std::set<uint64>::const_iterator itr = waveGuidList[i].begin(); itr != waveGuidList[i].end(); ++itr) - if (Creature* creature = instance->GetCreature(*itr)) - creature->DespawnOrUnsummon(1); - waveGuidList[i].clear(); - } - break; + break; + case EVENT_GUNSHIP_ARRIVAL_2: + if (Transport* gunship = instance->GetTransport(GunshipGUID)) + gunship->EnableMovement(false); + + for (uint64 guid : GunshipStairGUIDs) + if (GameObject* stairs = instance->GetGameObject(guid)) + stairs->SetRespawnTime(DAY); + + if (Creature* jainaOrSylvanas = instance->GetCreature(JainaOrSylvanasEscapeGUID)) + jainaOrSylvanas->AI()->DoAction(ACTION_GUNSHIP_ARRIVAL_2); + + if (Creature* captain = instance->GetCreature(CaptainGUID)) + captain->AI()->Talk(SAY_CAPTAIN_FINAL); + + break; + default: + break; + } } - } - uint32 GetData(uint32 type) const override - { - switch (type) + uint32 GetData(uint32 type) const override { - case DATA_WAVE_COUNT: - return _waveCount; - case DATA_TEAM_IN_INSTANCE: - return _teamInInstance; - case DATA_INTRO_EVENT: - return _introEvent; - case DATA_FROSWORN_EVENT: - return _frostwornGeneral; - case DATA_ESCAPE_EVENT: - return _escapeevent; - case DATA_SUMMONS: - return _mobsaticewall; - default: - break; - } + switch (type) + { + case DATA_WAVE_COUNT: + return _waveCount; + case DATA_TEAM_IN_INSTANCE: + return _teamInInstance; + case DATA_INTRO_EVENT: + return _introState; + case DATA_FROSTSWORN_GENERAL: + return _frostswornGeneralState; + default: + break; + } - return 0; - } + return 0; + } - uint64 GetData64(uint32 type) const override - { - switch (type) + uint64 GetData64(uint32 type) const override { - case DATA_FALRIC_EVENT: - return _falricGUID; - case DATA_MARWYN_EVENT: - return _marwynGUID; - case DATA_FROSWORN_EVENT: - return _frostwornGeneralGUID; - case DATA_FROSTWORN_DOOR: - return _frostwornDoorGUID; - case DATA_FROSTMOURNE: - return _frostmourneGUID; - case DATA_ESCAPE_LEADER: - return _jainaOrSylvanasPart2GUID; - case DATA_CAVE_IN: - return _caveGUID; - default: - break; - } + switch (type) + { + case DATA_FALRIC: + return FalricGUID; + case DATA_MARWYN: + return MarwynGUID; + case DATA_FROSTSWORN_GENERAL: + return FrostswornGeneralGUID; + case DATA_IMPENETRABLE_DOOR: + return ImpenetrableDoorGUID; + case DATA_FROSTMOURNE: + return FrostmourneGUID; + case DATA_ESCAPE_LEADER: + return JainaOrSylvanasEscapeGUID; + case DATA_KORELN_LORALEN: + return KorelnOrLoralenGUID; + case DATA_THE_LICH_KING_ESCAPE: + return TheLichKingEscapeGUID; + case DATA_GUNSHIP: + return GunshipGUID; + case DATA_ICEWALL: + return IcewallGUID; + case DATA_ICEWALL_TARGET: + return IcewallTargetGUID; + default: + break; + } - return 0; - } + return 0; + } - std::string GetSaveData() override - { - OUT_SAVE_INST_DATA; + std::string GetSaveData() override + { + OUT_SAVE_INST_DATA; - std::ostringstream saveStream; - saveStream << "H R " << GetBossSaveData() << _introEvent << ' ' << _frostwornGeneral << ' ' << _escapeevent; + std::ostringstream saveStream; + saveStream << "H R " << GetBossSaveData() << _introState << ' ' << _frostswornGeneralState; - OUT_SAVE_INST_DATA_COMPLETE; - return saveStream.str(); - } + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); + } - void Load(char const* in) override - { - if (!in) + void Load(char const* in) override { - OUT_LOAD_INST_DATA_FAIL; - return; - } + if (!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } - OUT_LOAD_INST_DATA(in); + OUT_LOAD_INST_DATA(in); - char dataHead1, dataHead2; + char dataHead1, dataHead2; - std::istringstream loadStream(in); - loadStream >> dataHead1 >> dataHead2; + std::istringstream loadStream(in); + loadStream >> dataHead1 >> dataHead2; - if (dataHead1 == 'H' && dataHead2 == 'R') - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (dataHead1 == 'H' && dataHead2 == 'R') { - uint32 tmpState; - loadStream >> tmpState; - if (tmpState == IN_PROGRESS || tmpState > SPECIAL) - tmpState = NOT_STARTED; + for (uint8 i = 0; i < EncounterCount; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; - SetBossState(i, EncounterState(tmpState)); - } + SetBossState(i, EncounterState(tmpState)); + } - uint32 temp = 0; - loadStream >> temp; - if (temp == DONE) - SetData(DATA_INTRO_EVENT, DONE); - else - SetData(DATA_INTRO_EVENT, NOT_STARTED); + uint32 temp = 0; + loadStream >> temp; + if (temp == DONE) + SetData(DATA_INTRO_EVENT, DONE); + else + SetData(DATA_INTRO_EVENT, NOT_STARTED); - loadStream >> temp; - if (temp == DONE) - SetData(DATA_FROSWORN_EVENT, DONE); + loadStream >> temp; + if (temp == DONE) + SetData(DATA_FROSTSWORN_GENERAL, DONE); + else + SetData(DATA_FROSTSWORN_GENERAL, NOT_STARTED); + } else - SetData(DATA_FROSWORN_EVENT, NOT_STARTED); + OUT_LOAD_INST_DATA_FAIL; - loadStream >> temp; - if (temp == DONE) - SetData(DATA_ESCAPE_EVENT, DONE); - else - SetData(DATA_ESCAPE_EVENT, NOT_STARTED); + OUT_LOAD_INST_DATA_COMPLETE; } - else - OUT_LOAD_INST_DATA_FAIL; - OUT_LOAD_INST_DATA_COMPLETE; + private: + uint64 JainaOrSylvanasIntroGUID; // unused + uint64 KorelnOrLoralenGUID; + uint64 TheLichkingIntroGUID; // unused + uint64 FalricGUID; + uint64 MarwynGUID; + uint64 FrostmourneAltarBunnyGUID; + uint64 FrostswornGeneralGUID; + uint64 JainaOrSylvanasEscapeGUID; + uint64 TheLichKingEscapeGUID; + + uint64 FrostmourneGUID; + uint64 EntranceDoorGUID; + uint64 ImpenetrableDoorGUID; + uint64 ShadowThroneDoorGUID; + uint64 CaveInGUID; + + uint32 _teamInInstance; + uint32 _waveCount; + uint32 _introState; + uint32 _frostswornGeneralState; + + EventMap events; + std::set<uint64> waveGuidList[8]; + + uint64 GunshipGUID; + uint64 CaptainsChestGUID; + uint64 CaptainGUID; + uint64 IcewallGUID; + uint64 IcewallTargetGUID; + + std::set<uint64> GunshipCannonGUIDs; + std::set<uint64> GunshipStairGUIDs; + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override + { + return new instance_halls_of_reflection_InstanceMapScript(map); } - - private: - uint64 _falricGUID; - uint64 _marwynGUID; - uint64 _jainaOrSylvanasPart1GUID; - uint64 _jainaOrSylvanasPart2GUID; - uint64 _lichkingPart1GUID; - uint64 _frostwornGeneralGUID; - - uint64 _frostmourneGUID; - uint64 _entranceDoorGUID; - uint64 _frostwornDoorGUID; - uint64 _arthasDoorGUID; - uint64 _escapeDoorGUID; - uint64 _caveGUID; - - uint32 _teamInInstance; - uint32 _waveCount; - uint32 _introEvent; - uint32 _frostwornGeneral; - uint32 _escapeevent; - uint32 _mobsaticewall; - - EventMap events; - - std::set<uint64> waveGuidList[8]; - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_halls_of_reflection_InstanceMapScript(map); - } }; void AddSC_instance_halls_of_reflection() diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 25cc47b358c..592c44940a4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -1800,7 +1800,7 @@ class spell_icc_sprit_alarm : public SpellScriptLoader } if (GameObject* trap = GetCaster()->FindNearestGameObject(trapId, 5.0f)) - trap->SetRespawnTime(trap->GetGOInfo()->trap.autoCloseTime); + trap->SetRespawnTime(trap->GetGOInfo()->GetAutoCloseTime()); std::list<Creature*> wards; GetCaster()->GetCreatureListWithEntryInGrid(wards, NPC_DEATHBOUND_WARD, 150.0f); diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 3f0fb2f93b1..192249955cf 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -1810,7 +1810,7 @@ public: class spell_malygos_vortex_dummy_SpellScript : public SpellScript { - PrepareSpellScript(spell_malygos_vortex_dummy_SpellScript) + PrepareSpellScript(spell_malygos_vortex_dummy_SpellScript); bool Load() override { @@ -2282,7 +2282,7 @@ class spell_malygos_surge_of_power_warning_selector_25 : public SpellScriptLoade class spell_malygos_surge_of_power_warning_selector_25_SpellScript : public SpellScript { - PrepareSpellScript(spell_malygos_surge_of_power_warning_selector_25_SpellScript) + PrepareSpellScript(spell_malygos_surge_of_power_warning_selector_25_SpellScript); bool Load() override { @@ -2348,7 +2348,7 @@ class spell_malygos_surge_of_power_25 : public SpellScriptLoader class spell_malygos_surge_of_power_25_SpellScript : public SpellScript { - PrepareSpellScript(spell_malygos_surge_of_power_25_SpellScript) + PrepareSpellScript(spell_malygos_surge_of_power_25_SpellScript); bool Load() override { diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp index 0870614ba78..585da8e28d3 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp @@ -299,7 +299,7 @@ class spell_varos_energize_core_area_enemy : public SpellScriptLoader class spell_varos_energize_core_area_enemySpellScript : public SpellScript { - PrepareSpellScript(spell_varos_energize_core_area_enemySpellScript) + PrepareSpellScript(spell_varos_energize_core_area_enemySpellScript); void FilterTargets(std::list<WorldObject*>& targets) { @@ -343,7 +343,7 @@ class spell_varos_energize_core_area_entry : public SpellScriptLoader class spell_varos_energize_core_area_entrySpellScript : public SpellScript { - PrepareSpellScript(spell_varos_energize_core_area_entrySpellScript) + PrepareSpellScript(spell_varos_energize_core_area_entrySpellScript); void FilterTargets(std::list<WorldObject*>& targets) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp index c81cd0b0b80..07cdfa3353c 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp @@ -15,14 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* Script Data Start -SDName: Boss krystallus -SDAuthor: LordVanMartin -SD%Complete: -SDComment: -SDCategory: -Script Data End */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" @@ -30,17 +22,13 @@ Script Data End */ enum Spells { - SPELL_BOULDER_TOSS = 50843, - H_SPELL_BOULDER_TOSS = 59742, - SPELL_GROUND_SPIKE = 59750, - SPELL_GROUND_SLAM = 50827, - SPELL_SHATTER = 50810, - H_SPELL_SHATTER = 61546, - SPELL_SHATTER_EFFECT = 50811, - H_SPELL_SHATTER_EFFECT = 61547, - SPELL_STONED = 50812, - SPELL_STOMP = 48131, - H_SPELL_STOMP = 59744 + SPELL_BOULDER_TOSS = 50843, + SPELL_GROUND_SPIKE = 59750, + SPELL_GROUND_SLAM = 50827, + SPELL_SHATTER = 50810, + SPELL_SHATTER_EFFECT = 50811, + SPELL_STONED = 50812, + SPELL_STOMP = 48131 }; enum Yells @@ -51,133 +39,103 @@ enum Yells SAY_SHATTER = 3 }; -class boss_krystallus : public CreatureScript +enum Events { -public: - boss_krystallus() : CreatureScript("boss_krystallus") { } - - struct boss_krystallusAI : public ScriptedAI - { - boss_krystallusAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - uint32 uiBoulderTossTimer; - uint32 uiGroundSpikeTimer; - uint32 uiGroundSlamTimer; - uint32 uiShatterTimer; - uint32 uiStompTimer; - - bool bIsSlam; - - InstanceScript* instance; - - void Reset() override - { - bIsSlam = false; - - uiBoulderTossTimer = urand(3000, 9000); - uiGroundSpikeTimer = urand(9000, 14000); - uiGroundSlamTimer = urand(15000, 18000); - uiStompTimer = urand(20000, 29000); - uiShatterTimer = 0; - - instance->SetBossState(DATA_KRYSTALLUS, NOT_STARTED); - } - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); + EVENT_BOULDER_TOSS = 1, + EVENT_GROUND_SPIKE, + EVENT_GROUND_SLAM, + EVENT_STOMP, + EVENT_SHATTER +}; - instance->SetBossState(DATA_KRYSTALLUS, IN_PROGRESS); - } +class boss_krystallus : public CreatureScript +{ + public: + boss_krystallus() : CreatureScript("boss_krystallus") { } - void UpdateAI(uint32 diff) override + struct boss_krystallusAI : public BossAI { - //Return since we have no target - if (!UpdateVictim()) - return; + boss_krystallusAI(Creature* creature) : BossAI(creature, DATA_KRYSTALLUS) { } - if (uiBoulderTossTimer <= diff) + void Reset() override { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - DoCast(target, SPELL_BOULDER_TOSS); - uiBoulderTossTimer = urand(9000, 15000); - } else uiBoulderTossTimer -= diff; - - if (uiGroundSpikeTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - DoCast(target, SPELL_GROUND_SPIKE); - uiGroundSpikeTimer = urand(12000, 17000); - } else uiGroundSpikeTimer -= diff; - - if (uiStompTimer <= diff) - { - DoCast(me, SPELL_STOMP); - uiStompTimer = urand(20000, 29000); - } else uiStompTimer -= diff; - - if (uiGroundSlamTimer <= diff) - { - DoCast(me, SPELL_GROUND_SLAM); - bIsSlam = true; - uiShatterTimer = 10000; - uiGroundSlamTimer = urand(15000, 18000); - } else uiGroundSlamTimer -= diff; + _Reset(); + } - if (bIsSlam) + void EnterCombat(Unit* /*who*/) override { - if (uiShatterTimer <= diff) - { - DoCast(me, DUNGEON_MODE(SPELL_SHATTER, H_SPELL_SHATTER)); - } else uiShatterTimer -= diff; + Talk(SAY_AGGRO); + _EnterCombat(); + + events.ScheduleEvent(EVENT_BOULDER_TOSS, urand(3000, 9000)); + events.ScheduleEvent(EVENT_GROUND_SLAM, urand(15000, 18000)); + events.ScheduleEvent(EVENT_STOMP, urand(20000, 29000)); + if (IsHeroic()) + events.ScheduleEvent(EVENT_GROUND_SPIKE, urand(9000, 14000)); } - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - - instance->SetBossState(DATA_KRYSTALLUS, DONE); - } + void UpdateAI(uint32 diff) override + { + // Return since we have no target + if (!UpdateVictim()) + return; - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() != TYPEID_PLAYER) - return; + events.Update(diff); - Talk(SAY_KILL); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void SpellHitTarget(Unit* /*target*/, const SpellInfo* pSpell) override - { - //this part should be in the core - if (pSpell->Id == SPELL_SHATTER || pSpell->Id == H_SPELL_SHATTER) - { - /// @todo we need eventmap to kill this stuff - //clear this, if we are still performing - if (bIsSlam) + while (uint32 eventId = events.ExecuteEvent()) { - bIsSlam = false; - - //and correct movement, if not already - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) + switch (eventId) { - if (me->GetVictim()) - me->GetMotionMaster()->MoveChase(me->GetVictim()); + case EVENT_BOULDER_TOSS: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true)) + DoCast(target, SPELL_BOULDER_TOSS); + events.ScheduleEvent(EVENT_BOULDER_TOSS, urand(9000, 15000)); + break; + case EVENT_GROUND_SPIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_GROUND_SPIKE); + events.ScheduleEvent(EVENT_GROUND_SPIKE, urand(12000, 17000)); + break; + case EVENT_GROUND_SLAM: + DoCast(me, SPELL_GROUND_SLAM); + events.ScheduleEvent(EVENT_SHATTER, 10000); + events.ScheduleEvent(EVENT_GROUND_SLAM, urand(15000, 18000)); + break; + case EVENT_STOMP: + DoCast(me, SPELL_STOMP); + events.ScheduleEvent(EVENT_STOMP, urand(20000, 29000)); + break; + case EVENT_SHATTER: + DoCast(me, SPELL_SHATTER); + break; + default: + break; } } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); } - } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfStoneAI<boss_krystallusAI>(creature); - } + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_KILL); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetHallsOfStoneAI<boss_krystallusAI>(creature); + } }; class spell_krystallus_shatter : public SpellScriptLoader diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index cfa5429ea79..f284aacf996 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -89,7 +89,7 @@ class spell_ulduar_proximity_mines : public SpellScriptLoader class spell_ulduar_proximity_minesSpellScript : public SpellScript { - PrepareSpellScript(spell_ulduar_proximity_minesSpellScript) + PrepareSpellScript(spell_ulduar_proximity_minesSpellScript); void HandleScript(SpellEffIndex effIndex) { diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 77a4faa7e8c..4c72d790059 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -509,7 +509,7 @@ class spell_gen_break_shield: public SpellScriptLoader class spell_gen_break_shield_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_break_shield_SpellScript) + PrepareSpellScript(spell_gen_break_shield_SpellScript); void HandleScriptEffect(SpellEffIndex effIndex) { @@ -671,7 +671,7 @@ class spell_gen_chaos_blast : public SpellScriptLoader class spell_gen_chaos_blast_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_chaos_blast_SpellScript) + PrepareSpellScript(spell_gen_chaos_blast_SpellScript); bool Validate(SpellInfo const* /*spellInfo*/) override { @@ -895,7 +895,7 @@ class spell_gen_count_pct_from_max_hp : public SpellScriptLoader class spell_gen_count_pct_from_max_hp_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_count_pct_from_max_hp_SpellScript) + PrepareSpellScript(spell_gen_count_pct_from_max_hp_SpellScript); public: spell_gen_count_pct_from_max_hp_SpellScript(int32 damagePct) : SpellScript(), _damagePct(damagePct) { } @@ -1446,6 +1446,7 @@ class spell_gen_elune_candle : public SpellScriptLoader class spell_gen_elune_candle_SpellScript : public SpellScript { PrepareSpellScript(spell_gen_elune_candle_SpellScript); + bool Validate(SpellInfo const* /*spellInfo*/) override { if (!sSpellMgr->GetSpellInfo(SPELL_ELUNE_CANDLE_OMEN_HEAD) || @@ -1511,7 +1512,7 @@ class spell_gen_gadgetzan_transporter_backfire : public SpellScriptLoader class spell_gen_gadgetzan_transporter_backfire_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_gadgetzan_transporter_backfire_SpellScript) + PrepareSpellScript(spell_gen_gadgetzan_transporter_backfire_SpellScript); bool Validate(SpellInfo const* /*spellInfo*/) override { @@ -1612,7 +1613,7 @@ class spell_gen_gnomish_transporter : public SpellScriptLoader class spell_gen_gnomish_transporter_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_gnomish_transporter_SpellScript) + PrepareSpellScript(spell_gen_gnomish_transporter_SpellScript); bool Validate(SpellInfo const* /*spellInfo*/) override { @@ -2093,7 +2094,7 @@ class spell_gen_mounted_charge: public SpellScriptLoader class spell_gen_mounted_charge_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_mounted_charge_SpellScript) + PrepareSpellScript(spell_gen_mounted_charge_SpellScript); void HandleScriptEffect(SpellEffIndex effIndex) { @@ -2794,7 +2795,7 @@ class spell_gen_parachute_ic : public SpellScriptLoader class spell_gen_parachute_ic_AuraScript : public AuraScript { - PrepareAuraScript(spell_gen_parachute_ic_AuraScript) + PrepareAuraScript(spell_gen_parachute_ic_AuraScript); void HandleTriggerSpell(AuraEffect const* /*aurEff*/) { @@ -2842,30 +2843,28 @@ class spell_gen_pet_summoned : public SpellScriptLoader if (player->GetLastPetNumber()) { PetType newPetType = (player->getClass() == CLASS_HUNTER) ? HUNTER_PET : SUMMON_PET; - if (Pet* newPet = new Pet(player, newPetType)) + Pet* newPet = new Pet(player, newPetType); + if (newPet->LoadPetFromDB(player, 0, player->GetLastPetNumber(), true)) { - if (newPet->LoadPetFromDB(player, 0, player->GetLastPetNumber(), true)) - { - // revive the pet if it is dead - if (newPet->getDeathState() == DEAD) - newPet->setDeathState(ALIVE); + // revive the pet if it is dead + if (newPet->getDeathState() == DEAD) + newPet->setDeathState(ALIVE); - newPet->SetFullHealth(); - newPet->SetPower(newPet->getPowerType(), newPet->GetMaxPower(newPet->getPowerType())); + newPet->SetFullHealth(); + newPet->SetPower(newPet->getPowerType(), newPet->GetMaxPower(newPet->getPowerType())); - switch (newPet->GetEntry()) - { - case NPC_DOOMGUARD: - case NPC_INFERNAL: - newPet->SetEntry(NPC_IMP); - break; - default: - break; - } + switch (newPet->GetEntry()) + { + case NPC_DOOMGUARD: + case NPC_INFERNAL: + newPet->SetEntry(NPC_IMP); + break; + default: + break; } - else - delete newPet; } + else + delete newPet; } } @@ -3123,7 +3122,7 @@ class spell_gen_spectator_cheer_trigger : public SpellScriptLoader class spell_gen_spectator_cheer_trigger_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_spectator_cheer_trigger_SpellScript) + PrepareSpellScript(spell_gen_spectator_cheer_trigger_SpellScript); void HandleDummy(SpellEffIndex /*effIndex*/) { @@ -3615,7 +3614,7 @@ class spell_gen_vendor_bark_trigger : public SpellScriptLoader class spell_gen_vendor_bark_trigger_SpellScript : public SpellScript { - PrepareSpellScript(spell_gen_vendor_bark_trigger_SpellScript) + PrepareSpellScript(spell_gen_vendor_bark_trigger_SpellScript); void HandleDummy(SpellEffIndex /* effIndex */) { diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp index dc0c70975dd..85bf85fa2d2 100644 --- a/src/server/scripts/Spells/spell_holiday.cpp +++ b/src/server/scripts/Spells/spell_holiday.cpp @@ -296,7 +296,7 @@ class spell_pilgrims_bounty_buff_food : public SpellScriptLoader class spell_pilgrims_bounty_buff_food_AuraScript : public AuraScript { - PrepareAuraScript(spell_pilgrims_bounty_buff_food_AuraScript) + PrepareAuraScript(spell_pilgrims_bounty_buff_food_AuraScript); private: uint32 const _triggeredSpellId; diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 590cad7007f..61ff79c505e 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -775,7 +775,7 @@ class spell_sha_lava_lash : public SpellScriptLoader class spell_sha_lava_lash_SpellScript : public SpellScript { - PrepareSpellScript(spell_sha_lava_lash_SpellScript) + PrepareSpellScript(spell_sha_lava_lash_SpellScript); bool Load() override { diff --git a/src/server/scripts/World/boss_emerald_dragons.cpp b/src/server/scripts/World/boss_emerald_dragons.cpp index 362c02e1af5..950b4cd10e9 100644 --- a/src/server/scripts/World/boss_emerald_dragons.cpp +++ b/src/server/scripts/World/boss_emerald_dragons.cpp @@ -781,4 +781,4 @@ void AddSC_emerald_dragons() // dragon spellscripts new spell_dream_fog_sleep(); new spell_mark_of_nature(); -}; +} diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index c60458323f7..3665a388854 100644 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -49,8 +49,10 @@ class DatabaseWorkerPool { public: /* Activity state */ - DatabaseWorkerPool() : _queue(new ACE_Activation_Queue()), _connectionInfo(NULL) + DatabaseWorkerPool() : _connectionInfo(NULL) { + _messageQueue = new ACE_Message_Queue<ACE_SYNCH>(8 * 1024 * 1024, 8 * 1024 * 1024); + _queue = new ACE_Activation_Queue(_messageQueue); memset(_connectionCount, 0, sizeof(_connectionCount)); _connections.resize(IDX_SIZE); @@ -131,6 +133,7 @@ class DatabaseWorkerPool //! Deletes the ACE_Activation_Queue object and its underlying ACE_Message_Queue delete _queue; + delete _messageQueue; TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); @@ -520,6 +523,7 @@ class DatabaseWorkerPool IDX_SIZE }; + ACE_Message_Queue<ACE_SYNCH>* _messageQueue; //! Message Queue used by ACE_Activation_Queue ACE_Activation_Queue* _queue; //! Queue shared by async worker threads. std::vector< std::vector<T*> > _connections; uint32 _connectionCount[2]; //! Counter of MySQL connections; diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index bc002668b3b..dc9bda62bfb 100644 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -250,13 +250,13 @@ void Log::ReadLoggersFromConfig() AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE); appenders[appender->getId()] = appender; - Logger& rootLogger = loggers[LOGGER_ROOT]; - rootLogger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR); - rootLogger.addAppender(appender->getId(), appender); + Logger& logger = loggers[LOGGER_ROOT]; + logger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR); + logger.addAppender(appender->getId(), appender); - Logger& serverLogger = loggers["server"]; - serverLogger.Create("server", LOG_LEVEL_INFO); - serverLogger.addAppender(appender->getId(), appender); + logger = loggers["server"]; + logger.Create("server", LOG_LEVEL_ERROR); + logger.addAppender(appender->getId(), appender); } } @@ -267,7 +267,7 @@ void Log::vlog(std::string const& filter, LogLevel level, char const* str, va_li write(new LogMessage(level, filter, text)); } -void Log::write(LogMessage* msg) +void Log::write(LogMessage* msg) const { Logger const* logger = GetLoggerByType(msg->type); msg->text.append("\n"); @@ -376,7 +376,6 @@ void Log::Close() delete worker; worker = NULL; loggers.clear(); - cachedLoggers.clear(); for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) { delete it->second; diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index 5fa638e2f40..a118e6e8773 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -35,7 +35,6 @@ class Log friend class ACE_Singleton<Log, ACE_Thread_Mutex>; typedef std::unordered_map<std::string, Logger> LoggerMap; - typedef std::unordered_map<std::string, Logger const*> CachedLoggerContainer; private: Log(); @@ -44,7 +43,7 @@ class Log public: void LoadFromConfig(); void Close(); - bool ShouldLog(std::string const& type, LogLevel level); + bool ShouldLog(std::string const& type, LogLevel level) const; bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true); void outMessage(std::string const& f, LogLevel level, char const* str, ...) ATTR_PRINTF(4, 5); @@ -57,9 +56,9 @@ class Log private: static std::string GetTimestampStr(); void vlog(std::string const& f, LogLevel level, char const* str, va_list argptr); - void write(LogMessage* msg); + void write(LogMessage* msg) const; - Logger const* GetLoggerByType(std::string const& type); + Logger const* GetLoggerByType(std::string const& type) const; Appender* GetAppenderByName(std::string const& name); uint8 NextAppenderId(); void CreateAppenderFromConfig(std::string const& name); @@ -69,7 +68,6 @@ class Log AppenderMap appenders; LoggerMap loggers; - CachedLoggerContainer cachedLoggers; uint8 AppenderId; std::string m_logsDir; @@ -78,37 +76,29 @@ class Log LogWorker* worker; }; -inline Logger const* Log::GetLoggerByType(std::string const& originalType) +inline Logger const* Log::GetLoggerByType(std::string const& type) const { - // Check if already cached - CachedLoggerContainer::const_iterator itCached = cachedLoggers.find(originalType); - if (itCached != cachedLoggers.end()) - return itCached->second; - - Logger const* logger = NULL; - std::string type(originalType); - - do - { - // Search for the logger "type.subtype" - LoggerMap::const_iterator it = loggers.find(type); - if (it == loggers.end()) - { - // Search for the logger "type", if our logger contains '.', otherwise search for LOGGER_ROOT - size_t found = type.find_last_of("."); - type = found != std::string::npos ? type.substr(0, found) : LOGGER_ROOT; - } - else - logger = &(it->second); - } - while (!logger); - - cachedLoggers[originalType] = logger; - return logger; + LoggerMap::const_iterator it = loggers.find(type); + if (it != loggers.end()) + return &(it->second); + + if (type == LOGGER_ROOT) + return NULL; + + std::string parentLogger = LOGGER_ROOT; + size_t found = type.find_last_of("."); + if (found != std::string::npos) + parentLogger = type.substr(0,found); + + return GetLoggerByType(parentLogger); } -inline bool Log::ShouldLog(std::string const& type, LogLevel level) +inline bool Log::ShouldLog(std::string const& type, LogLevel level) const { + // TODO: Use cache to store "Type.sub1.sub2": "Type" equivalence, should + // Speed up in cases where requesting "Type.sub1.sub2" but only configured + // Logger "Type" + Logger const* logger = GetLoggerByType(type); if (!logger) return false; diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index bc46b87fa27..dd0a9d5fdf4 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -377,9 +377,19 @@ class ByteBuffer return *this; } - uint8 * contents() { return &_storage[0]; } + uint8 * contents() + { + if (_storage.empty()) + throw ByteBufferException(); + return &_storage[0]; + } - const uint8 *contents() const { return &_storage[0]; } + const uint8 *contents() const + { + if (_storage.empty()) + throw ByteBufferException(); + return &_storage[0]; + } size_t size() const { return _storage.size(); } bool empty() const { return _storage.empty(); } diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 19112d84266..7832cef18de 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -906,7 +906,7 @@ namespace MMAP float p0[3], p1[3]; uint32 mid, tx, ty; float size; - if (sscanf(buf, "%d %d,%d (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty, + if (sscanf(buf, "%u %u,%u (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty, &p0[0], &p0[1], &p0[2], &p1[0], &p1[1], &p1[2], &size) != 10) continue; |